diff options
Diffstat (limited to 'engines/m4')
-rw-r--r-- | engines/m4/animation.cpp | 466 | ||||
-rw-r--r-- | engines/m4/animation.h | 107 | ||||
-rw-r--r-- | engines/m4/assets.cpp | 25 | ||||
-rw-r--r-- | engines/m4/assets.h | 3 | ||||
-rw-r--r-- | engines/m4/console.cpp | 57 | ||||
-rw-r--r-- | engines/m4/console.h | 3 | ||||
-rw-r--r-- | engines/m4/m4.cpp | 4 | ||||
-rw-r--r-- | engines/m4/m4.h | 1 | ||||
-rw-r--r-- | engines/m4/mads_views.cpp | 32 | ||||
-rw-r--r-- | engines/m4/mads_views.h | 34 |
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; |