aboutsummaryrefslogtreecommitdiff
path: root/engines/m4
diff options
context:
space:
mode:
Diffstat (limited to 'engines/m4')
-rw-r--r--engines/m4/animation.cpp466
-rw-r--r--engines/m4/animation.h107
-rw-r--r--engines/m4/assets.cpp25
-rw-r--r--engines/m4/assets.h3
-rw-r--r--engines/m4/console.cpp57
-rw-r--r--engines/m4/console.h3
-rw-r--r--engines/m4/m4.cpp4
-rw-r--r--engines/m4/m4.h1
-rw-r--r--engines/m4/mads_views.cpp32
-rw-r--r--engines/m4/mads_views.h34
10 files changed, 538 insertions, 194 deletions
diff --git a/engines/m4/animation.cpp b/engines/m4/animation.cpp
index fe46e121f0..4b6be82fad 100644
--- a/engines/m4/animation.cpp
+++ b/engines/m4/animation.cpp
@@ -31,177 +31,397 @@ namespace M4 {
// TODO: this code needs cleanup
-Animation::Animation(MadsM4Engine *vm) {
- _vm = vm;
+MadsAnimation::MadsAnimation(MadsM4Engine *vm, MadsView *view): Animation(vm), _view(view) {
_playing = false;
+ _font = NULL;
+ _unk1 = 0;
+ _skipLoad = false;
+ _unkIndex = -1;
+ _messageCtr= 0;
}
-void Animation::loadFullScreen(const char *filename) {
- _vm->_palette->deleteAllRanges();
- load(filename);
+MadsAnimation::~MadsAnimation() {
+ delete _font;
}
-void Animation::load(const char *filename) {
- MadsPack anim(filename, _vm);
+void MadsAnimation::load(const Common::String &filename) {
+ MadsPack anim(filename.c_str(), _vm);
+ bool madsRes = filename[0] == '*';
char buffer[20];
+ int streamIndex = 1;
// Chunk 1: header
// header
- // TODO: there are some unknown fields here, plus we don't read
- // the entire chunk
+
Common::SeekableReadStream *animStream = anim.getItemStream(0);
- Common::SeekableReadStream *spriteSeriesStream;
- //printf("Chunk 0, size %i\n", animStream->size());
- _seriesCount = animStream->readUint16LE();
- _frameCount = animStream->readUint16LE();
- _frameEntryCount = animStream->readUint16LE();
- // Unknown
- for (int i = 0; i < 43; i++)
- animStream->readByte();
+ int spriteListCount = animStream->readUint16LE();
+ int miscEntriesCount = animStream->readUint16LE();
+ int frameEntryCount = animStream->readUint16LE();
+ int messagesCount = animStream->readUint16LE();
+ animStream->skip(1);
+ _flags = animStream->readByte();
+
+ animStream->skip(2);
+ _animMode = animStream->readUint16LE();
+ assert(_animMode != 4);
+ _roomNumber = animStream->readUint16LE();
+ _field12 = animStream->readUint16LE() != 0;
+ animStream->skip(4);
+ _spriteListIndex = animStream->readUint16LE();
+ _scrollX = animStream->readUint16LE();
+ _scrollY = animStream->readSint16LE();
+ animStream->skip(10);
+
+ animStream->read(buffer, 13);
+ _field24 = Common::String(buffer, 13);
+
+ for (int i = 0; i < 10; ++i) {
+ animStream->read(buffer, 13);
+ _spriteSetNames[i] = Common::String(buffer, 13);
+ }
- _spriteSeriesNames = new Common::String[_seriesCount];
- printf("%i sprite series\n", _seriesCount);
+ animStream->skip(81);
+ animStream->read(buffer, 13);
+ _lbmFilename = Common::String(buffer, 13);
+ animStream->read(buffer, 13);
+ _spritesFilename = Common::String(buffer, 13);
+ animStream->skip(48);
+ animStream->read(buffer, 13);
+ _soundName = Common::String(buffer, 13);
+ animStream->skip(26);
+ animStream->read(buffer, 13);
+ Common::String fontResource(buffer, 13);
+
+ // TODO: Based on a weird usage of a flags word, a secondary method gets called here.
+ // Figure out secondary method, and when/if it's called
+
+ // Initialise the reference list
+ for (int i = 0; i < spriteListCount; ++i)
+ _spriteListIndexes.push_back(-1);
- // TODO: for now, we only load the first sprite series
- if (_seriesCount > 1)
- printf("TODO: Anim has %i sprite series, for now, we only load the first one\n", _seriesCount);
- _seriesCount = 1; // TODO
+ delete animStream;
- for (int i = 0; i < _seriesCount; i++) {
- animStream->read(buffer, 13);
- _spriteSeriesNames[i] = Common::String(buffer);
- //printf("%03d: %s\n", i, _spriteSeriesNames[i].c_str());
-
- spriteSeriesStream = _vm->res()->get(_spriteSeriesNames[i].c_str());
- _spriteSeries = new SpriteAsset(_vm, spriteSeriesStream,
- spriteSeriesStream->size(), _spriteSeriesNames[i].c_str());
- _vm->res()->toss(_spriteSeriesNames[i].c_str());
-
- // Adjust the palette of the sprites in the sprite series
- // so that they can be displayed on screen correctly
- RGBList *palData = new RGBList(_spriteSeries->getColorCount(), _spriteSeries->getPalette(), true);
- _vm->_palette->addRange(palData);
-
- for (int k = 0; k < _spriteSeries->getCount(); k++) {
- M4Sprite *spr = _spriteSeries->getFrame(k);
- spr->translate(palData); // sprite pixel translation
+ if (messagesCount > 0) {
+ // Chunk 2
+ // Following is a list of any messages for the animation
+
+ Common::SeekableReadStream *animStream = anim.getItemStream(streamIndex++);
+
+ for (int i = 0; i < messagesCount; ++i) {
+ AnimMessage rec;
+ animStream->read(rec.msg, 70);
+ rec.pos.x = animStream->readUint16LE();
+ rec.pos.y = animStream->readUint16LE();
+ animStream->readUint16LE();
+ rec.rgb1.r = animStream->readByte();
+ rec.rgb1.g = animStream->readByte();
+ rec.rgb1.b = animStream->readByte();
+ rec.rgb2.r = animStream->readByte();
+ rec.rgb2.g = animStream->readByte();
+ rec.rgb2.b = animStream->readByte();
+ rec.kernelMsgIndex = animStream->readUint16LE();
+ animStream->skip(6);
+ rec.startFrame = animStream->readUint16LE();
+ rec.endFrame = animStream->readUint16LE();
+ animStream->readUint16LE();
+
+ _messages.push_back(rec);
}
+
+ delete animStream;
}
- //printf("End pos: %i\n", animStream->pos());
+ if (frameEntryCount > 0) {
+ // Chunk 3: animation frame info
+ animStream = anim.getItemStream(streamIndex++);
+
+ for (int i = 0; i < frameEntryCount; i++) {
+ AnimFrameEntry rec;
+ rec.frameNumber = animStream->readUint16LE();
+ rec.seqIndex = animStream->readByte();
+ rec.spriteSlot.frameNumber = animStream->readUint16LE();
+ rec.spriteSlot.xp = animStream->readUint16LE();
+ rec.spriteSlot.yp = animStream->readUint16LE();
+ rec.spriteSlot.depth = animStream->readUint16LE();
+ rec.spriteSlot.scale = animStream->readUint16LE();
+
+ _frameEntries.push_back(rec);
+ }
+
+ delete animStream;
+ }
- delete animStream;
+ if (miscEntriesCount > 0) {
+ // Chunk 4: Misc Data
+ animStream = anim.getItemStream(streamIndex);
- // ------------------
-
- // Chunk 2: anim info
- AnimationFrame frame;
- animStream = anim.getItemStream(1);
- //printf("Chunk 1, size %i\n", animStream->size());
-
- _frameEntries = new AnimationFrame[_frameEntryCount];
-
- for (int i = 0; i < _frameEntryCount; i++) {
-
- frame.animFrameIndex = animStream->readUint16LE();
- frame.u = animStream->readByte();
- frame.seriesIndex = animStream->readByte();
- frame.seriesFrameIndex = animStream->readUint16LE();
- frame.x = animStream->readUint16LE();
- frame.y = animStream->readUint16LE();
- frame.v = animStream->readByte();
- frame.w = animStream->readByte();
-
- _frameEntries[i] = frame;
-
- /*
- printf(
- "animFrameIndex = %4d, "
- "u = %3d, "
- "seriesIndex = %3d, "
- "seriesFrameIndex = %6d, "
- "x = %3d, "
- "y = %3d, "
- "v = %3d, "
- "w = %3d\n",
-
- frame.animFrameIndex,
- frame.u,
- frame.seriesIndex,
- frame.seriesFrameIndex,
- frame.x,
- frame.y,
- frame.v,
- frame.w
- );
- */
- }
- //printf("End pos: %i\n", animStream->pos());
+ for (int i = 0; i < miscEntriesCount; ++i) {
+ AnimMiscEntry rec;
+ rec.soundNum = animStream->readUint16LE();
+ rec.numTicks = animStream->readUint16LE();
+ rec.posAdjust.x = animStream->readUint16LE();
+ rec.posAdjust.y = animStream->readUint16LE();
+ animStream->readUint16LE();
- delete animStream;
+ _miscEntries.push_back(rec);
+ }
- // Chunk 3: unknown (seems to be sound data?)
- // TODO
-}
+ delete animStream;
+ }
-Animation::~Animation() {
- //delete[] _spriteSeriesNames;
- //delete[] _spriteSeries;
- //delete[] _frameEntries;
+ // If the animation specifies a font, then load it for access
+ if (_flags & ANIM_CUSTOM_FONT) {
+ Common::String fontName;
+ if (madsRes)
+ fontName += "*";
+ fontName += fontResource;
+
+ _font = _vm->_font->getFont(fontName);
+ }
+
+ // Load all the sprite sets for the animation
+ for (int i = 0; i < spriteListCount; ++i) {
+ _spriteListIndexes[i] = _view->_spriteSlots.addSprites(_spriteSetNames[i].c_str());
+ }
+
+
+ if (_field12) {
+ Common::String resName;
+ if (madsRes)
+ resName += "*";
+ resName += _spriteSetNames[_spriteListIndex];
+
+ _spriteListIndexes[_spriteListIndex] = _view->_spriteSlots.addSprites(resName.c_str());
+ }
+
+ // TODO: Unknown section about handling palette entries - I think it's adjusting sprite sets
+ // to the palette of the game screen
+
+ // Process the sprite list indexes to remap them to the actual sprite list indexes
+
}
-void Animation::start() {
- _curFrame = 0;
- _curFrameEntry = 0;
+void MadsAnimation::start() {
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
//for (int i = 0; i < _seriesCount; i++) {
//_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str());
//}
_playing = true;
- updateAnim();
+ update();
}
-bool Animation::updateAnim() {
+bool MadsAnimation::update() {
if (!_playing)
return true;
- // Get the scene background surface
- M4Surface *bg = _vm->_scene->getBackgroundSurface();
+ if (_field12) {
+ int spriteListIndex = _spriteListIndexes[_spriteListIndex];
+ int newIndex = -1;
+
+ for (uint idx = _oldFrameEntry; idx < _frameEntries.size(); ++idx) {
+ if (_frameEntries[idx].frameNumber > _currentFrame)
+ break;
+ if (_frameEntries[idx].spriteSlot.spriteListIndex == spriteListIndex)
+ newIndex = _frameEntries[idx].spriteSlot.frameNumber;
+ }
+
+ if (newIndex >= 0)
+ load1(newIndex);
+ }
+
+ // If it's not time for the next frame, then exit
+ if (_madsVm->_currentTimer < _nextFrameTimer)
+ return false;
- while (_frameEntries[_curFrameEntry].animFrameIndex == _curFrame) {
- AnimationFrame *frame = &_frameEntries[_curFrameEntry];
- int seriesFrameIndex = (frame->seriesFrameIndex & 0x7FFF) - 1;
+ // Loop checks for any prior animation sprite slots to be expired
+ for (int slotIndex = 0; slotIndex < _view->_spriteSlots.startIndex; ++slotIndex) {
+ if ((_view->_spriteSlots[slotIndex].seqIndex >= 0x80) &&
+ (_view->_spriteSlots[slotIndex].seqIndex <= 0xFD)) {
+ // Flag the frame as animation sprite slot
+ _view->_spriteSlots[slotIndex].spriteType = EXPIRED_SPRITE;
+ }
+ }
+
+ // Validate the current frame
+ if (_currentFrame > (int)_miscEntries.size()) {
+ // Is the animation allowed to be repeated?
+ if (_resetFlag) {
+ _currentFrame = 0;
+ _oldFrameEntry = 0;
+ } else {
+ _unk1 = true;
+ return true;
+ }
+ }
+
+ // Handle starting any sound for this frame
+ AnimMiscEntry &misc = _miscEntries[_currentFrame];
+ if (misc.soundNum)
+ _vm->_sound->playSound(misc.soundNum);
+
+ bool screenChanged = false;
- // Write the sprite onto the screen
- M4Sprite *spr = _spriteSeries->getFrame(seriesFrameIndex);
+ // Handle any scrolling of the screen surface
+ if ((_scrollX != 0) || (_scrollY != 0)) {
+ _view->_bgSurface->scrollX(_scrollX);
+ _view->_bgSurface->scrollY(_scrollY);
- // FIXME: correct x, y
- spr->copyTo(bg, frame->x, frame->y, (int)spr->getTransparentColor());
+ screenChanged = true;
+ }
- // HACK: wait a bit
- g_system->delayMillis(100);
+ // Handle any offset adjustment for sprites as of this frame
+ if (_view->_posAdjust.x != misc.posAdjust.x) {
+ misc.posAdjust.x = _view->_posAdjust.x;
+ screenChanged = true;
+ }
+ if (_view->_posAdjust.y != misc.posAdjust.y) {
+ misc.posAdjust.y = _view->_posAdjust.y;
+ screenChanged = true;
+ }
+ if (screenChanged) {
+ // Signal the entire screen needs refreshing
+ _view->_spriteSlots.fullRefresh();
+ }
- //printf("_curFrameEntry = %d\n", _curFrameEntry);
- _curFrameEntry++;
+ int spriteSlotsMax = _view->_spriteSlots.startIndex;
+
+ // Main frame animation loop - frames get animated by being placed, as necessary, into the
+ // main sprite slot array
+ while ((uint)_oldFrameEntry < _frameEntries.size()) {
+ if (_frameEntries[_oldFrameEntry].frameNumber > _currentFrame)
+ break;
+ else if (_frameEntries[_oldFrameEntry].frameNumber == _currentFrame) {
+ // Found the correct frame
+ int spriteSlotIndex = 0;
+ int index = 0;
+
+ for (;;) {
+ if ((spriteSlotIndex == 0) && (index < spriteSlotsMax)) {
+ int seqIndex = _frameEntries[_oldFrameEntry].seqIndex - _view->_spriteSlots[index].seqIndex;
+ if (seqIndex == 0x80) {
+ if (_view->_spriteSlots[index] == _frameEntries[_oldFrameEntry].spriteSlot)
+ _view->_spriteSlots[index].spriteType = SPRITE_ZERO;
+ }
+ ++index;
+ continue;
+ }
+
+ if (spriteSlotIndex == 0) {
+ int slotIndex = _view->_spriteSlots.getIndex();
+ _view->_spriteSlots[slotIndex].copy(_frameEntries[_oldFrameEntry].spriteSlot);
+ _view->_spriteSlots[slotIndex].seqIndex += 0x80;
+
+ SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(
+ _view->_spriteSlots[slotIndex].spriteListIndex);
+
+ _view->_spriteSlots[slotIndex].spriteType = (spriteSet.getAssetType() == 0) ?
+ SPRITE_FOUR : SPRITE_ZERO;
+ }
+ break;
+ }
+ }
+
+ ++_oldFrameEntry;
}
- //printf("_curFrame = %d\n", _curFrame);
+ // Handle the display of any messages
+ for (uint idx = 0; idx < _messages.size(); ++idx) {
+ if (_messages[idx].kernelMsgIndex >= 0) {
+ // Handle currently active message
+ if ((_currentFrame < _messages[idx].startFrame) || (_currentFrame > _messages[idx].endFrame)) {
+ _view->_kernelMessages.remove(_messages[idx].kernelMsgIndex);
+ _messages[idx].kernelMsgIndex = -1;
+ --_messageCtr;
+ }
+ } else if ((_currentFrame >= _messages[idx].startFrame) && (_currentFrame <= _messages[idx].endFrame)) {
+ // Start displaying the message
+ AnimMessage &me = _messages[idx];
+
+ // The colour index to use is dependant on how many messages are currently on-screen
+ uint8 colIndex;
+ switch (_messageCtr) {
+ case 1:
+ colIndex = 252;
+ break;
+ case 2:
+ colIndex = 16;
+ break;
+ default:
+ colIndex = 250;
+ break;
+ }
+
+ _vm->_palette->setEntry(colIndex, me.rgb1.r, me.rgb1.g, me.rgb1.b);
+ _vm->_palette->setEntry(colIndex + 1, me.rgb2.r, me.rgb2.g, me.rgb2.b);
+
+ // Add a kernel message to display the given text
+ me.kernelMsgIndex = _view->_kernelMessages.add(me.pos, colIndex * 101, 0, 0, INDEFINITE_TIMEOUT, me.msg);
+ ++_messageCtr;
+ }
+ }
- _curFrame++;
- if (_curFrame >= _frameCount) // anim done
+ // Move to the next frame
+ _currentFrame++;
+ if (_currentFrame >= (int)_miscEntries.size()) {
+ // Animation is complete
stop();
- return _curFrame >= _frameCount;
+ if (_abortTimers != 0) {
+ _view->_abortTimers = _abortTimers;
+ _view->_abortTimersMode = _abortMode;
+
+ if (_abortMode != ABORTMODE_1) {
+ // Copy the noun list
+ for (int i = 0; i < 3; ++i)
+ _madsVm->scene()->actionNouns[i] = _actionNouns[i];
+ }
+ }
+ }
+
+ int frameNum = MIN(_currentFrame, (int)_miscEntries.size() - 1);
+ _nextFrameTimer = _madsVm->_currentTimer + _miscEntries[frameNum].numTicks;
+
+ return _currentFrame >= (int)_miscEntries.size();
}
-void Animation::stop() {
+void MadsAnimation::stop() {
_playing = false;
+}
- for (int i = 0; i < _seriesCount; i++) {
- // TODO: cleanup
- //delete _spriteSeries[i];
- //_spriteSeries[i] = NULL;
+void MadsAnimation::setCurrentFrame(int frameNumber) {
+ _currentFrame = frameNumber;
+ _oldFrameEntry = 0;
+ _unk1 = 0;
+}
+
+void MadsAnimation::load1(int frameNumber) {
+ if (_skipLoad)
+ return;
+
+ Common::Point pt;
+ int listIndex = _spriteListIndexes[_spriteListIndex];
+ SpriteAsset &spriteSet = _view->_spriteSlots.getSprite(listIndex);
+
+ if (_unkIndex < 0) {
+ M4Surface *frame = spriteSet.getFrame(0);
+ pt.x = frame->bounds().left;
+ pt.y = frame->bounds().top;
+ } else {
+ pt.x = _unkList[_unkIndex].x;
+ pt.y = _unkList[_unkIndex].y;
+ _unkIndex = 1 - _unkIndex;
}
+
+ if (proc1(spriteSet, pt, frameNumber))
+ error("proc1 failure");
+
+
+}
+
+bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber) {
+ return 0;
}
} // End of namespace M4
diff --git a/engines/m4/animation.h b/engines/m4/animation.h
index c8be7f5cb3..b7e88f0871 100644
--- a/engines/m4/animation.h
+++ b/engines/m4/animation.h
@@ -29,39 +29,90 @@
#include "m4/m4.h"
#include "m4/graphics.h"
#include "m4/assets.h"
+#include "m4/mads_views.h"
+#include "common/array.h"
namespace M4 {
-struct AnimationFrame {
- uint16 animFrameIndex;
- byte u;
- byte seriesIndex;
- uint16 seriesFrameIndex;
- uint16 x, y;
- byte v, w;
+class MadsView;
+class SpriteSlotSubset;
+
+class AnimMessage {
+public:
+ char msg[70];
+ Common::Point pos;
+ RGB8 rgb1, rgb2;
+ int kernelMsgIndex;
+
+ int startFrame, endFrame;
+};
+
+class AnimFrameEntry {
+public:
+ int frameNumber;
+ int seqIndex;
+ SpriteSlotSubset spriteSlot;
};
-class Animation {
- public:
- Animation(MadsM4Engine *vm);
- ~Animation();
-
- void load(const char *filename);
- void loadFullScreen(const char *filename);
- void start();
- bool updateAnim();
- void stop();
-
- private:
- bool _playing;
- MadsM4Engine *_vm;
- int _seriesCount;
- int _frameCount;
- int _frameEntryCount;
- AnimationFrame *_frameEntries;
- Common::String *_spriteSeriesNames;
- SpriteAsset *_spriteSeries;
- int _curFrame, _curFrameEntry;
+class AnimMiscEntry {
+public:
+ int soundNum;
+ int numTicks;
+ Common::Point posAdjust;
+};
+
+#define ANIM_SPRITE_SET_SIZE 50
+
+enum MadsAnimationFlags {ANIM_CUSTOM_FONT = 0x20};
+
+class MadsAnimation: public Animation {
+private:
+ bool _playing;
+ MadsView *_view;
+
+ int _spriteListCount;
+ Common::Array<AnimMessage> _messages;
+ Common::Array<AnimFrameEntry> _frameEntries;
+ Common::Array<AnimMiscEntry> _miscEntries;
+ Font *_font;
+
+ uint8 _flags;
+ int _animMode;
+ int _roomNumber;
+ bool _field12;
+ int _spriteListIndex;
+ int _scrollX;
+ int _scrollY;
+ Common::String _field24;
+ Common::String _spriteSetNames[10];
+ Common::String _lbmFilename;
+ Common::String _spritesFilename;
+ Common::String _soundName;
+ Common::Array<int> _spriteListIndexes;
+
+ int _currentFrame, _oldFrameEntry;
+ bool _resetFlag;
+ int _unk1;
+ bool _skipLoad;
+ int _unkIndex;
+ Common::Point _unkList[2];
+ uint32 _nextFrameTimer;
+ int _messageCtr;
+ int _abortTimers;
+ AbortTimerMode _abortMode;
+ uint16 _actionNouns[3];
+
+ void load1(int frameNumber);
+ bool MadsAnimation::proc1(SpriteAsset &spriteSet, const Common::Point &pt, int frameNumber);
+public:
+ MadsAnimation(MadsM4Engine *vm, MadsView *view);
+ ~MadsAnimation();
+
+ virtual void load(const Common::String &filename);
+ virtual void start();
+ virtual bool update();
+ virtual void stop();
+ virtual void setCurrentFrame(int frameNumber);
};
} // End of namespace M4
diff --git a/engines/m4/assets.cpp b/engines/m4/assets.cpp
index 14857e6f2b..91c371dec5 100644
--- a/engines/m4/assets.cpp
+++ b/engines/m4/assets.cpp
@@ -30,13 +30,13 @@
namespace M4 {
-BaseAsset::BaseAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : _vm(vm) {
+BaseAsset::BaseAsset(MadsM4Engine *vm) : _vm(vm) {
}
BaseAsset::~BaseAsset() {
}
-MachineAsset::MachineAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+MachineAsset::MachineAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
uint32 stateCount = stream->readUint32LE();
for (uint32 curState = 0; curState < stateCount; curState++) {
uint32 stateOffset = stream->readUint32LE();
@@ -61,7 +61,7 @@ uint32 MachineAsset::getStateOffset(uint32 state) {
return _stateTable[state];
}
-SequenceAsset::SequenceAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+SequenceAsset::SequenceAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
_localVarCount = stream->readUint32LE();
_codeSize = size - 4;
_code = new byte[_codeSize];
@@ -78,7 +78,7 @@ void SequenceAsset::getCode(byte *&code, uint32 &codeSize) {
}
-DataAsset::DataAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+DataAsset::DataAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm) {
_recCount = stream->readUint32LE();
_recSize = stream->readUint32LE();
@@ -98,7 +98,8 @@ long *DataAsset::getRow(int index) {
return &_data[_recSize * index];
}
-SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) : BaseAsset(vm, stream, size, name) {
+SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) :
+ BaseAsset(vm) {
_stream = stream;
_palInterface = NULL;
_paletteData = NULL;
@@ -110,6 +111,20 @@ SpriteAsset::SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, i
}
}
+SpriteAsset::SpriteAsset(MadsM4Engine *vm, const char *name): BaseAsset(vm) {
+ _stream = vm->res()->get(name);
+ _palInterface = NULL;
+ _paletteData = NULL;
+
+ if (_vm->isM4()) {
+ loadM4SpriteAsset(vm, _stream, true);
+ } else {
+ loadMadsSpriteAsset(vm, _stream);
+ }
+
+ vm->res()->toss(name);
+}
+
SpriteAsset::~SpriteAsset() {
if (_palInterface) {
// Internally stored palette translation data, so release it
diff --git a/engines/m4/assets.h b/engines/m4/assets.h
index cd0ae6ba78..816a8dcff0 100644
--- a/engines/m4/assets.h
+++ b/engines/m4/assets.h
@@ -49,7 +49,7 @@ class Palette;
class BaseAsset {
public:
- BaseAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
+ BaseAsset(MadsM4Engine *vm);
~BaseAsset();
const Common::String getName() const { return _name; }
protected:
@@ -103,6 +103,7 @@ struct SpriteAssetFrame {
class SpriteAsset : public BaseAsset {
public:
SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream = false);
+ SpriteAsset(MadsM4Engine *vm, const char *name);
~SpriteAsset();
void loadM4SpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream, bool asStream);
void loadMadsSpriteAsset(MadsM4Engine *vm, Common::SeekableReadStream* stream);
diff --git a/engines/m4/console.cpp b/engines/m4/console.cpp
index 0c2e80df0e..d568584d30 100644
--- a/engines/m4/console.cpp
+++ b/engines/m4/console.cpp
@@ -47,7 +47,6 @@ Console::Console(MadsM4Engine *vm) : GUI::Debugger() {
DCmd_Register("start_conv", WRAP_METHOD(Console, cmdStartConversation));
DCmd_Register("textview", WRAP_METHOD(Console, cmdShowTextview));
DCmd_Register("animview", WRAP_METHOD(Console, cmdShowAnimview));
- DCmd_Register("anim", WRAP_METHOD(Console, cmdPlayAnimation));
}
Console::~Console() {
@@ -247,33 +246,6 @@ bool Console::cmdShowAnimview(int argc, const char **argv) {
return false;
}
-bool Console::cmdPlayAnimation(int argc, const char **argv) {
- View *view = _vm->_viewManager->getView(VIEWID_SCENE);
- if (view == NULL) {
- DebugPrintf("The scene view isn't currently active\n");
- } else if (argc != 2 && argc != 3) {
- DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
- DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
- } else {
- char resourceName[20];
- strncpy(resourceName, argv[1], 15);
- resourceName[15] = '\0';
- if (!strchr(resourceName, '.'))
- strcat(resourceName, ".AA");
-
- _vm->_viewManager->moveToFront(view);
- if (argc == 3 && atoi(argv[2]) == 1)
- _vm->_animation->loadFullScreen(resourceName);
- else
- _vm->_animation->load(resourceName);
- _vm->_animation->start();
- view->restore(0, 0, view->width(), view->height());
- return false;
- }
-
- return true;
-}
-
/*--------------------------------------------------------------------------*/
MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
@@ -282,6 +254,7 @@ MadsConsole::MadsConsole(MadsEngine *vm): Console(vm) {
DCmd_Register("object", WRAP_METHOD(MadsConsole, cmdObject));
DCmd_Register("message", WRAP_METHOD(MadsConsole, cmdMessage));
DCmd_Register("scene_info", WRAP_METHOD(MadsConsole, cmdSceneInfo));
+ DCmd_Register("anim", WRAP_METHOD(MadsConsole, cmdPlayAnimation));
}
bool MadsConsole::cmdObject(int argc, const char **argv) {
@@ -386,6 +359,34 @@ bool MadsConsole::cmdSceneInfo(int argc, const char **argv) {
return true;
}
+bool MadsConsole::cmdPlayAnimation(int argc, const char **argv) {
+ View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+ if (view == NULL) {
+ DebugPrintf("The scene view isn't currently active\n");
+ } else if (argc != 2 && argc != 3) {
+ DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
+ DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
+ } else {
+ char resourceName[20];
+ strncpy(resourceName, argv[1], 15);
+ resourceName[15] = '\0';
+ if (!strchr(resourceName, '.'))
+ strcat(resourceName, ".AA");
+
+ _vm->_viewManager->moveToFront(view);
+ if (argc == 3 && atoi(argv[2]) == 1)
+ _madsVm->scene()->_sceneAnimation.loadFullScreen(resourceName);
+ else
+ _madsVm->scene()->_sceneAnimation.load(resourceName);
+ _madsVm->scene()->_sceneAnimation.start();
+
+ view->restore(0, 0, view->width(), view->height());
+ return false;
+ }
+
+ return true;
+}
+
/*--------------------------------------------------------------------------*/
M4Console::M4Console(M4Engine *vm): Console(vm) {
diff --git a/engines/m4/console.h b/engines/m4/console.h
index b592f041cf..53a47dada9 100644
--- a/engines/m4/console.h
+++ b/engines/m4/console.h
@@ -50,7 +50,6 @@ private:
bool cmdStartConversation(int argc, const char **argv);
bool cmdShowTextview(int argc, const char **argv);
bool cmdShowAnimview(int argc, const char **argv);
- bool cmdPlayAnimation(int argc, const char **argv);
public:
Console(MadsM4Engine *vm);
@@ -64,6 +63,8 @@ private:
bool cmdObject(int argc, const char **argv);
bool cmdMessage(int argc, const char **argv);
bool cmdSceneInfo(int argc, const char **argv);
+ bool cmdPlayAnimation(int argc, const char **argv);
+
public:
MadsConsole(MadsEngine *vm);
virtual ~MadsConsole() {}
diff --git a/engines/m4/m4.cpp b/engines/m4/m4.cpp
index 2024138f67..da271b10c9 100644
--- a/engines/m4/m4.cpp
+++ b/engines/m4/m4.cpp
@@ -145,7 +145,6 @@ MadsM4Engine::~MadsM4Engine() {
delete _script;
delete _ws;
delete _random;
- delete _animation;
delete _palette;
}
@@ -184,7 +183,6 @@ Common::Error MadsM4Engine::run() {
_sound = new Sound(this, _mixer, 255);
_script = new ScriptInterpreter(this);
_ws = new WoodScript(this);
- _animation = new Animation(this);
//_callbacks = new Callbacks(this);
_random = new Common::RandomSource();
g_eventRec.registerRandomSource(*_random, "m4");
@@ -581,8 +579,6 @@ Common::Error MadsEngine::run() {
while (!_events->quitFlag) {
eventHandler();
- _animation->updateAnim();
-
if (g_system->getMillis() >= nextFrame) {
nextFrame = g_system->getMillis() + GAME_FRAME_DELAY;
++_currentTimer;
diff --git a/engines/m4/m4.h b/engines/m4/m4.h
index 23204f2228..9937107668 100644
--- a/engines/m4/m4.h
+++ b/engines/m4/m4.h
@@ -200,7 +200,6 @@ public:
Rails *_rails;
ScriptInterpreter *_script;
WoodScript *_ws;
- Animation *_animation;
Common::RandomSource *_random;
Scene *scene() { return _scene; }
diff --git a/engines/m4/mads_views.cpp b/engines/m4/mads_views.cpp
index 3b5ba9e24c..e66b1d8d41 100644
--- a/engines/m4/mads_views.cpp
+++ b/engines/m4/mads_views.cpp
@@ -24,6 +24,7 @@
*/
#include "m4/m4_views.h"
+#include "m4/animation.h"
#include "m4/dialogs.h"
#include "m4/events.h"
#include "m4/font.h"
@@ -43,6 +44,22 @@ static const int SCROLLER_DELAY = 200;
//--------------------------------------------------------------------------
+bool MadsSpriteSlot::operator==(const SpriteSlotSubset &other) const {
+ return (spriteListIndex == other.spriteListIndex) && (frameNumber == other.frameNumber) &&
+ (xp == other.xp) && (yp == other.yp) && (depth == other.depth) && (scale == other.scale);
+}
+
+void MadsSpriteSlot::copy(const SpriteSlotSubset &other) {
+ spriteListIndex = other.spriteListIndex;
+ frameNumber = other.frameNumber;
+ xp = other.xp;
+ yp = other.yp;
+ depth = other.depth;
+ scale = other.scale;
+}
+
+//--------------------------------------------------------------------------
+
MadsSpriteSlots::MadsSpriteSlots(MadsView &owner): _owner(owner) {
for (int i = 0; i < SPRITE_SLOTS_SIZE; ++i) {
MadsSpriteSlot rec;
@@ -74,6 +91,7 @@ int MadsSpriteSlots::addSprites(const char *resName) {
Common::SeekableReadStream *data = _vm->res()->get(resName);
SpriteAsset *spriteSet = new SpriteAsset(_vm, data, data->size(), resName);
spriteSet->translate(_madsVm->_palette);
+ assert(spriteSet != NULL);
_sprites.push_back(SpriteList::value_type(spriteSet));
_vm->res()->toss(resName);
@@ -1125,8 +1143,20 @@ void MadsSequenceList::setAnimRange(int seqIndex, int startVal, int endVal) {
//--------------------------------------------------------------------------
+Animation::Animation(MadsM4Engine *vm): _vm(vm) {
+}
+
+void Animation::loadFullScreen(const Common::String &filename) {
+ _vm->_palette->deleteAllRanges();
+ load(filename);
+}
+
+//--------------------------------------------------------------------------
+
MadsView::MadsView(View *view): _view(view), _dynamicHotspots(*this), _sequenceList(*this),
- _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this) {
+ _kernelMessages(*this), _spriteSlots(*this), _dirtyAreas(*this), _textDisplay(*this),
+ // FIXME: There's probably a cleaner way to do this, and I don't think the destructor is ever called
+ _sceneAnimation(*new MadsAnimation(_vm, this)) {
_textSpacing = -1;
_ticksAmount = 3;
_newTimeout = 0;
diff --git a/engines/m4/mads_views.h b/engines/m4/mads_views.h
index 1661bac3df..6d6d576263 100644
--- a/engines/m4/mads_views.h
+++ b/engines/m4/mads_views.h
@@ -43,6 +43,16 @@ class MadsView;
enum AbortTimerMode {ABORTMODE_0 = 0, ABORTMODE_1 = 1, ABORTMODE_2 = 2};
+class SpriteSlotSubset {
+public:
+ int spriteListIndex;
+ int frameNumber;
+ int xp;
+ int yp;
+ int depth;
+ int scale;
+};
+
class MadsSpriteSlot {
public:
int spriteType;
@@ -55,12 +65,16 @@ public:
int scale;
MadsSpriteSlot() { }
+
+ bool operator==(const SpriteSlotSubset &other) const;
+ void copy(const SpriteSlotSubset &other);
};
#define SPRITE_SLOTS_SIZE 50
enum SpriteIdSpecial {
- BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, FOREGROUND_SPRITE = 1, EXPIRED_SPRITE = -1
+ BACKGROUND_SPRITE = -4, FULL_SCREEN_REFRESH = -2, EXPIRED_SPRITE = -1, SPRITE_ZERO = 0, FOREGROUND_SPRITE = 1,
+ SPRITE_FOUR = 4
};
typedef Common::Array<Common::SharedPtr<SpriteAsset> > SpriteList;
@@ -138,7 +152,7 @@ public:
};
#define TIMED_TEXT_SIZE 10
-#define TEXT_4A_SIZE 30
+#define INDEFINITE_TIMEOUT 9999999
enum KernelMessageFlags {KMSG_QUOTED = 1, KMSG_OWNER_TIMEOUT = 2, KMSG_SEQ_ENTRY = 4, KMSG_SCROLL = 8, KMSG_RIGHT_ALIGN = 0x10,
KMSG_CENTER_ALIGN = 0x20, KMSG_EXPIRE = 0x40, KMSG_ACTIVE = 0x80};
@@ -352,10 +366,26 @@ public:
void setAnimRange(int seqIndex, int startVal, int endVal);
};
+class Animation {
+protected:
+ MadsM4Engine *_vm;
+public:
+ Animation(MadsM4Engine *vm);
+ void loadFullScreen(const Common::String &filename);
+
+ virtual void load(const Common::String &filename) = 0;
+ virtual void start() = 0;
+ virtual bool update() = 0;
+ virtual void stop() = 0;
+ virtual void setCurrentFrame(int frameNumber) = 0;
+};
+
+
class MadsView {
private:
View *_view;
public:
+ Animation &_sceneAnimation;
MadsSpriteSlots _spriteSlots;
MadsTextDisplay _textDisplay;
MadsKernelMessageList _kernelMessages;