GOB: Implement parts of the Once Upon A Time end sequence

We don't yet support GCT files, so texts are still missing.
This commit is contained in:
Sven Hesse 2012-07-02 21:31:23 +02:00
parent 60f52ab9a0
commit df18bc9583
4 changed files with 177 additions and 37 deletions

View File

@ -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;
}
bool OnceUpon::sectionEnd() {
warning("OnceUpon::sectionEnd(): TODO");
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() {
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;
}

View File

@ -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;

View File

@ -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 {

View File

@ -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<ANIObject *> 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);