diff options
author | Paul Gilbert | 2014-03-03 20:53:27 -0500 |
---|---|---|
committer | Paul Gilbert | 2014-03-03 20:53:27 -0500 |
commit | 3a3a295758a87817e9d66d3c06df56859ef55529 (patch) | |
tree | 429deeae20d459baabe3d0b3aa302f9706baff9b | |
parent | d8026b9ef72d7ca22721486244309ccd4a003cae (diff) | |
download | scummvm-rg350-3a3a295758a87817e9d66d3c06df56859ef55529.tar.gz scummvm-rg350-3a3a295758a87817e9d66d3c06df56859ef55529.tar.bz2 scummvm-rg350-3a3a295758a87817e9d66d3c06df56859ef55529.zip |
MADS: Implemented sequence list, improvements for sprite assets
-rw-r--r-- | engines/mads/assets.cpp | 141 | ||||
-rw-r--r-- | engines/mads/assets.h | 43 | ||||
-rw-r--r-- | engines/mads/module.mk | 1 | ||||
-rw-r--r-- | engines/mads/scene.cpp | 7 | ||||
-rw-r--r-- | engines/mads/scene.h | 3 | ||||
-rw-r--r-- | engines/mads/scene_data.cpp | 112 | ||||
-rw-r--r-- | engines/mads/scene_data.h | 69 | ||||
-rw-r--r-- | engines/mads/sequence.cpp | 370 | ||||
-rw-r--r-- | engines/mads/sequence.h | 109 |
9 files changed, 744 insertions, 111 deletions
diff --git a/engines/mads/assets.cpp b/engines/mads/assets.cpp index f7188e9551..c968afc311 100644 --- a/engines/mads/assets.cpp +++ b/engines/mads/assets.cpp @@ -25,72 +25,161 @@ #include "mads/assets.h" #include "mads/compression.h" #include "mads/events.h" +#include "mads/palette.h" namespace MADS { -SpriteAsset::SpriteAsset(MADSEngine *vm, const Common::String &resourceName, int flags): - _vm(vm) { +SpriteAsset::SpriteAsset(MADSEngine *vm, const Common::String &resourceName, int flags) : + _vm(vm) { Common::String resName = resourceName; if (!resName.hasSuffix(".SS")) resName += ".SS"; - + File file(resName); - MadsPack sprites(&file); + load(&file, flags); + + file.close(); +} + +SpriteAsset::SpriteAsset(MADSEngine *vm, Common::SeekableReadStream *stream, int flags) : + _vm(vm) { + load(stream, flags); +} +void SpriteAsset::load(Common::SeekableReadStream *stream, int flags) { int curFrame = 0; uint32 frameOffset = 0; + MadsPack sprite(stream); _frameRate = 0; _pixelSpeed = 0; _maxWidth = 0; _maxHeight = 0; - Common::SeekableReadStream *spriteStream = sprites.getItemStream(0); - for (int i = 0; i < 19; i++) { - spriteStream->readUint16LE(); - } + Common::SeekableReadStream *spriteStream = sprite.getItemStream(0); + _mode = spriteStream->readByte(); + spriteStream->skip(1); + int type1 = spriteStream->readUint16LE(); + int type2 = spriteStream->readUint16LE(); + _isBackground = (type1 != 0) && (type2 < 4); + spriteStream->skip(32); _frameCount = spriteStream->readUint16LE(); + if ((flags & SPRITE_SET_CHAR_INFO) == 0) + _charInfo = nullptr; + else + _charInfo = new SpriteSetCharInfo(spriteStream); + + delete spriteStream; + // Get the palette data - spriteStream = sprites.getItemStream(2); + spriteStream = sprite.getItemStream(2); int numColors = 0; byte *palData = _vm->_palette->decodePalette(spriteStream, &numColors); - Common::copy(palData, &palData[numColors], &_palette[0]); - if (numColors < 256) - Common::fill(&_palette[numColors * 3], &_palette[PALETTE_SIZE], 0); + if (numColors < 256) + Common::fill((byte *)&_palette[numColors], (byte *)&_palette[256], 0); _colorCount = numColors; delete[] palData; delete spriteStream; - Common::SeekableReadStream *spriteDataStream = sprites.getItemStream(3); - + spriteStream = sprite.getItemStream(1); + Common::SeekableReadStream *spriteDataStream = sprite.getItemStream(3); SpriteAssetFrame frame; + Common::Array<int> frameSizes; for (curFrame = 0; curFrame < _frameCount; curFrame++) { - frame.comp = 0; + frame._stream = 0; + frame._comp = 0; frameOffset = spriteStream->readUint32LE(); _frameOffsets.push_back(frameOffset); - spriteStream->readUint32LE(); // frame size - frame.x = spriteStream->readUint16LE(); - frame.y = spriteStream->readUint16LE(); - frame.w = spriteStream->readUint16LE(); - frame.h = spriteStream->readUint16LE(); - if (curFrame == 0) { - debugN(kDebugGraphics, "%i frames, x = %i, y = %i, w = %i, h = %i\n", - _frameCount, frame.x, frame.y, frame.w, frame.h); + uint32 frameSize = spriteStream->readUint32LE(); + frameSizes.push_back(frameSize); + + frame._bounds.left = spriteStream->readSint16LE(); + frame._bounds.top = spriteStream->readSint16LE(); + frame._bounds.setWidth(spriteStream->readUint16LE()); + frame._bounds.setHeight(spriteStream->readUint16LE()); + + if (curFrame == 0) + debugC(1, kDebugGraphics, "%i frames, x = %i, y = %i, w = %i, h = %i\n", + _frameCount, frame._bounds.left, frame._bounds.top, + frame._bounds.width(), frame._bounds.height()); + + if (_mode == 0) { + // Create a frame and decompress the raw pixel data + uint32 currPos = (uint32)spriteDataStream->pos(); + frame._frame = new MSprite(spriteDataStream, + Common::Point(frame._bounds.left, frame._bounds.top), + frame._bounds.width(), frame._bounds.height(), false); + assert((uint32)spriteDataStream->pos() == (currPos + frameSize)); } - frame.frame = new MSprite(spriteDataStream, Common::Point(frame.x, frame.y), - frame.w, frame.h, false); _frames.push_back(frame); } + if (_mode != 0) { + // Handle decompressing Fab encoded data + for (curFrame = 0; curFrame < _frameCount; curFrame++) { + FabDecompressor fab; + + int srcSize = (curFrame == (_frameCount - 1)) ? spriteDataStream->size() - _frameOffsets[curFrame] : + _frameOffsets[curFrame + 1] - _frameOffsets[curFrame]; + byte *srcData = new byte[srcSize]; + assert(srcData); + spriteDataStream->read(srcData, srcSize); + + byte *destData = new byte[frameSizes[curFrame]]; + assert(destData); + + fab.decompress(srcData, srcSize, destData, frameSizes[curFrame]); + + // Load the frame + Common::MemoryReadStream *rs = new Common::MemoryReadStream(destData, frameSizes[curFrame]); + _frames[curFrame]._frame = new MSprite(rs, + Common::Point(_frames[curFrame]._bounds.left, _frames[curFrame]._bounds.top), + _frames[curFrame]._bounds.width(), _frames[curFrame]._bounds.height(), false); + delete rs; + + delete[] srcData; + delete[] destData; + } + } + + delete spriteStream; delete spriteDataStream; - file.close(); } +MSprite *SpriteAsset::getFrame(int frameIndex) { + if ((uint)frameIndex < _frames.size()) { + return _frames[frameIndex]._frame; + } else { + debugC(kDebugGraphics, "SpriteAsset::getFrame: Invalid frame %d, out of %d", frameIndex, _frames.size()); + return _frames[_frames.size() - 1]._frame; + } +} + + void SpriteAsset::drawScaled(int frameNumber, MSurface &depthSurface, MSurface &destSurface, int scale, int depth, const Common::Point &pos) { warning("TODO: SpriteAsset::drawScaled"); } +/*------------------------------------------------------------------------*/ + +SpriteSetCharInfo::SpriteSetCharInfo(Common::SeekableReadStream *s) { + _totalFrames = s->readByte(); + s->skip(1); + _numEntries = s->readUint16LE(); + + for (int i = 0; i < 16; ++i) + _frameList[i] = s->readUint16LE(); + for (int i = 0; i < 16; ++i) + _frameList2[i] = s->readUint16LE(); + for (int i = 0; i < 16; ++i) + _ticksList[i] = s->readUint16LE(); + + _unk1 = s->readUint16LE(); + _ticksAmount = s->readByte(); + _yScale = s->readByte(); +} + } // End of namespace MADS diff --git a/engines/mads/assets.h b/engines/mads/assets.h index 5964036789..7a6939b222 100644 --- a/engines/mads/assets.h +++ b/engines/mads/assets.h @@ -31,11 +31,27 @@ namespace MADS { +#define SPRITE_SET_CHAR_INFO 4 + struct SpriteAssetFrame { - uint32 stream; - int x, y, w, h; - uint32 comp; - MSprite *frame; + uint32 _stream; + Common::Rect _bounds; + uint32 _comp; + MSprite *_frame; +}; + +class SpriteSetCharInfo { +public: + SpriteSetCharInfo(Common::SeekableReadStream *s); + + int _totalFrames; + int _numEntries; + int _frameList2[16]; + int _frameList[16]; + int _ticksList[16]; + int _unk1; + int _ticksAmount; + int _yScale; }; class SpriteAsset { @@ -50,8 +66,26 @@ private: Common::Array<uint32> _frameOffsets; Common::Array<SpriteAssetFrame> _frames; uint32 _frameStartOffset; + uint8 _mode; + bool _isBackground; + + /** + * Load the data for the asset + */ + void load(Common::SeekableReadStream *stream, int flags); +public: + SpriteSetCharInfo *_charInfo; public: + /** + * Constructor + */ SpriteAsset(MADSEngine *vm, const Common::String &resourceName, int flags); + + /** + * Constructor + */ + SpriteAsset(MADSEngine *vm, Common::SeekableReadStream *stream, int flags); + int getCount() { return _frameCount; } int getFrameRate() const { return _frameRate; } int getPixelSpeed() const { return _pixelSpeed; } @@ -62,6 +96,7 @@ public: MSprite *getFrame(int frameIndex); byte *getPalette() { return _palette; } int getColorCount() { return _colorCount; } + bool isBackground() const { return _isBackground; } void drawScaled(int frameNumber, MSurface &depthSurface, MSurface &destSurface, int scale, int depth, const Common::Point &pos); diff --git a/engines/mads/module.mk b/engines/mads/module.mk index f715e1a4da..826e54f8fd 100644 --- a/engines/mads/module.mk +++ b/engines/mads/module.mk @@ -26,6 +26,7 @@ MODULE_OBJS := \ resources.o \ scene.o \ scene_data.o \ + sequence.o \ sound.o \ user_interface.o diff --git a/engines/mads/scene.cpp b/engines/mads/scene.cpp index 47b9bfac0d..6efbdf5072 100644 --- a/engines/mads/scene.cpp +++ b/engines/mads/scene.cpp @@ -29,7 +29,8 @@ namespace MADS { Scene::Scene(MADSEngine *vm): _vm(vm), _spriteSlots(vm), _action(_vm), - _dynamicHotspots(vm), _screenObjects(vm), _interface(vm) { + _dynamicHotspots(vm), _screenObjects(vm), _interface(vm), + _sequences(vm) { _priorSceneId = 0; _nextSceneId = 0; _currentSceneId = 0; @@ -355,6 +356,10 @@ void Scene::doFrame() { _vm->_events->setCursor(cursorId); } + if (!_vm->_game->_abortTimers) + _sequences.tick(); + + // TODO: Rest of Scene::doFrame } } diff --git a/engines/mads/scene.h b/engines/mads/scene.h index 4b822d111b..71bfe317d9 100644 --- a/engines/mads/scene.h +++ b/engines/mads/scene.h @@ -30,6 +30,7 @@ #include "mads/msurface.h" #include "mads/scene_data.h" #include "mads/animation.h" +#include "mads/sequence.h" namespace MADS { @@ -84,7 +85,7 @@ public: DynamicHotspots _dynamicHotspots; byte *_vocabBuffer; Common::Array<int> _activeVocabs; - Common::Array<SequenceEntry> _sequences; + SequenceList _sequences; Common::Array<KernelMessage> _messages; Common::String _talkFont; int _textSpacing; diff --git a/engines/mads/scene_data.cpp b/engines/mads/scene_data.cpp index 10d346ed11..6fa2f5b326 100644 --- a/engines/mads/scene_data.cpp +++ b/engines/mads/scene_data.cpp @@ -223,54 +223,96 @@ DynamicHotspot::DynamicHotspot() { /*------------------------------------------------------------------------*/ DynamicHotspots::DynamicHotspots(MADSEngine *vm): _vm(vm) { - _changed = false; + for (int i = 0; i < DYNAMIC_HOTSPOTS_SIZE; ++i) { + DynamicHotspot rec; + rec._active = false; + _entries.push_back(rec); + } + + _changed = true; + _count = 0; } -void DynamicHotspots::clear() { - Common::Array<DynamicHotspot>::clear(); - _changed = false; +int DynamicHotspots::add(int descId, int field14, int seqIndex, const Common::Rect &bounds) { + // Find a free slot + uint idx = 0; + while ((idx < _entries.size()) && _entries[idx]._active) + ++idx; + if (idx == _entries.size()) + error("DynamicHotspots overflow"); + + _entries[idx]._active = true; + _entries[idx]._descId = descId; + _entries[idx]._seqIndex = seqIndex; + _entries[idx]._bounds = bounds; + _entries[idx]._feetPos.x = -3; + _entries[idx]._feetPos.y = 0; + _entries[idx]._facing = 5; + _entries[idx]._field14 = field14; + _entries[idx]._articleNumber = 6; + _entries[idx]._cursor = CURSOR_NONE; + + ++_count; + _changed = true; + + if (seqIndex >= 0) + _vm->_game->_scene._sequences[seqIndex]._dynamicHotspotIndex = idx; + + return idx; } -void DynamicHotspots::refresh() { +int DynamicHotspots::setPosition(int index, int xp, int yp, int facing) { + if (index >= 0) { + _entries[index]._feetPos.x = xp; + _entries[index]._feetPos.y = yp; + _entries[index]._facing = facing; + } + + return index; +} + +int DynamicHotspots::setCursor(int index, CursorType cursor) { + if (index >= 0) + _entries[index]._cursor = cursor; + + return index; +} + +void DynamicHotspots::remove(int index) { Scene &scene = _vm->_game->_scene; - for (uint idx = 0; idx < size(); ++idx) { - DynamicHotspot &dh = (*this)[idx]; + if (_entries[index]._active) { + if (_entries[index]._seqIndex >= 0) + scene._sequences[_entries[index]._seqIndex]._dynamicHotspotIndex = -1; + _entries[index]._active = false; - switch (scene._screenObjects._v832EC) { - case 0: - case 2: - scene._screenObjects.add(dh._bounds, CAT_12, dh._descId); - scene._screenObjects._v8333C = true; - default: - break; - } + --_count; + _changed = true; } } -/*------------------------------------------------------------------------*/ +void DynamicHotspots::clear() { + for (uint i = 0; i < _entries.size(); ++i) + _entries[i]._active = false; -SequenceEntry::SequenceEntry() { - _spritesIndex = 0; - _flipped =0; - _frameIndex = 0; - _frameStart = 0; - _numSprites = 0; - _animType = 0; - _frameInc = 0; - _depth = 0; - _scale = 0; - _dynamicHotspotIndex = -1; - _triggerCountdown = 0; - _doneFlag = 0; - _entries._count = 0; - _abortMode = 0; - _actionNouns[0] = _actionNouns[1] = _actionNouns[2] = 0; - _numTicks = 0; - _extraTicks = 0; - _timeout = 0; + _changed = false; + _count = 0; } +void DynamicHotspots::reset() { + for (uint i = 0; i < _entries.size(); ++i) + remove(i); + + _count = 0; + _changed = false; +} + +void DynamicHotspots::refresh() { + error("DynamicHotspots::refresh"); +} + +/*------------------------------------------------------------------------*/ + KernelMessage::KernelMessage() { _flags = 0; _seqInex = 0; diff --git a/engines/mads/scene_data.h b/engines/mads/scene_data.h index c11c59aee1..dc59bff4cf 100644 --- a/engines/mads/scene_data.h +++ b/engines/mads/scene_data.h @@ -153,6 +153,18 @@ public: * @param index Specifies the index in the array */ void deleteEntry(int index); + + SpriteAsset &getSprite(int idx) { + error("TODO"); + } + void deleteTimer(int idx) { + warning("TODO: SpriteSlots::deleteTimer"); + } + int getIndex() { + warning("TODO: SpriteSlots::indexOf"); + return -1; + } + }; class SpriteSets: public Common::Array<SpriteAsset *> { @@ -179,6 +191,7 @@ public: class DynamicHotspot { public: + bool _active; int _seqIndex; Common::Rect _bounds; Common::Point _feetPos; @@ -191,60 +204,28 @@ public: DynamicHotspot(); }; -class DynamicHotspots : public Common::Array<DynamicHotspot> { +#define DYNAMIC_HOTSPOTS_SIZE 8 + +class DynamicHotspots { private: MADSEngine *_vm; + Common::Array<DynamicHotspot> _entries; + int _count; public: bool _changed; - - /** - * Constructor - */ +public: DynamicHotspots(MADSEngine *vm); - /** - * Clear the list - */ + DynamicHotspot &operator[](uint idx) { return _entries[idx]; } + int add(int descId, int field14, int seqIndex, const Common::Rect &bounds); + int setPosition(int index, int xp, int yp, int facing); + int setCursor(int index, CursorType cursor); + void remove(int index); void clear(); - - /** - * Refresh the list - */ + void reset(); void refresh(); }; -class SequenceEntry { -public: - int _spritesIndex; - int _flipped; - int _frameIndex; - int _frameStart; - int _numSprites; - int _animType; - int _frameInc; - int _depth; - int _scale; - int _dynamicHotspotIndex; - - Common::Point _msgPos; - - int _triggerCountdown; - bool _doneFlag; - struct { - int _count; - int _mode[5]; - int _frameIndex[5]; - int _abortVal[5]; - } _entries; - int _abortMode; - int _actionNouns[3]; - int _numTicks; - int _extraTicks; - int _timeout; - - SequenceEntry(); -}; - class KernelMessage { public: int _flags; diff --git a/engines/mads/sequence.cpp b/engines/mads/sequence.cpp new file mode 100644 index 0000000000..7c7b25d32a --- /dev/null +++ b/engines/mads/sequence.cpp @@ -0,0 +1,370 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "mads/mads.h" +#include "mads/assets.h" +#include "mads/sequence.h" +#include "mads/scene.h" + +namespace MADS { + +SequenceEntry::SequenceEntry() { + _spritesIndex = 0; + _flipped = 0; + _frameIndex = 0; + _frameStart = 0; + _numSprites = 0; + _animType = ANIMTYPE_NONE; + _frameInc = 0; + _depth = 0; + _scale = 0; + _dynamicHotspotIndex = -1; + _triggerCountdown = 0; + _doneFlag = 0; + _entries._count = 0; + _abortMode = ABORTMODE_0; + _actionNouns[0] = _actionNouns[1] = _actionNouns[2] = 0; + _numTicks = 0; + _extraTicks = 0; + _timeout = 0; +} + +/*------------------------------------------------------------------------*/ + +#define TIMER_LIST_SIZE 30 + +SequenceList::SequenceList(MADSEngine *vm) : _vm(vm) { + for (int i = 0; i < TIMER_LIST_SIZE; ++i) { + SequenceEntry rec; + rec._active = false; + rec._dynamicHotspotIndex = -1; + _entries.push_back(rec); + } +} + +void SequenceList::clear() { + for (uint i = 0; i < _entries.size(); ++i) { + _entries[i]._active = false; + _entries[i]._dynamicHotspotIndex = -1; + } +} + +bool SequenceList::addSubEntry(int index, SequenceSubEntryMode mode, int frameIndex, int abortVal) { + if (_entries[index]._entries._count >= TIMER_ENTRY_SUBSET_MAX) + return true; + + int subIndex = _entries[index]._entries._count++; + _entries[index]._entries._mode[subIndex] = mode; + _entries[index]._entries._frameIndex[subIndex] = frameIndex; + _entries[index]._entries._abortVal[subIndex] = abortVal; + + return false; +} + +int SequenceList::add(int spriteListIndex, bool flipped, int frameIndex, int triggerCountdown, int delayTicks, int extraTicks, int numTicks, + int msgX, int msgY, bool nonFixed, char scale, uint8 depth, int frameInc, SpriteAnimType animType, int numSprites, + int frameStart) { + Scene &scene = _vm->_game->_scene; + + // Find a free slot + uint seqIndex = 0; + while ((seqIndex < _entries.size()) && _entries[seqIndex]._active) + ++seqIndex; + if (seqIndex == _entries.size()) + error("TimerList full"); + + if (frameStart <= 0) + frameStart = 1; + if (numSprites == 0) + numSprites = scene._spriteSlots.getSprite(spriteListIndex).getCount(); + if (frameStart == numSprites) + frameInc = 0; + + // Set the list entry fields + _entries[seqIndex]._active = true; + _entries[seqIndex]._spritesIndex = spriteListIndex; + _entries[seqIndex]._flipped = flipped; + _entries[seqIndex]._frameIndex = frameIndex; + _entries[seqIndex]._frameStart = frameStart; + _entries[seqIndex]._numSprites = numSprites; + _entries[seqIndex]._animType = animType; + _entries[seqIndex]._frameInc = frameInc; + _entries[seqIndex]._depth = depth; + _entries[seqIndex]._scale = scale; + _entries[seqIndex]._nonFixed = nonFixed; + _entries[seqIndex]._msgPos.x = msgX; + _entries[seqIndex]._msgPos.y = msgY; + _entries[seqIndex]._numTicks = numTicks; + _entries[seqIndex]._extraTicks = extraTicks; + + _entries[seqIndex]._timeout = _vm->_events->_currentTimer + delayTicks; + + _entries[seqIndex]._triggerCountdown = triggerCountdown; + _entries[seqIndex]._doneFlag = false; + _entries[seqIndex]._field13 = 0; + _entries[seqIndex]._dynamicHotspotIndex = -1; + _entries[seqIndex]._entries._count = 0; + _entries[seqIndex]._abortMode = _vm->_game->_abortTimersMode2; + + for (int i = 0; i < 3; ++i) + _entries[seqIndex]._actionNouns[i] = _actionNouns[i]; + + return seqIndex; +} + +void SequenceList::remove(int seqIndex) { + Scene &scene = _vm->_game->_scene; + + if (_entries[seqIndex]._active) { + if (_entries[seqIndex]._dynamicHotspotIndex >= 0) + scene._dynamicHotspots.remove(_entries[seqIndex]._dynamicHotspotIndex); + } + + _entries[seqIndex]._active = false; + scene._spriteSlots.deleteTimer(seqIndex); +} + +void SequenceList::setSpriteSlot(int seqIndex, SpriteSlot &spriteSlot) { + Scene &scene = _vm->_game->_scene; + SequenceEntry &timerEntry = _entries[seqIndex]; + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(timerEntry._spritesIndex); + + spriteSlot._spriteType = spriteSet.isBackground() ? ST_BACKGROUND : ST_FOREGROUND; + spriteSlot._seqIndex = seqIndex; + spriteSlot._spritesIndex = timerEntry._spritesIndex; + spriteSlot._frameNumber = (timerEntry._flipped ? 0x8000 : 0) | timerEntry._frameIndex; + spriteSlot._depth = timerEntry._depth; + spriteSlot._scale = timerEntry._scale; + + if (!timerEntry._nonFixed) { + spriteSlot._position = timerEntry._msgPos; + } else { + spriteSlot._position = spriteSet.getFrame(timerEntry._frameIndex - 1)->_pos; + } +} + +bool SequenceList::loadSprites(int seqIndex) { + Scene &scene = _vm->_game->_scene; + SequenceEntry &seqEntry = _entries[seqIndex]; + int slotIndex; + bool result = false; + int idx = -1; + + scene._spriteSlots.deleteTimer(seqIndex); + if (seqEntry._doneFlag) { + remove(seqIndex); + return false; + } + + if (seqEntry._spritesIndex == -1) { + // Doesn't have an associated sprite anymore, so mark as done + seqEntry._doneFlag = true; + } + else if ((slotIndex = scene._spriteSlots.getIndex()) >= 0) { + SpriteSlot &spriteSlot = scene._spriteSlots[slotIndex]; + setSpriteSlot(seqIndex, spriteSlot); + + int x2 = 0, y2 = 0; + + if ((seqEntry._field13 != 0) || (seqEntry._dynamicHotspotIndex >= 0)) { + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(seqEntry._spritesIndex); + MSprite *frame = spriteSet.getFrame(seqEntry._frameIndex - 1); + int width = frame->getWidth() * seqEntry._scale / 200; + int height = frame->getHeight() * seqEntry._scale / 100; + + warning("frame size %d x %d", width, height); + + // TODO: Missing stuff here, and I'm not certain about the dynamic hotspot stuff below + + if (seqEntry._dynamicHotspotIndex >= 0) { + DynamicHotspot &dynHotspot = scene._dynamicHotspots[seqEntry._dynamicHotspotIndex]; + + dynHotspot._bounds.left = MAX(x2 - width, 0); + dynHotspot._bounds.right = MAX(x2 - width, 319) - dynHotspot._bounds.left + 1; + dynHotspot._bounds.top = MAX(y2 - height, 0); + dynHotspot._bounds.bottom = MIN(y2, 155) - dynHotspot._bounds.top; + + scene._dynamicHotspots._changed = true; + } + } + + // Frame adjustments + if (seqEntry._frameStart != seqEntry._numSprites) + seqEntry._frameIndex += seqEntry._frameInc; + + if (seqEntry._frameIndex >= seqEntry._frameStart) { + if (seqEntry._frameIndex > seqEntry._numSprites) { + result = true; + if (seqEntry._animType == ANIMTYPE_CYCLED) { + // Reset back to the starting frame (cyclic) + seqEntry._frameIndex = seqEntry._frameStart; + } + else { + // Switch into reverse mode + seqEntry._frameIndex = seqEntry._numSprites - 1; + seqEntry._frameInc = -1; + } + } + } + else { + // Currently in reverse mode and moved past starting frame + result = true; + + if (seqEntry._animType == ANIMTYPE_CYCLED) + { + // Switch back to forward direction again + seqEntry._frameIndex = seqEntry._frameStart + 1; + seqEntry._frameInc = 1; + } + else { + // Otherwise reset back to last sprite for further reverse animating + seqEntry._frameIndex = seqEntry._numSprites; + } + } + + if (result && (seqEntry._triggerCountdown != 0)) { + if (--seqEntry._triggerCountdown == 0) + seqEntry._doneFlag = true; + } + } + else { + // Out of sprite display slots, so mark entry as done + seqEntry._doneFlag = true; + } + + if (seqEntry._entries._count > 0) { + for (int i = 0; i <= seqEntry._entries._count; ++i) { + switch (seqEntry._entries._mode[i]) { + case SM_0: + case SM_1: + if (((seqEntry._entries._mode[i] == SM_0) && seqEntry._doneFlag) || + ((seqEntry._entries._mode[i] == SM_1) && result)) + idx = i; + break; + + case SM_FRAME_INDEX: { + int v = seqEntry._entries._frameIndex[i]; + if ((v == seqEntry._frameIndex) || (v == 0)) + idx = i; + break; + } + + default: + break; + } + } + } + + if (idx >= 0) { + _vm->_game->_abortTimers = seqEntry._entries._abortVal[idx]; + _vm->_game->_abortTimersMode = seqEntry._abortMode; + } + + return result; +} + +/** +* Handles counting down entries in the timer list for action +*/ +void SequenceList::tick() { + for (uint idx = 0; idx < _entries.size(); ++idx) { + if ((_vm->_game->_abortTimers2 == 0) && (_vm->_game->_abortTimers != 0)) + break; + + SequenceEntry &seqEntry = _entries[idx]; + uint32 currentTimer = _vm->_events->_currentTimer; + + if (!seqEntry._active || (currentTimer < seqEntry._timeout)) + continue; + + // Set the next timeout for the timer entry + seqEntry._timeout = currentTimer + seqEntry._numTicks; + + // Action the sprite + if (loadSprites(idx)) { + seqEntry._timeout += seqEntry._extraTicks; + } + } +} + +void SequenceList::delay(uint32 v1, uint32 v2) { + for (uint idx = 0; idx < _entries.size(); ++idx) { + if (_entries[idx]._active) { + _entries[idx]._timeout += v1 - v2; + } + } +} + +void SequenceList::setAnimRange(int seqIndex, int startVal, int endVal) { + Scene &scene = _vm->_game->_scene; + SequenceEntry &seqEntry = _entries[seqIndex]; + SpriteAsset &spriteSet = scene._spriteSlots.getSprite(seqEntry._spritesIndex); + int numSprites = spriteSet.getCount(); + int tempStart = startVal, tempEnd = endVal; + + switch (startVal) { + case -2: + tempStart = numSprites; + break; + case -1: + tempStart = 1; + break; + } + + switch (endVal) { + case -2: + case 0: + tempEnd = numSprites; + break; + case -1: + tempEnd = 1; + break; + default: + tempEnd = numSprites; + break; + } + + seqEntry._frameStart = tempStart; + seqEntry._numSprites = tempEnd; + + seqEntry._frameIndex = (seqEntry._frameInc < 0) ? tempStart : tempEnd; +} + +void SequenceList::scan() { + Scene &scene = _vm->_game->_scene; + + for (uint i = 0; i < _entries.size(); ++i) { + if (!_entries[i]._active && (_entries[i]._spritesIndex != -1)) { + int idx = scene._spriteSlots.getIndex(); + setSpriteSlot(i, scene._spriteSlots[idx]); + } + } +} + +/** +* Sets the depth of the specified entry in the sequence list +*/ +void SequenceList::setDepth(int seqIndex, int depth) { + _entries[seqIndex]._depth = depth; +} +} // End of namespace diff --git a/engines/mads/sequence.h b/engines/mads/sequence.h new file mode 100644 index 0000000000..1b9aefe294 --- /dev/null +++ b/engines/mads/sequence.h @@ -0,0 +1,109 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef MADS_SEQUENCE_H +#define MADS_SEQUENCE_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "common/rect.h" +#include "mads/action.h" + +namespace MADS { + +class SpriteSlot; + +enum SequenceSubEntryMode { SM_0 = 0, SM_1 = 1, SM_FRAME_INDEX = 2 }; + +enum SpriteAnimType { ANIMTYPE_NONE = 0, ANIMTYPE_CYCLED = 1, ANIMTYPE_REVERSIBLE = 2 }; + +#define TIMER_ENTRY_SUBSET_MAX 5 + +struct SequenceSubEntries { + int _count; + SequenceSubEntryMode _mode[TIMER_ENTRY_SUBSET_MAX]; + int _frameIndex[TIMER_ENTRY_SUBSET_MAX]; + int8 _abortVal[TIMER_ENTRY_SUBSET_MAX]; +}; + +struct SequenceEntry { + bool _active; + int8 _spritesIndex; + bool _flipped; + + int _frameIndex; + int _frameStart; + int _numSprites; + + SpriteAnimType _animType; + int _frameInc; + + int _depth; + int _scale; + int _dynamicHotspotIndex; + + bool _nonFixed; + int _field13; + + Common::Point _msgPos; + int _triggerCountdown; + bool _doneFlag; + SequenceSubEntries _entries; + AbortTimerMode _abortMode; + + uint16 _actionNouns[3]; + int _numTicks; + int _extraTicks; + uint32 _timeout; + + SequenceEntry(); +}; + +class MADSEngine; + +class SequenceList { +private: + MADSEngine *_vm; + Common::Array<SequenceEntry> _entries; + int _actionNouns[3]; +public: + SequenceList(MADSEngine *vm); + + SequenceEntry &operator[](int index) { return _entries[index]; } + void clear(); + bool addSubEntry(int index, SequenceSubEntryMode mode, int frameIndex, int abortVal); + int add(int spriteListIndex, bool flipped, int frameIndex, int triggerCountdown, int delayTicks, + int extraTicks, int numTicks, int msgX, int msgY, bool nonFixed, char scale, uint8 depth, + int frameInc, SpriteAnimType animType, int numSprites, int frameStart); + void remove(int seqIndex); + void setSpriteSlot(int seqIndex, SpriteSlot &spriteSlot); + bool loadSprites(int seqIndex); + void tick(); + void delay(uint32 v1, uint32 v2); + void setAnimRange(int seqIndex, int startVal, int endVal); + void scan(); + void setDepth(int seqIndex, int depth); +}; + +} // End of namespace MADS + +#endif /* MADS_SEQUENCE_H */ |