aboutsummaryrefslogtreecommitdiff
path: root/engines/draci
diff options
context:
space:
mode:
authorRobert Špalek2009-11-07 01:28:27 +0000
committerRobert Špalek2009-11-07 01:28:27 +0000
commit357d9989d4c6ae73e02a044b388f36069e093ce0 (patch)
tree06d8453b5babaa0c5a844ff0f31e56652276c665 /engines/draci
parentfdad4e7b543af2debcc35492e46c979ab1dd8fec (diff)
downloadscummvm-rg350-357d9989d4c6ae73e02a044b388f36069e093ce0.tar.gz
scummvm-rg350-357d9989d4c6ae73e02a044b388f36069e093ce0.tar.bz2
scummvm-rg350-357d9989d4c6ae73e02a044b388f36069e093ce0.zip
Implemented relative animations.
In these animations, each sprite can specify a relative shift with respect to the previous sprite. Moving animations (such as walking of the dragon) are easily described in this framework. I have sort of hacked their support and it seems to work. The current walking code does not interact with the new code yet, but it will be easy to do. svn-id: r45712
Diffstat (limited to 'engines/draci')
-rw-r--r--engines/draci/animation.cpp49
-rw-r--r--engines/draci/animation.h9
-rw-r--r--engines/draci/game.cpp10
-rw-r--r--engines/draci/walking.cpp3
4 files changed, 56 insertions, 15 deletions
diff --git a/engines/draci/animation.cpp b/engines/draci/animation.cpp
index 674e2473df..9d56c89674 100644
--- a/engines/draci/animation.cpp
+++ b/engines/draci/animation.cpp
@@ -33,6 +33,7 @@ Animation::Animation(DraciEngine *vm, int index) : _vm(vm) {
_id = kUnused;
_index = index;
_z = 0;
+ clearShift();
_displacement = kNoDisplacement;
_playing = false;
_looping = false;
@@ -56,6 +57,13 @@ void Animation::setRelative(int relx, int rely) {
_displacement.relY = rely;
}
+Displacement Animation::getCurrentFrameDisplacement() const {
+ Displacement dis = _displacement;
+ dis.relX += (int) (dis.extraScaleX * _shift.x);
+ dis.relY += (int) (dis.extraScaleY * _shift.y);
+ return dis;
+}
+
void Animation::setLooping(bool looping) {
_looping = looping;
debugC(7, kDraciAnimationDebugLevel, "Setting looping to %d on animation %d",
@@ -67,8 +75,8 @@ void Animation::markDirtyRect(Surface *surface) const {
return;
// Fetch the current frame's rectangle
- Drawable *frame = _frames[_currentFrame];
- Common::Rect frameRect = frame->getRect(_displacement);
+ const Drawable *frame = getConstCurrentFrame();
+ Common::Rect frameRect = frame->getRect(getCurrentFrameDisplacement());
// Mark the rectangle dirty on the surface
surface->markDirtyRect(frameRect);
@@ -79,7 +87,7 @@ void Animation::nextFrame(bool force) {
if (getFrameCount() == 0 || !_playing)
return;
- Drawable *frame = _frames[_currentFrame];
+ const Drawable *frame = getConstCurrentFrame();
Surface *surface = _vm->_screen->getSurface();
if (force || (_tick + frame->getDelay() <= _vm->_system->getMillis())) {
@@ -92,7 +100,12 @@ void Animation::nextFrame(bool force) {
// Mark old frame dirty so it gets deleted
markDirtyRect(surface);
+ _shift.x += _relativeShifts[_currentFrame].x;
+ _shift.y += _relativeShifts[_currentFrame].y;
_currentFrame = nextFrameNum();
+ if (!_currentFrame) {
+ clearShift(); // TODO: don't do that, but rather let the animation fly away when needed.
+ }
_tick = _vm->_system->getMillis();
// Fetch new frame and mark it dirty
@@ -123,13 +136,15 @@ void Animation::drawFrame(Surface *surface) {
if (_frames.size() == 0 || !_playing)
return;
- const Drawable *frame = _frames[_currentFrame];
+ const Drawable *frame = getConstCurrentFrame();
if (_id == kOverlayImage) {
+ // No displacement or relative animations is supported.
frame->draw(surface, false, 0, 0);
} else {
- // Draw frame
- frame->drawReScaled(surface, false, _displacement);
+ // Draw frame: first shifted by the relative shift and then
+ // scaled/shifted by the given displacement.
+ frame->drawReScaled(surface, false, getCurrentFrameDisplacement());
}
const SoundSample *sample = _samples[_currentFrame];
@@ -164,6 +179,15 @@ void Animation::setScaleFactors(double scaleX, double scaleY) {
void Animation::addFrame(Drawable *frame, const SoundSample *sample) {
_frames.push_back(frame);
_samples.push_back(sample);
+ _relativeShifts.push_back(Common::Point(0, 0));
+}
+
+void Animation::makeLastFrameRelative(int x, int y) {
+ _relativeShifts.back() = Common::Point(x, y);
+}
+
+void Animation::clearShift() {
+ _shift = Common::Point(0, 0);
}
void Animation::replaceFrame(int i, Drawable *frame, const SoundSample *sample) {
@@ -171,6 +195,11 @@ void Animation::replaceFrame(int i, Drawable *frame, const SoundSample *sample)
_samples[i] = sample;
}
+const Drawable *Animation::getConstCurrentFrame() const {
+ // If there are no frames stored, return NULL
+ return _frames.size() > 0 ? _frames[_currentFrame] : NULL;
+}
+
Drawable *Animation::getCurrentFrame() {
// If there are no frames stored, return NULL
return _frames.size() > 0 ? _frames[_currentFrame] : NULL;
@@ -202,6 +231,7 @@ void Animation::deleteFrames() {
delete _frames[i];
_frames.pop_back();
}
+ _relativeShifts.clear();
_samples.clear();
}
@@ -280,6 +310,7 @@ void AnimationManager::stop(int id) {
// Reset the animation to the beginning
anim->setCurrentFrame(0);
+ anim->clearShift();
debugC(3, kDraciAnimationDebugLevel, "Stopping animation %d...", id);
}
@@ -499,19 +530,19 @@ int AnimationManager::getTopAnimationID(int x, int y) const {
continue;
}
- const Drawable *frame = anim->getCurrentFrame();
+ const Drawable *frame = anim->getConstCurrentFrame();
if (frame == NULL) {
continue;
}
- if (frame->getRect(anim->getDisplacement()).contains(x, y)) {
+ if (frame->getRect(anim->getCurrentFrameDisplacement()).contains(x, y)) {
if (frame->getType() == kDrawableText) {
retval = anim->getID();
} else if (frame->getType() == kDrawableSprite &&
- reinterpret_cast<const Sprite *>(frame)->getPixel(x, y, anim->getDisplacement()) != transparent) {
+ reinterpret_cast<const Sprite *>(frame)->getPixel(x, y, anim->getCurrentFrameDisplacement()) != transparent) {
retval = anim->getID();
}
diff --git a/engines/draci/animation.h b/engines/draci/animation.h
index 473e875941..9fd5a87f97 100644
--- a/engines/draci/animation.h
+++ b/engines/draci/animation.h
@@ -28,6 +28,7 @@
#include "draci/sprite.h"
#include "draci/sound.h"
+#include "common/rect.h"
namespace Draci {
@@ -75,11 +76,14 @@ public:
void addFrame(Drawable *frame, const SoundSample *sample);
void replaceFrame(int i, Drawable *frame, const SoundSample *sample);
+ const Drawable *getConstCurrentFrame() const;
Drawable *getCurrentFrame();
Drawable *getFrame(int frameNum);
void setCurrentFrame(uint frame);
uint currentFrameNum() const { return _currentFrame; }
uint getFrameCount() const { return _frames.size(); }
+ void makeLastFrameRelative(int x, int y);
+ void clearShift();
bool isPlaying() const { return _playing; }
void setPlaying(bool playing);
@@ -93,7 +97,8 @@ public:
void setRelative(int relx, int rely);
int getRelativeX() const { return _displacement.relX; }
int getRelativeY() const { return _displacement.relY; }
- const Displacement &getDisplacement() const { return _displacement; }
+ const Displacement &getDisplacement() const { return _displacement; } // displacement of the whole animation
+ Displacement getCurrentFrameDisplacement() const; // displacement of the current frame (includes _shift)
int getIndex() const { return _index; }
void setIndex(int index) { _index = index; }
@@ -132,6 +137,7 @@ private:
uint _currentFrame;
uint _z;
+ Common::Point _shift; // partial sum of _relativeShifts from the beginning of the animation until the current frame
bool _hasChangedFrame;
Displacement _displacement;
@@ -144,6 +150,7 @@ private:
/** Array of frames of the animation. The animation object owns these pointers.
*/
Common::Array<Drawable *> _frames;
+ Common::Array<Common::Point> _relativeShifts;
/** Array of samples played during the animation. The animation
* object doesn't own these pointers, but they are stored in the
* cache.
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp
index 15ec8028f4..ed5768fd42 100644
--- a/engines/draci/game.cpp
+++ b/engines/draci/game.cpp
@@ -1194,9 +1194,7 @@ int Game::loadAnimation(uint animNum, uint z) {
// into details.
animationReader.readByte();
const bool cyclic = animationReader.readByte();
-
- // FIXME: handle this properly
- animationReader.readByte(); // Relative field, not used
+ const bool relative = animationReader.readByte();
Animation *anim = _vm->_anims->addAnimation(animNum, z, false);
@@ -1216,7 +1214,8 @@ int Game::loadAnimation(uint animNum, uint z) {
// _spritesArchive is flushed when entering a room. All
// scripts in a room are responsible for loading their animations.
const BAFile *spriteFile = _vm->_spritesArchive->getFile(spriteNum);
- Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length, x, y, true);
+ Sprite *sp = new Sprite(spriteFile->_data, spriteFile->_length,
+ relative ? 0 : x, relative ? 0 : y, true);
// Some frames set the scaled dimensions to 0 even though other frames
// from the same animations have them set to normal values
@@ -1239,6 +1238,9 @@ int Game::loadAnimation(uint animNum, uint z) {
const SoundSample *sam = _vm->_soundsArchive->getSample(sample, freq);
anim->addFrame(sp, sam);
+ if (relative) {
+ anim->makeLastFrameRelative(x, y);
+ }
}
return animNum;
diff --git a/engines/draci/walking.cpp b/engines/draci/walking.cpp
index 4a0e65c9b3..9edffc6996 100644
--- a/engines/draci/walking.cpp
+++ b/engines/draci/walking.cpp
@@ -522,8 +522,9 @@ bool WalkingState::continueWalking() {
// We are walking in the middle of an edge. The animation phase has
// just changed. Update the position of the hero.
+ _position += 4; // TODO: compute shifts properly from the animation
Common::Point newPos = WalkingMap::interpolate(
- _path[_segment], _path[_segment+1], ++_position, _length);
+ _path[_segment], _path[_segment+1], _position, _length);
_vm->_game->setHeroPosition(newPos);
_vm->_game->positionAnimAsHero(anim);