aboutsummaryrefslogtreecommitdiff
path: root/engines/m4/animation.cpp
diff options
context:
space:
mode:
authorPaul Gilbert2010-05-31 12:10:30 +0000
committerPaul Gilbert2010-05-31 12:10:30 +0000
commit088e6456ea4d009b8ab0c91176c84dce34a8ea41 (patch)
tree0789fe834b9a6fd72ff90d276ec9912c4556134f /engines/m4/animation.cpp
parent3f4302214c334a590b8428fe7ae32c76e64b6ed5 (diff)
downloadscummvm-rg350-088e6456ea4d009b8ab0c91176c84dce34a8ea41.tar.gz
scummvm-rg350-088e6456ea4d009b8ab0c91176c84dce34a8ea41.tar.bz2
scummvm-rg350-088e6456ea4d009b8ab0c91176c84dce34a8ea41.zip
In progress work implementing the animation player
svn-id: r49347
Diffstat (limited to 'engines/m4/animation.cpp')
-rw-r--r--engines/m4/animation.cpp466
1 files changed, 343 insertions, 123 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