diff options
author | Vicent Marti | 2008-06-14 14:44:29 +0000 |
---|---|---|
committer | Vicent Marti | 2008-06-14 14:44:29 +0000 |
commit | d0b27cf9c66b9281899acf826cb205e19dcb7260 (patch) | |
tree | 74e813b1d1f081f35f41ca7a95da5d048951b9e7 /engines/gob | |
parent | d51a0cab3fe494698f001d81d5d86cea7cd0395b (diff) | |
parent | 91d3ea31359950b59ee46af8355cc0f5790257e5 (diff) | |
download | scummvm-rg350-d0b27cf9c66b9281899acf826cb205e19dcb7260.tar.gz scummvm-rg350-d0b27cf9c66b9281899acf826cb205e19dcb7260.tar.bz2 scummvm-rg350-d0b27cf9c66b9281899acf826cb205e19dcb7260.zip |
Merged trunk into the GUI branch.
Fixed MSVS9 project files.
svn-id: r32702
Diffstat (limited to 'engines/gob')
80 files changed, 5569 insertions, 2369 deletions
diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp index d508dc75f9..415790e67b 100644 --- a/engines/gob/coktelvideo.cpp +++ b/engines/gob/coktelvideo.cpp @@ -123,8 +123,9 @@ bool Imd::load(Common::SeekableReadStream &stream) { return false; } - _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); - _frameLength = _soundSliceLength; + _soundSliceLength = (uint32) (((double) (1000 << 16)) / + ((double) _soundFreq / (double) _soundSliceSize)); + _frameLength = _soundSliceLength >> 16; _soundStage = 1; _hasSound = true; @@ -270,6 +271,13 @@ void Imd::disableSound() { _mixer = 0; } +bool Imd::isSoundPlaying() const { + if (_audioStream && _mixer->isSoundHandleActive(_audioHandle)) + return true; + + return false; +} + void Imd::seekFrame(int32 frame, int16 whence, bool restart) { if (!_stream) // Nothing to do @@ -318,11 +326,11 @@ void Imd::waitEndFrame() { return; if (_skipFrames == 0) { - int32 waitTime = (_curFrame * _soundSliceLength) - - (g_system->getMillis() - _soundStartTime); + int32 waitTime = (int16) (((_curFrame * _soundSliceLength) - + ((g_system->getMillis() - _soundStartTime) << 16)) >> 16); if (waitTime < 0) { - _skipFrames = -waitTime / _soundSliceLength; + _skipFrames = -waitTime / (_soundSliceLength >> 16); warning("Video A/V sync broken, skipping %d frame(s)", _skipFrames + 1); } else if (waitTime > 0) g_system->delayMillis(waitTime); @@ -333,6 +341,11 @@ void Imd::waitEndFrame() { g_system->delayMillis(_frameLength); } +void Imd::notifyPaused(uint32 duration) { + if (_soundStage == 2) + _soundStartTime += duration; +} + void Imd::copyCurrentFrame(byte *dest, uint16 left, uint16 top, uint16 width, uint16 height, uint16 x, uint16 y, uint16 pitch, int16 transp) { @@ -931,10 +944,9 @@ bool Vmd::load(Common::SeekableReadStream &stream) { _soundSliceSize = -_soundSliceSize; } - _soundSliceLength = (uint16) (1000.0 / + _soundSliceLength = (uint32) (((double) (1000 << 16)) / ((double) _soundFreq / (double) _soundSliceSize)); - - _frameLength = _soundSliceLength; + _frameLength = _soundSliceLength >> 16; _soundStage = 1; _audioStream = Audio::makeAppendableAudioStream(_soundFreq, @@ -1066,8 +1078,8 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { state.flags |= kStateNoVideoData; state.left = 0x7FFF; - state.right = 0x7FFF; - state.top = 0; + state.top = 0x7FFF; + state.right = 0; state.bottom = 0; if (!_vidMem) @@ -1121,6 +1133,8 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { } else if (part.type == kPartTypeVideo) { state.flags &= ~kStateNoVideoData; + uint32 size = part.size; + // New palette if (part.flags & 2) { uint8 index = _stream->readByte(); @@ -1130,9 +1144,12 @@ CoktelVideo::State Vmd::processFrame(uint16 frame) { _stream->skip((255 - count) * 3); state.flags |= kStatePalette; + + size -= (768 + 2); } - _stream->read(_frameData, part.size); + _stream->read(_frameData, size); + if (renderFrame(part.left, part.top, part.right, part.bottom)) { // Rendering succeeded, merging areas state.left = MIN(state.left, part.left); diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h index 4f9543e8d0..348e5e3ab1 100644 --- a/engines/gob/coktelvideo.h +++ b/engines/gob/coktelvideo.h @@ -134,11 +134,14 @@ public: /** Use an own memory block as video memory. */ virtual void setVideoMemory() = 0; - /** Play sound (if the IMD has sound). */ + /** Play sound (if the video has sound). */ virtual void enableSound(Audio::Mixer &mixer) = 0; /** Don't play sound or stop currently playing sound. */ virtual void disableSound() = 0; + /** Is sound currently playing? */ + virtual bool isSoundPlaying() const = 0; + /** Seek to a specific frame. * * @param frame The frame to which to seek. @@ -152,6 +155,9 @@ public: /** Wait for the frame to end. */ virtual void waitEndFrame() = 0; + /** Notifies the video that it was paused for duration ms. */ + virtual void notifyPaused(uint32 duration) = 0; + /** Copy the current frame. * * @param dest The memory to which to copy the current frame. @@ -184,7 +190,11 @@ public: int16 getHeight() const { return _height; } uint16 getFramesCount() const { return _framesCount; } uint16 getCurrentFrame() const { return _curFrame; } - int16 getFrameRate() const { if (_hasSound) return 1000 / _soundSliceLength; return _frameRate; } + int16 getFrameRate() const { + if (_hasSound) + return 1000 / (_soundSliceLength >> 16); + return _frameRate; + } uint32 getSyncLag() const { return _skipFrames; } const byte *getPalette() const { return _palette; } @@ -203,11 +213,15 @@ public: void enableSound(Audio::Mixer &mixer); void disableSound(); + bool isSoundPlaying() const; + void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false); State nextFrame(); void waitEndFrame(); + void notifyPaused(uint32 duration); + void copyCurrentFrame(byte *dest, uint16 left, uint16 top, uint16 width, uint16 height, uint16 x, uint16 y, uint16 pitch, int16 transp = -1); @@ -250,7 +264,7 @@ protected: int16 _soundFreq; int16 _soundSliceSize; int16 _soundSlicesCount; - uint16 _soundSliceLength; + uint32 _soundSliceLength; Audio::AppendableAudioStream *_audioStream; Audio::SoundHandle _audioHandle; diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 1fb43e96bb..8ae11b8755 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -233,8 +232,10 @@ int16 DataIO::getChunk(const char *chunkName) { if (_chunkPos[file * MAX_SLOT_COUNT + slot] == -1) break; - if (slot == MAX_SLOT_COUNT) + if (slot == MAX_SLOT_COUNT) { + warning("Chunk slots full"); return -1; + } dataDesc = _dataFiles[file]; for (int16 chunk = 0; chunk < _numDataChunks[file]; chunk++, dataDesc++) { diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 7637605dcd..8351f2ecfb 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -23,7 +23,6 @@ * */ - #include "base/plugins.h" #include "common/advancedDetector.h" @@ -1685,6 +1684,71 @@ static const GOBGameDescription gameDescriptions[] = { kFeatures640, "intro" }, + { // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + EN_GRB, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by DjDiabolik in bug report #1971294 + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "60348a87651f92e8492ee070556a96d8", 7069736), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, { { "dynasty", diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index 2a4732954c..8a7de9bdaa 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" diff --git a/engines/gob/draw_v1.cpp b/engines/gob/draw_v1.cpp index 959a064b7d..b5bc56b6f5 100644 --- a/engines/gob/draw_v1.cpp +++ b/engines/gob/draw_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "graphics/cursorman.h" @@ -31,9 +30,10 @@ #include "gob/draw.h" #include "gob/global.h" #include "gob/util.h" -#include "gob/cdrom.h" #include "gob/game.h" #include "gob/scenery.h" +#include "gob/inter.h" +#include "gob/sound/sound.h" namespace Gob { @@ -170,7 +170,7 @@ void Draw_v1::printTotText(int16 id) { int16 spriteRight, spriteBottom; char buf[20]; - _vm->_cdrom->playMultMusic(); + _vm->_sound->cdPlayMultMusic(); if (!_vm->_game->_totTextData || !_vm->_game->_totTextData->dataPtr) return; diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index 8f7d5b325b..378ff0dcdf 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "graphics/cursorman.h" @@ -33,6 +32,7 @@ #include "gob/util.h" #include "gob/game.h" #include "gob/scenery.h" +#include "gob/inter.h" #include "gob/video.h" namespace Gob { @@ -178,13 +178,13 @@ void Draw_v2::animateCursor(int16 cursor) { _vm->_util->delay(5); } } - } else + } else { blitCursor(); + _cursorX = newX; + _cursorY = newY; + } _showCursor &= ~1; - - _cursorX = newX; - _cursorY = newY; } void Draw_v2::printTotText(int16 id) { @@ -246,22 +246,29 @@ void Draw_v2::printTotText(int16 id) { } if (_renderFlags & RENDERFLAG_FROMSPLIT) { - destY = _vm->_video->_splitStart; + int16 start; + + start = _vm->_video->_splitStart; + + destY = start; spriteBottom = READ_LE_UINT16(ptr + 6) - READ_LE_UINT16(ptr + 2); + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) spriteBottom *= 3; - spriteBottom += _vm->_video->_splitStart; + + spriteBottom += start; + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { - spriteBottom += _backDeltaX; - destY += _backDeltaX; + spriteBottom += _backDeltaY; + destY += _backDeltaY; } } else { + destY = READ_LE_UINT16(ptr + 2); + spriteBottom = READ_LE_UINT16(ptr + 6); + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { - destY = READ_LE_UINT16(ptr + 2) * 2; - spriteBottom = READ_LE_UINT16(ptr + 6) * 2; - } else { - destY = READ_LE_UINT16(ptr + 2); - spriteBottom = READ_LE_UINT16(ptr + 6); + destY *= 2; + spriteBottom *= 2; } } @@ -629,8 +636,7 @@ void Draw_v2::spriteOperation(int16 operation) { _destSpriteX += _backDeltaX; _destSpriteY += _backDeltaY; if ((operation == DRAW_DRAWLINE) || - ((operation >= DRAW_DRAWBAR) && - (operation <= DRAW_FILLRECTABS))) { + ((operation >= DRAW_DRAWBAR) && (operation <= DRAW_FILLRECTABS))) { _spriteRight += _backDeltaX; _spriteBottom += _backDeltaY; } @@ -646,6 +652,24 @@ void Draw_v2::spriteOperation(int16 operation) { int16 destSurface = _destSurface; int16 sourceSurface = _sourceSurface; + if (_vm->_video->_splitSurf && ((_destSurface == 20) || (_destSurface == 21))) { + if ((_destSpriteY >= _vm->_video->_splitStart)) { + _destSpriteY -= _vm->_video->_splitStart; + if ((operation == DRAW_DRAWLINE) || + ((operation >= DRAW_DRAWBAR) && (operation <= DRAW_FILLRECTABS))) + _spriteBottom -= _vm->_video->_splitStart; + + _destSurface += 4; + } + + if ((_spriteTop >= _vm->_video->_splitStart) && (operation == DRAW_BLITSURF)) { + _spriteTop -= _vm->_video->_splitStart; + if (_destSurface < 24) + _destSurface += 4; + } + + } + adjustCoords(0, &_destSpriteX, &_destSpriteY); if ((operation != DRAW_LOADSPRITE) && (_needAdjust != 2)) { adjustCoords(0, &_spriteRight, &_spriteBottom); diff --git a/engines/gob/driver_vga.cpp b/engines/gob/driver_vga.cpp index 08235f16e2..f68ce47783 100644 --- a/engines/gob/driver_vga.cpp +++ b/engines/gob/driver_vga.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "graphics/primitives.h" @@ -110,10 +109,16 @@ void VGAVideoDriver::drawSprite(SurfaceDesc *source, SurfaceDesc *dest, int16 width = MIN((right - left) + 1, (int) dest->getWidth()); int16 height = MIN((bottom - top) + 1, (int) dest->getHeight()); + if ((width < 1) || (height < 1)) + return; + byte *srcPos = source->getVidMem() + (top * source->getWidth()) + left; byte *destPos = dest->getVidMem() + (y * dest->getWidth()) + x; + uint32 size = width * height; + if (transp) { + while (height--) { for (int16 i = 0; i < width; ++i) { if (srcPos[i]) @@ -123,13 +128,26 @@ void VGAVideoDriver::drawSprite(SurfaceDesc *source, SurfaceDesc *dest, srcPos += source->getWidth(); destPos += dest->getWidth(); } + + } else if (((srcPos >= destPos) && (srcPos <= (destPos + size))) || + ((destPos >= srcPos) && (destPos <= (srcPos + size)))) { + + while (height--) { + memmove(destPos, srcPos, width); + + srcPos += source->getWidth(); + destPos += dest->getWidth(); + } + } else { + while (height--) { memcpy(destPos, srcPos, width); srcPos += source->getWidth(); destPos += dest->getWidth(); } + } } diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index 666f46fde1..73fa820fa0 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -35,7 +34,7 @@ #include "gob/parse.h" #include "gob/draw.h" #include "gob/mult.h" -#include "gob/music.h" +#include "gob/sound/sound.h" namespace Gob { @@ -60,9 +59,6 @@ Game::Game(GobEngine *vm) : _vm(vm) { _collStackElemSizes[i] = 0; } - _infIns = 0; - _infogrames = 0; - _curTotFile[0] = 0; _curExtFile[0] = 0; _totToLoad[0] = 0; @@ -105,10 +101,6 @@ Game::Game(GobEngine *vm) : _vm(vm) { } Game::~Game() { - delete _infIns; - - for (int i = 0; i < 60; i++) - _soundSamples[i].free(); } byte *Game::loadExtData(int16 itemId, int16 *pResWidth, @@ -295,16 +287,7 @@ void Game::freeSoundSlot(int16 slot) { if (slot == -1) slot = _vm->_parse->parseValExpr(); - if ((slot < 0) || (slot >= 60) || _soundSamples[slot].empty()) - return; - - SoundDesc &sample = _soundSamples[slot]; - - if (sample.getType() == SOUND_ADL) - if (_vm->_adlib && (_vm->_adlib->getIndex() == slot)) - _vm->_adlib->stopPlay(); - - _vm->_snd->freeSample(sample); + _vm->_sound->sampleFree(_vm->_sound->sampleGetBySlot(slot)); } void Game::evaluateScroll(int16 x, int16 y) { @@ -367,7 +350,7 @@ int16 Game::checkKeys(int16 *pMouseX, int16 *pMouseY, _vm->_util->processInput(true); - if (_vm->_mult->_multData && _vm->_global->_inter_variables && + if (_vm->_mult->_multData && _vm->_inter->_variables && (VAR(58) != 0)) { if (_vm->_mult->_multData->frameStart != (int) VAR(58) - 1) _vm->_mult->_multData->frameStart++; @@ -380,7 +363,7 @@ int16 Game::checkKeys(int16 *pMouseX, int16 *pMouseY, if ((_vm->_inter->_soundEndTimeKey != 0) && (_vm->_util->getTimeKey() >= _vm->_inter->_soundEndTimeKey)) { - _vm->_snd->stopSound(_vm->_inter->_soundStopVal); + _vm->_sound->blasterStop(_vm->_inter->_soundStopVal); _vm->_inter->_soundEndTimeKey = 0; } @@ -497,8 +480,7 @@ void Game::totSub(int8 flags, const char *newTotFile) { _extTableArray[_backupedCount] = _extTable; _extHandleArray[_backupedCount] = _extHandle; _imFileDataArray[_backupedCount] = _imFileData; - _variablesArray[_backupedCount] = _vm->_global->_inter_variables; - _variablesSizesArray[_backupedCount] = _vm->_global->_inter_variablesSizes; + _variablesArray[_backupedCount] = _vm->_inter->_variables; strcpy(_curTotFileArray[_backupedCount], _curTotFile); curBackupPos = _curBackupPos; @@ -508,10 +490,8 @@ void Game::totSub(int8 flags, const char *newTotFile) { _totTextData = 0; _totFileData = 0; _totResourceTable = 0; - if (flags & 1) { - _vm->_global->_inter_variables = 0; - _vm->_global->_inter_variablesSizes = 0; - } + if (flags & 1) + _vm->_inter->_variables = 0; strncpy0(_curTotFile, newTotFile, 9); strcat(_curTotFile, ".TOT"); @@ -531,9 +511,8 @@ void Game::totSub(int8 flags, const char *newTotFile) { popCollisions(); - if ((flags & 1) && _vm->_global->_inter_variables) { - delete[] _vm->_global->_inter_variables; - delete[] _vm->_global->_inter_variablesSizes; + if ((flags & 1) && _vm->_inter->_variables) { + _vm->_inter->delocateVars(); } _backupedCount--; @@ -547,8 +526,7 @@ void Game::totSub(int8 flags, const char *newTotFile) { _extTable = _extTableArray[_backupedCount]; _extHandle = _extHandleArray[_backupedCount]; _imFileData = _imFileDataArray[_backupedCount]; - _vm->_global->_inter_variables = _variablesArray[_backupedCount]; - _vm->_global->_inter_variablesSizes = _variablesSizesArray[_backupedCount]; + _vm->_inter->_variables = _variablesArray[_backupedCount]; strcpy(_curTotFile, _curTotFileArray[_backupedCount]); strcpy(_curExtFile, _curTotFile); _curExtFile[strlen(_curExtFile) - 4] = '\0'; @@ -580,8 +558,7 @@ void Game::switchTotSub(int16 index, int16 skipPlay) { _extTableArray[_backupedCount] = _extTable; _extHandleArray[_backupedCount] = _extHandle; _imFileDataArray[_backupedCount] = _imFileData; - _variablesArray[_backupedCount] = _vm->_global->_inter_variables; - _variablesSizesArray[_backupedCount] = _vm->_global->_inter_variablesSizes; + _variablesArray[_backupedCount] = _vm->_inter->_variables; strcpy(_curTotFileArray[_backupedCount], _curTotFile); _backupedCount++; } @@ -597,8 +574,7 @@ void Game::switchTotSub(int16 index, int16 skipPlay) { _imFileData = _imFileDataArray[_curBackupPos]; _extTable = _extTableArray[_curBackupPos]; _extHandle = _extHandleArray[_curBackupPos]; - _vm->_global->_inter_variables = _variablesArray[_curBackupPos]; - _vm->_global->_inter_variablesSizes = _variablesSizesArray[_curBackupPos]; + _vm->_inter->_variables = _variablesArray[_curBackupPos]; strcpy(_curTotFile, _curTotFileArray[_curBackupPos]); strcpy(_curExtFile, _curTotFile); _curExtFile[strlen(_curExtFile) - 4] = '\0'; @@ -625,8 +601,7 @@ void Game::switchTotSub(int16 index, int16 skipPlay) { _extTable = _extTableArray[_curBackupPos]; _extHandle = _extHandleArray[_curBackupPos]; _imFileData = _imFileDataArray[_curBackupPos]; - _vm->_global->_inter_variables = _variablesArray[_curBackupPos]; - _vm->_global->_inter_variablesSizes = _variablesSizesArray[_curBackupPos]; + _vm->_inter->_variables = _variablesArray[_curBackupPos]; strcpy(_curTotFile, _curTotFileArray[_curBackupPos]); strcpy(_curExtFile, _curTotFile); _curExtFile[strlen(_curExtFile) - 4] = '\0'; diff --git a/engines/gob/game.h b/engines/gob/game.h index 5cf5e1bea6..15f6ab963a 100644 --- a/engines/gob/game.h +++ b/engines/gob/game.h @@ -26,9 +26,7 @@ #ifndef GOB_GAME_H #define GOB_GAME_H -#include "sound/mods/infogrames.h" - -#include "gob/sound.h" +#include "gob/variables.h" namespace Gob { @@ -119,12 +117,6 @@ public: int16 _extHandle; - SoundDesc _soundSamples[60]; - - Audio::Infogrames::Instruments *_infIns; - Audio::Infogrames *_infogrames; - Audio::SoundHandle _infHandle; - char _totToLoad[20]; int32 _startTimeKey; @@ -210,9 +202,8 @@ protected: ExtTable *_extTableArray[5]; int16 _extHandleArray[5]; byte *_imFileDataArray[5]; - byte *_variablesArray[5]; + Variables *_variablesArray[5]; char _curTotFileArray[5][14]; - byte *_variablesSizesArray[5]; GobEngine *_vm; diff --git a/engines/gob/game_v1.cpp b/engines/gob/game_v1.cpp index e9e37a027b..66deea8ec4 100644 --- a/engines/gob/game_v1.cpp +++ b/engines/gob/game_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/stream.h" @@ -32,15 +31,13 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" -#include "gob/music.h" -#include "gob/cdrom.h" #include "gob/draw.h" #include "gob/inter.h" #include "gob/mult.h" #include "gob/video.h" #include "gob/parse.h" -#include "gob/sound.h" #include "gob/scenery.h" +#include "gob/sound/sound.h" namespace Gob { @@ -74,11 +71,11 @@ void Game_v1::playTot(int16 skipPlay) { _vm->_draw->_fontToSprite[i].height = -1; } - if (_vm->_platform == Common::kPlatformMacintosh) { - if (_vm->_adlib) - _vm->_adlib->stopPlay(); - } else - _vm->_cdrom->stopPlaying(); + if (_vm->getPlatform() == Common::kPlatformMacintosh) + _vm->_sound->adlibStop(); + else + _vm->_sound->cdStop(); + _vm->_draw->animateCursor(4); _vm->_inter->initControlVars(1); _vm->_mult->initAll(); @@ -169,12 +166,8 @@ void Game_v1::playTot(int16 skipPlay) { _vm->_global->_inter_animDataSize = READ_LE_UINT16(_totFileData + 0x38); - if (!_vm->_global->_inter_variables) { - variablesCount = READ_LE_UINT16(_totFileData + 0x2C); - _vm->_global->_inter_variables = new byte[variablesCount * 4]; - _vm->_global->_inter_variablesSizes = new byte[variablesCount * 4]; - _vm->_global->clearVars(variablesCount); - } + if (!_vm->_inter->_variables) + _vm->_inter->allocateVars(READ_LE_UINT16(_totFileData + 0x2C)); _vm->_global->_inter_execPtr = _totFileData; _vm->_global->_inter_execPtr += READ_LE_UINT32(_totFileData + 0x64); @@ -229,7 +222,7 @@ void Game_v1::playTot(int16 skipPlay) { for (int i = 0; i < SPRITES_COUNT; i++) _vm->_draw->freeSprite(i); - _vm->_snd->stopSound(0); + _vm->_sound->blasterStop(0); for (int i = 0; i < 20; i++) freeSoundSlot(i); diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index 45542541e3..adf75176ab 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/stream.h" @@ -38,9 +37,9 @@ #include "gob/mult.h" #include "gob/parse.h" #include "gob/scenery.h" -#include "gob/sound.h" #include "gob/video.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -55,7 +54,6 @@ void Game_v2::playTot(int16 skipPlay) { int16 _captureCounter; int16 breakFrom; int16 nestLevel; - int32 variablesCount; int32 totSize; byte *filePtr; byte *savedIP; @@ -73,7 +71,7 @@ void Game_v2::playTot(int16 skipPlay) { if (skipPlay <= 0) { while (!_vm->_quitRequested) { - if (_vm->_global->_inter_variables) + if (_vm->_inter->_variables) _vm->_draw->animateCursor(4); if (skipPlay != -1) { @@ -205,12 +203,8 @@ void Game_v2::playTot(int16 skipPlay) { _vm->_global->_inter_animDataSize = READ_LE_UINT16(_totFileData + 0x38); - if (!_vm->_global->_inter_variables) { - variablesCount = READ_LE_UINT16(_totFileData + 0x2C); - _vm->_global->_inter_variables = new byte[variablesCount * 4]; - _vm->_global->_inter_variablesSizes = new byte[variablesCount * 4]; - _vm->_global->clearVars(variablesCount); - } + if (!_vm->_inter->_variables) + _vm->_inter->allocateVars(READ_LE_UINT16(_totFileData + 0x2C)); _vm->_global->_inter_execPtr = _totFileData; _vm->_global->_inter_execPtr += @@ -265,11 +259,14 @@ void Game_v2::playTot(int16 skipPlay) { if (skipPlay != -1) { _vm->_goblin->freeObjects(); - _vm->_snd->stopSound(0); + _vm->_sound->blasterStop(0); + + for (int i = 0; i < Sound::kSoundsCount; i++) { + SoundDesc *sound = _vm->_sound->sampleGetBySlot(i); - for (int i = 0; i < 60; i++) - if (_soundSamples[i].getType() == SOUND_SND) - _vm->_snd->freeSample(_soundSamples[i]); + if (sound && (sound->getType() == SOUND_SND)) + _vm->_sound->sampleFree(sound); + } } _vm->_vidPlayer->primaryClose(); @@ -630,13 +627,15 @@ void Game_v2::collisionsBlock(void) { Collision *collArea; int16 timeKey; byte *savedIP; + byte collAreaStart; if (_shouldPushColls) pushCollisions(0); - collArea = _collisionAreas; - while (collArea->left != 0xFFFF) - collArea++; + collAreaStart = 0; + while (_collisionAreas[collAreaStart].left != 0xFFFF) + collAreaStart++; + collArea = &_collisionAreas[collAreaStart]; _shouldPushColls = 0; collResId = -1; @@ -962,7 +961,7 @@ void Game_v2::collisionsBlock(void) { continue; _activeCollResId = collPtr->id; - _activeCollIndex = i; + _activeCollIndex = i + collAreaStart; _vm->_inter->storeMouse(); if (VAR(16) != 0) break; @@ -1004,7 +1003,7 @@ void Game_v2::collisionsBlock(void) { if ((collPtr->id & 0xF000) == 0x8000) if (++counter == descIndex) { _activeCollResId = collPtr->id; - _activeCollIndex = i; + _activeCollIndex = i + collAreaStart; break; } } @@ -1404,7 +1403,7 @@ int16 Game_v2::inputArea(int16 xPos, int16 yPos, int16 width, int16 height, flag = 1; - if (_vm->_global->_inter_variables) + if (_vm->_inter->_variables) WRITE_VAR(56, pos); while (1) { diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp index 1445601017..acca5564dd 100644 --- a/engines/gob/global.cpp +++ b/engines/gob/global.cpp @@ -123,8 +123,6 @@ Global::Global(GobEngine *vm) : _vm(vm) { _inter_resStr[0] = 0; _inter_resVal = 0; - _inter_variablesSizes = 0; - _inter_variables = 0; _inter_execPtr = 0; _inter_animDataSize = 10; diff --git a/engines/gob/global.h b/engines/gob/global.h index 45c179d277..32651cf15d 100644 --- a/engines/gob/global.h +++ b/engines/gob/global.h @@ -123,8 +123,6 @@ public: char _inter_resStr[200]; int32 _inter_resVal; - byte *_inter_variablesSizes; // 0: single byte, 1: two bytes, 3: four bytes - byte *_inter_variables; byte *_inter_execPtr; int16 _inter_animDataSize; @@ -134,73 +132,11 @@ public: // Can be 1, 2 or 3 for normal, double and triple speed, respectively uint8 _speedFactor; - void clearVars(uint32 count) { - uint32 size = count * 4; - - memset(_inter_variables, 0, size); - memset(_inter_variablesSizes, 0, size); - for (uint32 i = 0; i < size; i += 4) - _inter_variablesSizes[i] = 3; - } - - void writeVarSizeStr(uint32 offset, uint32 len) { - uint32 i; - uint32 inVar; - uint32 varOff; - - inVar = offset % 4; - varOff = (offset >> 2) << 2; - for (i = 0; i < 4; i++) { - if (_inter_variablesSizes[varOff + i] == 3) - _inter_variablesSizes[varOff + i] = 0; - else if ((inVar == (i+1)) && (_inter_variablesSizes[varOff + i] == 1)) - _inter_variablesSizes[varOff + i] = 0; - } - memset(_inter_variablesSizes + offset, 0, len); - } - - void writeVar(uint32 offset, uint32 val) { - WRITE_UINT32(_inter_variables + offset, val); - writeVarSize(offset, 3); - } - void writeVar(uint32 offset, uint16 val) { - WRITE_UINT16(_inter_variables + offset, val); - writeVarSize(offset, 1); - } - void writeVar(uint32 offset, uint8 val) { - (*(uint8 *)(_inter_variables + offset)) = val; - writeVarSize(offset, 0); - } - void writeVar(uint32 offset, const char *str) { - writeVarSizeStr(offset, strlen(str)); - strcpy((char *) (_inter_variables + offset), str); - } - Global(GobEngine *vm); ~Global(); protected: GobEngine *_vm; - - void writeVarSize(uint32 offset, byte n) { - uint32 i; - uint32 inVar; - uint32 varOff; - - inVar = offset % 4; - varOff = (offset >> 2) << 2; - for (i = 0; i < 4; i++) { - if (_inter_variablesSizes[varOff + i] == 3) - _inter_variablesSizes[varOff + i] = 0; - else if ((inVar == (i+1)) && (_inter_variablesSizes[varOff + i] == 1)) - _inter_variablesSizes[varOff + i] = 0; - } - - _inter_variablesSizes[offset] = n; - for (; n > 0; n--) - _inter_variablesSizes[offset + n] = 0; - } - }; } // End of namespace Gob diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 863665357b..a3fe0ebbe2 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/events.h" @@ -37,18 +36,16 @@ #include "gob/util.h" #include "gob/dataio.h" #include "gob/game.h" -#include "gob/sound.h" +#include "gob/sound/sound.h" #include "gob/init.h" #include "gob/inter.h" #include "gob/draw.h" -#include "gob/cdrom.h" #include "gob/goblin.h" #include "gob/map.h" #include "gob/mult.h" #include "gob/palanim.h" #include "gob/parse.h" #include "gob/scenery.h" -#include "gob/music.h" #include "gob/videoplayer.h" #include "gob/saveload.h" @@ -71,13 +68,14 @@ const Common::Language GobEngine::_gobToScummVMLang[] = { GobEngine::GobEngine(OSystem *syst) : Engine(syst) { _vm = this; - _snd = 0; _adlib = 0; _mult = 0; - _game = 0; _global = 0; _cdrom = 0; - _dataIO = 0; _goblin = 0; _vidPlayer = 0; - _init = 0; _inter = 0; _map = 0; - _palAnim = 0; _parse = 0; _scenery = 0; - _draw = 0; _util = 0; _video = 0; - _saveLoad = 0; + _sound = 0; _mult = 0; _game = 0; + _global = 0; _dataIO = 0; _goblin = 0; + _vidPlayer = 0; _init = 0; _inter = 0; + _map = 0; _palAnim = 0; _parse = 0; + _scenery = 0; _draw = 0; _util = 0; + _video = 0; _saveLoad = 0; + + _pauseStart = 0; // Setup mixer _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); @@ -89,21 +87,24 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) { Common::addSpecialDebugLevel(kDebugFuncOp, "FuncOpcodes", "Script FuncOpcodes debug level"); Common::addSpecialDebugLevel(kDebugDrawOp, "DrawOpcodes", "Script DrawOpcodes debug level"); Common::addSpecialDebugLevel(kDebugGobOp, "GoblinOpcodes", "Script GoblinOpcodes debug level"); - Common::addSpecialDebugLevel(kDebugMusic, "Music", "CD, Adlib and Infogrames music debug level"); + Common::addSpecialDebugLevel(kDebugSound, "Sound", "Sound output debug level"); Common::addSpecialDebugLevel(kDebugParser, "Parser", "Parser debug level"); Common::addSpecialDebugLevel(kDebugGameFlow, "Gameflow", "Gameflow debug level"); Common::addSpecialDebugLevel(kDebugFileIO, "FileIO", "File Input/Output debug level"); + Common::addSpecialDebugLevel(kDebugSaveLoad, "SaveLoad", "Saving/Loading debug level"); Common::addSpecialDebugLevel(kDebugGraphics, "Graphics", "Graphics debug level"); + Common::addSpecialDebugLevel(kDebugVideo, "Video", "IMD/VMD video debug level"); Common::addSpecialDebugLevel(kDebugCollisions, "Collisions", "Collisions debug level"); syst->getEventManager()->registerRandomSource(_rnd, "gob"); } GobEngine::~GobEngine() { + deinitGameParts(); + // Stop all mixer streams (except for the permanent ones). _vm->_mixer->stopAll(); - deinitGameParts(); delete[] _startTot; delete[] _startTot0; } @@ -118,6 +119,12 @@ void GobEngine::shutdown() { _quitRequested = true; } +const char *GobEngine::getLangDesc(int16 language) const { + if ((language < 0) || (language > 8)) + language = 2; + return Common::getLanguageDescription(_gobToScummVMLang[language]); +} + void GobEngine::validateLanguage() { if (_vm->_global->_languageWanted != _vm->_global->_language) { warning("Your game version doesn't support the requested language %s", @@ -140,6 +147,30 @@ void GobEngine::validateVideoMode(int16 videoMode) { error("Video mode 0x%X is not supported!", videoMode); } +Common::Platform GobEngine::getPlatform() const { + return _platform; +} + +GameType GobEngine::getGameType() const { + return _gameType; +} + +bool GobEngine::isCD() const { + return (_features & kFeaturesCD) != 0; +} + +bool GobEngine::isEGA() const { + return (_features & kFeaturesEGA) != 0; +} + +bool GobEngine::is640() const { + return (_features & kFeatures640) != 0; +} + +bool GobEngine::hasAdlib() const { + return (_features & kFeaturesAdlib) != 0; +} + int GobEngine::init() { if (!initGameParts()) { GUIErrorMessage("GobEngine::init(): Unknown version of game engine"); @@ -219,8 +250,26 @@ int GobEngine::init() { return 0; } +void GobEngine::pauseEngineIntern(bool pause) { + if (pause) { + _pauseStart = _system->getMillis(); + } else { + uint32 duration = _system->getMillis() - _pauseStart; + + _vm->_vidPlayer->notifyPaused(duration); + + _vm->_game->_startTimeKey += duration; + _vm->_draw->_cursorTimeKey += duration; + if (_vm->_inter->_soundEndTimeKey != 0) + _vm->_inter->_soundEndTimeKey += duration; + } + + _mixer->pauseAll(pause); +} + bool GobEngine::initGameParts() { - _adlib = 0; + _noMusic = MidiDriver::parseMusicDriver(ConfMan.get("music_driver")) == MD_NULL; + _saveLoad = 0; _global = new Global(this); @@ -228,8 +277,7 @@ bool GobEngine::initGameParts() { _dataIO = new DataIO(this); _palAnim = new PalAnim(this); _vidPlayer = new VideoPlayer(this); - _cdrom = new CDROM(this); - _snd = new Snd(this); + _sound = new Sound(this); switch (_gameType) { case kGameTypeGob1: @@ -327,7 +375,7 @@ bool GobEngine::initGameParts() { _map = new Map_v4(this); _goblin = new Goblin_v4(this); _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v3(this, _targetName.c_str()); + _saveLoad = new SaveLoad_v4(this, _targetName.c_str()); break; default: @@ -336,10 +384,6 @@ bool GobEngine::initGameParts() { break; } - _noMusic = MidiDriver::parseMusicDriver(ConfMan.get("music_driver")) == MD_NULL; - if (!_noMusic && hasAdlib()) - _adlib = new Adlib(this); - if (is640()) { _video->_surfWidth = _width = 640; _video->_surfHeight = _video->_splitHeight1 = _height = 480; @@ -360,15 +404,12 @@ bool GobEngine::initGameParts() { } void GobEngine::deinitGameParts() { - delete _snd; _snd = 0; - delete _adlib; _adlib = 0; + delete _saveLoad; _saveLoad = 0; delete _mult; _mult = 0; + delete _vidPlayer; _vidPlayer = 0; delete _game; _game = 0; delete _global; _global = 0; - delete _cdrom; _cdrom = 0; - delete _dataIO; _dataIO = 0; delete _goblin; _goblin = 0; - delete _vidPlayer; _vidPlayer = 0; delete _init; _init = 0; delete _inter; _inter = 0; delete _map; _map = 0; @@ -378,7 +419,8 @@ void GobEngine::deinitGameParts() { delete _draw; _draw = 0; delete _util; _util = 0; delete _video; _video = 0; - delete _saveLoad; _saveLoad = 0; + delete _sound; _sound = 0; + delete _dataIO; _dataIO = 0; } } // End of namespace Gob diff --git a/engines/gob/gob.h b/engines/gob/gob.h index e23e917a7c..ae2b53bc31 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -35,11 +35,10 @@ namespace Gob { class Game; -class Snd; +class Sound; class Video; class Global; class Draw; -class CDROM; class DataIO; class Goblin; class VideoPlayer; @@ -52,31 +51,33 @@ class Parse; class Scenery; class Util; class SaveLoad; -class Adlib; - -#define VARP(offs) (_vm->_global->_inter_variables + (offs)) -#define WRITE_VARO_UINT32(offs, val) _vm->_global->writeVar(offs, (uint32) (val)) -#define WRITE_VARO_UINT16(offs, val) _vm->_global->writeVar(offs, (uint16) (val)) -#define WRITE_VARO_UINT8(offs, val) _vm->_global->writeVar(offs, (uint8) (val)) -#define WRITE_VARO_STR(offs, str) _vm->_global->writeVar(offs, (const char *) (str)) -#define WRITE_VAR_UINT32(var, val) WRITE_VARO_UINT32((var) << 2, (val)) -#define WRITE_VAR_UINT16(var, val) WRITE_VARO_UINT16((var) << 2, (val)) -#define WRITE_VAR_UINT8(var, val) WRITE_VARO_UINT8((var) << 2, (val)) -#define WRITE_VAR_STR(var, str) WRITE_VARO_STR((var) << 2, (str)) -#define READ_VARO_UINT32(offs) READ_UINT32(VARP(offs)) -#define READ_VARO_UINT16(offs) READ_UINT16(VARP(offs)) -#define READ_VARO_UINT8(offs) (*((uint8 *) VARP(offs))) -#define READ_VAR_UINT32(var) READ_VARO_UINT32((var) << 2) -#define READ_VAR_UINT16(var) READ_VARO_UINT16((var) << 2) -#define READ_VAR_UINT8(var) READ_VARO_UINT8((var) << 2) -#define GET_VARO_STR(offs) ((char *) VARP(offs)) -#define GET_VAR_STR(var) GET_VARO_STR((var) << 2) - -#define WRITE_VAR_OFFSET(offs, val) WRITE_VARO_UINT32((offs), (val)) -#define WRITE_VAR(var, val) WRITE_VAR_UINT32((var), (val)) -#define VAR_OFFSET(offs) READ_VARO_UINT32(offs) -#define VAR(var) READ_VAR_UINT32(var) -#define VAR_ADDRESS(var) ((uint32 *) VARP((var) << 2)) + +#define WRITE_VAR_UINT32(var, val) _vm->_inter->_variables->writeVar32(var, val) +#define WRITE_VAR_UINT16(var, val) _vm->_inter->_variables->writeVar16(var, val) +#define WRITE_VAR_UINT8(var, val) _vm->_inter->_variables->writeVar8(var, val) +#define WRITE_VAR_STR(var, str) _vm->_inter->_variables->writeVarString(var, str) +#define WRITE_VARO_UINT32(off, val) _vm->_inter->_variables->writeOff32(off, val) +#define WRITE_VARO_UINT16(off, val) _vm->_inter->_variables->writeOff16(off, val) +#define WRITE_VARO_UINT8(off, val) _vm->_inter->_variables->writeOff8(off, val) +#define WRITE_VARO_STR(off, str) _vm->_inter->_variables->writeOffString(off, str) +#define READ_VAR_UINT32(var) _vm->_inter->_variables->readVar32(var) +#define READ_VAR_UINT16(var) _vm->_inter->_variables->readVar16(var) +#define READ_VAR_UINT8(var) _vm->_inter->_variables->readVar8(var) +#define READ_VARO_UINT32(off) _vm->_inter->_variables->readOff32(off) +#define READ_VARO_UINT16(off) _vm->_inter->_variables->readOff16(off) +#define READ_VARO_UINT8(off) _vm->_inter->_variables->readOff8(off) +#define GET_VAR_STR(var) _vm->_inter->_variables->getAddressVarString(var, 0) +#define GET_VARO_STR(off) _vm->_inter->_variables->getAddressOffString(off, 0) +#define GET_VAR_FSTR(var) _vm->_inter->_variables->getAddressVarString(var) +#define GET_VARO_FSTR(off) _vm->_inter->_variables->getAddressOffString(off) + +#define VAR_ADDRESS(var) _vm->_inter->_variables->getAddressVar32(var) + +#define WRITE_VAR_OFFSET(off, val) WRITE_VARO_UINT32((off), (val)) +#define WRITE_VAR(var, val) WRITE_VAR_UINT32((var), (val)) +#define VAR_OFFSET(off) READ_VARO_UINT32(off) +#define VAR(var) READ_VAR_UINT32(var) + enum GameType { kGameTypeNone = 0, @@ -102,12 +103,14 @@ enum { kDebugFuncOp = 1 << 0, kDebugDrawOp = 1 << 1, kDebugGobOp = 1 << 2, - kDebugMusic = 1 << 3, // CD, Adlib and Infogrames music + kDebugSound = 1 << 3, kDebugParser = 1 << 4, kDebugGameFlow = 1 << 5, kDebugFileIO = 1 << 6, - kDebugGraphics = 1 << 7, - kDebugCollisions = 1 << 8 + kDebugSaveLoad = 1 << 7, + kDebugGraphics = 1 << 8, + kDebugVideo = 1 << 9, + kDebugCollisions = 1 << 10 }; inline char *strncpy0(char *dest, const char *src, size_t n) { @@ -171,12 +174,19 @@ private: struct GOBGameDescription; class GobEngine : public Engine { -protected: +private: GobEngine *_vm; + GameType _gameType; + int32 _features; + Common::Platform _platform; + + uint32 _pauseStart; + int go(); int init(); + void pauseEngineIntern(bool pause); bool initGameParts(); void deinitGameParts(); @@ -185,11 +195,7 @@ public: Common::RandomSource _rnd; - GameType _gameType; - int32 _features; Common::Language _language; - Common::Platform _platform; - uint16 _width; uint16 _height; uint8 _mode; @@ -204,10 +210,9 @@ public: Util *_util; DataIO *_dataIO; Game *_game; - Snd *_snd; + Sound *_sound; Video *_video; Draw *_draw; - CDROM *_cdrom; Goblin *_goblin; Init *_init; Map *_map; @@ -217,24 +222,20 @@ public: Scenery *_scenery; Inter *_inter; SaveLoad *_saveLoad; - Adlib *_adlib; VideoPlayer *_vidPlayer; void shutdown(); - const char *getLangDesc(int16 language) { - if ((language < 0) || (language > 8)) - language = 2; - return Common::getLanguageDescription(_gobToScummVMLang[language]); - } + const char *getLangDesc(int16 language) const; void validateLanguage(); void validateVideoMode(int16 videoMode); - GameType getGameType() { return _gameType; } - bool isCD() { return (_features & kFeaturesCD) != 0; } - bool isEGA() { return (_features & kFeaturesEGA) != 0; } - bool is640() { return (_features & kFeatures640) != 0; } - bool hasAdlib() { return (_features & kFeaturesAdlib) != 0; } + Common::Platform getPlatform() const; + GameType getGameType() const; + bool isCD() const; + bool isEGA() const; + bool is640() const; + bool hasAdlib() const; GobEngine(OSystem *syst); virtual ~GobEngine(); diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index 64a2b15ef4..e7aed0790e 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -32,7 +32,8 @@ #include "gob/map.h" #include "gob/mult.h" #include "gob/scenery.h" -#include "gob/sound.h" +#include "gob/inter.h" +#include "gob/sound/sound.h" namespace Gob { @@ -164,7 +165,7 @@ Goblin::~Goblin() { for (col = 0; col < 6; col++) if (_goblins[i]->realStateMach[state][col]) delete _goblins[i]->realStateMach[state][col]; - delete []_goblins[i]->realStateMach; + delete[] _goblins[i]->realStateMach; } delete _goblins[i]; } @@ -176,7 +177,7 @@ Goblin::~Goblin() { for (col = 0; col < 6; col++) if (_objects[i]->realStateMach[state][col]) delete _objects[i]->realStateMach[state][col]; - delete []_objects[i]->realStateMach; + delete[] _objects[i]->realStateMach; } delete _objects[i]; } @@ -255,8 +256,8 @@ void Goblin::sortByOrder(Util::List *list) { void Goblin::playSound(SoundDesc &snd, int16 repCount, int16 freq) { if (!snd.empty()) { - _vm->_snd->stopSound(0); - _vm->_snd->playSample(snd, repCount, freq); + _vm->_sound->blasterStop(0); + _vm->_sound->blasterPlay(&snd, repCount, freq); } } @@ -1216,7 +1217,7 @@ void Goblin::zeroObjects(void) { _objects[i] = 0; for (int i = 0; i < 16; i++) - _vm->_snd->freeSample(_soundData[i]); + _vm->_sound->sampleFree(&_soundData[i]); } void Goblin::freeAllObjects(void) { @@ -1717,12 +1718,12 @@ void Goblin::playSounds(Mult::Mult_Object *obj) { if (!speaker) { sndSlot = obj->goblinStates[animData->state][i].sndItem; - _vm->_snd->stopSound(0); + _vm->_sound->blasterStop(0); if (sndSlot < _soundSlotsCount) - _vm->_snd->playSample(_vm->_game->_soundSamples[_soundSlots[sndSlot] & 0x7FFF], + _vm->_sound->blasterPlay(_vm->_sound->sampleGetBySlot(_soundSlots[sndSlot] & 0x7FFF), repCount, frequency); } else - _vm->_snd->speakerOn(frequency, repCount * 10); + _vm->_sound->speakerOn(frequency, repCount * 10); } } diff --git a/engines/gob/goblin.h b/engines/gob/goblin.h index f7ac4aa549..3fd8a9f93b 100644 --- a/engines/gob/goblin.h +++ b/engines/gob/goblin.h @@ -27,8 +27,8 @@ #define GOB_GOBLIN_H #include "gob/util.h" -#include "gob/sound.h" #include "gob/mult.h" +#include "gob/sound/sounddesc.h" namespace Gob { diff --git a/engines/gob/goblin_v1.cpp b/engines/gob/goblin_v1.cpp index f7bdbf10a5..6ac086767b 100644 --- a/engines/gob/goblin_v1.cpp +++ b/engines/gob/goblin_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -32,7 +31,7 @@ #include "gob/map.h" #include "gob/mult.h" #include "gob/scenery.h" -#include "gob/sound.h" +#include "gob/sound/sound.h" namespace Gob { @@ -48,7 +47,7 @@ void Goblin_v1::freeObjects(void) { int16 col; for (int i = 0; i < 16; i++) - _vm->_snd->freeSample(_soundData[i]); + _vm->_sound->sampleFree(&_soundData[i]); for (int i = 0; i < 4; i++) { if (_goblins[i] == 0) @@ -488,19 +487,19 @@ void Goblin_v1::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc, if ((gobDesc->state >= 0) && (gobDesc->state < 10) && (gobDesc->stateMach == gobDesc->realStateMach) && ((gobDesc->curFrame == 3) || (gobDesc->curFrame == 6))) { - _vm->_snd->speakerOn(10 * _vm->_util->getRandom(3) + 50, 5); + _vm->_sound->speakerOn(10 * _vm->_util->getRandom(3) + 50, 5); } if ((_currentGoblin == 0) && (gobDesc->stateMach == gobDesc->realStateMach) && ((gobDesc->state == 10) || (gobDesc->state == 11)) && (gobDesc->curFrame == 9)) { - _vm->_snd->stopSound(0); + _vm->_sound->blasterStop(0); if (_itemIndInPocket != -1) - _vm->_snd->playSample(_soundData[14], 1, 9000); + _vm->_sound->blasterPlay(&_soundData[14], 1, 9000); else - _vm->_snd->playSample(_soundData[14], 1, 5000); + _vm->_sound->blasterPlay(&_soundData[14], 1, 5000); } if (_boreCounter++ == 120) { diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp index c9e155ad08..9144e35070 100644 --- a/engines/gob/goblin_v2.cpp +++ b/engines/gob/goblin_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -34,6 +33,7 @@ #include "gob/map.h" #include "gob/mult.h" #include "gob/scenery.h" +#include "gob/inter.h" namespace Gob { diff --git a/engines/gob/goblin_v4.cpp b/engines/gob/goblin_v4.cpp index 167946e30d..1df5aab606 100644 --- a/engines/gob/goblin_v4.cpp +++ b/engines/gob/goblin_v4.cpp @@ -29,6 +29,7 @@ #include "gob/mult.h" #include "gob/map.h" #include "gob/scenery.h" +#include "gob/inter.h" namespace Gob { diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index 4d184c53d3..c2f8b48626 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -31,13 +30,13 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" -#include "gob/cdrom.h" #include "gob/draw.h" #include "gob/game.h" #include "gob/palanim.h" -#include "gob/sound.h" +#include "gob/inter.h" #include "gob/video.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -51,8 +50,8 @@ void Init::cleanup(void) { _vm->_video->freeDriver(); _vm->_global->_primarySurfDesc = 0; - _vm->_snd->speakerOff(); - _vm->_snd->stopSound(0); + _vm->_sound->speakerOff(); + _vm->_sound->blasterStop(0); _vm->_dataIO->closeDataFile(); } @@ -64,7 +63,6 @@ void Init::initGame(const char *totName) { char *infPtr; char *infEnd; char buffer[128]; - int32 varsCount; initVideo(); @@ -92,8 +90,6 @@ void Init::initGame(const char *totName) { _vm->_game->_totTextData = 0; _vm->_game->_totFileData = 0; _vm->_game->_totResourceTable = 0; - _vm->_global->_inter_variables = 0; - _vm->_global->_inter_variablesSizes = 0; _palDesc = new Video::PalDesc; _vm->validateVideoMode(_vm->_global->_videoMode); @@ -159,18 +155,14 @@ void Init::initGame(const char *totName) { DataStream *stream = _vm->_dataIO->openAsStream(handle, true); stream->seek(0x2C); - varsCount = stream->readUint16LE(); + _vm->_inter->allocateVars(stream->readUint16LE()); delete stream; - _vm->_global->_inter_variables = new byte[varsCount * 4]; - _vm->_global->_inter_variablesSizes = new byte[varsCount * 4]; - _vm->_global->clearVars(varsCount); - strcpy(_vm->_game->_curTotFile, buffer); - _vm->_cdrom->testCD(1, "GOB"); - _vm->_cdrom->readLIC("gob.lic"); + _vm->_sound->cdTest(1, "GOB"); + _vm->_sound->cdLoadLIC("gob.lic"); // Search for a Coktel logo animation or image to display imdHandle = _vm->_dataIO->openData("coktel.imd"); @@ -213,11 +205,9 @@ void Init::initGame(const char *totName) { _vm->_game->start(); - _vm->_cdrom->stopPlaying(); - _vm->_cdrom->freeLICbuffer(); + _vm->_sound->cdStop(); + _vm->_sound->cdUnloadLIC(); - delete[] _vm->_global->_inter_variables; - delete[] _vm->_global->_inter_variablesSizes; delete[] _vm->_game->_totFileData; if (_vm->_game->_totTextData) { if (_vm->_game->_totTextData->items) diff --git a/engines/gob/init_v1.cpp b/engines/gob/init_v1.cpp index 8065c4dc8c..90456f927c 100644 --- a/engines/gob/init_v1.cpp +++ b/engines/gob/init_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" diff --git a/engines/gob/init_v2.cpp b/engines/gob/init_v2.cpp index bb29f4e8fd..b468c15c25 100644 --- a/engines/gob/init_v2.cpp +++ b/engines/gob/init_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -50,8 +49,8 @@ void Init_v2::initVideo() { _vm->_global->_inVM = 0; _vm->_global->_colorCount = 16; - if (((_vm->_platform == Common::kPlatformPC) || - (_vm->_platform == Common::kPlatformMacintosh)) && + if (((_vm->getPlatform() == Common::kPlatformPC) || + (_vm->getPlatform() == Common::kPlatformMacintosh)) && ((_vm->_global->_videoMode == 0x13) || (_vm->_global->_videoMode == 0x14))) _vm->_global->_colorCount = 256; diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index de3ac4b1f5..9c39653a1d 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -23,6 +23,7 @@ * */ +#include <time.h> // FIXME: for Inter::renewTimeInVars() #include "common/endian.h" @@ -34,9 +35,7 @@ #include "gob/game.h" #include "gob/parse.h" #include "gob/scenery.h" -#include "gob/sound.h" - -#include <time.h> // FIXME: for Inter::renewTimeInVars() +#include "gob/sound/sound.h" namespace Gob { @@ -61,6 +60,12 @@ Inter::Inter(GobEngine *vm) : _vm(vm) { _pastePos = 0; _noBusyWait = false; + + _variables = 0; +} + +Inter::~Inter() { + delocateVars(); } void Inter::initControlVars(char full) { @@ -154,7 +159,7 @@ void Inter::storeKey(int16 key) { WRITE_VAR(12, _vm->_util->getTimeKey() - _vm->_game->_startTimeKey); storeMouse(); - WRITE_VAR(1, _vm->_snd->_playingSound); + WRITE_VAR(1, _vm->_sound->blasterPlayingSound()); if (key == 0x4800) key = 0x0B; @@ -280,4 +285,18 @@ void Inter::callSub(int16 retFlag) { _terminate = 1; } +void Inter::allocateVars(uint32 count) { + if ((_vm->getPlatform() == Common::kPlatformAmiga) || + (_vm->getPlatform() == Common::kPlatformMacintosh) || + (_vm->getPlatform() == Common::kPlatformAtariST)) + _variables = new VariablesBE(count * 4); + else + _variables = new VariablesLE(count * 4); +} + +void Inter::delocateVars() { + delete _variables; + _variables = 0; +} + } // End of namespace Gob diff --git a/engines/gob/inter.h b/engines/gob/inter.h index 582e57a2d4..60b3974d6d 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -27,6 +27,7 @@ #define GOB_INTER_H #include "gob/goblin.h" +#include "gob/variables.h" namespace Gob { @@ -48,6 +49,8 @@ public: uint32 _soundEndTimeKey; int16 _soundStopVal; + Variables *_variables; + void initControlVars(char full); int16 load16(); char evalExpr(int16 *pRes); @@ -59,11 +62,14 @@ public: void funcBlock(int16 retFlag); void callSub(int16 retFlag); + void allocateVars(uint32 count); + void delocateVars(); + virtual int16 loadSound(int16 slot) = 0; virtual void animPalette() = 0; Inter(GobEngine *vm); - virtual ~Inter() {} + virtual ~Inter(); protected: struct OpFuncParams { @@ -83,7 +89,7 @@ protected: int16 _animPalHighIndex[8]; int16 _animPalDir[8]; - char _pasteBuf[300]; + byte _pasteBuf[300]; byte _pasteSizeBuf[300]; int16 _pastePos; @@ -519,6 +525,7 @@ protected: virtual const char *getOpcodeFuncDesc(byte i, byte j); virtual const char *getOpcodeGoblinDesc(int i); + void o4_initScreen(); void o4_playVmdOrMusic(); }; diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index 702950d539..d493fb00d3 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -34,9 +33,9 @@ #include "gob/draw.h" #include "gob/game.h" #include "gob/palanim.h" -#include "gob/sound.h" #include "gob/video.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -768,9 +767,9 @@ void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { return; for (i = 0; i < 4; i++) - _vm->_snd->loadSample(samples[i], sndFiles[i]); - _vm->_snd->playComposition(comp, 0, samples, 4); - _vm->_snd->waitEndPlay(true, false); + _vm->_sound->sampleLoad(&samples[i], sndFiles[i]); + _vm->_sound->blasterPlayComposition(comp, 0, samples, 4); + _vm->_sound->blasterWaitEndPlay(true, false); _vm->_palAnim->fade(0, 0, 0); _vm->_video->clearSurf(_vm->_draw->_frontSurface); } @@ -787,12 +786,12 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { static const char *palFiles[] = {"2ou2.clt", "2ou3.clt", "2ou4.clt", "2ou5.clt"}; for (int i = 0; i < 2; i++) - _vm->_snd->loadSample(samples[i], sndFiles[i]); + _vm->_sound->sampleLoad(&samples[i], sndFiles[i]); for (int i = 0; i < 4; i++) palettes[i] = _vm->_dataIO->getData(palFiles[i]); palBak = _vm->_global->_pPaletteDesc->vgaPal; - _vm->_snd->playComposition(comp, 0, samples, 2); + _vm->_sound->blasterPlayComposition(comp, 0, samples, 2); for (int i = 0; i < 20; i++) { for (int j = 0; j < 4; j++) { _vm->_global->_pPaletteDesc->vgaPal = (Video::Color *) palettes[j]; @@ -801,7 +800,7 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { } if ((_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B) || _vm->_quitRequested) { - _vm->_snd->stopSound(10); + _vm->_sound->blasterStop(10); _vm->_palAnim->fade(0, -2, 0); _vm->_video->clearSurf(_vm->_draw->_frontSurface); memset((char *) _vm->_draw->_vgaPalette, 0, 768); @@ -811,7 +810,7 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { break; } } - _vm->_snd->waitEndPlay(false, false); + _vm->_sound->blasterWaitEndPlay(false, false); _vm->_global->_pPaletteDesc->vgaPal = palBak; for (int i = 0; i < 4; i++) diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index 9707a628b4..e2b8d65112 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/file.h" @@ -32,8 +31,6 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" -#include "gob/music.h" -#include "gob/cdrom.h" #include "gob/draw.h" #include "gob/game.h" #include "gob/goblin.h" @@ -43,8 +40,8 @@ #include "gob/palanim.h" #include "gob/parse.h" #include "gob/scenery.h" -#include "gob/sound.h" #include "gob/video.h" +#include "gob/sound/sound.h" namespace Gob { @@ -932,16 +929,16 @@ void Inter_v1::o1_initMult() { _vm->_mult->_objCount * sizeof(Mult::Mult_Object)); for (int i = 0; i < _vm->_mult->_objCount; i++) { - _vm->_mult->_objects[i].pPosX = - (int32 *)(_vm->_global->_inter_variables + - i * 4 + (posXVar / 4) * 4); - _vm->_mult->_objects[i].pPosY = - (int32 *)(_vm->_global->_inter_variables + - i * 4 + (posYVar / 4) * 4); + uint32 offPosX = i * 4 + (posXVar / 4) * 4; + uint32 offPosY = i * 4 + (posYVar / 4) * 4; + uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; + + _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX); + _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY); _vm->_mult->_objects[i].pAnimData = - (Mult::Mult_AnimData *) (_vm->_global->_inter_variables + - animDataVar + i * 4 * _vm->_global->_inter_animDataSize); + (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, + _vm->_global->_inter_animDataSize); _vm->_mult->_objects[i].pAnimData->isStatic = 1; _vm->_mult->_objects[i].tick = 0; @@ -1071,12 +1068,8 @@ void Inter_v1::o1_loadCurLayer() { void Inter_v1::o1_playCDTrack() { evalExpr(0); - if (_vm->_platform == Common::kPlatformMacintosh) { - if (_vm->_adlib) - _vm->_adlib->playTrack(_vm->_global->_inter_resStr); - } else - // Used in gob1 CD - _vm->_cdrom->startTrack(_vm->_global->_inter_resStr); + _vm->_sound->adlibPlayBgMusic(); // Mac version + _vm->_sound->cdPlay(_vm->_global->_inter_resStr); // PC CD version } void Inter_v1::o1_getCDTrackPos() { @@ -1088,19 +1081,15 @@ void Inter_v1::o1_getCDTrackPos() { _vm->_util->longDelay(1); - int pos = _vm->_cdrom->getTrackPos(); + int pos = _vm->_sound->cdGetTrackPos(); if (pos == -1) pos = 32767; WRITE_VAR(5, pos); } void Inter_v1::o1_stopCD() { - if (_vm->_platform == Common::kPlatformMacintosh) { - if (_vm->_adlib) - _vm->_adlib->stopPlay(); - } else - // Used in gob1 CD - _vm->_cdrom->stopPlaying(); + _vm->_sound->adlibStop(); // Mac version + _vm->_sound->cdStop(); // PC CD version } void Inter_v1::o1_loadFontToSprite() { @@ -1685,7 +1674,7 @@ bool Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { break; default: - _vm->_snd->speakerOnUpdate(cmd); + _vm->_sound->speakerOnUpdate(cmd); if (cmd < 20) { _vm->_util->delay(cmd); _noBusyWait = true; @@ -1759,12 +1748,12 @@ bool Inter_v1::o1_renewTimeInVars(OpFuncParams ¶ms) { } bool Inter_v1::o1_speakerOn(OpFuncParams ¶ms) { - _vm->_snd->speakerOn(_vm->_parse->parseValExpr(), -1); + _vm->_sound->speakerOn(_vm->_parse->parseValExpr(), -1); return false; } bool Inter_v1::o1_speakerOff(OpFuncParams ¶ms) { - _vm->_snd->speakerOff(); + _vm->_sound->speakerOff(); return false; } @@ -1978,10 +1967,10 @@ bool Inter_v1::o1_playSound(OpFuncParams ¶ms) { repCount = _vm->_parse->parseValExpr(); frequency = _vm->_parse->parseValExpr(); - SoundDesc &sample = _vm->_game->_soundSamples[index]; + SoundDesc *sample = _vm->_sound->sampleGetBySlot(index); _soundEndTimeKey = 0; - if (sample.empty()) + if (!sample || sample->empty()) return false; if (repCount < 0) { @@ -1991,31 +1980,28 @@ bool Inter_v1::o1_playSound(OpFuncParams ¶ms) { repCount = -repCount; _soundEndTimeKey = _vm->_util->getTimeKey(); - freq2 = frequency ? frequency : sample._frequency; + freq2 = frequency ? frequency : sample->_frequency; endRep = MAX(repCount - 1, 1); - _soundStopVal = sample.calcFadeOutLength(freq2); - _soundEndTimeKey += sample.calcLength(endRep, freq2, true); + _soundStopVal = sample->calcFadeOutLength(freq2); + _soundEndTimeKey += sample->calcLength(endRep, freq2, true); } - if (sample.getType() == SOUND_ADL) { - if (_vm->_adlib) { - _vm->_adlib->load(sample.getData(), sample.size(), index); - _vm->_adlib->setRepeating(repCount - 1); - _vm->_adlib->startPlay(); - } + if (sample->getType() == SOUND_ADL) { + _vm->_sound->adlibLoad(sample->getData(), sample->size(), index); + _vm->_sound->adlibSetRepeating(repCount - 1); + _vm->_sound->adlibPlay(); } else { - _vm->_snd->stopSound(0); - _vm->_snd->playSample(sample, repCount - 1, frequency); + _vm->_sound->blasterStop(0); + _vm->_sound->blasterPlay(sample, repCount - 1, frequency); } return false; } bool Inter_v1::o1_stopSound(OpFuncParams ¶ms) { - if (_vm->_adlib) - _vm->_adlib->stopPlay(); - _vm->_snd->stopSound(_vm->_parse->parseValExpr()); + _vm->_sound->adlibStop(); + _vm->_sound->blasterStop(_vm->_parse->parseValExpr()); _soundEndTimeKey = 0; return false; @@ -2032,7 +2018,7 @@ bool Inter_v1::o1_freeSoundSlot(OpFuncParams ¶ms) { } bool Inter_v1::o1_waitEndPlay(OpFuncParams ¶ms) { - _vm->_snd->waitEndPlay(); + _vm->_sound->blasterWaitEndPlay(); return false; } @@ -2046,7 +2032,7 @@ bool Inter_v1::o1_playComposition(OpFuncParams ¶ms) { for (int i = 0; i < 50; i++) composition[i] = (int16) VAR_OFFSET(dataVar + i * 4); - _vm->_snd->playComposition(composition, freqVal); + _vm->_sound->blasterPlayComposition(composition, freqVal); return false; } @@ -2083,8 +2069,7 @@ bool Inter_v1::o1_prepareStr(OpFuncParams ¶ms) { int16 strVar; strVar = _vm->_parse->parseVarIndex(); - _vm->_util->prepareStr(GET_VARO_STR(strVar)); - _vm->_global->writeVarSizeStr(strVar, strlen(GET_VARO_STR(strVar))); + _vm->_util->prepareStr(GET_VARO_FSTR(strVar)); return false; } @@ -2095,8 +2080,9 @@ bool Inter_v1::o1_insertStr(OpFuncParams ¶ms) { strVar = _vm->_parse->parseVarIndex(); evalExpr(0); pos = _vm->_parse->parseValExpr(); - _vm->_util->insertStr(_vm->_global->_inter_resStr, GET_VARO_STR(strVar), pos); - _vm->_global->writeVarSizeStr(strVar, strlen(GET_VARO_STR(strVar))); + + char *str = GET_VARO_FSTR(strVar); + _vm->_util->insertStr(_vm->_global->_inter_resStr, str, pos); return false; } @@ -2236,7 +2222,7 @@ bool Inter_v1::o1_readData(OpFuncParams ¶ms) { if (((dataVar >> 2) == 59) && (size == 4)) WRITE_VAR(59, stream->readUint32LE()); else - retSize = stream->read(_vm->_global->_inter_variables + dataVar, size); + retSize = stream->read((byte *) _variables->getAddressOff8(dataVar, size), size); if (retSize == size) WRITE_VAR(1, 0); @@ -2803,11 +2789,9 @@ void Inter_v1::o1_animateObjects(OpGobParams ¶ms) { void Inter_v1::o1_drawObjects(OpGobParams ¶ms) { _vm->_goblin->drawObjects(); - if (_vm->_platform == Common::kPlatformMacintosh) { - if (_vm->_adlib) - _vm->_adlib->playBgMusic(); - } else if (_vm->_cdrom->getTrackPos() == -1) - _vm->_cdrom->playBgMusic(); + _vm->_sound->adlibPlayBgMusic(); // Mac version + if (_vm->_sound->cdGetTrackPos() == -1) + _vm->_sound->cdPlayBgMusic(); // PC CD version } void Inter_v1::o1_loadMap(OpGobParams ¶ms) { @@ -2993,9 +2977,11 @@ int16 Inter_v1::loadSound(int16 slot) { dataSize = (uint32) ((int32) totSize); } - if (dataPtr) - _vm->_game->_soundSamples[slot].load(SOUND_SND, source, - dataPtr, dataSize); + if (dataPtr) { + SoundDesc *sample = _vm->_sound->sampleGetBySlot(slot); + if (sample) + sample->load(SOUND_SND, source, dataPtr, dataSize); + } return 0; } diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index be510df08a..d8c33fcce6 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "sound/mixer.h" #include "sound/mods/infogrames.h" @@ -33,8 +32,6 @@ #include "gob/global.h" #include "gob/util.h" #include "gob/dataio.h" -#include "gob/music.h" -#include "gob/cdrom.h" #include "gob/draw.h" #include "gob/game.h" #include "gob/goblin.h" @@ -42,10 +39,10 @@ #include "gob/mult.h" #include "gob/parse.h" #include "gob/scenery.h" -#include "gob/sound.h" #include "gob/video.h" #include "gob/saveload.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -899,26 +896,23 @@ void Inter_v2::o2_initMult() { if (_terminate) return; - _vm->_mult->_orderArray = new uint8[_vm->_mult->_objCount]; + _vm->_mult->_orderArray = new int8[_vm->_mult->_objCount]; memset(_vm->_mult->_orderArray, 0, _vm->_mult->_objCount * sizeof(int8)); _vm->_mult->_objects = new Mult::Mult_Object[_vm->_mult->_objCount]; memset(_vm->_mult->_objects, 0, _vm->_mult->_objCount * sizeof(Mult::Mult_Object)); for (int i = 0; i < _vm->_mult->_objCount; i++) { - _vm->_mult->_objects[i].pPosX = - (int32 *)(_vm->_global->_inter_variables + - i * 4 + (posXVar / 4) * 4); - _vm->_mult->_objects[i].pPosY = - (int32 *)(_vm->_global->_inter_variables + - i * 4 + (posYVar / 4) * 4); + uint32 offPosX = i * 4 + (posXVar / 4) * 4; + uint32 offPosY = i * 4 + (posYVar / 4) * 4; + uint32 offAnim = animDataVar + i * 4 * _vm->_global->_inter_animDataSize; + + _vm->_mult->_objects[i].pPosX = (int32 *) _variables->getAddressOff32(offPosX); + _vm->_mult->_objects[i].pPosY = (int32 *) _variables->getAddressOff32(offPosY); _vm->_mult->_objects[i].pAnimData = - (Mult::Mult_AnimData *) (_vm->_global->_inter_variables + - animDataVar + i * 4 * _vm->_global->_inter_animDataSize); - memset(_vm->_global->_inter_variablesSizes + - i * 4 * _vm->_global->_inter_animDataSize, 0, - _vm->_global->_inter_animDataSize); + (Mult::Mult_AnimData *) _variables->getAddressOff8(offAnim, + _vm->_global->_inter_animDataSize); _vm->_mult->_objects[i].pAnimData->isStatic = 1; _vm->_mult->_objects[i].tick = 0; @@ -1086,16 +1080,18 @@ void Inter_v2::o2_playCDTrack() { _vm->_draw->blitInvalidated(); evalExpr(0); - _vm->_cdrom->startTrack(_vm->_global->_inter_resStr); + _vm->_sound->cdPlay(_vm->_global->_inter_resStr); } void Inter_v2::o2_waitCDTrackEnd() { - while (_vm->_cdrom->getTrackPos() >= 0) + debugC(1, kDebugSound, "CDROM: Waiting for playback to end"); + + while (_vm->_sound->cdGetTrackPos() >= 0) _vm->_util->longDelay(1); } void Inter_v2::o2_stopCD() { - _vm->_cdrom->stopPlaying(); + _vm->_sound->cdStop(); } void Inter_v2::o2_readLIC() { @@ -1105,11 +1101,11 @@ void Inter_v2::o2_readLIC() { strncpy0(path, _vm->_global->_inter_resStr, 35); strcat(path, ".LIC"); - _vm->_cdrom->readLIC(path); + _vm->_sound->cdLoadLIC(path); } void Inter_v2::o2_freeLIC() { - _vm->_cdrom->freeLICbuffer(); + _vm->_sound->cdUnloadLIC(); } void Inter_v2::o2_getCDTrackPos() { @@ -1121,8 +1117,8 @@ void Inter_v2::o2_getCDTrackPos() { varPos = _vm->_parse->parseVarIndex(); varName = _vm->_parse->parseVarIndex(); - WRITE_VAR_OFFSET(varPos, _vm->_cdrom->getTrackPos(GET_VARO_STR(varName))); - WRITE_VARO_STR(varName, _vm->_cdrom->getCurTrack()); + WRITE_VAR_OFFSET(varPos, _vm->_sound->cdGetTrackPos(GET_VARO_STR(varName))); + WRITE_VARO_STR(varName, _vm->_sound->cdGetCurrentTrack()); } void Inter_v2::o2_loadFontToSprite() { @@ -1187,10 +1183,7 @@ void Inter_v2::o2_copyVars() { varOff = _vm->_parse->parseVarIndex(); _vm->_global->_inter_execPtr++; - memcpy(_pasteBuf + _pastePos, _vm->_global->_inter_variables + varOff, - _vm->_global->_inter_animDataSize * 4); - memcpy(_pasteSizeBuf + _pastePos, - _vm->_global->_inter_variablesSizes + varOff, + _variables->copyTo(varOff, _pasteBuf + _pastePos, _pasteSizeBuf + _pastePos, _vm->_global->_inter_animDataSize * 4); _pastePos += _vm->_global->_inter_animDataSize * 4; @@ -1200,6 +1193,7 @@ void Inter_v2::o2_copyVars() { } else { if (evalExpr(&varOff) == 20) _vm->_global->_inter_resVal = 0; + memcpy(_pasteBuf + _pastePos, &_vm->_global->_inter_resVal, 4); memcpy(_pasteSizeBuf + _pastePos, &_vm->_global->_inter_resVal, 4); _pastePos += 4; @@ -1223,8 +1217,7 @@ void Inter_v2::o2_pasteVars() { assert(sizeV == sizeS); _pastePos -= sizeV; - memcpy(_vm->_global->_inter_variables + varOff, _pasteBuf + _pastePos, sizeV); - memcpy(_vm->_global->_inter_variablesSizes + varOff, _pasteSizeBuf + _pastePos, sizeS); + _variables->copyFrom(varOff, _pasteBuf + _pastePos, _pasteSizeBuf + _pastePos, sizeV); } } @@ -1434,46 +1427,17 @@ void Inter_v2::o2_initScreen() { if (height > 0) _vm->_video->_surfHeight = height; - if (videoMode == 0x18) { - - if (_vm->_video->_surfWidth < _vm->_width) - _vm->_video->_screenDeltaX = (_vm->_width - _vm->_video->_surfWidth) / 2; - else - _vm->_video->_screenDeltaX = 0; - - _vm->_global->_mouseMinX = _vm->_video->_screenDeltaX; - _vm->_global->_mouseMaxX = _vm->_video->_screenDeltaX + _vm->_video->_surfWidth - 1; - - - int16 screenHeight = _vm->_video->_surfHeight; - - _vm->_video->_surfHeight += offY; + _vm->_video->_splitHeight1 = MIN<int16>(_vm->_height, _vm->_video->_surfHeight - offY); + _vm->_video->_splitHeight2 = offY; + _vm->_video->_splitStart = _vm->_video->_surfHeight - offY; - _vm->_video->_splitHeight1 = MIN<int16>(_vm->_height, screenHeight - offY); - _vm->_video->_splitHeight2 = offY; - _vm->_video->_splitStart = screenHeight; + _vm->_video->_screenDeltaX = 0; + _vm->_video->_screenDeltaY = 0; - if ((_vm->_video->_surfHeight + offY) < _vm->_height) - _vm->_video->_screenDeltaY = (_vm->_height - (screenHeight + offY)) / 2; - else - _vm->_video->_screenDeltaY = 0; - - _vm->_global->_mouseMaxY = (screenHeight + _vm->_video->_screenDeltaY) - offY - 1; - _vm->_global->_mouseMinY = _vm->_video->_screenDeltaY; - - } else { - _vm->_video->_splitHeight1 = MIN<int16>(_vm->_height, _vm->_video->_surfHeight - offY); - _vm->_video->_splitHeight2 = offY; - _vm->_video->_splitStart = _vm->_video->_surfHeight - offY; - - _vm->_video->_screenDeltaX = 0; - _vm->_video->_screenDeltaY = 0; - - _vm->_global->_mouseMinX = 0; - _vm->_global->_mouseMinY = 0; - _vm->_global->_mouseMaxX = _vm->_width; - _vm->_global->_mouseMaxY = _vm->_height - _vm->_video->_splitHeight2 - 1; - } + _vm->_global->_mouseMinX = 0; + _vm->_global->_mouseMinY = 0; + _vm->_global->_mouseMaxX = _vm->_width; + _vm->_global->_mouseMaxY = _vm->_height - _vm->_video->_splitHeight2 - 1; _vm->_draw->closeScreen(); _vm->_util->clearPalette(); @@ -1532,18 +1496,27 @@ void Inter_v2::o2_scroll() { } void Inter_v2::o2_setScrollOffset() { - int16 offset; + int16 offsetX, offsetY; - offset = _vm->_parse->parseValExpr(); + offsetX = _vm->_parse->parseValExpr(); + offsetY = _vm->_parse->parseValExpr(); - if (offset == -1) { - _vm->_parse->parseValExpr(); + if (offsetX == -1) { WRITE_VAR(2, _vm->_draw->_scrollOffsetX); WRITE_VAR(3, _vm->_draw->_scrollOffsetY); } else { - _vm->_draw->_scrollOffsetX = offset; - _vm->_draw->_scrollOffsetY = _vm->_parse->parseValExpr(); + int16 screenW = _vm->_video->_surfWidth; + int16 screenH = _vm->_video->_surfHeight; + + if (screenW > _vm->_width) + screenW -= _vm->_width; + if (screenH > _vm->_height) + screenH -= _vm->_height; + + _vm->_draw->_scrollOffsetX = CLIP<int16>(offsetX, 0, screenW); + _vm->_draw->_scrollOffsetY = CLIP<int16>(offsetY, 0, screenH); } + _vm->_util->setScrollOffset(); _noBusyWait = true; } @@ -1574,8 +1547,12 @@ void Inter_v2::o2_playImd() { palEnd = _vm->_parse->parseValExpr(); palCmd = 1 << (flags & 0x3F); + debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " + "paletteCmd %d (%d - %d), flags %X", _vm->_global->_inter_resStr, x, y, + startFrame, lastFrame, palCmd, palStart, palEnd, flags); + if ((imd[0] != 0) && !_vm->_vidPlayer->primaryOpen(imd, x, y, flags)) { - WRITE_VAR(11, -1); + WRITE_VAR(11, (uint32) -1); return; } @@ -1607,6 +1584,12 @@ void Inter_v2::o2_getImdInfo() { varWidth = _vm->_parse->parseVarIndex(); varHeight = _vm->_parse->parseVarIndex(); + // WORKAROUND: The nut rolling animation in the administration center + // in Woodruff is called "noixroul", but the scripts think it's "noixroule". + if ((_vm->getGameType() == kGameTypeWoodruff) && + (!scumm_stricmp(_vm->_global->_inter_resStr, "noixroule"))) + strcpy(_vm->_global->_inter_resStr, "noixroul"); + _vm->_vidPlayer->writeVideoInfo(_vm->_global->_inter_resStr, varX, varY, varFrames, varWidth, varHeight); } @@ -1883,10 +1866,9 @@ bool Inter_v2::o2_stopSound(OpFuncParams ¶ms) { expr = _vm->_parse->parseValExpr(); if (expr < 0) { - if (_vm->_adlib) - _vm->_adlib->stopPlay(); + _vm->_sound->adlibStop(); } else - _vm->_snd->stopSound(expr); + _vm->_sound->blasterStop(expr); _soundEndTimeKey = 0; return false; @@ -1915,7 +1897,7 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { int16 handle; int16 varOff; int32 size; - SaveType type; + SaveLoad::SaveMode mode; evalExpr(0); varOff = _vm->_parse->parseVarIndex(); @@ -1923,8 +1905,8 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { size = -1; handle = 1; - type = _vm->_saveLoad->getSaveType(_vm->_global->_inter_resStr); - if (type == kSaveNone) { + mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr); + if (mode == SaveLoad::kSaveModeNone) { handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr); if (handle >= 0) { @@ -1932,8 +1914,8 @@ bool Inter_v2::o2_checkData(OpFuncParams ¶ms) { size = _vm->_dataIO->getDataSize(_vm->_global->_inter_resStr); } else warning("File \"%s\" not found", _vm->_global->_inter_resStr); - } else - size = _vm->_saveLoad->getSize(type); + } else if (mode == SaveLoad::kSaveModeSave) + size = _vm->_saveLoad->getSize(_vm->_global->_inter_resStr); if (size == -1) handle = -1; @@ -1954,7 +1936,7 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { int16 dataVar; int16 handle; byte *buf; - SaveType type; + SaveLoad::SaveMode mode; evalExpr(0); dataVar = _vm->_parse->parseVarIndex(); @@ -1966,13 +1948,14 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { debugC(2, kDebugFileIO, "Read from file \"%s\" (%d, %d bytes at %d)", _vm->_global->_inter_resStr, dataVar, size, offset); - type = _vm->_saveLoad->getSaveType(_vm->_global->_inter_resStr); - if (type != kSaveNone) { + mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr); + if (mode == SaveLoad::kSaveModeSave) { WRITE_VAR(1, 1); - if (_vm->_saveLoad->load(type, dataVar, size, offset)) + if (_vm->_saveLoad->load(_vm->_global->_inter_resStr, dataVar, size, offset)) WRITE_VAR(1, 0); return false; - } + } else if (mode == SaveLoad::kSaveModeIgnore) + return false; if (size < 0) { warning("Attempted to read a raw sprite from file \"%s\"", @@ -1983,8 +1966,7 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { size = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; } - buf = _vm->_global->_inter_variables + dataVar; - memset(_vm->_global->_inter_variablesSizes + dataVar, 0, size); + buf = _variables->getAddressOff8(dataVar, size); if (_vm->_global->_inter_resStr[0] == 0) { WRITE_VAR(1, size); @@ -2009,7 +1991,7 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { WRITE_VAR(59, stream->readUint32LE()); // The scripts in some versions divide through 256^3 then, // effectively doing a LE->BE conversion - if ((_vm->_platform != Common::kPlatformPC) && (VAR(59) < 256)) + if ((_vm->getPlatform() != Common::kPlatformPC) && (VAR(59) < 256)) WRITE_VAR(59, SWAP_BYTES_32(VAR(59))); } else retSize = stream->read(buf, size); @@ -2025,7 +2007,7 @@ bool Inter_v2::o2_writeData(OpFuncParams ¶ms) { int32 offset; int32 size; int16 dataVar; - SaveType type; + SaveLoad::SaveMode mode; evalExpr(0); dataVar = _vm->_parse->parseVarIndex(); @@ -2038,11 +2020,11 @@ bool Inter_v2::o2_writeData(OpFuncParams ¶ms) { WRITE_VAR(1, 1); - type = _vm->_saveLoad->getSaveType(_vm->_global->_inter_resStr); - if (type != kSaveNone) { - if (_vm->_saveLoad->save(type, dataVar, size, offset)) + mode = _vm->_saveLoad->getSaveMode(_vm->_global->_inter_resStr); + if (mode == SaveLoad::kSaveModeSave) { + if (_vm->_saveLoad->save(_vm->_global->_inter_resStr, dataVar, size, offset)) WRITE_VAR(1, 0); - } else + } else if (mode == SaveLoad::kSaveModeNone) warning("Attempted to write to file \"%s\"", _vm->_global->_inter_resStr); return false; @@ -2054,29 +2036,10 @@ void Inter_v2::o2_loadInfogramesIns(OpGobParams ¶ms) { varName = load16(); - if (_vm->_noMusic) - return; - strncpy0(fileName, GET_VAR_STR(varName), 15); strcat(fileName, ".INS"); - debugC(1, kDebugMusic, "Loading Infogrames instrument file \"%s\"", - fileName); - - if (_vm->_game->_infogrames) { - _vm->_mixer->stopHandle(_vm->_game->_infHandle); - delete _vm->_game->_infogrames; - _vm->_game->_infogrames = 0; - } - - if (_vm->_game->_infIns) - delete _vm->_game->_infIns; - _vm->_game->_infIns = new Audio::Infogrames::Instruments; - if (!_vm->_game->_infIns->load(fileName)) { - warning("Couldn't load instruments file"); - delete _vm->_game->_infIns; - _vm->_game->_infIns = 0; - } + _vm->_sound->infogramesLoadInstruments(fileName); } void Inter_v2::o2_playInfogrames(OpGobParams ¶ms) { @@ -2085,58 +2048,23 @@ void Inter_v2::o2_playInfogrames(OpGobParams ¶ms) { varName = load16(); - if (_vm->_noMusic) - return; - strncpy0(fileName, GET_VAR_STR(varName), 15); strcat(fileName, ".DUM"); - debugC(1, kDebugMusic, "Playing Infogrames music file \"%s\"", fileName); - if (!_vm->_game->_infIns) { - _vm->_game->_infIns = new Audio::Infogrames::Instruments; - - if (!_vm->_game->_infIns->load("i1.ins")) { - warning("Couldn't load instruments file"); - delete _vm->_game->_infIns; - _vm->_game->_infIns = 0; - } - } - - if (_vm->_game->_infIns) { - _vm->_mixer->stopHandle(_vm->_game->_infHandle); - delete _vm->_game->_infogrames; - _vm->_game->_infogrames = - new Audio::Infogrames(*_vm->_game->_infIns, true, - _vm->_mixer->getOutputRate(), - _vm->_mixer->getOutputRate() / 75); - - if (!_vm->_game->_infogrames->load(fileName)) { - warning("Couldn't load infogrames music"); - delete _vm->_game->_infogrames; - _vm->_game->_infogrames = 0; - } else - _vm->_mixer->playInputStream(Audio::Mixer::kMusicSoundType, - &_vm->_game->_infHandle, _vm->_game->_infogrames, - -1, 255, 0, false); - } + _vm->_sound->infogramesLoadSong(fileName); + _vm->_sound->infogramesPlay(); } void Inter_v2::o2_startInfogrames(OpGobParams ¶ms) { load16(); - if (_vm->_game->_infogrames && - !_vm->_mixer->isSoundHandleActive(_vm->_game->_infHandle)) { - _vm->_game->_infogrames->restart(); - _vm->_mixer->playInputStream(Audio::Mixer::kMusicSoundType, - &_vm->_game->_infHandle, _vm->_game->_infogrames, - -1, 255, 0, false); - } + _vm->_sound->infogramesPlay(); } void Inter_v2::o2_stopInfogrames(OpGobParams ¶ms) { load16(); - _vm->_mixer->stopHandle(_vm->_game->_infHandle); + _vm->_sound->infogramesStop(); } void Inter_v2::o2_handleGoblins(OpGobParams ¶ms) { @@ -2172,15 +2100,15 @@ int16 Inter_v2::loadSound(int16 search) { } else { id = load16(); - for (slot = 0; slot < 60; slot++) - if (_vm->_game->_soundSamples[slot].isId(id)) { + for (slot = 0; slot < Sound::kSoundsCount; slot++) + if (_vm->_sound->sampleGetBySlot(slot)->isId(id)) { slotIdMask = 0x8000; break; } - if (slot == 60) { - for (slot = 59; slot >= 0; slot--) { - if (_vm->_game->_soundSamples[slot].empty()) + if (slot == Sound::kSoundsCount) { + for (slot = (Sound::kSoundsCount - 1); slot >= 0; slot--) { + if (_vm->_sound->sampleGetBySlot(slot)->empty()) break; } @@ -2192,7 +2120,9 @@ int16 Inter_v2::loadSound(int16 search) { } } - _vm->_game->freeSoundSlot(slot); + SoundDesc *sample = _vm->_sound->sampleGetBySlot(slot); + + _vm->_sound->sampleFree(sample, true, slot); if (id == -1) { char sndfile[14]; @@ -2224,8 +2154,8 @@ int16 Inter_v2::loadSound(int16 search) { } if (dataPtr) { - _vm->_game->_soundSamples[slot].load(type, source, dataPtr, dataSize); - _vm->_game->_soundSamples[slot]._id = id; + sample->load(type, source, dataPtr, dataSize); + sample->_id = id; } return slot | slotIdMask; diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp index b24e54ffbd..fb895dd5b2 100644 --- a/engines/gob/inter_v4.cpp +++ b/engines/gob/inter_v4.cpp @@ -29,9 +29,11 @@ #include "gob/gob.h" #include "gob/inter.h" #include "gob/global.h" +#include "gob/draw.h" #include "gob/game.h" #include "gob/parse.h" #include "gob/videoplayer.h" +#include "gob/sound/sound.h" namespace Gob { @@ -278,7 +280,7 @@ void Inter_v4::setupOpcodes() { {NULL, ""}, {NULL, ""}, /* 80 */ - OPCODE(o2_initScreen), + OPCODE(o4_initScreen), OPCODE(o2_scroll), OPCODE(o2_setScrollOffset), OPCODE(o4_playVmdOrMusic), @@ -503,7 +505,7 @@ void Inter_v4::setupOpcodes() { /* 30 */ OPCODE(o1_returnTo), OPCODE(o1_loadSpriteContent), - OPCODE(o3_copySprite), + OPCODE(o1_copySprite), OPCODE(o1_fillRect), /* 34 */ OPCODE(o1_drawLine), @@ -641,7 +643,7 @@ void Inter_v4::setupOpcodes() { void Inter_v4::executeDrawOpcode(byte i) { debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", - i, i, getOpcodeDrawDesc(i)); + i, i, getOpcodeDrawDesc(i)); OpcodeDrawProcV4 op = _opcodesDrawV4[i].proc; @@ -652,8 +654,10 @@ void Inter_v4::executeDrawOpcode(byte i) { } bool Inter_v4::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { - debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s)", - i, j, i, j, getOpcodeFuncDesc(i, j)); + debugC(1, kDebugFuncOp, "opcodeFunc %d.%d [0x%X.0x%X] (%s) - %s, %d, %d", + i, j, i, j, getOpcodeFuncDesc(i, j), _vm->_game->_curTotFile, + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData), + (uint) (_vm->_global->_inter_execPtr - _vm->_game->_totFileData - params.counter - 4)); if ((i > 4) || (j > 15)) { warning("unimplemented opcodeFunc: %d.%d", i, j); @@ -672,7 +676,7 @@ bool Inter_v4::executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms) { void Inter_v4::executeGoblinOpcode(int i, OpGobParams ¶ms) { debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", - i, i, getOpcodeGoblinDesc(i)); + i, i, getOpcodeGoblinDesc(i)); OpcodeGoblinProcV4 op = NULL; @@ -683,6 +687,8 @@ void Inter_v4::executeGoblinOpcode(int i, OpGobParams ¶ms) { } if (op == NULL) { + warning("unimplemented opcodeGoblin: %d", i); + int16 val; _vm->_global->_inter_execPtr -= 2; @@ -710,6 +716,86 @@ const char *Inter_v4::getOpcodeGoblinDesc(int i) { return ""; } +void Inter_v4::o4_initScreen() { + int16 offY; + int16 videoMode; + int16 width, height; + + offY = load16(); + + videoMode = offY & 0xFF; + offY = (offY >> 8) & 0xFF; + + width = _vm->_parse->parseValExpr(); + height = _vm->_parse->parseValExpr(); + + _vm->_video->clearScreen(); + + _vm->_global->_fakeVideoMode = videoMode; + + // Some versions require this + if (videoMode == 0xD) + videoMode = _vm->_mode; + + if ((videoMode == _vm->_global->_videoMode) && (width == -1)) + return; + + if (width > 0) + _vm->_video->_surfWidth = width; + if (height > 0) + _vm->_video->_surfHeight = height; + + _vm->_video->_screenDeltaX = 0; + if (_vm->_video->_surfWidth < _vm->_width) + _vm->_video->_screenDeltaX = (_vm->_width - _vm->_video->_surfWidth) / 2; + + _vm->_global->_mouseMinX = _vm->_video->_screenDeltaX; + _vm->_global->_mouseMaxX = _vm->_video->_screenDeltaX + _vm->_video->_surfWidth - 1; + + _vm->_video->_splitStart = _vm->_video->_surfHeight - offY; + + _vm->_video->_splitHeight1 = MIN<int16>(_vm->_height, _vm->_video->_surfHeight); + _vm->_video->_splitHeight2 = offY; + + if ((_vm->_video->_surfHeight + offY) < _vm->_height) + _vm->_video->_screenDeltaY = (_vm->_height - (_vm->_video->_surfHeight + offY)) / 2; + else + _vm->_video->_screenDeltaY = 0; + + _vm->_global->_mouseMaxY = (_vm->_video->_surfHeight + _vm->_video->_screenDeltaY) - offY - 1; + _vm->_global->_mouseMinY = _vm->_video->_screenDeltaY; + + _vm->_draw->closeScreen(); + _vm->_util->clearPalette(); + memset(_vm->_global->_redPalette, 0, 256); + memset(_vm->_global->_greenPalette, 0, 256); + memset(_vm->_global->_bluePalette, 0, 256); + + _vm->_video->_splitSurf = 0; + _vm->_draw->_spritesArray[24] = 0; + _vm->_draw->_spritesArray[25] = 0; + + _vm->_global->_videoMode = videoMode; + _vm->_video->initPrimary(videoMode); + WRITE_VAR(15, _vm->_global->_fakeVideoMode); + + _vm->_global->_setAllPalette = true; + + _vm->_util->setMousePos(_vm->_global->_inter_mouseX, + _vm->_global->_inter_mouseY); + _vm->_util->clearPalette(); + + _vm->_draw->initScreen(); + + _vm->_util->setScrollOffset(); + + if (offY > 0) { + _vm->_draw->_spritesArray[24] = new SurfaceDesc(videoMode, _vm->_width, offY); + _vm->_draw->_spritesArray[25] = new SurfaceDesc(videoMode, _vm->_width, offY); + _vm->_video->_splitSurf = _vm->_draw->_spritesArray[25]; + } +} + void Inter_v4::o4_playVmdOrMusic() { char fileName[128]; int16 x, y; @@ -725,6 +811,12 @@ void Inter_v4::o4_playVmdOrMusic() { evalExpr(0); strncpy0(fileName, _vm->_global->_inter_resStr, 127); + // WORKAROUND: The nut rolling animation in the administration center + // in Woodruff is called "noixroul", but the scripts think it's "noixroule". + if ((_vm->getGameType() == kGameTypeWoodruff) && + (!scumm_stricmp(fileName, "noixroule"))) + strcpy(fileName, "noixroul"); + x = _vm->_parse->parseValExpr(); y = _vm->_parse->parseValExpr(); startFrame = _vm->_parse->parseValExpr(); @@ -735,11 +827,14 @@ void Inter_v4::o4_playVmdOrMusic() { palEnd = _vm->_parse->parseValExpr(); palCmd = 1 << (flags & 0x3F); + debugC(1, kDebugVideo, "Playing video \"%s\" @ %d+%d, frames %d - %d, " + "paletteCmd %d (%d - %d), flags %X", fileName, x, y, startFrame, lastFrame, + palCmd, palStart, palEnd, flags); + close = false; if (lastFrame == -1) { close = true; } else if (lastFrame == -3) { - warning("Woodruff Stub: Video/Music command -3: Play background video %s, %d, %d, %d, %d", fileName, startFrame, x, y, VAR_OFFSET(7872)); _vm->_mult->_objects[startFrame].pAnimData->animation = -startFrame - 1; @@ -763,16 +858,19 @@ void Inter_v4::o4_playVmdOrMusic() { warning("Woodruff Stub: Video/Music command -4: Play background video %s", fileName); return; } else if (lastFrame == -5) { - warning("Woodruff Stub: Video/Music command -5: Stop background music"); + _vm->_sound->bgStop(); return; } else if (lastFrame == -6) { - warning("Woodruff Stub: Video/Music command -6: Load background video %s", fileName); + return; + } else if (lastFrame == -7) { return; } else if (lastFrame == -8) { warning("Woodruff Stub: Video/Music command -8: Play background video %s", fileName); return; } else if (lastFrame == -9) { - warning("Woodruff Stub: Video/Music command -9: Play background music %s (%d-%d)", fileName, palEnd, palStart); + _vm->_sound->bgStop(); + _vm->_sound->bgSetPlayMode(BackgroundAtmosphere::kPlayModeRandom); + _vm->_sound->bgPlay(fileName, palStart); return; } else if (lastFrame < 0) { warning("Unknown Video/Music command: %d, %s", lastFrame, fileName); @@ -785,7 +883,7 @@ void Inter_v4::o4_playVmdOrMusic() { } if ((fileName[0] != 0) && !_vm->_vidPlayer->primaryOpen(fileName, x, y, flags)) { - WRITE_VAR(11, -1); + WRITE_VAR(11, (uint32) -1); return; } diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp index cd8f9e3758..75867aaa6c 100644 --- a/engines/gob/map.cpp +++ b/engines/gob/map.cpp @@ -23,8 +23,6 @@ * */ - - #include "gob/gob.h" #include "gob/map.h" #include "gob/goblin.h" diff --git a/engines/gob/map_v1.cpp b/engines/gob/map_v1.cpp index c4b68fad85..4ac99d2465 100644 --- a/engines/gob/map_v1.cpp +++ b/engines/gob/map_v1.cpp @@ -23,15 +23,14 @@ * */ - #include "common/stream.h" #include "gob/gob.h" #include "gob/map.h" #include "gob/dataio.h" #include "gob/goblin.h" -#include "gob/sound.h" #include "gob/mult.h" +#include "gob/sound/sound.h" namespace Gob { @@ -160,7 +159,7 @@ void Map_v1::loadSounds(Common::SeekableReadStream &data) { strcpy(sndNames[i], buf); } - _vm->_snd->loadSample(_vm->_goblin->_soundData[14], "diamant1.snd"); + _vm->_sound->sampleLoad(&_vm->_goblin->_soundData[14], "diamant1.snd"); for (int i = 0; i < count; i++) { handle = _vm->_dataIO->openData(sndNames[i]); @@ -168,7 +167,7 @@ void Map_v1::loadSounds(Common::SeekableReadStream &data) { continue; _vm->_dataIO->closeData(handle); - _vm->_snd->loadSample(_vm->_goblin->_soundData[i], sndNames[i]); + _vm->_sound->sampleLoad(&_vm->_goblin->_soundData[i], sndNames[i]); } } diff --git a/engines/gob/map_v2.cpp b/engines/gob/map_v2.cpp index 2c383f5bb2..bd9f5b3efc 100644 --- a/engines/gob/map_v2.cpp +++ b/engines/gob/map_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/stream.h" #include "gob/gob.h" @@ -57,12 +56,12 @@ void Map_v2::loadMapObjects(const char *avjFile) { uint32 passPos; var = _vm->_parse->parseVarIndex(); - variables = _vm->_global->_inter_variables + var; + variables = _vm->_inter->_variables->getAddressOff8(var, 0); id = _vm->_inter->load16(); if (id == -1) { - _passMap = (int8 *)(_vm->_global->_inter_variables + var); + _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var, 0); return; } @@ -105,18 +104,17 @@ void Map_v2::loadMapObjects(const char *avjFile) { // In the original asm, this writes byte-wise into the variables-array tmpPos = mapData.pos(); mapData.seek(passPos); - if (variables != _vm->_global->_inter_variables) { - byte *sizes; + if ((variables != 0) && + (variables != _vm->_inter->_variables->getAddressOff8(0, 0))) { _passMap = (int8 *) variables; mapHeight = _screenHeight / _tilesHeight; mapWidth = _screenWidth / _tilesWidth; - sizes = _vm->_global->_inter_variablesSizes + - (((byte *) _passMap) - _vm->_global->_inter_variables); + for (int i = 0; i < mapHeight; i++) { for (int j = 0; j < mapWidth; j++) setPass(j, i, mapData.readSByte()); - memset(sizes + i * _passWidth, 0, mapWidth); + _vm->_inter->_variables->getAddressOff8(var + i * _passWidth, mapWidth); } } mapData.seek(tmpPos); diff --git a/engines/gob/map_v4.cpp b/engines/gob/map_v4.cpp index 721f040341..3a74c4b6aa 100644 --- a/engines/gob/map_v4.cpp +++ b/engines/gob/map_v4.cpp @@ -54,7 +54,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { uint32 passPos; var = _vm->_parse->parseVarIndex(); - variables = _vm->_global->_inter_variables + var; + variables = _vm->_inter->_variables->getAddressOff8(var, 0); id = _vm->_inter->load16(); @@ -62,7 +62,7 @@ void Map_v4::loadMapObjects(const char *avjFile) { warning("Woodruff Stub: loadMapObjects ID >= 65520"); return; } else if (id == -1) { - _passMap = (int8 *)(_vm->_global->_inter_variables + var); + _passMap = (int8 *) _vm->_inter->_variables->getAddressOff8(var, 0); return; } @@ -113,25 +113,24 @@ void Map_v4::loadMapObjects(const char *avjFile) { } if (_widthByte == 4) - _mapWidth = (int16) READ_VARO_UINT16(68); + _mapWidth = VAR(17); _passWidth = _mapWidth; // In the original asm, this writes byte-wise into the variables-array tmpPos = mapData.pos(); mapData.seek(passPos); - if (variables != _vm->_global->_inter_variables) { - byte *sizes; + if ((variables != 0) && + (variables != _vm->_inter->_variables->getAddressOff8(0, 0))) { _passMap = (int8 *) variables; mapHeight = _screenHeight / _tilesHeight; mapWidth = _screenWidth / _tilesWidth; - sizes = _vm->_global->_inter_variablesSizes + - (((byte *) _passMap) - _vm->_global->_inter_variables); + for (int i = 0; i < mapHeight; i++) { for (int j = 0; j < mapWidth; j++) setPass(j, i, mapData.readSByte()); - memset(sizes + i * _passWidth, 0, mapWidth); + _vm->_inter->_variables->getAddressOff8(var + i * _passWidth, mapWidth); } } mapData.seek(tmpPos); diff --git a/engines/gob/module.mk b/engines/gob/module.mk index aa2a235327..45048a0899 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -1,7 +1,6 @@ MODULE := engines/gob MODULE_OBJS := \ - cdrom.o \ dataio.o \ detection.o \ draw.o \ @@ -38,7 +37,6 @@ MODULE_OBJS := \ mult.o \ mult_v1.o \ mult_v2.o \ - music.o \ palanim.o \ parse.o \ parse_v1.o \ @@ -46,14 +44,24 @@ MODULE_OBJS := \ saveload.o \ saveload_v2.o \ saveload_v3.o \ + saveload_v4.o \ scenery.o \ scenery_v1.o \ scenery_v2.o \ - sound.o \ util.o \ + variables.o \ video.o \ video_v1.o \ - video_v2.o + video_v2.o \ + sound/sound.o \ + sound/sounddesc.o \ + sound/pcspeaker.o \ + sound/adlib.o \ + sound/infogrames.o \ + sound/soundmixer.o \ + sound/soundblaster.o \ + sound/cdrom.o \ + sound/bgatmosphere.o # This module can be built as a plugin ifeq ($(ENABLE_GOB), DYNAMIC_PLUGIN) diff --git a/engines/gob/mult.cpp b/engines/gob/mult.cpp index 70b6d33136..3d6a7942f9 100644 --- a/engines/gob/mult.cpp +++ b/engines/gob/mult.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -34,9 +33,10 @@ #include "gob/game.h" #include "gob/palanim.h" #include "gob/scenery.h" -#include "gob/sound.h" #include "gob/video.h" #include "gob/videoplayer.h" +#include "gob/inter.h" +#include "gob/sound/sound.h" namespace Gob { @@ -188,7 +188,7 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, if (_frame >= endFrame) stopNoClear = true; - if (_vm->_snd->_playingSound) + if (_vm->_sound->blasterPlayingSound()) stop = false; _vm->_util->processInput(); @@ -225,8 +225,8 @@ void Mult::playMult(int16 startFrame, int16 endFrame, char checkEscape, _animDataAllocated = false; } - if (_vm->_snd->_playingSound) - _vm->_snd->stopSound(10); + if (_vm->_sound->blasterPlayingSound()) + _vm->_sound->blasterStop(10); WRITE_VAR(57, (uint32) -1); } else @@ -415,21 +415,24 @@ void Mult::doSoundAnim(bool &stop, int16 frame) { if (sndKey->cmd != -1) { if ((sndKey->cmd == 1) || (sndKey->cmd == 4)) { - SoundDesc &sample = _vm->_game->_soundSamples[sndKey->soundIndex]; + SoundDesc *sample = _vm->_sound->sampleGetBySlot(sndKey->soundIndex); - _vm->_snd->stopSound(0); - if (!sample.empty()) - _vm->_snd->playSample(sample, sndKey->repCount, + _vm->_sound->blasterStop(0); + if (sample && !sample->empty()) + _vm->_sound->blasterPlay(sample, sndKey->repCount, sndKey->freq, sndKey->fadeLength); } } else { - if (_vm->_snd->_playingSound) - _vm->_snd->stopSound(sndKey->fadeLength); + if (_vm->_sound->blasterPlayingSound()) + _vm->_sound->blasterStop(sndKey->fadeLength); } } } void Mult::clearObjectVideos() { + if (!_objects) + return; + for (int i = 0; i < _objCount; i++) if (_objects[i].videoSlot > 0) _vm->_vidPlayer->slotClose(_objects[i].videoSlot - 1); diff --git a/engines/gob/mult.h b/engines/gob/mult.h index c283191ec8..aaf2e2826c 100644 --- a/engines/gob/mult.h +++ b/engines/gob/mult.h @@ -40,7 +40,7 @@ public: uint8 layer; uint8 frame; int8 animType; - uint8 order; + int8 order; int8 isPaused; int8 isStatic; int8 maxTick; @@ -229,7 +229,7 @@ public: int16 *_renderData; Mult_Object **_renderObjs; - uint8 *_orderArray; + int8 *_orderArray; SurfaceDesc::Ptr _animSurf; int16 _animLeft; diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp index 78071f1dd8..22683437e7 100644 --- a/engines/gob/mult_v1.cpp +++ b/engines/gob/mult_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/stream.h" diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 02211880ba..3a83ac1867 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/stream.h" @@ -526,14 +525,14 @@ void Mult_v2::playMultInit() { delete[] _animArrayData; _objects = new Mult_Object[_objCount]; - _orderArray = new uint8[_objCount]; + _orderArray = new int8[_objCount]; _renderObjs = new Mult_Object*[_objCount]; _animArrayX = new int32[_objCount]; _animArrayY = new int32[_objCount]; _animArrayData = new Mult_AnimData[_objCount]; memset(_objects, 0, _objCount * sizeof(Mult_Object)); - memset(_orderArray, 0, _objCount * sizeof(uint8)); + memset(_orderArray, 0, _objCount * sizeof(int8)); memset(_renderObjs, 0, _objCount * sizeof(Mult_Object *)); memset(_animArrayX, 0, _objCount * sizeof(int32)); memset(_animArrayY, 0, _objCount * sizeof(int32)); @@ -686,6 +685,11 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { return; animLayer = _vm->_scenery->getAnimLayer(nAnim, nLayer); + } else { + if (animObj.videoSlot > 0) { + _vm->_video->retrace(); + _vm->_vidPlayer->slotWaitEndFrame(animObj.videoSlot - 1, true); + } } if (animData.animType == 4) { @@ -693,7 +697,7 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { animData.frame = 0; animData.isPaused = 1; if (animData.animation < 0) - warning("TODO: AnimType 4, animation: %d", animData.animation); + warning("Woodruff Stub: AnimType 4, animation: %d", animData.animation); return; } @@ -701,9 +705,8 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { animData.animType = 11; if (animData.animType == 11) { - if (animData.isBusy != 0) { - warning("TODO: AnimType 11"); - } + if (animData.isBusy != 0) + warning("Woodruff Stub: AnimType 11"); return; } @@ -750,27 +753,39 @@ void Mult_v2::newCycleAnim(Mult_Object &animObj) { case 5: animData.isStatic = 1; animData.frame = 0; + if ((animData.animation < 0) && (animObj.videoSlot > 0)) { + _vm->_vidPlayer->slotClose(animObj.videoSlot - 1); + animObj.videoSlot = 0; + } + break; case 6: case 7: animData.frame--; animData.isPaused = 1; +/* if ((animData.animation < 0) && (animObj.videoSlot > 0)) { if (_vm->_vidPlayer->getFlags(animObj.videoSlot - 1) & 0x1000) { _vm->_vidPlayer->slotClose(animObj.videoSlot - 1); animObj.videoSlot = 0; } } +*/ + break; + + case 10: + warning("Woodruff Stub: AnimType 10"); break; } + animData.newCycle = 1; } void Mult_v2::animate() { - uint8 minOrder = 100; - uint8 maxOrder = 0; - uint8 *orderArray; + int8 minOrder = 100; + int8 maxOrder = 0; + int8 *orderArray; int orderArrayPos = 0; int8 animIndices[150]; int numAnims = 0; @@ -952,60 +967,58 @@ void Mult_v2::animate() { Mult_Object &animObj1 = *_renderObjs[orderArray[i]]; Mult_AnimData &animData1 = *(animObj1.pAnimData); - if (!animObj1.needRedraw && !animData1.isStatic) { - for (int j = 0; j < orderArrayPos; j++) { - Mult_Object &animObj2 = *_renderObjs[orderArray[j]]; + if (!animObj1.needRedraw) { - if (!animObj2.needRedraw) - continue; + if (!animData1.isStatic) { + for (int j = 0; j < orderArrayPos; j++) { + Mult_Object &animObj2 = *_renderObjs[orderArray[j]]; + + if (!animObj2.needRedraw) + continue; - if ((animObj1.newRight >= animObj2.newLeft) && - (animObj2.newRight >= animObj1.newLeft) && - (animObj1.newBottom >= animObj2.newTop) && - (animObj2.newBottom >= animObj1.newTop)) { + if ((animObj1.newRight >= animObj2.newLeft) && + (animObj2.newRight >= animObj1.newLeft) && + (animObj1.newBottom >= animObj2.newTop) && + (animObj2.newBottom >= animObj1.newTop)) { - _vm->_scenery->_toRedrawLeft = animObj2.newLeft; - _vm->_scenery->_toRedrawRight = animObj2.newRight; - _vm->_scenery->_toRedrawTop = animObj2.newTop; - _vm->_scenery->_toRedrawBottom = animObj2.newBottom; + _vm->_scenery->_toRedrawLeft = animObj2.newLeft; + _vm->_scenery->_toRedrawRight = animObj2.newRight; + _vm->_scenery->_toRedrawTop = animObj2.newTop; + _vm->_scenery->_toRedrawBottom = animObj2.newBottom; - _vm->_scenery->updateAnim(animData1.layer, animData1.frame, - animData1.animation, 12, *animObj1.pPosX, *animObj1.pPosY, 1); - _vm->_scenery->updateStatic(animData1.order + 1); + _vm->_scenery->updateAnim(animData1.layer, animData1.frame, + animData1.animation, 12, *animObj1.pPosX, *animObj1.pPosY, 1); + _vm->_scenery->updateStatic(animData1.order + 1); + } } } - } else if (!animData1.isStatic) { - _vm->_scenery->updateAnim(animData1.layer, animData1.frame, - animData1.animation, 10, *animObj1.pPosX, *animObj1.pPosY, 1); - - if (_vm->_scenery->_toRedrawLeft != -12345) { - if (_vm->_global->_pressedKeys[0x36]) { - _vm->_video->drawLine(_vm->_draw->_frontSurface, - _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawTop, - _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawTop, 15); - _vm->_video->drawLine(_vm->_draw->_frontSurface, - _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawBottom, - _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawBottom, 15); - _vm->_video->drawLine(_vm->_draw->_frontSurface, - _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawTop, - _vm->_scenery->_toRedrawLeft, _vm->_scenery->_toRedrawBottom, 15); - _vm->_video->drawLine(_vm->_draw->_frontSurface, - _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawTop, - _vm->_scenery->_toRedrawRight, _vm->_scenery->_toRedrawBottom, 15); - } - animObj1.lastLeft = _vm->_scenery->_toRedrawLeft; - animObj1.lastRight = _vm->_scenery->_toRedrawRight; - animObj1.lastTop = _vm->_scenery->_toRedrawTop; - animObj1.lastBottom = _vm->_scenery->_toRedrawBottom; - } else - animObj1.lastLeft = -1; + } else { - _vm->_scenery->_toRedrawLeft = animObj1.newLeft; - _vm->_scenery->_toRedrawRight = animObj1.newRight; - _vm->_scenery->_toRedrawTop = animObj1.newTop; - _vm->_scenery->_toRedrawBottom = animObj1.newBottom; + + if (animData1.isStatic != 0) { + _vm->_scenery->_toRedrawLeft = animObj1.newLeft; + _vm->_scenery->_toRedrawRight = animObj1.newRight; + _vm->_scenery->_toRedrawTop = animObj1.newTop; + _vm->_scenery->_toRedrawBottom = animObj1.newBottom; + } else { + _vm->_scenery->updateAnim(animData1.layer, animData1.frame, + animData1.animation, 10, *animObj1.pPosX, *animObj1.pPosY, 1); + + if (_vm->_scenery->_toRedrawLeft != -12345) { + animObj1.lastLeft = _vm->_scenery->_toRedrawLeft; + animObj1.lastRight = _vm->_scenery->_toRedrawRight; + animObj1.lastTop = _vm->_scenery->_toRedrawTop; + animObj1.lastBottom = _vm->_scenery->_toRedrawBottom; + } else { + animObj1.lastLeft = -1; + } + + } + + _vm->_scenery->updateStatic(animData1.order + 1); + } - _vm->_scenery->updateStatic(animData1.order + 1); + } // Advance animations diff --git a/engines/gob/parse.cpp b/engines/gob/parse.cpp index af12626c83..ad1f53bb6f 100644 --- a/engines/gob/parse.cpp +++ b/engines/gob/parse.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -45,7 +44,7 @@ int32 Parse::encodePtr(byte *ptr, int type) { offset = ptr - _vm->_game->_totFileData; break; case kInterVar: - offset = ptr - _vm->_global->_inter_variables; + offset = ptr - ((byte *) _vm->_inter->_variables->getAddressOff8(0, 0)); break; case kResStr: offset = ptr - ((byte *) _vm->_global->_inter_resStr); @@ -65,7 +64,7 @@ byte *Parse::decodePtr(int32 n) { ptr = _vm->_game->_totFileData; break; case kInterVar: - ptr = _vm->_global->_inter_variables; + ptr = (byte *) _vm->_inter->_variables->getAddressOff8(0, 0); break; case kResStr: ptr = (byte *) _vm->_global->_inter_resStr; diff --git a/engines/gob/parse_v1.cpp b/engines/gob/parse_v1.cpp index 2b84ac5cee..3c5f90c068 100644 --- a/engines/gob/parse_v1.cpp +++ b/engines/gob/parse_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -376,7 +375,7 @@ int16 Parse_v1::parseExpr(byte stopToken, byte *arg_2) { case 25: *operPtr = 22; temp = _vm->_inter->load16() * 4; - *valPtr = encodePtr(_vm->_global->_inter_variables + temp, + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(temp, 0), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; @@ -404,8 +403,8 @@ int16 Parse_v1::parseExpr(byte stopToken, byte *arg_2) { *valPtr = VAR(temp + offset); break; } - *valPtr = encodePtr(_vm->_global->_inter_variables + - temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8( + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; diff --git a/engines/gob/parse_v2.cpp b/engines/gob/parse_v2.cpp index 65315c083a..a2e6b8fb37 100644 --- a/engines/gob/parse_v2.cpp +++ b/engines/gob/parse_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" @@ -409,8 +408,8 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { else if (operation == 27) *valPtr = (int16) READ_VARO_UINT16(temp * 2 + offset * 2); else if (operation == 28) { - *valPtr = encodePtr(_vm->_global->_inter_variables + - temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8( + temp * 4 + offset * _vm->_global->_inter_animDataSize * 4, 0), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; @@ -468,7 +467,7 @@ int16 Parse_v2::parseExpr(byte stopToken, byte *arg_2) { case 25: *operPtr = 22; temp = _vm->_inter->load16() * 4; - *valPtr = encodePtr(_vm->_global->_inter_variables + temp, kInterVar); + *valPtr = encodePtr(_vm->_inter->_variables->getAddressOff8(temp, 0), kInterVar); if (*_vm->_global->_inter_execPtr == 13) { _vm->_global->_inter_execPtr++; temp += parseValExpr(12); diff --git a/engines/gob/saveload.cpp b/engines/gob/saveload.cpp index 717bc143a6..2788716858 100644 --- a/engines/gob/saveload.cpp +++ b/engines/gob/saveload.cpp @@ -24,456 +24,714 @@ */ #include "common/endian.h" -#include "common/file.h" +#include "common/savefile.h" #include "gob/gob.h" #include "gob/saveload.h" -#include "gob/global.h" #include "gob/draw.h" -#include "gob/video.h" namespace Gob { -SaveLoad::SaveLoad(GobEngine *vm, const char *targetName) : _vm(vm) { - _curSlot = -1; +TempSprite::TempSprite() { + _sprite = 0; + _width = _height = 0; + _size = -1; + memset(_palette, 0, 768); +} - _stagesCount = 0; - _buffer = 0; +TempSprite::~TempSprite() { + delete[] _sprite; +} - _tempSprite = 0; - memset(_tempPal, 0, 768); - _tempSpriteSize = -1; +int TempSprite::getSpriteIndex(int32 size) const { + if (size < -1000) + size += 1000; - _saveFiles = new char*[5]; + return -size - 1; +} - assert(_saveFiles); +bool TempSprite::getSpritePalette(int32 size) const { + return size < -1000; +} - _saveFiles[0] = new char[strlen(targetName) + 5]; - _saveFiles[1] = 0; - _saveFiles[2] = new char[strlen(targetName) + 5]; - _saveFiles[3] = _saveFiles[0]; - _saveFiles[4] = 0; +bool TempSprite::getProperties(int16 dataVar, int32 size, int32 offset, + int &index, bool &palette) const { - assert(_saveFiles[0] && _saveFiles[2]); + if (size >= 0) { + warning("Invalid index (%d)", size); + return false; + } - sprintf(_saveFiles[0], "%s.s00", targetName); - sprintf(_saveFiles[2], "%s.blo", targetName); -} + index = getSpriteIndex(size); + palette = getSpritePalette(size); -SaveLoad::~SaveLoad() { - if (_buffer) { - for (int i = 0; i < _stagesCount; i++) - delete[] _buffer[i]; - delete[] _buffer; + if ((index < 0) || (index >= SPRITES_COUNT)) { + warning("Index out of range (%d)", index); + return false; } - delete _tempSprite; + return true; +} - delete[] _saveFiles[0]; - delete[] _saveFiles[2]; - delete[] _saveFiles; +int32 TempSprite::getSize() const { + return _size; } -const char *SaveLoad::setCurSlot(int slot) { - static char *slotBase = _saveFiles[0] + strlen(_saveFiles[0]) - 2; +bool TempSprite::saveSprite(const SurfaceDesc &surfDesc) { + delete[] _sprite; + + _width = surfDesc.getWidth(); + _height = surfDesc.getHeight(); + _size = _width * _height; + _sprite = new byte[_size]; - if (_curSlot != slot) { - _curSlot = slot; + memcpy(_sprite, surfDesc.getVidMem(), _size); - if (_curSlot >= 0) - snprintf(slotBase, 3, "%02d", slot); + return true; +} + +bool TempSprite::savePalette(const Video::Color *palette) { + memcpy((byte *) _palette, (byte *) palette, 768); + return true; +} + +bool TempSprite::loadSprite(SurfaceDesc &surfDesc) { + if (!_sprite) { + warning("No sprite saved"); + return false; + } + + if (_size != (surfDesc.getWidth() * surfDesc.getHeight())) { + warning("Dimensions don't match (%dx%d - %dx%d", + _width, _height, surfDesc.getWidth(), surfDesc.getHeight()); + return false; } - return _saveFiles[0]; + memcpy(surfDesc.getVidMem(), _sprite, _size); + + return true; } -uint32 SaveLoad::read(Common::ReadStream &in, byte *buf, - byte *sizes, uint32 count) { - uint32 nRead; +bool TempSprite::loadPalette(Video::Color *palette) { + memcpy((byte *) palette, (byte *) _palette, 768); + return true; +} - nRead = in.read(buf, count); - if (nRead != count) { - warning("Can't read data: requested %d, got %d", count, nRead); - return 0; +bool TempSprite::toBuffer(byte *buffer, int32 size, bool palette) const { + + int32 haveSize = _size + (palette ? 768 : 0); + if (size != haveSize) { + warning("Sizes don't match (%d != %d)", size, haveSize); + return false; } - nRead = in.read(sizes, count); - if (nRead != count) { - warning("Can't read data sizes: requested %d, got %d", count, nRead); - return 0; + if (palette) { + memcpy(buffer, (byte *) _palette, 768); + buffer += 768; } - return count; + memcpy(buffer, _sprite, _size); + + return true; } -uint32 SaveLoad::write(Common::WriteStream &out, byte *buf, - byte *sizes, uint32 count) { - uint32 written; +bool TempSprite::fromBuffer(const byte *buffer, int32 size, bool palette) { + if (palette) { + memcpy((byte *) _palette, buffer, 768); + buffer += 768; + size -= 768; + } - written = out.write(buf, count); - if (written != count) { - warning("Can't write data: requested %d, wrote %d", count, written); - return 0; + _size = size; + + delete[] _sprite; + _sprite = new byte[_size]; + + memcpy(_sprite, buffer, _size); + + return true; +} + + +PlainSave::PlainSave() { +} + +PlainSave::~PlainSave() { +} + +bool PlainSave::save(int16 dataVar, int32 size, int32 offset, const char *name, + const Variables *variables) { + + if ((size <= 0) || (offset != 0)) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; } - written = out.write(sizes, count); - if (written != count) { - warning("Can't write data: requested %d, wrote %d", count, written); - return 0; + byte *vars = new byte[size]; + byte *varSizes = new byte[size]; + + if (!variables->copyTo(dataVar, vars, varSizes, size)) { + delete[] vars; + delete[] varSizes; + warning("dataVar (%d) or size (%d) out of range", dataVar, size); + return false; } - return count; + bool result = save(0, size, offset, name, vars, varSizes); + + delete[] vars; + delete[] varSizes; + + return result; } -bool SaveLoad::loadDataEndian(Common::ReadStream &in, - int16 dataVar, uint32 size) { +bool PlainSave::load(int16 dataVar, int32 size, int32 offset, const char *name, + Variables *variables) { - bool retVal = false; + if ((size <= 0) || (offset != 0)) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } - byte *varBuf = new byte[size]; - byte *sizeBuf = new byte[size]; + byte *vars = new byte[size]; + byte *varSizes = new byte[size]; - assert(varBuf && sizeBuf); + bool result = load(0, size, offset, name, vars, varSizes); - if (read(in, varBuf, sizeBuf, size) == size) { - if (fromEndian(varBuf, sizeBuf, size)) { - memcpy(_vm->_global->_inter_variables + dataVar, varBuf, size); - memcpy(_vm->_global->_inter_variablesSizes + dataVar, sizeBuf, size); - retVal = true; + if (result && variables) { + if (!variables->copyFrom(dataVar, vars, varSizes, size)) { + delete[] vars; + delete[] varSizes; + warning("dataVar (%d) or size (%d) out of range", dataVar, size); + return false; } } - delete[] varBuf; - delete[] sizeBuf; + delete[] vars; + delete[] varSizes; - return retVal; + return result; } -bool SaveLoad::saveDataEndian(Common::WriteStream &out, - int16 dataVar, uint32 size) { +bool PlainSave::save(int16 dataVar, int32 size, int32 offset, const char *name, + const byte *variables, const byte *variableSizes) const { - bool retVal = false; + if ((size <= 0) || (offset != 0)) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } - byte *varBuf = new byte[size]; - byte *sizeBuf = new byte[size]; + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::OutSaveFile *out = saveMan->openForSaving(name); - assert(varBuf && sizeBuf); + if (!out) { + warning("Can't open file \"%s\" for writing", name); + return false; + } - memcpy(varBuf, _vm->_global->_inter_variables + dataVar, size); - memcpy(sizeBuf, _vm->_global->_inter_variablesSizes + dataVar, size); + bool retVal; + retVal = SaveLoad::saveDataEndian(*out, dataVar, size, variables, variableSizes); - if (toEndian(varBuf, sizeBuf, size)) - if (write(out, varBuf, sizeBuf, size) == size) - retVal = true; + out->finalize(); + if (out->ioFailed()) { + warning("Can't write to file \"%s\"", name); + retVal = false; + } - delete[] varBuf; - delete[] sizeBuf; + delete out; + return retVal; +} + +bool PlainSave::load(int16 dataVar, int32 size, int32 offset, const char *name, + byte *variables, byte *variableSizes) const { + + if ((size <= 0) || (offset != 0)) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in = saveMan->openForLoading(name); + + if (!in) { + warning("Can't open file \"%s\" for reading", name); + return false; + } + bool retVal = SaveLoad::loadDataEndian(*in, dataVar, size, variables, variableSizes); + delete in; return retVal; } -int32 SaveLoad::getSize(SaveType type) { - switch (type) { - case kSaveNone: - return -1; - break; - case kSaveGame: - return getSizeGame(); - break; +StagedSave::StagedSave() { + _mode = kModeNone; + _name = 0; + _loaded = false; +} - case kSaveTempSprite: - return getSizeTempSprite(); - break; +StagedSave::~StagedSave() { + clear(); +} - case kSaveNotes: - return getSizeNotes(); - break; +void StagedSave::addStage(int32 size, bool endianed) { + int32 offset = 0; - case kSaveScreenshot: - return getSizeScreenshot(); - break; + if (!_stages.empty()) + offset = _stages[_stages.size() - 1].offset + + _stages[_stages.size() - 1].size; - case kSaveIgnore: - return -1; - break; - } + Stage stage(size, offset, endianed); + _stages.push_back(stage); +} + +int StagedSave::findStage(int16 dataVar, int32 size, int32 offset) const { + for (uint i = 0; i < _stages.size(); i++) + if ((_stages[i].size == size) && + (_stages[i].offset == offset)) + return i; return -1; } -bool SaveLoad::load(SaveType type, int16 dataVar, int32 size, int32 offset) { - switch (type) { - case kSaveNone: - return false; - break; - - case kSaveGame: - return loadGame(dataVar, size, offset); - break; +bool StagedSave::allSaved() const { + for (uint i = 0; i < _stages.size(); i++) + if (!_stages[i].bufVar) + return false; - case kSaveTempSprite: - return loadTempSprite(dataVar, size, offset); - break; + return true; +} - case kSaveNotes: - return loadNotes(dataVar, size, offset); - break; +uint32 StagedSave::getSize() const { + uint32 size = 0; - case kSaveScreenshot: - return loadScreenshot(dataVar, size, offset); - break; + for (uint i = 0; i < _stages.size(); i++) { + if (_stages[i].endianed) + size += 2 * _stages[i].size; + else + size += _stages[i].size; + } + + return size; +} - case kSaveIgnore: - return true; - break; +void StagedSave::clear() { + for (uint i = 0; i < _stages.size(); i++) { + delete[] _stages[i].bufVar; + delete[] _stages[i].bufVarSizes; + _stages[i].bufVar = 0; + _stages[i].bufVarSizes = 0; } - return false; + delete[] _name; + _name = 0; + + _mode = kModeNone; + _loaded = false; } -bool SaveLoad::save(SaveType type, int16 dataVar, int32 size, int32 offset) { - switch (type) { - case kSaveNone: - return false; - break; +void StagedSave::assertMode(Mode mode, const char *name) { + if ((_mode != mode) || ((name[0] != '\0') && strcmp(_name, name))) { + clear(); + _mode = mode; + _name = new char[strlen(name) + 1]; + strcpy(_name, name); + } +} - case kSaveGame: - return saveGame(dataVar, size, offset); - break; +bool StagedSave::save(int16 dataVar, int32 size, int32 offset, const char *name, + const Variables *variables) { - case kSaveTempSprite: - return saveTempSprite(dataVar, size, offset); - break; + if ((dataVar < 0) || (size <= 0) || (offset < 0)) { + warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); + return false; + } - case kSaveNotes: - return saveNotes(dataVar, size, offset); - break; + byte *vars = 0, *varSizes = 0; - case kSaveScreenshot: - return saveScreenshot(dataVar, size, offset); - break; + if (variables) { + vars = new byte[size]; + varSizes = new byte[size]; - case kSaveIgnore: - return true; - break; + if (!variables->copyTo(dataVar, vars, varSizes, size)) { + delete[] vars; + delete[] varSizes; + warning("dataVar (%d) or size (%d) out of range", dataVar, size); + return false; + } } - return false; -} + bool result = save(0, size, offset, name, vars, varSizes); + + delete[] vars; + delete[] varSizes; -int32 SaveLoad::getSizeTempSprite() { - return _tempSpriteSize; + return result; } -bool SaveLoad::loadTempSprite(int16 dataVar, int32 size, int32 offset) { - int index; - bool readPal; +bool StagedSave::load(int16 dataVar, int32 size, int32 offset, const char *name, + Variables *variables) { - if (size >= 0) { - warning("Invalid attempt at loading from the temporary sprite"); + if ((dataVar < 0) || (size <= 0) || (offset < 0)) { + warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); return false; } - index = getSpriteIndex(size); - readPal = getSpritePalette(size); + byte *vars = new byte[size]; + byte *varSizes = new byte[size]; - if ((index < 0) || (index >= SPRITES_COUNT)) { - warning("Index out of range while loading from the temporary " - "sprite (%d)", index); - return false; + bool result = load(0, size, offset, name, vars, varSizes); + + if (result && variables) { + if (!variables->copyFrom(dataVar, vars, varSizes, size)) { + delete[] vars; + delete[] varSizes; + warning("dataVar (%d) or size (%d) out of range", dataVar, size); + return false; + } } - return loadTempSprite(index, readPal); + delete[] vars; + delete[] varSizes; + + return result; } -bool SaveLoad::saveTempSprite(int16 dataVar, int32 size, int32 offset) { - int index; - bool readPal; +bool StagedSave::save(int16 dataVar, int32 size, int32 offset, const char *name, + const byte *variables, const byte *variableSizes) { - if (size >= 0) { - warning("Invalid attempt at saving to the temporary sprite"); + if ((dataVar < 0) || (size <= 0) || (offset < 0)) { + warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); return false; } - index = getSpriteIndex(size); - readPal = getSpritePalette(size); + int stage = findStage(dataVar, size, offset); + if (stage == -1) { + warning("Invalid saving procedure"); + return false; + } - if ((index < 0) || (index >= SPRITES_COUNT)) { - warning("Index out of range while saving to the temporary sprite (%d)", - index); + if (!variables || (_stages[stage].endianed && !variableSizes)) { + warning("Missing data"); return false; } - return saveTempSprite(index, readPal); -} + assertMode(kModeSave, name); -bool SaveLoad::loadTempSprite(uint32 index, bool palette) { - SurfaceDesc *sprite; + _stages[stage].bufVar = new byte[size]; + memcpy(_stages[stage].bufVar, variables + dataVar, size); - if (palette) { - memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, - (char *) _tempPal, 768); - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + if (_stages[stage].endianed) { + _stages[stage].bufVarSizes = new byte[size]; + memcpy(_stages[stage].bufVarSizes, variableSizes + dataVar, size); + } + + if (allSaved()) { + bool result = write(); + clear(); + return result; } - sprite = _vm->_draw->_spritesArray[index]; + return true; +} + +bool StagedSave::load(int16 dataVar, int32 size, int32 offset, const char *name, + byte *variables, byte *variableSizes) { - if (!sprite) { - warning("Couldn't load from the temporary sprite: " - "No such sprite %d", index); + if ((dataVar < 0) || (size <= 0) || (offset < 0)) { + warning("Invalid dataVar (%d), size (%d) or offset (%d)", dataVar, size, offset); return false; } - if ((sprite->getWidth() != _tempSprite->getWidth()) || - (sprite->getHeight() != _tempSprite->getHeight())) { - warning("Resolution doesn't match while loading from the " - "temporary sprite (%d: %dx%d vs. %dx%d)", index, - sprite->getWidth(), sprite->getHeight(), - _tempSprite->getWidth(), _tempSprite->getHeight()); + int stage = findStage(dataVar, size, offset); + if (stage == -1) { + warning("Invalid loading procedure"); return false; } - _vm->_video->drawSprite(_tempSprite, sprite, 0, 0, - sprite->getWidth() - 1, sprite->getHeight() - 1, 0, 0, 0); + assertMode(kModeLoad, name); - if (index == 21) { - _vm->_draw->forceBlit(); - _vm->_video->retrace(); + if (!_loaded) { + if (!read()) { + clear(); + return false; + } } + if (variables) + memcpy(variables + dataVar, _stages[stage].bufVar, size); + if (_stages[stage].endianed && variableSizes) + memcpy(variableSizes + dataVar, _stages[stage].bufVarSizes, size); + return true; } -bool SaveLoad::saveTempSprite(uint32 index, bool palette) { - SurfaceDesc *sprite = _vm->_draw->_spritesArray[index]; +bool StagedSave::write() const { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::OutSaveFile *out = saveMan->openForSaving(_name); - if (!sprite) { - warning("Couldn't save to the temporary sprite: " - "No such sprite %d", index); + if (!out) { + warning("Can't open file \"%s\" for writing", _name); return false; } - delete _tempSprite; - _tempSprite = _vm->_video->initSurfDesc(_vm->_global->_videoMode, - sprite->getWidth(), sprite->getHeight(), 0); + bool result = true; + for (uint i = 0; (i < _stages.size()) && result; i++) { + if (!_stages[i].endianed) { - _vm->_video->drawSprite(sprite, _tempSprite, 0, 0, - sprite->getWidth() - 1, sprite->getHeight() - 1, 0, 0, 0); + uint32 written = out->write(_stages[i].bufVar, _stages[i].size); - _tempSpriteSize = _vm->_draw->getSpriteRectSize(index); + result = (written == ((uint32) _stages[i].size)); + if (!result) + warning("Can't write data: requested %d, wrote %d", _stages[i].size, written); - if (palette) { - memcpy((char *) _tempPal, - (char *) _vm->_global->_pPaletteDesc->vgaPal, 768); - _tempSpriteSize += 768; + } else + result = SaveLoad::saveDataEndian(*out, 0, _stages[i].size, + _stages[i].bufVar, _stages[i].bufVarSizes); } - return true; + if (result) { + out->finalize(); + if (out->ioFailed()) { + warning("Can't write to file \"%s\"", _name); + result = false; + } + } + + delete out; + return result; } -bool SaveLoad::loadSprite(Common::ReadStream &in, int32 size) { - SurfaceDesc *sprite; - byte *buf; - int nRead; - int index; - bool readPal; +bool StagedSave::read() { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in = saveMan->openForLoading(_name); - if (size >= 0) { - warning("Invalid attempt at loading a sprite"); + if (!in) { + warning("Can't open file \"%s\" for reading", _name); return false; } - index = getSpriteIndex(size); - readPal = getSpritePalette(size); - - if ((index < 0) || (index >= SPRITES_COUNT)) { - warning("Index out of range while loading a sprite (%d)", - index); + uint32 saveSize = getSize(); + if (in->size() != saveSize) { + warning("Wrong size (%d != %d)", in->size(), saveSize); return false; } - size = _vm->_draw->getSpriteRectSize(index); - sprite = _vm->_draw->_spritesArray[index]; + bool result = true; + for (uint i = 0; ((i < _stages.size()) && result); i++) { + _stages[i].bufVar = new byte[_stages[i].size]; - if (!sprite) { - warning("Couldn't load sprite: No such sprite %d", index); - return false; - } + if (!_stages[i].endianed) { - buf = new byte[MAX<int>(768, size)]; - assert(buf); + uint32 nRead = in->read(_stages[i].bufVar, _stages[i].size); - if (readPal) { - nRead = in.read(buf, 768); - if (nRead != 768) { - warning("Couldn't read a palette: requested 768, got %d", nRead); - delete[] buf; - return false; - } + result = (nRead == ((uint32) _stages[i].size)); + if (!result) + warning("Can't read data: requested %d, got %d", _stages[i].size, nRead); - memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, - (char *) buf, 768); - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - } + } else { + _stages[i].bufVarSizes = new byte[_stages[i].size]; - nRead = in.read(buf, size); - if (nRead != size) { - warning("Couldn't read sprite data: requested %d, got %d", size, nRead); - delete[] buf; - return false; + result = SaveLoad::loadDataEndian(*in, 0, _stages[i].size, + _stages[i].bufVar, _stages[i].bufVarSizes); + } } - memcpy((char *) sprite->getVidMem(), buf, size); + if (result) + _loaded = true; + + delete in; + return result; +} + + +PagedBuffer::PagedBuffer(uint32 pageSize) { + + _size = 0; + _pageSize = pageSize; +} + +PagedBuffer::~PagedBuffer() { + clear(); +} + +bool PagedBuffer::empty() const { + return _pages.empty(); +} + +uint32 PagedBuffer::getSize() const { + return _size; +} + +void PagedBuffer::clear() { + for (uint i = 0; i < _pages.size(); i++) + delete[] _pages[i]; + _pages.clear(); + _size = 0; +} + +bool PagedBuffer::write(const byte *buffer, uint32 size, uint32 offset) { + grow(size, offset); + + uint page = offset / _pageSize; + while (size > 0) { + if (!_pages[page]) + _pages[page] = new byte[_pageSize]; + + uint32 pStart = offset % _pageSize; + uint32 n = MIN(size, _pageSize - pStart); + + memcpy(_pages[page] + pStart, buffer, n); + + buffer += n; + offset += n; + size -= n; + page++; + } - delete[] buf; return true; } -bool SaveLoad::saveSprite(Common::WriteStream &out, int32 size) { - SurfaceDesc *sprite; - int written; - int index; - bool readPal; +bool PagedBuffer::read(byte *buffer, uint32 size, uint32 offset) const { + uint page = offset / _pageSize; - if (size >= 0) { - warning("Invalid attempt at saving a sprite"); - return false; + while (size > 0) { + if (offset >= _size) { + memset(buffer, 0, size); + break; + } + + uint32 pStart = offset % _pageSize; + uint32 n = MIN(MIN(size, _pageSize - pStart), _size - offset); + + if (_pages[page]) + memcpy(buffer, _pages[page] + pStart, n); + else + memset(buffer, 0, n); + + buffer += n; + offset += n; + size -= n; + page++; } - index = getSpriteIndex(size); - readPal = getSpritePalette(size); + return true; +} - if ((index < 0) || (index >= SPRITES_COUNT)) { - warning("Index out of range while saving a sprite (%d)", - index); - return false; +uint32 PagedBuffer::writeToStream(Common::WriteStream &out) const { + for (uint i = 0; i < _pages.size(); i++) { + if (!_pages[i]) { + for (uint32 j = 0; j < _pageSize; j++) + out.writeByte(0); + } else + out.write(_pages[i], _pageSize); } - size = _vm->_draw->getSpriteRectSize(index); - sprite = _vm->_draw->_spritesArray[index]; + return _size; +} + +uint32 PagedBuffer::readFromStream(Common::ReadStream &in) { + clear(); - if (!sprite) { - warning("Couldn't save sprite: No such sprite %d", index); - return false; + while (!in.eos()) { + byte *buffer = new byte[_pageSize]; + + _size += in.read(buffer, _pageSize); + + _pages.push_back(buffer); } - if (readPal) { - written = out.write((char *) _vm->_global->_pPaletteDesc->vgaPal, 768); - if (written != 768) { - warning("Couldn't write a palette: requested 768, wrote %d", written); - return false; - } + return _size; +} + +void PagedBuffer::grow(uint32 size, uint32 offset) { + uint32 eSize = offset + size; + + while (_size < eSize) { + _pages.push_back(0); + _size += MIN(_pageSize, eSize - _size); } +} + + +SaveLoad::SaveLoad(GobEngine *vm, const char *targetName) : _vm(vm) { + + _targetName = new char[strlen(targetName) + 1]; + strcpy(_targetName, targetName); +} + +SaveLoad::~SaveLoad() { + delete[] _targetName; +} - written = out.write((char *) sprite->getVidMem(), size); - if (written != size) { - warning("Couldn't write a sprite: requested %d, wrote %d", - size, written); +int32 SaveLoad::getSize(const char *fileName) { + int type; + + type = getSaveType(stripPath(fileName)); + if (type == -1) + return -1; + + debugC(3, kDebugSaveLoad, "Requested size of save file \"%s\" (type %d)", + fileName, type); + + return getSizeVersioned(type); +} + +bool SaveLoad::load(const char *fileName, int16 dataVar, int32 size, int32 offset) { + int type; + + type = getSaveType(stripPath(fileName)); + if (type == -1) return false; - } - return true; + debugC(3, kDebugSaveLoad, "Requested loading of save file \"%s\" (type %d) - %d, %d, %d", + fileName, type, dataVar, size, offset); + + return loadVersioned(type, dataVar, size, offset); +} + +bool SaveLoad::save(const char *fileName, int16 dataVar, int32 size, int32 offset) { + int type; + + type = getSaveType(stripPath(fileName)); + if (type == -1) + return false; + + debugC(3, kDebugSaveLoad, "Requested saving of save file \"%s\" (type %d) - %d, %d, %d", + fileName, type, dataVar, size, offset); + + return saveVersioned(type, dataVar, size, offset); +} + +const char *SaveLoad::stripPath(const char *fileName) { + const char *backSlash; + if ((backSlash = strrchr(fileName, '\\'))) + return backSlash + 1; + + return fileName; +} + +char *SaveLoad::setCurrentSlot(char *destName, int slot) { + char *slotBase = destName + strlen(destName) - 2; + + snprintf(slotBase, 3, "%02d", slot); + + return destName; +} + +void SaveLoad::buildIndex(byte *buffer, char *name, int n, int32 size, int32 offset) { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + + for (int i = 0; i < n; i++, buffer += size) { + in = saveMan->openForLoading(setCurrentSlot(name, i)); + if (in) { + in->seek(offset); + in->read(buffer, size); + delete in; + } else + memset(buffer, 0, size); + } } bool SaveLoad::fromEndian(byte *buf, const byte *sizes, uint32 count) { @@ -514,4 +772,89 @@ bool SaveLoad::toEndian(byte *buf, const byte *sizes, uint32 count) { return true; } +uint32 SaveLoad::read(Common::ReadStream &in, + byte *buf, byte *sizes, uint32 count) { + uint32 nRead; + + nRead = in.read(buf, count); + if (nRead != count) { + warning("Can't read data: requested %d, got %d", count, nRead); + return 0; + } + + nRead = in.read(sizes, count); + if (nRead != count) { + warning("Can't read data sizes: requested %d, got %d", count, nRead); + return 0; + } + + return count; +} + +uint32 SaveLoad::write(Common::WriteStream &out, + const byte *buf, const byte *sizes, uint32 count) { + uint32 written; + + written = out.write(buf, count); + if (written != count) { + warning("Can't write data: requested %d, wrote %d", count, written); + return 0; + } + + written = out.write(sizes, count); + if (written != count) { + warning("Can't write data: requested %d, wrote %d", count, written); + return 0; + } + + return count; +} + +bool SaveLoad::loadDataEndian(Common::ReadStream &in, + int16 dataVar, uint32 size, byte *variables, byte *variableSizes) { + + bool retVal = false; + + byte *varBuf = new byte[size]; + byte *sizeBuf = new byte[size]; + + assert(varBuf && sizeBuf); + + if (read(in, varBuf, sizeBuf, size) == size) { + if (fromEndian(varBuf, sizeBuf, size)) { + memcpy(variables + dataVar, varBuf, size); + memcpy(variableSizes + dataVar, sizeBuf, size); + retVal = true; + } + } + + delete[] varBuf; + delete[] sizeBuf; + + return retVal; +} + +bool SaveLoad::saveDataEndian(Common::WriteStream &out, + int16 dataVar, uint32 size, const byte *variables, const byte *variableSizes) { + + bool retVal = false; + + byte *varBuf = new byte[size]; + byte *sizeBuf = new byte[size]; + + assert(varBuf && sizeBuf); + + memcpy(varBuf, variables + dataVar, size); + memcpy(sizeBuf, variableSizes + dataVar, size); + + if (toEndian(varBuf, sizeBuf, size)) + if (write(out, varBuf, sizeBuf, size) == size) + retVal = true; + + delete[] varBuf; + delete[] sizeBuf; + + return retVal; +} + } // End of namespace Gob diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h index bf1e4c01a8..29f7ee2594 100644 --- a/engines/gob/saveload.h +++ b/engines/gob/saveload.h @@ -26,143 +26,380 @@ #ifndef GOB_SAVELOAD_H #define GOB_SAVELOAD_H +#include "common/array.h" #include "common/stream.h" #include "gob/video.h" +#include "gob/variables.h" namespace Gob { -enum SaveType { - kSaveNone = -1, - kSaveGame, - kSaveTempSprite, - kSaveNotes, - kSaveScreenshot, - kSaveIgnore +class TempSprite { +public: + TempSprite(); + ~TempSprite(); + + bool getProperties(int16 dataVar, int32 size, int32 offset, + int &index, bool &palette) const; + + int32 getSize() const; + + bool saveSprite(const SurfaceDesc &surfDesc); + bool savePalette(const Video::Color *palette); + bool loadSprite(SurfaceDesc &surfDesc); + bool loadPalette(Video::Color *palette); + + bool toBuffer(byte *buffer, int32 size, bool palette) const; + bool fromBuffer(const byte *buffer, int32 size, bool palette); + +private: + byte *_sprite; + int16 _width; + int16 _height; + int32 _size; + Video::Color _palette[256]; + + int getSpriteIndex(int32 size) const; + bool getSpritePalette(int32 size) const; }; -class SaveLoad { +class PlainSave { +public: + PlainSave(); + ~PlainSave(); + + bool save(int16 dataVar, int32 size, int32 offset, const char *name, + const Variables *variables); + bool load(int16 dataVar, int32 size, int32 offset, const char *name, + Variables *variables); + + bool save(int16 dataVar, int32 size, int32 offset, const char *name, + const byte *variables, const byte *variableSizes) const; + bool load(int16 dataVar, int32 size, int32 offset, const char *name, + byte *variables, byte *variableSizes) const; +}; + +class StagedSave { public: - int32 getSize(SaveType type); - bool load(SaveType type, int16 dataVar, int32 size, int32 offset); - bool save(SaveType type, int16 dataVar, int32 size, int32 offset); + StagedSave(); + ~StagedSave(); + + void addStage(int32 size, bool endianed = true); - virtual SaveType getSaveType(const char *fileName) = 0; + bool save(int16 dataVar, int32 size, int32 offset, const char *name, + const Variables *variables); + bool load(int16 dataVar, int32 size, int32 offset, const char *name, + Variables *variables); + + bool save(int16 dataVar, int32 size, int32 offset, const char *name, + const byte *variables, const byte *variableSizes); + bool load(int16 dataVar, int32 size, int32 offset, const char *name, + byte *variables, byte *variableSizes); + +private: + struct Stage { + byte *bufVar; + byte *bufVarSizes; + int32 size; + int32 offset; + bool endianed; + + Stage(int32 s = 0, int32 off = 0, bool end = true) : + bufVar(0), bufVarSizes(0), size(s), offset(off), endianed(end) {} + }; + + enum Mode { + kModeNone, + kModeSave, + kModeLoad + }; + + Common::Array<Stage> _stages; + enum Mode _mode; + char *_name; + + bool _loaded; + + int findStage(int16 dataVar, int32 size, int32 offset) const; + bool allSaved() const; + + uint32 getSize() const; + + void clear(); + void assertMode(Mode mode, const char *name); + + bool write() const; + bool read(); +}; + +class PagedBuffer { +public: + PagedBuffer(uint32 pageSize = 1024); + ~PagedBuffer(); + + bool empty() const; + uint32 getSize() const; + + void clear(); + + bool write(const byte *buffer, uint32 size, uint32 offset); + bool read(byte *buffer, uint32 size, uint32 offset) const; + + uint32 writeToStream(Common::WriteStream &out) const; + uint32 readFromStream(Common::ReadStream &in); + +private: + uint32 _size; + uint32 _pageSize; + Common::Array<byte *> _pages; + + void grow(uint32 size, uint32 offset); +}; + +class SaveLoad { +public: + enum SaveMode { + kSaveModeNone, + kSaveModeIgnore, + kSaveModeSave + }; SaveLoad(GobEngine *vm, const char *targetName); virtual ~SaveLoad(); -protected: - int _curSlot; - char **_saveFiles; + virtual SaveMode getSaveMode(const char *fileName) = 0; - int _stagesCount; - byte **_buffer; + int32 getSize(const char *fileName); + bool load(const char *fileName, int16 dataVar, int32 size, int32 offset); + bool save(const char *fileName, int16 dataVar, int32 size, int32 offset); - // While using the notepad or changing the font, the original executable - // temporarily dumps Draw::_backSurface to a file. Since that's not really - // a nice thing to do, we work around it. - SurfaceDesc *_tempSprite; - Video::Color _tempPal[256]; - int32 _tempSpriteSize; + char *setCurrentSlot(char *destName, int slot); + void buildIndex(byte *buffer, char *name, int n, int32 size, int32 offset = 0); + static const char *stripPath(const char *fileName); + + static bool fromEndian(byte *buf, const byte *sizes, uint32 count); + static bool toEndian(byte *buf, const byte *sizes, uint32 count); + static uint32 read(Common::ReadStream &in, + byte *buf, byte *sizes, uint32 count); + static uint32 write(Common::WriteStream &out, + const byte *buf, const byte *sizes, uint32 count); + + static bool loadDataEndian(Common::ReadStream &in, + int16 dataVar, uint32 size, byte *variables, byte *variableSizes); + static bool saveDataEndian(Common::WriteStream &out, + int16 dataVar, uint32 size, const byte *variables, const byte *variableSizes); + +protected: GobEngine *_vm; - int getSpriteIndex(int32 size) { - if (size < -1000) - size += 1000; - - return -size - 1; - } - bool getSpritePalette(int32 size) { - return size < -1000; - } - - const char *setCurSlot(int slot); - bool fromEndian(byte *buf, const byte *sizes, uint32 count); - bool toEndian(byte *buf, const byte *sizes, uint32 count); - uint32 read(Common::ReadStream &in, byte *buf, - byte *sizes, uint32 count); - uint32 write(Common::WriteStream &out, byte *buf, - byte *sizes, uint32 count); - - bool loadDataEndian(Common::ReadStream &in, int16 dataVar, uint32 size); - bool saveDataEndian(Common::WriteStream &out, int16 dataVar, uint32 size); - - bool loadTempSprite(uint32 index, bool palette); - bool saveTempSprite(uint32 index, bool palette); - bool loadSprite(Common::ReadStream &in, int32 size); - bool saveSprite(Common::WriteStream &out, int32 size); - - int32 getSizeTempSprite(); - bool loadTempSprite(int16 dataVar, int32 size, int32 offset); - bool saveTempSprite(int16 dataVar, int32 size, int32 offset); - - virtual uint32 getSaveGameSize() = 0; - - virtual int32 getSizeGame() = 0; - virtual int32 getSizeNotes() = 0; - virtual int32 getSizeScreenshot() = 0; - virtual bool loadGame(int16 dataVar, int32 size, int32 offset) = 0; - virtual bool loadNotes(int16 dataVar, int32 size, int32 offset) = 0; - virtual bool loadScreenshot(int16 dataVar, int32 size, int32 offset) = 0; - virtual bool saveGame(int16 dataVar, int32 size, int32 offset) = 0; - virtual bool saveNotes(int16 dataVar, int32 size, int32 offset) = 0; - virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset) = 0; + char *_targetName; + + virtual int getSaveType(const char *fileName) = 0; + + virtual int32 getSizeVersioned(int type) = 0; + virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset) = 0; + virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset) = 0; }; class SaveLoad_v2 : public SaveLoad { public: - virtual SaveType getSaveType(const char *fileName); + enum SaveType { + kSaveGame, + kSaveTempSprite, + kSaveNotes + }; SaveLoad_v2(GobEngine *vm, const char *targetName); - virtual ~SaveLoad_v2() {} + virtual ~SaveLoad_v2(); + + virtual SaveMode getSaveMode(const char *fileName); protected: - virtual uint32 getSaveGameSize(); - - virtual int32 getSizeGame(); - virtual int32 getSizeNotes(); - virtual int32 getSizeScreenshot(); - virtual bool loadGame(int16 dataVar, int32 size, int32 offset); - virtual bool loadNotes(int16 dataVar, int32 size, int32 offset); - virtual bool loadScreenshot(int16 dataVar, int32 size, int32 offset); - virtual bool saveGame(int16 dataVar, int32 size, int32 offset); - virtual bool saveNotes(int16 dataVar, int32 size, int32 offset); - virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset); - - void initBuffer(); + struct SaveFile { + const char *sourceName; + char *destName; + SaveMode mode; + SaveType type; + }; + + static SaveFile _saveFiles[]; + + int32 _varSize; + + TempSprite _tmpSprite; + PlainSave _notes; + StagedSave _save; + + byte _indexBuffer[600]; + bool _hasIndex; + + virtual int getSaveType(const char *fileName); + + virtual int32 getSizeVersioned(int type); + virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); + virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + int32 getSizeGame(SaveFile &saveFile); + int32 getSizeTempSprite(SaveFile &saveFile); + int32 getSizeNotes(SaveFile &saveFile); + + bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + + bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + + void assertInited(); }; -class SaveLoad_v3 : public SaveLoad_v2 { -public: - virtual SaveType getSaveType(const char *fileName); +enum SaveType { + kSaveNone = -1, + kSaveGame, + kSaveTempSprite, + kSaveNotes, + kSaveScreenshot, + kSaveIgnore +}; - SaveLoad_v3(GobEngine *vm, const char *targetName, uint32 screenshotSize = 19968, +class SaveLoad_v3 : public SaveLoad { +public: + enum SaveType { + kSaveNone, + kSaveGame, + kSaveTempSprite, + kSaveNotes, + kSaveScreenshot + }; + + SaveLoad_v3(GobEngine *vm, const char *targetName, + uint32 screenshotSize = 19968, int32 indexOffset = 40, int32 screenshotOffset = 80); - virtual ~SaveLoad_v3() {} + virtual ~SaveLoad_v3(); + + virtual SaveMode getSaveMode(const char *fileName); protected: + struct SaveFile { + const char *sourceName; + char *destName; + SaveMode mode; + SaveType type; + int slot; + }; + bool _useScreenshots; bool _firstSizeGame; - int8 _saveSlot; uint32 _screenshotSize; int32 _indexOffset; int32 _screenshotOffset; - virtual uint32 getSaveGameSize(); + static SaveFile _saveFiles[]; + + int32 _varSize; + + TempSprite _screenshot; + TempSprite _tmpSprite; + PlainSave _notes; + StagedSave _save; + + byte _propBuffer[1000]; + byte _indexBuffer[1200]; + bool _hasIndex; + + virtual int getSaveType(const char *fileName); + + virtual int32 getSizeVersioned(int type); + virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); + virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + int32 getSizeGame(SaveFile &saveFile); + int32 getSizeTempSprite(SaveFile &saveFile); + int32 getSizeNotes(SaveFile &saveFile); + int32 getSizeScreenshot(SaveFile &saveFile); + + bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadScreenshot(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + + bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveTempSprite(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveNotes(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveScreenshot(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + + void assertInited(); + + void buildScreenshotIndex(byte *buffer, char *name, int n); +}; + +class SaveLoad_v4 : public SaveLoad { +public: + enum SaveType { + kSaveNone, + kSaveScreenProps, + kSaveGame, + kSaveGameScreenProps + }; + + bool _firstSizeGame; + + SaveLoad_v4(GobEngine *vm, const char *targetName); + virtual ~SaveLoad_v4(); + + virtual SaveMode getSaveMode(const char *fileName); + +protected: + struct SaveFile { + const char *sourceName; + char *destName; + SaveMode mode; + SaveType type; + }; + + static SaveFile _saveFiles[]; + + int32 _varSize; + + StagedSave _save; + + byte _propBuffer[1000]; + byte _indexBuffer[1200]; + bool _hasIndex; + + byte *_screenProps; + + virtual int getSaveType(const char *fileName); + + virtual int32 getSizeVersioned(int type); + virtual bool loadVersioned(int type, int16 dataVar, int32 size, int32 offset); + virtual bool saveVersioned(int type, int16 dataVar, int32 size, int32 offset); + + int getSlot(int32 offset) const; + int getSlotRemainder(int32 offset) const; + + int32 getSizeScreenProps(SaveFile &saveFile); + int32 getSizeGame(SaveFile &saveFile); + int32 getSizeGameScreenProps(SaveFile &saveFile); + + bool loadScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool loadGameScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - virtual int32 getSizeGame(); - virtual int32 getSizeScreenshot(); - virtual bool loadGame(int16 dataVar, int32 size, int32 offset); - virtual bool loadScreenshot(int16 dataVar, int32 size, int32 offset); - virtual bool saveGame(int16 dataVar, int32 size, int32 offset); - virtual bool saveNotes(int16 dataVar, int32 size, int32 offset); - virtual bool saveScreenshot(int16 dataVar, int32 size, int32 offset); + bool saveScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveGame(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); + bool saveGameScreenProps(SaveFile &saveFile, int16 dataVar, int32 size, int32 offset); - bool saveGame(int32 screenshotSize); - void initBuffer(); + void assertInited(); }; } // End of namespace Gob diff --git a/engines/gob/saveload_v2.cpp b/engines/gob/saveload_v2.cpp index ab7211b216..a92fe8cf01 100644 --- a/engines/gob/saveload_v2.cpp +++ b/engines/gob/saveload_v2.cpp @@ -24,273 +24,344 @@ */ #include "common/endian.h" -#include "common/file.h" +#include "common/savefile.h" #include "gob/gob.h" #include "gob/saveload.h" #include "gob/global.h" #include "gob/game.h" +#include "gob/draw.h" +#include "gob/inter.h" namespace Gob { +SaveLoad_v2::SaveFile SaveLoad_v2::_saveFiles[] = { + { "cat.inf", 0, kSaveModeSave, kSaveGame}, + { "cat.cat", 0, kSaveModeSave, kSaveGame}, + { "save.inf", 0, kSaveModeSave, kSaveTempSprite}, + { "bloc.inf", 0, kSaveModeSave, kSaveNotes} +}; + SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : - SaveLoad(vm, targetName) { + SaveLoad(vm, targetName) { + + _saveFiles[0].destName = new char[strlen(targetName) + 5]; + _saveFiles[1].destName = _saveFiles[0].destName; + _saveFiles[2].destName = 0; + _saveFiles[3].destName = new char[strlen(targetName) + 5]; - _stagesCount = 1; + sprintf(_saveFiles[0].destName, "%s.s00", targetName); + sprintf(_saveFiles[3].destName, "%s.blo", targetName); + + _varSize = 0; + _hasIndex = false; } -SaveType SaveLoad_v2::getSaveType(const char *fileName) { - const char *backSlash; - if ((backSlash = strrchr(fileName, '\\'))) - fileName = backSlash + 1; - - if (!scumm_stricmp(fileName, "cat.inf")) - return kSaveGame; - if (!scumm_stricmp(fileName, "cat.cat")) - return kSaveGame; - if (!scumm_stricmp(fileName, "save.inf")) - return kSaveTempSprite; - if (!scumm_stricmp(fileName, "bloc.inf")) - return kSaveNotes; - - return kSaveNone; +SaveLoad_v2::~SaveLoad_v2() { + delete[] _saveFiles[0].destName; + delete[] _saveFiles[3].destName; } -uint32 SaveLoad_v2::getSaveGameSize() { - return 80 + (READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4) * 2; +SaveLoad::SaveMode SaveLoad_v2::getSaveMode(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return _saveFiles[i].mode; + + return kSaveModeNone; } -int32 SaveLoad_v2::getSizeNotes() { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; - int32 size = -1; +int SaveLoad_v2::getSaveType(const char *fileName) { + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return i; - in = saveMan->openForLoading(_saveFiles[(int) kSaveNotes]); - if (in) { - size = in->size(); - delete in; + return -1; +} + +int32 SaveLoad_v2::getSizeVersioned(int type) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + return getSizeGame(_saveFiles[type]); + case kSaveTempSprite: + return getSizeTempSprite(_saveFiles[type]); + case kSaveNotes: + return getSizeNotes(_saveFiles[type]); } - return size; + return -1; } -int32 SaveLoad_v2::getSizeGame() { +bool SaveLoad_v2::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + if (loadGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading from slot %d", getSlot(offset)); + break; + + case kSaveTempSprite: + if(loadTempSprite(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading the temporary sprite"); + break; + + case kSaveNotes: + if (loadNotes(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading the notes"); + break; + } + + return false; +} + +bool SaveLoad_v2::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + if (saveGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving to slot %d", getSlot(offset)); + break; + + case kSaveTempSprite: + if(saveTempSprite(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving the temporary sprite"); + break; + + case kSaveNotes: + if (saveNotes(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving the notes"); + break; + } + + return false; +} + +int SaveLoad_v2::getSlot(int32 offset) const { + return ((offset - 600) / _varSize); +} + +int SaveLoad_v2::getSlotRemainder(int32 offset) const { + return ((offset - 600) % _varSize); +} + +int32 SaveLoad_v2::getSizeGame(SaveFile &saveFile) { Common::SaveFileManager *saveMan = g_system->getSavefileManager(); Common::InSaveFile *in; for (int i = 14; i >= 0; i--) { - in = saveMan->openForLoading(setCurSlot(i)); + in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); if (in) { delete in; - return (i + 1) * READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * - 4 + 600; + return (i + 1) * _varSize + 600; } } return -1; } -int32 SaveLoad_v2::getSizeScreenshot() { - return -1; +int32 SaveLoad_v2::getSizeTempSprite(SaveFile &saveFile) { + return _tmpSprite.getSize(); } -bool SaveLoad_v2::loadGame(int16 dataVar, int32 size, int32 offset) { +int32 SaveLoad_v2::getSizeNotes(SaveFile &saveFile) { Common::SaveFileManager *saveMan = g_system->getSavefileManager(); Common::InSaveFile *in; - int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + int32 size = -1; + + in = saveMan->openForLoading(saveFile.destName); + if (in) { + size = in->size(); + delete in; + } + + return size; +} + +bool SaveLoad_v2::loadGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { if (size == 0) { dataVar = 0; - size = varSize; + size = _varSize; } - int slot = (offset - 600) / varSize; - int slotR = (offset - 600) % varSize; + if (offset == 0) { + debugC(3, kDebugSaveLoad, "Loading save index"); - if ((offset == 0) && (size == 600)) { - - byte *varBuf = _vm->_global->_inter_variables + dataVar; - for (int i = 0; i < 15; i++, varBuf += 40) { - in = saveMan->openForLoading(setCurSlot(i)); - if (in) { - in->read(varBuf, 40); - delete in; - } else - memset(varBuf, 0, 40); + if (size != 600) { + warning("Requested index has wrong size (%d)", size); + return false; } - memset(_vm->_global->_inter_variablesSizes + dataVar, 0, 600); - return true; - } else if ((offset > 0) && (slot < 15) && - (slotR == 0) && (size == varSize)) { + SaveLoad::buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar, 600), + saveFile.destName, 15, 40); + + } else { + int slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); - in = saveMan->openForLoading(setCurSlot(slot)); - if (!in) { - warning("Can't open file for slot %d", slot); + SaveLoad::setCurrentSlot(saveFile.destName, slot); + + if ((slot >= 15) || (slotRem != 0)) { + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); return false; } - uint32 sGameSize = getSaveGameSize(); - uint32 fSize = in->size(); - if (fSize != sGameSize) { - warning("Can't load from slot %d: Wrong size (%d, %d)", slot, - fSize, sGameSize); - delete in; + if (!_save.load(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) return false; - } + } - in->seek(80); - if (loadDataEndian(*in, dataVar, size)) { - delete in; - debugC(1, kDebugFileIO, "Loading from slot %d", slot); - return true; - } - delete in; + return true; +} - } else - warning("Invalid loading procedure (%d, %d, %d, %d)", - offset, size, slot, slotR); +bool SaveLoad_v2::loadTempSprite(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - return false; -} + debugC(3, kDebugSaveLoad, "Loading from the temporary sprite"); -bool SaveLoad_v2::loadNotes(int16 dataVar, int32 size, int32 offset) { - bool retVal; + int index; + bool palette; - if ((size <= 0) || (offset != 0)) { - warning("Invalid attempt at loading the notes (%d, %d)", size, offset); + if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) return false; - } - - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - char *sName = _saveFiles[(int) kSaveNotes]; - Common::InSaveFile *in = saveMan->openForLoading(sName); - if (!in) { - warning("Can't open file \"%s\" for reading", sName); + if (!_tmpSprite.loadSprite(*_vm->_draw->_spritesArray[index])) return false; + + if (palette) { + if (!_tmpSprite.loadPalette(_vm->_global->_pPaletteDesc->vgaPal)) + return false; + + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); } - retVal = loadDataEndian(*in, dataVar, size); - delete in; - return retVal; -} + if (index == 21) { + _vm->_draw->forceBlit(); + _vm->_video->retrace(); + } -bool SaveLoad_v2::loadScreenshot(int16 dataVar, int32 size, int32 offset) { - return false; + return true; } -bool SaveLoad_v2::saveGame(int16 dataVar, int32 size, int32 offset) { - int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; +bool SaveLoad_v2::loadNotes(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + debugC(2, kDebugSaveLoad, "Loading the notes"); + + return _notes.load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); +} - initBuffer(); +bool SaveLoad_v2::saveGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { if (size == 0) { dataVar = 0; - size = varSize; + size = _varSize; } - int slot = (offset - 600) / varSize; - int slotR = (offset - 600) % varSize; + if (offset == 0) { + debugC(3, kDebugSaveLoad, "Saving save index"); - if ((offset == 0) && (size == 600)) { + if (size != 600) { + warning("Requested index has wrong size (%d)", size); + return false; + } - delete[] _buffer[0]; - _buffer[0] = new byte[1200]; - assert(_buffer[0]); + _vm->_inter->_variables->copyTo(dataVar, _indexBuffer, 0, 600); + _hasIndex = true; - memcpy(_buffer[0], _vm->_global->_inter_variables + dataVar, 600); - memset(_buffer[0] + 600, 0, 600); + } else { + int slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); - return true; + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); - } else if ((offset > 0) && (slot < 15) && - (slotR == 0) && (size == varSize)) { + SaveLoad::setCurrentSlot(saveFile.destName, slot); - if (!_buffer[0]) { - warning("Tried to save without writing the index first"); + if ((slot >= 15) || (slotRem != 0)) { + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); return false; } - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::OutSaveFile *out; - - out = saveMan->openForSaving(setCurSlot(slot)); - if (!out) { - warning("Can't open file for slot %d for writing", slot); - delete[] _buffer[0]; - _buffer[0] = 0; + if (!_hasIndex) { + warning("No index written yet"); return false; } - bool retVal = false; + _hasIndex = false; - if (out->write(_buffer[0] + slot * 40, 40) == 40) - if (out->write(_buffer[0] + 600 + slot * 40, 40) == 40) - if (saveDataEndian(*out, dataVar, size)) { - out->finalize(); - if (!out->ioFailed()) - retVal = true; - } - - if (!retVal) - warning("Can't save to slot %d", slot); - else - debugC(1, kDebugFileIO, "Saved to slot %d", slot); - - delete[] _buffer[0]; - _buffer[0] = 0; - delete out; + byte sizes[40]; + memset(sizes, 0, 40); + if(!_save.save(0, 40, 0, saveFile.destName, _indexBuffer + (slot * 40), sizes)) + return false; - return retVal; + if (!_save.save(dataVar, size, 40, saveFile.destName, _vm->_inter->_variables)) + return false; - } else - warning("Invalid saving procedure (%d, %d, %d, %d)", - offset, size, slot, slotR); + } - return false; + return true; } -bool SaveLoad_v2::saveNotes(int16 dataVar, int32 size, int32 offset) { - bool retVal; +bool SaveLoad_v2::saveTempSprite(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - if ((size <= 0) || (offset != 0)) { - warning("Invalid attempt at saving the notes (%d, %d)", size, offset); - return false; - } + debugC(3, kDebugSaveLoad, "Saving to the temporary sprite"); - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - char *sName = _saveFiles[(int) kSaveNotes]; + int index; + bool palette; - Common::OutSaveFile *out = saveMan->openForSaving(sName); - if (!out) { - warning("Can't open file \"%s\" for writing", sName); + if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) return false; - } - retVal = saveDataEndian(*out, dataVar, size); + if (!_tmpSprite.saveSprite(*_vm->_draw->_spritesArray[index])) + return false; - out->finalize(); - if (out->ioFailed()) { - warning("Can't save notes"); - retVal = false; - } + if (palette) + if (!_tmpSprite.savePalette(_vm->_global->_pPaletteDesc->vgaPal)) + return false; - delete out; - return retVal; + return true; } -bool SaveLoad_v2::saveScreenshot(int16 dataVar, int32 size, int32 offset) { +bool SaveLoad_v2::saveNotes(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + debugC(2, kDebugSaveLoad, "Saving the notes"); + + return _notes.save(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); return false; } -void SaveLoad_v2::initBuffer() { - if (_buffer) +void SaveLoad_v2::assertInited() { + if (_varSize > 0) return; - _buffer = new byte*[_stagesCount]; - assert(_buffer); - _buffer[0] = 0; + _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + + _save.addStage(40); + _save.addStage(_varSize); } } // End of namespace Gob diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp index 4a4036fded..67879db3d1 100644 --- a/engines/gob/saveload_v3.cpp +++ b/engines/gob/saveload_v3.cpp @@ -24,62 +24,181 @@ */ #include "common/endian.h" -#include "common/file.h" +#include "common/savefile.h" #include "gob/gob.h" #include "gob/saveload.h" #include "gob/global.h" #include "gob/game.h" +#include "gob/draw.h" +#include "gob/inter.h" namespace Gob { +SaveLoad_v3::SaveFile SaveLoad_v3::_saveFiles[] = { + { "cat.inf", 0, kSaveModeSave, kSaveGame, -1}, + { "ima.inf", 0, kSaveModeSave, kSaveScreenshot, -1}, + { "intro.$$$", 0, kSaveModeSave, kSaveTempSprite, -1}, + { "bloc.inf", 0, kSaveModeSave, kSaveNotes, -1}, + { "prot", 0, kSaveModeIgnore, kSaveNone, -1}, + { "config", 0, kSaveModeIgnore, kSaveNone, -1}, +}; + SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, uint32 screenshotSize, int32 indexOffset, int32 screenshotOffset) : - SaveLoad_v2(vm, targetName) { + SaveLoad(vm, targetName) { _screenshotSize = screenshotSize; _indexOffset = indexOffset; _screenshotOffset = screenshotOffset; - _saveSlot = -1; - _stagesCount = 3; - _useScreenshots = false; _firstSizeGame = true; + + _saveFiles[0].destName = new char[strlen(targetName) + 5]; + _saveFiles[1].destName = _saveFiles[0].destName; + _saveFiles[2].destName = 0; + _saveFiles[3].destName = new char[strlen(targetName) + 5]; + _saveFiles[4].destName = 0; + _saveFiles[5].destName = 0; + + sprintf(_saveFiles[0].destName, "%s.s00", targetName); + sprintf(_saveFiles[3].destName, "%s.blo", targetName); + + _varSize = 0; + _hasIndex = false; + memset(_propBuffer, 0, 1000); } -SaveType SaveLoad_v3::getSaveType(const char *fileName) { - const char *backSlash; - if ((backSlash = strrchr(fileName, '\\'))) - fileName = backSlash + 1; - - if (!scumm_stricmp(fileName, "cat.inf")) - return kSaveGame; - if (!scumm_stricmp(fileName, "ima.inf")) - return kSaveScreenshot; - if (!scumm_stricmp(fileName, "intro.$$$")) - return kSaveTempSprite; - if (!scumm_stricmp(fileName, "bloc.inf")) - return kSaveNotes; - if (!scumm_stricmp(fileName, "prot")) - return kSaveIgnore; - if (!scumm_stricmp(fileName, "config")) - return kSaveIgnore; - - return kSaveNone; +SaveLoad_v3::~SaveLoad_v3() { + delete[] _saveFiles[0].destName; + delete[] _saveFiles[3].destName; } -uint32 SaveLoad_v3::getSaveGameSize() { - uint32 size; +SaveLoad::SaveMode SaveLoad_v3::getSaveMode(const char *fileName) { + fileName = stripPath(fileName); - size = 1040 + (READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4) * 2; - if (_useScreenshots) - size += _screenshotSize; + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return _saveFiles[i].mode; - return size; + return kSaveModeNone; +} + +int SaveLoad_v3::getSaveType(const char *fileName) { + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return i; + + return -1; +} + +int32 SaveLoad_v3::getSizeVersioned(int type) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + return getSizeGame(_saveFiles[type]); + case kSaveTempSprite: + return getSizeTempSprite(_saveFiles[type]); + case kSaveNotes: + return getSizeNotes(_saveFiles[type]); + case kSaveScreenshot: + return getSizeScreenshot(_saveFiles[type]); + default: + break; + } + + return -1; +} + +bool SaveLoad_v3::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + if (loadGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading from slot %d", getSlot(offset)); + break; + + case kSaveTempSprite: + if(loadTempSprite(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading the temporary sprite"); + break; + + case kSaveNotes: + if (loadNotes(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading the notes"); + break; + + case kSaveScreenshot: + if (loadScreenshot(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading a screenshot"); + break; + + default: + break; + } + + return false; } -int32 SaveLoad_v3::getSizeGame() { +bool SaveLoad_v3::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveGame: + if (saveGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving to slot %d", getSlot(offset)); + break; + + case kSaveTempSprite: + if(saveTempSprite(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving the temporary sprite"); + break; + + case kSaveNotes: + if (saveNotes(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving the notes"); + break; + + case kSaveScreenshot: + if (saveScreenshot(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving a screenshot"); + break; + + default: + break; + } + + return false; +} + +int SaveLoad_v3::getSlot(int32 offset) const { + return ((offset - 1700) / _varSize); +} + +int SaveLoad_v3::getSlotRemainder(int32 offset) const { + return ((offset - 1700) % _varSize); +} + +int32 SaveLoad_v3::getSizeGame(SaveFile &saveFile) { if (_firstSizeGame) { _firstSizeGame = false; return -1; @@ -89,358 +208,403 @@ int32 SaveLoad_v3::getSizeGame() { Common::InSaveFile *in; int32 size = -1; - int slot = _curSlot; + int slot = saveFile.slot; for (int i = 29; i >= 0; i--) { - in = saveMan->openForLoading(setCurSlot(i)); + in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); if (in) { delete in; - size = (i + 1) * READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * - 4 + 1700; + size = (i + 1) * _varSize + 1700; break; } } - setCurSlot(slot); + setCurrentSlot(saveFile.destName, slot); return size; } -int32 SaveLoad_v3::getSizeScreenshot() { +int32 SaveLoad_v3::getSizeTempSprite(SaveFile &saveFile) { + return _tmpSprite.getSize(); +} + +int32 SaveLoad_v3::getSizeNotes(SaveFile &saveFile) { Common::SaveFileManager *saveMan = g_system->getSavefileManager(); Common::InSaveFile *in; int32 size = -1; - _useScreenshots = true; - int slot = _curSlot; + in = saveMan->openForLoading(saveFile.destName); + if (in) { + size = in->size(); + delete in; + } + + return size; +} + +int32 SaveLoad_v3::getSizeScreenshot(SaveFile &saveFile) { + if (!_useScreenshots) { + _useScreenshots = true; + _save.addStage(_screenshotSize, false); + } + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + int32 size = -1; + + int slot = saveFile.slot; for (int i = 29; i >= 0; i--) { - in = saveMan->openForLoading(setCurSlot(i)); + in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); if (in) { delete in; size = (i + 1) * _screenshotSize + _screenshotOffset; break; } } - setCurSlot(slot); + setCurrentSlot(saveFile.destName, slot); return size; } -bool SaveLoad_v3::loadGame(int16 dataVar, int32 size, int32 offset) { - int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; +bool SaveLoad_v3::loadGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - int slot = (offset - 1700) / varSize; - int slotR = (offset - 1700) % varSize; - - initBuffer(); + if (size == 0) { + dataVar = 0; + size = _varSize; + } - if ((size > 0) && (offset < 500) && ((size + offset) <= 500)) { + if (offset < 500) { + debugC(3, kDebugSaveLoad, "Loading global properties"); - memcpy(_vm->_global->_inter_variables + dataVar, - _buffer[0] + offset, size); - memcpy(_vm->_global->_inter_variablesSizes + dataVar, - _buffer[0] + offset + 500, size); - return true; + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } - } else if ((size == 1200) && (offset == 500)) { + _vm->_inter->_variables->copyFrom(dataVar, + _propBuffer + offset, _propBuffer + offset + 500, size); - memset(_buffer[1], 0, 1200); + } else if (offset == 500) { + debugC(3, kDebugSaveLoad, "Loading save index"); - slot = _curSlot; - for (int i = 0; i < 30; i++) { - in = saveMan->openForLoading(setCurSlot(i)); - if (in) { - in->seek(1000); - in->read(_buffer[1] + i * 40, 40); - delete in; - } + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; } - setCurSlot(slot); - memcpy(_vm->_global->_inter_variables + dataVar, _buffer[1], 1200); - memset(_vm->_global->_inter_variablesSizes + dataVar, 0, 1200); - return true; + int slot = saveFile.slot; + + SaveLoad::buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar, 1200), + saveFile.destName, 30, 40, 1000); - } else if ((offset > 0) && (slot < 30) && - (slotR == 0) && (size == 0)) { + setCurrentSlot(saveFile.destName, slot); - in = saveMan->openForLoading(setCurSlot(slot)); - if (!in) { - warning("Can't open file for slot %d", slot); + } else { + saveFile.slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", saveFile.slot); + + SaveLoad::setCurrentSlot(saveFile.destName, saveFile.slot); + + if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, saveFile.slot, slotRem); return false; } - uint32 sGameSize = getSaveGameSize(); - uint32 fSize = in->size(); - if (fSize != sGameSize) { - warning("Can't load from slot %d: Wrong size (%d, %d)", slot, - fSize, sGameSize); - delete in; + if (!_save.load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) return false; - } + } - byte varBuf[500], sizeBuf[500]; - if (read(*in, varBuf, sizeBuf, 500) == 500) { - if (fromEndian(varBuf, sizeBuf, 500)) { - memcpy(_buffer[0], varBuf, 500); - memcpy(_buffer[0] + 500, sizeBuf, 500); - in->seek(1040); - if (loadDataEndian(*in, 0, varSize)) { - delete in; - debugC(1, kDebugFileIO, "Loading from slot %d", slot); - return true; - } - } - } - delete in; + return true; +} - } else - warning("Invalid loading procedure (%d, %d, %d, %d)", - offset, size, slot, slotR); +bool SaveLoad_v3::loadTempSprite(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - return false; + debugC(3, kDebugSaveLoad, "Loading from the temporary sprite"); + + int index; + bool palette; + + if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) + return false; + + if (!_tmpSprite.loadSprite(*_vm->_draw->_spritesArray[index])) + return false; + + if (palette) { + if (!_tmpSprite.loadPalette(_vm->_global->_pPaletteDesc->vgaPal)) + return false; + + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + } + + if (index == 21) { + _vm->_draw->forceBlit(); + _vm->_video->retrace(); + } + + return true; } -bool SaveLoad_v3::loadScreenshot(int16 dataVar, int32 size, int32 offset) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::InSaveFile *in; +bool SaveLoad_v3::loadNotes(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - int slot = (offset - _screenshotOffset) / _screenshotSize; - int slotR = (offset - _screenshotOffset) % _screenshotSize; + debugC(2, kDebugSaveLoad, "Loading the notes"); - _useScreenshots = true; - if ((size == 40) && (offset == _indexOffset)) { - char buf[40]; + return _notes.load(dataVar, size, offset, saveFile.destName, _vm->_inter->_variables); +} - memset(buf, 0, 40); +bool SaveLoad_v3::loadScreenshot(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - slot = _curSlot; - for (int i = 0; i < 30; i++) { - in = saveMan->openForLoading(setCurSlot(i)); - if (in) { - delete in; - buf[i] = 1; - } + debugC(3, kDebugSaveLoad, "Loading a screenshot"); + + if (!_useScreenshots) { + _useScreenshots = true; + _save.addStage(_screenshotSize, false); + } + + if (offset == _indexOffset) { + if (size != 40) { + warning("Requested index has wrong size (%d)", size); + return false; } - setCurSlot(slot); - memcpy(_vm->_global->_inter_variables + dataVar, buf, 40); - memset(_vm->_global->_inter_variablesSizes + dataVar, 0, 40); - return true; + byte buffer[40]; + memset(buffer, 0, 40); + + int slot = saveFile.slot; + buildScreenshotIndex(buffer, saveFile.destName, 30); + setCurrentSlot(saveFile.destName, slot); - } else if ((offset > 0) && (slot < 30) && - (slotR == 0) && (size < 0)) { + memcpy(_vm->_inter->_variables->getAddressOff8(dataVar, 40), buffer, 40); - int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + } else { + saveFile.slot = (offset - _screenshotOffset) / _screenshotSize; + int slotRem = (offset - _screenshotOffset) % _screenshotSize; - in = saveMan->openForLoading(setCurSlot(slot)); - if (!in) { - warning("Can't open file for slot %d", slot); + SaveLoad::setCurrentSlot(saveFile.destName, saveFile.slot); + + if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, saveFile.slot, slotRem); return false; } - uint32 sGameSize = getSaveGameSize(); - uint32 fSize = in->size(); - if (fSize != sGameSize) { - warning("Can't load screenshot from slot %d: Wrong size (%d, %d)", - slot, fSize, sGameSize); - delete in; + byte *buffer = new byte[_screenshotSize]; + + if (!_save.load(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { + delete[] buffer; return false; } - in->seek(1040 + varSize * 2); + int index; + bool palette; - bool success = loadSprite(*in, size); - delete in; - return success; + if (!_screenshot.getProperties(dataVar, size, offset, index, palette)) { + delete[] buffer; + return false; + } - } else - warning("Invalid attempt at loading a screenshot (%d, %d, %d, %d)", - offset, size, slot, slotR); + if (!_screenshot.fromBuffer(buffer, _screenshotSize, palette)) { + delete[] buffer; + return false; + } - return false; -} + if (!_screenshot.loadSprite(*_vm->_draw->_spritesArray[index])) { + delete[] buffer; + return false; + } -bool SaveLoad_v3::saveGame(int16 dataVar, int32 size, int32 offset) { - int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + if (palette) { + if (!_screenshot.loadPalette(_vm->_global->_pPaletteDesc->vgaPal)) { + delete[] buffer; + return false; + } + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + } + + delete[] buffer; + } - int slot = (offset - 1700) / varSize; - int slotR = (offset - 1700) % varSize; + return true; +} - initBuffer(); +bool SaveLoad_v3::saveGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - if ((size > 0) && (offset < 500) && ((size + offset) <= 500)) { + if (size == 0) { + dataVar = 0; + size = _varSize; + } - memcpy(_buffer[0] + offset, - _vm->_global->_inter_variables + dataVar, size); - memcpy(_buffer[0] + offset + 500, - _vm->_global->_inter_variablesSizes + dataVar, size); + if (offset < 500) { + debugC(3, kDebugSaveLoad, "Loading global properties"); - return true; + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } - } else if ((size > 0) && (offset >= 500) && (offset < 1700) && - ((size + offset) <= 1700)) { + _vm->_inter->_variables->copyTo(dataVar, + _propBuffer + offset, _propBuffer + offset + 500, size); - memcpy(_buffer[1] + offset - 500, - _vm->_global->_inter_variables + dataVar, size); + } else if (offset == 500) { + debugC(3, kDebugSaveLoad, "Saving save index"); - return true; + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } - } else if ((offset > 0) && (slot < 30) && - (slotR == 0) && (size == 0)) { + _vm->_inter->_variables->copyTo(dataVar, _indexBuffer, 0, size); + _hasIndex = true; - _saveSlot = -1; + } else { + saveFile.slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); - delete _buffer[2]; - _buffer[2] = new byte[varSize * 2]; - assert(_buffer[2]); + debugC(2, kDebugSaveLoad, "Saving to slot %d", saveFile.slot); - memcpy(_buffer[2], _vm->_global->_inter_variables, varSize); - memcpy(_buffer[2] + varSize, - _vm->_global->_inter_variablesSizes, varSize); + SaveLoad::setCurrentSlot(saveFile.destName, saveFile.slot); - if (!toEndian(_buffer[2], _buffer[2] + varSize, varSize)) { - delete _buffer[2]; - _buffer[2] = 0; + if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, saveFile.slot, slotRem); return false; } - _saveSlot = slot; + if (!_hasIndex) { + warning("No index written yet"); + return false; + } - if (!_useScreenshots) - return saveGame(0); + _hasIndex = false; - return true; + if(!_save.save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) + return false; - } else - warning("Invalid saving procedure (%d, %d, %d, %d)", - offset, size, slot, slotR); + if(!_save.save(0, 40, 500, saveFile.destName, _indexBuffer + (saveFile.slot * 40), 0)) + return false; - return false; -} + if (!_save.save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + return false; + + } -bool SaveLoad_v3::saveNotes(int16 dataVar, int32 size, int32 offset) { - return SaveLoad_v2::saveNotes(dataVar, size - 160, offset); + return true; } -bool SaveLoad_v3::saveScreenshot(int16 dataVar, int32 size, int32 offset) { - int slot = (offset - _screenshotOffset) / _screenshotSize; - int slotR = (offset - _screenshotOffset) % _screenshotSize; +bool SaveLoad_v3::saveTempSprite(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - _useScreenshots = true; + debugC(3, kDebugSaveLoad, "Saving to the temporary sprite"); - if ((offset < _screenshotOffset) && (size > 0)) { + int index; + bool palette; - return true; + if (!_tmpSprite.getProperties(dataVar, size, offset, index, palette)) + return false; - } else if ((offset > 0) && (slot < 30) && - (slotR == 0) && (size < 0)) { + if (!_tmpSprite.saveSprite(*_vm->_draw->_spritesArray[index])) + return false; + + if (palette) + if (!_tmpSprite.savePalette(_vm->_global->_pPaletteDesc->vgaPal)) + return false; + + return true; +} - return saveGame(size); +bool SaveLoad_v3::saveNotes(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - } else - warning("Invalid attempt at saving a screenshot (%d, %d, %d, %d)", - offset, size, slot, slotR); + debugC(2, kDebugSaveLoad, "Saving the notes"); + return _notes.save(dataVar, size - 160, offset, saveFile.destName, _vm->_inter->_variables); return false; } -bool SaveLoad_v3::saveGame(int32 screenshotSize) { - int8 slot = _saveSlot; - - _saveSlot = -1; +bool SaveLoad_v3::saveScreenshot(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { - initBuffer(); + debugC(3, kDebugSaveLoad, "Saving a screenshot"); - if ((slot < 0) || (slot > 29)) { - warning("Can't save to slot %d: Out of range", slot); - delete[] _buffer[2]; - _buffer[2] = 0; - return false; + if (!_useScreenshots) { + _useScreenshots = true; + _save.addStage(_screenshotSize, false); } - if (!_buffer[2]) { - warning("Can't save to slot %d: No data", slot); - return false; - } + if (offset >= _screenshotOffset) { - Common::SaveFileManager *saveMan = g_system->getSavefileManager(); - Common::OutSaveFile *out; + saveFile.slot = (offset - _screenshotOffset) / _screenshotSize; + int slotRem = (offset - _screenshotOffset) % _screenshotSize; - out = saveMan->openForSaving(setCurSlot(slot)); - if (!out) { - warning("Can't open file for slot %d for writing", slot); - delete[] _buffer[2]; - _buffer[2] = 0; - return false; - } + setCurrentSlot(saveFile.destName, saveFile.slot); + + if ((saveFile.slot < 0) || (saveFile.slot >= 30) || (slotRem != 0)) { + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, saveFile.slot, slotRem); + return false; + } - int32 varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - byte varBuf[500], sizeBuf[500]; + int index; + bool palette; - memcpy(varBuf, _buffer[0], 500); - memcpy(sizeBuf, _buffer[0] + 500, 500); + if (!_screenshot.getProperties(dataVar, size, offset, index, palette)) + return false; - bool retVal = false; - if (toEndian(varBuf, sizeBuf, 500)) - if (write(*out, varBuf, sizeBuf, 500) == 500) - if (out->write(_buffer[1] + slot * 40, 40) == 40) - if (out->write(_buffer[2], varSize * 2) == ((uint32) (varSize * 2))) { - out->flush(); - if (!out->ioFailed()) - retVal = true; - } + if (!_screenshot.saveSprite(*_vm->_draw->_spritesArray[index])) + return false; - delete[] _buffer[2]; - _buffer[2] = 0; + if (palette) + if (!_screenshot.savePalette(_vm->_global->_pPaletteDesc->vgaPal)) + return false; - if (!retVal) { - warning("Can't save to slot %d", slot); - delete out; - return false; - } + + byte *buffer = new byte[_screenshotSize]; - if (_useScreenshots) { - if (screenshotSize >= 0) { - warning("Can't save to slot %d: Screenshot expected", slot); - delete out; + if (!_screenshot.toBuffer(buffer, _screenshotSize, palette)) { + delete[] buffer; return false; } - if (!saveSprite(*out, screenshotSize)) { - delete out; + if (!_save.save(0, _screenshotSize, _varSize + 540, saveFile.destName, buffer, 0)) { + delete[] buffer; return false; } - } - out->finalize(); - if (out->ioFailed()) { - warning("Can't save to slot %d", slot); - delete out; - return false; + delete[] buffer; } - debugC(1, kDebugFileIO, "Saved to slot %d", slot); - delete out; return true; } -void SaveLoad_v3::initBuffer() { - if (_buffer) +void SaveLoad_v3::assertInited() { + if (_varSize > 0) return; - _buffer = new byte*[_stagesCount]; - - assert(_buffer); + _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; - _buffer[0] = new byte[1000]; - _buffer[1] = new byte[1200]; - _buffer[2] = 0; + _save.addStage(500); + _save.addStage(40, false); + _save.addStage(_varSize); +} - assert(_buffer[0] && _buffer[1]); +void SaveLoad_v3::buildScreenshotIndex(byte *buffer, char *name, int n) { + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; - memset(_buffer[0], 0, 1000); - memset(_buffer[1], 0, 1200); + memset(buffer, 0, n); + for (int i = 0; i < n; i++) { + in = saveMan->openForLoading(setCurrentSlot(name, i)); + if (in) { + delete in; + buffer[i] = 1; + } + } } } // End of namespace Gob diff --git a/engines/gob/saveload_v4.cpp b/engines/gob/saveload_v4.cpp new file mode 100644 index 0000000000..a6548dd82d --- /dev/null +++ b/engines/gob/saveload_v4.cpp @@ -0,0 +1,439 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" + +#include "gob/gob.h" +#include "gob/saveload.h" +#include "gob/game.h" +#include "gob/inter.h" + +namespace Gob { + +SaveLoad_v4::SaveFile SaveLoad_v4::_saveFiles[] = { + { "save.tmp", 0, kSaveModeSave, kSaveScreenProps }, + { "cat.inf", 0, kSaveModeSave, kSaveGame }, + { "save0.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save1.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save2.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save3.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save4.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save5.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save6.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save7.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save8.tmp", 0, kSaveModeSave, kSaveGameScreenProps }, + { "save9.tmp", 0, kSaveModeSave, kSaveGameScreenProps } +}; + +SaveLoad_v4::SaveLoad_v4(GobEngine *vm, const char *targetName) : + SaveLoad(vm, targetName) { + + _firstSizeGame = true; + + _saveFiles[0].destName = 0; + _saveFiles[1].destName = new char[strlen(targetName) + 5]; + _saveFiles[2].destName = _saveFiles[1].destName; + _saveFiles[3].destName = _saveFiles[1].destName; + _saveFiles[4].destName = _saveFiles[1].destName; + _saveFiles[5].destName = _saveFiles[1].destName; + _saveFiles[6].destName = _saveFiles[1].destName; + _saveFiles[7].destName = _saveFiles[1].destName; + _saveFiles[8].destName = _saveFiles[1].destName; + _saveFiles[9].destName = _saveFiles[1].destName; + _saveFiles[10].destName = _saveFiles[1].destName; + _saveFiles[11].destName = _saveFiles[1].destName; + + sprintf(_saveFiles[1].destName, "%s.s00", targetName); + + _varSize = 0; + _hasIndex = false; + memset(_propBuffer, 0, 1000); + + _screenProps = new byte[512000]; + memset(_screenProps, 0, 512000); +} + +SaveLoad_v4::~SaveLoad_v4() { + delete[] _screenProps; + delete[] _saveFiles[1].destName; +} + +SaveLoad::SaveMode SaveLoad_v4::getSaveMode(const char *fileName) { + fileName = stripPath(fileName); + + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return _saveFiles[i].mode; + + return kSaveModeNone; +} + +int SaveLoad_v4::getSaveType(const char *fileName) { + for (int i = 0; i < ARRAYSIZE(_saveFiles); i++) + if (!scumm_stricmp(fileName, _saveFiles[i].sourceName)) + return i; + + return -1; +} + +int32 SaveLoad_v4::getSizeVersioned(int type) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveScreenProps: + return getSizeScreenProps(_saveFiles[type]); + case kSaveGame: + return getSizeGame(_saveFiles[type]); + case kSaveGameScreenProps: + return getSizeGameScreenProps(_saveFiles[type]); + default: + break; + } + + return -1; +} + +bool SaveLoad_v4::loadVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveScreenProps: + if (loadScreenProps(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading screen properties"); + break; + + case kSaveGame: + if (loadGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading from slot %d", getSlot(offset)); + break; + + case kSaveGameScreenProps: + if (loadGameScreenProps(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While loading screen properties from slot %d", getSlot(offset)); + break; + + default: + break; + } + + return false; +} + +bool SaveLoad_v4::saveVersioned(int type, int16 dataVar, int32 size, int32 offset) { + assertInited(); + + switch (_saveFiles[type].type) { + case kSaveScreenProps: + if (saveScreenProps(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving screen properties"); + break; + + case kSaveGame: + if (saveGame(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving to slot %d", getSlot(offset)); + break; + + case kSaveGameScreenProps: + if (saveGameScreenProps(_saveFiles[type], dataVar, size, offset)) + return true; + + warning("While saving screen properties to slot %d", getSlot(offset)); + break; + + default: + break; + } + + return false; +} + +int SaveLoad_v4::getSlot(int32 offset) const { + return ((offset - 1700) / _varSize); +} + +int SaveLoad_v4::getSlotRemainder(int32 offset) const { + return ((offset - 1700) % _varSize); +} + +int32 SaveLoad_v4::getSizeScreenProps(SaveFile &saveFile) { + return 256000; +} + +int32 SaveLoad_v4::getSizeGame(SaveFile &saveFile) { + if (_firstSizeGame) { + _firstSizeGame = false; + return -1; + } + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + int32 size = -1; + + for (int i = 29; i >= 0; i--) { + in = saveMan->openForLoading(setCurrentSlot(saveFile.destName, i)); + if (in) { + delete in; + size = (i + 1) * _varSize + 1700; + break; + } + } + + return size; +} + +int32 SaveLoad_v4::getSizeGameScreenProps(SaveFile &saveFile) { + return -1; + + Common::SaveFileManager *saveMan = g_system->getSavefileManager(); + Common::InSaveFile *in; + + setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); + in = saveMan->openForLoading(saveFile.destName); + + if (!in) + return -1; + + int32 size = in->size(); + + delete in; + + return size; +} + +bool SaveLoad_v4::loadScreenProps(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + // Using a sprite as a buffer + if (size <= 0) + return true; + + if ((offset < 0) || (size + offset) > 256000) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } + + debugC(3, kDebugSaveLoad, "Loading screen properties (%d, %d, %d)", + dataVar, size, offset); + + _vm->_inter->_variables->copyFrom(dataVar, + _screenProps + offset, _screenProps + 256000 + offset, size); + + return true; +} + +bool SaveLoad_v4::loadGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + if (size == 0) { + dataVar = 0; + size = _varSize; + } + + if (offset < 500) { + debugC(3, kDebugSaveLoad, "Loading global properties"); + + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyFrom(dataVar, + _propBuffer + offset, _propBuffer + offset + 500, size); + + } else if (offset == 500) { + debugC(3, kDebugSaveLoad, "Loading save index"); + + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + SaveLoad::buildIndex(_vm->_inter->_variables->getAddressOff8(dataVar, 1200), + saveFile.destName, 30, 40, 1000); + + } else { + int slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Loading from slot %d", slot); + + SaveLoad::setCurrentSlot(saveFile.destName, slot); + + if ((slot < 0) || (slot >= 30) || (slotRem != 0)) { + warning("Invalid loading procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + if (!_save.load(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + return false; + } + + return true; +} + +bool SaveLoad_v4::loadGameScreenProps(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + if (size != -5) { + warning("Invalid loading procedure (%d, %d, %d)", dataVar, size, offset); + return false; + } + + setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); + + if (!_save.load(0, 256000, _varSize + 540, saveFile.destName, + _screenProps, _screenProps + 256000)) + return false; + + return true; +} + +bool SaveLoad_v4::saveScreenProps(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + // Using a sprite as a buffer + if (size <= 0) + return true; + + if ((offset < 0) || (size + offset) > 256000) { + warning("Invalid size (%d) or offset (%d)", size, offset); + return false; + } + + debugC(3, kDebugSaveLoad, "Saving screen properties (%d, %d, %d)", + dataVar, size, offset); + + _vm->_inter->_variables->copyTo(dataVar, + _screenProps + offset, _screenProps + 256000 + offset, size); + + return true; +} + +bool SaveLoad_v4::saveGame(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + if (size == 0) { + dataVar = 0; + size = _varSize; + } + + if (offset < 500) { + debugC(3, kDebugSaveLoad, "Loading global properties"); + + if ((size + offset) > 500) { + warning("Wrong global properties list size (%d, %d)", size, offset); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, + _propBuffer + offset, _propBuffer + offset + 500, size); + + } else if (offset == 500) { + debugC(3, kDebugSaveLoad, "Saving save index"); + + if (size != 1200) { + warning("Requested index has wrong size (%d)", size); + return false; + } + + _vm->_inter->_variables->copyTo(dataVar, _indexBuffer, 0, size); + _hasIndex = true; + + } else { + int slot = getSlot(offset); + int slotRem = getSlotRemainder(offset); + + debugC(2, kDebugSaveLoad, "Saving to slot %d", slot); + + SaveLoad::setCurrentSlot(saveFile.destName, slot); + + if ((slot < 0) || (slot >= 30) || (slotRem != 0)) { + warning("Invalid saving procedure (%d, %d, %d, %d, %d)", + dataVar, size, offset, slot, slotRem); + return false; + } + + if (!_hasIndex) { + warning("No index written yet"); + return false; + } + + _hasIndex = false; + + if(!_save.save(0, 500, 0, saveFile.destName, _propBuffer, _propBuffer + 500)) + return false; + + if(!_save.save(0, 40, 500, saveFile.destName, _indexBuffer + (slot * 40), 0)) + return false; + + if (!_save.save(dataVar, size, 540, saveFile.destName, _vm->_inter->_variables)) + return false; + + } + + return true; +} + +bool SaveLoad_v4::saveGameScreenProps(SaveFile &saveFile, + int16 dataVar, int32 size, int32 offset) { + + if (size != -5) { + warning("Invalid saving procedure (%d, %d, %d)", dataVar, size, offset); + return false; + } + + setCurrentSlot(saveFile.destName, saveFile.sourceName[4] - '0'); + + if (!_save.save(0, 256000, _varSize + 540, saveFile.destName, + _screenProps, _screenProps + 256000)) + return false; + + return true; +} + +void SaveLoad_v4::assertInited() { + if (_varSize > 0) + return; + + _varSize = READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4; + + _save.addStage(500); + _save.addStage(40, false); + _save.addStage(_varSize); + _save.addStage(256000); +} + +} // End of namespace Gob diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index 3f9ec9e6f2..6b52cdbbd6 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "common/stream.h" @@ -101,7 +100,6 @@ int16 Scenery::loadStatic(char search) { byte *extData = 0; byte *dataPtr; Static *ptr; - int16 pictDescId; int16 width; int16 height; int16 sprResId; @@ -144,8 +142,6 @@ int16 Scenery::loadStatic(char search) { dataPtr += 2; ptr->layers = new StaticLayer[ptr->layersCount]; - ptr->pieces = new PieceDesc*[picsCount]; - ptr->piecesFromExt = new bool[picsCount]; for (int i = 0; i < ptr->layersCount; i++) { int16 offset = READ_LE_UINT16(dataPtr + i * 2); @@ -155,9 +151,9 @@ int16 Scenery::loadStatic(char search) { ptr->layers[i].planes = new StaticPlane[ptr->layers[i].planeCount]; for (int j = 0; j < ptr->layers[i].planeCount; ++j) { - ptr->layers[i].planes[j].pictIndex = layerData.readSByte(); - ptr->layers[i].planes[j].pieceIndex = layerData.readSByte(); - ptr->layers[i].planes[j].drawOrder = layerData.readSByte(); + ptr->layers[i].planes[j].pictIndex = layerData.readByte(); + ptr->layers[i].planes[j].pieceIndex = layerData.readByte(); + ptr->layers[i].planes[j].drawOrder = layerData.readByte(); ptr->layers[i].planes[j].destX = layerData.readSint16LE(); ptr->layers[i].planes[j].destY = layerData.readSint16LE(); ptr->layers[i].planes[j].transp = layerData.readSByte(); @@ -167,18 +163,13 @@ int16 Scenery::loadStatic(char search) { backsPtr++; } + ptr->pieces = new PieceDesc*[picsCount]; + ptr->piecesCount = new uint32[picsCount]; + for (int i = 0; i < picsCount; i++) { - pictDescId = _vm->_inter->load16(); + int16 pictDescId = _vm->_inter->load16(); - if (pictDescId >= 30000) { - ptr->pieces[i] = - (PieceDesc *) _vm->_game->loadExtData(pictDescId, 0, 0); - ptr->piecesFromExt[i] = true; - } else { - ptr->pieces[i] = - (PieceDesc *) _vm->_game->loadTotResource(pictDescId); - ptr->piecesFromExt[i] = false; - } + loadPieces(pictDescId, ptr->pieces[i], ptr->piecesCount[i]); width = _vm->_inter->load16(); height = _vm->_inter->load16(); @@ -225,8 +216,7 @@ void Scenery::freeStatic(int16 index) { return; for (int i = 0; i < _staticPictCount[index]; i++) { - if (_statics[index].piecesFromExt[i]) - delete[] _statics[index].pieces[i]; + delete[] _statics[index].pieces[i]; spr = _staticPictToSprite[index * 7 + i]; _spriteRefs[spr]--; @@ -240,7 +230,7 @@ void Scenery::freeStatic(int16 index) { delete[] _statics[index].layers[i].planes; delete[] _statics[index].layers; delete[] _statics[index].pieces; - delete[] _statics[index].piecesFromExt; + delete[] _statics[index].piecesCount; _statics[index].layersCount = 0; _staticPictCount[index] = -1; @@ -254,8 +244,8 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { int16 order; int16 plane; - int16 pieceIndex; - int16 pictIndex; + uint16 pieceIndex; + uint16 pictIndex; int16 left; int16 right; @@ -278,7 +268,7 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { } planeCount = layerPtr->planeCount; - for (order = 0; order < 40; order++) { + for (order = 0; order < 100; order++) { for (plane = 0, planePtr = layerPtr->planes; plane < planeCount; plane++, planePtr++) { if (planePtr->drawOrder != order) @@ -287,12 +277,21 @@ void Scenery::renderStatic(int16 scenery, int16 layer) { pieceIndex = planePtr->pieceIndex; pictIndex = planePtr->pictIndex - 1; + if (pictIndex >= _staticPictCount[scenery]) + continue; + + if (!ptr->pieces || !ptr->pieces[pictIndex]) + continue; + + if (pieceIndex >= ptr->piecesCount[pictIndex]) + continue; + _vm->_draw->_destSpriteX = planePtr->destX; _vm->_draw->_destSpriteY = planePtr->destY; - left = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].left); - right = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].right); - top = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].top); - bottom = FROM_LE_16(ptr->pieces[pictIndex][pieceIndex].bottom); + left = ptr->pieces[pictIndex][pieceIndex].left; + right = ptr->pieces[pictIndex][pieceIndex].right; + top = ptr->pieces[pictIndex][pieceIndex].top; + bottom = ptr->pieces[pictIndex][pieceIndex].bottom; _vm->_draw->_sourceSurface = _staticPictToSprite[scenery * 7 + pictIndex]; @@ -314,8 +313,8 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { int16 planeCount; int16 order; int16 plane; - int16 pieceIndex; - int16 pictIndex; + uint16 pieceIndex; + uint16 pictIndex; int16 left; int16 right; @@ -330,7 +329,7 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { planeCount = layerPtr->planeCount; - for (order = orderFrom; order < 40; order++) { + for (order = orderFrom; order < 100; order++) { for (planePtr = layerPtr->planes, plane = 0; plane < planeCount; plane++, planePtr++) { if (planePtr->drawOrder != order) @@ -338,13 +337,23 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { pieceIndex = planePtr->pieceIndex; pictIndex = planePtr->pictIndex - 1; + + if (pictIndex >= _staticPictCount[index]) + continue; + + if (!pictPtr || !pictPtr[pictIndex]) + continue; + + if (pieceIndex >= _statics[index].piecesCount[pictIndex]) + continue; + _vm->_draw->_destSpriteX = planePtr->destX; _vm->_draw->_destSpriteY = planePtr->destY; - left = FROM_LE_16(pictPtr[pictIndex][pieceIndex].left); - right = FROM_LE_16(pictPtr[pictIndex][pieceIndex].right); - top = FROM_LE_16(pictPtr[pictIndex][pieceIndex].top); - bottom = FROM_LE_16(pictPtr[pictIndex][pieceIndex].bottom); + left = pictPtr[pictIndex][pieceIndex].left; + right = pictPtr[pictIndex][pieceIndex].right; + top = pictPtr[pictIndex][pieceIndex].top; + bottom = pictPtr[pictIndex][pieceIndex].bottom; if (_vm->_draw->_destSpriteX > _toRedrawRight) continue; @@ -415,7 +424,6 @@ int16 Scenery::loadAnim(char search) { byte *extData; byte *dataPtr; Animation *ptr; - int16 pictDescId; int16 width; int16 height; int16 sprResId; @@ -454,9 +462,6 @@ int16 Scenery::loadAnim(char search) { dataPtr += 2; ptr->layers = new AnimLayer[ptr->layersCount]; - ptr->pieces = new PieceDesc*[picsCount]; - ptr->piecesFromExt = new bool[picsCount]; - ptr->sizes = new uint16[picsCount]; for (i = 0; i < ptr->layersCount; i++) { int16 offset = READ_LE_UINT16(dataPtr + i * 2); @@ -492,23 +497,13 @@ int16 Scenery::loadAnim(char search) { } } + ptr->pieces = new PieceDesc*[picsCount]; + ptr->piecesCount = new uint32[picsCount]; + for (i = 0; i < picsCount; i++) { - pictDescId = _vm->_inter->load16(); - if (pictDescId >= 30000) { - uint32 size; - - ptr->pieces[i] = - (PieceDesc *) _vm->_game->loadExtData(pictDescId, 0, 0, &size); - ptr->piecesFromExt[i] = true; - ptr->sizes[i] = size / 8; - } else { - int16 size; + int16 pictDescId = _vm->_inter->load16(); - ptr->pieces[i] = - (PieceDesc *) _vm->_game->loadTotResource(pictDescId, &size); - ptr->piecesFromExt[i] = false; - ptr->sizes[i] = size / 8; - } + loadPieces(pictDescId, ptr->pieces[i], ptr->piecesCount[i]); width = _vm->_inter->load16(); height = _vm->_inter->load16(); @@ -554,8 +549,7 @@ void Scenery::freeAnim(int16 index) { return; for (int i = 0; i < _animPictCount[index]; i++) { - if (_animations[index].piecesFromExt[i]) - delete[] _animations[index].pieces[i]; + delete[] _animations[index].pieces[i]; spr = _animPictToSprite[index * 7 + i]; _spriteRefs[spr]--; @@ -569,8 +563,7 @@ void Scenery::freeAnim(int16 index) { delete[] _animations[index].layers[i].frames; delete[] _animations[index].layers; delete[] _animations[index].pieces; - delete[] _animations[index].piecesFromExt; - delete[] _animations[index].sizes; + delete[] _animations[index].piecesCount; _animPictCount[index] = 0; } @@ -620,8 +613,8 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, Mult::Mult_Object &obj = _vm->_mult->_objects[-animation - 1]; - if (!_vm->_vidPlayer->slotIsOpen(obj.videoSlot - 1)) { - _toRedrawLeft = -1234; + if ((obj.videoSlot == 0) || !_vm->_vidPlayer->slotIsOpen(obj.videoSlot - 1)) { + _toRedrawLeft = -12345; return; } @@ -629,8 +622,17 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, frame = _vm->_vidPlayer->getFramesCount(obj.videoSlot - 1) - 1; // Seek to frame - while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) <= frame) - _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); + if (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) < 256) { + while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) <= frame) + _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); + } else { + int16 curFrame = _vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1); + uint8 frameWrap = curFrame / 256; + frame = (frame + 1) % 256; + + while (_vm->_vidPlayer->getCurrentFrame(obj.videoSlot - 1) < (frameWrap * 256 + frame)) + _vm->_vidPlayer->slotPlay(obj.videoSlot - 1); + } destX = 0; destY = 0; @@ -724,7 +726,7 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, } - if (flags & 4) { + if (!(flags & 4)) { _animLeft = _toRedrawLeft = left; _animTop = _toRedrawTop = top; _animRight = _toRedrawRight = right; @@ -812,20 +814,19 @@ void Scenery::updateAnim(int16 layer, int16 frame, int16 animation, int16 flags, pictIndex = (pictIndex & 15) - 1; - if ((pictIndex == 0xFFFF) || (_animPictCount[animation] <= pictIndex)) { - warning("Scenery::updateAnim: pictIndex out of range"); - return; - } + if (pictIndex >= _animPictCount[animation]) + continue; - if (_animations[animation].sizes[pictIndex] <= pieceIndex) { - warning("Scenery::updateAnim: pieceIndex out of range"); + if (!pictPtr[pictIndex]) continue; - } - left = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].left); - right = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].right); - top = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].top); - bottom = READ_LE_UINT16(&pictPtr[pictIndex][pieceIndex].bottom); + if (pieceIndex >= _animations[animation].piecesCount[pictIndex]) + continue; + + left = pictPtr[pictIndex][pieceIndex].left; + right = pictPtr[pictIndex][pieceIndex].right; + top = pictPtr[pictIndex][pieceIndex].top; + bottom = pictPtr[pictIndex][pieceIndex].bottom; if (flags & 2) { if (destX < _vm->_mult->_animLeft) { @@ -946,4 +947,42 @@ Scenery::AnimLayer *Scenery::getAnimLayer(uint16 index, uint16 layer) { return &_animations[index].layers[layer]; } +void Scenery::loadPieces(int16 pictDescId, PieceDesc *&pieceDesc, uint32 &piecesCount) { + byte *data; + uint32 size; + bool fromExt = false; + + if (pictDescId >= 30000) { + fromExt = true; + + uint32 eSize; + + data = _vm->_game->loadExtData(pictDescId, 0, 0, &eSize); + size = eSize; + } else { + int16 tSize; + + data = _vm->_game->loadTotResource(pictDescId, &tSize); + size = tSize; + } + + if (!data) + error("Scenery::loadPieces(): Can't load pictDescId %d", pictDescId); + + piecesCount = size / 8; + pieceDesc = new PieceDesc[piecesCount]; + + Common::MemoryReadStream pieceData(data, size); + + for (uint32 i = 0; i < piecesCount; i++) { + pieceDesc[i].left = (int16) pieceData.readUint16LE(); + pieceDesc[i].right = (int16) pieceData.readUint16LE(); + pieceDesc[i].top = (int16) pieceData.readUint16LE(); + pieceDesc[i].bottom = (int16) pieceData.readUint16LE(); + } + + if (fromExt) + delete[] data; +} + } // End of namespace Gob diff --git a/engines/gob/scenery.h b/engines/gob/scenery.h index a1a1304d4d..21bf29deda 100644 --- a/engines/gob/scenery.h +++ b/engines/gob/scenery.h @@ -34,16 +34,16 @@ public: #include "common/pack-start.h" // START STRUCT PACKING struct PieceDesc { - int16 left; //NOTE: - int16 right; //These are stored in Little Endian format - int16 top; //And should be converted by client code when accessed - int16 bottom; //i.e. use FROM_LE_16() + int16 left; + int16 right; + int16 top; + int16 bottom; } PACKED_STRUCT; struct StaticPlane { - int8 pictIndex; - int8 pieceIndex; - int8 drawOrder; + uint8 pictIndex; + uint8 pieceIndex; + uint8 drawOrder; int16 destX; int16 destY; int8 transp; @@ -82,19 +82,16 @@ public: int16 layersCount; StaticLayer *layers; PieceDesc **pieces; - bool *piecesFromExt; - Static() : layersCount(0), layers(0), pieces(0), - piecesFromExt(0) {} + uint32 *piecesCount; + Static() : layersCount(0), layers(0), pieces(0), piecesCount(0) {} }; struct Animation { int16 layersCount; AnimLayer *layers; PieceDesc **pieces; - bool *piecesFromExt; - uint16 *sizes; - Animation() : layersCount(0), layers(0), pieces(0), - piecesFromExt(0) {} + uint32 *piecesCount; + Animation() : layersCount(0), layers(0), pieces(0), piecesCount(0) {} }; int16 _curStatic; @@ -151,6 +148,8 @@ protected: GobEngine *_vm; + void loadPieces(int16 pictDescId, PieceDesc *&pieceDesc, uint32 &piecesCount); + void updateStatic(int16 orderFrom, byte index, byte layer); }; diff --git a/engines/gob/scenery_v1.cpp b/engines/gob/scenery_v1.cpp index 5d3eb15a95..605b098693 100644 --- a/engines/gob/scenery_v1.cpp +++ b/engines/gob/scenery_v1.cpp @@ -23,13 +23,12 @@ * */ - #include "common/endian.h" #include "gob/gob.h" #include "gob/scenery.h" #include "gob/util.h" -#include "gob/cdrom.h" +#include "gob/sound/sound.h" namespace Gob { @@ -37,11 +36,11 @@ Scenery_v1::Scenery_v1(GobEngine *vm) : Scenery(vm) { } int16 Scenery_v1::loadAnim(char search) { - if (_vm->_cdrom->_cdPlaying) { - while (_vm->_cdrom->getTrackPos() != -1) + if (_vm->_sound->cdIsPlaying()) { + while (_vm->_sound->cdGetTrackPos() != -1) _vm->_util->longDelay(50); - _vm->_cdrom->_cdPlaying = false; + _vm->_sound->cdStop(); } return Scenery::loadAnim(search); diff --git a/engines/gob/scenery_v2.cpp b/engines/gob/scenery_v2.cpp index 6ed377af64..1a0de6f291 100644 --- a/engines/gob/scenery_v2.cpp +++ b/engines/gob/scenery_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" diff --git a/engines/gob/sound.cpp b/engines/gob/sound.cpp deleted file mode 100644 index 6b227cfb0e..0000000000 --- a/engines/gob/sound.cpp +++ /dev/null @@ -1,374 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - - -#include "common/endian.h" - -#include "gob/gob.h" -#include "gob/sound.h" -#include "gob/global.h" -#include "gob/util.h" -#include "gob/dataio.h" -#include "gob/game.h" - -namespace Gob { - -void SoundDesc::set(SoundType type, SoundSource src, - byte *data, uint32 dSize) { - - free(); - - _type = type; - _source = src; - _data = _dataPtr = data; - _size = dSize; -} - -void SoundDesc::load(SoundType type, SoundSource src, - byte *data, uint32 dSize) { - - free(); - - _source = src; - switch (type) { - case SOUND_ADL: - loadADL(data, dSize); - break; - case SOUND_SND: - loadSND(data, dSize); - break; - } -} - -void SoundDesc::free() { - if (_source != SOUND_TOT) - delete[] _data; - _data = _dataPtr = 0; - _id = 0; -} - -void SoundDesc::convToSigned() { - if ((_type == SOUND_SND) && _data && _dataPtr) - for (uint32 i = 0; i < _size; i++) - _dataPtr[i] ^= 0x80; -} - -void SoundDesc::loadSND(byte *data, uint32 dSize) { - assert(dSize > 6); - - _type = SOUND_SND; - _data = data; - _dataPtr = data + 6; - _frequency = MAX((int16) READ_BE_UINT16(data + 4), (int16) 4700); - _flag = data[0] ? (data[0] & 0x7F) : 8; - data[0] = 0; - _size = MIN(READ_BE_UINT32(data), dSize - 6); -} - -void SoundDesc::loadADL(byte *data, uint32 dSize) { - _type = SOUND_ADL; - _data = _dataPtr = data; - _size = dSize; -} - -Snd::Snd(GobEngine *vm) : _vm(vm) { - _playingSound = 0; - _curSoundDesc = 0; - - _rate = _vm->_mixer->getOutputRate(); - _end = true; - _data = 0; - _length = 0; - _freq = 0; - _repCount = 0; - - _offset = 0; - _offsetFrac = 0; - _offsetInc = 0; - - _cur = 0; - _last = 0; - - _fade = false; - _fadeVol = 65536; - _fadeVolStep = 0; - _fadeSamples = 0; - _curFadeSamples = 0; - - _compositionSamples = 0; - _compositionSampleCount = 0; - _compositionPos = -1; - - _speakerStream = new Audio::PCSpeaker(_vm->_mixer->getOutputRate()); - - _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_handle, - this, -1, 255, 0, false, true); - _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_speakerHandle, - _speakerStream, -1, 50, 0, false, true); -} - -Snd::~Snd() { - // stop permanent streams manually: - - // First the speaker stream - _vm->_mixer->stopHandle(_speakerHandle); - delete _speakerStream; - - // Next, this stream (class Snd is an AudioStream, too) - _vm->_mixer->stopHandle(_handle); -} - -void Snd::speakerOn(int16 frequency, int32 length) { - _speakerStream->play(Audio::PCSpeaker::kWaveFormSquare, frequency, length); -} - -void Snd::speakerOff() { - _speakerStream->stop(); -} - -void Snd::speakerOnUpdate(uint32 milis) { - if (_speakerStream->isPlaying()) - _speakerStream->stop(milis); -} - -void Snd::stopSound(int16 fadeLength, SoundDesc *sndDesc) { - Common::StackLock slock(_mutex); - - if (sndDesc && (sndDesc != _curSoundDesc)) - return; - - if (fadeLength <= 0) { - _data = 0; - _end = true; - _playingSound = 0; - _curSoundDesc = 0; - return; - } - - _fade = true; - _fadeVol = 65536; - _fadeSamples = (int) (fadeLength * (((double) _rate) / 10.0)); - _fadeVolStep = MAX((int32) 1, (int32) (65536 / _fadeSamples)); - _curFadeSamples = 0; -} - -void Snd::setRepeating(int32 repCount) { - Common::StackLock slock(_mutex); - - _repCount = repCount; -} - -void Snd::waitEndPlay(bool interruptible, bool stopComp) { - if (stopComp) - _compositionPos = -1; - while (!_end && !_vm->_quitRequested) { - if (interruptible && (_vm->_util->checkKey() == 0x11B)) { - WRITE_VAR(57, -1); - return; - } - _vm->_util->longDelay(200); - } - stopSound(0); -} - -void Snd::stopComposition() { - if (_compositionPos != -1) { - stopSound(0); - _compositionPos = -1; - } -} - -void Snd::nextCompositionPos() { - int8 slot; - - while ((++_compositionPos < 50) && - ((slot = _composition[_compositionPos]) != -1)) { - if ((slot >= 0) && (slot < _compositionSampleCount)) { - SoundDesc &sample = _compositionSamples[slot]; - if (!sample.empty() && (sample.getType() == SOUND_SND)) { - setSample(sample, 1, 0, 0); - return; - } - } - if (_compositionPos == 49) - _compositionPos = -1; - } - _compositionPos = -1; -} - -void Snd::playComposition(int16 *composition, int16 freqVal, - SoundDesc *sndDescs, int8 sndCount) { - int i; - - waitEndPlay(); - stopComposition(); - - _compositionSamples = sndDescs ? sndDescs : _vm->_game->_soundSamples; - _compositionSampleCount = sndCount; - - i = -1; - do { - i++; - _composition[i] = composition[i]; - } while ((i < 50) && (composition[i] != -1)); - - _compositionPos = -1; - nextCompositionPos(); -} - -void Snd::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, - int16 fadeLength) { - - if (frequency <= 0) - frequency = sndDesc._frequency; - - _curSoundDesc = &sndDesc; - sndDesc._repCount = repCount - 1; - sndDesc._frequency = frequency; - - _data = (int8 *) sndDesc.getData(); - _length = sndDesc.size(); - _freq = frequency; - - _repCount = repCount; - _end = false; - _playingSound = 1; - - _offset = 0; - _offsetFrac = 0; - _offsetInc = (_freq << FRAC_BITS) / _rate; - - _last = _cur; - _cur = _data[0]; - - _curFadeSamples = 0; - if (fadeLength == 0) { - _fade = false; - _fadeVol = 65536; - _fadeSamples = 0; - _fadeVolStep = 0; - } else { - _fade = true; - _fadeVol = 0; - _fadeSamples = (int) (fadeLength * (((double) _rate) / 10.0)); - _fadeVolStep = - MAX((int32) 1, (int32) (65536 / _fadeSamples)); - } -} - -bool Snd::loadSample(SoundDesc &sndDesc, const char *fileName) { - byte *data; - uint32 size; - - data = (byte *) _vm->_dataIO->getData(fileName); - if (!data) - return false; - - size = _vm->_dataIO->getDataSize(fileName); - sndDesc.load(SOUND_SND, SOUND_FILE, data, size); - - return true; -} - -void Snd::freeSample(SoundDesc &sndDesc) { - stopSound(0, &sndDesc); - sndDesc.free(); -} - -void Snd::playSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, - int16 fadeLength) { - Common::StackLock slock(_mutex); - - if (!_end) - return; - - setSample(sndDesc, repCount, frequency, fadeLength); -} - -void Snd::checkEndSample() { - if (_compositionPos != -1) - nextCompositionPos(); - else if ((_repCount == -1) || (--_repCount > 0)) { - _offset = 0; - _offsetFrac = 0; - _end = false; - _playingSound = 1; - } else { - _end = true; - _playingSound = 0; - } -} - -int Snd::readBuffer(int16 *buffer, const int numSamples) { - Common::StackLock slock(_mutex); - - for (int i = 0; i < numSamples; i++) { - if (!_data) - return i; - if (_end || (_offset >= _length)) - checkEndSample(); - if (_end) - return i; - - // Linear interpolation. See sound/rate.cpp - - int16 val = (_last + (((_cur - _last) * _offsetFrac + - FRAC_HALF) >> FRAC_BITS)) << 8; - *buffer++ = (val * _fadeVol) >> 16; - - _offsetFrac += _offsetInc; - - // Was there an integral change? - if (fracToInt(_offsetFrac) > 0) { - _last = _cur; - _cur = _data[_offset]; - _offset += fracToInt(_offsetFrac); - _offsetFrac &= FRAC_LO_MASK; - } - - if (_fade) { - - if (++_curFadeSamples >= _fadeSamples) { - if (_fadeVolStep > 0) { - _data = 0; - _end = true; - _playingSound = 0; - _compositionPos = -1; - _curSoundDesc = 0; - } else { - _fadeVol = 65536; - _fade = false; - } - } else - _fadeVol -= _fadeVolStep; - - if (_fadeVol < 0) - _fadeVol = 0; - - } - } - return numSamples; -} - -} // End of namespace Gob diff --git a/engines/gob/sound.h b/engines/gob/sound.h deleted file mode 100644 index 6780c201b5..0000000000 --- a/engines/gob/sound.h +++ /dev/null @@ -1,172 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * $URL$ - * $Id$ - * - */ - -#ifndef GOB_SOUND_H -#define GOB_SOUND_H - -#include "common/mutex.h" -#include "common/frac.h" -#include "sound/audiostream.h" -#include "sound/mixer.h" -#include "sound/softsynth/pcspk.h" - -namespace Gob { - -enum SoundType { - SOUND_SND, - SOUND_ADL -}; - -enum SoundSource { - SOUND_FILE, - SOUND_TOT, - SOUND_EXT -}; - -class SoundDesc { -public: - int16 _repCount; - int16 _frequency; - int16 _flag; - int16 _id; - - byte *getData() { return _dataPtr; } - uint32 size() { return _size; } - bool empty() { return !_dataPtr; } - bool isId(int16 id) { return _dataPtr && _id == id; } - SoundType getType() { return _type; } - - void set(SoundType type, SoundSource src, byte *data, uint32 dSize); - void load(SoundType type, SoundSource src, byte *data, uint32 dSize); - void free(); - void convToSigned(); - - // Which fade out length to use when the fade starts half-way through? - int16 calcFadeOutLength(int16 frequency) { - return (10 * (_size / 2)) / frequency; - } - uint32 calcLength(int16 repCount, int16 frequency, bool fade) { - uint32 fadeSize = fade ? _size / 2 : 0; - return ((_size * repCount - fadeSize) * 1000) / frequency; - } - - SoundDesc() : _data(0), _dataPtr(0), _size(0), _type(SOUND_SND), - _source(SOUND_FILE), _repCount(0), _frequency(0), - _flag(0), _id(0) {} - ~SoundDesc() { free(); } - -private: - byte *_data; - byte *_dataPtr; - uint32 _size; - - SoundType _type; - SoundSource _source; - - void loadSND(byte *data, uint32 dSize); - void loadADL(byte *data, uint32 dSize); -}; - -class Snd : public Audio::AudioStream { -public: - char _playingSound; - - Snd(GobEngine *vm); - ~Snd(); - - void speakerOn(int16 frequency, int32 length); - void speakerOff(); - void speakerOnUpdate(uint32 milis); - void stopSound(int16 fadeLength, SoundDesc *sndDesc = 0); - - bool loadSample(SoundDesc &sndDesc, const char *fileName); - void freeSample(SoundDesc &sndDesc); - void playSample(SoundDesc &sndDesc, int16 repCount, - int16 frequency, int16 fadeLength = 0); - - void playComposition(int16 *composition, int16 freqVal, - SoundDesc *sndDescs = 0, int8 sndCount = 60); - void stopComposition(); - void setRepeating(int32 repCount); - void waitEndPlay(bool interruptible = false, bool stopComp = true); - - static void convToSigned(byte *buffer, int length) { - while (length-- > 0) - *buffer++ ^= 0x80; - } - - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const { return _end; } - bool endOfStream() const { return false; } - int getRate() const { return _rate; } - -protected: - Audio::PCSpeaker *_speakerStream; - Audio::SoundHandle _speakerHandle; - - Audio::SoundHandle *_activeHandle; - Audio::SoundHandle _compositionHandle; - - SoundDesc *_compositionSamples; - int8 _compositionSampleCount; - int16 _composition[50]; - int8 _compositionPos; - - Audio::SoundHandle _handle; - Common::Mutex _mutex; - SoundDesc *_curSoundDesc; - bool _end; - int8 *_data; - uint32 _length; - uint32 _rate; - int32 _freq; - int32 _repCount; - - uint32 _offset; - frac_t _offsetFrac; - frac_t _offsetInc; - - int16 _cur; - int16 _last; - - bool _fade; - int32 _fadeVol; - int32 _fadeVolStep; - uint8 _fadeLength; - uint32 _fadeSamples; - uint32 _curFadeSamples; - - GobEngine *_vm; - - void setSample(SoundDesc &sndDesc, int16 repCount, - int16 frequency, int16 fadeLength); - void checkEndSample(); - void nextCompositionPos(); -}; - -} // End of namespace Gob - -#endif // GOB_SOUND_H diff --git a/engines/gob/music.cpp b/engines/gob/sound/adlib.cpp index 7be046c02a..b3d392ad1e 100644 --- a/engines/gob/music.cpp +++ b/engines/gob/sound/adlib.cpp @@ -24,91 +24,55 @@ */ #include "common/file.h" - #include "common/endian.h" #include "gob/gob.h" -#include "gob/music.h" -#include "gob/game.h" -#include "gob/util.h" +#include "gob/sound/adlib.h" namespace Gob { -const char *Adlib::_tracks[][2] = { - {"avt00.tot", "mine"}, - {"avt001.tot", "nuit"}, - {"avt002.tot", "campagne"}, - {"avt003.tot", "extsor1"}, - {"avt004.tot", "interieure"}, - {"avt005.tot", "zombie"}, - {"avt006.tot", "zombie"}, - {"avt007.tot", "campagne"}, - {"avt008.tot", "campagne"}, - {"avt009.tot", "extsor1"}, - {"avt010.tot", "extsor1"}, - {"avt011.tot", "interieure"}, - {"avt012.tot", "zombie"}, - {"avt014.tot", "nuit"}, - {"avt015.tot", "interieure"}, - {"avt016.tot", "statue"}, - {"avt017.tot", "zombie"}, - {"avt018.tot", "statue"}, - {"avt019.tot", "mine"}, - {"avt020.tot", "statue"}, - {"avt021.tot", "mine"}, - {"avt022.tot", "zombie"} -}; - -const char *Adlib::_trackFiles[] = { -// "musmac1.adl", // TODO: This track isn't played correctly at all yet - "musmac2.adl", - "musmac3.adl", - "musmac4.adl", - "musmac5.adl", - "musmac6.adl" -}; - -const unsigned char Adlib::_operators[] = {0, 1, 2, 8, 9, 10, 16, 17, 18}; -const unsigned char Adlib::_volRegNums[] = { +const unsigned char AdLib::_operators[] = {0, 1, 2, 8, 9, 10, 16, 17, 18}; +const unsigned char AdLib::_volRegNums[] = { 3, 4, 5, 11, 12, 13, 19, 20, 21 }; -Adlib::Adlib(GobEngine *vm) : _vm(vm) { - int i; - +AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer) { _index = -1; _data = 0; _playPos = 0; _dataSize = 0; - _rate = _vm->_mixer->getOutputRate(); + + _rate = _mixer->getOutputRate(); _opl = makeAdlibOPL(_rate); + _first = true; _ended = false; _playing = false; _needFree = false; + _repCount = -1; _samplesTillPoll = 0; - for (i = 0; i < 16; i ++) + for (int i = 0; i < 16; i ++) _pollNotes[i] = 0; setFreqs(); - _vm->_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_handle, + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_handle, this, -1, 255, 0, false, true); } -Adlib::~Adlib() { +AdLib::~AdLib() { Common::StackLock slock(_mutex); - _vm->_mixer->stopHandle(_handle); + _mixer->stopHandle(_handle); OPLDestroy(_opl); if (_data && _needFree) delete[] _data; } -int Adlib::readBuffer(int16 *buffer, const int numSamples) { +int AdLib::readBuffer(int16 *buffer, const int numSamples) { Common::StackLock slock(_mutex); int samples; int render; @@ -160,12 +124,12 @@ int Adlib::readBuffer(int16 *buffer, const int numSamples) { return numSamples; } -void Adlib::writeOPL(byte reg, byte val) { - debugC(6, kDebugMusic, "writeOPL(%02X, %02X)", reg, val); +void AdLib::writeOPL(byte reg, byte val) { + debugC(6, kDebugSound, "writeOPL(%02X, %02X)", reg, val); OPLWriteReg(_opl, reg, val); } -void Adlib::setFreqs() { +void AdLib::setFreqs() { byte lin; byte col; long val = 0; @@ -191,7 +155,7 @@ void Adlib::setFreqs() { } } -void Adlib::reset() { +void AdLib::reset() { _first = true; OPLResetChip(_opl); _samplesTillPoll = 0; @@ -209,13 +173,13 @@ void Adlib::reset() { writeOPL(0x01, 0x20); } -void Adlib::setVoices() { +void AdLib::setVoices() { // Definitions of the 9 instruments for (int i = 0; i < 9; i++) setVoice(i, i, true); } -void Adlib::setVoice(byte voice, byte instr, bool set) { +void AdLib::setVoice(byte voice, byte instr, bool set) { int i; int j; uint16 strct[27]; @@ -251,7 +215,7 @@ void Adlib::setVoice(byte voice, byte instr, bool set) { } } -void Adlib::setKey(byte voice, byte note, bool on, bool spec) { +void AdLib::setKey(byte voice, byte note, bool on, bool spec) { short freq = 0; short octa = 0; @@ -317,12 +281,12 @@ void Adlib::setKey(byte voice, byte note, bool on, bool spec) { warning("Voice %d, note %02X unknown\n", voice, note); } -void Adlib::setVolume(byte voice, byte volume) { +void AdLib::setVolume(byte voice, byte volume) { volume = 0x3F - (volume * 0x7E + 0x7F) / 0xFE; writeOPL(0x40 + _volRegNums[voice], volume); } -void Adlib::pollMusic() { +void AdLib::pollMusic() { unsigned char instr; byte channel; byte note; @@ -419,24 +383,7 @@ void Adlib::pollMusic() { _samplesTillPoll = tempo * (_rate / 1000); } -void Adlib::playBgMusic() { - for (int i = 0; i < ARRAYSIZE(_tracks); i++) - if (!scumm_stricmp(_vm->_game->_curTotFile, _tracks[i][0])) { - playTrack(_tracks[i][1]); - break; - } -} - -void Adlib::playTrack(const char *trackname) { - if (_playing) return; - - debugC(1, kDebugMusic, "Adlib::playTrack(%s)", trackname); - unload(); - load(_trackFiles[_vm->_util->getRandom(ARRAYSIZE(_trackFiles))]); - startPlay(); -} - -bool Adlib::load(const char *fileName) { +bool AdLib::load(const char *fileName) { Common::File song; unload(); @@ -457,7 +404,7 @@ bool Adlib::load(const char *fileName) { return true; } -void Adlib::load(byte *data, uint32 size, int index) { +bool AdLib::load(byte *data, uint32 size, int index) { unload(); _repCount = 0; @@ -468,9 +415,11 @@ void Adlib::load(byte *data, uint32 size, int index) { reset(); setVoices(); _playPos = _data + 3 + (_data[1] + 1) * 0x38; + + return true; } -void Adlib::unload() { +void AdLib::unload() { _playing = false; _index = -1; @@ -480,4 +429,29 @@ void Adlib::unload() { _needFree = false; } +bool AdLib::isPlaying() const { + return _playing; +} + +bool AdLib::getRepeating() const { + return _repCount != 0; +} + +void AdLib::setRepeating(int32 repCount) { + _repCount = repCount; +} + +int AdLib::getIndex() const { + return _index; +} + +void AdLib::startPlay() { + if (_data) _playing = true; +} + +void AdLib::stopPlay() { + Common::StackLock slock(_mutex); + _playing = false; +} + } // End of namespace Gob diff --git a/engines/gob/music.h b/engines/gob/sound/adlib.h index 199ea515b0..4cd83d5883 100644 --- a/engines/gob/music.h +++ b/engines/gob/sound/adlib.h @@ -23,8 +23,8 @@ * */ -#ifndef GOB_MUSIC_H -#define GOB_MUSIC_H +#ifndef GOB_SOUND_ADLIB_H +#define GOB_SOUND_ADLIB_H #include "common/mutex.h" #include "sound/audiostream.h" @@ -35,61 +35,63 @@ namespace Gob { class GobEngine; -class Adlib : public Audio::AudioStream { +class AdLib : public Audio::AudioStream { public: - Adlib(GobEngine *vm); - ~Adlib(); - - void lock() { _mutex.lock(); } - void unlock() { _mutex.unlock(); } - bool playing() const { return _playing; } - bool getRepeating() const { return _repCount != 0; } - void setRepeating (int32 repCount) { _repCount = repCount; } - int getIndex() const { return _index; } - void startPlay() { if (_data) _playing = true; } - void stopPlay() { - Common::StackLock slock(_mutex); - _playing = false; - } - void playTrack(const char *trackname); - void playBgMusic(); + AdLib(Audio::Mixer &mixer); + ~AdLib(); + + bool isPlaying() const; + int getIndex() const; + bool getRepeating() const; + + void setRepeating(int32 repCount); + + void startPlay(); + void stopPlay(); + bool load(const char *fileName); - void load(byte *data, uint32 size, int index = -1); + bool load(byte *data, uint32 size, int index = -1); void unload(); // AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return false; } - bool endOfData() const { return !_playing; } - bool endOfStream() const { return false; } - int getRate() const { return _rate; } + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return false; } + bool endOfData() const { return !_playing; } + bool endOfStream() const { return false; } + int getRate() const { return _rate; } protected: - static const char *_tracks[][2]; - static const char *_trackFiles[]; static const unsigned char _operators[]; static const unsigned char _volRegNums []; + + Audio::Mixer *_mixer; Audio::SoundHandle _handle; FM_OPL *_opl; - int _index; + + Common::Mutex _mutex; + + uint32 _rate; + byte *_data; byte *_playPos; uint32 _dataSize; - uint32 _rate; + short _freqs[25][12]; byte _notes[11]; byte _notCol[11]; byte _notLin[11]; bool _notOn[11]; byte _pollNotes[16]; + int _samplesTillPoll; int32 _repCount; + bool _playing; bool _first; bool _ended; bool _needFree; - Common::Mutex _mutex; - GobEngine *_vm; + + int _index; void writeOPL(byte reg, byte val); void setFreqs(); @@ -103,4 +105,4 @@ protected: } // End of namespace Gob -#endif // GOB_MUSIC_H +#endif // GOB_SOUND_ADLIB_H diff --git a/engines/gob/sound/bgatmosphere.cpp b/engines/gob/sound/bgatmosphere.cpp new file mode 100644 index 0000000000..f5a7fe0fdb --- /dev/null +++ b/engines/gob/sound/bgatmosphere.cpp @@ -0,0 +1,128 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/system.h" +#include "common/events.h" + +#include "gob/sound/bgatmosphere.h" + +namespace Gob { + +BackgroundAtmosphere::BackgroundAtmosphere(Audio::Mixer &mixer) : + SoundMixer(mixer, Audio::Mixer::kMusicSoundType) { + + _playMode = kPlayModeLinear; + _queuePos = -1; + _shaded = false; + + g_system->getEventManager()->registerRandomSource(_rnd, "gobBA"); +} + +BackgroundAtmosphere::~BackgroundAtmosphere() { + queueClear(); +} + +void BackgroundAtmosphere::play() { + Common::StackLock slock(_mutex); + + _queuePos = -1; + getNextQueuePos(); + + if (_queuePos == -1) + return; + + SoundMixer::play(*_queue[_queuePos], 1, 0); +} + +void BackgroundAtmosphere::stop() { + SoundMixer::stop(0); +} + +void BackgroundAtmosphere::setPlayMode(PlayMode mode) { + _playMode = mode; +} + +void BackgroundAtmosphere::queueSample(SoundDesc &sndDesc) { + Common::StackLock slock(_mutex); + + _queue.push_back(&sndDesc); +} + +void BackgroundAtmosphere::queueClear() { + Common::StackLock slock(_mutex); + + SoundMixer::stop(0); + for (uint i = 0; i < _queue.size(); i++) + delete _queue[i]; + + _queue.clear(); + _queuePos = -1; +} + +void BackgroundAtmosphere::checkEndSample() { + Common::StackLock slock(_mutex); + + getNextQueuePos(); + + if (_queuePos == -1) { + _end = true; + _playingSound = 0; + } else { + SoundMixer::setSample(*_queue[_queuePos], 1, 0, 0); + if (_shaded) + _fadeVol = 20000; + } +} + +void BackgroundAtmosphere::getNextQueuePos() { + if (_queue.size() == 0) { + _queuePos = -1; + return; + } + + switch (_playMode) { + + case kPlayModeLinear: + _queuePos = (_queuePos + 1) % _queue.size(); + break; + + case kPlayModeRandom: + _queuePos = _rnd.getRandomNumber(_queue.size() - 1); + break; + + } +} + +void BackgroundAtmosphere::shade() { + _shaded = true; + _fadeVol = 32768; +} + +void BackgroundAtmosphere::unshade() { + _shaded = false; + _fadeVol = 65536; +} + +} // End of namespace Gob diff --git a/engines/gob/sound/bgatmosphere.h b/engines/gob/sound/bgatmosphere.h new file mode 100644 index 0000000000..72b5614282 --- /dev/null +++ b/engines/gob/sound/bgatmosphere.h @@ -0,0 +1,75 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_BGATMOSPHERE_H +#define GOB_SOUND_BGATMOSPHERE_H + +#include "sound/mixer.h" +#include "common/mutex.h" + +#include "gob/sound/sounddesc.h" +#include "gob/sound/soundmixer.h" + +namespace Gob { + +class BackgroundAtmosphere : private SoundMixer { +public: + enum PlayMode { + kPlayModeLinear, + kPlayModeRandom + }; + + BackgroundAtmosphere(Audio::Mixer &mixer); + ~BackgroundAtmosphere(); + + void play(); + void stop(); + + void setPlayMode(PlayMode mode); + + void queueSample(SoundDesc &sndDesc); + void queueClear(); + + void shade(); + void unshade(); + +private: + PlayMode _playMode; + + Common::Array<SoundDesc *> _queue; + int _queuePos; + bool _shaded; + + Common::Mutex _mutex; + + Common::RandomSource _rnd; + + void checkEndSample(); + void getNextQueuePos(); +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_BGATMOSPHERE_H diff --git a/engines/gob/cdrom.cpp b/engines/gob/sound/cdrom.cpp index c037d24bbe..eef8025cc2 100644 --- a/engines/gob/cdrom.cpp +++ b/engines/gob/sound/cdrom.cpp @@ -23,20 +23,16 @@ * */ - #include "common/endian.h" +#include "common/util.h" #include "sound/audiocd.h" #include "gob/gob.h" -#include "gob/cdrom.h" -#include "gob/global.h" -#include "gob/util.h" -#include "gob/dataio.h" -#include "gob/game.h" +#include "gob/sound/cdrom.h" namespace Gob { -CDROM::CDROM(GobEngine *vm) : _vm(vm) { +CDROM::CDROM() { _cdPlaying = false; _LICbuffer = 0; @@ -47,116 +43,46 @@ CDROM::CDROM(GobEngine *vm) : _vm(vm) { _startTime = 0; } -void CDROM::readLIC(const char *fname) { - char tmp[80]; - int handle; - uint16 version, startChunk, pos; +CDROM::~CDROM() { +} - freeLICbuffer(); +void CDROM::readLIC(DataStream &stream) { + uint16 version, startChunk, pos; + freeLICBuffer(); *_curTrack = 0; - strncpy0(tmp, fname, 79); - - handle = _vm->_dataIO->openData(tmp); - - if (handle == -1) - return; - - _vm->_dataIO->closeData(handle); - - _vm->_dataIO->getUnpackedData(tmp); - - handle = _vm->_dataIO->openData(tmp); - DataStream *stream = _vm->_dataIO->openAsStream(handle, true); - - version = stream->readUint16LE(); - startChunk = stream->readUint16LE(); - _numTracks = stream->readUint16LE(); + version = stream.readUint16LE(); + startChunk = stream.readUint16LE(); + _numTracks = stream.readUint16LE(); if (version != 3) - error("%s: Unknown version %d", fname, version); + error("Unknown version %d while reading LIC", version); - stream->seek(50); + stream.seek(50); for (int i = 0; i < startChunk; i++) { - pos = stream->readUint16LE(); + pos = stream.readUint16LE(); if (!pos) break; - stream->skip(pos); + stream.skip(pos); } _LICbuffer = new byte[_numTracks * 22]; - stream->read(_LICbuffer, _numTracks * 22); - - delete stream; + stream.read(_LICbuffer, _numTracks * 22); } -void CDROM::freeLICbuffer() { +void CDROM::freeLICBuffer() { delete[] _LICbuffer; _LICbuffer = 0; } -void CDROM::playBgMusic() { - static const char *tracks[][2] = { - {"avt00.tot", "mine"}, - {"avt001.tot", "nuit"}, - {"avt002.tot", "campagne"}, - {"avt003.tot", "extsor1"}, - {"avt004.tot", "interieure"}, - {"avt005.tot", "zombie"}, - {"avt006.tot", "zombie"}, - {"avt007.tot", "campagne"}, - {"avt008.tot", "campagne"}, - {"avt009.tot", "extsor1"}, - {"avt010.tot", "extsor1"}, - {"avt011.tot", "interieure"}, - {"avt012.tot", "zombie"}, - {"avt014.tot", "nuit"}, - {"avt015.tot", "interieure"}, - {"avt016.tot", "statue"}, - {"avt017.tot", "zombie"}, - {"avt018.tot", "statue"}, - {"avt019.tot", "mine"}, - {"avt020.tot", "statue"}, - {"avt021.tot", "mine"}, - {"avt022.tot", "zombie"} - }; - - for (int i = 0; i < ARRAYSIZE(tracks); i++) - if (!scumm_stricmp(_vm->_game->_curTotFile, tracks[i][0])) { - startTrack(tracks[i][1]); - break; - } -} - -void CDROM::playMultMusic() { - static const char *tracks[][6] = { - {"avt005.tot", "fra1", "all1", "ang1", "esp1", "ita1"}, - {"avt006.tot", "fra2", "all2", "ang2", "esp2", "ita2"}, - {"avt012.tot", "fra3", "all3", "ang3", "esp3", "ita3"}, - {"avt016.tot", "fra4", "all4", "ang4", "esp4", "ita4"}, - {"avt019.tot", "fra5", "all5", "ang5", "esp5", "ita5"}, - {"avt022.tot", "fra6", "all6", "ang6", "esp6", "ita6"} - }; - - // Default to "ang?" for other languages (including EN_USA) - int language = _vm->_global->_language <= 4 ? _vm->_global->_language : 2; - for (int i = 0; i < ARRAYSIZE(tracks); i++) - if (!scumm_stricmp(_vm->_game->_curTotFile, tracks[i][0])) { - startTrack(tracks[i][language + 1]); - break; - } -} - void CDROM::startTrack(const char *trackName) { if (!_LICbuffer) return; - debugC(1, kDebugMusic, "CDROM::startTrack(%s)", trackName); - byte *matchPtr = getTrackBuffer(trackName); if (!matchPtr) { warning("Track \"%s\" not found", trackName); @@ -175,7 +101,7 @@ void CDROM::startTrack(const char *trackName) { play(start, end); - _startTime = _vm->_util->getTimeKey(); + _startTime = g_system->getMillis(); _trackStop = _startTime + (end - start + 1 + 150) * 40 / 3; } @@ -186,17 +112,19 @@ void CDROM::play(uint32 from, uint32 to) { // HSG encodes frame information into a double word: // minute multiplied by 4500, plus second multiplied by 75, // plus frame, minus 150 - debugC(1, kDebugMusic, "CDROM::play(%d, %d)", from, to); - AudioCD.play(1, 1, from, to - from + 1); _cdPlaying = true; } -int32 CDROM::getTrackPos(const char *keyTrack) { +bool CDROM::isPlaying() const { + return _cdPlaying; +} + +int32 CDROM::getTrackPos(const char *keyTrack) const { byte *keyBuffer = getTrackBuffer(keyTrack); - uint32 curPos = (_vm->_util->getTimeKey() - _startTime) * 3 / 40; + uint32 curPos = (g_system->getMillis() - _startTime) * 3 / 40; - if (_cdPlaying && (_vm->_util->getTimeKey() < _trackStop)) { + if (_cdPlaying && (g_system->getMillis() < _trackStop)) { if (keyBuffer && _curTrackBuffer && (keyBuffer != _curTrackBuffer)) { uint32 kStart = READ_LE_UINT32(keyBuffer + 12); uint32 kEnd = READ_LE_UINT32(keyBuffer + 16); @@ -216,7 +144,7 @@ int32 CDROM::getTrackPos(const char *keyTrack) { return -1; } -const char *CDROM::getCurTrack() { +const char *CDROM::getCurTrack() const { return _curTrack; } @@ -227,8 +155,6 @@ void CDROM::stopPlaying() { } void CDROM::stop() { - debugC(1, kDebugMusic, "CDROM::stop()"); - _curTrackBuffer = 0; AudioCD.stop(); _cdPlaying = false; @@ -248,7 +174,7 @@ void CDROM::testCD(int trySubst, const char *label) { // CD secor reading } -byte *CDROM::getTrackBuffer(const char *trackName) { +byte *CDROM::getTrackBuffer(const char *trackName) const { if (!_LICbuffer || !trackName) return 0; diff --git a/engines/gob/cdrom.h b/engines/gob/sound/cdrom.h index 25490de5dc..201f7adb75 100644 --- a/engines/gob/cdrom.h +++ b/engines/gob/sound/cdrom.h @@ -23,29 +23,30 @@ * */ -#ifndef GOB_CDROM_H -#define GOB_CDROM_H +#ifndef GOB_SOUND_CDROM_H +#define GOB_SOUND_CDROM_H + +#include "gob/dataio.h" namespace Gob { class CDROM { public: - bool _cdPlaying; + CDROM(); + ~CDROM(); - void readLIC(const char *fname); - void freeLICbuffer(); + void readLIC(DataStream &stream); + void freeLICBuffer(); void startTrack(const char *trackName); - void playBgMusic(); - void playMultMusic(); - void play(uint32 from, uint32 to); - int32 getTrackPos(const char *keyTrack = 0); - const char *getCurTrack(); void stopPlaying(); - void stop(); - void testCD(int trySubst, const char *label); - CDROM(GobEngine *vm); + bool isPlaying() const; + + int32 getTrackPos(const char *keyTrack = 0) const; + const char *getCurTrack() const; + + void testCD(int trySubst, const char *label); protected: byte *_LICbuffer; @@ -54,11 +55,14 @@ protected: uint16 _numTracks; uint32 _trackStop; uint32 _startTime; - GobEngine *_vm; + bool _cdPlaying; + + void play(uint32 from, uint32 to); + void stop(); - byte *getTrackBuffer(const char *trackName); + byte *getTrackBuffer(const char *trackName) const; }; } // End of namespace Gob -#endif // GOB_CDROM_H +#endif // GOB_SOUND_CDROM_H diff --git a/engines/gob/sound/infogrames.cpp b/engines/gob/sound/infogrames.cpp new file mode 100644 index 0000000000..0b46f3485c --- /dev/null +++ b/engines/gob/sound/infogrames.cpp @@ -0,0 +1,103 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/sound/infogrames.h" + +namespace Gob { + +Infogrames::Infogrames(Audio::Mixer &mixer) : _mixer(&mixer) { + _instruments = 0; + _song = 0; +} + +Infogrames::~Infogrames() { + clearSong(); + clearInstruments(); +} + +bool Infogrames::loadInstruments(const char *fileName) { + clearSong(); + clearInstruments(); + + return loadInst(fileName); +} + +bool Infogrames::loadSong(const char *fileName) { + clearSong(); + + if (!_instruments) + if (!loadInst("i1.ins")) + return false; + + _song = new Audio::Infogrames(*_instruments, true, + _mixer->getOutputRate(), _mixer->getOutputRate() / 75); + + if (!_song->load(fileName)) { + warning("Couldn't load infogrames music"); + clearSong(); + return false; + } + + return true; +} + +void Infogrames::play() { + if (_song && !_mixer->isSoundHandleActive(_handle)) { + _song->restart(); + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, + &_handle, _song, -1, 255, 0, false); + } +} + +void Infogrames::stop() { + _mixer->stopHandle(_handle); +} + +void Infogrames::clearInstruments() { + delete _instruments; + _instruments = 0; +} + +void Infogrames::clearSong() { + if (_song) { + _mixer->stopHandle(_handle); + + delete _song; + _song = 0; + } +} + +bool Infogrames::loadInst(const char *fileName) { + _instruments = new Audio::Infogrames::Instruments; + if (!_instruments->load(fileName)) { + warning("Couldn't load instruments file"); + clearInstruments(); + return false; + } + + return true; +} + +} // End of namespace Gob diff --git a/engines/gob/sound/infogrames.h b/engines/gob/sound/infogrames.h new file mode 100644 index 0000000000..4a20dceb22 --- /dev/null +++ b/engines/gob/sound/infogrames.h @@ -0,0 +1,60 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_INFOGRAMES_H +#define GOB_SOUND_INFOGRAMES_H + +#include "sound/mixer.h" +#include "sound/mods/infogrames.h" + +namespace Gob { + +class Infogrames { +public: + Infogrames(Audio::Mixer &mixer); + ~Infogrames(); + + bool loadInstruments(const char *fileName); + bool loadSong(const char *fileName); + + void play(); + void stop(); + +private: + Audio::Mixer *_mixer; + + Audio::Infogrames::Instruments *_instruments; + Audio::Infogrames *_song; + Audio::SoundHandle _handle; + + void clearInstruments(); + void clearSong(); + + bool loadInst(const char *fileName); +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_INFOGRAMES_H diff --git a/engines/gob/sound/pcspeaker.cpp b/engines/gob/sound/pcspeaker.cpp new file mode 100644 index 0000000000..0d1fc0a6db --- /dev/null +++ b/engines/gob/sound/pcspeaker.cpp @@ -0,0 +1,55 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/sound/pcspeaker.h" + +namespace Gob { + +PCSpeaker::PCSpeaker(Audio::Mixer &mixer) : _mixer(&mixer) { + + _stream = new Audio::PCSpeaker(_mixer->getOutputRate()); + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, + &_handle, _stream, -1, 50, 0, false, true); +} + +PCSpeaker::~PCSpeaker() { + _mixer->stopHandle(_handle); + delete _stream; +} + +void PCSpeaker::speakerOn(int16 frequency, int32 length) { + _stream->play(Audio::PCSpeaker::kWaveFormSquare, frequency, length); +} + +void PCSpeaker::speakerOff() { + _stream->stop(); +} + +void PCSpeaker::onUpdate(uint32 millis) { + if (_stream->isPlaying()) + _stream->stop(millis); +} + +} // End of namespace Gob diff --git a/engines/gob/sound/pcspeaker.h b/engines/gob/sound/pcspeaker.h new file mode 100644 index 0000000000..8c4fb08021 --- /dev/null +++ b/engines/gob/sound/pcspeaker.h @@ -0,0 +1,52 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_PCSPEAKER_H +#define GOB_SOUND_PCSPEAKER_H + +#include "sound/mixer.h" +#include "sound/softsynth/pcspk.h" + +namespace Gob { + +class PCSpeaker { +public: + PCSpeaker(Audio::Mixer &mixer); + ~PCSpeaker(); + + void speakerOn(int16 frequency, int32 length = -1); + void speakerOff(); + void onUpdate(uint32 millis); + +private: + Audio::Mixer *_mixer; + + Audio::PCSpeaker *_stream; + Audio::SoundHandle _handle; +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_PCSPEAKER_H diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp new file mode 100644 index 0000000000..2d2bf8e043 --- /dev/null +++ b/engines/gob/sound/sound.cpp @@ -0,0 +1,582 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/gob.h" +#include "gob/sound/sound.h" +#include "gob/global.h" +#include "gob/util.h" +#include "gob/dataio.h" +#include "gob/game.h" +#include "gob/inter.h" + +namespace Gob { + +Sound::Sound(GobEngine *vm) : _vm(vm) { + _pcspeaker = new PCSpeaker(*_vm->_mixer); + _blaster = new SoundBlaster(*_vm->_mixer); + + _adlib = 0; + _infogrames = 0; + _cdrom = 0; + _bgatmos = 0; + + if (!_vm->_noMusic && _vm->hasAdlib()) + _adlib = new AdLib(*_vm->_mixer); + if (!_vm->_noMusic && (_vm->getPlatform() == Common::kPlatformAmiga)) + _infogrames = new Infogrames(*_vm->_mixer); + if (_vm->isCD()) + _cdrom = new CDROM; + if (_vm->getGameType() == kGameTypeWoodruff) + _bgatmos = new BackgroundAtmosphere(*_vm->_mixer); +} + +Sound::~Sound() { + delete _pcspeaker; + delete _blaster; + delete _adlib; + delete _infogrames; + delete _cdrom; + delete _bgatmos; + + for (int i = 0; i < kSoundsCount; i++) + _sounds[i].free(); +} + +void Sound::convToSigned(byte *buffer, int length) { + while (length-- > 0) + *buffer++ ^= 0x80; +} + +SoundDesc *Sound::sampleGetBySlot(int slot) { + if ((slot < 0) || (slot >= kSoundsCount)) + return 0; + + return &_sounds[slot]; +} + +const SoundDesc *Sound::sampleGetBySlot(int slot) const { + if ((slot < 0) || (slot >= kSoundsCount)) + return 0; + + return &_sounds[slot]; +} + +int Sound::sampleGetNextFreeSlot() const { + for (int i = 0; i < kSoundsCount; i++) + if (_sounds[i].empty()) + return i; + + return -1; +} + +bool Sound::sampleLoad(SoundDesc *sndDesc, const char *fileName, bool tryExist) { + if (!sndDesc) + return false; + + debugC(2, kDebugSound, "Loading sample \"%s\"", fileName); + + int16 handle = _vm->_dataIO->openData(fileName); + if (handle < 0) { + warning("Can't open sample file \"%s\"", fileName); + return false; + } + + _vm->_dataIO->closeData(handle); + + byte *data; + uint32 size; + + data = (byte *) _vm->_dataIO->getData(fileName); + if (!data) + return false; + + size = _vm->_dataIO->getDataSize(fileName); + sndDesc->load(SOUND_SND, SOUND_FILE, data, size); + + return true; +} + +void Sound::sampleFree(SoundDesc *sndDesc, bool noteAdlib, int index) { + if (!sndDesc || sndDesc->empty()) + return; + + if (sndDesc->getType() == SOUND_ADL) { + + if (_adlib && noteAdlib) + if ((index == -1) || (_adlib->getIndex() == index)) + _adlib->stopPlay(); + + } else { + + if (_blaster) + _blaster->stopSound(0, sndDesc); + + } + + sndDesc->free(); +} + +void Sound::speakerOn(int16 frequency, int32 length) { + if (!_pcspeaker) + return; + + debugC(1, kDebugSound, "PCSpeaker: Playing tone (%d, %d)", frequency, length); + + _pcspeaker->speakerOn(frequency, length); +} + +void Sound::speakerOff() { + if (!_pcspeaker) + return; + + debugC(1, kDebugSound, "PCSpeaker: Stopping tone"); + + _pcspeaker->speakerOff(); +} + +void Sound::speakerOnUpdate(uint32 millis) { + if (!_pcspeaker) + return; + + _pcspeaker->onUpdate(millis); +} + +bool Sound::infogramesLoadInstruments(const char *fileName) { + if (!_infogrames) + return false; + + debugC(1, kDebugSound, "Infogrames: Loading instruments \"%s\"", fileName); + + return _infogrames->loadInstruments(fileName); +} + +bool Sound::infogramesLoadSong(const char *fileName) { + if (!_infogrames) + return false; + + debugC(1, kDebugSound, "Infogrames: Loading song \"%s\"", fileName); + + return _infogrames->loadSong(fileName); +} + +void Sound::infogramesPlay() { + if (!_infogrames) + return; + + debugC(1, kDebugSound, "Infogrames: Starting playback"); + + _infogrames->play(); +} + +void Sound::infogramesStop() { + if (!_infogrames) + return; + + debugC(1, kDebugSound, "Infogrames: Stopping playback"); + + _infogrames->stop(); +} + +bool Sound::adlibLoad(const char *fileName) { + if (!_adlib) + return false; + + debugC(1, kDebugSound, "Adlib: Loading data (\"%s\")", fileName); + + return _adlib->load(fileName); +} + +bool Sound::adlibLoad(byte *data, uint32 size, int index) { + if (!_adlib) + return false; + + debugC(1, kDebugSound, "Adlib: Loading data (%d)", index); + + return _adlib->load(data, size, index); +} + +void Sound::adlibUnload() { + if (!_adlib) + return; + + debugC(1, kDebugSound, "Adlib: Unloading data"); + + _adlib->unload(); +} + +void Sound::adlibPlayTrack(const char *trackname) { + if (!_adlib || _adlib->isPlaying()) + return; + + debugC(1, kDebugSound, "Adlib: Playing track \"%s\"", trackname); + + _adlib->unload(); + _adlib->load(trackname); + _adlib->startPlay(); +} + +void Sound::adlibPlayBgMusic() { + if (!_adlib) + return; + + static const char *tracks[] = { +// "musmac1.adl", // TODO: This track isn't played correctly at all yet + "musmac2.adl", + "musmac3.adl", + "musmac4.adl", + "musmac5.adl", + "musmac6.adl" + }; + + int track = _vm->_util->getRandom(ARRAYSIZE(tracks)); + adlibPlayTrack(tracks[track]); +} + +void Sound::adlibPlay() { + if (!_adlib) + return; + + debugC(1, kDebugSound, "Adlib: Starting playback"); + + _adlib->startPlay(); +} + +void Sound::adlibStop() { + if (!_adlib) + return; + + debugC(1, kDebugSound, "Adlib: Stopping playback"); + + _adlib->stopPlay(); +} + +bool Sound::adlibIsPlaying() const { + if (!_adlib) + return false; + + return _adlib->isPlaying(); +} + +int Sound::adlibGetIndex() const { + if (!_adlib) + return -1; + + return _adlib->getIndex(); +} + +bool Sound::adlibGetRepeating() const { + if (!_adlib) + return false; + + return _adlib->getRepeating(); +} + +void Sound::adlibSetRepeating(int32 repCount) { + if (!_adlib) + return; + + _adlib->setRepeating(repCount); +} + +void Sound::blasterPlay(SoundDesc *sndDesc, int16 repCount, + int16 frequency, int16 fadeLength) { + if (!_blaster || !sndDesc) + return; + + debugC(1, kDebugSound, "SoundBlaster: Playing sample (%d, %d, %d)", + repCount, frequency, fadeLength); + + _blaster->playSample(*sndDesc, repCount, frequency, fadeLength); +} + +void Sound::blasterStop(int16 fadeLength, SoundDesc *sndDesc) { + if (!_blaster) + return; + + debugC(1, kDebugSound, "SoundBlaster: Stopping playback"); + + _blaster->stopSound(fadeLength, sndDesc); +} + +void Sound::blasterPlayComposition(int16 *composition, int16 freqVal, + SoundDesc *sndDescs, int8 sndCount) { + if (!_blaster) + return; + + debugC(1, kDebugSound, "SoundBlaster: Playing composition (%d, %d)", + freqVal, sndCount); + + blasterWaitEndPlay(); + _blaster->stopComposition(); + + if (!sndDescs) + sndDescs = _sounds; + + _blaster->playComposition(composition, freqVal, sndDescs, sndCount); +} + +void Sound::blasterStopComposition() { + if (!_blaster) + return; + + debugC(1, kDebugSound, "SoundBlaster: Stopping composition"); + + _blaster->stopComposition(); +} + +char Sound::blasterPlayingSound() const { + if (!_blaster) + return 0; + + return _blaster->getPlayingSound(); +} + +void Sound::blasterSetRepeating(int32 repCount) { + if (!_blaster) + return; + + _blaster->setRepeating(repCount); +} + +void Sound::blasterWaitEndPlay(bool interruptible, bool stopComp) { + if (!_blaster) + return; + + debugC(1, kDebugSound, "SoundBlaster: Waiting for playback to end"); + + if (stopComp) + _blaster->endComposition(); + + while (_blaster->isPlaying() && !_vm->_quitRequested) { + if (interruptible && (_vm->_util->checkKey() == 0x11B)) { + WRITE_VAR(57, (uint32) -1); + return; + } + _vm->_util->longDelay(200); + } + + _blaster->stopSound(0); +} + +void Sound::cdLoadLIC(const char *fname) { + if (!_cdrom) + return; + + debugC(1, kDebugSound, "CDROM: Loading LIC \"%s\"", fname); + + int handle = _vm->_dataIO->openData(fname); + + if (handle == -1) + return; + + _vm->_dataIO->closeData(handle); + + _vm->_dataIO->getUnpackedData(fname); + + handle = _vm->_dataIO->openData(fname); + DataStream *stream = _vm->_dataIO->openAsStream(handle, true); + + _cdrom->readLIC(*stream); + + delete stream; +} + +void Sound::cdUnloadLIC() { + if (!_cdrom) + return; + + debugC(1, kDebugSound, "CDROM: Unloading LIC"); + + _cdrom->freeLICBuffer(); +} + +void Sound::cdPlayBgMusic() { + if (!_cdrom) + return; + + static const char *tracks[][2] = { + {"avt00.tot", "mine"}, + {"avt001.tot", "nuit"}, + {"avt002.tot", "campagne"}, + {"avt003.tot", "extsor1"}, + {"avt004.tot", "interieure"}, + {"avt005.tot", "zombie"}, + {"avt006.tot", "zombie"}, + {"avt007.tot", "campagne"}, + {"avt008.tot", "campagne"}, + {"avt009.tot", "extsor1"}, + {"avt010.tot", "extsor1"}, + {"avt011.tot", "interieure"}, + {"avt012.tot", "zombie"}, + {"avt014.tot", "nuit"}, + {"avt015.tot", "interieure"}, + {"avt016.tot", "statue"}, + {"avt017.tot", "zombie"}, + {"avt018.tot", "statue"}, + {"avt019.tot", "mine"}, + {"avt020.tot", "statue"}, + {"avt021.tot", "mine"}, + {"avt022.tot", "zombie"} + }; + + for (int i = 0; i < ARRAYSIZE(tracks); i++) + if (!scumm_stricmp(_vm->_game->_curTotFile, tracks[i][0])) { + debugC(1, kDebugSound, "CDROM: Playing background music \"%s\" (\"%s\")", + tracks[i][1], _vm->_game->_curTotFile); + + _cdrom->startTrack(tracks[i][1]); + break; + } +} + +void Sound::cdPlayMultMusic() { + if (!_cdrom) + return; + + static const char *tracks[][6] = { + {"avt005.tot", "fra1", "all1", "ang1", "esp1", "ita1"}, + {"avt006.tot", "fra2", "all2", "ang2", "esp2", "ita2"}, + {"avt012.tot", "fra3", "all3", "ang3", "esp3", "ita3"}, + {"avt016.tot", "fra4", "all4", "ang4", "esp4", "ita4"}, + {"avt019.tot", "fra5", "all5", "ang5", "esp5", "ita5"}, + {"avt022.tot", "fra6", "all6", "ang6", "esp6", "ita6"} + }; + + // Default to "ang?" for other languages (including EN_USA) + int language = _vm->_global->_language <= 4 ? _vm->_global->_language : 2; + for (int i = 0; i < ARRAYSIZE(tracks); i++) + if (!scumm_stricmp(_vm->_game->_curTotFile, tracks[i][0])) { + debugC(1, kDebugSound, "CDROM: Playing mult music \"%s\" (\"%s\")", + tracks[i][language + 1], _vm->_game->_curTotFile); + + _cdrom->startTrack(tracks[i][language + 1]); + break; + } +} + +void Sound::cdPlay(const char *trackName) { + if (!_cdrom) + return; + + debugC(1, kDebugSound, "CDROM: Playing track \"%s\"", trackName); + _cdrom->startTrack(trackName); +} + +void Sound::cdStop() { + if (!_cdrom) + return; + + debugC(1, kDebugSound, "CDROM: Stopping playback"); + _cdrom->stopPlaying(); +} + +bool Sound::cdIsPlaying() const { + if (!_cdrom) + return false; + + return _cdrom->isPlaying(); +} + +int32 Sound::cdGetTrackPos(const char *keyTrack) const { + if (!_cdrom) + return -1; + + return _cdrom->getTrackPos(keyTrack); +} + +const char *Sound::cdGetCurrentTrack() const { + if (!_cdrom) + return ""; + + return _cdrom->getCurTrack(); +} + +void Sound::cdTest(int trySubst, const char *label) { + if (!_cdrom) + return; + + _cdrom->testCD(trySubst, label); +} + +void Sound::bgPlay(const char *base, int count) { + if (!_bgatmos) + return; + + debugC(1, kDebugSound, "BackgroundAtmosphere: Playing \"%s\" (%d)", base, count); + + _bgatmos->stop(); + _bgatmos->queueClear(); + + int length = strlen(base) + 7; + char *fileName = new char[length]; + SoundDesc *sndDesc; + + for (int i = 1; i <= count; i++) { + snprintf(fileName, length, "%s%02d.SND", base, i); + + sndDesc = new SoundDesc; + if (sampleLoad(sndDesc, fileName)) + _bgatmos->queueSample(*sndDesc); + } + + _bgatmos->play(); +} + +void Sound::bgStop() { + if (!_bgatmos) + return; + + debugC(1, kDebugSound, "BackgroundAtmosphere: Stopping playback"); + + _bgatmos->stop(); + _bgatmos->queueClear(); +} + +void Sound::bgSetPlayMode(BackgroundAtmosphere::PlayMode mode) { + if (!_bgatmos) + return; + + _bgatmos->setPlayMode(mode); +} + +void Sound::bgShade() { + if (!_bgatmos) + return; + + debugC(1, kDebugSound, "BackgroundAtmosphere: Shading playback"); + + _bgatmos->shade(); +} + +void Sound::bgUnshade() { + if (!_bgatmos) + return; + + debugC(1, kDebugSound, "BackgroundAtmosphere: Unshading playback"); + + _bgatmos->unshade(); +} + +} // End of namespace Gob diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h new file mode 100644 index 0000000000..b59510e4bb --- /dev/null +++ b/engines/gob/sound/sound.h @@ -0,0 +1,147 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_SOUND_H +#define GOB_SOUND_SOUND_H + +#include "gob/sound/sounddesc.h" +#include "gob/sound/pcspeaker.h" +#include "gob/sound/soundblaster.h" +#include "gob/sound/adlib.h" +#include "gob/sound/infogrames.h" +#include "gob/sound/cdrom.h" +#include "gob/sound/bgatmosphere.h" + +namespace Gob { + +class Sound { +public: + static const int kSoundsCount = 60; + + Sound(GobEngine *vm); + ~Sound(); + + static void convToSigned(byte *buffer, int length); + + // Samples + SoundDesc *sampleGetBySlot(int slot); + const SoundDesc *sampleGetBySlot(int slot) const; + int sampleGetNextFreeSlot() const; + + bool sampleLoad(SoundDesc *sndDesc, const char *fileName, bool tryExist = true); + void sampleFree(SoundDesc *sndDesc, bool noteAdlib = false, int index = -1); + + + // SoundBlaster + void blasterPlay(SoundDesc *sndDesc, int16 repCount, + int16 frequency, int16 fadeLength = 0); + void blasterStop(int16 fadeLength, SoundDesc *sndDesc = 0); + + void blasterPlayComposition(int16 *composition, int16 freqVal, + SoundDesc *sndDescs = 0, int8 sndCount = kSoundsCount); + void blasterStopComposition(); + + char blasterPlayingSound() const; + + void blasterSetRepeating(int32 repCount); + void blasterWaitEndPlay(bool interruptible = false, bool stopComp = true); + + + // PCSpeaker + void speakerOn(int16 frequency, int32 length = -1); + void speakerOff(); + void speakerOnUpdate(uint32 millis); + + + // AdLib + bool adlibLoad(const char *fileName); + bool adlibLoad(byte *data, uint32 size, int index = -1); + void adlibUnload(); + + void adlibPlayTrack(const char *trackname); + void adlibPlayBgMusic(); + + void adlibPlay(); + void adlibStop(); + + bool adlibIsPlaying() const; + + int adlibGetIndex() const; + bool adlibGetRepeating() const; + + void adlibSetRepeating(int32 repCount); + + + // Infogrames + bool infogramesLoadInstruments(const char *fileName); + bool infogramesLoadSong(const char *fileName); + + void infogramesPlay(); + void infogramesStop(); + + + // CD-ROM + void cdLoadLIC(const char *fname); + void cdUnloadLIC(); + + void cdPlayBgMusic(); + void cdPlayMultMusic(); + + void cdPlay(const char *trackName); + void cdStop(); + + bool cdIsPlaying() const; + + int32 cdGetTrackPos(const char *keyTrack = 0) const; + const char *cdGetCurrentTrack() const; + + void cdTest(int trySubst, const char *label); + + + // Background Atmosphere + void bgPlay(const char *base, int count); + void bgStop(); + + void bgSetPlayMode(BackgroundAtmosphere::PlayMode mode); + + void bgShade(); + void bgUnshade(); + +private: + GobEngine *_vm; + + SoundDesc _sounds[kSoundsCount]; + + PCSpeaker *_pcspeaker; + SoundBlaster *_blaster; + AdLib *_adlib; + Infogrames *_infogrames; + CDROM *_cdrom; + BackgroundAtmosphere *_bgatmos; +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_H diff --git a/engines/gob/sound/soundblaster.cpp b/engines/gob/sound/soundblaster.cpp new file mode 100644 index 0000000000..eeedfaa3cb --- /dev/null +++ b/engines/gob/sound/soundblaster.cpp @@ -0,0 +1,126 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/sound/soundblaster.h" + +namespace Gob { + +SoundBlaster::SoundBlaster(Audio::Mixer &mixer) : SoundMixer(mixer, Audio::Mixer::kSFXSoundType) { + _curSoundDesc = 0; + + _compositionSamples = 0; + _compositionSampleCount = 0; + _compositionPos = -1; +} + +SoundBlaster::~SoundBlaster() { +} + +void SoundBlaster::playSample(SoundDesc &sndDesc, int16 repCount, + int16 frequency, int16 fadeLength) { + SoundMixer::play(sndDesc, repCount, frequency, fadeLength); +} + +void SoundBlaster::stopSound(int16 fadeLength, SoundDesc *sndDesc) { + Common::StackLock slock(_mutex); + + if (sndDesc && (sndDesc != _curSoundDesc)) + return; + + if (fadeLength <= 0) + _curSoundDesc = 0; + + SoundMixer::stop(fadeLength); +} + +void SoundBlaster::stopComposition() { + if (_compositionPos != -1) { + stopSound(0); + _compositionPos = -1; + } +} + +void SoundBlaster::endComposition() { + _compositionPos = -1; +} + +void SoundBlaster::nextCompositionPos() { + int8 slot; + + while ((++_compositionPos < 50) && + ((slot = _composition[_compositionPos]) != -1)) { + if ((slot >= 0) && (slot < _compositionSampleCount)) { + SoundDesc &sample = _compositionSamples[slot]; + if (!sample.empty() && (sample.getType() == SOUND_SND)) { + setSample(sample, 1, 0, 0); + return; + } + } + if (_compositionPos == 49) + _compositionPos = -1; + } + _compositionPos = -1; +} + +void SoundBlaster::playComposition(int16 *composition, int16 freqVal, + SoundDesc *sndDescs, int8 sndCount) { + + _compositionSamples = sndDescs; + _compositionSampleCount = sndCount; + + int i = -1; + do { + i++; + _composition[i] = composition[i]; + } while ((i < 50) && (composition[i] != -1)); + + _compositionPos = -1; + nextCompositionPos(); +} + +void SoundBlaster::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, + int16 fadeLength) { + + _curSoundDesc = &sndDesc; + SoundMixer::setSample(sndDesc, repCount, frequency, fadeLength); +} + +void SoundBlaster::checkEndSample() { + if (_compositionPos != -1) + nextCompositionPos(); + else + SoundMixer::checkEndSample(); +} + +void SoundBlaster::endFade() { + if (_fadeVolStep > 0) { + _compositionPos = -1; + _curSoundDesc = 0; + } + + SoundMixer::endFade(); +} + +} // End of namespace Gob diff --git a/engines/gob/sound/soundblaster.h b/engines/gob/sound/soundblaster.h new file mode 100644 index 0000000000..c57e4a443e --- /dev/null +++ b/engines/gob/sound/soundblaster.h @@ -0,0 +1,71 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_SOUNDBLASTER_H +#define GOB_SOUND_SOUNDBLASTER_H + +#include "common/mutex.h" +#include "sound/mixer.h" + +#include "gob/sound/sounddesc.h" +#include "gob/sound/soundmixer.h" + +namespace Gob { + +class SoundBlaster : public SoundMixer { +public: + SoundBlaster(Audio::Mixer &mixer); + ~SoundBlaster(); + + void playSample(SoundDesc &sndDesc, int16 repCount, + int16 frequency, int16 fadeLength = 0); + void stopSound(int16 fadeLength, SoundDesc *sndDesc = 0); + + void playComposition(int16 *composition, int16 freqVal, + SoundDesc *sndDescs = 0, int8 sndCount = 60); + void stopComposition(); + void endComposition(); + +protected: + Common::Mutex _mutex; + + SoundDesc *_compositionSamples; + int8 _compositionSampleCount; + int16 _composition[50]; + int8 _compositionPos; + + SoundDesc *_curSoundDesc; + + void setSample(SoundDesc &sndDesc, int16 repCount, + int16 frequency, int16 fadeLength); + void checkEndSample(); + void endFade(); + + void nextCompositionPos(); +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_SOUNDBLASTER_H diff --git a/engines/gob/sound/sounddesc.cpp b/engines/gob/sound/sounddesc.cpp new file mode 100644 index 0000000000..e0885d9faa --- /dev/null +++ b/engines/gob/sound/sounddesc.cpp @@ -0,0 +1,116 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#include "common/util.h" + +#include "gob/sound/sounddesc.h" + +namespace Gob { + +SoundDesc::SoundDesc() { + _data = _dataPtr = 0; + _size = 0; + + _type = SOUND_SND; + _source = SOUND_FILE; + + _repCount = 0; + _frequency = 0; + _flag = 0; + _id = 0; +} + +SoundDesc::~SoundDesc() { + free(); +} + +void SoundDesc::set(SoundType type, SoundSource src, + byte *data, uint32 dSize) { + + free(); + + _type = type; + _source = src; + _data = _dataPtr = data; + _size = dSize; +} + +void SoundDesc::load(SoundType type, SoundSource src, + byte *data, uint32 dSize) { + + free(); + + _source = src; + switch (type) { + case SOUND_ADL: + loadADL(data, dSize); + break; + case SOUND_SND: + loadSND(data, dSize); + break; + } +} + +void SoundDesc::free() { + if (_source != SOUND_TOT) + delete[] _data; + _data = _dataPtr = 0; + _id = 0; +} + +void SoundDesc::convToSigned() { + if ((_type == SOUND_SND) && _data && _dataPtr) + for (uint32 i = 0; i < _size; i++) + _dataPtr[i] ^= 0x80; +} + +int16 SoundDesc::calcFadeOutLength(int16 frequency) { + return (10 * (_size / 2)) / frequency; +} + +uint32 SoundDesc::calcLength(int16 repCount, int16 frequency, bool fade) { + uint32 fadeSize = fade ? _size / 2 : 0; + return ((_size * repCount - fadeSize) * 1000) / frequency; +} + +void SoundDesc::loadSND(byte *data, uint32 dSize) { + assert(dSize > 6); + + _type = SOUND_SND; + _data = data; + _dataPtr = data + 6; + _frequency = MAX((int16) READ_BE_UINT16(data + 4), (int16) 4700); + _flag = data[0] ? (data[0] & 0x7F) : 8; + data[0] = 0; + _size = MIN(READ_BE_UINT32(data), dSize - 6); +} + +void SoundDesc::loadADL(byte *data, uint32 dSize) { + _type = SOUND_ADL; + _data = _dataPtr = data; + _size = dSize; +} + +} // End of namespace Gob diff --git a/engines/gob/sound/sounddesc.h b/engines/gob/sound/sounddesc.h new file mode 100644 index 0000000000..ed4447254c --- /dev/null +++ b/engines/gob/sound/sounddesc.h @@ -0,0 +1,85 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_SOUNDDESC_H +#define GOB_SOUND_SOUNDDESC_H + +#include "common/endian.h" + +namespace Gob { + +enum SoundType { + SOUND_SND, + SOUND_ADL +}; + +enum SoundSource { + SOUND_FILE, + SOUND_TOT, + SOUND_EXT +}; + +class SoundDesc { +public: + int16 _repCount; + int16 _frequency; + int16 _flag; + int16 _id; + + byte *getData() { return _dataPtr; } + + uint32 size() const { return _size; } + bool empty() const { return !_dataPtr; } + SoundType getType() const { return _type; } + + bool isId(int16 id) const { return _dataPtr && (_id == id); } + + void set(SoundType type, SoundSource src, byte *data, uint32 dSize); + void load(SoundType type, SoundSource src, byte *data, uint32 dSize); + void free(); + void convToSigned(); + + // Which fade out length to use when the fade starts half-way through? + int16 calcFadeOutLength(int16 frequency); + uint32 calcLength(int16 repCount, int16 frequency, bool fade); + + SoundDesc(); + ~SoundDesc(); + +private: + byte *_data; + byte *_dataPtr; + uint32 _size; + + SoundType _type; + SoundSource _source; + + void loadSND(byte *data, uint32 dSize); + void loadADL(byte *data, uint32 dSize); +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_SOUNDDESC_H diff --git a/engines/gob/sound/soundmixer.cpp b/engines/gob/sound/soundmixer.cpp new file mode 100644 index 0000000000..1a287d782f --- /dev/null +++ b/engines/gob/sound/soundmixer.cpp @@ -0,0 +1,204 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/sound/soundmixer.h" + +namespace Gob { + +SoundMixer::SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type) : _mixer(&mixer) { + _playingSound = 0; + + _rate = _mixer->getOutputRate(); + _end = true; + _data = 0; + _length = 0; + _freq = 0; + _repCount = 0; + + _offset = 0; + _offsetFrac = 0; + _offsetInc = 0; + + _cur = 0; + _last = 0; + + _fade = false; + _fadeVol = 65536; + _fadeVolStep = 0; + _fadeSamples = 0; + _curFadeSamples = 0; + + _mixer->playInputStream(type, &_handle, this, -1, 255, 0, false, true); +} + +SoundMixer::~SoundMixer() { + _mixer->stopHandle(_handle); +} + +bool SoundMixer::isPlaying() const { + return !_end; +} + +char SoundMixer::getPlayingSound() const { + return _playingSound; +} + +void SoundMixer::stop(int16 fadeLength) { + Common::StackLock slock(_mutex); + + if (fadeLength <= 0) { + _data = 0; + _end = true; + _playingSound = 0; + return; + } + + _fade = true; + _fadeVol = 65536; + _fadeSamples = (int) (fadeLength * (((double) _rate) / 10.0)); + _fadeVolStep = MAX((int32) 1, (int32) (65536 / _fadeSamples)); + _curFadeSamples = 0; +} + +void SoundMixer::setRepeating(int32 repCount) { + Common::StackLock slock(_mutex); + + _repCount = repCount; +} + +void SoundMixer::setSample(SoundDesc &sndDesc, int16 repCount, int16 frequency, + int16 fadeLength) { + + if (frequency <= 0) + frequency = sndDesc._frequency; + + sndDesc._repCount = repCount - 1; + sndDesc._frequency = frequency; + + _data = (int8 *) sndDesc.getData(); + _length = sndDesc.size(); + _freq = frequency; + + _repCount = repCount; + _end = false; + _playingSound = 1; + + _offset = 0; + _offsetFrac = 0; + _offsetInc = (_freq << FRAC_BITS) / _rate; + + _last = _cur; + _cur = _data[0]; + + _curFadeSamples = 0; + if (fadeLength == 0) { + _fade = false; + _fadeVol = 65536; + _fadeSamples = 0; + _fadeVolStep = 0; + } else { + _fade = true; + _fadeVol = 0; + _fadeSamples = (int) (fadeLength * (((double) _rate) / 10.0)); + _fadeVolStep = - MAX((int32) 1, (int32) (65536 / _fadeSamples)); + } +} + +void SoundMixer::play(SoundDesc &sndDesc, int16 repCount, int16 frequency, + int16 fadeLength) { + Common::StackLock slock(_mutex); + + if (!_end) + return; + + setSample(sndDesc, repCount, frequency, fadeLength); +} + +void SoundMixer::checkEndSample() { + if ((_repCount == -1) || (--_repCount > 0)) { + _offset = 0; + _offsetFrac = 0; + _end = false; + _playingSound = 1; + } else { + _end = true; + _playingSound = 0; + } +} + +int SoundMixer::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock slock(_mutex); + + for (int i = 0; i < numSamples; i++) { + if (!_data) + return i; + if (_end || (_offset >= _length)) + checkEndSample(); + if (_end) + return i; + + // Linear interpolation. See sound/rate.cpp + + int16 val = (_last + (((_cur - _last) * _offsetFrac + + FRAC_HALF) >> FRAC_BITS)) << 8; + *buffer++ = (val * _fadeVol) >> 16; + + _offsetFrac += _offsetInc; + + // Was there an integral change? + if (fracToInt(_offsetFrac) > 0) { + _last = _cur; + _cur = _data[_offset]; + _offset += fracToInt(_offsetFrac); + _offsetFrac &= FRAC_LO_MASK; + } + + if (_fade) { + + if (++_curFadeSamples >= _fadeSamples) + endFade(); + else + _fadeVol -= _fadeVolStep; + + if (_fadeVol < 0) + _fadeVol = 0; + + } + } + return numSamples; +} + +void SoundMixer::endFade() { + if (_fadeVolStep > 0) { + _data = 0; + _end = true; + _playingSound = 0; + } else { + _fadeVol = 65536; + _fade = false; + } +} + +} // End of namespace Gob diff --git a/engines/gob/sound/soundmixer.h b/engines/gob/sound/soundmixer.h new file mode 100644 index 0000000000..5789885a99 --- /dev/null +++ b/engines/gob/sound/soundmixer.h @@ -0,0 +1,95 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_SOUND_SOUNDMIXER_H +#define GOB_SOUND_SOUNDMIXER_H + +#include "common/mutex.h" +#include "common/frac.h" +#include "sound/audiostream.h" +#include "sound/mixer.h" + +#include "gob/sound/sounddesc.h" + +namespace Gob { + +class SoundMixer : public Audio::AudioStream { +public: + SoundMixer(Audio::Mixer &mixer, Audio::Mixer::SoundType type = Audio::Mixer::kPlainSoundType); + ~SoundMixer(); + + virtual void play(SoundDesc &sndDesc, int16 repCount, + int16 frequency, int16 fadeLength = 0); + virtual void stop(int16 fadeLength); + + bool isPlaying() const; + char getPlayingSound() const; + + void setRepeating(int32 repCount); + + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return false; } + bool endOfData() const { return _end; } + bool endOfStream() const { return false; } + int getRate() const { return _rate; } + +protected: + Audio::Mixer *_mixer; + + Audio::SoundHandle _handle; + Common::Mutex _mutex; + + bool _end; + int8 *_data; + uint32 _length; + uint32 _rate; + int32 _freq; + int32 _repCount; + + uint32 _offset; + frac_t _offsetFrac; + frac_t _offsetInc; + + int16 _cur; + int16 _last; + + bool _fade; + int32 _fadeVol; + int32 _fadeVolStep; + uint8 _fadeLength; + uint32 _fadeSamples; + uint32 _curFadeSamples; + + char _playingSound; + + virtual void setSample(SoundDesc &sndDesc, int16 repCount, + int16 frequency, int16 fadeLength); + virtual void checkEndSample(); + virtual void endFade(); +}; + +} // End of namespace Gob + +#endif // GOB_SOUND_SOUNDMIXER_H diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 8e573ddb1a..4987426fe0 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -23,7 +23,6 @@ * */ - #include "common/events.h" #include "gob/gob.h" @@ -32,8 +31,8 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/sound.h" #include "gob/video.h" +#include "gob/sound/sound.h" namespace Gob { @@ -60,7 +59,7 @@ void Util::beep(int16 freq) { if (_vm->_global->_soundFlags == 0) return; - _vm->_snd->speakerOn(freq, 50); + _vm->_sound->speakerOn(freq, 50); } void Util::delay(uint16 msecs) { diff --git a/engines/gob/variables.cpp b/engines/gob/variables.cpp new file mode 100644 index 0000000000..0eea2f6547 --- /dev/null +++ b/engines/gob/variables.cpp @@ -0,0 +1,311 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/endian.h" + +#include "gob/gob.h" +#include "gob/variables.h" + +namespace Gob { + +Variables::Variables(uint32 size) { + _size = size; + + _vars = new byte[_size]; + _sizes = new byte[_size]; + + clear(); +} + +Variables::~Variables() { + delete[] _vars; + delete[] _sizes; +} + +void Variables::clear() { + memset(_vars, 0, _size); + + // All variables are 32 bit wide per default + memset(_sizes, 0, _size); + for (uint32 i = 0; i < _size; i += 4) + _sizes[i] = kSize32; +} + +void Variables::clearSize(uint32 offset) { + uint32 inVar = offset % 4; + uint32 varOff = (offset >> 2) << 2; + + // Clearing out the old size + for (uint32 i = 0; i < 4; i++) { + if (_sizes[varOff + i] == kSize32) + _sizes[varOff + i] = kSize8; + else if ((inVar == (i + 1)) && (_sizes[varOff + i] == kSize16)) + _sizes[varOff + i] = kSize8; + } +} + +void Variables::writeSize(uint32 offset, byte n) { + clearSize(offset); + + _sizes[offset] = n; + // Setting following bytes of size to 8 bit, for easy clearing out afterwards + for (; n > 0; n--) + _sizes[offset + n] = kSize8; +} + +void Variables::writeSizeString(uint32 offset, uint32 length) { + clearSize(offset); + + memset(_sizes + offset, kSize8, length); +} + +void Variables::writeVar8(uint32 var, uint8 value) { + writeOff8(var * 4, value); +} + +void Variables::writeVar16(uint32 var, uint16 value) { + writeOff16(var * 4, value); +} + +void Variables::writeVar32(uint32 var, uint32 value) { + writeOff32(var * 4, value); +} + +void Variables::writeVarString(uint32 var, const char *value) { + writeOffString(var * 4, value); +} + +void Variables::writeOff8(uint32 offset, uint8 value) { + write8(_vars + offset, value); + writeSize(offset, kSize8); +} + +void Variables::writeOff16(uint32 offset, uint16 value) { + write16(_vars + offset, value); + writeSize(offset, kSize16); +} + +void Variables::writeOff32(uint32 offset, uint32 value) { + write32(_vars + offset, value); + writeSize(offset, kSize32); +} + +void Variables::writeOffString(uint32 offset, const char *value) { + strcpy((char *) (_vars + offset), value); + writeSizeString(offset, strlen(value)); +} + +uint8 Variables::readVar8(uint32 var) const { + return readOff8(var * 4); +} + +uint16 Variables::readVar16(uint32 var) const { + return readOff16(var * 4); +} + +uint32 Variables::readVar32(uint32 var) const { + return readOff32(var * 4); +} + +void Variables::readVarString(uint32 var, char *value, uint32 length) { + readOffString(var * 4, value, length); +} + +uint8 Variables::readOff8(uint32 offset) const { + return read8(_vars + offset); +} + +uint16 Variables::readOff16(uint32 offset) const { + return read16(_vars + offset); +} + +uint32 Variables::readOff32(uint32 offset) const { + return read32(_vars + offset); +} + +void Variables::readOffString(uint32 offset, char *value, uint32 length) { + strncpy0(value, (const char *) (_vars + offset), length - 1); +} + +const uint8 *Variables::getAddressVar8(uint32 var) const { + return getAddressOff8(var * 4); +} + +uint8 *Variables::getAddressVar8(uint32 var, uint32 n) { + return getAddressOff8(var * 4, n); +} + +const uint16 *Variables::getAddressVar16(uint32 var) const { + return getAddressOff16(var * 4); +} + +uint16 *Variables::getAddressVar16(uint32 var, uint32 n) { + return getAddressOff16(var * 4, n); +} + +const uint32 *Variables::getAddressVar32(uint32 var) const { + return getAddressOff32(var * 4); +} + +uint32 *Variables::getAddressVar32(uint32 var, uint32 n) { + return getAddressOff32(var * 4, n); +} + +const char *Variables::getAddressVarString(uint32 var) const { + return getAddressOffString(var * 4); +} + +char *Variables::getAddressVarString(uint32 var, uint32 n) { + return getAddressOffString(var * 4, n); +} + +const uint8 *Variables::getAddressOff8(uint32 offset) const { + return ((const uint8 *) (_vars + offset)); +} + +uint8 *Variables::getAddressOff8(uint32 offset, uint32 n) { + for (uint32 i = 0; i < n; i++) + writeSize(offset + i, kSize8); + + return ((uint8 *) (_vars + offset)); +} + +const uint16 *Variables::getAddressOff16(uint32 offset) const { + return ((const uint16 *) (_vars + offset)); +} + +uint16 *Variables::getAddressOff16(uint32 offset, uint32 n) { + for (uint32 i = 0; i < n; i++) + writeSize(offset + i * 2, kSize16); + + return ((uint16 *) (_vars + offset)); +} + +const uint32 *Variables::getAddressOff32(uint32 offset) const { + return ((const uint32 *) (_vars + offset)); +} + +uint32 *Variables::getAddressOff32(uint32 offset, uint32 n) { + for (uint32 i = 0; i < n; i++) + writeSize(offset + i * 4, kSize32); + + return ((uint32 *) (_vars + offset)); +} + +const char *Variables::getAddressOffString(uint32 offset) const { + return ((const char *) (_vars + offset)); +} + +char *Variables::getAddressOffString(uint32 offset, uint32 n) { + writeSizeString(offset, (n == 0xFFFFFFFF) ? strlen((char *) (_vars + offset)) : n); + + return ((char *) (_vars + offset)); +} + +bool Variables::copyTo(uint32 offset, byte *variables, byte *sizes, uint32 n) const { + if ((offset + n) > _size) + return false; + + if (variables) + memcpy(variables, _vars + offset, n); + if (sizes) + memcpy(sizes, _sizes + offset, n); + + return true; +} + +bool Variables::copyFrom(uint32 offset, const byte *variables, const byte *sizes, uint32 n) { + if (((offset + n) > _size) || !variables || !sizes) + return false; + + memcpy(_vars + offset, variables, n); + memcpy(_sizes + offset, sizes, n); + + return true; +} + + +VariablesLE::VariablesLE(uint32 size) : Variables(size) { +} + +VariablesLE::~VariablesLE() { +} + +void VariablesLE::write8(byte *buf, uint8 data) const { + *buf = (byte) data; +} + +void VariablesLE::write16(byte *buf, uint16 data) const { + WRITE_LE_UINT16(buf, data); +} + +void VariablesLE::write32(byte *buf, uint32 data) const { + WRITE_LE_UINT32(buf, data); +} + +uint8 VariablesLE::read8(const byte *buf) const { + return (uint8) *buf; +} + +uint16 VariablesLE::read16(const byte *buf) const { + return READ_LE_UINT16(buf); +} + +uint32 VariablesLE::read32(const byte *buf) const { + return READ_LE_UINT32(buf); +} + + +VariablesBE::VariablesBE(uint32 size) : Variables(size) { +} + +VariablesBE::~VariablesBE() { +} + +void VariablesBE::write8(byte *buf, uint8 data) const { + *buf = (byte) data; +} + +void VariablesBE::write16(byte *buf, uint16 data) const { + WRITE_BE_UINT16(buf, data); +} + +void VariablesBE::write32(byte *buf, uint32 data) const { + WRITE_BE_UINT32(buf, data); +} + +uint8 VariablesBE::read8(const byte *buf) const { + return (uint8) *buf; +} + +uint16 VariablesBE::read16(const byte *buf) const { + return READ_BE_UINT16(buf); +} + +uint32 VariablesBE::read32(const byte *buf) const { + return READ_BE_UINT32(buf); +} + +} // End of namespace Gob diff --git a/engines/gob/variables.h b/engines/gob/variables.h new file mode 100644 index 0000000000..5989ed38ee --- /dev/null +++ b/engines/gob/variables.h @@ -0,0 +1,147 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_VARIABLES_H +#define GOB_VARIABLES_H + +namespace Gob { + +class Variables { +public: + Variables(uint32 size); + virtual ~Variables(); + + void writeVar8(uint32 var, uint8 value); + void writeVar16(uint32 var, uint16 value); + void writeVar32(uint32 var, uint32 value); + + void writeVarString(uint32 var, const char *value); + + void writeOff8(uint32 offset, uint8 value); + void writeOff16(uint32 offset, uint16 value); + void writeOff32(uint32 offset, uint32 value); + + void writeOffString(uint32 offset, const char *value); + + uint8 readVar8(uint32 var) const; + uint16 readVar16(uint32 var) const; + uint32 readVar32(uint32 var) const; + + void readVarString(uint32 var, char *value, uint32 length); + + uint8 readOff8(uint32 offset) const; + uint16 readOff16(uint32 offset) const; + uint32 readOff32(uint32 offset) const; + + void readOffString(uint32 offset, char *value, uint32 length); + + + const uint8 *getAddressVar8(uint32 var) const; + uint8 *getAddressVar8(uint32 var, uint32 n = 1); + + const uint16 *getAddressVar16(uint32 var) const; + uint16 *getAddressVar16(uint32 var, uint32 n = 1); + + const uint32 *getAddressVar32(uint32 var) const; + uint32 *getAddressVar32(uint32 var, uint32 n = 1); + + const char *getAddressVarString(uint32 var) const; + char *getAddressVarString(uint32 var, uint32 n = 0xFFFFFFFF); + + const uint8 *getAddressOff8(uint32 offset) const; + uint8 *getAddressOff8(uint32 offset, uint32 n = 1); + + const uint16 *getAddressOff16(uint32 offset) const; + uint16 *getAddressOff16(uint32 offset, uint32 n = 1); + + const uint32 *getAddressOff32(uint32 offset) const; + uint32 *getAddressOff32(uint32 offset, uint32 n = 1); + + const char *getAddressOffString(uint32 offset) const; + char *getAddressOffString(uint32 offset, uint32 n = 0xFFFFFFFF); + + + bool copyTo(uint32 offset, byte *variables, byte *sizes, uint32 n) const; + bool copyFrom(uint32 offset, const byte *variables, const byte *sizes, uint32 n); + +protected: + virtual void write8(byte *buf, uint8 data) const = 0; + virtual void write16(byte *buf, uint16 data) const = 0; + virtual void write32(byte *buf, uint32 data) const = 0; + + virtual uint8 read8(const byte *buf) const = 0; + virtual uint16 read16(const byte *buf) const = 0; + virtual uint32 read32(const byte *buf) const = 0; + +private: + // Basically the number of additional bytes occupied + static const byte kSize8 = 0; + static const byte kSize16 = 1; + static const byte kSize32 = 3; + + uint32 _size; + + byte *_vars; + byte *_sizes; + + void clear(); + void clearSize(uint32 offset); + void writeSize(uint32 offset, byte n); + void writeSizeString(uint32 offset, uint32 length); +}; + +class VariablesLE : public Variables { +public: + VariablesLE(uint32 size); + ~VariablesLE(); + +protected: + void write8(byte *buf, uint8 data) const; + void write16(byte *buf, uint16 data) const; + void write32(byte *buf, uint32 data) const; + + uint8 read8(const byte *buf) const; + uint16 read16(const byte *buf) const; + uint32 read32(const byte *buf) const; +}; + +class VariablesBE : public Variables { +public: + VariablesBE(uint32 size); + ~VariablesBE(); + +protected: + void write8(byte *buf, uint8 data) const; + void write16(byte *buf, uint16 data) const; + void write32(byte *buf, uint32 data) const; + + uint8 read8(const byte *buf) const; + uint16 read16(const byte *buf) const; + uint32 read32(const byte *buf) const; +}; + +} // End of namespace Gob + +#endif // GOB_VARIABLES_H diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp index 9a004318b8..453613d1ae 100644 --- a/engines/gob/video.cpp +++ b/engines/gob/video.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "graphics/cursorman.h" @@ -87,10 +86,14 @@ void SurfaceDesc::swap(SurfaceDesc &surf) { Video::Video(GobEngine *vm) : _vm(vm) { _doRangeClamp = false; _videoDriver = 0; + _surfWidth = 320; _surfHeight = 200; + _scrollOffsetX = 0; _scrollOffsetY = 0; + + _splitSurf = 0; _splitHeight1 = 200; _splitHeight2 = 0; _splitStart = 0; @@ -179,21 +182,34 @@ void Video::retrace(bool mouse) { int screenOffset = _scrollOffsetY * _surfWidth + _scrollOffsetX; int screenX = _screenDeltaX; int screenY = _screenDeltaY; - int screenWidth = _vm->_width; - int screenHeight = _splitHeight1; + int screenWidth = MIN<int>(_surfWidth - _scrollOffsetX, _vm->_width); + int screenHeight = MIN<int>(_surfHeight - _splitHeight2 - _scrollOffsetY, _vm->_height); g_system->copyRectToScreen(_vm->_global->_primarySurfDesc->getVidMem() + screenOffset, _surfWidth, screenX, screenY, screenWidth, screenHeight); - if (_splitHeight2 > 0) { + if (_splitSurf) { + + screenOffset = 0; + screenX = 0; + screenY = _vm->_height - _splitSurf->getHeight(); + screenWidth = MIN<int>(_vm->_width, _splitSurf->getWidth()); + screenHeight = _splitSurf->getHeight(); + + g_system->copyRectToScreen(_splitSurf->getVidMem() + screenOffset, + _splitSurf->getWidth(), screenX, screenY, screenWidth, screenHeight); + + } else if (_splitHeight2 > 0) { + screenOffset = _splitStart * _surfWidth; screenX = 0; screenY = _vm->_height - _splitHeight2; - screenWidth = _vm->_width; + screenWidth = MIN<int>(_surfWidth, _vm->_width); screenHeight = _splitHeight2; g_system->copyRectToScreen(_vm->_global->_primarySurfDesc->getVidMem() + screenOffset, _surfWidth, screenX, screenY, screenWidth, screenHeight); + } g_system->updateScreen(); diff --git a/engines/gob/video.h b/engines/gob/video.h index 4a585d8857..1338885588 100644 --- a/engines/gob/video.h +++ b/engines/gob/video.h @@ -37,10 +37,11 @@ class SurfaceDesc : public ReferenceCounter<SurfaceDesc> { public: int16 _vidMode; - int16 getWidth() { return _width; } - int16 getHeight() { return _height; } + int16 getWidth() const { return _width; } + int16 getHeight() const { return _height; } byte *getVidMem() { return _vidMem; } - bool hasOwnVidMem() { return _ownVidMem; } + const byte *getVidMem() const { return _vidMem; } + bool hasOwnVidMem() const { return _ownVidMem; } void setVidMem(byte *vidMem); void resize(int16 width, int16 height); @@ -97,13 +98,18 @@ public: }; bool _doRangeClamp; + int16 _surfWidth; int16 _surfHeight; + int16 _scrollOffsetX; int16 _scrollOffsetY; + + SurfaceDesc::Ptr _splitSurf; int16 _splitHeight1; int16 _splitHeight2; int16 _splitStart; + int16 _screenDeltaX; int16 _screenDeltaY; diff --git a/engines/gob/video_v1.cpp b/engines/gob/video_v1.cpp index 4ed3b04bad..3c9627c041 100644 --- a/engines/gob/video_v1.cpp +++ b/engines/gob/video_v1.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" diff --git a/engines/gob/video_v2.cpp b/engines/gob/video_v2.cpp index 52b349ca67..ab0c7e52db 100644 --- a/engines/gob/video_v2.cpp +++ b/engines/gob/video_v2.cpp @@ -23,7 +23,6 @@ * */ - #include "common/endian.h" #include "gob/gob.h" diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index e088646498..909d39a63b 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -33,6 +33,7 @@ #include "gob/palanim.h" #include "gob/inter.h" #include "gob/map.h" +#include "gob/sound/sound.h" namespace Gob { @@ -289,6 +290,8 @@ void VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, if (doPlay(startFrame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame)) break; + evalBgShading(video); + if (fade) { _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); fade = false; @@ -299,18 +302,27 @@ void VideoPlayer::primaryPlay(int16 startFrame, int16 lastFrame, int16 breakKey, startFrame++; } + evalBgShading(video); + if (reverseTo >= 0) { int16 toFrame = video.getFramesCount() - reverseTo; for (int i = video.getCurrentFrame(); i >= toFrame; i--) { video.seekFrame(i, SEEK_SET, true); - if (doPlay(i, breakKey, 0, 0, 0, 0, 0)) { + + bool b = doPlay(i, breakKey, 0, 0, 0, 0, 0); + evalBgShading(video); + + if (b) { _vm->_palAnim->fade(0, -2, 0); memset((char *) _vm->_draw->_vgaPalette, 0, 768); } + if (!_noCursorSwitch) video.waitEndFrame(); } } + + evalBgShading(video); } void VideoPlayer::primaryClose() { @@ -334,17 +346,32 @@ int VideoPlayer::slotOpen(const char *videoFile, Type which) { } video->getVideo()->setVideoMemory(); - video->getVideo()->disableSound(); + video->getVideo()->enableSound(*_vm->_mixer); + + int slot = getNextFreeSlot(); - _videoSlots.push_back(video); + _videoSlots[slot] = video; WRITE_VAR(7, video->getVideo()->getFramesCount()); - return _videoSlots.size() - 1; + return slot; +} + +int VideoPlayer::getNextFreeSlot() { + uint slot; + + for (slot = 0; slot < _videoSlots.size(); slot++) + if (!_videoSlots[slot]) + break; + + if (slot == _videoSlots.size()) + _videoSlots.push_back(0); + + return slot; } void VideoPlayer::slotPlay(int slot, int16 frame) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) return; CoktelVideo &video = *(_videoSlots[slot]->getVideo()); @@ -360,21 +387,23 @@ void VideoPlayer::slotPlay(int slot, int16 frame) { _videoSlots[slot]->nextFrame(); WRITE_VAR(11, frame); + + evalBgShading(video); } void VideoPlayer::slotClose(int slot) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) return; delete _videoSlots[slot]; - _videoSlots.remove_at(slot); + _videoSlots[slot] = 0; } void VideoPlayer::slotCopyFrame(int slot, byte *dest, uint16 left, uint16 top, uint16 width, uint16 height, uint16 x, uint16 y, uint16 pitch, int16 transp) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) return; _videoSlots[slot]->getVideo()->copyCurrentFrame(dest, @@ -382,14 +411,24 @@ void VideoPlayer::slotCopyFrame(int slot, byte *dest, } void VideoPlayer::slotCopyPalette(int slot, int16 palStart, int16 palEnd) { - if ((slot < 0) || (((uint) slot) >= _videoSlots.size())) + if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) return; copyPalette(*(_videoSlots[slot]->getVideo()), palStart, palEnd); } +void VideoPlayer::slotWaitEndFrame(int slot, bool onlySound) { + if ((slot < 0) || (((uint) slot) >= _videoSlots.size()) || !_videoSlots[slot]) + return; + + CoktelVideo &video = *(_videoSlots[slot]->getVideo()); + + if (!onlySound || (video.getFeatures() & CoktelVideo::kFeaturesSound)) + video.waitEndFrame(); +} + bool VideoPlayer::slotIsOpen(int slot) const { - if ((slot >= 0) && (((uint) slot) < _videoSlots.size())) + if ((slot >= 0) && (((uint) slot) < _videoSlots.size()) && _videoSlots[slot]) return true; return false; @@ -399,7 +438,7 @@ const VideoPlayer::Video *VideoPlayer::getVideoBySlot(int slot) const { if (slot < 0) { if (_primaryVideo->isOpen()) return _primaryVideo; - } else if (((uint) slot) < _videoSlots.size()) + } else if (((uint) slot) < _videoSlots.size() && _videoSlots[slot]) return _videoSlots[slot]; return 0; @@ -503,7 +542,7 @@ bool VideoPlayer::doPlay(int16 frame, int16 breakKey, _vm->_draw->_noInvalidated = true; } - if (state.flags & CoktelVideo::kStatePalette) { + if ((state.flags & CoktelVideo::kStatePalette) && (palCmd > 1)) { copyPalette(*(_primaryVideo->getVideo()), palStart, palEnd); if (!_backSurf) @@ -563,14 +602,13 @@ void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, if (primaryOpen(videoFile)) { int16 x, y, width, height; - if ((VAR_OFFSET(varX) != 0xFFFFFFFF) || - !_primaryVideo->getVideo()->getAnchor(1, 2, x, y, width, height)) { + x = _primaryVideo->getVideo()->getX(); + y = _primaryVideo->getVideo()->getY(); + width = _primaryVideo->getVideo()->getWidth(); + height = _primaryVideo->getVideo()->getHeight(); - x = _primaryVideo->getVideo()->getX(); - y = _primaryVideo->getVideo()->getY(); - width = _primaryVideo->getVideo()->getWidth(); - height = _primaryVideo->getVideo()->getHeight(); - } + if (VAR_OFFSET(varX) == 0xFFFFFFFF) + _primaryVideo->getVideo()->getAnchor(1, 2, x, y, width, height); WRITE_VAR_OFFSET(varX, x); WRITE_VAR_OFFSET(varY, y); @@ -580,12 +618,28 @@ void VideoPlayer::writeVideoInfo(const char *videoFile, int16 varX, int16 varY, primaryClose(); } else { - WRITE_VAR_OFFSET(varX, -1); - WRITE_VAR_OFFSET(varY, -1); - WRITE_VAR_OFFSET(varFrames, -1); - WRITE_VAR_OFFSET(varWidth, -1); - WRITE_VAR_OFFSET(varHeight, -1); + WRITE_VAR_OFFSET(varX, (uint32) -1); + WRITE_VAR_OFFSET(varY, (uint32) -1); + WRITE_VAR_OFFSET(varFrames, (uint32) -1); + WRITE_VAR_OFFSET(varWidth, (uint32) -1); + WRITE_VAR_OFFSET(varHeight, (uint32) -1); } } +void VideoPlayer::evalBgShading(CoktelVideo &video) { + if (video.isSoundPlaying()) + _vm->_sound->bgShade(); + else + _vm->_sound->bgUnshade(); +} + +void VideoPlayer::notifyPaused(uint32 duration) { + if (_primaryVideo->isOpen()) + _primaryVideo->getVideo()->notifyPaused(duration); + + for (uint i = 0; i < _videoSlots.size(); i++) + if (_videoSlots[i] && _videoSlots[i]->isOpen()) + _videoSlots[i]->getVideo()->notifyPaused(duration); +} + } // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index fd3c68aa1a..b7aa7313b0 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -68,6 +68,7 @@ public: uint16 left, uint16 top, uint16 width, uint16 height, uint16 x, uint16 y, uint16 pitch, int16 transp = -1); void slotCopyPalette(int slot, int16 palStart = -1, int16 palEnd = -1); + void slotWaitEndFrame(int slot, bool onlySound = false); bool slotIsOpen(int slot) const; @@ -82,6 +83,8 @@ public: void writeVideoInfo(const char *videoFile, int16 varX, int16 varY, int16 varFrames, int16 varWidth, int16 varHeight); + void notifyPaused(uint32 duration); + private: class Video { public: @@ -127,10 +130,13 @@ private: const Video *getVideoBySlot(int slot = -1) const; + int getNextFreeSlot(); + void copyPalette(CoktelVideo &video, int16 palStart = -1, int16 palEnd = -1); bool doPlay(int16 frame, int16 breakKey, uint16 palCmd, int16 palStart, int16 palEnd, int16 palFrame, int16 endFrame); + void evalBgShading(CoktelVideo &video); }; } // End of namespace Gob |