aboutsummaryrefslogtreecommitdiff
path: root/engines/mads/sequence.cpp
diff options
context:
space:
mode:
authorPaul Gilbert2014-03-03 20:53:27 -0500
committerPaul Gilbert2014-03-03 20:53:27 -0500
commit3a3a295758a87817e9d66d3c06df56859ef55529 (patch)
tree429deeae20d459baabe3d0b3aa302f9706baff9b /engines/mads/sequence.cpp
parentd8026b9ef72d7ca22721486244309ccd4a003cae (diff)
downloadscummvm-rg350-3a3a295758a87817e9d66d3c06df56859ef55529.tar.gz
scummvm-rg350-3a3a295758a87817e9d66d3c06df56859ef55529.tar.bz2
scummvm-rg350-3a3a295758a87817e9d66d3c06df56859ef55529.zip
MADS: Implemented sequence list, improvements for sprite assets
Diffstat (limited to 'engines/mads/sequence.cpp')
-rw-r--r--engines/mads/sequence.cpp370
1 files changed, 370 insertions, 0 deletions
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