aboutsummaryrefslogtreecommitdiff
path: root/engines/avalanche/animation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/avalanche/animation.cpp')
-rw-r--r--engines/avalanche/animation.cpp1459
1 files changed, 1459 insertions, 0 deletions
diff --git a/engines/avalanche/animation.cpp b/engines/avalanche/animation.cpp
new file mode 100644
index 0000000000..ef30faa87c
--- /dev/null
+++ b/engines/avalanche/animation.cpp
@@ -0,0 +1,1459 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on the original source code of Lord Avalot d'Argent version 1.3.
+ * Copyright (c) 1994-1995 Mike, Mark and Thomas Thurman.
+ */
+
+/* TRIP5 Trippancy V - the sprite animation subsystem */
+
+#include "avalanche/avalanche.h"
+#include "avalanche/animation.h"
+
+namespace Avalanche {
+
+// Art gallery at 2,1; notice about this at 2,2.
+const int32 Animation::kCatacombMap[8][8] = {
+ // Geida's room
+ // 1 2 3 4 5 6 7 8
+ {0x204, 0x200, 0xd0f0, 0xf0ff, 0xff, 0xd20f, 0xd200, 0x200},
+ {0x50f1, 0x20ff, 0x2ff, 0xff, 0xe0ff, 0x20ff, 0x200f, 0x7210},
+ {0xe3f0, 0xe10f, 0x72f0, 0xff, 0xe0ff, 0xff, 0xff, 0x800f},
+ {0x2201, 0x2030, 0x800f, 0x220, 0x20f, 0x30, 0xff, 0x23f}, // >> Oubliette
+ {0x5024, 0xf3, 0xff, 0x200f, 0x22f0, 0x20f, 0x200, 0x7260},
+ {0xf0, 0x2ff, 0xe2ff, 0xff, 0x200f, 0x50f0, 0x72ff, 0x201f},
+ {0xf6, 0x220f, 0x22f0, 0x30f, 0xf0, 0x20f, 0x8200, 0x2f0}, // <<< In here
+ {0x34, 0x200f, 0x51f0, 0x201f, 0xf1, 0x50ff, 0x902f, 0x2062}
+};
+
+AnimationType::AnimationType(Animation *anim) {
+ _anim = anim;
+}
+
+/**
+ * Loads & sets up the sprite.
+ */
+void AnimationType::init(byte spritenum, bool doCheck) {
+ const int32 idshould = -1317732048;
+
+ if (spritenum == 177)
+ return; // Already running!
+
+ Common::File inf;
+ Common::String filename = Common::String::format("sprite%d.avd", spritenum);
+ if (!inf.open(filename))
+ error("AVALANCHE: Trip: File not found: %s", filename.c_str());
+
+ inf.seek(177);
+
+ int32 id = inf.readSint32LE();
+ if (id != idshould) {
+ inf.close();
+ return;
+ }
+
+ // Replace variable named 'soa' in the original code.
+ inf.skip(2);
+ // Skip real name Size (1 byte) then fixed sized zone containing name (12 bytes)
+ inf.skip(1 + 12);
+ // Skip real comment size (1 byte) then fixed sized zone containing comment (16 bytes)
+ inf.skip(1 + 16);
+
+ _frameNum = inf.readByte();
+ _xLength = inf.readByte();
+ _yLength = inf.readByte();
+ _seq = inf.readByte();
+ uint16 size = inf.readUint16LE();
+ assert (size > 6);
+ _fgBubbleCol = (Color)inf.readByte();
+ _bgBubbleCol = (Color)inf.readByte();
+ _characterId = inf.readByte();
+
+ byte xWidth = _xLength / 8;
+ if ((_xLength % 8) > 0)
+ xWidth++;
+ for (int i = 0; i < _frameNum; i++) {
+ _sil[i] = new SilType[11 * (_yLength + 1)];
+ _mani[i] = new ManiType[size - 6];
+ for (int j = 0; j <= _yLength; j++)
+ inf.read((*_sil[i])[j], xWidth);
+ inf.read(*_mani[i], size - 6);
+ }
+
+ _x = 0;
+ _y = 0;
+ _quick = true;
+ _visible = false;
+ _speedX = kWalk;
+ _speedY = 1;
+ _homing = false;
+ _moveX = 0;
+ _moveY = 0;
+ _stepNum = 0;
+ _doCheck = doCheck;
+ _count = 0;
+ _id = spritenum;
+ _vanishIfStill = false;
+ _callEachStepFl = false;
+
+ inf.close();
+}
+
+/**
+ * Just sets 'quick' to false.
+ * @remarks Originally called 'original'
+ */
+void AnimationType::reset() {
+ _quick = false;
+ _id = 177;
+}
+
+/**
+ * Drops sprite onto screen.
+ * @remarks Originally called 'andexor'
+ */
+void AnimationType::draw() {
+ if (_vanishIfStill && (_moveX == 0) && (_moveY == 0))
+ return;
+
+ byte picnum = _facingDir * _seq + _stepNum;
+
+ _anim->_vm->_graphics->drawSprite(this, picnum, _x, _y);
+}
+
+/**
+ * Turns character round.
+ */
+void AnimationType::turn(Direction whichway) {
+ if (whichway == 8)
+ _facingDir = kDirUp;
+ else
+ _facingDir = whichway;
+}
+
+/**
+ * Switches it on.
+ */
+void AnimationType::appear(int16 wx, int16 wy, Direction wf) {
+ _x = (wx / 8) * 8;
+ _y = wy;
+ _oldX[_anim->_vm->_cp] = wx;
+ _oldY[_anim->_vm->_cp] = wy;
+ turn(wf);
+ _visible = true;
+ _moveX = 0;
+ _moveY = 0;
+}
+
+/**
+ * Check collision
+ * @remarks Originally called 'collision_check'
+ */
+bool AnimationType::checkCollision() {
+ for (int i = 0; i < _anim->kSpriteNumbMax; i++) {
+ AnimationType *spr = _anim->_sprites[i];
+ if (spr->_quick && (spr->_id != _id) && (_x + _xLength > spr->_x) && (_x < spr->_x + spr->_xLength) && (spr->_y == _y))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Prepares for draw(), etc.
+ */
+void AnimationType::walk() {
+ if (!_anim->_vm->_doingSpriteRun) {
+ _oldX[_anim->_vm->_cp] = _x;
+ _oldY[_anim->_vm->_cp] = _y;
+ if (_homing)
+ homeStep();
+ _x += _moveX;
+ _y += _moveY;
+ }
+
+ if (_doCheck) {
+ if (checkCollision()) {
+ bounce();
+ return;
+ }
+
+ byte magicColor = _anim->checkFeet(_x, _x + _xLength, _oldY[_anim->_vm->_cp], _y, _yLength) - 1;
+ // -1 is because the modified array indexes of magics[] compared to Pascal .
+
+ if ((magicColor != 255) & !_anim->_vm->_doingSpriteRun) {
+ MagicType *magic = &_anim->_vm->_magics[magicColor];
+ switch (magic->_operation) {
+ case kMagicExclaim:
+ bounce();
+ _anim->_mustExclaim = true;
+ _anim->_sayWhat = magic->_data;
+ break;
+ case kMagicBounce:
+ bounce();
+ break;
+ case kMagicTransport:
+ _anim->_vm->flipRoom((Room)(magic->_data >> 8), magic->_data & 0xff);
+ break;
+ case kMagicUnfinished: {
+ bounce();
+ Common::String tmpStr = Common::String::format("%c%cSorry.%cThis place is not available yet!",
+ kControlBell, kControlCenter, kControlRoman);
+ _anim->_vm->_dialogs->displayText(tmpStr);
+ }
+ break;
+ case kMagicSpecial:
+ _anim->callSpecial(magic->_data);
+ break;
+ case kMagicOpenDoor:
+ _anim->_vm->openDoor((Room)(magic->_data >> 8), magic->_data & 0xff, magicColor);
+ break;
+ }
+ }
+ }
+
+ if (!_anim->_vm->_doingSpriteRun) {
+ _count++;
+ if (((_moveX != 0) || (_moveY != 0)) && (_count > 1)) {
+ _stepNum++;
+ if (_stepNum == _seq)
+ _stepNum = 0;
+ _count = 0;
+ }
+ }
+}
+
+/**
+ * Bounces off walls
+ */
+void AnimationType::bounce() {
+ _x = _oldX[_anim->_vm->_cp];
+ _y = _oldY[_anim->_vm->_cp];
+ if (_doCheck)
+ _anim->stopWalking();
+ else
+ stopWalk();
+ _anim->_vm->drawDirection();
+}
+
+int8 AnimationType::getSign(int16 val) {
+ if (val > 0)
+ return 1;
+ else if (val < 0)
+ return -1;
+ else
+ return 0;
+}
+
+/**
+ * Home in on a point.
+ */
+void AnimationType::walkTo(byte pedNum) {
+ PedType *curPed = &_anim->_vm->_peds[pedNum];
+
+ setSpeed(getSign(curPed->_x - _x) * 4, getSign(curPed->_y - _y));
+ _homingX = curPed->_x - _xLength / 2;
+ _homingY = curPed->_y - _yLength;
+ _homing = true;
+}
+
+void AnimationType::stopHoming() {
+ _homing = false;
+}
+
+/**
+ * Calculates ix & iy for one homing step.
+ */
+void AnimationType::homeStep() {
+ int16 temp;
+
+ if ((_homingX == _x) && (_homingY == _y)) {
+ // touching the target
+ stopWalk();
+ return;
+ }
+ _moveX = 0;
+ _moveY = 0;
+ if (_homingY != _y) {
+ temp = _homingY - _y;
+ if (temp > 4)
+ _moveY = 4;
+ else if (temp < -4)
+ _moveY = -4;
+ else
+ _moveY = temp;
+ }
+ if (_homingX != _x) {
+ temp = _homingX - _x;
+ if (temp > 4)
+ _moveX = 4;
+ else if (temp < -4)
+ _moveX = -4;
+ else
+ _moveX = temp;
+ }
+}
+
+/**
+ * Sets ix & iy, non-homing, etc.
+ */
+void AnimationType::setSpeed(int8 xx, int8 yy) {
+ _moveX = xx;
+ _moveY = yy;
+ if ((_moveX == 0) && (_moveY == 0))
+ return; // no movement
+ if (_moveX == 0) {
+ // No horz movement
+ if (_moveY < 0)
+ turn(kDirUp);
+ else
+ turn(kDirDown);
+ } else {
+ if (_moveX < 0)
+ turn(kDirLeft);
+ else
+ turn(kDirRight);
+ }
+}
+
+/**
+ * Stops the sprite from moving.
+ */
+void AnimationType::stopWalk() {
+ _moveX = 0;
+ _moveY = 0;
+ _homing = false;
+}
+
+/**
+ * Sets up talk vars.
+ */
+void AnimationType::chatter() {
+ _anim->_vm->_dialogs->setTalkPos(_x + _xLength / 2, _y);
+ _anim->_vm->_graphics->setDialogColor(_bgBubbleCol, _fgBubbleCol);
+}
+
+void AnimationType::remove() {
+ for (int i = 0; i < _frameNum; i++) {
+ delete[] _mani[i];
+ delete[] _sil[i];
+ }
+
+ _quick = false;
+ _id = 177;
+}
+
+Animation::Animation(AvalancheEngine *vm) {
+ _vm = vm;
+ _mustExclaim = false;
+
+ for (int16 i = 0; i < kSpriteNumbMax; i++) {
+ _sprites[i] = new AnimationType(this);
+ }
+}
+
+Animation::~Animation() {
+ for (int16 i = 0; i < kSpriteNumbMax; i++) {
+ AnimationType *curSpr = _sprites[i];
+
+ if (curSpr->_quick)
+ curSpr->remove();
+ delete(curSpr);
+ }
+}
+
+/**
+ * Resets Animation variables.
+ * @remarks Originally called 'loadtrip'
+ */
+void Animation::resetAnims() {
+ setDirection(kDirStopped);
+ for (int16 i = 0; i < kSpriteNumbMax; i++)
+ _sprites[i]->reset();
+}
+
+byte Animation::checkFeet(int16 x1, int16 x2, int16 oy, int16 y, byte yl) {
+ if (!_vm->_alive)
+ return 0;
+
+ if (x1 < 0)
+ x1 = 0;
+ if (x2 > 639)
+ x2 = 639;
+
+ int16 minY = MIN(oy, y) + yl;
+ int16 maxY = MAX(oy, y) + yl;
+
+ return _vm->_graphics->getAlsoColor(x1, minY, x2, maxY);
+}
+
+byte Animation::geidaPed(byte ped) {
+ switch (ped) {
+ case 1:
+ return 6;
+ case 2:
+ case 6:
+ return 7;
+ case 3:
+ case 5:
+ return 8;
+ case 4:
+ return 9;
+ default:
+ error("geidaPed(): Unhandled ped value %d", ped);
+ }
+}
+
+/**
+ * When you enter a new position in the catacombs, this procedure should be
+ * called. It changes the 'also' codes so that they may match the picture
+ * on the screen.
+ */
+void Animation::catacombMove(byte ped) {
+ // XY_uint16 is _catacombX+_catacombY*256. Thus, every room in the
+ // catacombs has a different number for it.
+ uint16 xy = _vm->_catacombX + _vm->_catacombY * 256;
+ _geidaSpin = 0;
+
+ switch (xy) {
+ case 1801: // Exit catacombs
+ _vm->flipRoom(kRoomLustiesRoom, 4);
+ _vm->_dialogs->displayText("Phew! Nice to be out of there!");
+ return;
+ case 1033:{ // Oubliette
+ _vm->flipRoom(kRoomOubliette, 1);
+ Common::String tmpStr = Common::String::format("Oh, NO!%c1%c", kControlRegister, kControlSpeechBubble);
+ _vm->_dialogs->displayText(tmpStr);
+ }
+ return;
+ case 4:
+ _vm->flipRoom(kRoomGeidas, 1);
+ return;
+ case 2307:
+ _vm->flipRoom(kRoomLusties, 5);
+ _vm->_dialogs->displayText("Oh no... here we go again...");
+ _vm->_userMovesAvvy = false;
+ _sprites[0]->_moveY = 1;
+ _sprites[0]->_moveX = 0;
+ return;
+ }
+
+ if (!_vm->_enterCatacombsFromLustiesRoom)
+ _vm->loadRoom(29);
+ int32 here = kCatacombMap[_vm->_catacombY - 1][_vm->_catacombX - 1];
+
+ switch (here & 0xf) { // West.
+ case 0: // no connection (wall)
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 27);
+ break;
+ case 0x1: // no connection (wall + shield),
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 28); // ...shield.
+ break;
+ case 0x2: // wall with door
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 29); // ...door.
+ break;
+ case 0x3: // wall with door and shield
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 29); // ...door, and...
+ _vm->_background->draw(-1, -1, 28); // ...shield.
+ break;
+ case 0x4: // no connection (wall + window),
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 4); // ...window.
+ break;
+ case 0x5: // wall with door and window
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 29); // ...door, and...
+ _vm->_background->draw(-1, -1, 4); // ...window.
+ break;
+ case 0x6: // no connection (wall + torches),
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicNothing; // No door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 6); // ...torches.
+ break;
+ case 0x7: // wall with door and torches
+ _vm->_magics[1]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[4]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 27); // Wall, plus...
+ _vm->_background->draw(-1, -1, 29); // ...door, and...
+ _vm->_background->draw(-1, -1, 6); // ...torches.
+ break;
+ case 0xf: // straight-through corridor.
+ _vm->_magics[1]._operation = kMagicNothing; // Sloping wall.
+ _vm->_magics[2]._operation = kMagicSpecial; // Straight wall.
+ break;
+ }
+
+ /* ---- */
+
+ switch ((here & 0xf0) >> 4) { // East
+ case 0: // no connection (wall)
+ _vm->_magics[4]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[6]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 18);
+ break;
+ case 0x1: // no connection (wall + window),
+ _vm->_magics[4]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[6]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 18); // Wall, plus...
+ _vm->_background->draw(-1, -1, 19); // ...window.
+ break;
+ case 0x2: // wall with door
+ _vm->_magics[4]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[6]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 18); // Wall, plus...
+ _vm->_background->draw(-1, -1, 20); // ...door.
+ break;
+ case 0x3: // wall with door and window
+ _vm->_magics[4]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[6]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 18); // Wall, plus...
+ _vm->_background->draw(-1, -1, 19); // ...door, and...
+ _vm->_background->draw(-1, -1, 20); // ...window.
+ break;
+ case 0x6: // no connection (wall + torches),
+ _vm->_magics[4]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[6]._operation = kMagicNothing; // No door.
+ _vm->_background->draw(-1, -1, 18); // Wall, plus...
+ _vm->_background->draw(-1, -1, 17); // ...torches.
+ break;
+ case 0x7: // wall with door and torches
+ _vm->_magics[4]._operation = kMagicBounce; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicNothing; // Straight wall.
+ _vm->_portals[6]._operation = kMagicSpecial; // Door.
+ _vm->_background->draw(-1, -1, 18); // Wall, plus...
+ _vm->_background->draw(-1, -1, 20); // ...door, and...
+ _vm->_background->draw(-1, -1, 17); // ...torches.
+ break;
+ case 0xf: // straight-through corridor.
+ _vm->_magics[4]._operation = kMagicNothing; // Sloping wall.
+ _vm->_magics[5]._operation = kMagicSpecial; // Straight wall.
+ _vm->_portals[6]._operation = kMagicNothing; // Door.
+ break;
+ }
+
+ switch ((here & 0xf00) >> 8) { // South
+ case 0: // No connection.
+ _vm->_magics[6]._operation = kMagicBounce;
+ _vm->_magics[11]._operation = kMagicBounce;
+ _vm->_magics[12]._operation = kMagicBounce;
+ break;
+ case 0x1:
+ _vm->_background->draw(-1, -1, 21);
+
+ if ((xy == 2051) && _vm->_geidaFollows)
+ _vm->_magics[12]._operation = kMagicExclaim;
+ else
+ _vm->_magics[12]._operation = kMagicSpecial; // Right exit south.
+
+ _vm->_magics[6]._operation = kMagicBounce;
+ _vm->_magics[11]._operation = kMagicBounce;
+ break;
+ case 0x2:
+ _vm->_background->draw(-1, -1, 22);
+ _vm->_magics[6]._operation = kMagicSpecial; // Middle exit south.
+ _vm->_magics[11]._operation = kMagicBounce;
+ _vm->_magics[12]._operation = kMagicBounce;
+ break;
+ case 0x3:
+ _vm->_background->draw(-1, -1, 23);
+ _vm->_magics[11]._operation = kMagicSpecial; // Left exit south.
+ _vm->_magics[6]._operation = kMagicBounce;
+ _vm->_magics[12]._operation = kMagicBounce;
+ break;
+ }
+
+ switch ((here & 0xf000) >> 12) { // North
+ case 0: // No connection
+ _vm->_magics[0]._operation = kMagicBounce;
+ _vm->_portals[3]._operation = kMagicNothing; // Door.
+ break;
+ // LEFT handles:
+#if 0
+ case 0x1:
+ _vm->_celer->show_one(-1, -1, 4);
+ _vm->magics[1].op = _vm->bounces; // { Left exit north. } { Change magic number! }
+ _vm->portals[12].op = _vm->special; // { Door. }
+ break;
+#endif
+ case 0x2:
+ _vm->_background->draw(-1, -1, 3);
+ _vm->_magics[0]._operation = kMagicBounce; // Middle exit north.
+ _vm->_portals[3]._operation = kMagicSpecial; // Door.
+ break;
+#if 0
+ case 0x3:
+ _vm->_celer->show_one(-1, -1, 4);
+ _vm->magics[1].op = _vm->bounces; // { Right exit north. } { Change magic number! }
+ _vm->portals[12].op = _vm->special; // { Door. }
+ break;
+ // RIGHT handles:
+ case 0x4:
+ _vm->_celer->show_one(-1, -1, 3);
+ _vm->magics[1].op = _vm->bounces; // { Left exit north. } { Change magic number! }
+ _vm->portals[12].op = _vm->special; // { Door. }
+ break;
+#endif
+ case 0x5:
+ _vm->_background->draw(-1, -1, 2);
+ _vm->_magics[0]._operation = kMagicBounce; // Middle exit north.
+ _vm->_portals[3]._operation = kMagicSpecial; // Door.
+ break;
+#if 0
+ case 0x6:
+ _vm->_celer->show_one(-1, -1, 3);
+ _vm->magics[1].op = _vm->bounces; // { Right exit north. }
+ _vm->portals[12].op = _vm->special; // { Door. }
+ break;
+#endif
+ // ARCHWAYS:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ _vm->_background->draw(-1, -1, 5);
+
+ if (((here & 0xf000) >> 12) > 0x7)
+ _vm->_background->draw(-1, -1, 30);
+ if (((here & 0xf000) >> 12) == 0x9)
+ _vm->_background->draw(-1, -1, 31);
+
+ _vm->_magics[0]._operation = kMagicSpecial; // Middle arch north.
+ _vm->_portals[3]._operation = kMagicNothing; // Door.
+ break;
+ // DECORATIONS:
+ case 0xd: // No connection + WINDOW
+ _vm->_magics[0]._operation = kMagicBounce;
+ _vm->_portals[3]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 13);
+ break;
+ case 0xe: // No connection + TORCH
+ _vm->_magics[0]._operation = kMagicBounce;
+ _vm->_portals[3]._operation = kMagicNothing; // Door.
+ _vm->_background->draw(-1, -1, 7);
+ break;
+ // Recessed door:
+ case 0xf:
+ _vm->_magics[0]._operation = kMagicNothing; // Door to Geida's room.
+ _vm->_background->draw(-1, -1, 0);
+ _vm->_portals[3]._operation = kMagicSpecial; // Door.
+ break;
+ }
+
+ switch (xy) {
+ case 514:
+ _vm->_background->draw(-1, -1, 16);
+ break; // [2,2] : "Art Gallery" sign over door.
+ case 264:
+ _vm->_background->draw(-1, -1, 8);
+ break; // [8,1] : "The Wrong Way!" sign.
+ case 1797:
+ _vm->_background->draw(-1, -1, 1);
+ break; // [5,7] : "Ite Mingite" sign.
+ case 258:
+ for (int i = 0; i <= 2; i++) { // [2,1] : Art gallery - pictures
+ _vm->_background->draw(130 + i * 120, 70, 14);
+ _vm->_background->draw(184 + i * 120, 78, 15);
+ }
+ break;
+ case 1287:
+ for (int i = 10; i <= 13; i++)
+ _vm->_background->draw(-1, -1, i - 1);
+ break; // [7,5] : 4 candles.
+ case 776:
+ _vm->_background->draw(-1, -1, 9);
+ break; // [8,3] : 1 candle.
+ case 2049:
+ _vm->_background->draw(-1, -1, 10);
+ break; // [1,8] : another candle.
+ case 257:
+ _vm->_background->draw(-1, -1, 11);
+ _vm->_background->draw(-1, -1, 12);
+ break; // [1,1] : the other two.
+ }
+
+ if (_vm->_geidaFollows && (ped > 0)) {
+ AnimationType *spr1 = _sprites[1];
+
+ if (!spr1->_quick) // If we don't already have her...
+ spr1->init(5, true); // ...Load Geida.
+ appearPed(1, geidaPed(ped));
+ spr1->_callEachStepFl = true;
+ spr1->_eachStepProc = kProcGeida;
+ }
+}
+
+/**
+ * This proc gets called whenever you touch a line defined as _vm->special.
+ */
+void Animation::dawnDelay() {
+ _vm->_timer->addTimer(2, Timer::kProcDawnDelay, Timer::kReasonDawndelay);
+}
+
+void Animation::callSpecial(uint16 which) {
+ switch (which) {
+ case 1: // _vm->special 1: Room 22: top of stairs.
+ _vm->_background->draw(-1, -1, 0);
+ _vm->_brummieStairs = 1;
+ _vm->_magics[9]._operation = kMagicNothing;
+ _vm->_timer->addTimer(10, Timer::kProcStairs, Timer::kReasonBrummieStairs);
+ stopWalking();
+ _vm->_userMovesAvvy = false;
+ break;
+ case 2: // _vm->special 2: Room 22: bottom of stairs.
+ _vm->_brummieStairs = 3;
+ _vm->_magics[10]._operation = kMagicNothing;
+ _vm->_magics[11]._operation = kMagicExclaim;
+ _vm->_magics[11]._data = 5;
+ _vm->_magics[3]._operation = kMagicBounce; // Now works as planned!
+ stopWalking();
+ _vm->_dialogs->displayScrollChain('q', 26);
+ _vm->_userMovesAvvy = true;
+ break;
+ case 3: // _vm->special 3: Room 71: triggers dart.
+ _sprites[0]->bounce(); // Must include that.
+
+ if (!_arrowTriggered) {
+ _arrowTriggered = true;
+
+ AnimationType *spr1 = _sprites[1];
+ appearPed(1, 3); // The dart starts at ped 4, and...
+ spr1->walkTo(4); // flies to ped 5 (- 1 for pascal to C conversion).
+ spr1->_facingDir = kDirUp; // Only face.
+ // Should call some kind of Eachstep procedure which will deallocate
+ // the sprite when it hits the wall, and replace it with the chunk
+ // graphic of the arrow buried in the plaster. */
+
+ // OK!
+ spr1->_callEachStepFl = true;
+ spr1->_eachStepProc = kProcArrow;
+ }
+ break;
+ case 4: // This is the ghost room link.
+ _vm->fadeOut();
+ _sprites[0]->turn(kDirRight); // you'll see this after we get back from bootstrap
+ _vm->_timer->addTimer(1, Timer::kProcGhostRoomPhew, Timer::kReasonGhostRoomPhew);
+ //_vm->_enid->backToBootstrap(3); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then!
+ break;
+ case 5:
+ if (_vm->_friarWillTieYouUp) {
+ // _vm->special 5: Room 42: touched tree, and get tied up.
+ _vm->_magics[4]._operation = kMagicBounce; // Boundary effect is now working again.
+ _vm->_dialogs->displayScrollChain('q', 35);
+ _sprites[0]->remove();
+ //tr[1].vanishifstill:=true;
+
+ AnimationType *spr1 = _sprites[1];
+ _vm->_background->draw(-1, -1, 1);
+ _vm->_dialogs->displayScrollChain('q', 36);
+ _vm->_tiedUp = true;
+ _vm->_friarWillTieYouUp = false;
+ spr1->walkTo(2);
+ spr1->_vanishIfStill = true;
+ spr1->_doCheck = true; // One of them must have Check_Me switched on.
+ _vm->setRoom(kPeopleFriarTuck, kRoomDummy); // Not here, then.
+ _vm->_timer->addTimer(364, Timer::kProcHangAround, Timer::kReasonHangingAround);
+ }
+ break;
+ case 6: {
+ // _vm->special 6: fall down oubliette.
+ AnimationType *avvy = _sprites[0];
+ _vm->_userMovesAvvy = false;
+ avvy->_moveX = 3;
+ avvy->_moveY = 0;
+ avvy->_facingDir = kDirRight;
+ _vm->_timer->addTimer(1, Timer::kProcFallDownOubliette, Timer::kReasonFallingDownOubliette);
+ }
+ break;
+ case 7: // _vm->special 7: stop falling down oubliette.
+ _sprites[0]->_visible = false;
+ _vm->_magics[9]._operation = kMagicNothing;
+ stopWalking();
+ _vm->_timer->loseTimer(Timer::kReasonFallingDownOubliette);
+ //_vm->mblit(12, 80, 38, 160, 3, 0);
+ //_vm->mblit(12, 80, 38, 160, 3, 1);
+ _vm->_dialogs->displayText("Oh dear, you seem to be down the bottom of an oubliette.");
+ _vm->_timer->addTimer(200, Timer::kProcMeetAvaroid, Timer::kReasonMeetingAvaroid);
+ break;
+ case 8: // _vm->special 8: leave du Lustie's room.
+ if (_vm->_geidaFollows && !_vm->_lustieIsAsleep) {
+ AnimationType *spr1 = _sprites[1];
+ _vm->_dialogs->displayScrollChain('q', 63);
+ spr1->turn(kDirDown);
+ spr1->stopWalk();
+ spr1->_callEachStepFl = false; // Geida
+ _vm->gameOver();
+ }
+ break;
+ case 9: {
+ // _vm->special 9: lose Geida to Robin Hood...
+ if (!_vm->_geidaFollows)
+ return; // DOESN'T COUNT: no Geida.
+ AnimationType *spr1 = _sprites[1];
+ spr1->_callEachStepFl = false; // She no longer follows Avvy around.
+ spr1->walkTo(3); // She walks to somewhere...
+ _sprites[0]->remove(); // Lose Avvy.
+ _vm->_userMovesAvvy = false;
+ _vm->_timer->addTimer(40, Timer::kProcRobinHoodAndGeida, Timer::kReasonRobinHoodAndGeida);
+ }
+ break;
+ case 10: // _vm->special 10: transfer north in catacombs.
+ if ((_vm->_catacombX == 4) && (_vm->_catacombY == 1)) {
+ // Into Geida's room.
+ if (_vm->_objects[kObjectKey - 1])
+ _vm->_dialogs->displayScrollChain('q', 62);
+ else {
+ _vm->_dialogs->displayScrollChain('q', 61);
+ return;
+ }
+ }
+ _vm->fadeOut();
+ _vm->_catacombY--;
+ catacombMove(4);
+ if (_vm->_room != kRoomCatacombs)
+ return;
+ switch ((kCatacombMap[_vm->_catacombY - 1][_vm->_catacombX - 1] & 0xf00) >> 8) {
+ case 0x1:
+ appearPed(0, 11);
+ break;
+ case 0x3:
+ appearPed(0, 10);
+ break;
+ default:
+ appearPed(0, 3);
+ }
+ dawnDelay();
+ break;
+ case 11: // _vm->special 11: transfer east in catacombs.
+ _vm->fadeOut();
+ _vm->_catacombX++;
+ catacombMove(1);
+ if (_vm->_room != kRoomCatacombs)
+ return;
+ appearPed(0, 0);
+ dawnDelay();
+ break;
+ case 12: // _vm->special 12: transfer south in catacombs.
+ _vm->fadeOut();
+ _vm->_catacombY++;
+ catacombMove(2);
+ if (_vm->_room != kRoomCatacombs)
+ return;
+ appearPed(0, 1);
+ dawnDelay();
+ break;
+ case 13: // _vm->special 13: transfer west in catacombs.
+ _vm->fadeOut();
+ _vm->_catacombX--;
+ catacombMove(3);
+ if (_vm->_room != kRoomCatacombs)
+ return;
+ appearPed(0, 2);
+ dawnDelay();
+ break;
+ }
+}
+
+void Animation::updateSpeed() {
+ AnimationType *avvy = _sprites[0];
+ // Given that you've just changed the speed in _speedX, this adjusts _moveX.
+ avvy->_moveX = (avvy->_moveX / 3) * avvy->_speedX;
+ _vm->_graphics->drawSpeedBar(avvy->_speedX);
+}
+
+void Animation::setMoveSpeed(byte t, Direction dir) {
+ AnimationType *spr = _sprites[t];
+ switch (dir) {
+ case kDirUp:
+ spr->setSpeed(0, -spr->_speedY);
+ break;
+ case kDirDown:
+ spr->setSpeed(0, spr->_speedY);
+ break;
+ case kDirLeft:
+ spr->setSpeed(-spr->_speedX, 0);
+ break;
+ case kDirRight:
+ spr->setSpeed(spr->_speedX, 0);
+ break;
+ case kDirUpLeft:
+ spr->setSpeed(-spr->_speedX, -spr->_speedY);
+ break;
+ case kDirUpRight:
+ spr->setSpeed(spr->_speedX, -spr->_speedY);
+ break;
+ case kDirDownLeft:
+ spr->setSpeed(-spr->_speedX, spr->_speedY);
+ break;
+ case kDirDownRight:
+ spr->setSpeed(spr->_speedX, spr->_speedY);
+ break;
+ default:
+ break;
+ }
+}
+
+void Animation::appearPed(byte sprNum, byte pedNum) {
+ AnimationType *curSpr = _sprites[sprNum];
+ PedType *curPed = &_vm->_peds[pedNum];
+ curSpr->appear(curPed->_x - curSpr->_xLength / 2, curPed->_y - curSpr->_yLength, curPed->_direction);
+ setMoveSpeed(sprNum, curPed->_direction);
+}
+
+/**
+ * @remarks Originally called 'follow_avvy_y'
+ */
+void Animation::followAvalotY(byte tripnum) {
+ if (_sprites[0]->_facingDir == kDirLeft)
+ return;
+
+ AnimationType *tripSpr = _sprites[tripnum];
+ AnimationType *spr1 = _sprites[1];
+
+ if (tripSpr->_homing)
+ tripSpr->_homingY = spr1->_y;
+ else {
+ if (tripSpr->_y < spr1->_y)
+ tripSpr->_y++;
+ else if (tripSpr->_y > spr1->_y)
+ tripSpr->_y--;
+ else
+ return;
+
+ if (tripSpr->_moveX == 0) {
+ tripSpr->_stepNum++;
+ if (tripSpr->_stepNum == tripSpr->_seq)
+ tripSpr->_stepNum = 0;
+ tripSpr->_count = 0;
+ }
+ }
+}
+
+void Animation::backAndForth(byte tripnum) {
+ AnimationType *tripSpr = _sprites[tripnum];
+
+ if (!tripSpr->_homing) {
+ if (tripSpr->_facingDir == kDirRight)
+ tripSpr->walkTo(3);
+ else
+ tripSpr->walkTo(4);
+ }
+}
+
+void Animation::faceAvvy(byte tripnum) {
+ AnimationType *tripSpr = _sprites[tripnum];
+
+ if (!tripSpr->_homing) {
+ if (_sprites[0]->_x >= tripSpr->_x)
+ tripSpr->_facingDir = kDirRight;
+ else
+ tripSpr->_facingDir = kDirLeft;
+ }
+}
+
+void Animation::arrowProcs(byte tripnum) {
+ AnimationType *tripSpr = _sprites[tripnum];
+ AnimationType *avvy = _sprites[tripnum];
+
+ if (tripSpr->_homing) {
+ // Arrow is still in flight.
+ // We must check whether or not the arrow has collided tr[tripnum] Avvy's head.
+ // This is so if: a) the bottom of the arrow is below Avvy's head,
+ // b) the left of the arrow is left of the right of Avvy's head, and
+ // c) the right of the arrow is right of the left of Avvy's head.
+ if ((tripSpr->_y + tripSpr->_yLength >= avvy->_y) // A
+ && (tripSpr->_x <= avvy->_x + avvy->_xLength) // B
+ && (tripSpr->_x + tripSpr->_xLength >= avvy->_x)) { // C
+ // OK, it's hit him... what now?
+
+ _sprites[1]->_callEachStepFl = false; // prevent recursion.
+ _vm->_dialogs->displayScrollChain('Q', 47); // Complaint!
+ tripSpr->remove(); // Deallocate the arrow.
+
+ _vm->gameOver();
+
+ _vm->_userMovesAvvy = false; // Stop the user from moving him.
+ _vm->_timer->addTimer(55, Timer::kProcNaughtyDuke, Timer::kReasonNaughtyDuke);
+ }
+ } else { // Arrow has hit the wall!
+ tripSpr->remove(); // Deallocate the arrow.
+ _vm->_background->draw(-1, -1, 2); // Show pic of arrow stuck into the door.
+ _vm->_arrowInTheDoor = true; // So that we can pick it up.
+ }
+}
+
+void Animation::grabAvvy(byte tripnum) { // For Friar Tuck, in Nottingham.
+ AnimationType *tripSpr = _sprites[tripnum];
+ AnimationType *avvy = _sprites[tripnum];
+
+ int16 tox = avvy->_x + 17;
+ int16 toy = avvy->_y - 1;
+ if ((tripSpr->_x == tox) && (tripSpr->_y == toy)) {
+ tripSpr->_callEachStepFl = false;
+ tripSpr->_facingDir = kDirLeft;
+ tripSpr->stopWalk();
+ // ... whatever ...
+ } else {
+ // Still some way to go.
+ if (tripSpr->_x < tox) {
+ tripSpr->_x += 5;
+ if (tripSpr->_x > tox)
+ tripSpr->_x = tox;
+ }
+ if (tripSpr->_y < toy)
+ tripSpr->_y++;
+ tripSpr->_stepNum++;
+ if (tripSpr->_stepNum == tripSpr->_seq)
+ tripSpr->_stepNum = 0;
+ }
+}
+
+void Animation::takeAStep(byte &tripnum) {
+ AnimationType *tripSpr = _sprites[tripnum];
+
+ if (tripSpr->_moveX == 0) {
+ tripSpr->_stepNum++;
+ if (tripSpr->_stepNum == tripSpr->_seq)
+ tripSpr->_stepNum = 0;
+ tripSpr->_count = 0;
+ }
+}
+
+void Animation::spin(Direction dir, byte &tripnum) {
+ AnimationType *tripSpr = _sprites[tripnum];
+
+ if (tripSpr->_facingDir == dir)
+ return;
+
+ tripSpr->_facingDir = dir;
+ if (tripSpr->_id == 2)
+ return; // Not for Spludwick
+
+ _geidaSpin++;
+ _geidaTime = 20;
+ if (_geidaSpin == 5) {
+ _vm->_dialogs->displayText("Steady on, Avvy, you'll make the poor girl dizzy!");
+ _geidaSpin = 0;
+ _geidaTime = 0; // knock out records
+ }
+}
+
+void Animation::geidaProcs(byte tripnum) {
+ AnimationType *tripSpr = _sprites[tripnum];
+ AnimationType *avvy = _sprites[0];
+
+ if (_geidaTime > 0) {
+ _geidaTime--;
+ if (_geidaTime == 0)
+ _geidaSpin = 0;
+ }
+
+ if (tripSpr->_y < (avvy->_y - 2)) {
+ // Geida is further from the screen than Avvy.
+ spin(kDirDown, tripnum);
+ tripSpr->_moveY = 1;
+ tripSpr->_moveX = 0;
+ takeAStep(tripnum);
+ return;
+ } else if (tripSpr->_y > (avvy->_y + 2)) {
+ // Avvy is further from the screen than Geida.
+ spin(kDirUp, tripnum);
+ tripSpr->_moveY = -1;
+ tripSpr->_moveX = 0;
+ takeAStep(tripnum);
+ return;
+ }
+
+ tripSpr->_moveY = 0;
+ // These 12-s are not in the original, I added them to make the following method more "smooth".
+ // Now the NPC which is following Avvy won't block his way and will walk next to him properly.
+ if (tripSpr->_x < avvy->_x - avvy->_speedX * 8 - 12) {
+ tripSpr->_moveX = avvy->_speedX;
+ spin(kDirRight, tripnum);
+ takeAStep(tripnum);
+ } else if (tripSpr->_x > avvy->_x + avvy->_speedX * 8 + 12) {
+ tripSpr->_moveX = -avvy->_speedX;
+ spin(kDirLeft, tripnum);
+ takeAStep(tripnum);
+ } else
+ tripSpr->_moveX = 0;
+}
+
+/**
+ * @remarks Originally called 'call_andexors'
+ */
+void Animation::drawSprites() {
+ int8 order[5];
+ byte temp;
+ bool ok;
+
+ for (int i = 0; i < 5; i++)
+ order[i] = -1;
+
+ for (int16 i = 0; i < kSpriteNumbMax; i++) {
+ AnimationType *curSpr = _sprites[i];
+ if (curSpr->_quick && curSpr->_visible)
+ order[i] = i;
+ }
+
+ do {
+ ok = true;
+ for (int i = 0; i < 4; i++) {
+ if ((order[i] != -1) && (order[i + 1] != -1) && (_sprites[order[i]]->_y > _sprites[order[i + 1]]->_y)) {
+ // Swap them!
+ temp = order[i];
+ order[i] = order[i + 1];
+ order[i + 1] = temp;
+ ok = false;
+ }
+ }
+ } while (!ok);
+
+ _vm->_graphics->refreshBackground();
+
+ for (int i = 0; i < 5; i++) {
+ if (order[i] > -1)
+ _sprites[order[i]]->draw();
+ }
+}
+
+/**
+ * Animation links
+ * @remarks Originally called 'trippancy_link'
+ */
+void Animation::animLink() {
+ if (_vm->_menu->isActive() || _vm->_seeScroll)
+ return;
+ for (int16 i = 0; i < kSpriteNumbMax; i++) {
+ AnimationType *curSpr = _sprites[i];
+ if (curSpr->_quick && curSpr->_visible)
+ curSpr->walk();
+ }
+
+ drawSprites();
+
+ for (int16 i = 0; i < kSpriteNumbMax; i++) {
+ AnimationType *curSpr = _sprites[i];
+ if (curSpr->_quick && curSpr->_callEachStepFl) {
+ switch (curSpr->_eachStepProc) {
+ case kProcFollowAvvyY :
+ followAvalotY(i);
+ break;
+ case kProcBackAndForth :
+ backAndForth(i);
+ break;
+ case kProcFaceAvvy :
+ faceAvvy(i);
+ break;
+ case kProcArrow :
+ arrowProcs(i);
+ break;
+ // PROCSpludwick_procs : spludwick_procs(fv);
+ case kProcGrabAvvy :
+ grabAvvy(i);
+ break;
+ case kProcGeida :
+ geidaProcs(i);
+ break;
+ }
+ }
+ }
+
+ if (_mustExclaim) {
+ _mustExclaim = false;
+ _vm->_dialogs->displayScrollChain('x', _sayWhat);
+ }
+}
+
+void Animation::stopWalking() {
+ AnimationType *avvy = _sprites[0];
+
+ avvy->stopWalk();
+ _direction = kDirStopped;
+ if (_vm->_alive)
+ avvy->_stepNum = 1;
+}
+
+/**
+ * Hide in the cupboard
+ * @remarks Originally called 'hide_in_the_cupboard'
+ */
+void Animation::hideInCupboard() {
+ if (_vm->_avvysInTheCupboard) {
+ if (_vm->_parser->_wearing == kObjectDummy) {
+ Common::String tmpStr = Common::String::format("%cAVVY!%cGet dressed first!", kControlItalic, kControlRoman);
+ _vm->_dialogs->displayText(tmpStr);
+ } else {
+ _sprites[0]->_visible = true;
+ _vm->_userMovesAvvy = true;
+ appearPed(0, 2); // Walk out of the cupboard.
+ _vm->_dialogs->displayText("You leave the cupboard. Nice to be out of there!");
+ _vm->_avvysInTheCupboard = false;
+ _vm->_sequence->startCupboardSeq();
+ }
+ } else {
+ // Not hiding in the cupboard
+ _sprites[0]->_visible = false;
+ _vm->_userMovesAvvy = false;
+ Common::String tmpStr = Common::String::format("You walk into the room...%cIt seems to be an empty, " \
+ "but dusty, cupboard. Hmmmm... you leave the door slightly open to avoid suffocation.", kControlParagraph);
+ _vm->_dialogs->displayText(tmpStr);
+ _vm->_avvysInTheCupboard = true;
+ _vm->_background->draw(-1, -1, 7);
+ }
+}
+
+/**
+ * Returns true if you're within field "which".
+ */
+bool Animation::inField(byte which) {
+ AnimationType *avvy = _sprites[0];
+
+ FieldType *curField = &_vm->_fields[which];
+ int16 yy = avvy->_y + avvy->_yLength;
+
+ return (avvy->_x >= curField->_x1) && (avvy->_x <= curField->_x2) && (yy >= curField->_y1) && (yy <= curField->_y2);
+}
+
+/**
+ * Returns True if you're near a door.
+ */
+bool Animation::nearDoor() {
+ if (_vm->_fieldNum < 8)
+ // there ARE no doors here!
+ return false;
+
+ AnimationType *avvy = _sprites[0];
+
+ int16 ux = avvy->_x;
+ int16 uy = avvy->_y + avvy->_yLength;
+
+ for (int i = 8; i < _vm->_fieldNum; i++) {
+ FieldType *curField = &_vm->_fields[i];
+ if ((ux >= curField->_x1) && (ux <= curField->_x2) && (uy >= curField->_y1) && (uy <= curField->_y2))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * @remarks Originally called 'tripkey'
+ */
+void Animation::handleMoveKey(const Common::Event &event) {
+ if (!_vm->_userMovesAvvy)
+ return;
+
+ if (_vm->_menu->_activeMenuItem._activeNow)
+ _vm->_parser->tryDropdown();
+ else {
+ switch (event.kbd.keycode) {
+ case Common::KEYCODE_UP:
+ if (_direction != kDirUp) {
+ _direction = kDirUp;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_DOWN:
+ if (_direction != kDirDown) {
+ _direction = kDirDown;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_LEFT:
+ if (_direction != kDirLeft) {
+ _direction = kDirLeft;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_RIGHT:
+ if (_direction != kDirRight) {
+ _direction = kDirRight;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_PAGEUP:
+ if (_direction != kDirUpRight) {
+ _direction = kDirUpRight;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_PAGEDOWN:
+ if (_direction != kDirDownRight) {
+ _direction = kDirDownRight;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_END:
+ if (_direction != kDirDownLeft) {
+ _direction = kDirDownLeft;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_HOME:
+ if (_direction != kDirUpLeft) {
+ _direction = kDirUpLeft;
+ setMoveSpeed(0, _direction);
+ } else
+ stopWalking();
+ break;
+ case Common::KEYCODE_KP5:
+ stopWalking();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void Animation::setDirection(Direction dir) {
+ _direction = dir;
+}
+
+void Animation::setOldDirection(Direction dir) {
+ _oldDirection = dir;
+}
+
+Direction Animation::getDirection() {
+ return _direction;
+}
+
+Direction Animation::getOldDirection() {
+ return _oldDirection;
+}
+
+void Animation::setAvvyClothes(int id) {
+ AnimationType *spr = _sprites[0];
+ if (spr->_id == id)
+ return;
+
+ int16 x = spr->_x;
+ int16 y = spr->_y;
+ spr->remove();
+ spr->init(id, true);
+ spr->appear(x, y, kDirLeft);
+ spr->_visible = false;
+}
+
+int Animation::getAvvyClothes() {
+ return _sprites[0]->_id;
+}
+
+void Animation::resetVariables() {
+ _geidaSpin = 0;
+ _geidaTime = 0;
+ _arrowTriggered = false;
+}
+
+void Animation::synchronize(Common::Serializer &sz) {
+ sz.syncAsByte(_direction);
+ sz.syncAsByte(_geidaSpin);
+ sz.syncAsByte(_geidaTime);
+
+ byte spriteNum = 0;
+ if (sz.isSaving()) {
+ for (int i = 0; i < kSpriteNumbMax; i++) {
+ if (_sprites[i]->_quick)
+ spriteNum++;
+ }
+ }
+ sz.syncAsByte(spriteNum);
+
+ if (sz.isLoading()) {
+ for (int i = 0; i < kSpriteNumbMax; i++) { // Deallocate sprites.
+ AnimationType *spr = _sprites[i];
+ if (spr->_quick)
+ spr->remove();
+ }
+ }
+
+ for (int i = 0; i < spriteNum; i++) {
+ AnimationType *spr = _sprites[i];
+ sz.syncAsByte(spr->_id);
+ sz.syncAsByte(spr->_doCheck);
+
+ if (sz.isLoading()) {
+ spr->_quick = true;
+ spr->init(spr->_id, spr->_doCheck);
+ }
+
+ sz.syncAsByte(spr->_moveX);
+ sz.syncAsByte(spr->_moveY);
+ sz.syncAsByte(spr->_facingDir);
+ sz.syncAsByte(spr->_stepNum);
+ sz.syncAsByte(spr->_visible);
+ sz.syncAsByte(spr->_homing);
+ sz.syncAsByte(spr->_count);
+ sz.syncAsByte(spr->_speedX);
+ sz.syncAsByte(spr->_speedY);
+ sz.syncAsByte(spr->_frameNum);
+ sz.syncAsSint16LE(spr->_homingX);
+ sz.syncAsSint16LE(spr->_homingY);
+ sz.syncAsByte(spr->_callEachStepFl);
+ sz.syncAsByte(spr->_eachStepProc);
+ sz.syncAsByte(spr->_vanishIfStill);
+ sz.syncAsSint16LE(spr->_x);
+ sz.syncAsSint16LE(spr->_y);
+
+ if (sz.isLoading() && spr->_visible)
+ spr->appear(spr->_x, spr->_y, spr->_facingDir);
+ }
+
+ sz.syncAsByte(_arrowTriggered);
+}
+
+} // End of namespace Avalanche.