aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mads/assets.cpp141
-rw-r--r--engines/mads/assets.h43
-rw-r--r--engines/mads/module.mk1
-rw-r--r--engines/mads/scene.cpp7
-rw-r--r--engines/mads/scene.h3
-rw-r--r--engines/mads/scene_data.cpp112
-rw-r--r--engines/mads/scene_data.h69
-rw-r--r--engines/mads/sequence.cpp370
-rw-r--r--engines/mads/sequence.h109
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 */