scummvm/engines/avalanche/animation.cpp

1400 lines
42 KiB
C++
Raw Normal View History

2013-06-27 10:13:00 +00:00
/* 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 */
2013-06-27 10:13:00 +00:00
#include "avalanche/avalanche.h"
#include "avalanche/animation.h"
#include "avalanche/scrolls.h"
#include "avalanche/lucerna.h"
#include "avalanche/gyro.h"
2013-09-19 18:53:47 +00:00
#include "avalanche/background.h"
#include "avalanche/sequence.h"
2013-09-08 09:30:23 +00:00
#include "avalanche/timer.h"
2013-06-27 10:13:00 +00:00
2013-06-29 14:36:40 +00:00
#include "common/scummsys.h"
#include "common/textconsole.h"
#include "common/file.h"
2013-06-29 14:36:40 +00:00
2013-06-27 10:13:00 +00:00
namespace Avalanche {
2013-09-08 10:53:19 +00:00
void AnimationType::init(byte spritenum, bool doCheck, Animation *anim) {
_anim = anim;
const int32 idshould = -1317732048;
if (spritenum == 177)
return; // Already running!
2013-09-07 21:42:34 +00:00
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);
2013-09-07 21:42:34 +00:00
int32 id = inf.readSint32LE();
if (id != idshould) {
inf.close();
return;
}
2013-09-21 13:36:13 +00:00
// Replace variable named 'soa' in the original code.
inf.skip(2);
if (!_stat._name.empty())
_stat._name.clear();
byte nameSize = inf.readByte();
2013-09-16 20:57:38 +00:00
for (int i = 0; i < nameSize; i++)
_stat._name += inf.readByte();
inf.skip(12 - nameSize);
byte commentSize = inf.readByte();
2013-09-16 20:57:38 +00:00
for (int i = 0; i < commentSize; i++)
_stat._comment += inf.readByte();
inf.skip(16 - commentSize);
_stat._frameNum = inf.readByte();
_info._xLength = inf.readByte();
_info._yLength = inf.readByte();
_stat._seq = inf.readByte();
_info._size = inf.readUint16LE();
_stat._fgBubbleCol = inf.readByte();
_stat._bgBubbleCol = inf.readByte();
_stat._acciNum = inf.readByte();
_animCount = 0; // = 1;
_info._xWidth = _info._xLength / 8;
if ((_info._xLength % 8) > 0)
_info._xWidth++;
2013-09-16 20:57:38 +00:00
for (int i = 0; i < _stat._frameNum; i++) {
_info._sil[_animCount] = new SilType[11 * (_info._yLength + 1)];
_info._mani[_animCount] = new ManiType[_info._size - 6];
2013-09-16 20:57:38 +00:00
for (int j = 0; j <= _info._yLength; j++)
2013-09-07 21:42:34 +00:00
inf.read((*_info._sil[_animCount])[j], _info._xWidth);
inf.read(*_info._mani[_animCount], _info._size - 6);
_animCount++;
}
_animCount++;
CursorMan.showMouse(true);
_x = 0;
_y = 0;
2013-09-07 21:42:34 +00:00
_quick = true;
_visible = false;
_speedX = 3;
_speedY = 1;
if (spritenum == 1)
2013-09-08 10:53:19 +00:00
_anim->updateSpeed(); // Just for the lights.
_homing = false;
_moveX = 0;
_moveY = 0;
2013-09-07 21:42:34 +00:00
_stepNum = 0;
_doCheck = doCheck;
_count = 0;
_id = spritenum;
2013-09-07 21:42:34 +00:00
_vanishIfStill = false;
_callEachStepFl = false;
inf.close();
}
void AnimationType::original() {
2013-09-07 21:42:34 +00:00
_quick = false;
_id = 177;
}
void AnimationType::draw() {
2013-09-07 21:42:34 +00:00
if ((_vanishIfStill) && (_moveX == 0) && (_moveY == 0))
return;
2013-09-21 13:36:13 +00:00
byte picnum = _facingDir * _stat._seq + _stepNum;
2013-09-08 10:53:19 +00:00
_anim->_vm->_graphics->drawSprite(_info, picnum, _x, _y);
}
void AnimationType::turn(byte whichway) {
2013-06-30 12:10:33 +00:00
if (whichway == 8)
_facingDir = Animation::kDirUp;
2013-06-30 12:10:33 +00:00
else
_facingDir = whichway;
}
void AnimationType::appear(int16 wx, int16 wy, byte wf) {
_x = (wx / 8) * 8;
_y = wy;
2013-09-08 10:53:19 +00:00
_oldX[_anim->_vm->_gyro->_cp] = wx;
_oldY[_anim->_vm->_gyro->_cp] = wy;
turn(wf);
_visible = true;
_moveX = 0;
_moveY = 0;
}
/**
* Check collision
* @remarks Originally called 'collision_check'
*/
bool AnimationType::checkCollision() {
2013-09-16 20:57:38 +00:00
for (int i = 0; i < _anim->kSpriteNumbMax; i++) {
2013-09-15 08:50:43 +00:00
AnimationType *spr = &_anim->_sprites[i];
if (spr->_quick && (spr->_id != _id) && (_x + _info._xLength > spr->_x) && (_x < spr->_x + spr->_info._xLength) && (spr->_y == _y))
return true;
}
2013-07-03 12:05:06 +00:00
return false;
}
void AnimationType::walk() {
if (_visible) {
ByteField r;
r._x1 = (_x / 8) - 1;
2013-09-06 14:23:57 +00:00
if (r._x1 == 255)
r._x1 = 0;
r._y1 = _y - 2;
r._x2 = ((_x + _info._xLength) / 8) + 1;
r._y2 = _y + _info._yLength + 2;
2013-07-24 15:02:38 +00:00
}
2013-09-08 10:53:19 +00:00
if (!_anim->_vm->_gyro->_doingSpriteRun) {
_oldX[_anim->_vm->_gyro->_cp] = _x;
_oldY[_anim->_vm->_gyro->_cp] = _y;
if (_homing)
2013-09-08 09:34:21 +00:00
homeStep();
_x += _moveX;
_y += _moveY;
2013-07-24 15:02:38 +00:00
}
2013-09-07 21:42:34 +00:00
if (_doCheck) {
if (checkCollision()) {
2013-07-24 15:02:38 +00:00
bounce();
return;
}
byte magicColor = _anim->checkFeet(_x, _x + _info._xLength, _oldY[_anim->_vm->_gyro->_cp], _y, _info._yLength) - 1;
// -1 is because the modified array indexes of magics[] compared to Pascal .
2013-07-24 15:02:38 +00:00
if ((magicColor != 255) & (!_anim->_vm->_gyro->_doingSpriteRun)) {
MagicType *magic = &_anim->_vm->_gyro->_magics[magicColor];
2013-09-14 23:10:10 +00:00
switch (magic->_operation) {
2013-09-08 21:37:13 +00:00
case Gyro::kMagicExclaim:
2013-07-24 15:02:38 +00:00
bounce();
2013-09-08 10:53:19 +00:00
_anim->_mustExclaim = true;
2013-09-14 23:10:10 +00:00
_anim->_sayWhat = magic->_data;
2013-07-24 15:02:38 +00:00
break;
2013-09-05 21:57:58 +00:00
case Gyro::kMagicBounce:
2013-07-24 15:02:38 +00:00
bounce();
break;
2013-09-05 21:57:58 +00:00
case Gyro::kMagicTransport:
2013-09-14 23:10:10 +00:00
_anim->flipRoom(magic->_data >> 8, magic->_data & 0xff);
2013-07-24 15:02:38 +00:00
break;
2013-09-05 21:57:58 +00:00
case Gyro::kMagicUnfinished: {
2013-07-24 15:02:38 +00:00
bounce();
Common::String tmpStr = Common::String::format("%c%cSorry.%cThis place is not available yet!", Scrolls::kControlBell, Scrolls::kControlCenter, Scrolls::kControlRoman);
2013-09-08 21:37:13 +00:00
_anim->_vm->_scrolls->displayText(tmpStr);
2013-07-24 15:02:38 +00:00
}
break;
2013-09-05 21:57:58 +00:00
case Gyro::kMagicSpecial:
2013-09-14 23:10:10 +00:00
_anim->callSpecial(magic->_data);
2013-07-24 15:02:38 +00:00
break;
2013-09-05 21:57:58 +00:00
case Gyro::kMagicOpenDoor:
_anim->openDoor(magic->_data >> 8, magic->_data & 0xff, magicColor);
2013-07-24 15:02:38 +00:00
break;
}
}
}
2013-09-08 10:53:19 +00:00
if (!_anim->_vm->_gyro->_doingSpriteRun) {
2013-09-07 21:42:34 +00:00
_count++;
if (((_moveX != 0) || (_moveY != 0)) && (_count > 1)) {
_stepNum++;
if (_stepNum == _stat._seq)
2013-09-07 21:42:34 +00:00
_stepNum = 0;
_count = 0;
2013-07-24 15:02:38 +00:00
}
}
}
void AnimationType::bounce() {
2013-09-08 10:53:19 +00:00
_x = _oldX[_anim->_vm->_gyro->_cp];
_y = _oldY[_anim->_vm->_gyro->_cp];
2013-09-07 21:42:34 +00:00
if (_doCheck)
2013-09-08 10:53:19 +00:00
_anim->stopWalking();
2013-06-30 12:10:33 +00:00
else
stopWalk();
2013-09-08 10:53:19 +00:00
_anim->_vm->_lucerna->drawDirection();
}
int8 AnimationType::getSign(int16 val) {
2013-09-04 15:54:08 +00:00
if (val > 0)
return 1;
2013-09-04 15:54:08 +00:00
else if (val < 0)
return -1;
else
return 0;
}
2013-09-15 08:50:43 +00:00
void AnimationType::walkTo(byte pedNum) {
PedType *curPed = &_anim->_vm->_gyro->_peds[pedNum];
2013-09-15 08:50:43 +00:00
setSpeed(getSign(curPed->_x - _x) * 4, getSign(curPed->_y - _y));
_homingX = curPed->_x - _info._xLength / 2;
_homingY = curPed->_y - _info._yLength;
_homing = true;
}
void AnimationType::stopHoming() {
_homing = false;
}
2013-09-08 09:34:21 +00:00
void AnimationType::homeStep() {
int16 temp;
if ((_homingX == _x) && (_homingY == _y)) {
// touching the target
stopWalk();
return;
2013-06-27 10:13:00 +00:00
}
_moveX = 0;
_moveY = 0;
if (_homingY != _y) {
temp = _homingY - _y;
2013-06-30 12:10:33 +00:00
if (temp > 4)
_moveY = 4;
2013-06-30 12:10:33 +00:00
else if (temp < -4)
_moveY = -4;
2013-06-30 12:10:33 +00:00
else
_moveY = temp;
2013-06-27 10:13:00 +00:00
}
if (_homingX != _x) {
temp = _homingX - _x;
2013-06-30 12:10:33 +00:00
if (temp > 4)
_moveX = 4;
2013-06-30 12:10:33 +00:00
else if (temp < -4)
_moveX = -4;
2013-06-30 12:10:33 +00:00
else
_moveX = temp;
}
}
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(Animation::kDirUp);
2013-06-30 12:10:33 +00:00
else
turn(Animation::kDirDown);
} else {
if (_moveX < 0)
turn(Animation::kDirLeft);
2013-06-30 12:10:33 +00:00
else
turn(Animation::kDirRight);
}
}
void AnimationType::stopWalk() {
_moveX = 0;
_moveY = 0;
_homing = false;
}
void AnimationType::chatter() {
2013-09-08 10:53:19 +00:00
_anim->_vm->_gyro->_talkX = _x + _info._xLength / 2;
_anim->_vm->_gyro->_talkY = _y;
_anim->_vm->_gyro->_talkFontColor = _stat._fgBubbleCol;
_anim->_vm->_gyro->_talkBackgroundColor = _stat._bgBubbleCol;
}
void AnimationType::remove() {
_animCount--;
_info._xWidth = _info._xLength / 8;
if ((_info._xLength % 8) > 0)
_info._xWidth++;
2013-09-16 20:57:38 +00:00
for (int i = 0; i < _stat._frameNum; i++) {
assert(_animCount > 0);
_animCount--;
delete[] _info._mani[_animCount];
delete[] _info._sil[_animCount];
2013-06-27 10:13:00 +00:00
}
2013-09-07 21:42:34 +00:00
_quick = false;
_id = 177;
}
2013-06-27 10:13:00 +00:00
Animation::Animation(AvalancheEngine *vm) {
_vm = vm;
_mustExclaim = false;
}
2013-06-27 10:13:00 +00:00
Animation::~Animation() {
for (int16 i = 0; i < kSpriteNumbMax; i++) {
if (_sprites[i]._quick)
_sprites[i].remove();
2013-09-05 13:48:30 +00:00
}
}
void Animation::loadAnims() {
for (int16 i = 0; i < kSpriteNumbMax; i++)
_sprites[i].original();
}
2013-06-27 10:13:00 +00:00
byte Animation::checkFeet(int16 x1, int16 x2, int16 oy, int16 y, byte yl) {
2013-09-21 13:36:13 +00:00
if (!_vm->_gyro->_alive)
return 0;
if (x1 < 0)
x1 = 0;
if (x2 > 639)
x2 = 639;
2013-09-21 13:36:13 +00:00
int16 minY = MIN(oy, y) + yl;
int16 maxY = MAX(oy, y) + yl;
byte returnColor = 0;
for (int16 i = x1; i <= x2; i++) {
for (int16 j = minY; j <= maxY; j++) {
byte actColor = *(byte *)_vm->_graphics->_magics.getBasePtr(i, j);
returnColor = MAX(returnColor, actColor);
}
}
return returnColor;
}
2013-09-21 13:36:13 +00:00
byte Animation::geidaPed(byte ped) {
switch (ped) {
case 1:
2013-09-21 13:36:13 +00:00
return 6;
case 2:
case 6:
2013-09-21 13:36:13 +00:00
return 7;
case 3:
case 5:
2013-09-21 13:36:13 +00:00
return 8;
case 4:
2013-09-21 13:36:13 +00:00
return 9;
2013-09-04 10:02:01 +00:00
default:
2013-09-21 13:36:13 +00:00
error("geidaPed(): Unhandled ped value %d", ped);
}
}
2013-06-27 10:13:00 +00:00
void Animation::catacombMove(byte ped) {
int32 here;
uint16 xy_uint16;
2013-06-27 10:13:00 +00:00
// XY_uint16 is cat_x+cat_y*256. Thus, every room in the
// catacombs has a different number for it.
xy_uint16 = _vm->_gyro->_catacombX + _vm->_gyro->_catacombY * 256;
_vm->_gyro->_geidaSpin = 0;
switch (xy_uint16) {
case 1801: // Exit catacombs
flipRoom(kRoomLustiesRoom, 4);
2013-09-07 18:37:42 +00:00
_vm->_scrolls->displayText("Phew! Nice to be out of there!");
return;
2013-09-08 21:13:58 +00:00
case 1033:{ // Oubliette
flipRoom(kRoomOubliette, 1);
2013-09-08 21:13:58 +00:00
Common::String tmpStr = Common::String::format("Oh, NO!%c1%c", Scrolls::kControlRegister, Scrolls::kControlSpeechBubble);
_vm->_scrolls->displayText(tmpStr);
}
return;
2013-06-30 12:10:33 +00:00
case 4:
flipRoom(kRoomGeidas, 1);
return;
2013-06-30 12:10:33 +00:00
case 2307:
flipRoom(kRoomLusties, 5);
2013-09-07 18:37:42 +00:00
_vm->_scrolls->displayText("Oh no... here we go again...");
_vm->_gyro->_userMovesAvvy = false;
_sprites[0]._moveY = 1;
_sprites[0]._moveX = 0;
return;
}
2013-06-27 10:13:00 +00:00
if (!_vm->_gyro->_enterCatacombsFromLustiesRoom)
_vm->_lucerna->loadRoom(29);
here = _vm->_gyro->kCatacombMap[_vm->_gyro->_catacombY - 1][_vm->_gyro->_catacombX - 1];
2013-06-27 10:13:00 +00:00
switch (here & 0xf) { // West.
case 0: // no connection (wall)
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27);
2013-06-30 12:10:33 +00:00
break;
case 0x1: // no connection (wall + shield),
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 28); // ...shield.
2013-06-30 12:10:33 +00:00
break;
case 0x2: // wall with door
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 29); // ...door.
2013-06-30 12:10:33 +00:00
break;
case 0x3: // wall with door and shield
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 29); // ...door, and...
_vm->_background->drawBackgroundSprite(-1, -1, 28); // ...shield.
2013-06-30 12:10:33 +00:00
break;
case 0x4: // no connection (wall + window),
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 4); // ...window.
2013-06-30 12:10:33 +00:00
break;
case 0x5: // wall with door and window
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 29); // ...door, and...
_vm->_background->drawBackgroundSprite(-1, -1, 4); // ...window.
2013-06-30 12:10:33 +00:00
break;
case 0x6: // no connection (wall + torches),
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicNothing; // No door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 6); // ...torches.
2013-06-30 12:10:33 +00:00
break;
case 0x7: // wall with door and torches
_vm->_gyro->_magics[1]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[4]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 27); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 29); // ...door, and...
_vm->_background->drawBackgroundSprite(-1, -1, 6); // ...torches.
2013-06-30 12:10:33 +00:00
break;
case 0xf: // straight-through corridor.
_vm->_gyro->_magics[1]._operation = Gyro::kMagicNothing; // Sloping wall.
_vm->_gyro->_magics[2]._operation = Gyro::kMagicSpecial; // Straight wall.
2013-06-30 12:10:33 +00:00
break;
2013-06-27 10:13:00 +00:00
}
/* ---- */
2013-06-27 10:13:00 +00:00
switch ((here & 0xf0) >> 4) { // East
case 0: // no connection (wall)
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 18);
2013-06-30 12:10:33 +00:00
break;
case 0x1: // no connection (wall + window),
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 18); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 19); // ...window.
2013-06-30 12:10:33 +00:00
break;
case 0x2: // wall with door
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 18); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 20); // ...door.
2013-06-30 12:10:33 +00:00
break;
case 0x3: // wall with door and window
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 18); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 19); // ...door, and...
_vm->_background->drawBackgroundSprite(-1, -1, 20); // ...window.
2013-06-30 12:10:33 +00:00
break;
case 0x6: // no connection (wall + torches),
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicNothing; // No door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 18); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 17); // ...torches.
2013-06-30 12:10:33 +00:00
break;
case 0x7: // wall with door and torches
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicNothing; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicSpecial; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 18); // Wall, plus...
_vm->_background->drawBackgroundSprite(-1, -1, 20); // ...door, and...
_vm->_background->drawBackgroundSprite(-1, -1, 17); // ...torches.
2013-06-30 12:10:33 +00:00
break;
case 0xf: // straight-through corridor.
_vm->_gyro->_magics[4]._operation = Gyro::kMagicNothing; // Sloping wall.
_vm->_gyro->_magics[5]._operation = Gyro::kMagicSpecial; // Straight wall.
_vm->_gyro->_portals[6]._operation = Gyro::kMagicNothing; // Door.
2013-06-30 12:10:33 +00:00
break;
}
2013-06-27 10:13:00 +00:00
switch ((here & 0xf00) >> 8) { // South
case 0: // No connection.
_vm->_gyro->_magics[6]._operation = Gyro::kMagicBounce;
_vm->_gyro->_magics[11]._operation = Gyro::kMagicBounce;
_vm->_gyro->_magics[12]._operation = Gyro::kMagicBounce;
2013-06-30 12:10:33 +00:00
break;
case 0x1:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 21);
if ((xy_uint16 == 2051) && (_vm->_gyro->_geidaFollows))
_vm->_gyro->_magics[12]._operation = Gyro::kMagicExclaim;
else
_vm->_gyro->_magics[12]._operation = Gyro::kMagicSpecial; // Right exit south.
2013-06-27 10:13:00 +00:00
_vm->_gyro->_magics[6]._operation = Gyro::kMagicBounce;
_vm->_gyro->_magics[11]._operation = Gyro::kMagicBounce;
2013-06-30 12:10:33 +00:00
break;
case 0x2:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 22);
_vm->_gyro->_magics[6]._operation = Gyro::kMagicSpecial; // Middle exit south.
_vm->_gyro->_magics[11]._operation = Gyro::kMagicBounce;
_vm->_gyro->_magics[12]._operation = Gyro::kMagicBounce;
2013-06-30 12:10:33 +00:00
break;
case 0x3:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 23);
_vm->_gyro->_magics[11]._operation = Gyro::kMagicSpecial; // Left exit south.
_vm->_gyro->_magics[6]._operation = Gyro::kMagicBounce;
_vm->_gyro->_magics[12]._operation = Gyro::kMagicBounce;
2013-06-30 12:10:33 +00:00
break;
2013-06-27 10:13:00 +00:00
}
switch ((here & 0xf000) >> 12) { // North
case 0: // No connection
_vm->_gyro->_magics[0]._operation = Gyro::kMagicBounce;
_vm->_gyro->_portals[3]._operation = Gyro::kMagicNothing; // Door.
2013-06-30 12:10:33 +00:00
break;
// LEFT handles:
#if 0
2013-06-30 12:10:33 +00:00
case 0x1:
_vm->_celer->show_one(-1, -1, 4);
_vm->_gyro->magics[1].op = _vm->_gyro->bounces; // { Left exit north. } { Change magic number! }
_vm->_gyro->portals[12].op = _vm->_gyro->special; // { Door. }
2013-06-30 12:10:33 +00:00
break;
#endif
2013-06-30 12:10:33 +00:00
case 0x2:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 3);
_vm->_gyro->_magics[0]._operation = Gyro::kMagicBounce; // Middle exit north.
_vm->_gyro->_portals[3]._operation = Gyro::kMagicSpecial; // Door.
2013-06-30 12:10:33 +00:00
break;
#if 0
case 0x3:
_vm->_celer->show_one(-1, -1, 4);
_vm->_gyro->magics[1].op = _vm->_gyro->bounces; // { Right exit north. } { Change magic number! }
_vm->_gyro->portals[12].op = _vm->_gyro->special; // { Door. }
2013-06-30 12:10:33 +00:00
break;
// RIGHT handles:
case 0x4:
_vm->_celer->show_one(-1, -1, 3);
_vm->_gyro->magics[1].op = _vm->_gyro->bounces; // { Left exit north. } { Change magic number! }
_vm->_gyro->portals[12].op = _vm->_gyro->special; // { Door. }
2013-06-30 12:10:33 +00:00
break;
#endif
2013-06-30 12:10:33 +00:00
case 0x5:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 2);
_vm->_gyro->_magics[0]._operation = Gyro::kMagicBounce; // Middle exit north.
_vm->_gyro->_portals[3]._operation = Gyro::kMagicSpecial; // Door.
2013-06-30 12:10:33 +00:00
break;
#if 0
2013-06-30 12:10:33 +00:00
case 0x6:
_vm->_celer->show_one(-1, -1, 3);
_vm->_gyro->magics[1].op = _vm->_gyro->bounces; // { Right exit north. }
_vm->_gyro->portals[12].op = _vm->_gyro->special; // { Door. }
2013-06-30 12:10:33 +00:00
break;
#endif
2013-06-30 12:10:33 +00:00
// ARCHWAYS:
case 0x7:
case 0x8:
case 0x9:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 5);
2013-06-30 12:10:33 +00:00
if (((here & 0xf000) >> 12) > 0x7)
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 30);
2013-06-30 12:10:33 +00:00
if (((here & 0xf000) >> 12) == 0x9)
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 31);
_vm->_gyro->_magics[0]._operation = Gyro::kMagicSpecial; // Middle arch north.
_vm->_gyro->_portals[3]._operation = Gyro::kMagicNothing; // Door.
break;
// DECORATIONS:
case 0xd: // No connection + WINDOW
_vm->_gyro->_magics[0]._operation = Gyro::kMagicBounce;
_vm->_gyro->_portals[3]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 13);
2013-06-30 12:10:33 +00:00
break;
case 0xe: // No connection + TORCH
_vm->_gyro->_magics[0]._operation = Gyro::kMagicBounce;
_vm->_gyro->_portals[3]._operation = Gyro::kMagicNothing; // Door.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 7);
2013-06-30 12:10:33 +00:00
break;
// Recessed door:
2013-06-30 12:10:33 +00:00
case 0xf:
_vm->_gyro->_magics[0]._operation = Gyro::kMagicNothing; // Door to Geida's room.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 0);
_vm->_gyro->_portals[3]._operation = Gyro::kMagicSpecial; // Door.
2013-06-30 12:10:33 +00:00
break;
2013-06-27 10:13:00 +00:00
}
switch (xy_uint16) {
case 514:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 16);
break; // [2,2] : "Art Gallery" sign over door.
case 264:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 8);
break; // [8,1] : "The Wrong Way!" sign.
case 1797:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 1);
break; // [5,7] : "Ite Mingite" sign.
case 258:
for (int i = 0; i <= 2; i++) { // [2,1] : Art gallery - pictures
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(130 + i * 120, 70, 14);
_vm->_background->drawBackgroundSprite(184 + i * 120, 78, 15);
}
break;
case 1287:
for (int i = 10; i <= 13; i++)
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, i - 1);
break; // [7,5] : 4 candles.
case 776:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 9);
break; // [8,3] : 1 candle.
case 2049:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 10);
break; // [1,8] : another candle.
2013-06-30 12:10:33 +00:00
case 257:
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 11);
_vm->_background->drawBackgroundSprite(-1, -1, 12);
break; // [1,1] : the other two.
2013-06-27 10:13:00 +00:00
}
if ((_vm->_gyro->_geidaFollows) && (ped > 0)) {
if (!_sprites[1]._quick) // If we don't already have her...
_sprites[1].init(5, true, this); // ...Load Geida.
2013-09-21 13:36:13 +00:00
appearPed(1, geidaPed(ped));
_sprites[1]._callEachStepFl = true;
_sprites[1]._eachStepProc = kProcGeida;
}
}
// This proc gets called whenever you touch a line defined as _vm->_gyro->special.
void Animation::dawnDelay() {
_vm->_timer->addTimer(2, Timer::kProcDawnDelay, Timer::kReasonDawndelay);
}
void Animation::callSpecial(uint16 which) {
switch (which) {
case 1: // _vm->_gyro->special 1: Room 22: top of stairs.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 0);
_vm->_gyro->_brummieStairs = 1;
_vm->_gyro->_magics[9]._operation = Gyro::kMagicNothing;
_vm->_timer->addTimer(10, Timer::kProcStairs, Timer::kReasonBrummieStairs);
stopWalking();
_vm->_gyro->_userMovesAvvy = false;
break;
case 2: // _vm->_gyro->special 2: Room 22: bottom of stairs.
_vm->_gyro->_brummieStairs = 3;
_vm->_gyro->_magics[10]._operation = Gyro::kMagicNothing;
_vm->_gyro->_magics[11]._operation = Gyro::kMagicExclaim;
2013-09-06 14:23:57 +00:00
_vm->_gyro->_magics[11]._data = 5;
_vm->_gyro->_magics[3]._operation = Gyro::kMagicBounce; // Now works as planned!
stopWalking();
_vm->_scrolls->displayScrollChain('q', 26);
_vm->_gyro->_userMovesAvvy = true;
2013-06-30 12:10:33 +00:00
break;
case 3: // _vm->_gyro->special 3: Room 71: triggers dart.
_sprites[0].bounce(); // Must include that.
if (!_vm->_gyro->_arrowTriggered) {
_vm->_gyro->_arrowTriggered = true;
appearPed(1, 3); // The dart starts at ped 4, and...
_sprites[1].walkTo(4); // flies to ped 5 (- 1 for pascal to C conversion).
_sprites[1]._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!
_sprites[1]._callEachStepFl = true;
_sprites[1]._eachStepProc = kProcArrow;
2013-06-27 10:13:00 +00:00
}
2013-06-30 12:10:33 +00:00
break;
case 4: // This is the ghost room link.
_vm->_lucerna->dusk();
_sprites[0].turn(kDirRight); // you'll see this after we get back from bootstrap
_vm->_timer->addTimer(1, Timer::kProcGhostRoomPhew, Timer::kReasonGhostRoomPhew);
2013-09-15 11:21:03 +00:00
//_vm->_enid->backToBootstrap(3); TODO: Replace it with proper ScummVM-friendly function(s)! Do not remove until then!
2013-06-30 12:10:33 +00:00
break;
case 5:
if (_vm->_gyro->_friarWillTieYouUp) {
// _vm->_gyro->special 5: Room 42: touched tree, and get tied up.
_vm->_gyro->_magics[4]._operation = Gyro::kMagicBounce; // Boundary effect is now working again.
_vm->_scrolls->displayScrollChain('q', 35);
_sprites[0].remove();
//tr[1].vanishifstill:=true;
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 1);
_vm->_scrolls->displayScrollChain('q', 36);
_vm->_gyro->_tiedUp = true;
_vm->_gyro->_friarWillTieYouUp = false;
_sprites[1].walkTo(2);
_sprites[1]._vanishIfStill = true;
_sprites[1]._doCheck = true; // One of them must have Check_Me switched on.
_vm->_gyro->_whereIs[Gyro::kPeopleFriarTuck - 150] = kRoomDummy; // Not here, then.
_vm->_timer->addTimer(364, Timer::kProcHangAround, Timer::kReasonHangingAround);
2013-06-27 10:13:00 +00:00
}
break;
case 6: // _vm->_gyro->special 6: fall down oubliette.
_vm->_gyro->_userMovesAvvy = false;
_sprites[0]._moveX = 3;
_sprites[0]._moveY = 0;
_sprites[0]._facingDir = kDirRight;
_vm->_timer->addTimer(1, Timer::kProcFallDownOubliette, Timer::kReasonFallingDownOubliette);
2013-06-30 12:10:33 +00:00
break;
case 7: // _vm->_gyro->special 7: stop falling down oubliette.
_sprites[0]._visible = false;
_vm->_gyro->_magics[9]._operation = Gyro::kMagicNothing;
stopWalking();
_vm->_timer->loseTimer(Timer::kReasonFallingDownOubliette);
//_vm->_lucerna->mblit(12, 80, 38, 160, 3, 0);
//_vm->_lucerna->mblit(12, 80, 38, 160, 3, 1);
2013-09-07 18:37:42 +00:00
_vm->_scrolls->displayText("Oh dear, you seem to be down the bottom of an oubliette.");
_vm->_timer->addTimer(200, Timer::kProcMeetAvaroid, Timer::kReasonMeetingAvaroid);
2013-06-30 12:10:33 +00:00
break;
case 8: // _vm->_gyro->special 8: leave du Lustie's room.
if ((_vm->_gyro->_geidaFollows) && (!_vm->_gyro->_lustieIsAsleep)) {
_vm->_scrolls->displayScrollChain('q', 63);
_sprites[1].turn(kDirDown);
_sprites[1].stopWalk();
_sprites[1]._callEachStepFl = false; // Geida
_vm->_lucerna->gameOver();
2013-06-27 10:13:00 +00:00
}
break;
case 9: // _vm->_gyro->special 9: lose Geida to Robin Hood...
if (!_vm->_gyro->_geidaFollows)
return; // DOESN'T COUNT: no Geida.
_sprites[1]._callEachStepFl = false; // She no longer follows Avvy around.
_sprites[1].walkTo(3); // She walks to somewhere...
_sprites[0].remove(); // Lose Avvy.
_vm->_gyro->_userMovesAvvy = false;
_vm->_timer->addTimer(40, Timer::kProcRobinHoodAndGeida, Timer::kReasonRobinHoodAndGeida);
2013-06-30 12:10:33 +00:00
break;
case 10: // _vm->_gyro->special 10: transfer north in catacombs.
if ((_vm->_gyro->_catacombX == 4) && (_vm->_gyro->_catacombY == 1)) {
// Into Geida's room.
if (_vm->_gyro->_objects[Gyro::kObjectKey - 1])
_vm->_scrolls->displayScrollChain('q', 62);
else {
_vm->_scrolls->displayScrollChain('q', 61);
return;
}
}
_vm->_lucerna->dusk();
_vm->_gyro->_catacombY--;
catacombMove(4);
if (_vm->_gyro->_room != kRoomCatacombs)
2013-06-30 12:10:33 +00:00
return;
switch ((_vm->_gyro->kCatacombMap[_vm->_gyro->_catacombY - 1][_vm->_gyro->_catacombX - 1] & 0xf00) >> 8) {
case 0x1:
appearPed(0, 11);
break;
case 0x3:
appearPed(0, 10);
break;
default:
appearPed(0, 3);
}
dawnDelay();
2013-06-30 12:10:33 +00:00
break;
case 11: // _vm->_gyro->special 11: transfer east in catacombs.
_vm->_lucerna->dusk();
_vm->_gyro->_catacombX++;
catacombMove(1);
if (_vm->_gyro->_room != kRoomCatacombs)
2013-06-30 12:10:33 +00:00
return;
appearPed(0, 0);
dawnDelay();
2013-06-30 12:10:33 +00:00
break;
case 12: // _vm->_gyro->special 12: transfer south in catacombs.
_vm->_lucerna->dusk();
_vm->_gyro->_catacombY += 1;
catacombMove(2);
if (_vm->_gyro->_room != kRoomCatacombs)
2013-06-30 12:10:33 +00:00
return;
appearPed(0, 1);
dawnDelay();
2013-06-30 12:10:33 +00:00
break;
case 13: // _vm->_gyro->special 13: transfer west in catacombs.
_vm->_lucerna->dusk();
_vm->_gyro->_catacombX--;
catacombMove(3);
if (_vm->_gyro->_room != kRoomCatacombs)
2013-06-30 12:10:33 +00:00
return;
appearPed(0, 2);
dawnDelay();
2013-06-30 12:10:33 +00:00
break;
}
}
2013-09-07 21:42:34 +00:00
/**
* Open the Door.
* This slides the door open. The data really ought to be saved in
* the Also file, and will be next time. However, for now, they're
* here.
* @remarks Originally called 'open_the_door'
*/
void Animation::openDoor(byte whither, byte ped, byte magicnum) {
switch (_vm->_gyro->_room) {
case kRoomOutsideYours:
case kRoomOutsideNottsPub:
case kRoomOutsideDucks:
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(1);
_vm->_sequence->thenShow(2);
_vm->_sequence->thenShow(3);
2013-06-30 12:10:33 +00:00
break;
case kRoomInsideCardiffCastle:
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(1);
_vm->_sequence->thenShow(5);
2013-06-30 12:10:33 +00:00
break;
case kRoomAvvysGarden:
case kRoomEntranceHall:
case kRoomInsideAbbey:
case kRoomYourHall:
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(1);
_vm->_sequence->thenShow(2);
2013-06-30 12:10:33 +00:00
break;
case kRoomMusicRoom:
case kRoomOutsideArgentPub:
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(5);
_vm->_sequence->thenShow(6);
2013-06-30 12:10:33 +00:00
break;
case kRoomLusties:
switch (magicnum) {
case 14:
if (_vm->_gyro->_avvysInTheCupboard) {
hideInCupboard();
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(8);
_vm->_sequence->thenShow(7);
_vm->_sequence->startToClose();
return;
} else {
appearPed(0, 5);
_sprites[0]._facingDir = kDirRight; // added by TT 12/3/1995
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(8);
_vm->_sequence->thenShow(9);
2013-06-27 10:13:00 +00:00
}
break;
2013-06-30 12:10:33 +00:00
case 12:
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(4);
_vm->_sequence->thenShow(5);
_vm->_sequence->thenShow(6);
2013-06-30 12:10:33 +00:00
break;
2013-06-27 10:13:00 +00:00
}
break;
2013-06-27 10:13:00 +00:00
}
2013-09-07 22:02:20 +00:00
_vm->_sequence->thenFlip(whither, ped);
_vm->_sequence->startToOpen();
}
2013-06-27 10:13:00 +00:00
void Animation::updateSpeed() {
2013-09-07 21:42:34 +00:00
// Given that you've just changed the speed in triptype._speedX, this adjusts _moveX.
2013-08-17 15:14:00 +00:00
_sprites[0]._moveX = (_sprites[0]._moveX / 3) * _sprites[0]._speedX;
if (_sprites[0]._speedX == _vm->_gyro->kRun)
2013-09-05 21:07:08 +00:00
_vm->_graphics->_surface.drawLine(371, 199, 373, 199, kColorYellow);
2013-08-17 15:14:00 +00:00
else
2013-09-05 21:07:08 +00:00
_vm->_graphics->_surface.drawLine(336, 199, 338, 199, kColorYellow);
2013-08-17 15:14:00 +00:00
if (_sprites[0]._speedX == _vm->_gyro->kRun)
2013-09-05 21:07:08 +00:00
_vm->_graphics->_surface.drawLine(336, 199, 338, 199, kColorLightblue);
2013-08-17 15:14:00 +00:00
else
2013-09-05 21:07:08 +00:00
_vm->_graphics->_surface.drawLine(371, 199, 373, 199, kColorLightblue);
}
2013-06-27 10:13:00 +00:00
void Animation::changeDirection(byte t, byte dir) {
2013-09-04 15:54:08 +00:00
switch (dir) {
case kDirUp:
_sprites[t].setSpeed(0, -_sprites[t]._speedY);
2013-06-30 12:10:33 +00:00
break;
case kDirDown:
_sprites[t].setSpeed(0, _sprites[t]._speedY);
2013-06-30 12:10:33 +00:00
break;
case kDirLeft:
_sprites[t].setSpeed(-_sprites[t]._speedX, 0);
2013-06-30 12:10:33 +00:00
break;
case kDirRight:
_sprites[t].setSpeed(_sprites[t]._speedX, 0);
2013-06-30 12:10:33 +00:00
break;
case kDirUpLeft:
_sprites[t].setSpeed(-_sprites[t]._speedX, -_sprites[t]._speedY);
2013-06-30 12:10:33 +00:00
break;
case kDirUpRight:
_sprites[t].setSpeed(_sprites[t]._speedX, -_sprites[t]._speedY);
2013-06-30 12:10:33 +00:00
break;
case kDirDownLeft:
_sprites[t].setSpeed(-_sprites[t]._speedX, _sprites[t]._speedY);
2013-06-30 12:10:33 +00:00
break;
case kDirDownRight:
_sprites[t].setSpeed(_sprites[t]._speedX, _sprites[t]._speedY);
2013-06-30 12:10:33 +00:00
break;
}
}
2013-06-27 10:13:00 +00:00
2013-09-15 08:50:43 +00:00
void Animation::appearPed(byte sprNum, byte pedNum) {
AnimationType *curSpr = &_sprites[sprNum];
PedType *curPed = &_vm->_gyro->_peds[pedNum];
2013-09-15 08:50:43 +00:00
curSpr->appear(curPed->_x - curSpr->_info._xLength / 2, curPed->_y - curSpr->_info._yLength, curPed->_direction);
changeDirection(sprNum, curPed->_direction);
}
void Animation::followAvalotY(byte tripnum) {
if (_sprites[0]._facingDir == kDirLeft)
return;
if (_sprites[tripnum]._homing)
_sprites[tripnum]._homingY = _sprites[1]._y;
else {
if (_sprites[tripnum]._y < _sprites[1]._y)
_sprites[tripnum]._y += 1;
else if (_sprites[tripnum]._y > _sprites[1]._y)
_sprites[tripnum]._y -= 1;
else
2013-06-27 10:13:00 +00:00
return;
if (_sprites[tripnum]._moveX == 0) {
_sprites[tripnum]._stepNum += 1;
if (_sprites[tripnum]._stepNum == _sprites[tripnum]._stat._seq)
_sprites[tripnum]._stepNum = 0;
_sprites[tripnum]._count = 0;
2013-06-27 10:13:00 +00:00
}
}
}
2013-06-27 10:13:00 +00:00
void Animation::backAndForth(byte tripnum) {
if (!_sprites[tripnum]._homing) {
if (_sprites[tripnum]._facingDir == kDirRight)
_sprites[tripnum].walkTo(3);
else
_sprites[tripnum].walkTo(4);
2013-06-27 10:13:00 +00:00
}
}
2013-06-27 10:13:00 +00:00
void Animation::faceAvvy(byte tripnum) {
if (!_sprites[tripnum]._homing) {
if (_sprites[0]._x >= _sprites[tripnum]._x)
_sprites[tripnum]._facingDir = kDirRight;
2013-06-30 12:10:33 +00:00
else
_sprites[tripnum]._facingDir = kDirLeft;
2013-06-27 10:13:00 +00:00
}
}
2013-06-27 10:13:00 +00:00
void Animation::arrowProcs(byte tripnum) {
if (_sprites[tripnum]._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 (((_sprites[tripnum]._y + _sprites[tripnum]._info._yLength) >= _sprites[0]._y) // A
&& (_sprites[tripnum]._x <= (_sprites[0]._x + _sprites[0]._info._xLength)) // B
&& ((_sprites[tripnum]._x + _sprites[tripnum]._info._xLength) >= _sprites[0]._x)) { // C
// OK, it's hit him... what now?
_sprites[1]._callEachStepFl = false; // prevent recursion.
_vm->_scrolls->displayScrollChain('Q', 47); // Complaint!
_sprites[tripnum].remove(); // Deallocate the arrow.
_vm->_lucerna->gameOver();
_vm->_gyro->_userMovesAvvy = false; // Stop the user from moving him.
_vm->_timer->addTimer(55, Timer::kProcNaughtyDuke, Timer::kReasonNaughtyDuke);
2013-06-27 10:13:00 +00:00
}
} else { // Arrow has hit the wall!
_sprites[tripnum].remove(); // Deallocate the arrow.
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 2); // Show pic of arrow stuck into the door.
_vm->_gyro->_arrowInTheDoor = true; // So that we can pick it up.
2013-06-27 10:13:00 +00:00
}
}
void Animation::grabAvvy(byte tripnum) { // For Friar Tuck, in Nottingham.
int16 tox = _sprites[0]._x + 17;
int16 toy = _sprites[0]._y - 1;
if ((_sprites[tripnum]._x == tox) && (_sprites[tripnum]._y == toy)) {
_sprites[tripnum]._callEachStepFl = false;
_sprites[tripnum]._facingDir = kDirLeft;
_sprites[tripnum].stopWalk();
// ... whatever ...
} else {
// Still some way to go.
if (_sprites[tripnum]._x < tox) {
_sprites[tripnum]._x += 5;
if (_sprites[tripnum]._x > tox)
_sprites[tripnum]._x = tox;
}
if (_sprites[tripnum]._y < toy)
_sprites[tripnum]._y++;
_sprites[tripnum]._stepNum++;
if (_sprites[tripnum]._stepNum == _sprites[tripnum]._stat._seq)
_sprites[tripnum]._stepNum = 0;
2013-06-27 10:13:00 +00:00
}
}
2013-06-27 10:13:00 +00:00
void Animation::takeAStep(byte &tripnum) {
if (_sprites[tripnum]._moveX == 0) {
_sprites[tripnum]._stepNum++;
if (_sprites[tripnum]._stepNum == _sprites[tripnum]._stat._seq)
_sprites[tripnum]._stepNum = 0;
_sprites[tripnum]._count = 0;
2013-06-27 10:13:00 +00:00
}
}
2013-06-27 10:13:00 +00:00
void Animation::spin(byte whichway, byte &tripnum) {
if (_sprites[tripnum]._facingDir != whichway) {
_sprites[tripnum]._facingDir = whichway;
if (_sprites[tripnum]._id == 2)
return; // Not for Spludwick
2013-06-27 10:13:00 +00:00
_vm->_gyro->_geidaSpin += 1;
_vm->_gyro->_geidaTime = 20;
if (_vm->_gyro->_geidaSpin == 5) {
2013-09-07 18:37:42 +00:00
_vm->_scrolls->displayText("Steady on, Avvy, you'll make the poor girl dizzy!");
_vm->_gyro->_geidaSpin = 0;
_vm->_gyro->_geidaTime = 0; // knock out records
2013-06-27 10:13:00 +00:00
}
}
}
2013-06-27 10:13:00 +00:00
void Animation::geidaProcs(byte tripnum) {
if (_vm->_gyro->_geidaTime > 0) {
_vm->_gyro->_geidaTime--;
if (_vm->_gyro->_geidaTime == 0)
_vm->_gyro->_geidaSpin = 0;
}
2013-06-27 10:13:00 +00:00
if (_sprites[tripnum]._y < (_sprites[0]._y - 2)) {
// Geida is further from the screen than Avvy.
spin(kDirDown, tripnum);
_sprites[tripnum]._moveY = 1;
_sprites[tripnum]._moveX = 0;
takeAStep(tripnum);
return;
} else if (_sprites[tripnum]._y > (_sprites[0]._y + 2)) {
// Avvy is further from the screen than Geida.
spin(kDirUp, tripnum);
_sprites[tripnum]._moveY = -1;
_sprites[tripnum]._moveX = 0;
takeAStep(tripnum);
return;
2013-06-27 10:13:00 +00:00
}
_sprites[tripnum]._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 (_sprites[tripnum]._x < _sprites[0]._x - _sprites[0]._speedX * 8 - 12) {
_sprites[tripnum]._moveX = _sprites[0]._speedX;
spin(kDirRight, tripnum);
takeAStep(tripnum);
} else if (_sprites[tripnum]._x > _sprites[0]._x + _sprites[0]._speedX * 8 + 12) {
_sprites[tripnum]._moveX = -_sprites[0]._speedX;
spin(kDirLeft, tripnum);
takeAStep(tripnum);
2013-06-30 12:10:33 +00:00
} else
_sprites[tripnum]._moveX = 0;
}
// That's all...
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++) {
if (_sprites[i]._quick && _sprites[i]._visible)
order[i] = i;
}
2013-06-27 10:13:00 +00:00
do {
ok = true;
2013-09-16 20:57:38 +00:00
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;
}
2013-06-30 12:10:33 +00:00
}
} while (!ok);
2013-06-27 10:13:00 +00:00
_vm->_graphics->refreshBackground();
2013-09-16 20:57:38 +00:00
for (int i = 0; i < 5; i++) {
if (order[i] > -1)
_sprites[order[i]].draw();
2013-06-30 12:10:33 +00:00
}
}
2013-06-27 10:13:00 +00:00
/**
* Animation links
* @remarks Originally called 'trippancy_link'
*/
void Animation::animLink() {
if (_vm->_menu->isActive() | _vm->_gyro->_onToolbar | _vm->_gyro->_seeScroll)
2013-06-30 12:10:33 +00:00
return;
for (int16 i = 0; i < kSpriteNumbMax; i++) {
if (_sprites[i]._quick && _sprites[i]._visible)
_sprites[i].walk();
}
2013-06-27 10:13:00 +00:00
drawSprites();
for (int16 i = 0; i < kSpriteNumbMax; i++) {
if (_sprites[i]._quick && _sprites[i]._callEachStepFl) {
switch (_sprites[i]._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;
2013-06-27 10:13:00 +00:00
}
}
}
if (_mustExclaim) {
_mustExclaim = false;
_vm->_scrolls->displayScrollChain('x', _sayWhat);
2013-06-30 12:10:33 +00:00
}
}
void Animation::stopWalking() {
_sprites[0].stopWalk();
_direction = kDirStopped;
2013-09-06 14:23:57 +00:00
if (_vm->_gyro->_alive)
_sprites[0]._stepNum = 1;
}
2013-06-27 10:13:00 +00:00
/**
* Hide in the cupboard
* @remarks Originally called 'hide_in_the_cupboard'
*/
void Animation::hideInCupboard() {
if (_vm->_gyro->_avvysInTheCupboard) {
if (_vm->_gyro->_wearing == Acci::kNothing) {
2013-09-08 21:13:58 +00:00
Common::String tmpStr = Common::String::format("%cAVVY!%cGet dressed first!", Scrolls::kControlItalic, Scrolls::kControlRoman);
_vm->_scrolls->displayText(tmpStr);
} else {
_sprites[0]._visible = true;
_vm->_gyro->_userMovesAvvy = true;
appearPed(0, 2); // Walk out of the cupboard.
2013-09-07 18:37:42 +00:00
_vm->_scrolls->displayText("You leave the cupboard. Nice to be out of there!");
_vm->_gyro->_avvysInTheCupboard = false;
2013-09-07 22:02:20 +00:00
_vm->_sequence->firstShow(8);
_vm->_sequence->thenShow(7);
_vm->_sequence->startToClose();
}
} else {
// Not hiding in the cupboard
_sprites[0]._visible = false;
_vm->_gyro->_userMovesAvvy = false;
2013-09-08 21:13:58 +00:00
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.", Scrolls::kControlParagraph);
_vm->_scrolls->displayText(tmpStr);
_vm->_gyro->_avvysInTheCupboard = true;
2013-09-19 18:53:47 +00:00
_vm->_background->drawBackgroundSprite(-1, -1, 7);
2013-06-27 10:13:00 +00:00
}
}
2013-06-27 10:13:00 +00:00
void Animation::flipRoom(byte room, byte ped) {
assert((ped > 0) && (ped < 15));
2013-09-06 14:23:57 +00:00
if (!_vm->_gyro->_alive) {
// You can't leave the room if you're dead.
_sprites[0]._moveX = 0;
_sprites[0]._moveY = 0; // Stop him from moving.
return;
}
2013-06-27 10:13:00 +00:00
if ((room == kRoomDummy) && (_vm->_gyro->_room == kRoomLusties)) {
hideInCupboard();
return;
}
2013-06-27 10:13:00 +00:00
if ((_vm->_gyro->_jumpStatus > 0) && (_vm->_gyro->_room == kRoomInsideCardiffCastle)) {
// You can't *jump* out of Cardiff Castle!
_sprites[0]._moveX = 0;
return;
}
2013-06-27 10:13:00 +00:00
_vm->_lucerna->exitRoom(_vm->_gyro->_room);
_vm->_lucerna->dusk();
2013-06-27 10:13:00 +00:00
for (int16 i = 1; i < kSpriteNumbMax; i++) {
if (_sprites[i]._quick)
_sprites[i].remove();
} // Deallocate sprite
2013-06-27 10:13:00 +00:00
if (_vm->_gyro->_room == kRoomLustiesRoom)
_vm->_gyro->_enterCatacombsFromLustiesRoom = true;
2013-06-27 10:13:00 +00:00
_vm->_lucerna->enterRoom(room, ped);
appearPed(0, ped - 1);
_vm->_gyro->_enterCatacombsFromLustiesRoom = false;
_oldDirection = _direction;
_direction = _sprites[0]._facingDir;
_vm->_lucerna->drawDirection();
2013-06-27 10:13:00 +00:00
_vm->_lucerna->dawn();
}
2013-06-27 10:13:00 +00:00
bool Animation::inField(byte which) {
FieldType *curField = &_vm->_gyro->_fields[which];
int16 yy = _sprites[0]._y + _sprites[0]._info._yLength;
2013-06-27 10:13:00 +00:00
2013-09-15 08:50:43 +00:00
return (_sprites[0]._x >= curField->_x1) && (_sprites[0]._x <= curField->_x2) && (yy >= curField->_y1) && (yy <= curField->_y2);
}
bool Animation::nearDoor() {
2013-09-06 14:23:57 +00:00
if (_vm->_gyro->_fieldNum < 8) {
// there ARE no doors here!
return false;
2013-06-27 10:13:00 +00:00
}
int16 ux = _sprites[0]._x;
int16 uy = _sprites[0]._y + _sprites[0]._info._yLength;
2013-09-15 08:50:43 +00:00
2013-09-16 20:57:38 +00:00
for (int i = 8; i < _vm->_gyro->_fieldNum; i++) {
2013-09-15 08:50:43 +00:00
FieldType *curField = &_vm->_gyro->_fields[i];
if ((ux >= curField->_x1) && (ux <= curField->_x2) && (uy >= curField->_y1) && (uy <= curField->_y2))
return true;
}
return false;
}
2013-06-27 10:13:00 +00:00
void Animation::handleMoveKey(const Common::Event &event) {
if (!_vm->_gyro->_userMovesAvvy)
return;
if (_vm->_menu->_activeMenuItem._activeNow)
_vm->_parser->tryDropdown();
else {
switch (event.kbd.keycode) {
case Common::KEYCODE_UP:
if (_direction != kDirUp) {
_direction = kDirUp;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_DOWN:
if (_direction != kDirDown) {
_direction = kDirDown;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_LEFT:
if (_direction != kDirLeft) {
_direction = kDirLeft;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_RIGHT:
if (_direction != kDirRight) {
_direction = kDirRight;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_PAGEUP:
if (_direction != kDirUpRight) {
_direction = kDirUpRight;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_PAGEDOWN:
if (_direction != kDirDownRight) {
_direction = kDirDownRight;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_END:
if (_direction != kDirDownLeft) {
_direction = kDirDownLeft;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_HOME:
if (_direction != kDirUpLeft) {
_direction = kDirUpLeft;
changeDirection(0, _direction);
} else
stopWalking();
break;
case Common::KEYCODE_KP5:
stopWalking();
break;
2013-09-04 15:15:33 +00:00
default:
break;
}
}
}
2013-06-27 10:13:00 +00:00
} // End of namespace Avalanche.