diff options
Diffstat (limited to 'engines/gob')
43 files changed, 4464 insertions, 1889 deletions
diff --git a/engines/gob/cdrom.cpp b/engines/gob/cdrom.cpp index 6b32720cff..2ee8595ad3 100644 --- a/engines/gob/cdrom.cpp +++ b/engines/gob/cdrom.cpp @@ -68,29 +68,30 @@ void CDROM::readLIC(const char *fname) { _vm->_dataIO->getUnpackedData(tmp); handle = _vm->_dataIO->openData(tmp); + DataStream *stream = _vm->_dataIO->openAsStream(handle, true); - version = _vm->_dataIO->readUint16(handle); - startChunk = _vm->_dataIO->readUint16(handle); - _numTracks = _vm->_dataIO->readUint16(handle); + version = stream->readUint16LE(); + startChunk = stream->readUint16LE(); + _numTracks = stream->readUint16LE(); if (version != 3) error("%s: Unknown version %d", fname, version); - _vm->_dataIO->seekData(handle, 50, SEEK_SET); + stream->seek(50); for (int i = 0; i < startChunk; i++) { - pos = _vm->_dataIO->readUint16(handle); + pos = stream->readUint16LE(); if (!pos) break; - _vm->_dataIO->seekData(handle, pos, SEEK_CUR); + stream->skip(pos); } _LICbuffer = new byte[_numTracks * 22]; - _vm->_dataIO->readData(handle, _LICbuffer, _numTracks * 22); + stream->read(_LICbuffer, _numTracks * 22); - _vm->_dataIO->closeData(handle); + delete stream; } void CDROM::freeLICbuffer() { diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp new file mode 100644 index 0000000000..16df54d85f --- /dev/null +++ b/engines/gob/coktelvideo.cpp @@ -0,0 +1,1289 @@ +/* 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/stdafx.h" +#include "common/endian.h" +#include "common/system.h" + +#include "gob/coktelvideo.h" + +namespace Gob { + +Imd::Imd() { + clear(false); +} + +Imd::~Imd() { + clear(); +} + +bool Imd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + // Version + uint16 handle = _stream->readUint16LE(); + _version = _stream->readByte(); + + // Version checking + if ((handle != 0) || (_version < 2)) { + warning("IMD Version incorrect (%d,%X)", handle, _version); + unload(); + return false; + } + + // Rest header + _features = _stream->readByte(); + _framesCount = _stream->readUint16LE(); + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); + _flags = _stream->readUint16LE(); + _firstFramePos = _stream->readUint16LE(); + + // IMDs always have video + _features |= kFeaturesVideo; + + // Palette + _stream->read((byte *) _palette, 768); + + // Standard coordinates + if (_version >= 3) { + _stdX = _stream->readUint16LE(); + if (_stdX > 1) { + warning("IMD: More than one standard coordinate quad found (%d)", _stdX); + unload(); + return false; + } + if (_stdX != 0) { + _stdX = _stream->readSint16LE(); + _stdY = _stream->readSint16LE(); + _stdWidth = _stream->readSint16LE(); + _stdHeight = _stream->readSint16LE(); + _features |= kFeaturesStdCoords; + } else + _stdX = -1; + } else + _stdX = -1; + + // Offset to frame positions table + uint32 framesPosPos = 0; + if (_version >= 4) { + framesPosPos = _stream->readUint32LE(); + if (framesPosPos != 0) { + _framesPos = new uint32[_framesCount]; + assert(_framesPos); + _features |= kFeaturesFramesPos; + } + } + + // Offset to frame coordinates + uint32 framesCoordsPos = 0; + if (_features & kFeaturesFrameCoords) + framesCoordsPos = _stream->readUint32LE(); + + // Sound + if (_features & kFeaturesSound) { + _soundFreq = _stream->readSint16LE(); + _soundSliceSize = _stream->readSint16LE(); + _soundSlicesCount = _stream->readSint16LE(); + + if (_soundFreq < 0) + _soundFreq = -_soundFreq; + + if (_soundSlicesCount < 0) + _soundSlicesCount = -_soundSlicesCount - 1; + + if (_soundSlicesCount > 40) { + warning("IMD: More than 40 sound slices found (%d)", _soundSlicesCount); + unload(); + return false; + } + + _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); + _frameLength = _soundSliceLength; + + _soundStage = 1; + _hasSound = true; + + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); + } else + _frameLength = 1000 / 12; // 12 FPS for a video without sound + + // Sizes of the frame data and extra video buffer + if (_features & kFeaturesDataSize) { + _frameDataSize = _stream->readUint16LE(); + if (_frameDataSize == 0) { + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + } else + _vidBufferSize = _stream->readUint16LE(); + } else { + _frameDataSize = _width * _height + 500; + if (!(_flags & 0x100) || (_flags & 0x1000)) + _vidBufferSize = _frameDataSize; + } + + // Frame positions table + if (_framesPos) { + _stream->seek(framesPosPos, SEEK_SET); + for (int i = 0; i < _framesCount; i++) + _framesPos[i] = _stream->readUint32LE(); + } + + // Frame coordinates table + if (_features & kFeaturesFrameCoords) { + _stream->seek(framesCoordsPos, SEEK_SET); + _frameCoords = new Coord[_framesCount]; + assert(_frameCoords); + for (int i = 0; i < _framesCount; i++) { + _frameCoords[i].left = _stream->readSint16LE(); + _frameCoords[i].top = _stream->readSint16LE(); + _frameCoords[i].right = _stream->readSint16LE(); + _frameCoords[i].bottom = _stream->readSint16LE(); + } + } + + // Seek to the first frame + _stream->seek(_firstFramePos, SEEK_SET); + + // Allocating working memory + _frameData = new byte[_frameDataSize + 500]; + assert(_frameData); + memset(_frameData, 0, _frameDataSize + 500); + _vidBuffer = new byte[_vidBufferSize + 500]; + assert(_vidBuffer); + memset(_vidBuffer, 0, _vidBufferSize + 500); + + return true; +} + +void Imd::unload() { + clear(); +} + +void Imd::setXY(int16 x, int16 y) { + // Adjusting the standard coordinates + if (_stdX != -1) { + if (x >= 0) + _stdX = _stdX - _x + x; + if (y >= 0) + _stdY = _stdY - _y + y; + } + + // Going through the coordinate table as well + if (_frameCoords) { + for (int i = 0; i < _framesCount; i++) { + if (_frameCoords[i].left != -1) { + if (x >= 0) { + _frameCoords[i].left = _frameCoords[i].left - _x + x; + _frameCoords[i].right = _frameCoords[i].right - _x + x; + } + if (y >= 0) { + _frameCoords[i].top = _frameCoords[i].top - _y + y; + _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y; + } + } + } + } + + if (x >= 0) + _x = x; + if (y >= 0) + _y = y; +} + +void Imd::setVideoMemory(byte *vidMem, uint16 width, uint16 height) { + deleteVidMem(); + + _hasOwnVidMem = false; + _vidMem = vidMem; + _vidMemWidth = width; + _vidMemHeight = height; +} + +void Imd::setVideoMemory() { + deleteVidMem(); + + if ((_width > 0) && (_height > 0)) { + setXY(0, 0); + _hasOwnVidMem = true; + _vidMem = new byte[_width * _height]; + _vidMemWidth = _width; + _vidMemHeight = _height; + } +} + +void Imd::enableSound(Audio::Mixer &mixer) { + // Only possible on the first frame + if (_curFrame > 0) + return; + + _mixer = &mixer; + _soundEnabled = true; +} + +void Imd::disableSound() { + if (_audioStream) { + + if (_soundStage == 2) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + } else + delete _audioStream; + + _audioStream = 0; + _soundStage = 0; + } + _soundEnabled = false; + _mixer = 0; +} + +void Imd::seekFrame(int32 frame, int16 whence, bool restart) { + if (!_stream) + // Nothing to do + return; + + // Find the frame to which to seek + if (whence == SEEK_CUR) + frame += _curFrame; + else if (whence == SEEK_END) + frame = _framesCount - frame - 1; + else if (whence != SEEK_SET) + return; + + if ((frame < 0) || (frame >= _framesCount) || (frame == _curFrame)) + // Nothing to do + return; + + // Try every possible way to find a file offset to that frame + uint32 framePos = 0; + if (frame == 0) { + framePos = _firstFramePos; + } else if (frame == 1) { + framePos = _firstFramePos; + _stream->seek(framePos, SEEK_SET); + framePos += _stream->readUint16LE() + 4; + } else if (_framesPos) { + framePos = _framesPos[frame]; + } else if (restart && (_soundStage == 0)) { + for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++) + processFrame(i); + } else + error("Frame %d is not directly accessible", frame); + + // Seek + _stream->seek(framePos); + _curFrame = frame; +} + +CoktelVideo::State Imd::nextFrame() { + return processFrame(_curFrame); +} + +void Imd::waitEndFrame() { + if (_soundEnabled && _hasSound) { + if (_soundStage != 2) + return; + + if (_skipFrames == 0) { + int32 waitTime = (_curFrame * _soundSliceLength) - + (g_system->getMillis() - _soundStartTime); + + if (waitTime < 0) { + _skipFrames = -waitTime / _soundSliceLength; + warning("Video A/V sync broken, skipping %d frame(s)", _skipFrames + 1); + } else if (waitTime > 0) + g_system->delayMillis(waitTime); + + } else + _skipFrames--; + } else + g_system->delayMillis(_frameLength); +} + +void Imd::copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp) { + if (!_vidMem) + return; + + dest += width * y; + + uint16 copyWidth = MIN<int16>(width - x, _width); + uint16 destPitch = width - x; + byte *vidMem = _vidMem; + + if (transp < 0) { + // No transparency + if ((x > 0) || (_width != width)) { + // Copy row-by-row + for (int i = 0; i < _height; i++) { + dest += x; + memcpy(dest, vidMem, copyWidth); + dest += destPitch; + vidMem += _width; + } + + } else + // Dimensions fit, copy everything at once + memcpy(dest, _vidMem, _width * _height); + + return; + } + + // Transparency, copy per pixel + for (int i = 0; i < _height; i++) { + byte *s = vidMem; + byte *d = dest; + + d += x; + for (int j = 0; j < _width; j++) { + if (*s != transp) + *d = *s; + + s++; + d++; + } + + dest += width;; + vidMem += _width; + } +} + +void Imd::deleteVidMem(bool del) { + if (del) { + if (_hasOwnVidMem) + delete[] _vidMem; + } + + _hasOwnVidMem = false; + _vidMem = 0; + _vidMemWidth = _vidMemHeight = 0; +} + +void Imd::clear(bool del) { + if (del) { + delete[] _framesPos; + delete[] _frameCoords; + delete[] _frameData; + delete[] _vidBuffer; + + disableSound(); + } + + _stream = 0; + + _version = 0; + _features = 0; + _flags = 0; + _x = _y = _width = _height = 0; + _stdX = _stdY = _stdWidth = _stdHeight = 0; + _framesCount = _curFrame = 0; + _framesPos = 0; + _firstFramePos = 0; + _frameCoords = 0; + + _frameDataSize = _vidBufferSize = 0; + _frameData = _vidBuffer = 0; + + memset(_palette, 0, 768); + + deleteVidMem(del); + + _hasSound = false; + _soundEnabled = false; + _soundStage = 0; + _soundStartTime = 0; + _skipFrames = 0; + + _soundFlags = 0; + _soundFreq = 0; + _soundSliceSize = 0; + _soundSlicesCount = 0; + _soundSliceLength = 0; + + _audioStream = 0; + + _frameLength = 0; + _lastFrameTime = 0; +} + +CoktelVideo::State Imd::processFrame(uint16 frame) { + State state; + uint32 cmd = 0; + bool hasNextCmd = false; + bool startSound = false; + + if (!_stream || (frame >= _framesCount)) { + state.flags = kStateBreak; + return state; + } + + if (frame != _curFrame) { + state.flags |= kStateSeeked; + seekFrame(frame); + } + + if (!_vidMem) + setVideoMemory(); + + state.left = _x; + state.top = _y; + state.right = _width + state.left - 1; + state.bottom = _height + state.top - 1; + + do { + if (frame != 0) { + if (_stdX != -1) { + state.left = _stdX; + state.top = _stdY; + state.right = _stdWidth + state.left - 1; + state.bottom = _stdHeight + state.top - 1; + state.flags |= kStateStdCoords; + } + if (_frameCoords && + (_frameCoords[frame].left != -1)) { + state.left = _frameCoords[frame].left; + state.top = _frameCoords[frame].top; + state.right = _frameCoords[frame].right; + state.bottom = _frameCoords[frame].bottom; + state.flags |= kStateFrameCoords; + } + } + + cmd = _stream->readUint16LE(); + + if ((cmd & 0xFFF8) == 0xFFF0) { + if (cmd == 0xFFF0) { + _stream->seek(2, SEEK_CUR); + cmd = _stream->readUint16LE(); + } + + if (cmd == 0xFFF1) { + state.flags = kStateBreak; + continue; + } else if (cmd == 0xFFF2) { // Skip (16 bit) + cmd = _stream->readUint16LE(); + _stream->seek(cmd, SEEK_CUR); + state.flags = kStateBreak; + continue; + } else if (cmd == 0xFFF3) { // Skip (32 bit) + cmd = _stream->readUint32LE(); + _stream->seek(cmd, SEEK_CUR); + state.flags = kStateBreak; + continue; + } + } + + if (_soundStage != 0) { + byte *soundBuf; + + // Next sound slice data + if (cmd == 0xFF00) { + + if (!hasNextCmd && _soundEnabled) { + soundBuf = new byte[_soundSliceSize]; + assert(soundBuf); + + _stream->read(soundBuf, _soundSliceSize); + unsignedToSigned(soundBuf, _soundSliceSize); + _audioStream->queueBuffer(soundBuf, _soundSliceSize); + } else + _stream->seek(_soundSliceSize, SEEK_CUR); + + cmd = _stream->readUint16LE(); + + // Initial sound data (all slices) + } else if (cmd == 0xFF01) { + int dataLength = _soundSliceSize * _soundSlicesCount; + + if (!hasNextCmd && _soundEnabled) { + soundBuf = new byte[dataLength]; + assert(soundBuf); + + _stream->read(soundBuf, dataLength); + unsignedToSigned(soundBuf, dataLength); + + if (_soundStage == 1) + startSound = true; + + _audioStream->queueBuffer(soundBuf, dataLength); + } else + _stream->seek(dataLength, SEEK_CUR); + + cmd = _stream->readUint16LE(); + + // Empty sound slice + } else if (!hasNextCmd && (_soundEnabled)) { + soundBuf = new byte[_soundSliceSize]; + assert(soundBuf); + + memset(soundBuf, 0, _soundSliceSize); + + _audioStream->queueBuffer(soundBuf, _soundSliceSize); + } + } + + // Set palette + if (cmd == 0xFFF4) { + _stream->seek(2, SEEK_CUR); + state.flags |= kStatePalette; + _stream->read(_palette, 768); + cmd = _stream->readUint16LE(); + } + + hasNextCmd = false; + + // Jump to frame + if (cmd == 0xFFFD) { + + frame = _stream->readSint16LE(); + if (_framesPos) { + _curFrame = frame; + _stream->seek(_framesPos[frame], SEEK_SET); + + hasNextCmd = true; + state.flags |= kStateJump; + } + + } else if (cmd == 0xFFFC) { + + state.flags |= 1; + cmd = _stream->readUint32LE(); + _stream->read(_frameData, cmd + 2); + + if (_vidMemWidth <= state.right) { + state.left = 0; + state.right -= state.left; + } + if (_vidMemWidth <= state.right) + state.right = _vidMemWidth - 1; + if (_vidMemHeight <= state.bottom) { + state.top = 0; + state.bottom -= state.top; + } + if (_vidMemHeight <= state.bottom) + state.bottom = _vidMemHeight -1; + + state.flags |= renderFrame(state.left, state.top, state.right, state.bottom); + state.flags |= _frameData[0]; + + // Frame video data + } else if (cmd != 0) { + + _stream->read(_frameData, cmd + 2); + + state.flags |= renderFrame(state.left, state.top, state.right, state.bottom); + state.flags |= _frameData[0]; + + } else + state.flags |= kStateNoVideoData; + + } while (hasNextCmd); + + if (startSound && _soundEnabled) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); + _soundStartTime = g_system->getMillis(); + _skipFrames = 0; + _soundStage = 2; + } + + _curFrame++; + if ((_curFrame == _framesCount) && (_soundStage == 2)) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + _audioStream = 0; + _soundStage = 0; + } + + _lastFrameTime = g_system->getMillis(); + return state; +} + +uint32 Imd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) { + if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0)) + return 0; + + uint32 retVal = 0; + int16 width = right - left + 1; + int16 height = bottom - top + 1; + int16 sW = _vidMemWidth; + byte *dataPtr = _frameData; + byte *imdVidMem = _vidMem + sW * top + left; + byte *srcPtr; + uint8 type = *dataPtr++; + + if (type & 0x10) { // Palette data + // One byte index + int index = *dataPtr++; + // 16 entries with each 3 bytes (RGB) + memcpy(_palette + index * 3, dataPtr, MIN((255 - index) * 3, 48)); + + retVal = kStatePalette; + dataPtr += 48; + type ^= 0x10; + } + + srcPtr = dataPtr; + + if (type & 0x80) { // Frame data is compressed + srcPtr = _vidBuffer; + type &= 0x7F; + if ((type == 2) && (width == sW)) { + deLZ77(imdVidMem, dataPtr); + return retVal; + } else + deLZ77(srcPtr, dataPtr); + } + + uint16 pixCount, pixWritten; + byte *imdVidMemBak; + + if (type == 2) { // Whole block + for (int i = 0; i < height; i++) { + memcpy(imdVidMem, srcPtr, width); + srcPtr += width; + imdVidMem += sW; + } + } else if (type == 1) { // Sparse block + imdVidMemBak = imdVidMem; + for (int i = 0; i < height; i++) { + pixWritten = 0; + while (pixWritten < width) { + pixCount = *srcPtr++; + if (pixCount & 0x80) { // data + pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); + memcpy(imdVidMem, srcPtr, pixCount); + + pixWritten += pixCount; + imdVidMem += pixCount; + srcPtr += pixCount; + } else { // "hole" + pixCount = (pixCount + 1) % 256; + pixWritten += pixCount; + imdVidMem += pixCount; + } + } + imdVidMemBak += sW; + imdVidMem = imdVidMemBak; + } + } else if (type == 0x42) { // Whole quarter-wide block + for (int i = 0; i < height; i++) { + imdVidMemBak = imdVidMem; + + for (int j = 0; j < width; j += 4, imdVidMem += 4, srcPtr++) + memset(imdVidMem, *srcPtr, 4); + + imdVidMemBak += sW; + imdVidMem = imdVidMemBak; + } + } else if ((type & 0xF) == 2) { // Whole half-high block + for (; height > 1; height -= 2, imdVidMem += sW + sW, srcPtr += width) { + memcpy(imdVidMem, srcPtr, width); + memcpy(imdVidMem + sW, srcPtr, width); + } + if (height == -1) + memcpy(imdVidMem, srcPtr, width); + } else { // Sparse half-high block + imdVidMemBak = imdVidMem; + for (int i = 0; i < height; i += 2) { + pixWritten = 0; + while (pixWritten < width) { + pixCount = *srcPtr++; + if (pixCount & 0x80) { // data + pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); + memcpy(imdVidMem, srcPtr, pixCount); + memcpy(imdVidMem + sW, srcPtr, pixCount); + + pixWritten += pixCount; + imdVidMem += pixCount; + srcPtr += pixCount; + } else { // "hole" + pixCount = (pixCount + 1) % 256; + pixWritten += pixCount; + imdVidMem += pixCount; + } + } + imdVidMemBak += sW + sW; + imdVidMem = imdVidMemBak; + } + } + + return retVal; +} + +void Imd::deLZ77(byte *dest, byte *src) { + int i; + byte buf[4370]; + uint16 chunkLength; + uint16 frameLength; + uint16 bufPos1; + uint16 bufPos2; + uint16 tmp; + uint8 chunkBitField; + uint8 chunkCount; + bool mode; + + frameLength = READ_LE_UINT32(src); + src += 4; + + if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { + src += 4; + bufPos1 = 273; + mode = 1; // 123Ch (cmp al, 12h) + } else { + bufPos1 = 4078; + mode = 0; // 275h (jnz +2) + } + + memset(buf, 32, bufPos1); + chunkCount = 1; + chunkBitField = 0; + + while (frameLength > 0) { + chunkCount--; + if (chunkCount == 0) { + tmp = *src++; + chunkCount = 8; + chunkBitField = tmp; + } + if (chunkBitField % 2) { + chunkBitField >>= 1; + buf[bufPos1] = *src; + *dest++ = *src++; + bufPos1 = (bufPos1 + 1) % 4096; + frameLength--; + continue; + } + chunkBitField >>= 1; + + tmp = READ_LE_UINT16(src); + src += 2; + chunkLength = ((tmp & 0xF00) >> 8) + 3; + + if ((mode && ((chunkLength & 0xFF) == 0x12)) || + (!mode && (chunkLength == 0))) + chunkLength = *src++ + 0x12; + + bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00); + if (((tmp + chunkLength) >= 4096) || + ((chunkLength + bufPos1) >= 4096)) { + + for (i = 0; i < chunkLength; i++, dest++) { + *dest = buf[bufPos2]; + buf[bufPos1] = buf[bufPos2]; + bufPos1 = (bufPos1 + 1) % 4096; + bufPos2 = (bufPos2 + 1) % 4096; + } + + } else if (((tmp + chunkLength) < bufPos1) || + ((chunkLength + bufPos1) < bufPos2)) { + + memcpy(dest, buf + bufPos2, chunkLength); + memmove(buf + bufPos1, buf + bufPos2, chunkLength); + + dest += chunkLength; + bufPos1 += chunkLength; + bufPos2 += chunkLength; + + } else { + + for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) { + *dest = buf[bufPos2]; + buf[bufPos1] = buf[bufPos2]; + } + + } + frameLength -= chunkLength; + + } +} + +const uint16 Vmd::_tableDPCM[128] = { + 0x0000, 0x0008, 0x0010, 0x0020, 0x0030, 0x0040, 0x0050, 0x0060, 0x0070, 0x0080, + 0x0090, 0x00A0, 0x00B0, 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0100, 0x0110, 0x0120, + 0x0130, 0x0140, 0x0150, 0x0160, 0x0170, 0x0180, 0x0190, 0x01A0, 0x01B0, 0x01C0, + 0x01D0, 0x01E0, 0x01F0, 0x0200, 0x0208, 0x0210, 0x0218, 0x0220, 0x0228, 0x0230, + 0x0238, 0x0240, 0x0248, 0x0250, 0x0258, 0x0260, 0x0268, 0x0270, 0x0278, 0x0280, + 0x0288, 0x0290, 0x0298, 0x02A0, 0x02A8, 0x02B0, 0x02B8, 0x02C0, 0x02C8, 0x02D0, + 0x02D8, 0x02E0, 0x02E8, 0x02F0, 0x02F8, 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, + 0x0328, 0x0330, 0x0338, 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, + 0x0378, 0x0380, 0x0388, 0x0390, 0x0398, 0x03A0, 0x03A8, 0x03B0, 0x03B8, 0x03C0, + 0x03C8, 0x03D0, 0x03D8, 0x03E0, 0x03E8, 0x03F0, 0x03F8, 0x0400, 0x0440, 0x0480, + 0x04C0, 0x0500, 0x0540, 0x0580, 0x05C0, 0x0600, 0x0640, 0x0680, 0x06C0, 0x0700, + 0x0740, 0x0780, 0x07C0, 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, + 0x0F00, 0x1000, 0x1400, 0x1800, 0x1C00, 0x2000, 0x3000, 0x4000 +}; + +Vmd::Vmd() { + clear(false); +} + +Vmd::~Vmd() { + clear(); +} + +bool Vmd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + uint16 headerLength = _stream->readUint16LE(); + uint16 handle = _stream->readUint16LE(); + _version = _stream->readUint16LE(); + + // Version checking + if ((headerLength != 814) || (handle != 0) || (_version != 1)) { + warning("VMD Version incorrect (%d, %d, %d)", headerLength, handle, _version); + unload(); + return false; + } + + _framesCount = _stream->readUint16LE(); + + _x = _stream->readSint16LE(); + _y = _stream->readSint16LE(); + _width = _stream->readSint16LE(); + _height = _stream->readSint16LE(); + if ((_width != 0) && (_height != 0)) { + _hasVideo = true; + _features |= kFeaturesVideo; + } else + _hasVideo = false; + + _flags = _stream->readUint16LE(); + _partsPerFrame = _stream->readUint16LE(); + _firstFramePos = _stream->readUint32LE(); + _stream->skip(4); // Unknown + + _stream->read((byte *) _palette, 768); + + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + + if (_hasVideo) { + if (_frameDataSize == 0) + _frameDataSize = _width * _height + 500; + if (_vidBufferSize == 0) + _vidBufferSize = _frameDataSize; + + _frameData = new byte[_frameDataSize]; + assert(_frameData); + memset(_frameData, 0, _frameDataSize); + _vidBuffer = new byte[_vidBufferSize]; + assert(_vidBuffer); + memset(_vidBuffer, 0, _vidBufferSize); + } + + _soundFreq = _stream->readSint16LE(); + _soundSliceSize = _stream->readSint16LE(); + _soundSlicesCount = _stream->readSint16LE(); + _soundFlags = _stream->readUint16LE(); + _hasSound = (_soundFreq != 0); + + if (_hasSound) { + _features |= kFeaturesSound; + + _soundStereo = (_soundFlags & 0x8000) ? 1 : ((_soundFlags & 0x200) ? 2 : 0); + if (_soundStereo > 0) { + warning("TODO: VMD stereo"); + unload(); + return false; + } + + if (_soundSliceSize < 0) { + _soundBytesPerSample = 2; + _soundSliceSize = -_soundSliceSize; + } + + _soundSliceLength = (uint16) (1000.0 / + ((double) _soundFreq / (double) _soundSliceSize)); + + _frameLength = _soundSliceLength; + + _soundStage = 1; + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, + (_soundBytesPerSample == 2) ? Audio::Mixer::FLAG_16BITS : 0); + } else + _frameLength = 1000 / 12; // 12 FPS for a video without sound + + uint32 frameInfoOffset = _stream->readUint32LE(); + + _stream->seek(frameInfoOffset); + _frames = new Frame[_framesCount]; + for (uint16 i = 0; i < _framesCount; i++) { + _frames[i].parts = new Part[_partsPerFrame]; + _stream->skip(2); // Unknown + _frames[i].offset = _stream->readUint32LE(); + } + for (uint16 i = 0; i < _framesCount; i++) { + for (uint16 j = 0; j < _partsPerFrame; j++) { + + _frames[i].parts[j].type = (PartType) _stream->readByte(); + _stream->skip(1); // Unknown + _frames[i].parts[j].size = _stream->readUint32LE(); + + if (_frames[i].parts[j].type == kPartTypeAudio) { + + _frames[i].parts[j].flags = _stream->readByte(); + _stream->skip(9); // Unknow + + } else if (_frames[i].parts[j].type == kPartTypeVideo) { + + _frames[i].parts[j].left = _stream->readUint16LE(); + _frames[i].parts[j].top = _stream->readUint16LE(); + _frames[i].parts[j].right = _stream->readUint16LE(); + _frames[i].parts[j].bottom = _stream->readUint16LE(); + _stream->skip(1); // Unknown + _frames[i].parts[j].flags = _stream->readByte(); + + } else { + // Unknow type + _stream->skip(10); + } + + } + } + + return true; +} + +void Vmd::unload() { + clear(); +} + +void Vmd::setXY(int16 x, int16 y) { + + for (int i = 0; i < _framesCount; i++) { + for (int j = 0; j < _partsPerFrame; j++) { + + if (_frames[i].parts[j].type == kPartTypeVideo) { + if (x >= 0) { + _frames[i].parts[j].left = _frames[i].parts[j].left - _x + x; + _frames[i].parts[j].right = _frames[i].parts[j].right - _x + x; + } + if (y >= 0) { + _frames[i].parts[j].top = _frames[i].parts[j].top - _y + y; + _frames[i].parts[j].bottom = _frames[i].parts[j].bottom - _y + y; + } + } + + } + } + + if (x >= 0) + _x = x; + if (y >= 0) + _y = y; +} + +void Vmd::seekFrame(int32 frame, int16 whence, bool restart) { + if (!_stream) + // Nothing to do + return; + + // Find the frame to which to seek + if (whence == SEEK_CUR) + frame += _curFrame; + else if (whence == SEEK_END) + frame = _framesCount - frame - 1; + else if (whence != SEEK_SET) + return; + + if ((frame < 0) || (frame >= _framesCount)) + // Nothing to do + return; + + // Seek + _stream->seek(_frames[frame].offset); + _curFrame = frame; +} + +CoktelVideo::State Vmd::nextFrame() { + State state; + + state = processFrame(_curFrame); + _curFrame++; + return state; +} + +void Vmd::clear(bool del) { + Imd::clear(del); + + if (del) { + delete[] _frames; + } + + _hasVideo = true; + + _partsPerFrame = 0; + _frames = 0; + + _soundBytesPerSample = 1; + _soundStereo = 0; +} + +CoktelVideo::State Vmd::processFrame(uint16 frame) { + State state; + bool startSound = false; + + seekFrame(frame); + + state.flags |= kStateNoVideoData; + state.left = 0x7FFF; + state.right = 0x7FFF; + state.top = 0; + state.bottom = 0; + + if (!_vidMem) + setVideoMemory(); + + for (uint16 i = 0; i < _partsPerFrame; i++) { + Part &part = _frames[frame].parts[i]; + + if (part.type == kPartTypeAudio) { + // Next sound slice data + if (part.flags == 1) { + + if (_soundEnabled) + filledSoundSlice(part.size); + else + _stream->skip(part.size); + + // Initial sound data (all slices) + } else if (part.flags == 2) { + + if (_soundEnabled) { + uint32 mask = _stream->readUint32LE(); + filledSoundSlices(part.size - 4, mask); + + if (_soundStage == 1) + startSound = true; + + } else + _stream->skip(part.size); + + // Empty sound slice + } else if (part.flags == 3) { + + if (_soundEnabled && (part.size > 0)) + emptySoundSlice(part.size); + else + _stream->skip(part.size); + + } + + } else if (part.type == kPartTypeVideo) { + state.flags &= ~kStateNoVideoData; + + // New palette + if (part.flags & 2) { + uint8 index = _stream->readByte(); + uint8 count = _stream->readByte(); + + _stream->read(_palette + index * 3, (count + 1) * 3); + _stream->skip((255 - count) * 3); + + state.flags |= kStatePalette; + } + + _stream->read(_frameData, part.size); + if (renderFrame(part.left, part.top, part.right, part.bottom)) { + // Rendering succeeded, merging areas + state.left = MIN(state.left, part.left); + state.top = MIN(state.top, part.top); + state.right = MAX(state.right, part.right); + state.bottom = MAX(state.bottom, part.bottom); + } + + } else if (part.type == 4) { + // Unknown + _stream->skip(part.size); + } else { + // Unknow type +// warning("Unknown frame part type %d, size %d (%d of %d)", part.type, part.size, i + 1, _partsPerFrame); + } + } + + if (startSound && _soundEnabled) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); + _soundStartTime = g_system->getMillis(); + _skipFrames = 0; + _soundStage = 2; + } + + if ((_curFrame == (_framesCount - 1)) && (_soundStage == 2)) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + _audioStream = 0; + _soundStage = 0; + } + + _lastFrameTime = g_system->getMillis(); + return state; +} + +uint32 Vmd::renderFrame(int16 left, int16 top, int16 right, int16 bottom) { + if (!_frameData || !_vidMem || (_width <= 0) || (_height <= 0)) + return 0; + + int16 width = right - left + 1; + int16 height = bottom - top + 1; + int16 sW = _vidMemWidth; + byte *dataPtr = _frameData; + byte *imdVidMem = _vidMem + sW * top + left; + byte *srcPtr; + uint8 type = *dataPtr++; + + srcPtr = dataPtr; + + if (type & 0x80) { // Frame data is compressed + srcPtr = _vidBuffer; + type &= 0x7F; + if ((type == 2) && (width == sW)) { + deLZ77(imdVidMem, dataPtr); + return 1; + } else + deLZ77(srcPtr, dataPtr); + } + + uint16 pixCount, pixWritten; + byte *imdVidMemBak; + + if (type == 1) { // Sparse block + imdVidMemBak = imdVidMem; + for (int i = 0; i < height; i++) { + pixWritten = 0; + while (pixWritten < width) { + pixCount = *srcPtr++; + if (pixCount & 0x80) { // data + pixCount = MIN((pixCount & 0x7F) + 1, width - pixWritten); + memcpy(imdVidMem, srcPtr, pixCount); + + pixWritten += pixCount; + imdVidMem += pixCount; + srcPtr += pixCount; + } else { // "hole" + pixCount = (pixCount + 1) % 256; + pixWritten += pixCount; + imdVidMem += pixCount; + } + } + imdVidMemBak += sW; + imdVidMem = imdVidMemBak; + } + } else if (type == 2) { // Whole block + for (int i = 0; i < height; i++) { + memcpy(imdVidMem, srcPtr, width); + srcPtr += width; + imdVidMem += sW; + } + } else if (type == 3) { // RLE block + warning("Frame render method 3: RLE block"); + return 0; + } else { + warning("Unkown frame rendering method %d (0x%X)", type, type); + return 0; + } + + return 1; +} + +void Vmd::emptySoundSlice(uint32 size) { + byte *soundBuf = new byte[size]; + assert(soundBuf); + + memset(soundBuf, 0, size); + + _audioStream->queueBuffer(soundBuf, size); +} + +void Vmd::soundSlice8bit(uint32 size) { + byte *soundBuf = new byte[size]; + assert(soundBuf); + + _stream->read(soundBuf, size); + unsignedToSigned(soundBuf, size); + + _audioStream->queueBuffer(soundBuf, size); +} + +void Vmd::soundSlice16bit(uint32 size, int16 &init) { + byte *dataBuf = new byte[size]; + byte *soundBuf = new byte[size * 2]; + + _stream->read(dataBuf, size); + deDPCM(soundBuf, dataBuf, init, size); + _audioStream->queueBuffer(soundBuf, size * 2); + + delete[] dataBuf; +} + +void Vmd::filledSoundSlice(uint32 size) { + if (_soundBytesPerSample == 1) { + soundSlice8bit(size); + } else if (_soundBytesPerSample == 2) { + int16 init = _stream->readSint16LE(); + soundSlice16bit(size - 1, init); + } +} + +void Vmd::filledSoundSlices(uint32 size, uint32 mask) { + if (_soundBytesPerSample == 1) { + soundSlice8bit(size); + return; + } + + for (int i = 0; i < (_soundSlicesCount - 1); i++) { + + if (mask & 1) + emptySoundSlice(_soundSliceSize * 2); + else { + int16 init = _stream->readSint16LE(); + soundSlice16bit(_soundSliceSize, init); + } + + mask >>= 1; + } + +} + +void Vmd::deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n) { + int16 *out = (int16 *) soundBuf; + + int32 s = init; + for (uint32 i = 0; i < n; i++) { + if(dataBuf[i] & 0x80) + s -= _tableDPCM[dataBuf[i] & 0x7F]; + else + s += _tableDPCM[dataBuf[i]]; + + s = CLIP<int32>(s, -32768, 32767); + *out++ = TO_BE_16(s); + } +} + +} // End of namespace Gob diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h new file mode 100644 index 0000000000..a4e5452cce --- /dev/null +++ b/engines/gob/coktelvideo.h @@ -0,0 +1,313 @@ +/* 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_COKTELVIDEO_H +#define GOB_COKTELVIDEO_H + +#include "common/stream.h" +#include "sound/mixer.h" +#include "sound/audiostream.h" + +namespace Gob { + +/** Common interface for handling Coktel Vision videos and derivated formats. */ +class CoktelVideo { +public: + enum Features { + kFeaturesNone = 0, + /** Has an own palette. */ + kFeaturesPalette = 8, + /** Suggests a data size. */ + kFeaturesDataSize = 0x20, + /** Has sound. */ + kFeaturesSound = 0x40, + /** Has specific frame coordinates. */ + kFeaturesFrameCoords = 0x80, + /** Has general standard coordinates. */ + kFeaturesStdCoords = 0x100, + /** Has a frame positions table. */ + kFeaturesFramesPos = 0x200, + /** Has video. */ + kFeaturesVideo = 0x400 + }; + + enum StateFlags { + kStateNone = 0, + /** Changed the palette. */ + kStatePalette = 0x10, + /** Performed a jump to another frame. */ + kStateJump = 0x200, + /** Updated according to the specific frame coordinates. */ + kStateFrameCoords = 0x400, + /** Got no frame data. */ + kStateNoVideoData = 0x800, + /** Updated according to the general standard coordinates. */ + kStateStdCoords = 0x1000, + /** Had to explicitely seek to the frame. */ + kStateSeeked = 0x2000, + /** Reached a break-point. */ + kStateBreak = 0x8000 + }; + + struct State { + /** Left-most value of the updated rectangle. */ + int16 left; + /** Top-most value of the updated rectangle. */ + int16 top; + /** Right-most value of the updated rectangle. */ + int16 right; + /** Bottom-most value of the updated rectangle. */ + int16 bottom; + /** Set accordingly to what was done. */ + uint32 flags; + + State() : left(0), top(0), right(0), bottom(0), flags(0) { } + }; + + virtual ~CoktelVideo() { } + + /** Returns the features the loaded video possesses. */ + virtual uint16 getFeatures() const = 0; + /** Returns the x coordinate of the video. */ + virtual int16 getX() const = 0; + /** Returns the y coordinate of the video. */ + virtual int16 getY() const = 0; + /** Returns the width of the video. */ + virtual int16 getWidth() const = 0; + /** Returns the height of the video. */ + virtual int16 getHeight() const = 0; + /** Returns the number of frames the loaded video has. */ + virtual uint16 getFramesCount() const = 0; + /** Returns the current frame number. + * + * This is the current frame after the last nextFrame()-call, + * i.e. it's 0 after loading, 1 after the first nextFrame()-call, etc.. + */ + virtual uint16 getCurrentFrame() const = 0; + /** Returns the frame rate. */ + virtual int16 getFrameRate() const = 0; + /** Returns the number of frames the video lags behind the audio. */ + virtual uint32 getSyncLag() const = 0; + /** Returns the current frame's palette. */ + virtual const byte *getPalette() const = 0; + + /** Load a video out of a stream. */ + virtual bool load(Common::SeekableReadStream &stream) = 0; + /** Unload the currently loaded video. */ + virtual void unload() = 0; + + /** Set the coordinations where to draw the video. */ + virtual void setXY(int16 x, int16 y) = 0; + /** Use a specific memory block as video memory. */ + virtual void setVideoMemory(byte *vidMem, uint16 width, uint16 height) = 0; + /** Use an own memory block as video memory. */ + virtual void setVideoMemory() = 0; + + /** Play sound (if the IMD has sound). */ + virtual void enableSound(Audio::Mixer &mixer) = 0; + /** Don't play sound or stop currently playing sound. */ + virtual void disableSound() = 0; + + /** Seek to a specific frame. + * + * @param frame The frame to which to seek. + * @param whence The offset from whence the frame is given. + * @param restart Restart the video to reach an otherwise inaccessible frame? + */ + virtual void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false) = 0; + + /** Render the next frame. */ + virtual State nextFrame() = 0; + /** Wait for the frame to end. */ + virtual void waitEndFrame() = 0; + + /** Copy the current frame. + * + * @param dest The memory to which to copy the current frame + * @param x The x position to where to copy. + * @param y The y position to where to copy. + * @param pitch The buffer's width. + * @param transp Which color should be seen as transparent? + */ + virtual void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1) = 0; +}; + +/** Coktel Vision's IMD files. + */ +class Imd : public CoktelVideo { +public: + Imd(); + ~Imd(); + + uint16 getFeatures() const { return _features; } + int16 getX() const { return _x; } + int16 getY() const { return _y; } + int16 getWidth() const { return _width; } + int16 getHeight() const { return _height; } + uint16 getFramesCount() const { return _framesCount; } + uint16 getCurrentFrame() const { return _curFrame; } + int16 getFrameRate() const { if (_hasSound) return 1000 / _soundSliceLength; return 12; } + uint32 getSyncLag() const { return _skipFrames; } + const byte *getPalette() const { return _palette; } + + bool load(Common::SeekableReadStream &stream); + void unload(); + + void setXY(int16 x, int16 y); + void setVideoMemory(byte *vidMem, uint16 width, uint16 height); + void setVideoMemory(); + + void enableSound(Audio::Mixer &mixer); + void disableSound(); + + void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false); + + State nextFrame(); + void waitEndFrame(); + + void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1); + +protected: + struct Coord { + int16 left; + int16 top; + int16 right; + int16 bottom; + } PACKED_STRUCT; + + Common::SeekableReadStream *_stream; + uint16 _version; + uint16 _features; + uint16 _flags; + int16 _x, _y, _width, _height; + int16 _stdX, _stdY, _stdWidth, _stdHeight; + uint16 _framesCount, _curFrame; + uint32 *_framesPos; + uint32 _firstFramePos; + Coord *_frameCoords; + + uint32 _frameDataSize, _vidBufferSize; + byte *_frameData, *_vidBuffer; + + byte _palette[768]; + + bool _hasOwnVidMem; + byte *_vidMem; + uint16 _vidMemWidth, _vidMemHeight; + + bool _hasSound; + bool _soundEnabled; + uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing) + uint32 _soundStartTime; + uint32 _skipFrames; + + uint16 _soundFlags; + int16 _soundFreq; + int16 _soundSliceSize; + int16 _soundSlicesCount; + uint16 _soundSliceLength; + + Audio::AppendableAudioStream *_audioStream; + Audio::SoundHandle _audioHandle; + + uint32 _frameLength; + uint32 _lastFrameTime; + + Audio::Mixer *_mixer; + + void unsignedToSigned(byte *buffer, int length) { + while (length-- > 0) *buffer++ ^= 0x80; + } + + void deleteVidMem(bool del = true); + void clear(bool del = true); + + State processFrame(uint16 frame); + uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom); + void deLZ77(byte *dest, byte *src); +}; + +class Vmd : public Imd { +public: + Vmd(); + ~Vmd(); + + bool load(Common::SeekableReadStream &stream); + void unload(); + + void setXY(int16 x, int16 y); + + void seekFrame(int32 frame, int16 whence = SEEK_SET, bool restart = false); + + State nextFrame(); + +protected: + enum PartType { + kPartTypeAudio = 1, + kPartTypeVideo = 2 + }; + struct Part { + PartType type; + uint32 size; + int16 left; + int16 top; + int16 right; + int16 bottom; + byte flags; + } PACKED_STRUCT; + struct Frame { + uint32 offset; + Part *parts; + + Frame() : parts(0) { } + ~Frame() { delete[] parts; } + } PACKED_STRUCT; + + static const uint16 _tableDPCM[128]; + + bool _hasVideo; + + uint16 _partsPerFrame; + Frame *_frames; + + byte _soundBytesPerSample; + byte _soundStereo; // (0: mono, 1: old-style stereo, 2: new-style stereo) + + void clear(bool del = true); + + State processFrame(uint16 frame); + uint32 renderFrame(int16 left, int16 top, int16 right, int16 bottom); + + void emptySoundSlice(uint32 size); + void soundSlice8bit(uint32 size); + void soundSlice16bit(uint32 size, int16 &init); + void filledSoundSlice(uint32 size); + void filledSoundSlices(uint32 size, uint32 mask); + void deDPCM(byte *soundBuf, byte *dataBuf, int16 &init, uint32 n); +}; + +} // End of namespace Gob + +#endif // GOB_COKTELVIDEO_H diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 7ded953427..361627caf4 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -33,6 +33,92 @@ namespace Gob { +DataStream::DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose) { + _io = &io; + _handle = handle; + _size = dSize; + _dispose = dispose; + + _data = 0; + _stream = 0; +} + +DataStream::DataStream(byte *buf, uint32 dSize, bool dispose) { + _data = buf; + _size = dSize; + _stream = new Common::MemoryReadStream(_data, _size); + _dispose = dispose; + + _io = 0; + _handle = -1; +} + +DataStream::~DataStream() { + delete _stream; + + if (_dispose) { + delete[] _data; + if ((_handle >= 0) && _io) + _io->closeData(_handle); + } +} + +uint32 DataStream::pos() const { + if (_stream) + return _stream->pos(); + + uint32 resPos = _io->getChunkPos(_handle); + if (resPos != 0xFFFFFFFF) + return resPos; + + return _io->file_getHandle(_handle)->pos(); +} + +uint32 DataStream::size() const { + if (_stream) + return _stream->size(); + + return _size; +} + +void DataStream::seek(int32 offset, int whence) { + if (_stream) + _stream->seek(offset, whence); + + int32 resPos = _io->seekChunk(_handle, offset, whence); + if (resPos != -1) + return; + + _io->file_getHandle(_handle)->seek(offset, whence); +} + +bool DataStream::eos() const { + if (_stream) + return _stream->eos(); + + return pos() >= size(); +} + +uint32 DataStream::read(void *dataPtr, uint32 dataSize) { + if (_stream) + return _stream->read(dataPtr, dataSize); + + if ((_handle < 50) || (_handle >= 128)) + return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); + + byte *data = (byte *) dataPtr; + uint32 haveRead = 0; + while (dataSize > 0x3FFF) { + _io->readChunk(_handle, (byte *) data, 0x3FFF); + dataSize -= 0x3FFF; + data += 0x3FFF; + haveRead += 0x3FFF; + } + _io->readChunk(_handle, (byte *) data, dataSize); + + return haveRead + dataSize; +} + DataIO::DataIO(GobEngine *vm) : _vm(vm) { for (int i = 0; i < MAX_DATA_FILES; i++) { _dataFiles[i] = 0; @@ -115,6 +201,10 @@ Common::File *DataIO::file_getHandle(int16 handle) { return &_filesHandles[handle]; } +const Common::File *DataIO::file_getHandle(int16 handle) const { + return &_filesHandles[handle]; +} + int16 DataIO::file_open(const char *path, Common::File::AccessMode mode) { int16 i; @@ -226,7 +316,7 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { return _chunkPos[file * MAX_SLOT_COUNT + slot]; } -uint32 DataIO::getChunkPos(int16 handle) { +uint32 DataIO::getChunkPos(int16 handle) const { int16 file; int16 slot; @@ -390,39 +480,23 @@ int16 DataIO::openData(const char *path, Common::File::AccessMode mode) { return file_open(path, mode); } -int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { - int32 res; - - res = readChunk(handle, buf, size); - if (res >= 0) - return res; - - return file_getHandle(handle)->read(buf, size); -} +DataStream *DataIO::openAsStream(int16 handle, bool dispose) { + uint32 curPos = getPos(handle); + seekData(handle, 0, SEEK_END); + uint32 size = getPos(handle); + seekData(handle, curPos, SEEK_SET); -byte DataIO::readByte(int16 handle) { - byte buf; - - readData(handle, &buf, 1); - return ((byte) buf); + return new DataStream(*this, handle, size, dispose); } -uint16 DataIO::readUint16(int16 handle) { - byte buf[2]; - - readData(handle, buf, 2); - return READ_LE_UINT16(buf); -} - -uint32 DataIO::readUint32(int16 handle) { - byte buf[4]; +uint32 DataIO::getPos(int16 handle) { + uint32 resPos; - readData(handle, buf, 4); - return READ_LE_UINT32(buf); -} + resPos = getChunkPos(handle); + if (resPos != 0xFFFFFFFF) + return resPos; -int32 DataIO::writeData(int16 handle, byte *buf, uint16 size) { - return file_getHandle(handle)->write(buf, size); + return file_getHandle(handle)->pos(); } void DataIO::seekData(int16 handle, int32 pos, int16 from) { @@ -435,14 +509,14 @@ void DataIO::seekData(int16 handle, int32 pos, int16 from) { file_getHandle(handle)->seek(pos, from); } -uint32 DataIO::getPos(int16 handle) { - uint32 resPos; +int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { + int32 res; - resPos = getChunkPos(handle); - if (resPos != 0xFFFFFFFF) - return resPos; + res = readChunk(handle, buf, size); + if (res >= 0) + return res; - return file_getHandle(handle)->pos(); + return file_getHandle(handle)->read(buf, size); } int32 DataIO::getDataSize(const char *name) { @@ -492,4 +566,11 @@ byte *DataIO::getData(const char *path) { return data; } +DataStream *DataIO::getDataStream(const char *path) { + uint32 size = getDataSize(path); + byte *data = getData(path); + + return new DataStream(data, size); +} + } // End of namespace Gob diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index 3ea29c0efe..b30a389865 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -35,7 +35,33 @@ namespace Gob { #define MAX_FILES 30 #define MAX_DATA_FILES 8 -#define MAX_SLOT_COUNT 4 +#define MAX_SLOT_COUNT 8 + +class DataIO; + +class DataStream : public Common::SeekableReadStream { +public: + DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose = false); + DataStream(byte *buf, uint32 dSize, bool dispose = true); + virtual ~DataStream(); + + virtual uint32 pos() const; + virtual uint32 size() const; + + virtual void seek(int32 offset, int whence = SEEK_SET); + + virtual bool eos() const; + + virtual uint32 read(void *dataPtr, uint32 dataSize); + +private: + DataIO *_io; + int16 _handle; + uint32 _size; + byte *_data; + Common::MemoryReadStream *_stream; + bool _dispose; +}; class DataIO { public: @@ -55,15 +81,11 @@ public: void closeData(int16 handle); int16 openData(const char *path, Common::File::AccessMode mode = Common::File::kFileReadMode); - int32 readData(int16 handle, byte *buf, uint16 size); - byte readByte(int16 handle); - uint16 readUint16(int16 handle); - uint32 readUint32(int16 handle); - int32 writeData(int16 handle, byte *buf, uint16 size); - void seekData(int16 handle, int32 pos, int16 from); - uint32 getPos(int16 handle); + DataStream *openAsStream(int16 handle, bool dispose = false); + int32 getDataSize(const char *name); byte *getData(const char *path); + DataStream *getDataStream(const char *path); DataIO(class GobEngine *vm); ~DataIO(); @@ -85,13 +107,20 @@ protected: int16 file_open(const char *path, Common::File::AccessMode mode = Common::File::kFileReadMode); Common::File *file_getHandle(int16 handle); + const Common::File *file_getHandle(int16 handle) const; int16 getChunk(const char *chunkName); char freeChunk(int16 handle); int32 readChunk(int16 handle, byte *buf, uint16 size); int16 seekChunk(int16 handle, int32 pos, int16 from); - uint32 getChunkPos(int16 handle); + uint32 getChunkPos(int16 handle) const; int32 getChunkSize(const char *chunkName); + + uint32 getPos(int16 handle); + void seekData(int16 handle, int32 pos, int16 from); + int32 readData(int16 handle, byte *buf, uint16 size); + +friend class DataStream; }; } // End of namespace Gob diff --git a/engines/gob/detection.cpp b/engines/gob/detection.cpp index 1c275185ca..7faef57cc1 100644 --- a/engines/gob/detection.cpp +++ b/engines/gob/detection.cpp @@ -34,7 +34,8 @@ namespace Gob { struct GOBGameDescription { Common::ADGameDescription desc; - uint32 features; + GameType gameType; + int32 features; const char *startTotBase; }; @@ -48,11 +49,15 @@ static const PlainGameDescriptor gobGames[] = { {"gob1cd", "Gobliiins CD"}, {"gob2", "Gobliins 2"}, {"gob2cd", "Gobliins 2 CD"}, + {"ween", "Ween: The Prophecy"}, + {"bargon", "Bargon Attack"}, + {"ajworld", "A.J's World of Discovery"}, {"gob3", "Goblins Quest 3"}, {"gob3cd", "Goblins Quest 3 CD"}, - {"bargon", "Bargon Attack"}, - {"ween", "Ween: The Prophecy"}, + {"lostintime", "Lost in Time"}, + {"inca2", "Inca II: Wiracocha"}, {"woodruff", "The Bizarre Adventures of Woodruff and the Schnibble"}, +// {"dynasty", "The Last Dynasty"}, {0, 0} }; @@ -74,7 +79,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_EGA, + kGameTypeGob1, + kFeaturesEGA, "intro" }, { @@ -86,7 +92,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_EGA, + kGameTypeGob1, + kFeaturesEGA, "intro" }, { // Supplied by Theruler76 in bug report #1201233 @@ -98,7 +105,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesNone, "intro" }, { // CD 1.000 version. @@ -110,7 +118,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.000 version. @@ -122,7 +131,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.000 version. @@ -134,7 +144,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.000 version. @@ -146,7 +157,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.000 version. @@ -158,7 +170,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.02 version. Multilingual @@ -170,7 +183,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.02 version. Multilingual @@ -182,7 +196,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.02 version. Multilingual @@ -194,7 +209,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.02 version. Multilingual @@ -206,7 +222,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { // CD 1.02 version. Multilingual @@ -218,7 +235,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { @@ -230,7 +248,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_DEMO }, - GF_GOB1, + kGameTypeGob1, + kFeaturesNone, "intro" }, { @@ -242,7 +261,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB1, + kGameTypeGob1, + kFeaturesNone, "intro" }, { // Supplied by paul66 in bug report #1652352 @@ -254,7 +274,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesAdlib, "intro" }, { // Supplied by paul66 in bug report #1652352 @@ -266,7 +287,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesAdlib, "intro" }, { // Supplied by paul66 in bug report #1652352 @@ -278,7 +300,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesAdlib, "intro" }, { // Supplied by paul66 in bug report #1652352 @@ -290,7 +313,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesAdlib, "intro" }, { // Supplied by paul66 in bug report #1652352 @@ -302,7 +326,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesAdlib, "intro" }, { @@ -314,7 +339,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { // Supplied by arcepi in bug report #1659884 @@ -326,7 +352,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -338,7 +365,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { // Supplied by fac76 in bug report #1673397 @@ -354,7 +382,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -366,7 +395,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -378,7 +408,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -390,7 +421,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -402,7 +434,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesNone, "intro" }, { // Supplied by blackwhiteeagle in bug report #1605235 @@ -414,7 +447,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { // Supplied by bgk in bug report #1706861 @@ -426,7 +460,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAtariST, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesNone, "intro" }, { @@ -438,7 +473,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -450,7 +486,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -462,7 +499,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -474,7 +512,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -486,7 +525,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -498,7 +538,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -510,7 +551,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "usa" }, { @@ -522,7 +564,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -534,7 +577,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -546,7 +590,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "intro" }, { @@ -558,7 +603,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "intro" }, { // Supplied by cybot_tmin in bug report #1667743 @@ -570,19 +616,42 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "intro" }, { // Supplied by vampir_raziel in bug report #1658373 { "ween", "", - AD_ENTRY1s("intro.stk", "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570), + { + {"intro.stk", 0, "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570}, + {"ween.ins", 0, "d2cb24292c9ddafcad07e23382027218", 87800}, + {NULL, 0, NULL, 0} + }, EN_GRB, kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesNone, + "intro" + }, + { // Supplied by pwigren in bug report #1764174 + { + "ween", + "", + { + {"intro.stk", 0, "bfd9d02faf3d8d60a2cf744f95eb48dd", 456570}, + {"music__5.snd", 0, "7d1819b9981ecddd53d3aacbc75f1cc8", 13446}, + {NULL, 0, NULL, 0} + }, + EN_GRB, + kPlatformAtariST, + Common::ADGF_NO_FLAGS + }, + kGameTypeWeen, + kFeaturesNone, "intro" }, { // Supplied by vampir_raziel in bug report #1658373 @@ -594,7 +663,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesNone, "intro" }, { // Supplied by vampir_raziel in bug report #1658373 @@ -606,7 +676,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesNone, "intro" }, { // Supplied by vampir_raziel in bug report #1658373 @@ -618,7 +689,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesNone, "intro" }, { @@ -630,7 +702,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAtariST, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesNone, "intro" }, { @@ -642,7 +715,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "intro" }, { // Supplied by cartman_ on #scummvm @@ -654,7 +728,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "intro" }, { // Supplied by glorfindel in bugreport #1722142 @@ -666,7 +741,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "intro" }, { @@ -678,7 +754,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "show" }, { @@ -690,7 +767,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB2, + kGameTypeWeen, + kFeaturesAdlib, "show" }, { @@ -702,7 +780,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_BARGON, + kGameTypeBargon, + kFeaturesNone, "intro" }, { // Supplied by Trekky in the forums @@ -714,7 +793,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAtariST, Common::ADGF_NO_FLAGS }, - GF_BARGON, + kGameTypeBargon, + kFeaturesNone, "intro" }, { // Supplied by cesardark in bug #1681649 @@ -726,7 +806,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_BARGON, + kGameTypeBargon, + kFeaturesNone, "intro" }, { // Supplied by paul66 in bug #1692667 @@ -738,7 +819,21 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_BARGON, + kGameTypeBargon, + kFeaturesNone, + "intro" + }, + { // Supplied by pwigren in bugreport #1764174 + { + "bargon", + "", + AD_ENTRY1s("intro.stk", "569d679fe41d49972d34c9fce5930dda", 269825), + EN_ANY, + kPlatformAmiga, + Common::ADGF_NO_FLAGS + }, + kGameTypeBargon, + kFeaturesNone, "intro" }, { // Supplied by glorfindel in bugreport #1722142 @@ -750,7 +845,112 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_BARGON, + kGameTypeBargon, + kFeaturesNone, + "intro" + }, + { + { + "ajworld", + "", + AD_ENTRY1s("intro.stk", "e453bea7b28a67c930764d945f64d898", 3913628), + EN_ANY, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob2, + kFeaturesAdlib, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "7b7f48490dedc8a7cb999388e2fadbe3", 3930674), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesAdlib, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, + "intro" + }, + { + { + "lostintime", + "", + AD_ENTRY1s("intro.stk", "6263d09e996c1b4e84ef2d650b820e57", 4831170), + EN_GRB, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeLostInTime, + kFeaturesCD, "intro" }, { @@ -762,7 +962,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { // Supplied by fac76 in bug report #1742716 @@ -778,7 +979,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformMacintosh, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -790,7 +992,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { // Supplied by paul66 in bug report #1652352 @@ -802,7 +1005,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -814,7 +1018,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { // Supplied by Paranoimia on #scummvm @@ -826,7 +1031,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -838,7 +1044,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -850,7 +1057,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -862,7 +1070,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesNone, "menu" }, { @@ -874,7 +1083,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformAmiga, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesNone, "menu" }, { @@ -886,7 +1096,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, "intro" }, { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 @@ -898,7 +1109,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, "intro" }, { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 @@ -910,7 +1122,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, "intro" }, { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 @@ -922,7 +1135,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, "intro" }, { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 @@ -934,7 +1148,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, "intro" }, { // Supplied by paul66 and noizert in bug reports #1652352 and #1691230 @@ -946,7 +1161,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, "intro" }, { @@ -958,7 +1174,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -970,7 +1187,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -982,7 +1200,8 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -994,7 +1213,73 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_DEMO }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, + "intro" + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob3, + kFeaturesCD, + "intro" + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob3, + kFeaturesCD, + "intro" + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob3, + kFeaturesCD, + "intro" + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob3, + kFeaturesCD, + "intro" + }, + { + { + "inca2", + "", + AD_ENTRY1s("intro.stk", "47c3b452767c4f49ea7b109143e77c30", 916828), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeGob3, + kFeaturesCD, "intro" }, { @@ -1002,11 +1287,64 @@ static const GOBGameDescription gameDescriptions[] = { "woodruff", "", AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), - UNK_LANG, + EN_GRB, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + DE_DEU, kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_WOODRUFF, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "dccf9d31cb720b34d75487408821b77e", 20296390), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, "intro" }, { @@ -1014,11 +1352,64 @@ static const GOBGameDescription gameDescriptions[] = { "woodruff", "", AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), - EN_USA, + EN_GRB, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + IT_ITA, kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_WOODRUFF, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "b50fee012a5abcd0ac2963e1b4b56bec", 20298108), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, "intro" }, { @@ -1030,10 +1421,128 @@ static const GOBGameDescription gameDescriptions[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_WOODRUFF, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + ES_ESP, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, "intro" }, - { AD_TABLE_END_MARKER, 0, NULL } + { // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + EN_GRB, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by jvprat on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "270529d9b8cce770b1575908a3800b52", 20296452), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by Hkz on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), + IT_ITA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by Hkz on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), + DE_DEU, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + { // Supplied by Hkz on #scummvm + { + "woodruff", + "", + AD_ENTRY1s("intro.stk", "f4c344023b073782d2fddd9d8b515318", 7069736), + FR_FRA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + }, + /*{ + { + "dynasty", + "", + AD_ENTRY1s("intro.stk", "6190e32404b672f4bbbc39cf76f41fda", 2511470), + EN_USA, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, + "intro" + },*/ + { AD_TABLE_END_MARKER, kGameTypeNone, kFeaturesNone, NULL } }; static const GOBGameDescription fallbackDescs[] = { @@ -1046,7 +1555,8 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1, + kGameTypeGob1, + kFeaturesNone, "intro" }, { @@ -1058,7 +1568,8 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB1 | GF_CD, + kGameTypeGob1, + kFeaturesCD, "intro" }, { @@ -1070,7 +1581,8 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2, + kGameTypeGob2, + kFeaturesAdlib, "intro" }, { @@ -1082,7 +1594,8 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB2 | GF_CD, + kGameTypeGob2, + kFeaturesCD, "intro" }, { @@ -1094,7 +1607,8 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_BARGON, + kGameTypeBargon, + kFeaturesNone, "intro" }, { @@ -1106,7 +1620,8 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3, + kGameTypeGob3, + kFeaturesAdlib, "intro" }, { @@ -1118,7 +1633,21 @@ static const GOBGameDescription fallbackDescs[] = { kPlatformPC, Common::ADGF_NO_FLAGS }, - GF_GOB3 | GF_CD, + kGameTypeGob3, + kFeaturesCD, + "intro" + }, + { + { + "woodruff", + "unknown", + AD_ENTRY1(0, 0), + UNK_LANG, + kPlatformPC, + Common::ADGF_NO_FLAGS + }, + kGameTypeWoodruff, + kFeatures640, "intro" }, }; @@ -1132,6 +1661,7 @@ static const ADFileBasedFallback fileBased[] = { { &fallbackDescs[4], { "intro.stk", "scaa.imd", "scba.imd", "scbf.imd", 0 } }, { &fallbackDescs[5], { "intro.stk", "imd.itk", 0 } }, { &fallbackDescs[6], { "intro.stk", "mus_gob3.lic", 0 } }, + { &fallbackDescs[7], { "intro.stk", "woodruff.itk", 0 } }, { 0, { 0 } } }; @@ -1186,6 +1716,7 @@ bool GobEngine::detectGame() { strcat(_startTot0, "0.tot"); } + _gameType = gd->gameType; _features = gd->features; _language = gd->desc.language; _platform = gd->desc.platform; diff --git a/engines/gob/draw.cpp b/engines/gob/draw.cpp index bc5b205bd1..acf4d5765b 100644 --- a/engines/gob/draw.cpp +++ b/engines/gob/draw.cpp @@ -33,6 +33,7 @@ #include "gob/game.h" #include "gob/inter.h" #include "gob/video.h" +#include "gob/palanim.h" namespace Gob { @@ -411,4 +412,88 @@ void Draw::forceBlit(bool backwards) { 0, 0, 0); } +const int16 Draw::_wobbleTable[360] = { + 0x0000, 0x011D, 0x023B, 0x0359, 0x0476, 0x0593, 0x06B0, 0x07CC, 0x08E8, + 0x0A03, 0x0B1D, 0x0C36, 0x0D4E, 0x0E65, 0x0F7B, 0x1090, 0x11A4, 0x12B6, + 0x13C6, 0x14D6, 0x15E3, 0x16EF, 0x17F9, 0x1901, 0x1A07, 0x1B0C, 0x1C0E, + 0x1D0E, 0x1E0B, 0x1F07, 0x2000, 0x20F6, 0x21EA, 0x22DB, 0x23C9, 0x24B5, + 0x259E, 0x2684, 0x2766, 0x2846, 0x2923, 0x29FC, 0x2AD3, 0x2BA5, 0x2C75, + 0x2D41, 0x2E09, 0x2ECE, 0x2F8F, 0x304D, 0x3106, 0x31BC, 0x326E, 0x331C, + 0x33C6, 0x346C, 0x350E, 0x35AC, 0x3646, 0x36DB, 0x376C, 0x37F9, 0x3882, + 0x3906, 0x3985, 0x3A00, 0x3A77, 0x3AE9, 0x3B56, 0x3BBF, 0x3C23, 0x3C83, + 0x3CDE, 0x3D34, 0x3D85, 0x3DD1, 0x3E19, 0x3E5C, 0x3E99, 0x3ED2, 0x3F07, + 0x3F36, 0x3F60, 0x3F85, 0x3FA6, 0x3FC1, 0x3FD8, 0x3FE9, 0x3FF6, 0x3FFD, + 0x4000, 0x3FFD, 0x3FF6, 0x3FE9, 0x3FD8, 0x3FC1, 0x3FA6, 0x3F85, 0x3F60, + 0x3F36, 0x3F07, 0x3ED2, 0x3E99, 0x3E5C, 0x3E19, 0x3DD1, 0x3D85, 0x3D34, + 0x3CDE, 0x3C83, 0x3C23, 0x3BBF, 0x3B56, 0x3AE9, 0x3A77, 0x3A00, 0x3985, + 0x3906, 0x3882, 0x37F9, 0x376C, 0x36DB, 0x3646, 0x35AC, 0x350E, 0x346C, + 0x33C6, 0x331C, 0x326E, 0x31BC, 0x3106, 0x304D, 0x2F8F, 0x2ECE, 0x2E09, + 0x2D41, 0x2C75, 0x2BA5, 0x2AD3, 0x29FC, 0x2923, 0x2846, 0x2766, 0x2684, + 0x259E, 0x24B5, 0x23C9, 0x22DB, 0x21EA, 0x20F6, 0x1FFF, 0x1F07, 0x1E0B, + 0x1D0E, 0x1C0E, 0x1B0C, 0x1A07, 0x1901, 0x17F9, 0x16EF, 0x15E3, 0x14D6, + 0x13C6, 0x12B6, 0x11A4, 0x1090, 0x0F7B, 0x0E65, 0x0D4E, 0x0C36, 0x0B1D, + 0x0A03, 0x08E8, 0x07CC, 0x06B0, 0x0593, 0x0476, 0x0359, 0x023B, 0x011D + -0x0000, -0x011D, -0x023B, -0x0359, -0x0476, -0x0593, -0x06B0, -0x07CC, -0x08E8, + -0x0A03, -0x0B1D, -0x0C36, -0x0D4E, -0x0E65, -0x0F7B, -0x1090, -0x11A4, -0x12B6, + -0x13C6, -0x14D6, -0x15E3, -0x16EF, -0x17F9, -0x1901, -0x1A07, -0x1B0C, -0x1C0E, + -0x1D0E, -0x1E0B, -0x1F07, -0x2000, -0x20F6, -0x21EA, -0x22DB, -0x23C9, -0x24B5, + -0x259E, -0x2684, -0x2766, -0x2846, -0x2923, -0x29FC, -0x2AD3, -0x2BA5, -0x2C75, + -0x2D41, -0x2E09, -0x2ECE, -0x2F8F, -0x304D, -0x3106, -0x31BC, -0x326E, -0x331C, + -0x33C6, -0x346C, -0x350E, -0x35AC, -0x3646, -0x36DB, -0x376C, -0x37F9, -0x3882, + -0x3906, -0x3985, -0x3A00, -0x3A77, -0x3AE9, -0x3B56, -0x3BBF, -0x3C23, -0x3C83, + -0x3CDE, -0x3D34, -0x3D85, -0x3DD1, -0x3E19, -0x3E5C, -0x3E99, -0x3ED2, -0x3F07, + -0x3F36, -0x3F60, -0x3F85, -0x3FA6, -0x3FC1, -0x3FD8, -0x3FE9, -0x3FF6, -0x3FFD, + -0x4000, -0x3FFD, -0x3FF6, -0x3FE9, -0x3FD8, -0x3FC1, -0x3FA6, -0x3F85, -0x3F60, + -0x3F36, -0x3F07, -0x3ED2, -0x3E99, -0x3E5C, -0x3E19, -0x3DD1, -0x3D85, -0x3D34, + -0x3CDE, -0x3C83, -0x3C23, -0x3BBF, -0x3B56, -0x3AE9, -0x3A77, -0x3A00, -0x3985, + -0x3906, -0x3882, -0x37F9, -0x376C, -0x36DB, -0x3646, -0x35AC, -0x350E, -0x346C, + -0x33C6, -0x331C, -0x326E, -0x31BC, -0x3106, -0x304D, -0x2F8F, -0x2ECE, -0x2E09, + -0x2D41, -0x2C75, -0x2BA5, -0x2AD3, -0x29FC, -0x2923, -0x2846, -0x2766, -0x2684, + -0x259E, -0x24B5, -0x23C9, -0x22DB, -0x21EA, -0x20F6, -0x1FFF, -0x1F07, -0x1E0B, + -0x1D0E, -0x1C0E, -0x1B0C, -0x1A07, -0x1901, -0x17F9, -0x16EF, -0x15E3, -0x14D6, + -0x13C6, -0x12B6, -0x11A4, -0x1090, -0x0F7B, -0x0E65, -0x0D4E, -0x0C36, -0x0B1D, + -0x0A03, -0x08E8, -0x07CC, -0x06B0, -0x0593, -0x0476, -0x0359, -0x023B, -0x011D +}; + +void Draw::wobble(SurfaceDesc *surfDesc) { + int16 amplitude = 32; + uint16 curFrame = 0; + uint16 frameWobble = 0; + uint16 rowWobble = 0; + int8 *offsets = new int8[_vm->_height]; + + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, -1); + + while (amplitude > 0) { + rowWobble = frameWobble; + frameWobble = (frameWobble + 20) % 360; + + for (uint16 y = 0; y < _vm->_height; y++) { + offsets[y] = amplitude + + ((_wobbleTable[rowWobble] * amplitude) / 0x4000); + + rowWobble = (rowWobble + 20) % 360; + } + + if (curFrame++ & 16) + amplitude--; + + for (uint16 y = 0; y < _vm->_height; y++) + _vm->_video->drawSprite(surfDesc, _frontSurface, + 0, y, _vm->_width - 1, y, offsets[y], y, 0); + + _vm->_palAnim->fadeStep(0); + _vm->_video->waitRetrace(); + } + + _vm->_video->drawSprite(surfDesc, _frontSurface, + 0, 0, _vm->_width - 1, _vm->_height - 1, 0, 0, 0); + + _applyPal = false; + _invalidatedCount = 0; + _noInvalidated = true; + + delete[] offsets; +} + } // End of namespace Gob diff --git a/engines/gob/draw.h b/engines/gob/draw.h index e37ecda334..4bf59856be 100644 --- a/engines/gob/draw.h +++ b/engines/gob/draw.h @@ -32,13 +32,15 @@ namespace Gob { #define SPRITES_COUNT 50 -#define RENDERFLAG_NOINVALIDATE 0x001 -#define RENDERFLAG_CAPTUREPUSH 0x002 -#define RENDERFLAG_COLLISIONS 0x004 -#define RENDERFLAG_CAPTUREPOP 0x008 -#define RENDERFLAG_USEDELTAS 0x010 -#define RENDERFLAG_NOBLITINVALIDATED 0x200 -#define RENDERFLAG_SKIPOPTIONALTEXT 0x400 +#define RENDERFLAG_NOINVALIDATE 0x0001 +#define RENDERFLAG_CAPTUREPUSH 0x0002 +#define RENDERFLAG_COLLISIONS 0x0004 +#define RENDERFLAG_CAPTUREPOP 0x0008 +#define RENDERFLAG_USEDELTAS 0x0010 +#define RENDERFLAG_NOBLITINVALIDATED 0x0200 +#define RENDERFLAG_SKIPOPTIONALTEXT 0x0400 +#define RENDERFLAG_FROMSPLIT 0x0800 +#define RENDERFLAG_DOUBLECOORDS 0x1000 class Draw { public: @@ -151,6 +153,9 @@ public: int32 getSpriteRectSize(int16 index); void forceBlit(bool backwards = false); + static const int16 _wobbleTable[360]; + void wobble(SurfaceDesc *surfDesc); + virtual void initScreen() = 0; virtual void closeScreen() = 0; virtual void blitCursor() = 0; diff --git a/engines/gob/draw_v2.cpp b/engines/gob/draw_v2.cpp index c45bd0de27..55585f5619 100644 --- a/engines/gob/draw_v2.cpp +++ b/engines/gob/draw_v2.cpp @@ -197,7 +197,12 @@ void Draw_v2::printTotText(int16 id) { int16 rectLeft, rectTop, rectRight, rectBottom; int16 size; - if (!_vm->_game->_totTextData || !_vm->_game->_totTextData->dataPtr) + id &= 0xFFF; + + if (!_vm->_game->_totTextData || !_vm->_game->_totTextData->dataPtr || + (id >= _vm->_game->_totTextData->itemsCount) || + (_vm->_game->_totTextData->items[id].offset == -1) || + (_vm->_game->_totTextData->items[id].size == 0)) return; _vm->validateLanguage(); @@ -210,10 +215,34 @@ void Draw_v2::printTotText(int16 id) { if ((_renderFlags & RENDERFLAG_SKIPOPTIONALTEXT) && (ptr[1] & 0x80)) return; - destX = READ_LE_UINT16(ptr) & 0x7FFF; - destY = READ_LE_UINT16(ptr + 2); - spriteRight = READ_LE_UINT16(ptr + 4); - spriteBottom = READ_LE_UINT16(ptr + 6); + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { + destX = (READ_LE_UINT16(ptr) & 0x7FFF) * 2; + spriteRight = READ_LE_UINT16(ptr + 4) * 2 + 1; + } else { + destX = READ_LE_UINT16(ptr) & 0x7FFF; + spriteRight = READ_LE_UINT16(ptr + 4); + } + + if (_renderFlags & RENDERFLAG_FROMSPLIT) { + destY = _vm->_video->_splitHeight1; + spriteBottom = READ_LE_UINT16(ptr + 6) - READ_LE_UINT16(ptr + 2); + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) + spriteBottom *= 3; + spriteBottom += _vm->_video->_splitHeight1; + if (_renderFlags & RENDERFLAG_DOUBLECOORDS) { + spriteBottom += _backDeltaX; + destY += _backDeltaX; + } + } else { + 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); + } + } + ptr += 8; if (_renderFlags & RENDERFLAG_CAPTUREPUSH) { diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index 795484ef0e..37817c12a3 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -140,8 +140,18 @@ byte *Game::loadExtData(int16 itemId, int16 *pResWidth, size = item->size; isPacked = (item->width & 0x8000) != 0; - if (pResWidth != 0) { + if ((pResWidth != 0) && (pResHeight != 0)) { *pResWidth = item->width & 0x7FFF; + + if (*pResWidth & 0x4000) + size += 1 << 16; + if (*pResWidth & 0x2000) + size += 2 << 16; + if (*pResWidth & 0x1000) + size += 4 << 16; + + *pResWidth &= 0xFFF; + *pResHeight = item->height; debugC(7, kDebugFileIO, "loadExtData(%d, %d, %d)", itemId, *pResWidth, *pResHeight); @@ -164,8 +174,10 @@ byte *Game::loadExtData(int16 itemId, int16 *pResWidth, } else handle = _extHandle; + DataStream *stream = _vm->_dataIO->openAsStream(handle); + debugC(7, kDebugFileIO, "off: %d size: %d", offset, tableSize); - _vm->_dataIO->seekData(handle, offset + tableSize, SEEK_SET); + stream->seek(offset + tableSize); realSize = size; if (isPacked) dataBuf = new byte[size + 2]; @@ -175,11 +187,13 @@ byte *Game::loadExtData(int16 itemId, int16 *pResWidth, dataPtr = dataBuf; while (size > 32000) { // BUG: huge->far conversion. Need normalization? - _vm->_dataIO->readData(handle, dataPtr, 32000); + stream->read(dataPtr, 32000); size -= 32000; dataPtr += 32000; } - _vm->_dataIO->readData(handle, dataPtr, size); + stream->read(dataPtr, size); + + delete stream; if (commonHandle != -1) { _vm->_dataIO->closeData(commonHandle); _extHandle = _vm->_dataIO->openData(_curExtFile); @@ -315,11 +329,12 @@ void Game::evaluateScroll(int16 x, int16 y) { } int16 cursorRight = x + _vm->_draw->_cursorWidth; - int16 screenRight = _vm->_draw->_scrollOffsetX + 320; + int16 screenRight = _vm->_draw->_scrollOffsetX + _vm->_width; int16 cursorBottom = y + _vm->_draw->_cursorHeight; - int16 screenBottom = _vm->_draw->_scrollOffsetY + 200; + int16 screenBottom = _vm->_draw->_scrollOffsetY + _vm->_height; - if ((cursorRight >= 320) && (screenRight < _vm->_video->_surfWidth)) { + if ((cursorRight >= _vm->_width) && + (screenRight < _vm->_video->_surfWidth)) { uint16 off; off = MIN(_vm->_draw->_cursorWidth, @@ -328,8 +343,8 @@ void Game::evaluateScroll(int16 x, int16 y) { _vm->_draw->_scrollOffsetX += off; - _vm->_util->setMousePos(320 - _vm->_draw->_cursorWidth, y); - } else if ((cursorBottom >= (200 - _vm->_video->_splitHeight2)) && + _vm->_util->setMousePos(_vm->_width - _vm->_draw->_cursorWidth, y); + } else if ((cursorBottom >= (_vm->_height - _vm->_video->_splitHeight2)) && (screenBottom < _vm->_video->_surfHeight)) { uint16 off; @@ -339,7 +354,7 @@ void Game::evaluateScroll(int16 x, int16 y) { _vm->_draw->_scrollOffsetY += off; - _vm->_util->setMousePos(x, 200 - _vm->_video->_splitHeight2 - + _vm->_util->setMousePos(x, _vm->_height - _vm->_video->_splitHeight2 - _vm->_draw->_cursorHeight); } @@ -368,10 +383,12 @@ int16 Game::checkKeys(int16 *pMouseX, int16 *pMouseY, _vm->_inter->_soundEndTimeKey = 0; } - _vm->_util->getMouseState(pMouseX, pMouseY, pButtons); + if (pMouseX && pMouseY && pButtons) { + _vm->_util->getMouseState(pMouseX, pMouseY, pButtons); - if (*pButtons == 3) - *pButtons = 0; + if (*pButtons == 3) + *pButtons = 0; + } return _vm->_util->checkKey(); } @@ -408,23 +425,26 @@ void Game::loadExtTable(void) { if (_extHandle < 0) return; - count = _vm->_dataIO->readUint16(_extHandle); + DataStream *stream = _vm->_dataIO->openAsStream(_extHandle); + count = stream->readUint16LE(); - _vm->_dataIO->seekData(_extHandle, 0, SEEK_SET); + stream->seek(0); _extTable = new ExtTable; _extTable->items = 0; if (count) _extTable->items = new ExtItem[count]; - _extTable->itemsCount = _vm->_dataIO->readUint16(_extHandle); - _extTable->unknown = _vm->_dataIO->readByte(_extHandle); + _extTable->itemsCount = stream->readUint16LE(); + _extTable->unknown = stream->readByte(); for (int i = 0; i < count; i++) { - _extTable->items[i].offset = _vm->_dataIO->readUint32(_extHandle); - _extTable->items[i].size = _vm->_dataIO->readUint16(_extHandle); - _extTable->items[i].width = _vm->_dataIO->readUint16(_extHandle); - _extTable->items[i].height = _vm->_dataIO->readUint16(_extHandle); + _extTable->items[i].offset = stream->readUint32LE(); + _extTable->items[i].size = stream->readUint16LE(); + _extTable->items[i].width = stream->readUint16LE(); + _extTable->items[i].height = stream->readUint16LE(); } + + delete stream; } void Game::loadImFile(void) { @@ -544,7 +564,7 @@ void Game::switchTotSub(int16 index, int16 skipPlay) { int16 newPos = _curBackupPos - index - ((index >= 0) ? 1 : 0); // WORKAROUND: Some versions don't make the MOVEMENT menu item unselectable // in the dreamland screen, resulting in a crash when it's clicked. - if ((_vm->_features & GF_GOB2) && (index == -1) && (skipPlay == 7) && + if ((_vm->getGameType() == kGameTypeGob2) && (index == -1) && (skipPlay == 7) && !scumm_stricmp(_curTotFileArray[newPos], "gob06.tot")) return; @@ -652,7 +672,7 @@ int16 Game::openLocTextFile(char *locTextFile, int language) { return _vm->_dataIO->openData(locTextFile); } -byte *Game::loadLocTexts(void) { +byte *Game::loadLocTexts(int32 *dataSize) { char locTextFile[20]; int16 handle; int i; @@ -661,23 +681,48 @@ byte *Game::loadLocTexts(void) { handle = openLocTextFile(locTextFile, _vm->_global->_languageWanted); if (handle >= 0) { + _foundTotLoc = true; _vm->_global->_language = _vm->_global->_languageWanted; - } - else if (!_foundTotLoc) { - for (i = 0; i < 10; i++) { - handle = openLocTextFile(locTextFile, i); + + } else if (!_foundTotLoc) { + bool found = false; + + if (_vm->_global->_languageWanted == 2) { + handle = openLocTextFile(locTextFile, 5); + if (handle >= 0) { + _vm->_global->_language = 5; + found = true; + } + } else if (_vm->_global->_languageWanted == 5) { + handle = openLocTextFile(locTextFile, 2); if (handle >= 0) { - _vm->_global->_language = i; - break; + _vm->_global->_language = 2; + found = true; + } + } + + if (!found) { + for (i = 0; i < 10; i++) { + handle = openLocTextFile(locTextFile, i); + if (handle >= 0) { + _vm->_global->_language = i; + break; + } } } + } + debugC(1, kDebugFileIO, "Using language %d for %s", _vm->_global->_language, _curTotFile); if (handle >= 0) { _vm->_dataIO->closeData(handle); + + if (dataSize) + *dataSize = _vm->_dataIO->getDataSize(locTextFile); + return _vm->_dataIO->getData(locTextFile); } return 0; diff --git a/engines/gob/game.h b/engines/gob/game.h index 2181d219f2..c83497eaeb 100644 --- a/engines/gob/game.h +++ b/engines/gob/game.h @@ -147,11 +147,14 @@ public: void evaluateScroll(int16 x, int16 y); - int16 checkKeys(int16 *pMousex, int16 *pMouseY, int16 *pButtons, char handleMouse); + int16 checkKeys(int16 *pMousex = 0, int16 *pMouseY = 0, + int16 *pButtons = 0, char handleMouse = 0); void start(void); void totSub(int8 flags, const char *newTotFile); void switchTotSub(int16 index, int16 skipPlay); + void freeCollision(int16 id); + virtual void playTot(int16 skipPlay) = 0; virtual void clearCollisions(void) = 0; @@ -215,13 +218,12 @@ protected: int16 adjustKey(int16 key); - byte *loadLocTexts(void); + byte *loadLocTexts(int32 *dataSize = 0); int32 loadTotFile(const char *path); void loadExtTable(void); void loadImFile(void); void setCollisions(void); - void freeCollision(int16 id); void collSub(uint16 offset); void collAreaSub(int16 index, int8 enter); int16 openLocTextFile(char *locTextFile, int language); diff --git a/engines/gob/game_v1.cpp b/engines/gob/game_v1.cpp index 6ba68553c7..9c18ec1151 100644 --- a/engines/gob/game_v1.cpp +++ b/engines/gob/game_v1.cpp @@ -911,7 +911,8 @@ void Game_v1::collisionsBlock(void) { _shouldPushColls = 0; _vm->_global->_inter_execPtr = savedIP; deltaTime = timeVal - - (_vm->_util->getTimeKey() - timeKey); + ((_vm->_util->getTimeKey() - timeKey) + - _vm->_video->_lastRetraceLength); if (deltaTime < 2) deltaTime = 2; diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index 245c1f4544..7e87b9e8f8 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -1,27 +1,27 @@ -/* 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$ - * - */ + /* 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/stdafx.h" #include "common/endian.h" @@ -34,13 +34,13 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/goblin.h" -#include "gob/imd.h" #include "gob/inter.h" #include "gob/mult.h" #include "gob/parse.h" #include "gob/scenery.h" #include "gob/sound.h" #include "gob/video.h" +#include "gob/videoplayer.h" namespace Gob { @@ -101,6 +101,7 @@ void Game_v2::playTot(int16 skipPlay) { _extTable = 0; _extHandle = -1; + _vm->_draw->_cursorHotspotXVar = -1; _totToLoad[0] = 0; if ((_curTotFile[0] == 0) && (_totFileData == 0)) @@ -134,12 +135,16 @@ void Game_v2::playTot(int16 skipPlay) { totTextLoc = false; if (READ_LE_UINT32(filePtr) != (uint32) -1) { _totTextData = new TotTextTable; + + int32 size; + if (READ_LE_UINT32(filePtr) == 0) { - _totTextData->dataPtr = loadLocTexts(); + _totTextData->dataPtr = loadLocTexts(&size); totTextLoc = true; } else { _totTextData->dataPtr = (_totFileData + READ_LE_UINT32(_totFileData + 0x30)); + size = totSize; _vm->_global->_language = _vm->_global->_languageWanted; } @@ -147,7 +152,7 @@ void Game_v2::playTot(int16 skipPlay) { if (_totTextData->dataPtr != 0) { Common::MemoryReadStream totTextData(_totTextData->dataPtr, 4294967295U); - _totTextData->itemsCount = totTextData.readSint16LE(); + _totTextData->itemsCount = totTextData.readSint16LE() & 0x3FFF; _totTextData->items = new TotTextItem[_totTextData->itemsCount]; for (int i = 0; i < _totTextData->itemsCount; ++i) { @@ -267,7 +272,7 @@ void Game_v2::playTot(int16 skipPlay) { _vm->_snd->freeSample(_soundSamples[i]); } - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); if (_totToLoad[0] == 0) break; diff --git a/engines/gob/global.cpp b/engines/gob/global.cpp index ec2fa6b043..f3bc0611fd 100644 --- a/engines/gob/global.cpp +++ b/engines/gob/global.cpp @@ -112,7 +112,7 @@ Global::Global(GobEngine *vm) : _vm(vm) { _setAllPalette = false; _dontSetPalette = false; - _primarySurfDesc = new SurfaceDesc(0x13, 320, 200); + _primarySurfDesc = 0; _debugFlag = 0; _inVM = 0; diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 32caca31d8..d9385b1b0f 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -48,7 +48,7 @@ #include "gob/parse.h" #include "gob/scenery.h" #include "gob/music.h" -#include "gob/imd.h" +#include "gob/videoplayer.h" #include "gob/saveload.h" namespace Gob { @@ -68,6 +68,16 @@ 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; + // Setup mixer if (!_mixer->isReady()) { warning("Sound initialization failed."); @@ -94,25 +104,7 @@ GobEngine::~GobEngine() { // Stop all mixer streams (except for the permanent ones). _vm->_mixer->stopAll(); - delete _snd; - delete _adlib; - delete _mult; - delete _game; - delete _global; - delete _cdrom; - delete _dataIO; - delete _goblin; - delete _imdPlayer; - delete _init; - delete _inter; - delete _map; - delete _palAnim; - delete _parse; - delete _scenery; - delete _draw; - delete _util; - delete _video; - delete _saveLoad; + deinitGameParts(); delete[] _startTot; delete[] _startTot0; } @@ -129,15 +121,23 @@ void GobEngine::shutdown() { void GobEngine::validateLanguage() { if (_vm->_global->_languageWanted != _vm->_global->_language) { - warning("Your game version doesn't support the requested language"); - warning("Using the first language available: %s", - getLangDesc(_vm->_global->_language)); + warning("Your game version doesn't support the requested language %s", + getLangDesc(_vm->_global->_languageWanted)); + + if (((_vm->_global->_languageWanted == 2) && (_vm->_global->_language == 5)) || + ((_vm->_global->_languageWanted == 5) && (_vm->_global->_language == 2))) + warning("Using %s instead", getLangDesc(_vm->_global->_language)); + else + warning("Using the first language available: %s", + getLangDesc(_vm->_global->_language)); + _vm->_global->_languageWanted = _vm->_global->_language; } } void GobEngine::validateVideoMode(int16 videoMode) { - if ((videoMode != 0x13) && (videoMode != 0x14)) + if ((videoMode != 0x10) && (videoMode != 0x13) && + (videoMode != 0x14) && (videoMode != 0x18)) error("Video mode 0x%X is not supported!", videoMode); } @@ -148,82 +148,18 @@ int GobEngine::init() { return -1; } - _adlib = 0; - _saveLoad = 0; - _global = new Global(this); - _util = new Util(this); - _dataIO = new DataIO(this); - _palAnim = new PalAnim(this); - _imdPlayer = new ImdPlayer(this); - _cdrom = new CDROM(this); - _snd = new Snd(this); - if (_features & Gob::GF_GOB1) { - _init = new Init_v1(this); - _video = new Video_v1(this); - _inter = new Inter_v1(this); - _parse = new Parse_v1(this); - _mult = new Mult_v1(this); - _draw = new Draw_v1(this); - _game = new Game_v1(this); - _map = new Map_v1(this); - _goblin = new Goblin_v1(this); - _scenery = new Scenery_v1(this); - } else if (_features & Gob::GF_GOB2) { - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_v2(this); - _parse = new Parse_v2(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _game = new Game_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); - } else if (_features & Gob::GF_BARGON) { - _init = new Init_v2(this); - _video = new Video_v2(this); - _inter = new Inter_Bargon(this); - _parse = new Parse_v2(this); - _mult = new Mult_v2(this); - _draw = new Draw_Bargon(this); - _game = new Game_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v2(this); - _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); - } else if (_features & Gob::GF_GOB3) { - _init = new Init_v3(this); - _video = new Video_v2(this); - _inter = new Inter_v3(this); - _parse = new Parse_v2(this); - _mult = new Mult_v2(this); - _draw = new Draw_v2(this); - _game = new Game_v2(this); - _map = new Map_v2(this); - _goblin = new Goblin_v3(this); - _scenery = new Scenery_v2(this); - _saveLoad = new SaveLoad_v3(this, _targetName.c_str()); - } else - error("GobEngine::init(): Unknown version of game engine"); - - _noMusic = MidiDriver::parseMusicDriver(ConfMan.get("music_driver")) == MD_NULL; - if (!_noMusic && !(_platform == Common::kPlatformAmiga) && - !(_platform == Common::kPlatformAtariST) && - (((_platform == Common::kPlatformMacintosh) && (_features & Gob::GF_GOB1)) || - (_features & Gob::GF_GOB2) || (_features & Gob::GF_GOB3))) - _adlib = new Adlib(this); - _vm = this; - - _map->init(); + if (!initGameParts()) { + GUIErrorMessage("GobEngine::init(): Unknown version of game engine"); + return -1; + } _system->beginGFXTransaction(); - initCommonGFX(false); - _system->initSize(320, 200); + _system->initSize(_width, _height); + initCommonGFX(is640()); _system->endGFXTransaction(); // On some systems it's not safe to run CD audio games from the CD. - if (_features & GF_CD) + if (isCD()) checkCD(); int cd_num = ConfMan.getInt("cdrom"); @@ -293,4 +229,167 @@ int GobEngine::init() { return 0; } +bool GobEngine::initGameParts() { + _adlib = 0; + _saveLoad = 0; + + _global = new Global(this); + _util = new Util(this); + _dataIO = new DataIO(this); + _palAnim = new PalAnim(this); + _vidPlayer = new VideoPlayer(this); + _cdrom = new CDROM(this); + _snd = new Snd(this); + + switch (_gameType) { + case kGameTypeGob1: + _init = new Init_v1(this); + _video = new Video_v1(this); + _inter = new Inter_v1(this); + _parse = new Parse_v1(this); + _mult = new Mult_v1(this); + _draw = new Draw_v1(this); + _game = new Game_v1(this); + _map = new Map_v1(this); + _goblin = new Goblin_v1(this); + _scenery = new Scenery_v1(this); + break; + + case kGameTypeGob2: + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_v2(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); + break; + + case kGameTypeBargon: + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_Bargon(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_Bargon(this); + _game = new Game_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); + break; + + case kGameTypeWeen: + _init = new Init_v2(this); + _video = new Video_v2(this); + _inter = new Inter_v2(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v2(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v2(this, _targetName.c_str()); + break; + + case kGameTypeGob3: + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v3(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v3(this, _targetName.c_str()); + break; + + case kGameTypeLostInTime: + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v3(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v3(this, _targetName.c_str(), 4768, 0, 50); + break; + + case kGameTypeWoodruff: + _init = new Init_v3(this); + _video = new Video_v2(this); + _inter = new Inter_v4(this); + _parse = new Parse_v2(this); + _mult = new Mult_v2(this); + _draw = new Draw_v2(this); + _game = new Game_v2(this); + _map = new Map_v2(this); + _goblin = new Goblin_v3(this); + _scenery = new Scenery_v2(this); + _saveLoad = new SaveLoad_v3(this, _targetName.c_str()); + break; + + default: + deinitGameParts(); + return false; + break; + } + + _noMusic = MidiDriver::parseMusicDriver(ConfMan.get("music_driver")) == MD_NULL; + if (!_noMusic && hasAdlib()) + _adlib = new Adlib(this); + + _map->init(); + + if (is640()) { + _video->_surfWidth = _width = 640; + _video->_surfHeight = _video->_splitHeight1 = _height = 480; + _global->_mouseMaxCol = 640; + _global->_mouseMaxRow = 480; + _mode = 0x18; + _global->_primarySurfDesc = new SurfaceDesc(0x18, 640, 480); + } else { + _video->_surfWidth = _width = 320; + _video->_surfHeight = _video->_splitHeight1 = _height = 200; + _global->_mouseMaxCol = 320; + _global->_mouseMaxRow = 200; + _mode = 0x14; + _global->_primarySurfDesc = new SurfaceDesc(0x14, 320, 200); + } + + return true; +} + +void GobEngine::deinitGameParts() { + delete _snd; _snd = 0; + delete _adlib; _adlib = 0; + delete _mult; _mult = 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; + delete _palAnim; _palAnim = 0; + delete _parse; _parse = 0; + delete _scenery; _scenery = 0; + delete _draw; _draw = 0; + delete _util; _util = 0; + delete _video; _video = 0; + delete _saveLoad; _saveLoad = 0; +} + } // End of namespace Gob diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 97ee312bff..d573dc3a89 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -42,7 +42,7 @@ class Draw; class CDROM; class DataIO; class Goblin; -class ImdPlayer; +class VideoPlayer; class Init; class Inter; class Map; @@ -78,14 +78,23 @@ class Adlib; #define VAR(var) READ_VAR_UINT32(var) #define VAR_ADDRESS(var) ((uint32 *) VARP((var) << 2)) -enum { - GF_GOB1 = 1 << 0, - GF_GOB2 = 1 << 1, - GF_GOB3 = 1 << 2, - GF_WOODRUFF = 1 << 3, - GF_BARGON = 1 << 4, - GF_CD = 1 << 5, - GF_EGA = 1 << 6 +enum GameType { + kGameTypeNone = 0, + kGameTypeGob1, + kGameTypeGob2, + kGameTypeGob3, + kGameTypeWoodruff, + kGameTypeBargon, + kGameTypeWeen, + kGameTypeLostInTime +}; + +enum Features { + kFeaturesNone = 0, + kFeaturesCD = 1 << 0, + kFeaturesEGA = 1 << 1, + kFeaturesAdlib = 1 << 2, + kFeatures640 = 1 << 3 }; enum { @@ -165,6 +174,9 @@ protected: int go(); int init(); + bool initGameParts(); + void deinitGameParts(); + bool detectGame(); public: @@ -172,9 +184,15 @@ public: Common::RandomSource _rnd; + GameType _gameType; int32 _features; Common::Language _language; Common::Platform _platform; + + uint16 _width; + uint16 _height; + uint8 _mode; + char *_startTot; char *_startTot0; bool _copyProtection; @@ -199,7 +217,7 @@ public: Inter *_inter; SaveLoad *_saveLoad; Adlib *_adlib; - ImdPlayer *_imdPlayer; + VideoPlayer *_vidPlayer; void shutdown(); @@ -211,6 +229,12 @@ public: 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; } + GobEngine(OSystem *syst); virtual ~GobEngine(); }; diff --git a/engines/gob/goblin.cpp b/engines/gob/goblin.cpp index 418b31e2ee..1db741bd44 100644 --- a/engines/gob/goblin.cpp +++ b/engines/gob/goblin.cpp @@ -1698,6 +1698,9 @@ void Goblin::playSounds(Mult::Mult_Object *obj) { int16 sndSlot; int16 frame; + if (!obj->goblinStates) + return; + animData = obj->pAnimData; for (int i = 1; i <= obj->goblinStates[animData->state][0].dataCount; i++) { diff --git a/engines/gob/goblin_v2.cpp b/engines/gob/goblin_v2.cpp index 67e9f65444..608b0f0790 100644 --- a/engines/gob/goblin_v2.cpp +++ b/engines/gob/goblin_v2.cpp @@ -314,6 +314,9 @@ void Goblin_v2::moveAdvance(Mult::Mult_Object *obj, Gob_Object *gobDesc, int16 state; int16 layer; + if (!obj->goblinStates) + return; + movePathFind(obj, 0, 0); playSounds(obj); diff --git a/engines/gob/goblin_v3.cpp b/engines/gob/goblin_v3.cpp index 002ef7b749..f4aa872fa1 100644 --- a/engines/gob/goblin_v3.cpp +++ b/engines/gob/goblin_v3.cpp @@ -115,6 +115,9 @@ void Goblin_v3::placeObject(Gob_Object *objDesc, char animated, Mult::Mult_Object &obj = _vm->_mult->_objects[index]; Mult::Mult_AnimData &objAnim = *(obj.pAnimData); + if (!obj.goblinStates) + return; + if ((state != -1) && (obj.goblinStates[state] != 0)) { if (state == 8) objAnim.curLookDir = 0; diff --git a/engines/gob/imd.cpp b/engines/gob/imd.cpp deleted file mode 100644 index 395fb01f9b..0000000000 --- a/engines/gob/imd.cpp +++ /dev/null @@ -1,1249 +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/stdafx.h" -#include "common/endian.h" - -#include "gob/gob.h" -#include "gob/imd.h" -#include "gob/global.h" -#include "gob/util.h" -#include "gob/dataio.h" -#include "gob/draw.h" -#include "gob/game.h" -#include "gob/inter.h" -#include "gob/palanim.h" -#include "gob/sound.h" -#include "gob/video.h" - -namespace Gob { - -ImdPlayer::ImdPlayer(GobEngine *vm) : _vm(vm) { - _curImd = 0; - _curFile[0] = 0; - - _curX = 0; - _curY = 0; - _left = 0; - _top = 0; - _right = 0; - _bottom = 0; - - _frameData = 0; - _vidBuffer = 0; - - _frontSurf = 21; - _backSurf = 21; - _frontMem = 0; - _frameDelay = 0; - - _noSound = true; - - _soundStartTime = 0; - _skipFrames = 0; - - _soundFreq = 0; - _soundSliceSize = 0; - _soundSlicesCount = 0; - - _soundSliceLength = 0; - _soundStage = 0; - - _audioStream = 0; -} - -ImdPlayer::~ImdPlayer() { - if (_curImd) { - delete[] _curImd->palette; - delete[] _curImd->framesPos; - delete[] _curImd->frameCoords; - delete[] _curImd->extraPalette; - } - delete[] _frameData; - delete[] _vidBuffer; - delete[] _frontMem; - delete _curImd; -} - -// flag bits: 0 = read and set palette -// 1 = read palette -ImdPlayer::Imd *ImdPlayer::loadImdFile(const char *path, SurfaceDesc *surfDesc, int8 flags) { - Imd *imdPtr; - int16 handle; - char buf[18]; - uint32 framesPosPos = 0; - uint32 framesCordsPos = 0; - - strncpy0(buf, path, 17); - if (!strchr(buf, '.')) { - buf[13] = 0; - strcat(buf, ".IMD"); - } - - handle = _vm->_dataIO->openData(buf); - - if (handle < 0) { - warning("Can't open IMD \"%s\"", buf); - return 0; - } - - imdPtr = new Imd; - assert(imdPtr); - memset(imdPtr, 0, sizeof(Imd)); - - imdPtr->handle = _vm->_dataIO->readUint16(handle); - imdPtr->verMin = _vm->_dataIO->readUint16(handle); - imdPtr->framesCount = _vm->_dataIO->readUint16(handle); - imdPtr->x = _vm->_dataIO->readUint16(handle); - imdPtr->y = _vm->_dataIO->readUint16(handle); - imdPtr->width = _vm->_dataIO->readUint16(handle); - imdPtr->height = _vm->_dataIO->readUint16(handle); - imdPtr->field_E = _vm->_dataIO->readUint16(handle); - imdPtr->curFrame = _vm->_dataIO->readUint16(handle); - - if ((imdPtr->handle != 0) || ((imdPtr->verMin & 0xFF) < 2)) { - warning("%s: Version incorrect (%d,%X)", buf, imdPtr->handle, imdPtr->verMin); - _vm->_dataIO->closeData(handle); - delete imdPtr; - return 0; - } - - imdPtr->handle = handle; - imdPtr->surfDesc = surfDesc; - imdPtr->firstFramePos = imdPtr->curFrame; - imdPtr->curFrame = 0; - - if ((imdPtr->verMin & 0x800) && ((flags & 3) != 3)) - imdPtr->extraPalette = new Video::Color[256]; - - if (flags & 3) { - imdPtr->palette = new Video::Color[256]; - assert(imdPtr->palette); - _vm->_dataIO->readData(handle, (byte *) imdPtr->palette, 768); - } else - _vm->_dataIO->seekData(handle, 768, SEEK_CUR); - - if ((flags & 3) == 1) - _vm->_video->setPalette(imdPtr->palette); - - if ((imdPtr->verMin & 0xFF) >= 3) { - imdPtr->stdX = _vm->_dataIO->readUint16(handle); - if (imdPtr->stdX > 1) { - warning("%s: More than one standard coordinate quad found (%d)", - buf, imdPtr->stdX); - finishImd(imdPtr); - return 0; - } - if (imdPtr->stdX != 0) { - imdPtr->stdX = _vm->_dataIO->readUint16(handle); - imdPtr->stdY = _vm->_dataIO->readUint16(handle); - imdPtr->stdWidth = _vm->_dataIO->readUint16(handle); - imdPtr->stdHeight = _vm->_dataIO->readUint16(handle); - } else - imdPtr->stdX = -1; - } else - imdPtr->stdX = -1; - - if ((imdPtr->verMin & 0xFF) >= 4) { - framesPosPos = _vm->_dataIO->readUint32(handle); - if (framesPosPos != 0) { - imdPtr->framesPos = new int32[imdPtr->framesCount]; - assert(imdPtr->framesPos); - } - } - - if (imdPtr->verMin & 0x8000) - framesCordsPos = _vm->_dataIO->readUint32(handle); - - _noSound = true; - _soundStage = 0; - if (imdPtr->verMin & 0x4000) { - _soundFreq = _vm->_dataIO->readUint16(handle); - _soundSliceSize = _vm->_dataIO->readUint16(handle); - _soundSlicesCount = _vm->_dataIO->readUint16(handle); - - if (_soundFreq < 0) - _soundFreq = -_soundFreq; - - if (_soundSlicesCount < 0) - _soundSlicesCount = -_soundSlicesCount - 1; - - if (_soundSlicesCount > 40) { - warning("%s: More than 40 sound slices found (%d)", - buf, _soundSlicesCount); - finishImd(imdPtr); - return 0; - } - - _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); - - _soundStage = 1; - _noSound = false; - - _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); - } - - if (imdPtr->verMin & 0x2000) { - imdPtr->frameDataSize = _vm->_dataIO->readUint16(handle); - if (imdPtr->frameDataSize == 0) { - imdPtr->frameDataSize = _vm->_dataIO->readUint32(handle); - imdPtr->vidBufferSize = _vm->_dataIO->readUint32(handle); - } else - imdPtr->vidBufferSize = _vm->_dataIO->readUint16(handle); - } else { - imdPtr->frameDataSize = imdPtr->width * imdPtr->height + 500; - if (!(imdPtr->field_E & 0x100) || (imdPtr->field_E & 0x1000)) - imdPtr->vidBufferSize = imdPtr->frameDataSize; - } - - if (imdPtr->framesPos) { - _vm->_dataIO->seekData(handle, framesPosPos, SEEK_SET); - for (int i = 0; i < imdPtr->framesCount; i++) - imdPtr->framesPos[i] = _vm->_dataIO->readUint32(handle); - } - - if (imdPtr->verMin & 0x8000) { - _vm->_dataIO->seekData(handle, framesCordsPos, SEEK_SET); - imdPtr->frameCoords = new ImdCoord[imdPtr->framesCount]; - assert(imdPtr->frameCoords); - for (int i = 0; i < imdPtr->framesCount; i++) { - imdPtr->frameCoords[i].left = _vm->_dataIO->readUint16(handle); - imdPtr->frameCoords[i].top = _vm->_dataIO->readUint16(handle); - imdPtr->frameCoords[i].right = _vm->_dataIO->readUint16(handle); - imdPtr->frameCoords[i].bottom = _vm->_dataIO->readUint16(handle); - } - } - - _vm->_dataIO->seekData(handle, imdPtr->firstFramePos, SEEK_SET); - return imdPtr; -} - -void ImdPlayer::finishImd(ImdPlayer::Imd *&imdPtr) { - if (!imdPtr) - return; - - if (_soundStage == 2) - _vm->_snd->stopSound(0); - - _vm->_dataIO->closeData(imdPtr->handle); - - delete[] imdPtr->frameCoords; - delete[] imdPtr->palette; - delete[] imdPtr->framesPos; - delete[] imdPtr->extraPalette; - - delete imdPtr; - - if (_audioStream) { - _audioStream->finish(); - _vm->_mixer->stopHandle(_audioHandle); - _audioStream = 0; - } -} - -int8 ImdPlayer::openImd(const char *path, int16 x, int16 y, - int16 startFrame, int16 flags) { - const char *src; - byte *vidMem; - SurfaceDesc *surfDesc; - - if (!_curImd) - _curFile[0] = 0; - - src = strrchr(path, '\\'); - src = !src ? path : src + 1; - - if ((path[0] != 0) && scumm_stricmp(_curFile, src)) { - closeImd(); - - _curImd = loadImdFile(path, 0, 3); - if (!_curImd) - return 0; - - _curX = _curImd->x; - _curY = _curImd->y; - strncpy0(_curFile, src, 17); - - delete[] _frameData; - _frameData = new byte[_curImd->frameDataSize + 500]; - assert(_frameData); - memset(_frameData, 0, _curImd->frameDataSize + 500); - - delete[] _vidBuffer; - _vidBuffer = new byte[_curImd->vidBufferSize + 500]; - assert(_vidBuffer); - memset(_vidBuffer, 0, _curImd->vidBufferSize + 500); - - if (!(flags & 0x100)) { - - if (_vm->_global->_videoMode == 0x14) { - - _backSurf = (flags & 0x80) ? 20 : 21; - if (!(_curImd->field_E & 0x100) || (_curImd->field_E & 0x2000)) { - setXY(_curImd, 0, 0); - _curImd->surfDesc = - _vm->_video->initSurfDesc(0x13, - _curImd->width, _curImd->height, 0); - } else { - _curImd->surfDesc = _vm->_draw->_spritesArray[_frontSurf]; - if ((x != -1) || (y != -1)) { - _curX = x != -1 ? x : _curX; - _curY = y != -1 ? y : _curY; - setXY(_curImd, _curX, _curY); - } - } - - if (flags & 0x40) { - _curX = x != -1 ? x : _curX; - _curY = y != -1 ? y : _curY; - if (_curImd->surfDesc->_vidMode == 0x14) { - surfDesc = _vm->_video->initSurfDesc(0x13, - _curImd->width, _curImd->height, 0); - _vm->_video->drawSprite(_vm->_draw->_spritesArray[21], - surfDesc, _curX, _curY, - _curX + _curImd->width - 1, _curY + _curImd->height - 1, - 0, 0, 0); - - vidMem = _curImd->surfDesc->getVidMem(); - for (int i = 0; i < _curImd->height; i++) - for (int j = 0; j < _curImd->width; j++, vidMem++) { - *(vidMem) = *(surfDesc->getVidMem() + - (j / 4) + (surfDesc->getWidth() / 4 * i)); - } - surfDesc = 0; - } - } - - } else { - if ((x != -1) || (y != -1)) { - _curX = (x != -1) ? x : _curX; - _curY = (y != -1) ? y : _curY; - setXY(_curImd, _curX, _curY); - } - _backSurf = (flags & 0x80) ? 20 : 21; - _curImd->surfDesc = _vm->_draw->_spritesArray[_backSurf]; - } - - } - } - - if (!_curImd) - return 0; - - if (startFrame == -1) { - closeImd(); - return 0; - } - - _curX = (x != -1) ? x : _curX; - _curY = (y != -1) ? y : _curY; - - WRITE_VAR(7, _curImd->framesCount); - - return 1; -} - -void ImdPlayer::closeImd(void) { - finishImd(_curImd); - - delete[] _frameData; - delete[] _vidBuffer; - _frameData = 0; - _vidBuffer = 0; - - _curImd = 0; -} - -void ImdPlayer::setXY(ImdPlayer::Imd *imdPtr, int16 x, int16 y) { - int i; - - if (imdPtr->stdX != -1) { - imdPtr->stdX = imdPtr->stdX - imdPtr->x + x; - imdPtr->stdY = imdPtr->stdY - imdPtr->y + y; - } - - if (imdPtr->frameCoords) { - for (i = 0; i < imdPtr->framesCount; i++) { - if (imdPtr->frameCoords[i].left != -1) { - imdPtr->frameCoords[i].left = - imdPtr->frameCoords[i].left - imdPtr->x + x; - imdPtr->frameCoords[i].top = - imdPtr->frameCoords[i].top - imdPtr->y + y; - imdPtr->frameCoords[i].right = - imdPtr->frameCoords[i].right - imdPtr->x + x; - imdPtr->frameCoords[i].bottom = - imdPtr->frameCoords[i].bottom - imdPtr->y + y; - } - } - } - - imdPtr->x = x; - imdPtr->y = y; -} - -void ImdPlayer::drawFrame(Imd *imdPtr, int16 frame, int16 x, int16 y, - SurfaceDesc *dest) { - if (!dest) - dest = _vm->_draw->_frontSurface; - - if (frame == 0) - _vm->_video->drawSprite(imdPtr->surfDesc, dest, 0, 0, - imdPtr->width - 1, imdPtr->height - 1, x, y, 0); - else if (imdPtr->frameCoords && (imdPtr->frameCoords[frame].left != -1)) - _vm->_video->drawSprite(imdPtr->surfDesc, dest, - imdPtr->frameCoords[frame].left, imdPtr->frameCoords[frame].top, - imdPtr->frameCoords[frame].right, imdPtr->frameCoords[frame].bottom, - imdPtr->frameCoords[frame].left + x, - imdPtr->frameCoords[frame].top + y, 0); - else if (imdPtr->stdX != -1) - _vm->_video->drawSprite(imdPtr->surfDesc, dest, - imdPtr->stdX, imdPtr->stdY, imdPtr->stdX + imdPtr->stdWidth - 1, - imdPtr->stdY + imdPtr->stdHeight - 1, x + imdPtr->stdX, - y + imdPtr->stdY, 0); - else - _vm->_video->drawSprite(imdPtr->surfDesc, dest, 0, 0, - imdPtr->width - 1, imdPtr->height - 1, x, y, 0); -} - -void ImdPlayer::renderFrame(Imd *imdPtr) { - int16 imdX, imdY; - int16 imdW, imdH; - int16 sW; - uint16 pixCount, pixWritten; - uint8 type; - byte *imdVidMem; - byte *imdVidMemBak; - byte *dataPtr = 0; - byte *srcPtr = 0; - - dataPtr = _frameData; - imdX = imdPtr->x; - imdY = imdPtr->y; - imdW = imdPtr->width; - imdH = imdPtr->height; - sW = imdPtr->surfDesc->getWidth(); - imdVidMem = imdPtr->surfDesc->getVidMem() + sW * imdY + imdX; - - type = *dataPtr++; - srcPtr = dataPtr; - - if (type & 0x10) { // Palette data - type ^= 0x10; - dataPtr += 49; - } - - srcPtr = dataPtr; - if (type & 0x80) { // Frame data is compressed - srcPtr = _vidBuffer; - type &= 0x7F; - if ((type == 2) && (imdW == sW)) { - frameUncompressor(imdVidMem, dataPtr); - return; - } else - frameUncompressor(srcPtr, dataPtr); - } - - if (type == 2) { // Whole block - for (int i = 0; i < imdH; i++) { - memcpy(imdVidMem, srcPtr, imdW); - srcPtr += imdW; - imdVidMem += sW; - } - } else if (type == 1) { // Sparse block - imdVidMemBak = imdVidMem; - for (int i = 0; i < imdH; i++) { - pixWritten = 0; - while (pixWritten < imdW) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // data - pixCount = MIN((pixCount & 0x7F) + 1, imdW - pixWritten); - memcpy(imdVidMem, srcPtr, pixCount); - - pixWritten += pixCount; - imdVidMem += pixCount; - srcPtr += pixCount; - } else { // "hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - imdVidMem += pixCount; - } - } - imdVidMemBak += sW; - imdVidMem = imdVidMemBak; - } - } else if (type == 0x42) { // Whole quarter-wide block - for (int i = 0; i < imdH; i++) { - imdVidMemBak = imdVidMem; - - for (int j = 0; j < imdW; j += 4, imdVidMem += 4, srcPtr++) - memset(imdVidMem, *srcPtr, 4); - - imdVidMemBak += sW; - imdVidMem = imdVidMemBak; - } - } else if ((type & 0xF) == 2) { // Whole half-high block - for (; imdH > 1; imdH -= 2, imdVidMem += sW + sW, srcPtr += imdW) { - memcpy(imdVidMem, srcPtr, imdW); - memcpy(imdVidMem + sW, srcPtr, imdW); - } - if (imdH == -1) - memcpy(imdVidMem, srcPtr, imdW); - } else { // Sparse half-high block - imdVidMemBak = imdVidMem; - for (int i = 0; i < imdH; i += 2) { - pixWritten = 0; - while (pixWritten < imdW) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // data - pixCount = MIN((pixCount & 0x7F) + 1, imdW - pixWritten); - memcpy(imdVidMem, srcPtr, pixCount); - memcpy(imdVidMem + sW, srcPtr, pixCount); - - pixWritten += pixCount; - imdVidMem += pixCount; - srcPtr += pixCount; - } else { // "hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - imdVidMem += pixCount; - } - } - imdVidMemBak += sW + sW; - imdVidMem = imdVidMemBak; - } - } -} - -void ImdPlayer::frameUncompressor(byte *dest, byte *src) { - int i; - byte buf[4370]; - uint16 chunkLength; - uint16 frameLength; - uint16 bufPos1; - uint16 bufPos2; - uint16 tmp; - uint8 chunkBitField; - uint8 chunkCount; - bool mode; - - frameLength = READ_LE_UINT16(src); - src += 4; - - if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { - src += 4; - bufPos1 = 273; - mode = 1; // 123Ch (cmp al, 12h) - } else { - bufPos1 = 4078; - mode = 0; // 275h (jnz +2) - } - - memset(buf, 32, bufPos1); - chunkCount = 1; - chunkBitField = 0; - - while (frameLength > 0) { - chunkCount--; - if (chunkCount == 0) { - tmp = *src++; - chunkCount = 8; - chunkBitField = tmp; - } - if (chunkBitField % 2) { - chunkBitField >>= 1; - buf[bufPos1] = *src; - *dest++ = *src++; - bufPos1 = (bufPos1 + 1) % 4096; - frameLength--; - continue; - } - chunkBitField >>= 1; - - tmp = READ_LE_UINT16(src); - src += 2; - chunkLength = ((tmp & 0xF00) >> 8) + 3; - - if ((mode && ((chunkLength & 0xFF) == 0x12)) || - (!mode && (chunkLength == 0))) - chunkLength = *src++ + 0x12; - - bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00); - if (((tmp + chunkLength) >= 4096) || - ((chunkLength + bufPos1) >= 4096)) { - - for (i = 0; i < chunkLength; i++, dest++) { - *dest = buf[bufPos2]; - buf[bufPos1] = buf[bufPos2]; - bufPos1 = (bufPos1 + 1) % 4096; - bufPos2 = (bufPos2 + 1) % 4096; - } - - } else if (((tmp + chunkLength) < bufPos1) || - ((chunkLength + bufPos1) < bufPos2)) { - - memcpy(dest, buf + bufPos2, chunkLength); - memmove(buf + bufPos1, buf + bufPos2, chunkLength); - - dest += chunkLength; - bufPos1 += chunkLength; - bufPos2 += chunkLength; - - } else { - - for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) { - *dest = buf[bufPos2]; - buf[bufPos1] = buf[bufPos2]; - } - - } - frameLength -= chunkLength; - - } -} - -void ImdPlayer::play(const char *path, int16 x, int16 y, bool interruptible) { - int16 mouseX; - int16 mouseY; - int16 buttons; - - _vm->_util->setFrameRate(12); - if (!openImd(path, x, y, 0, 2)) - return; - - _vm->_video->fillRect(_vm->_draw->_frontSurface, x, y, - x + _curImd->width - 1, y + _curImd->height - 1, 0); - - for (int i = 0; i < _curImd->framesCount; i++) { - play(i, 4, 0, 255, 0, _curImd->framesCount - 1); - - if (_vm->_quitRequested || (interruptible && - (_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B))) - break; - } - - closeImd(); -} - -void ImdPlayer::play(const char *path, int16 x, int16 y, int16 startFrame, - int16 frames, bool fade, bool interruptible) { - int16 mouseX; - int16 mouseY; - int16 buttons = 0; - int endFrame; - - _vm->_util->setFrameRate(12); - if (!openImd(path, x, y, 0, 0)) - return; - - _vm->_video->fillRect(_vm->_draw->_frontSurface, x, y, - x + _curImd->width - 1, y + _curImd->height - 1, 0); - - if (fade) - _vm->_palAnim->fade(0, -2, 0); - - endFrame = frames > 0 ? frames : _curImd->framesCount; - for (int i = startFrame; i < endFrame; i++) { - view(_curImd, i); - drawFrame(_curImd, i, x, y); - if (fade) { - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - fade = false; - } - _vm->_video->waitRetrace(); - - if (_vm->_quitRequested || (interruptible && - (_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B))) { - _vm->_palAnim->fade(0, -2, 0); - _vm->_video->clearSurf(_vm->_draw->_frontSurface); - memset((char *) _vm->_draw->_vgaPalette, 0, 768); - - WRITE_VAR(4, buttons); - WRITE_VAR(0, 0x11B); - WRITE_VAR(57, (uint32) -1); - break; - } - - _vm->_util->waitEndFrame(); - } - - if (frames < 0) { - endFrame = _curImd->framesCount + frames; - for (int i = _curImd->framesCount - 1; i >= endFrame; i--) { - seekFrame(_curImd, i, SEEK_SET, true); - drawFrame(_curImd, i, x, y); - _vm->_video->waitRetrace(); - - if (_vm->_quitRequested || (interruptible && - (_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B))) { - _vm->_palAnim->fade(0, -2, 0); - _vm->_video->clearSurf(_vm->_draw->_frontSurface); - memset((char *) _vm->_draw->_vgaPalette, 0, 768); - - WRITE_VAR(4, buttons); - WRITE_VAR(0, 0x11B); - WRITE_VAR(57, (uint32) -1); - break; - } - - _vm->_util->waitEndFrame(); - } - } - - closeImd(); -} - -void ImdPlayer::play(int16 frame, uint16 palCmd, - int16 palStart, int16 palEnd, int16 palFrame, int16 lastFrame) { - uint32 viewRet = 0; - SurfaceDesc *surfDescBak; - bool modifiedPal = false; - - _vm->_draw->_showCursor = 0; - - if ((frame < 0) || (frame > lastFrame)) - return; - - palCmd &= 0x3F; - if ((frame == palFrame) || ((frame == lastFrame) && (palCmd == 8))) { - modifiedPal = true; - _vm->_draw->_applyPal = true; - - if (palCmd >= 4) - copyPalette(palStart, palEnd); - } - - if (modifiedPal && (palCmd == 8) && (_backSurf == 20)) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - - if (_curImd->surfDesc) { - if (_curImd->surfDesc->_vidMode == 0x14) { - - if ((_frontMem == _vm->_draw->_frontSurface->getVidMem()) && - (_frontSurf == 20)) { - _vm->_draw->_frontSurface->swap(_vm->_draw->_backSurface); - viewRet = view(_curImd, frame); - _vm->_draw->_frontSurface->swap(_vm->_draw->_backSurface); - } else - viewRet = view(_curImd, frame); - - if (_frontSurf == 21) - _vm->_draw->invalidateRect(_left, _top, _right, _bottom); - - } else { - if ((_curImd->field_E & 0x100) && - (_vm->_global->_videoMode == 0x14) && - (_frontSurf == 20) && - (checkFrameType(_curImd, frame) & 0x8000) && - (_backSurf == 21)) { - - surfDescBak = _curImd->surfDesc; - if (_frontMem == _vm->_draw->_spritesArray[20]->getVidMem()) - _curImd->surfDesc = _vm->_draw->_spritesArray[21]; - else - _curImd->surfDesc = _vm->_draw->_spritesArray[20]; - setXY(_curImd, _curX, _curY); - viewRet = view(_curImd, frame); - _curImd->surfDesc = surfDescBak; - setXY(_curImd, 0, 0); - - } else { - viewRet = view(_curImd, frame); - if (!(viewRet & 0x800)) - drawFrame(frame); - } - } - } else - viewRet = view(_curImd, frame); - - if (modifiedPal && (palCmd == 16)) { - if (_backSurf == 21) - _vm->_draw->forceBlit(); - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - _vm->_draw->_noInvalidated = true; - } - - if (viewRet & 0x10) { - copyPalette(palStart, palEnd); - - if (_backSurf == 20) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - else - _vm->_draw->_applyPal = true; - } - - if (modifiedPal && (palCmd == 8) && (_backSurf == 21)) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - - if (!(viewRet & 0x800)) { - if (_vm->_draw->_cursorIndex == -1) { - if (_frontSurf == 20) - flipFrontMem(); - else - _vm->_draw->blitInvalidated(); - } else - _vm->_draw->animateCursor(-1); - } - - if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - - // To allow quitting, etc. during IMDs - _vm->_util->processInput(); - if (_vm->_quitRequested) - return; - - if (_soundStage != 2) { - if (viewRet & 0x800) { - if (_frameDelay == 0) - _vm->_util->delay(30); - else { - _frameDelay -= 30; - if (_frameDelay < 0) - _frameDelay = 0; - } - } else - _vm->_util->waitEndFrame(); - } - - _vm->_inter->animPalette(); -} - -inline void ImdPlayer::drawFrame(int16 frame) { - if (_backSurf == 21) { - - if (_vm->_global->_videoMode == 0x14) { - if (_frontSurf == 21) { - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - drawFrame(_curImd, frame, _curX, _curY); - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - _vm->_draw->invalidateRect(_curX + _left, _curY + _top, - _curX + _right, _curY + _bottom); - } else { - if (_frontMem == _vm->_draw->_spritesArray[20]->getVidMem()) { - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - drawFrame(_curImd, frame, _curX, _curY); - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - } else - drawFrame(_curImd, frame, _curX, _curY); - } - } else - _vm->_draw->invalidateRect(_left, _top, _right, _bottom); - - } else if (_vm->_global->_videoMode == 0x14) - drawFrame(_curImd, frame, _curX, _curY); -} - -inline void ImdPlayer::copyPalette(int16 palStart, int16 palEnd) { - if ((palStart == -1) || (palEnd == -1)) - memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, - (char *) _curImd->palette, 768); - else - memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + - palStart * 3, ((char *) (_curImd->palette)) + palStart * 3, - (palEnd - palStart + 1) * 3); -} - -inline void ImdPlayer::flipFrontMem() { - if (_frontMem == _vm->_draw->_frontSurface->getVidMem()) - _frontMem = _vm->_draw->_backSurface->getVidMem(); - else - _frontMem = _vm->_draw->_frontSurface->getVidMem(); -} - -uint16 ImdPlayer::checkFrameType(Imd *imdPtr, int16 frame) { - uint16 retVal = 0; - uint32 posBak; - uint32 tmp; - uint16 cmd; - int16 frameBak; - - if (!imdPtr) - return 0x8000; - - posBak = _vm->_dataIO->getPos(imdPtr->handle); - frameBak = imdPtr->curFrame; - - if (imdPtr->curFrame != frame) { - retVal |= 0x2000; - seekFrame(imdPtr, frame, SEEK_SET); - } - - do { - if (frame != 0) { - if (imdPtr->stdX != -1) - retVal |= 0x1000; - if (imdPtr->frameCoords && (imdPtr->frameCoords[frame].left != -1)) - retVal |= 0x400; - } - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { - _vm->_dataIO->seekData(imdPtr->handle, 2, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - if (cmd == 0xFFF1) { - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) - tmp = _vm->_dataIO->readUint32(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } - } - - // Jump to frame - if (cmd == 0xFFFD) { - frame = _vm->_dataIO->readUint16(imdPtr->handle); - if (imdPtr->framesPos) { - _vm->_dataIO->seekData(imdPtr->handle, - imdPtr->framesPos[frame], SEEK_SET); - retVal |= 0x200; - continue; - } - break; - } - - // Next sound slice data - if (cmd == 0xFF00) { - _vm->_dataIO->seekData(imdPtr->handle, - _soundSliceSize, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - _vm->_dataIO->seekData(imdPtr->handle, - _soundSliceSize * _soundSlicesCount, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - // Frame video data - if (cmd != 0) { - _vm->_dataIO->readData(imdPtr->handle, _frameData, 5); - retVal |= _frameData[0]; - } else - retVal |= 0x800; - - break; - - } while (true); - - _vm->_dataIO->seekData(imdPtr->handle, posBak, SEEK_SET); - imdPtr->curFrame = frameBak; - return retVal; -} - -void ImdPlayer::seekFrame(Imd *imdPtr, int16 frame, int16 from, bool restart) { - uint32 framePos = 0; - - if (!imdPtr) - return; - - if (from == SEEK_CUR) - frame += imdPtr->curFrame; - else if (from == SEEK_END) - frame = imdPtr->framesCount - frame - 1; - - if (frame >= imdPtr->framesCount) - return; - - if (frame == 0) { - framePos = imdPtr->firstFramePos; - } else if (frame == 1) { - framePos = imdPtr->firstFramePos; - _vm->_dataIO->seekData(imdPtr->handle, framePos, SEEK_SET); - framePos += _vm->_dataIO->readUint16(imdPtr->handle) + 4; - } else if (imdPtr->framesPos) { - framePos = imdPtr->framesPos[frame]; - } else if (restart && (_soundStage == 0)) { - for (int i = 0; i <= frame; i++) - view(_curImd, i); - } else - error("%s: Frame %d is not directly accessible", _curFile, frame); - - _vm->_dataIO->seekData(imdPtr->handle, framePos, SEEK_SET); - imdPtr->curFrame = frame; -} - -uint32 ImdPlayer::view(Imd *imdPtr, int16 frame) { - uint32 retVal = 0; - uint32 cmd = 0; - int16 xBak, yBak, heightBak, widthBak; - bool hasNextCmd = false; - bool startSound = false; - - if (!imdPtr) - return 0x8000; - - if (frame != imdPtr->curFrame) { - retVal |= 0x2000; - seekFrame(imdPtr, frame, SEEK_SET); - } - - _left = xBak = imdPtr->x; - _top = yBak = imdPtr->y; - _bottom = heightBak= imdPtr->height; - _right = widthBak = imdPtr->width; - _right += _left - 1; - _bottom += _top - 1; - - if ((frame == 0) && (imdPtr->verMin & 0x800)) - _vm->_video->setPalette(imdPtr->palette); - - do { - if (frame != 0) { - if (imdPtr->stdX != -1) { - _left = imdPtr->x = imdPtr->stdX; - _top = imdPtr->y = imdPtr->stdY; - _right = imdPtr->width = imdPtr->stdWidth; - _bottom = imdPtr->height = imdPtr->stdHeight; - _right += _left - 1; - _bottom += _top - 1; - retVal |= 0x1000; - } - if (imdPtr->frameCoords && - (imdPtr->frameCoords[frame].left != -1)) { - _left = imdPtr->x = imdPtr->frameCoords[frame].left; - _top = imdPtr->y = imdPtr->frameCoords[frame].top; - _right = imdPtr->width = - imdPtr->frameCoords[frame].right - imdPtr->x + 1; - _bottom = imdPtr->height = - imdPtr->frameCoords[frame].bottom - imdPtr->y + 1; - _right += _left - 1; - _bottom += _top - 1; - retVal |= 0x400; - } - } - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { - _vm->_dataIO->seekData(imdPtr->handle, 2, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - if (cmd == 0xFFF1) { - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) - cmd = _vm->_dataIO->readUint32(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } - } - - if (_soundStage != 0) { - byte *soundBuf; - - if (!hasNextCmd) - waitEndSoundSlice(); - - // Next sound slice data - if (cmd == 0xFF00) { - - if (!hasNextCmd && !_noSound) { - soundBuf = new byte[_soundSliceSize]; - assert(soundBuf); - - _vm->_dataIO->readData(imdPtr->handle, soundBuf, - _soundSliceSize); - _vm->_snd->convToSigned(soundBuf, _soundSliceSize); - _audioStream->queueBuffer(soundBuf, _soundSliceSize); - } else - _vm->_dataIO->seekData(imdPtr->handle, - _soundSliceSize, SEEK_CUR); - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - int dataLength = _soundSliceSize * _soundSlicesCount; - - if (!hasNextCmd && !_noSound) { - soundBuf = new byte[dataLength]; - assert(soundBuf); - - _vm->_dataIO->readData(imdPtr->handle, soundBuf, dataLength); - _vm->_snd->convToSigned(soundBuf, dataLength); - - _soundStage = 1; - startSound = true; - _audioStream->queueBuffer(soundBuf, dataLength); - } else - _vm->_dataIO->seekData(imdPtr->handle, dataLength, SEEK_CUR); - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - // Empty sound slice - } else if (!hasNextCmd && (!_noSound)) { - soundBuf = new byte[_soundSliceSize]; - assert(soundBuf); - - memset(soundBuf, 0, _soundSliceSize); - _audioStream->queueBuffer(soundBuf, _soundSliceSize); - } - } - - // Set palette - if (cmd == 0xFFF4) { - _vm->_dataIO->seekData(imdPtr->handle, 2, SEEK_CUR); - retVal |= 0x10; - if (imdPtr->extraPalette) { - _vm->_dataIO->readData(imdPtr->handle, - (byte *) imdPtr->extraPalette, 768); - _vm->_video->setPalette(imdPtr->extraPalette); - } else if (imdPtr->palette) - _vm->_dataIO->readData(imdPtr->handle, - (byte *) imdPtr->palette, 768); - else - _vm->_dataIO->readData(imdPtr->handle, _frameData, 768); - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - hasNextCmd = false; - - // Jump to frame - if (cmd == 0xFFFD) { - - frame = _vm->_dataIO->readUint16(imdPtr->handle); - if (imdPtr->framesPos) { - imdPtr->curFrame = frame; - _vm->_dataIO->seekData(imdPtr->handle, - imdPtr->framesPos[frame], SEEK_SET); - - hasNextCmd = true; - retVal |= 0x200; - } - - } else if (cmd == 0xFFFC) { - - retVal |= 1; - cmd = _vm->_dataIO->readUint32(imdPtr->handle); - _vm->_dataIO->readData(imdPtr->handle, _frameData, cmd + 2); - - if (imdPtr->surfDesc) { - int16 left = imdPtr->x; - int16 top = imdPtr->y; - int16 right = imdPtr->width + left; - int16 bottom = imdPtr->height + top; - - if (imdPtr->surfDesc->getWidth() < right) { - left = 0; - right = imdPtr->width; - } - if (imdPtr->surfDesc->getWidth() < right) - right = imdPtr->surfDesc->getWidth(); - if (imdPtr->surfDesc->getHeight() < bottom) { - top = 0; - bottom = imdPtr->height; - } - if (imdPtr->surfDesc->getHeight() < bottom) - bottom = imdPtr->surfDesc->getHeight(); - - imdPtr->x = left; - imdPtr->y = top; - imdPtr->height = bottom - top; - imdPtr->width = right - left; - - renderFrame(imdPtr); - } - - retVal |= _frameData[0]; - - // Frame video data - } else if (cmd != 0) { - - _vm->_dataIO->readData(imdPtr->handle, _frameData, cmd + 2); - if (imdPtr->surfDesc) - renderFrame(imdPtr); - - retVal |= _frameData[0]; - - } else - retVal |= 0x800; - - } while (hasNextCmd); - - if (startSound) { - _vm->_snd->stopSound(0); - _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); - _soundStartTime = _vm->_util->getTimeKey(); - _skipFrames = 0; - _soundStage = 2; - } - - imdPtr->x = xBak; - imdPtr->y = yBak; - imdPtr->width = widthBak; - imdPtr->height = heightBak; - - imdPtr->curFrame++; - if ((imdPtr->curFrame == imdPtr->framesCount) && (_soundStage == 2)) { - waitEndSoundSlice(); - _audioStream->finish(); - _vm->_mixer->stopHandle(_audioHandle); - _audioStream = 0; - } - - return retVal; -} - -inline void ImdPlayer::waitEndSoundSlice() { - if (_soundStage != 2) - return; - - if (_skipFrames == 0) { - - _vm->_video->retrace(); - - int32 waitTime = (_curImd->curFrame * _soundSliceLength) - - (_vm->_util->getTimeKey() - _soundStartTime); - - if (waitTime < 0) { - _skipFrames = -waitTime / _soundSliceLength; - warning("IMD A/V sync broken, skipping %d frame(s)", _skipFrames + 1); - } else if (waitTime > 0) - _vm->_util->delay(waitTime); - - } else - _skipFrames--; -} - -} // End of namespace Gob diff --git a/engines/gob/imd.h b/engines/gob/imd.h deleted file mode 100644 index 27d95cd579..0000000000 --- a/engines/gob/imd.h +++ /dev/null @@ -1,143 +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_IMD_H -#define GOB_IMD_H - -#include "gob/video.h" -#include "gob/sound.h" - -namespace Gob { - -class ImdPlayer { -public: - -#include "common/pack-start.h" // START STRUCT PACKING - - struct ImdCoord { - int16 left; - int16 top; - int16 right; - int16 bottom; - } PACKED_STRUCT; - - struct Imd { - int16 handle; - int16 verMin; - int16 framesCount; - int16 x; - int16 y; - int16 width; - int16 height; - int16 field_E; - int16 curFrame; - Video::Color *palette; - SurfaceDesc *surfDesc; - int32 *framesPos; - int32 firstFramePos; - int16 stdX; - int16 stdY; - int16 stdWidth; - int16 stdHeight; - ImdCoord *frameCoords; - int32 frameDataSize; - int32 vidBufferSize; - Video::Color *extraPalette; - } PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING - - Imd *_curImd; - byte _frontSurf; - int8 _backSurf; - byte *_frontMem; - int32 _frameDelay; - - uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing) - - ImdPlayer(GobEngine *vm); - virtual ~ImdPlayer(); - - Imd *loadImdFile(const char *path, SurfaceDesc *surfDesc, int8 flags); - void finishImd(Imd *&imdPtr); - - int8 openImd(const char *path, int16 x, int16 y, - int16 startFrame, int16 flags); - void closeImd(void); - - void play(int16 frame, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 lastFrame); - void play(const char *path, int16 x, int16 y, bool interruptible); - void play(const char *path, int16 x, int16 y, int16 startFrame, - int16 frames, bool fade, bool interruptible); - -protected: - char _curFile[18]; - - int16 _curX; - int16 _curY; - int16 _left; - int16 _top; - int16 _right; - int16 _bottom; - - byte *_frameData; - byte *_vidBuffer; - - bool _noSound; - - uint32 _soundStartTime; - uint32 _skipFrames; - - int16 _soundFreq; - uint16 _soundSliceSize; - int16 _soundSlicesCount; - uint16 _soundSliceLength; - - Audio::AppendableAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - - GobEngine *_vm; - - void copyPalette(int16 palStart, int16 palEnd); - void flipFrontMem(); - void drawFrame(int16 frame); - void setXY(Imd *imdPtr, int16 x, int16 y); - - void seekFrame(Imd *imdPtr, int16 frame, int16 from, bool restart = false); - uint16 checkFrameType(Imd *imdPtr, int16 frame); - void drawFrame(Imd *imdPtr, int16 frame, int16 x, int16 y, - SurfaceDesc *dest = 0); - - uint32 view(ImdPlayer::Imd *imdPtr, int16 arg_4); - void renderFrame(Imd *imdPtr); - void frameUncompressor(byte *dest, byte *src); - - void waitEndSoundSlice(); -}; - -} // End of namespace Gob - -#endif // GOB_IMD_H diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index 2f1dbe5326..4712a19a5d 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -37,7 +37,7 @@ #include "gob/palanim.h" #include "gob/sound.h" #include "gob/video.h" -#include "gob/imd.h" +#include "gob/videoplayer.h" namespace Gob { @@ -147,10 +147,12 @@ void Init::initGame(const char *totName) { handle = _vm->_dataIO->openData(buffer); if (handle >= 0) { - // Get variables count - _vm->_dataIO->seekData(handle, 0x2C, SEEK_SET); - varsCount = _vm->_dataIO->readUint16(handle); - _vm->_dataIO->closeData(handle); + DataStream *stream = _vm->_dataIO->openAsStream(handle, true); + + stream->seek(0x2C); + varsCount = stream->readUint16LE(); + + delete stream; _vm->_global->_inter_variables = new byte[varsCount * 4]; _vm->_global->_inter_variablesSizes = new byte[varsCount * 4]; @@ -167,14 +169,23 @@ void Init::initGame(const char *totName) { _vm->_dataIO->closeData(imdHandle); _vm->_draw->initScreen(); _vm->_draw->_cursorIndex = -1; + _vm->_util->longDelay(200); // Letting everything settle - _vm->_imdPlayer->play("coktel", -1, -1, true); + + if (_vm->_vidPlayer->openVideo("coktel.imd")) { + _vm->_vidPlayer->play(); + _vm->_vidPlayer->closeVideo(); + } + _vm->_draw->closeScreen(); } else if ((imdHandle = _vm->_dataIO->openData("coktel.clt")) >= 0) { _vm->_draw->initScreen(); + + stream = _vm->_dataIO->openAsStream(imdHandle, true); _vm->_util->clearPalette(); - _vm->_dataIO->readData(imdHandle, (byte *) _vm->_draw->_vgaPalette, 768); - _vm->_dataIO->closeData(imdHandle); + stream->read((byte *) _vm->_draw->_vgaPalette, 768); + delete stream; + imdHandle = _vm->_dataIO->openData("coktel.ims"); if (imdHandle >= 0) { byte *sprBuf; diff --git a/engines/gob/inter.cpp b/engines/gob/inter.cpp index 1f529b7634..4da3746681 100644 --- a/engines/gob/inter.cpp +++ b/engines/gob/inter.cpp @@ -209,7 +209,7 @@ void Inter::funcBlock(int16 retFlag) { // WORKAROUND: // The EGA version of gob1 doesn't add a delay after showing // images between levels. We manually add it here. - if ((_vm->_features & GF_GOB1) && (_vm->_features & GF_EGA)) { + if ((_vm->getGameType() == kGameTypeGob1) && _vm->isEGA()) { int addr = _vm->_global->_inter_execPtr-_vm->_game->_totFileData; if ((startaddr == 0x18B4 && addr == 0x1A7F && // Zombie !strncmp(_vm->_game->_curTotFile, "avt005.tot", 10)) || diff --git a/engines/gob/inter.h b/engines/gob/inter.h index fe84741eed..a7317492ad 100644 --- a/engines/gob/inter.h +++ b/engines/gob/inter.h @@ -342,6 +342,7 @@ protected: virtual void checkSwitchTable(byte **ppExec); void o2_playMult(); + void o2_freeMultKeys(); void o2_setRenderFlags(); void o2_multSub(); void o2_initMult(); @@ -378,6 +379,8 @@ protected: bool o2_evaluateStore(OpFuncParams ¶ms); bool o2_printText(OpFuncParams ¶ms); bool o2_animPalInit(OpFuncParams ¶ms); + bool o2_addCollision(OpFuncParams ¶ms); + bool o2_freeCollision(OpFuncParams ¶ms); bool o2_goblinFunc(OpFuncParams ¶ms); bool o2_createSprite(OpFuncParams ¶ms); bool o2_stopSound(OpFuncParams ¶ms); @@ -478,6 +481,45 @@ protected: bool o3_checkData(OpFuncParams ¶ms); bool o3_readData(OpFuncParams ¶ms); bool o3_writeData(OpFuncParams ¶ms); + + void o3_wobble(OpGobParams ¶ms); +}; + +class Inter_v4 : public Inter_v3 { +public: + Inter_v4(GobEngine *vm); + virtual ~Inter_v4() {} + +protected: + typedef void (Inter_v4::*OpcodeDrawProcV4)(); + typedef bool (Inter_v4::*OpcodeFuncProcV4)(OpFuncParams &); + typedef void (Inter_v4::*OpcodeGoblinProcV4)(OpGobParams &); + struct OpcodeDrawEntryV4 { + OpcodeDrawProcV4 proc; + const char *desc; + }; + struct OpcodeFuncEntryV4 { + OpcodeFuncProcV4 proc; + const char *desc; + }; + struct OpcodeGoblinEntryV4 { + OpcodeGoblinProcV4 proc; + const char *desc; + }; + const OpcodeDrawEntryV4 *_opcodesDrawV4; + const OpcodeFuncEntryV4 *_opcodesFuncV4; + const OpcodeGoblinEntryV4 *_opcodesGoblinV4; + static const int _goblinFuncLookUp[][2]; + + virtual void setupOpcodes(); + virtual void executeDrawOpcode(byte i); + virtual bool executeFuncOpcode(byte i, byte j, OpFuncParams ¶ms); + virtual void executeGoblinOpcode(int i, OpGobParams ¶ms); + virtual const char *getOpcodeDrawDesc(byte i); + virtual const char *getOpcodeFuncDesc(byte i, byte j); + virtual const char *getOpcodeGoblinDesc(int i); + + void o4_playVmdOrMusic(); }; } // End of namespace Gob diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index ffbe9e45ea..492ea198a1 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -33,10 +33,10 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/imd.h" #include "gob/palanim.h" #include "gob/sound.h" #include "gob/video.h" +#include "gob/videoplayer.h" namespace Gob { @@ -717,11 +717,17 @@ const char *Inter_Bargon::getOpcodeGoblinDesc(int i) { } void Inter_Bargon::oBargon_intro0(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scaa", 0, 160, 0, 92, 0, 1); + if (_vm->_vidPlayer->openVideo("scaa", 0, 160)) { + _vm->_vidPlayer->play(0, 92, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro1(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scaa", 0, 160, 0, -23, 1, 1); + if (_vm->_vidPlayer->openVideo("scaa", 0, 160)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0, 0, 0, true, 23); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { @@ -813,27 +819,45 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { } void Inter_Bargon::oBargon_intro4(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scba", 191, 54, 0, 0, 1, 1); + if (_vm->_vidPlayer->openVideo("scba", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0, 0, 0, true); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro5(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbb", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbb", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro6(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbc", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbc", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro7(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbf", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbf", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro8(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbc", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbc", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro9(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbd", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbd", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } } // End of namespace Gob diff --git a/engines/gob/inter_v1.cpp b/engines/gob/inter_v1.cpp index a3277047e7..9f30d9dea2 100644 --- a/engines/gob/inter_v1.cpp +++ b/engines/gob/inter_v1.cpp @@ -1136,13 +1136,13 @@ bool Inter_v1::o1_callSub(OpFuncParams ¶ms) { } // Skipping the copy protection screen in Gobliiins - if (!_vm->_copyProtection && (_vm->_features & GF_GOB1) && (offset == 3905) + if (!_vm->_copyProtection && (_vm->getGameType() == kGameTypeGob1) && (offset == 3905) && !scumm_stricmp(_vm->_game->_curTotFile, _vm->_startTot)) { debugC(2, kDebugGameFlow, "Skipping copy protection screen"); return false; } // Skipping the copy protection screen in Gobliins 2 - if (!_vm->_copyProtection && (_vm->_features & GF_GOB2) && (offset == 1746) + if (!_vm->_copyProtection && (_vm->getGameType() == kGameTypeGob2) && (offset == 1746) && !scumm_stricmp(_vm->_game->_curTotFile, _vm->_startTot0)) { debugC(2, kDebugGameFlow, "Skipping copy protection screen"); return false; @@ -1174,6 +1174,10 @@ bool Inter_v1::o1_loadCursor(OpFuncParams ¶ms) { id = load16(); index = (int8) *_vm->_global->_inter_execPtr++; + + if ((index * _vm->_draw->_cursorWidth) >= _vm->_draw->_cursorSprites->getWidth()) + return false; + itemPtr = &_vm->_game->_totResourceTable->items[id]; offset = itemPtr->offset; @@ -1613,7 +1617,7 @@ bool Inter_v1::o1_palLoad(OpFuncParams ¶ms) { _vm->_global->_pPaletteDesc->unused1 = _vm->_draw->_unusedPalette1; if (_vm->_global->_videoMode < 0x13) { - _vm->_global->_pPaletteDesc->vgaPal = _vm->_draw->_vgaSmallPalette; + _vm->_global->_pPaletteDesc->vgaPal = _vm->_draw->_vgaPalette; _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0); return false; } @@ -1650,8 +1654,9 @@ bool Inter_v1::o1_keyFunc(OpFuncParams ¶ms) { // WORKAROUND for bug #1726130: Ween busy-waits in the intro for a counter // to become 5000. We deliberately slow down busy-waiting, so we shorten // the counting, too. - if (((_vm->_global->_inter_execPtr - _vm->_game->_totFileData) == 729) && - (VAR(59) < 4000) && !scumm_stricmp(_vm->_game->_curTotFile, "intro5.tot")) + if ((_vm->getGameType() == kGameTypeWeen) && (VAR(59) < 4000) && + ((_vm->_global->_inter_execPtr - _vm->_game->_totFileData) == 729) && + !scumm_stricmp(_vm->_game->_curTotFile, "intro5.tot")) WRITE_VAR(59, 4000); switch (cmd) { @@ -1700,6 +1705,10 @@ bool Inter_v1::o1_capturePush(OpFuncParams ¶ms) { top = _vm->_parse->parseValExpr(); width = _vm->_parse->parseValExpr(); height = _vm->_parse->parseValExpr(); + + if ((width < 0) || (height < 0)) + return false; + _vm->_game->capturePush(left, top, width, height); (*_vm->_scenery->_pCaptureCounter)++; return false; @@ -1887,7 +1896,9 @@ bool Inter_v1::o1_copySprite(OpFuncParams ¶ms) { } bool Inter_v1::o1_fillRect(OpFuncParams ¶ms) { - _vm->_draw->_destSurface = load16(); + int16 destSurf; + + _vm->_draw->_destSurface = destSurf = load16(); _vm->_draw->_destSpriteX = _vm->_parse->parseValExpr(); _vm->_draw->_destSpriteY = _vm->_parse->parseValExpr(); @@ -1895,6 +1906,19 @@ bool Inter_v1::o1_fillRect(OpFuncParams ¶ms) { _vm->_draw->_spriteBottom = _vm->_parse->parseValExpr(); _vm->_draw->_backColor = _vm->_parse->parseValExpr(); + + if (!_vm->_draw->_spritesArray[(destSurf > 100) ? (destSurf - 80) : destSurf]) + return false; + + if (_vm->_draw->_spriteRight < 0) { + _vm->_draw->_destSpriteX += _vm->_draw->_spriteRight - 1; + _vm->_draw->_spriteRight = -_vm->_draw->_spriteRight + 2; + } + if (_vm->_draw->_spriteBottom < 0) { + _vm->_draw->_destSpriteY += _vm->_draw->_spriteBottom - 1; + _vm->_draw->_spriteBottom = -_vm->_draw->_spriteBottom + 2; + } + _vm->_draw->spriteOperation(DRAW_FILLRECT); return false; } @@ -2201,22 +2225,23 @@ bool Inter_v1::o1_readData(OpFuncParams ¶ms) { WRITE_VAR(1, 1); handle = _vm->_dataIO->openData(_vm->_global->_inter_resStr); if (handle >= 0) { + DataStream *stream = _vm->_dataIO->openAsStream(handle, true); + _vm->_draw->animateCursor(4); if (offset < 0) - _vm->_dataIO->seekData(handle, -offset - 1, SEEK_END); + stream->seek(-offset - 1, SEEK_END); else - _vm->_dataIO->seekData(handle, offset, SEEK_SET); + stream->seek(offset); if (((dataVar >> 2) == 59) && (size == 4)) - WRITE_VAR(59, _vm->_dataIO->readUint32(handle)); + WRITE_VAR(59, stream->readUint32LE()); else - retSize = _vm->_dataIO->readData(handle, - _vm->_global->_inter_variables + dataVar, size); - - _vm->_dataIO->closeData(handle); + retSize = stream->read(_vm->_global->_inter_variables + dataVar, size); if (retSize == size) WRITE_VAR(1, 0); + + delete stream; } if (_vm->_game->_extHandle >= 0) diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index d69b6fda97..376aef75d9 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -38,7 +38,6 @@ #include "gob/draw.h" #include "gob/game.h" #include "gob/goblin.h" -#include "gob/imd.h" #include "gob/map.h" #include "gob/mult.h" #include "gob/parse.h" @@ -46,6 +45,7 @@ #include "gob/sound.h" #include "gob/video.h" #include "gob/saveload.h" +#include "gob/videoplayer.h" namespace Gob { @@ -134,7 +134,7 @@ void Inter_v2::setupOpcodes() { /* 00 */ OPCODE(o1_loadMult), OPCODE(o2_playMult), - OPCODE(o1_freeMultKeys), + OPCODE(o2_freeMultKeys), {NULL, ""}, /* 04 */ {NULL, ""}, @@ -485,8 +485,8 @@ void Inter_v2::setupOpcodes() { OPCODE(o1_capturePop), OPCODE(o2_animPalInit), /* 18 */ - {NULL, ""}, - {NULL, ""}, + OPCODE(o2_addCollision), + OPCODE(o2_freeCollision), {NULL, ""}, {NULL, ""}, /* 1C */ @@ -826,6 +826,17 @@ void Inter_v2::o2_playMult() { _vm->_mult->playMult(VAR(57), -1, checkEscape & 0x1, 0); } +void Inter_v2::o2_freeMultKeys() { + uint16 index = load16(); + + if (!_vm->_mult->hasMultData(index)) + return; + + _vm->_mult->setMultData(index); + _vm->_mult->freeMultKeys(); + _vm->_mult->zeroMultData(index); +} + void Inter_v2::o2_setRenderFlags() { int16 expr; @@ -1364,11 +1375,37 @@ void Inter_v2::o2_initScreen() { width = _vm->_parse->parseValExpr(); height = _vm->_parse->parseValExpr(); + // Lost in Time switches to 640x400x16 when showing the title screen + if (_vm->getGameType() == kGameTypeLostInTime) { + if (videoMode == 0x10) { + width = _vm->_width = 640; + height = _vm->_height = 400; + _vm->_global->_colorCount = 16; + _vm->_system->beginGFXTransaction(); + _vm->_system->initSize(_vm->_width, _vm->_height); + _vm->initCommonGFX(true); + _vm->_system->endGFXTransaction(); + } else if (_vm->_global->_videoMode == 0x10) { + if (width == -1) + width = 320; + if (height == -1) + height = 200; + + _vm->_width = 320; + _vm->_height = 200; + _vm->_global->_colorCount = 256; + _vm->_system->beginGFXTransaction(); + _vm->_system->initSize(_vm->_width, _vm->_height); + _vm->initCommonGFX(false); + _vm->_system->endGFXTransaction(); + } + } + _vm->_global->_fakeVideoMode = videoMode; // Some versions require this if (videoMode == 0xD) - videoMode = 0x14; + videoMode = _vm->_mode; if ((videoMode == _vm->_global->_videoMode) && (width == -1)) return; @@ -1378,7 +1415,8 @@ void Inter_v2::o2_initScreen() { if (height > 0) _vm->_video->_surfHeight = height; - _vm->_video->_splitHeight1 = MIN(200, _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; @@ -1414,13 +1452,13 @@ void Inter_v2::o2_scroll() { int16 curY; startX = CLIP((int) _vm->_parse->parseValExpr(), 0, - _vm->_video->_surfWidth - 320); + _vm->_video->_surfWidth - _vm->_width); startY = CLIP((int) _vm->_parse->parseValExpr(), 0, - _vm->_video->_surfHeight - 200); + _vm->_video->_surfHeight - _vm->_height); endX = CLIP((int) _vm->_parse->parseValExpr(), 0, - _vm->_video->_surfWidth - 320); + _vm->_video->_surfWidth - _vm->_width); endY = CLIP((int) _vm->_parse->parseValExpr(), 0, - _vm->_video->_surfHeight - 200); + _vm->_video->_surfHeight - _vm->_height); stepX = _vm->_parse->parseValExpr(); stepY = _vm->_parse->parseValExpr(); @@ -1481,48 +1519,28 @@ void Inter_v2::o2_playImd() { palEnd = _vm->_parse->parseValExpr(); palCmd = 1 << (flags & 0x3F); - if (!_vm->_imdPlayer->openImd(imd, x, y, startFrame, flags)) { + if ((imd[0] != 0) && !_vm->_vidPlayer->openVideo(imd, x, y, flags)) { WRITE_VAR(11, -1); return; } close = (lastFrame == -1); - if (lastFrame < 0) - lastFrame = _vm->_imdPlayer->_curImd->framesCount - 1; if (startFrame == -2) { startFrame = lastFrame = 0; close = false; } - _vm->_game->_preventScroll = true; - for (int i = startFrame; i <= lastFrame; i++) { - _vm->_imdPlayer->play(i, palCmd, palStart, palEnd, 0, lastFrame); - WRITE_VAR(11, i); - - if (_vm->_quitRequested) - break; - - if (breakKey != 0) { - _vm->_util->getMouseState(&_vm->_global->_inter_mouseX, - &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons); - - storeKey(_vm->_util->checkKey()); - if (VAR(0) == (unsigned) breakKey) { - if (_vm->_imdPlayer->_soundStage == 2) - _vm->_snd->stopSound(0); - _vm->_game->_preventScroll = false; - return; - } - } + if (startFrame >= 0) { + _vm->_game->_preventScroll = true; + _vm->_vidPlayer->play(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + _vm->_game->_preventScroll = false; } - _vm->_game->_preventScroll = false; if (close) - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); } void Inter_v2::o2_getImdInfo() { - ImdPlayer::Imd *imd; int16 varX, varY; int16 varFrames; int16 varWidth, varHeight; @@ -1533,21 +1551,9 @@ void Inter_v2::o2_getImdInfo() { varFrames = _vm->_parse->parseVarIndex(); varWidth = _vm->_parse->parseVarIndex(); varHeight = _vm->_parse->parseVarIndex(); - imd = _vm->_imdPlayer->loadImdFile(_vm->_global->_inter_resStr, 0, 2); - if (!imd) { - 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); - } else { - WRITE_VAR_OFFSET(varX, imd->x); - WRITE_VAR_OFFSET(varY, imd->y); - WRITE_VAR_OFFSET(varFrames, imd->framesCount); - WRITE_VAR_OFFSET(varWidth, imd->width); - WRITE_VAR_OFFSET(varHeight, imd->height); - } - _vm->_imdPlayer->finishImd(imd); + + _vm->_vidPlayer->writeVideoInfo(_vm->_global->_inter_resStr, varX, varY, + varFrames, varWidth, varHeight); } void Inter_v2::o2_openItk() { @@ -1565,21 +1571,9 @@ void Inter_v2::o2_closeItk() { } void Inter_v2::o2_setImdFrontSurf() { - _vm->_imdPlayer->_frontSurf = 21; - if (_vm->_global->_videoMode == 0x14) { - _vm->_imdPlayer->_frontMem = _vm->_draw->_frontSurface->getVidMem(); - _vm->_draw->blitInvalidated(); - _vm->_imdPlayer->_frontSurf = 20; - } } void Inter_v2::o2_resetImdFrontSurf() { - _vm->_imdPlayer->_frontSurf = 21; - if (_vm->_imdPlayer->_frontMem) { - _vm->_imdPlayer->_frontMem = _vm->_draw->_frontSurface->getVidMem(); - _vm->_draw->forceBlit(); - } else - _vm->_draw->forceBlit(true); } bool Inter_v2::o2_evaluateStore(OpFuncParams ¶ms) { @@ -1721,6 +1715,71 @@ bool Inter_v2::o2_animPalInit(OpFuncParams ¶ms) { return false; } +bool Inter_v2::o2_addCollision(OpFuncParams ¶ms) { + int16 id; + int16 left, top, width, height; + int16 flags; + int16 key; + int16 funcSub; + + id = _vm->_parse->parseValExpr(); + funcSub = _vm->_global->_inter_execPtr - _vm->_game->_totFileData; + left = _vm->_parse->parseValExpr(); + top = _vm->_parse->parseValExpr(); + width = _vm->_parse->parseValExpr(); + height = _vm->_parse->parseValExpr(); + flags = _vm->_parse->parseValExpr(); + key = load16(); + + if (key == 0) + key = ABS(id) + 41960; + + _vm->_draw->adjustCoords(0, &left, &top); + _vm->_draw->adjustCoords(2, &width, &height); + + if (left < 0) { + width += left; + left = 0; + } + + if (top < 0) { + height += top; + top = 0; + } + + int16 index; + if (id < 0) + index = _vm->_game->addNewCollision(0xD000 - id, left & 0xFFFC, top & 0xFFFC, + left + width + 3, top + height + 3, flags, key, 0, 0); + else + index = _vm->_game->addNewCollision(0xE000 + id, left, top, + left + width - 1, top + height - 1, flags, key, 0, 0); + + _vm->_game->_collisionAreas[index].funcSub = funcSub; + + return false; +} + +bool Inter_v2::o2_freeCollision(OpFuncParams ¶ms) { + int16 id; + + id = _vm->_parse->parseValExpr(); + if (id == -2) { + for (int i = 0; i < 150; i++) { + if ((_vm->_game->_collisionAreas[i].id & 0xF000) == 0xD000) + _vm->_game->_collisionAreas[i].left = 0xFFFF; + } + } else if (id == -1) { + for (int i = 0; i < 150; i++) { + if ((_vm->_game->_collisionAreas[i].id & 0xF000) == 0xE000) + _vm->_game->_collisionAreas[i].left = 0xFFFF; + } + } else + _vm->_game->freeCollision(0xE000 + id); + + return false; +} + bool Inter_v2::o2_goblinFunc(OpFuncParams ¶ms) { OpGobParams gobParams; int16 cmd; @@ -1870,25 +1929,27 @@ bool Inter_v2::o2_readData(OpFuncParams ¶ms) { if (handle < 0) return false; + DataStream *stream = _vm->_dataIO->openAsStream(handle, true); + _vm->_draw->animateCursor(4); if (offset < 0) - _vm->_dataIO->seekData(handle, -offset - 1, SEEK_END); + stream->seek(-offset - 1, SEEK_END); else - _vm->_dataIO->seekData(handle, offset, SEEK_SET); + stream->seek(offset); if (((dataVar >> 2) == 59) && (size == 4)) { - WRITE_VAR(59, _vm->_dataIO->readUint32(handle)); + 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)) WRITE_VAR(59, SWAP_BYTES_32(VAR(59))); } else - retSize = _vm->_dataIO->readData(handle, buf, size); + retSize = stream->read(buf, size); if (retSize == size) WRITE_VAR(1, 0); - _vm->_dataIO->closeData(handle); + delete stream; return false; } diff --git a/engines/gob/inter_v3.cpp b/engines/gob/inter_v3.cpp index d3389f2671..51413c839a 100644 --- a/engines/gob/inter_v3.cpp +++ b/engines/gob/inter_v3.cpp @@ -122,7 +122,7 @@ void Inter_v3::setupOpcodes() { /* 00 */ OPCODE(o1_loadMult), OPCODE(o2_playMult), - OPCODE(o1_freeMultKeys), + OPCODE(o2_freeMultKeys), {NULL, ""}, /* 04 */ {NULL, ""}, @@ -473,8 +473,8 @@ void Inter_v3::setupOpcodes() { OPCODE(o1_capturePop), OPCODE(o2_animPalInit), /* 18 */ - {NULL, ""}, - {NULL, ""}, + OPCODE(o2_addCollision), + OPCODE(o2_freeCollision), OPCODE(o3_getTotTextItemPart), {NULL, ""}, /* 1C */ @@ -594,7 +594,7 @@ void Inter_v3::setupOpcodes() { {NULL, ""}, {NULL, ""}, {NULL, ""}, - OPCODE(o2_handleGoblins), + OPCODE(o3_wobble), /* 28 */ {NULL, ""}, {NULL, ""}, @@ -894,4 +894,8 @@ bool Inter_v3::o3_copySprite(OpFuncParams ¶ms) { return false; } +void Inter_v3::o3_wobble(OpGobParams ¶ms) { + _vm->_draw->wobble(_vm->_draw->_backSurface); +} + } // End of namespace Gob diff --git a/engines/gob/inter_v4.cpp b/engines/gob/inter_v4.cpp new file mode 100644 index 0000000000..81f53757a3 --- /dev/null +++ b/engines/gob/inter_v4.cpp @@ -0,0 +1,786 @@ +/* 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/stdafx.h" +#include "common/endian.h" +#include "common/file.h" + +#include "gob/gob.h" +#include "gob/inter.h" +#include "gob/global.h" +#include "gob/game.h" +#include "gob/parse.h" +#include "gob/videoplayer.h" + +namespace Gob { + +#define OPCODE(x) _OPCODE(Inter_v4, x) + +const int Inter_v4::_goblinFuncLookUp[][2] = { + {0, 0}, + {1, 1}, + {2, 2}, + {4, 3}, + {5, 4}, + {6, 5}, + {7, 6}, + {8, 7}, + {9, 8}, + {10, 9}, + {12, 10}, + {13, 11}, + {14, 12}, + {15, 13}, + {16, 14}, + {21, 15}, + {22, 16}, + {23, 17}, + {24, 18}, + {25, 19}, + {26, 20}, + {27, 21}, + {28, 22}, + {29, 23}, + {30, 24}, + {32, 25}, + {33, 26}, + {34, 27}, + {35, 28}, + {36, 29}, + {37, 30}, + {40, 31}, + {41, 32}, + {42, 33}, + {43, 34}, + {44, 35}, + {50, 36}, + {52, 37}, + {53, 38}, + {100, 39}, + {152, 40}, + {200, 41}, + {201, 42}, + {202, 43}, + {203, 44}, + {204, 45}, + {250, 46}, + {251, 47}, + {252, 48}, + {500, 49}, + {502, 50}, + {503, 51}, + {600, 52}, + {601, 53}, + {602, 54}, + {603, 55}, + {604, 56}, + {605, 57}, + {1000, 58}, + {1001, 59}, + {1002, 60}, + {1003, 61}, + {1004, 62}, + {1005, 63}, + {1006, 64}, + {1008, 65}, + {1009, 66}, + {1010, 67}, + {1011, 68}, + {1015, 69}, + {2005, 70} +}; + +Inter_v4::Inter_v4(GobEngine *vm) : Inter_v3(vm) { + setupOpcodes(); +} + +void Inter_v4::setupOpcodes() { + static const OpcodeDrawEntryV4 opcodesDraw[256] = { + /* 00 */ + OPCODE(o1_loadMult), + OPCODE(o2_playMult), + OPCODE(o2_freeMultKeys), + {NULL, ""}, + /* 04 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_initCursor), + /* 08 */ + OPCODE(o1_initCursorAnim), + OPCODE(o1_clearCursorAnim), + OPCODE(o2_setRenderFlags), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + OPCODE(o1_loadAnim), + OPCODE(o1_freeAnim), + OPCODE(o1_updateAnim), + OPCODE(o2_multSub), + /* 14 */ + OPCODE(o2_initMult), + OPCODE(o1_freeMult), + OPCODE(o1_animate), + OPCODE(o2_loadMultObject), + /* 18 */ + OPCODE(o1_getAnimLayerInfo), + OPCODE(o1_getObjAnimSize), + OPCODE(o1_loadStatic), + OPCODE(o1_freeStatic), + /* 1C */ + OPCODE(o2_renderStatic), + OPCODE(o2_loadCurLayer), + {NULL, ""}, + {NULL, ""}, + /* 20 */ + OPCODE(o2_playCDTrack), + OPCODE(o2_waitCDTrackEnd), + OPCODE(o2_stopCD), + OPCODE(o2_readLIC), + /* 24 */ + OPCODE(o2_freeLIC), + OPCODE(o2_getCDTrackPos), + {NULL, ""}, + {NULL, ""}, + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o2_loadFontToSprite), + OPCODE(o1_freeFontToSprite), + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + OPCODE(o2_totSub), + OPCODE(o2_switchTotSub), + OPCODE(o2_copyVars), + OPCODE(o2_pasteVars), + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 48 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 4C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 50 */ + OPCODE(o2_loadMapObjects), + OPCODE(o2_freeGoblins), + OPCODE(o2_moveGoblin), + OPCODE(o2_writeGoblinPos), + /* 54 */ + OPCODE(o2_stopGoblin), + OPCODE(o2_setGoblinState), + OPCODE(o2_placeGoblin), + {NULL, ""}, + /* 58 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 5C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 60 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 64 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 68 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 6C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 70 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 74 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 78 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 7C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 80 */ + OPCODE(o2_initScreen), + OPCODE(o2_scroll), + OPCODE(o2_setScrollOffset), + OPCODE(o4_playVmdOrMusic), + /* 84 */ + OPCODE(o2_getImdInfo), + OPCODE(o2_openItk), + OPCODE(o2_closeItk), + OPCODE(o2_setImdFrontSurf), + /* 88 */ + OPCODE(o2_resetImdFrontSurf), + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 8C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 90 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 94 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 98 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 9C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* A8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* AC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* B8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* BC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* C8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* CC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* D8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* DC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* E8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* EC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F0 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F4 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* F8 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* FC */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""} + }; + + static const OpcodeFuncEntryV4 opcodesFunc[80] = { + /* 00 */ + OPCODE(o1_callSub), + OPCODE(o1_callSub), + OPCODE(o1_printTotText), + OPCODE(o1_loadCursor), + /* 04 */ + {NULL, ""}, + OPCODE(o1_switch), + OPCODE(o1_repeatUntil), + OPCODE(o1_whileDo), + /* 08 */ + OPCODE(o1_if), + OPCODE(o2_evaluateStore), + OPCODE(o1_loadSpriteToPos), + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + {NULL, ""}, + OPCODE(o2_printText), + OPCODE(o1_loadTot), + OPCODE(o1_palLoad), + /* 14 */ + OPCODE(o1_keyFunc), + OPCODE(o1_capturePush), + OPCODE(o1_capturePop), + OPCODE(o2_animPalInit), + /* 18 */ + OPCODE(o2_addCollision), + OPCODE(o2_freeCollision), + OPCODE(o3_getTotTextItemPart), + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + OPCODE(o1_drawOperations), + OPCODE(o1_setcmdCount), + /* 20 */ + OPCODE(o1_return), + OPCODE(o1_renewTimeInVars), + OPCODE(o1_speakerOn), + OPCODE(o1_speakerOff), + /* 24 */ + OPCODE(o1_putPixel), + OPCODE(o2_goblinFunc), + OPCODE(o2_createSprite), + OPCODE(o1_freeSprite), + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + OPCODE(o1_returnTo), + OPCODE(o1_loadSpriteContent), + OPCODE(o3_copySprite), + OPCODE(o1_fillRect), + /* 34 */ + OPCODE(o1_drawLine), + OPCODE(o1_strToLong), + OPCODE(o1_invalidate), + OPCODE(o1_setBackDelta), + /* 38 */ + OPCODE(o1_playSound), + OPCODE(o2_stopSound), + OPCODE(o2_loadSound), + OPCODE(o1_freeSoundSlot), + /* 3C */ + OPCODE(o1_waitEndPlay), + OPCODE(o1_playComposition), + OPCODE(o2_getFreeMem), + OPCODE(o2_checkData), + /* 40 */ + {NULL, ""}, + OPCODE(o1_prepareStr), + OPCODE(o1_insertStr), + OPCODE(o1_cutStr), + /* 44 */ + OPCODE(o1_strstr), + OPCODE(o1_istrlen), + OPCODE(o1_setMousePos), + OPCODE(o1_setFrameRate), + /* 48 */ + OPCODE(o1_animatePalette), + OPCODE(o1_animateCursor), + OPCODE(o1_blitCursor), + OPCODE(o1_loadFont), + /* 4C */ + OPCODE(o1_freeFont), + OPCODE(o2_readData), + OPCODE(o2_writeData), + OPCODE(o1_manageDataFile), + }; + + static const OpcodeGoblinEntryV4 opcodesGoblin[71] = { + /* 00 */ + OPCODE(o2_loadInfogramesIns), + OPCODE(o2_startInfogrames), + OPCODE(o2_stopInfogrames), + {NULL, ""}, + /* 04 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 08 */ + {NULL, ""}, + OPCODE(o2_playInfogrames), + {NULL, ""}, + {NULL, ""}, + /* 0C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 10 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 14 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 18 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 1C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 20 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 24 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + OPCODE(o2_handleGoblins), + /* 28 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 2C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 30 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 34 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 38 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 3C */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 40 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + /* 44 */ + {NULL, ""}, + {NULL, ""}, + {NULL, ""}, + }; + + _opcodesDrawV4 = opcodesDraw; + _opcodesFuncV4 = opcodesFunc; + _opcodesGoblinV4 = opcodesGoblin; +} + +void Inter_v4::executeDrawOpcode(byte i) { + debugC(1, kDebugDrawOp, "opcodeDraw %d [0x%X] (%s)", + i, i, getOpcodeDrawDesc(i)); + + OpcodeDrawProcV4 op = _opcodesDrawV4[i].proc; + + if (op == NULL) + warning("unimplemented opcodeDraw: %d", i); + else + (this->*op) (); +} + +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)); + + if ((i > 4) || (j > 15)) { + warning("unimplemented opcodeFunc: %d.%d", i, j); + return false; + } + + OpcodeFuncProcV4 op = _opcodesFuncV4[i*16 + j].proc; + + if (op == NULL) + warning("unimplemented opcodeFunc: %d.%d", i, j); + else + return (this->*op) (params); + + return false; +} + +void Inter_v4::executeGoblinOpcode(int i, OpGobParams ¶ms) { + debugC(1, kDebugGobOp, "opcodeGoblin %d [0x%X] (%s)", + i, i, getOpcodeGoblinDesc(i)); + + OpcodeGoblinProcV4 op = NULL; + + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) { + op = _opcodesGoblinV4[_goblinFuncLookUp[j][1]].proc; + break; + } + + if (op == NULL) { + int16 val; + + _vm->_global->_inter_execPtr -= 2; + val = load16(); + _vm->_global->_inter_execPtr += val << 1; + } else + (this->*op) (params); +} + +const char *Inter_v4::getOpcodeDrawDesc(byte i) { + return _opcodesDrawV4[i].desc; +} + +const char *Inter_v4::getOpcodeFuncDesc(byte i, byte j) { + if ((i > 4) || (j > 15)) + return ""; + + return _opcodesFuncV4[i*16 + j].desc; +} + +const char *Inter_v4::getOpcodeGoblinDesc(int i) { + for (int j = 0; j < ARRAYSIZE(_goblinFuncLookUp); j++) + if (_goblinFuncLookUp[j][0] == i) + return _opcodesGoblinV4[_goblinFuncLookUp[j][1]].desc; + return ""; +} + +void Inter_v4::o4_playVmdOrMusic() { + char fileName[128]; + int16 x, y; + int16 startFrame; + int16 lastFrame; + int16 breakKey; + int16 flags; + int16 palStart; + int16 palEnd; + uint16 palCmd; + bool close; + + evalExpr(0); + _vm->_global->_inter_resStr[8] = 0; + strncpy0(fileName, _vm->_global->_inter_resStr, 127); + + x = _vm->_parse->parseValExpr(); + y = _vm->_parse->parseValExpr(); + startFrame = _vm->_parse->parseValExpr(); + lastFrame = _vm->_parse->parseValExpr(); + breakKey = _vm->_parse->parseValExpr(); + flags = _vm->_parse->parseValExpr(); + palStart = _vm->_parse->parseValExpr(); + palEnd = _vm->_parse->parseValExpr(); + palCmd = 1 << (flags & 0x3F); + + close = false; + if (lastFrame == -1) { + close = true; + } else if (lastFrame == -3) { + warning("Woodruff Stub: Video/Music command -3: Play background video %s", fileName); +// return; + } else if (lastFrame == -4) { + 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"); + return; + } else if (lastFrame == -6) { + warning("Woodruff Stub: Video/Music command -6: Load background video %s", fileName); + 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); + return; + } else if (lastFrame < 0) { + warning("Unknown Video/Music command: %d, %s", lastFrame, fileName); + return; + } + + if (startFrame == -2) { + startFrame = lastFrame = 0; + close = false; + } + + if ((fileName[0] != 0) && !_vm->_vidPlayer->openVideo(fileName, x, y, flags)) { + WRITE_VAR(11, -1); + return; + } + + if (startFrame >= 0) { + _vm->_game->_preventScroll = true; + _vm->_vidPlayer->play(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + _vm->_game->_preventScroll = false; + } + + if (close) + _vm->_vidPlayer->closeVideo(); +} + +} // End of namespace Gob diff --git a/engines/gob/map.cpp b/engines/gob/map.cpp index 3c1895d099..5485d66987 100644 --- a/engines/gob/map.cpp +++ b/engines/gob/map.cpp @@ -261,7 +261,7 @@ void Map::findNearestWalkable(int16 &gobDestX, int16 &gobDestY, int i; mapWidth = _screenWidth / _tilesWidth; - mapHeight = 200 / _tilesHeight; + mapHeight = _vm->_width / _tilesHeight; direction = 0; for (i = 1; i <= gobDestX; i++) diff --git a/engines/gob/module.mk b/engines/gob/module.mk index db0660fa5c..7571853f27 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -18,7 +18,8 @@ MODULE_OBJS := \ goblin_v1.o \ goblin_v2.o \ goblin_v3.o \ - imd.o \ + coktelvideo.o \ + videoplayer.o \ init.o \ init_v1.o \ init_v2.o \ @@ -26,8 +27,9 @@ MODULE_OBJS := \ inter.o \ inter_v1.o \ inter_v2.o \ - inter_v3.o \ inter_bargon.o \ + inter_v3.o \ + inter_v4.o \ map.o \ map_v1.o \ map_v2.o \ diff --git a/engines/gob/mult.h b/engines/gob/mult.h index edfbb682ea..16d9961f89 100644 --- a/engines/gob/mult.h +++ b/engines/gob/mult.h @@ -112,7 +112,7 @@ public: } PACKED_STRUCT; struct Mult_AnimKey { - int16 frame; + uint16 frame; int16 layer; int16 posX; int16 posY; @@ -246,8 +246,10 @@ public: virtual void loadMult(int16 resId) = 0; virtual void freeMultKeys() = 0; - virtual void setMultData(uint16 multindex) = 0; - virtual void multSub(uint16 multindex) = 0; + virtual bool hasMultData(uint16 multIndex) = 0; + virtual void setMultData(uint16 multIndex) = 0; + virtual void zeroMultData(uint16 multIndex) = 0; + virtual void multSub(uint16 multIndex) = 0; virtual void animate() = 0; Mult(GobEngine *vm); @@ -299,8 +301,10 @@ public: virtual void loadMult(int16 resId); virtual void freeMultKeys(); - virtual void setMultData(uint16 multindex); - virtual void multSub(uint16 multindex); + virtual bool hasMultData(uint16 multIndex); + virtual void setMultData(uint16 multIndex); + virtual void zeroMultData(uint16 multIndex); + virtual void multSub(uint16 multIndex); virtual void animate(); protected: @@ -317,8 +321,10 @@ public: virtual void loadMult(int16 resId); virtual void freeMultKeys(); - virtual void setMultData(uint16 multindex); - virtual void multSub(uint16 multindex); + virtual bool hasMultData(uint16 multIndex); + virtual void setMultData(uint16 multIndex); + virtual void zeroMultData(uint16 multIndex); + virtual void multSub(uint16 multIndex); virtual void animate(); protected: diff --git a/engines/gob/mult_v1.cpp b/engines/gob/mult_v1.cpp index 45ce9aa8a0..0c367870ac 100644 --- a/engines/gob/mult_v1.cpp +++ b/engines/gob/mult_v1.cpp @@ -237,11 +237,19 @@ void Mult_v1::freeMultKeys() { _multData = 0; } -void Mult_v1::setMultData(uint16 multindex) { +bool Mult_v1::hasMultData(uint16 multIndex) { error("Switching mults not supported for Gob1"); } -void Mult_v1::multSub(uint16 multindex) { +void Mult_v1::setMultData(uint16 multIndex) { + error("Switching mults not supported for Gob1"); +} + +void Mult_v1::zeroMultData(uint16 multIndex) { + error("Switching mults not supported for Gob1"); +} + +void Mult_v1::multSub(uint16 multIndex) { error("Switching mults not supported for Gob1"); } diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index f57d5ecb0c..cced4aac63 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -34,11 +34,11 @@ #include "gob/draw.h" #include "gob/game.h" #include "gob/goblin.h" -#include "gob/imd.h" #include "gob/inter.h" #include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" +#include "gob/videoplayer.h" namespace Gob { @@ -346,28 +346,42 @@ void Mult_v2::freeMultKeys() { _multData = 0; } -void Mult_v2::setMultData(uint16 multindex) { - if (multindex > 7) +bool Mult_v2::hasMultData(uint16 multIndex) { + if (multIndex > 7) error("Multindex out of range"); - debugC(4, kDebugGameFlow, "Switching to mult %d", multindex); - _multData = _multDatas[multindex]; + return _multDatas[multIndex] != 0; } -void Mult_v2::multSub(uint16 multindex) { +void Mult_v2::setMultData(uint16 multIndex) { + if (multIndex > 7) + error("Multindex out of range"); + + debugC(4, kDebugGameFlow, "Switching to mult %d", multIndex); + _multData = _multDatas[multIndex]; +} + +void Mult_v2::zeroMultData(uint16 multIndex) { + if (multIndex > 7) + error("Multindex out of range"); + + _multDatas[multIndex] = 0; +} + +void Mult_v2::multSub(uint16 multIndex) { uint16 flags; int16 expr; int16 index; int16 startFrame, stopFrame, firstFrame; - flags = multindex; - multindex = (multindex >> 12) & 0xF; + flags = multIndex; + multIndex = (multIndex >> 12) & 0xF; - if (multindex > 7) + if (multIndex > 7) error("Multindex out of range"); - debugC(4, kDebugGameFlow, "Sub mult %d", multindex); - _multData = _multDatas[multindex]; + debugC(4, kDebugGameFlow, "Sub mult %d", multIndex); + _multData = _multDatas[multIndex]; if (!_multData) { _vm->_parse->parseValExpr(); @@ -1027,7 +1041,7 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, x = y = -1; if (key.imdFile == -1) { - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); _vm->_game->_preventScroll = false; return; } @@ -1045,23 +1059,24 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, if ((lastFrame - palFrame) < startFrame) if (!(key.flags & 0x4000)) { _vm->_game->_preventScroll = false; - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); return; } - if (!_vm->_imdPlayer->openImd(imdFile, x, y, 0, flags)) { + if (!_vm->_vidPlayer->openVideo(imdFile, x, y, flags)) { _vm->_game->_preventScroll = false; return; } if (palFrame == -1) palFrame = 0; + if (lastFrame == -1) - lastFrame = _vm->_imdPlayer->_curImd->framesCount - 1; + lastFrame = _vm->_vidPlayer->getFramesCount() - 1; baseFrame = startFrame % (lastFrame - palFrame + 1); - _vm->_imdPlayer->play(baseFrame + palFrame, flags & 0x7F, - palStart, palEnd, palFrame, lastFrame); + _vm->_vidPlayer->play(baseFrame + palFrame, baseFrame + palFrame, 0, + flags & 0x7F, palStart, palEnd, palFrame, lastFrame); } void Mult_v2::advanceObjects(int16 index) { @@ -1074,13 +1089,19 @@ void Mult_v2::advanceObjects(int16 index) { return; for (int i = 0; i < 4; i++) { + int obj = _multData->animObjs[index][i]; + if (_multData->animObjs[index][i] != -1) { int keyIndex = _multData->animKeysIndices[index][i]; int count = _multData->animKeysCount[i]; for (int j = keyIndex; j < count; j++) { + + if ((obj == -1) || (obj == 1024)) + continue; + Mult_AnimKey &key = _multData->animKeys[i][j]; - Mult_Object &animObj = _objects[_multData->animObjs[index][i]]; + Mult_Object &animObj = _objects[obj]; Mult_AnimData &animData = *(animObj.pAnimData); if (key.frame > frame) @@ -1122,7 +1143,7 @@ void Mult_v2::advanceObjects(int16 index) { } } - if (_multData->animObjs[index][i] != -1) { + if (obj != -1) { int keyIndex = _multData->imdKeysIndices[index][i]; int count = _multData->imdKeysCount[i]; diff --git a/engines/gob/saveload.h b/engines/gob/saveload.h index b8c9e730dd..d7e45246ad 100644 --- a/engines/gob/saveload.h +++ b/engines/gob/saveload.h @@ -136,7 +136,8 @@ class SaveLoad_v3 : public SaveLoad_v2 { public: virtual SaveType getSaveType(const char *fileName); - SaveLoad_v3(GobEngine *vm, const char *targetName); + SaveLoad_v3(GobEngine *vm, const char *targetName, uint32 screenshotSize = 19968, + int32 indexOffset = 40, int32 screenshotOffset = 80); virtual ~SaveLoad_v3() {} protected: @@ -144,13 +145,15 @@ protected: bool _firstSizeGame; int8 _saveSlot; + uint32 _screenshotSize; + int32 _indexOffset; + int32 _screenshotOffset; + 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); diff --git a/engines/gob/saveload_v2.cpp b/engines/gob/saveload_v2.cpp index 35c3429ab6..13f23cccb6 100644 --- a/engines/gob/saveload_v2.cpp +++ b/engines/gob/saveload_v2.cpp @@ -47,6 +47,10 @@ SaveLoad_v2::SaveLoad_v2(GobEngine *vm, const char *targetName) : } 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")) diff --git a/engines/gob/saveload_v3.cpp b/engines/gob/saveload_v3.cpp index b376a8a75c..d0f791d8df 100644 --- a/engines/gob/saveload_v3.cpp +++ b/engines/gob/saveload_v3.cpp @@ -34,9 +34,14 @@ namespace Gob { -SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName) : +SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName, + uint32 screenshotSize, int32 indexOffset, int32 screenshotOffset) : SaveLoad_v2(vm, targetName) { + _screenshotSize = screenshotSize; + _indexOffset = indexOffset; + _screenshotOffset = screenshotOffset; + _saveSlot = -1; _stagesCount = 3; @@ -58,12 +63,18 @@ SaveLoad_v3::SaveLoad_v3(GobEngine *vm, const char *targetName) : } 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")) @@ -77,15 +88,11 @@ uint32 SaveLoad_v3::getSaveGameSize() { size = 1040 + (READ_LE_UINT32(_vm->_game->_totFileData + 0x2C) * 4) * 2; if (_useScreenshots) - size += 19968; + size += _screenshotSize; return size; } -int32 SaveLoad_v3::getSizeNotes() { - return -1; -} - int32 SaveLoad_v3::getSizeGame() { if (_firstSizeGame) { _firstSizeGame = false; @@ -122,7 +129,7 @@ int32 SaveLoad_v3::getSizeScreenshot() { in = saveMan->openForLoading(setCurSlot(i)); if (in) { delete in; - size = (i + 1) * 19968 + 80; + size = (i + 1) * _screenshotSize + _screenshotOffset; break; } } @@ -206,19 +213,15 @@ bool SaveLoad_v3::loadGame(int16 dataVar, int32 size, int32 offset) { return false; } -bool SaveLoad_v3::loadNotes(int16 dataVar, int32 size, int32 offset) { - return false; -} - bool SaveLoad_v3::loadScreenshot(int16 dataVar, int32 size, int32 offset) { Common::SaveFileManager *saveMan = g_system->getSavefileManager(); Common::InSaveFile *in; - int slot = (offset - 80) / 19968; - int slotR = (offset - 80) % 19968; + int slot = (offset - _screenshotOffset) / _screenshotSize; + int slotR = (offset - _screenshotOffset) % _screenshotSize; _useScreenshots = true; - if ((size == 40) && (offset == 40)) { + if ((size == 40) && (offset == _indexOffset)) { char buf[40]; memset(buf, 0, 40); @@ -327,16 +330,16 @@ bool SaveLoad_v3::saveGame(int16 dataVar, int32 size, int32 offset) { } bool SaveLoad_v3::saveNotes(int16 dataVar, int32 size, int32 offset) { - return false; + return SaveLoad_v2::saveNotes(dataVar, size - 160, offset); } bool SaveLoad_v3::saveScreenshot(int16 dataVar, int32 size, int32 offset) { - int slot = (offset - 80) / 19968; - int slotR = (offset - 80) % 19968; + int slot = (offset - _screenshotOffset) / _screenshotSize; + int slotR = (offset - _screenshotOffset) % _screenshotSize; _useScreenshots = true; - if ((offset < 80) && (size > 0)) { + if ((offset < _screenshotOffset) && (size > 0)) { return true; diff --git a/engines/gob/scenery.cpp b/engines/gob/scenery.cpp index ae04c220d3..95cf90bddc 100644 --- a/engines/gob/scenery.cpp +++ b/engines/gob/scenery.cpp @@ -320,7 +320,7 @@ void Scenery::updateStatic(int16 orderFrom, byte index, byte layer) { int16 top; int16 bottom; - if (layer >= _statics[index].layersCount) + if ((index >= 10) || layer >= _statics[index].layersCount) return; layerPtr = &_statics[index].layers[layer]; diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index ff6333aa9e..40acf21f9e 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -32,7 +32,6 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/imd.h" #include "gob/sound.h" #include "gob/video.h" @@ -50,6 +49,9 @@ uint32 Util::getTimeKey(void) { } int16 Util::getRandom(int16 max) { + if (max == 0) + return 0; + return _vm->_rnd.getRandomNumber(max - 1); } @@ -126,8 +128,8 @@ void Util::processInput(bool scroll) { _vm->_global->_speedFactor = MIN(_fastMode + 1, 3); if (scroll && hasMove) { - if (y >= (200 - _vm->_video->_splitHeight2)) { - y = 200 - _vm->_video->_splitHeight2 - 1; + if (y >= (_vm->_height - _vm->_video->_splitHeight2)) { + y = _vm->_height - _vm->_video->_splitHeight2 - 1; _vm->_util->setMousePos(x, y); } _vm->_game->evaluateScroll(x, y); @@ -301,7 +303,6 @@ void Util::setFrameRate(int16 rate) { _vm->_global->_frameWaitTime = 1000 / rate; _vm->_global->_startFrameTime = getTimeKey(); - _vm->_imdPlayer->_frameDelay = 0; } void Util::waitEndFrame() { @@ -312,17 +313,13 @@ void Util::waitEndFrame() { time = getTimeKey() - _vm->_global->_startFrameTime; if ((time > 1000) || (time < 0)) { _vm->_global->_startFrameTime = getTimeKey(); - _vm->_imdPlayer->_frameDelay = 0; return; } - if (_vm->_global->_frameWaitTime - time > 0) { - _vm->_imdPlayer->_frameDelay = 0; - delay(_vm->_global->_frameWaitTime - _vm->_imdPlayer->_frameDelay - time); - } + if ((_vm->_global->_frameWaitTime - time) > 0) + delay(_vm->_global->_frameWaitTime - time); _vm->_global->_startFrameTime = getTimeKey(); - _vm->_imdPlayer->_frameDelay = time - _vm->_global->_frameWaitTime; } void Util::setScrollOffset(int16 x, int16 y) { diff --git a/engines/gob/video.cpp b/engines/gob/video.cpp index 6f88a5a993..0dc15a8657 100644 --- a/engines/gob/video.cpp +++ b/engines/gob/video.cpp @@ -94,6 +94,7 @@ Video::Video(GobEngine *vm) : _vm(vm) { _splitHeight1 = 200; _splitHeight2 = 0; _splitStart = 0; + _lastRetraceLength = 0; _curSparse = 0; _lastSparse = 0xFFFFFFFF; @@ -161,26 +162,27 @@ SurfaceDesc *Video::initSurfDesc(int16 vidMode, int16 width, int16 height, } void Video::retrace(bool mouse) { + uint32 time = _vm->_util->getTimeKey(); + if (mouse) CursorMan.showMouse((_vm->_draw->_showCursor & 2) != 0); if (_vm->_global->_primarySurfDesc) { g_system->copyRectToScreen(_vm->_global->_primarySurfDesc->getVidMem() + _scrollOffsetY * _surfWidth + _scrollOffsetX, _surfWidth, - 0, 0, 320, _splitHeight1); + 0, 0, _vm->_width, _splitHeight1); if (_splitHeight2 > 0) g_system->copyRectToScreen(_vm->_global->_primarySurfDesc->getVidMem() + _splitStart * _surfWidth, _surfWidth, 0, - 200 - _splitHeight2, 320, _splitHeight2); + _vm->_height - _splitHeight2, _vm->_width, _splitHeight2); g_system->updateScreen(); } + + _lastRetraceLength = _vm->_util->getTimeKey() - time; } void Video::waitRetrace(bool mouse) { - uint32 time; - - time = _vm->_util->getTimeKey(); retrace(mouse); - _vm->_util->delay(MAX(1, 10 - (int)(_vm->_util->getTimeKey() - time))); + _vm->_util->delay(MAX(1, 10 - (int) _lastRetraceLength)); } void Video::sparseRetrace(int max) { diff --git a/engines/gob/video.h b/engines/gob/video.h index 51d02bd219..dc23bda81e 100644 --- a/engines/gob/video.h +++ b/engines/gob/video.h @@ -104,6 +104,7 @@ public: int16 _splitHeight1; int16 _splitHeight2; int16 _splitStart; + uint32 _lastRetraceLength; void freeDriver(); void initPrimary(int16 mode); diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp new file mode 100644 index 0000000000..e72354a169 --- /dev/null +++ b/engines/gob/videoplayer.cpp @@ -0,0 +1,333 @@ +/* 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/videoplayer.h" +#include "gob/global.h" +#include "gob/util.h" +#include "gob/dataio.h" +#include "gob/video.h" +#include "gob/draw.h" +#include "gob/game.h" +#include "gob/palanim.h" +#include "gob/inter.h" + +namespace Gob { + +const char *VideoPlayer::_extensions[] = { "IMD", "VMD" }; + +VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { + _curFile[0] = 0; + _stream = 0; + _video = 0; + _backSurf = false; +} + +VideoPlayer::~VideoPlayer() { + closeVideo(); +} + +bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Type which) { + char fileName[256]; + + strncpy0(fileName, video, 250); + + char *extStart = strchr(fileName, '.'); + if (extStart) { + // The requested file already has an extension. Verifying. + + int i; + for (i = 0; i < ARRAYSIZE(_extensions); i++) { + if (!scumm_stricmp(extStart + 1, _extensions[i])) { + if ((which != kVideoTypeTry) && (which == ((Type) i))) { + warning("Attempted to open video \"%s\", " + "but requested a different type", fileName); + return false; + } + which = (Type) i; + break; + } + } + if (i >= ARRAYSIZE(_extensions)) + extStart = 0; + + } + + if (!extStart) { + // No or unrecognized extension. Probing. + + int len = strlen(fileName); + + int i; + for (i = 0; i < ARRAYSIZE(_extensions); i++) { + if ((which == kVideoTypeTry) || (which == ((Type) i))) { + int16 handle; + + fileName[len] = '.'; + fileName[len + 1] = 0; + strcat(fileName, _extensions[i]); + + handle = _vm->_dataIO->openData(fileName); + if (handle >= 0) { + _vm->_dataIO->closeData(handle); + which = (Type) i; + break; + } + } + } + if ((i >= ARRAYSIZE(_extensions)) || (which == kVideoTypeTry)) { + fileName[len] = 0; + warning("Couldn't open video \"%s\"", fileName); + return false; + } + + } + + if (scumm_strnicmp(_curFile, fileName, strlen(fileName))) { + closeVideo(); + + int16 handle = _vm->_dataIO->openData(fileName); + + if (handle < 0) { + warning("Couldn't open video \"%s\": No such file", fileName); + return false; + } + + _stream = _vm->_dataIO->openAsStream(handle, true); + + if (which == kVideoTypeIMD) { + _video = new Imd(); + } else if (which == kVideoTypeVMD) { + _video = new Vmd(); + } else { + warning("Couldn't open video \"%s\": Invalid video Type", fileName); + closeVideo(); + return false; + } + + if (!_video->load(*_stream)) { + warning("While loading video \"%s\"", fileName); + closeVideo(); + return false; + } + + _video->setXY(x, y); + + if (!(flags & kFlagNoVideo)) { + _backSurf = ((flags & kFlagFrontSurface) == 0); + SurfaceDesc::Ptr surf = _vm->_draw->_spritesArray[_backSurf ? 21 : 20]; + _video->setVideoMemory(surf->getVidMem(), surf->getWidth(), surf->getHeight()); + } else + _video->setVideoMemory(); + + _video->enableSound(*_vm->_mixer); + } + + if (!_video) + return false; + + WRITE_VAR(7, _video->getFramesCount()); + + return true; +} + +void VideoPlayer::play(int16 startFrame, int16 lastFrame, int16 breakKey, + uint16 palCmd, int16 palStart, int16 palEnd, + int16 palFrame, int16 endFrame, bool fade, int16 reverseTo) { + + if (!_video) + return; + + breakKey = 27; + if (startFrame < 0) + startFrame = _video->getCurrentFrame(); + if (lastFrame < 0) + lastFrame = _video->getFramesCount() - 1; + if (palFrame < 0) + palFrame = startFrame; + if (endFrame < 0) + endFrame = lastFrame; + palCmd &= 0x3F; + + if (_video->getCurrentFrame() != startFrame) + _video->seekFrame(startFrame); + + _vm->_draw->_showCursor = 0; + _vm->_util->setFrameRate(12); + + if (fade) + _vm->_palAnim->fade(0, -2, 0); + + while (startFrame <= lastFrame) { + if (doPlay(startFrame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame)) + break; + + if (fade) { + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + fade = false; + } + + _video->waitEndFrame(); + startFrame++; + } + + 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)) { + _vm->_palAnim->fade(0, -2, 0); + memset((char *) _vm->_draw->_vgaPalette, 0, 768); + } + _video->waitEndFrame(); + } + } +} + +int16 VideoPlayer::getFramesCount() const { + if (!_video) + return 0; + + return _video->getFramesCount(); +} + +int16 VideoPlayer::getCurrentFrame() const { + if (!_video) + return 0; + + return _video->getCurrentFrame(); +} + +bool VideoPlayer::doPlay(int16 frame, int16 breakKey, + uint16 palCmd, int16 palStart, int16 palEnd, + int16 palFrame, int16 endFrame) { + + bool modifiedPal = false; + + if ((frame == palFrame) || ((frame == endFrame) && (palCmd == 8))) { + modifiedPal = true; + _vm->_draw->_applyPal = true; + + if (palCmd >= 4) + copyPalette(palStart, palEnd); + } + + if (modifiedPal && (palCmd == 8) && !_backSurf) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + + + CoktelVideo::State state = _video->nextFrame(); + WRITE_VAR(11, frame); + + + if (modifiedPal && (palCmd == 16)) { + if (_backSurf) + _vm->_draw->forceBlit(); + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + _vm->_draw->_noInvalidated = true; + } + + if (state.flags & CoktelVideo::kStatePalette) { + copyPalette(palStart, palEnd); + + if (!_backSurf) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + else + _vm->_draw->_applyPal = true; + } + + if (modifiedPal && (palCmd == 8) && _backSurf) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + + + if (_backSurf) { + _vm->_draw->invalidateRect(state.left, state.top, state.right, state.bottom); + _vm->_draw->blitInvalidated(); + } + _vm->_video->retrace(); + + + if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + + + _vm->_util->processInput(); + + if (_vm->_quitRequested) { + _video->disableSound(); + return true; + } + + if (breakKey != 0) { + _vm->_util->getMouseState(&_vm->_global->_inter_mouseX, + &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons); + + _vm->_inter->storeKey(_vm->_util->checkKey()); + if (VAR(0) == (unsigned) breakKey) { + _video->disableSound(); + return true; + } + } + + return false; +} + +void VideoPlayer::copyPalette(int16 palStart, int16 palEnd) { + if ((palStart == -1) || (palEnd == -1)) + memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, + _video->getPalette(), 768); + else + memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + + palStart * 3, _video->getPalette() + palStart * 3, + (palEnd - palStart + 1) * 3); +} + +void VideoPlayer::writeVideoInfo(const char *video, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight) { + + if (openVideo(video)) { + WRITE_VAR_OFFSET(varX, _video->getX()); + WRITE_VAR_OFFSET(varY, _video->getY()); + WRITE_VAR_OFFSET(varFrames, _video->getFramesCount()); + WRITE_VAR_OFFSET(varWidth, _video->getWidth()); + WRITE_VAR_OFFSET(varHeight, _video->getHeight()); + closeVideo(); + } 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); + } +} + +void VideoPlayer::closeVideo() { + delete _video; + delete _stream; + + _video = 0; + _stream = 0; +} + +} // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h new file mode 100644 index 0000000000..c4c608dc99 --- /dev/null +++ b/engines/gob/videoplayer.h @@ -0,0 +1,86 @@ +/* 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_VIDEOPLAYER_H +#define GOB_VIDEOPLAYER_H + +#include "gob/coktelvideo.h" +#include "gob/dataio.h" + +namespace Gob { + +class GobEngine; + +class VideoPlayer { +public: + enum Flags { + kFlagNone = 0, + kFlagFrontSurface = 0x80, + kFlagNoVideo = 0x100 + }; + + enum Type { + kVideoTypeTry = -1, + kVideoTypeIMD = 0, + kVideoTypeVMD = 1 + }; + + VideoPlayer(GobEngine *vm); + ~VideoPlayer(); + + bool openVideo(const char *video, int16 x = -1, int16 y = -1, + int16 flags = kFlagFrontSurface, Type which = kVideoTypeTry); + + void play(int16 startFrame = -1, int16 lastFrame = -1, int16 breakKey = 27, + uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, + int16 palFrame = -1, int16 endFrame = -1, bool fade = false, + int16 reverseTo = -1); + + int16 getFramesCount() const; + int16 getCurrentFrame() const; + void writeVideoInfo(const char *video, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight); + + void closeVideo(); + +private: + static const char *_extensions[]; + + GobEngine *_vm; + + char _curFile[256]; + DataStream *_stream; + CoktelVideo *_video; + bool _backSurf; + + void copyPalette(int16 palStart = -1, int16 palEnd = -1); + bool doPlay(int16 frame, int16 breakKey, + uint16 palCmd, int16 palStart, int16 palEnd, + int16 palFrame, int16 endFrame); +}; + +} // End of namespace Gob + +#endif // GOB_VIDEOPLAYER_H |