From df18bc95834837f1f905bfe5613ffd43dfc908f9 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Mon, 2 Jul 2012 21:31:23 +0200 Subject: GOB: Implement parts of the Once Upon A Time end sequence We don't yet support GCT files, so texts are still missing. --- engines/gob/pregob/onceupon/onceupon.cpp | 103 +++++++++++++++++++++++++------ engines/gob/pregob/onceupon/onceupon.h | 10 ++- engines/gob/pregob/pregob.cpp | 62 ++++++++++++++++--- engines/gob/pregob/pregob.h | 37 +++++++++-- 4 files changed, 176 insertions(+), 36 deletions(-) diff --git a/engines/gob/pregob/onceupon/onceupon.cpp b/engines/gob/pregob/onceupon/onceupon.cpp index fb9629566c..aed1b45e02 100644 --- a/engines/gob/pregob/onceupon/onceupon.cpp +++ b/engines/gob/pregob/onceupon/onceupon.cpp @@ -264,14 +264,6 @@ void OnceUpon::setGameCursor() { setCursor(cursor, 105, 0, 120, 15, 0, 0); } -void OnceUpon::setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const { - ani.setAnimation(state); - ani.setMode(once ? ANIObject::kModeOnce : ANIObject::kModeContinuous); - ani.setPause(pause); - ani.setVisible(true); - ani.setPosition(); -} - void OnceUpon::drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y) const { @@ -374,6 +366,18 @@ Common::String OnceUpon::fixString(const Common::String &str) const { return str; } +enum ClownAnimation { + kClownAnimationStand = 0, + kClownAnimationCheer = 1, + kClownAnimationCry = 2 +}; + +const PreGob::AnimProperties OnceUpon::kClownAnimations[] = { + { 1, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 0, 0, ANIObject::kModeOnce , true, false, false, 0, 0}, + { 6, 0, ANIObject::kModeOnce , true, false, false, 0, 0} +}; + enum CopyProtectionState { kCPStateSetup, // Set up the screen kCPStateWaitUser, // Waiting for the user to pick a shape @@ -392,8 +396,10 @@ bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20 _vm->_video->drawPackedSprite("grille2.cmp", sprites[1]); // Load the clown animation - ANIFile ani (_vm, "grille.ani", 320); - ANIObject clown(ani); + ANIFile ani (_vm, "grille.ani", 320); + ANIList anims; + + loadAnims(anims, ani, 1, &kClownAnimations[kClownAnimationStand]); // Set the copy protection cursor setCursor(sprites[1], 5, 110, 20, 134, 3, 0); @@ -406,20 +412,20 @@ bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20 bool hasCorrect = false; while (!_vm->shouldQuit() && (state != kCPStateFinish)) { - clearAnim(clown); + clearAnim(anims); // Set up the screen if (state == kCPStateSetup) { animalShape = cpSetup(colors, shapes, obfuscate, sprites); - setAnimState(clown, kClownAnimationClownStand, false, false); + setAnim(*anims[0], kClownAnimations[kClownAnimationStand]); state = kCPStateWaitUser; } - drawAnim(clown); + drawAnim(anims); // If we're waiting for the clown and he finished, evaluate if we're finished - if (!clown.isVisible() && (state == kCPStateWaitClown)) + if (!anims[0]->isVisible() && (state == kCPStateWaitClown)) state = (hasCorrect || (--triesLeft == 0)) ? kCPStateFinish : kCPStateSetup; showCursor(); @@ -443,12 +449,14 @@ bool OnceUpon::doCopyProtection(const uint8 colors[7], const uint8 shapes[7 * 20 hasCorrect = guessedShape == animalShape; animalShape = -1; - setAnimState(clown, hasCorrect ? kClownAnimationClownCheer : kClownAnimationClownCry, true, false); + setAnim(*anims[0], kClownAnimations[hasCorrect ? kClownAnimationCheer : kClownAnimationCry]); state = kCPStateWaitClown; } } } + freeAnims(anims); + fadeOut(); hideCursor(); clearScreen(); @@ -625,6 +633,10 @@ void OnceUpon::showQuote() { fadeOut(); } +const PreGob::AnimProperties OnceUpon::kTitleAnimation = { + 8, 0, ANIObject::kModeContinuous, true, false, false, 0, 0 +}; + void OnceUpon::showTitle() { // Show the Once Upon A Time title animation // NOTE: This is currently only a mock-up. The real animation is in "ville.seq". @@ -639,15 +651,15 @@ void OnceUpon::showTitle() { _vm->_video->drawPackedSprite("ville.cmp", *_vm->_draw->_backSurface); _vm->_draw->forceBlit(); - ANIFile ani (_vm, "pres.ani", 320); - ANIObject title(ani); + ANIFile ani (_vm, "pres.ani", 320); + ANIList anims; - setAnimState(title, 8, false, false); + loadAnims(anims, ani, 1, &kTitleAnimation); playTitleMusic(); while (!_vm->shouldQuit()) { - redrawAnim(title); + redrawAnim(anims); fadeIn(); @@ -657,6 +669,8 @@ void OnceUpon::showTitle() { break; } + freeAnims(anims); + fadeOut(); stopTitleMusic(); } @@ -1349,9 +1363,58 @@ bool OnceUpon::sectionChapter7() { return true; } +const PreGob::AnimProperties OnceUpon::kSectionEndAnimations[] = { + { 0, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 6, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + { 9, 0, ANIObject::kModeContinuous, true, false, false, 0, 0}, + {11, 0, ANIObject::kModeContinuous, true, false, false, 0, 0} +}; + bool OnceUpon::sectionEnd() { - warning("OnceUpon::sectionEnd(): TODO"); + fadeOut(); + setGamePalette(9); + + _vm->_video->drawPackedSprite("cadre.cmp", *_vm->_draw->_backSurface); + + Surface endBackground(320, 200, 1); + _vm->_video->drawPackedSprite("fin.cmp", endBackground); + + _vm->_draw->_backSurface->blit(endBackground, 0, 0, 288, 137, 16, 50); + + ANIFile ani(_vm, "fin.ani", 320); + ANIList anims; + + loadAnims(anims, ani, ARRAYSIZE(kSectionEndAnimations), kSectionEndAnimations); + drawAnim(anims); + + _vm->_draw->forceBlit(); + + MenuAction action = kMenuActionNone; + while (!_vm->shouldQuit() && (action == kMenuActionNone)) { + redrawAnim(anims); + + fadeIn(); + + endFrame(true); + + int16 mouseX, mouseY; + MouseButtons mouseButtons; + + int16 key = checkInput(mouseX, mouseY, mouseButtons); + if ((key != 0) && (key != kKeyEscape)) + // Any key pressed => Quit + action = kMenuActionQuit; + + action = doIngameMenu(key, mouseButtons); + } + + freeAnims(anims); + + // Restart requested + if (action == kMenuActionRestart) + return false; + // Last scene. Even if we didn't explicitly request a quit, the game ends here _quit = true; return false; } diff --git a/engines/gob/pregob/onceupon/onceupon.h b/engines/gob/pregob/onceupon/onceupon.h index 0cae369758..caaf155d06 100644 --- a/engines/gob/pregob/onceupon/onceupon.h +++ b/engines/gob/pregob/onceupon/onceupon.h @@ -149,19 +149,23 @@ private: /** All general game sounds we know about. */ static const char *kSound[kSoundMAX]; + + static const AnimProperties kClownAnimations[]; + static const AnimProperties kTitleAnimation; + static const AnimProperties kSectionEndAnimations[]; + + /** Function pointer type for a section handler. */ typedef bool (OnceUpon::*SectionFunc)(); /** Section handler function. */ static const SectionFunc kSectionFuncs[kSectionCount]; + // -- General helpers -- void setGamePalette(uint palette); ///< Set a game palette. void setGameCursor(); ///< Set the default game cursor. - /** Set the state of an ANIObject. */ - void setAnimState(ANIObject &ani, uint16 state, bool once, bool pause) const; - /** Draw this sprite in a fancy, animated line-by-line way. */ void drawLineByLine(const Surface &src, int16 left, int16 top, int16 right, int16 bottom, int16 x, int16 y) const; diff --git a/engines/gob/pregob/pregob.cpp b/engines/gob/pregob/pregob.cpp index 675958035d..4ee5430de7 100644 --- a/engines/gob/pregob/pregob.cpp +++ b/engines/gob/pregob/pregob.cpp @@ -251,24 +251,70 @@ bool PreGob::hasInput() { return checkInput(mouseX, mouseY, mouseButtons) || (mouseButtons != kMouseButtonsNone); } -void PreGob::clearAnim(ANIObject &ani) { +void PreGob::clearAnim(ANIObject &anim) { int16 left, top, right, bottom; - if (ani.clear(*_vm->_draw->_backSurface, left, top, right, bottom)) + if (anim.clear(*_vm->_draw->_backSurface, left, top, right, bottom)) _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); } -void PreGob::drawAnim(ANIObject &ani) { +void PreGob::drawAnim(ANIObject &anim) { int16 left, top, right, bottom; - if (ani.draw(*_vm->_draw->_backSurface, left, top, right, bottom)) + if (anim.draw(*_vm->_draw->_backSurface, left, top, right, bottom)) _vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom); - ani.advance(); + anim.advance(); } -void PreGob::redrawAnim(ANIObject &ani) { - clearAnim(ani); - drawAnim(ani); +void PreGob::redrawAnim(ANIObject &anim) { + clearAnim(anim); + drawAnim(anim); +} + +void PreGob::clearAnim(const ANIList &anims) { + for (int i = (anims.size() - 1); i >= 0; i--) + clearAnim(*anims[i]); +} + +void PreGob::drawAnim(const ANIList &anims) { + for (ANIList::const_iterator a = anims.begin(); a != anims.end(); ++a) + drawAnim(**a); +} + +void PreGob::redrawAnim(const ANIList &anims) { + clearAnim(anims); + drawAnim(anims); +} + +void PreGob::loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const { + freeAnims(anims); + + anims.resize(count); + for (uint i = 0; i < count; i++) { + anims[i] = new ANIObject(ani); + + setAnim(*anims[i], props[i]); + } +} + +void PreGob::freeAnims(ANIList &anims) const { + for (ANIList::iterator a = anims.begin(); a != anims.end(); ++a) + delete *a; + + anims.clear(); +} + +void PreGob::setAnim(ANIObject &anim, const AnimProperties &props) const { + anim.setAnimation(props.animation); + anim.setFrame(props.frame); + anim.setMode(props.mode); + anim.setPause(props.paused); + anim.setVisible(props.visible); + + if (props.hasPosition) + anim.setPosition(props.x, props.y); + else + anim.setPosition(); } Common::String PreGob::getLocFile(const Common::String &file) const { diff --git a/engines/gob/pregob/pregob.h b/engines/gob/pregob/pregob.h index e62a59042b..f1728036ab 100644 --- a/engines/gob/pregob/pregob.h +++ b/engines/gob/pregob/pregob.h @@ -27,6 +27,7 @@ #include "common/array.h" #include "gob/util.h" +#include "gob/aniobject.h" #include "gob/sound/sounddesc.h" @@ -37,8 +38,6 @@ namespace Gob { class GobEngine; class Surface; -class ANIObject; - class PreGob { public: PreGob(GobEngine *vm); @@ -46,7 +45,23 @@ public: virtual void run() = 0; + struct AnimProperties { + uint16 animation; + uint16 frame; + + ANIObject::Mode mode; + + bool visible; + bool paused; + + bool hasPosition; + int16 x; + int16 y; + }; + protected: + typedef Common::Array ANIList; + static const char kLanguageSuffixShort[5]; static const char *kLanguageSuffixLong [5]; @@ -88,11 +103,23 @@ protected: bool isCursorVisible() const; /** Remove an animation from the screen. */ - void clearAnim(ANIObject &ani); + void clearAnim(ANIObject &anim); /** Draw an animation to the screen, advancing it. */ - void drawAnim(ANIObject &ani); + void drawAnim(ANIObject &anim); /** Clear and draw an animation to the screen, advancing it. */ - void redrawAnim(ANIObject &ani); + void redrawAnim(ANIObject &anim); + + /** Remove animations from the screen. */ + void clearAnim(const ANIList &anims); + /** Draw animations to the screen, advancing them. */ + void drawAnim(const ANIList &anims); + /** Clear and draw animations to the screen, advancing them. */ + void redrawAnim(const ANIList &anims); + + void loadAnims(ANIList &anims, ANIFile &ani, uint count, const AnimProperties *props) const; + void freeAnims(ANIList &anims) const; + + void setAnim(ANIObject &anim, const AnimProperties &props) const; /** Wait for the frame to end, handling screen updates and optionally update input. */ void endFrame(bool doInput); -- cgit v1.2.3