diff options
Diffstat (limited to 'engines')
42 files changed, 31306 insertions, 0 deletions
diff --git a/engines/gnap/character.cpp b/engines/gnap/character.cpp new file mode 100644 index 0000000000..76e30d9dfa --- /dev/null +++ b/engines/gnap/character.cpp @@ -0,0 +1,1447 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/character.h" +#include "gnap/gamesys.h" + +namespace Gnap { + +Character::Character(GnapEngine *vm) : _vm(vm) { + _pos = Common::Point(0, 0); + _idleFacing = kDirIdleLeft; + _actionStatus = 0; + _sequenceId = 0; + _sequenceDatNum = 0; + _id = 0; + _gridX = 0; + _gridY = 0; + + _walkNodesCount = 0; + _walkDestX = _walkDestY = 0; + _walkDeltaX = _walkDeltaY = 0; + _walkDirX = _walkDirY = 0; + _walkDirXIncr = _walkDirYIncr = 0; + + for(int i = 0; i < kMaxGridStructs; i++) { + _walkNodes[i]._id = 0; + _walkNodes[i]._sequenceId = 0; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = 0; + _walkNodes[i]._gridX1 = 0; + _walkNodes[i]._gridY1 = 0; + } +} + +Character::~Character() {} + +void Character::walkStep() { + for (int i = 1; i < _vm->_gridMaxX; ++i) { + Common::Point checkPt = Common::Point(_pos.x + i, _pos.y); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x - i, _pos.y); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x, _pos.y + 1); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x, _pos.y - 1); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x + 1, _pos.y + 1); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x - 1, _pos.y + 1); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x + 1, _pos.y - 1); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + + checkPt = Common::Point(_pos.x - 1, _pos.y - 1); + if (!_vm->isPointBlocked(checkPt)) { + walkTo(checkPt, -1, -1, 1); + break; + } + } +} +/************************************************************************************************/ + +PlayerGnap::PlayerGnap(GnapEngine * vm) : Character(vm) { + _brainPulseNum = 0; + _brainPulseRndValue = 0; +} + +int PlayerGnap::getSequenceId(int kind, Common::Point gridPos) { + int sequenceId = 0; + + switch (kind) { + case kGSPullOutDevice: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x83F; + _idleFacing = kDirUpLeft; + } else { + sequenceId = 0x83D; + _idleFacing = kDirUpRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x83B; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x839; + _idleFacing = kDirBottomRight; + } + } + } else { + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = 0x839; + break; + case kDirBottomLeft: + sequenceId = 0x83B; + break; + case kDirUpRight: + sequenceId = 0x83D; + break; + default: + sequenceId = 0x83F; + break; + } + } + break; + + case kGSPullOutDeviceNonWorking: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x829; + _idleFacing = kDirUpLeft; + } else { + sequenceId = 0x828; + _idleFacing = kDirUpRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x827; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x826; + _idleFacing = kDirBottomRight; + } + } + } else { + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = 0x826; + break; + case kDirBottomLeft: + sequenceId = 0x827; + break; + case kDirUpRight: + sequenceId = 0x828; + break; + default: + sequenceId = 0x829; + break; + } + } + break; + + case kGSScratchingHead: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x834; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x885; + _idleFacing = kDirUpRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x834; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x833; + _idleFacing = kDirBottomRight; + } + } + } else { + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = 0x833; + _idleFacing = kDirBottomRight; + break; + case kDirBottomLeft: + sequenceId = 0x834; + _idleFacing = kDirBottomLeft; + break; + case kDirUpRight: + sequenceId = 0x885; + _idleFacing = kDirUpRight; + break; + default: + sequenceId = 0x834; + _idleFacing = kDirBottomLeft; + break; + } + } + break; + + case kGSIdle: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x7BC; + _idleFacing = kDirUpLeft; + } else { + sequenceId = 0x7BB; + _idleFacing = kDirUpRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x7BA; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7B9; + _idleFacing = kDirBottomRight; + } + } + } else { + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = 0x7B9; + break; + case kDirBottomLeft: + sequenceId = 0x7BA; + break; + case kDirUpRight: + sequenceId = 0x7BB; + break; + default: + sequenceId = 0x7BC; + break; + } + } + break; + + case kGSBrainPulsating: + _brainPulseNum = (_brainPulseNum + 1) & 1; + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812; + _idleFacing = kDirUpLeft; + } else { + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE; + _idleFacing = kDirUpRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA; + _idleFacing = kDirBottomRight; + } + } + } else { + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7EA; + break; + case kDirBottomLeft: + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7D6; + break; + case kDirUpRight: + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x7FE; + break; + default: + sequenceId = _brainPulseRndValue + _brainPulseNum + 0x812; + break; + } + } + break; + + case kGSImpossible: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x831; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7A8; + _idleFacing = kDirBottomRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x831; + _idleFacing = kDirBottomLeft; + } else { + if (_pos.x % 2) + sequenceId = 0x7A8; + else + sequenceId = 0x89A; + _idleFacing = kDirBottomRight; + } + } + } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) { + sequenceId = 0x831; + _idleFacing = kDirBottomLeft; + } else { + if (_vm->_currentSceneNum % 2) + sequenceId = 0x7A8; + else + sequenceId = 0x89A; + _idleFacing = kDirBottomRight; + } + break; + + case kGSDeflect: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x830; + _idleFacing = kDirUpLeft; + } else { + sequenceId = 0x82F; + _idleFacing = kDirUpRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x82E; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7A7; + _idleFacing = kDirBottomRight; + } + } + } else { + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = 0x7A7; + break; + case kDirBottomLeft: + sequenceId = 0x82E; + break; + case kDirUpLeft: + sequenceId = 0x830; + break; + case kDirUpRight: + sequenceId = 0x82F; + break; + case kDirIdleLeft: + case kDirIdleRight: + break; + } + } + break; + + case kGSUseDevice: + switch (_idleFacing) { + case kDirBottomRight: + sequenceId = 0x83A; + break; + case kDirBottomLeft: + sequenceId = 0x83C; + break; + case kDirUpLeft: + sequenceId = 0x840; + break; + case kDirUpRight: + sequenceId = 0x83E; + break; + case kDirIdleLeft: + case kDirIdleRight: + break; + } + break; + + case kGSMoan1: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x832; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7AA; + _idleFacing = kDirBottomRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x832; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7AA; + _idleFacing = kDirBottomRight; + } + } + } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) { + sequenceId = 0x832; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7AA; + _idleFacing = kDirBottomRight; + } + break; + + case kGSMoan2: + if (gridPos.x > 0 && gridPos.y > 0) { + if (_pos.y > gridPos.y) { + if (_pos.x > gridPos.x) { + sequenceId = 0x832; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7AA; + _idleFacing = kDirBottomRight; + } + } else { + if (_pos.x > gridPos.x) { + sequenceId = 0x832; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7AA; + _idleFacing = kDirBottomRight; + } + } + } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) { + sequenceId = 0x832; + _idleFacing = kDirBottomLeft; + } else { + sequenceId = 0x7AA; + _idleFacing = kDirBottomRight; + } + break; + } + + return sequenceId | 0x10000; +} + +void PlayerGnap::useJointOnPlatypus() { + PlayerPlat& plat = *_vm->_plat; + + _vm->setGrabCursorSprite(-1); + if (doPlatypusAction(1, 0, 0x107C1, 0)) { + _actionStatus = 100; + _vm->_gameSys->setAnimation(0, 0, 1); + _vm->_gameSys->setAnimation(0x10876, plat._id, 0); + _vm->_gameSys->insertSequence(0x10875, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 15 * (5 * _pos.x - 30), 48 * (_pos.y - 7)); + _sequenceDatNum = 1; + _sequenceId = 0x875; + _vm->_gameSys->insertSequence(0x10876, plat._id, + plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, + kSeqSyncWait, 0, 15 * (5 * plat._pos.x - 25), 48 * (plat._pos.y - 7)); + plat._sequenceDatNum = 1; + plat._sequenceId = 0x876; + plat._idleFacing = kDirIdleLeft; + playSequence(0x107B5); + walkStep(); + while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + _vm->_gameSys->setAnimation(0, 0, 0); + _actionStatus = -1; + } else { + playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000); + } +} + +void PlayerGnap::kissPlatypus(int callback) { + PlayerPlat& plat = *_vm->_plat; + + if (doPlatypusAction(-1, 0, 0x107D1, callback)) { + _actionStatus = 100; + _vm->_gameSys->setAnimation(0, 0, 1); + _vm->_gameSys->setAnimation(0x10847, _id, 0); + _vm->_gameSys->insertSequence(0x10847, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 15 * (5 * _pos.x - 20) - (21 - _vm->_gridMinX), 48 * (_pos.y - 6) - (146 - _vm->_gridMinY)); + _sequenceDatNum = 1; + _sequenceId = 0x847; + _vm->_gameSys->insertSequence(0x107CB, plat._id, + makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id, + kSeqSyncWait, _vm->getSequenceTotalDuration(0x10847), 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY); + plat._sequenceDatNum = 1; + plat._sequenceId = 0x7CB; + plat._idleFacing = kDirIdleLeft; + playSequence(0x107B5); + while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->doCallback(callback); + _vm->gameUpdateTick(); + } + _vm->_gameSys->setAnimation(0, 0, 0); + _actionStatus = -1; + } else { + playSequence(getSequenceId(kGSScratchingHead, plat._pos) | 0x10000); + } +} + +void PlayerGnap::useDeviceOnPlatypus() { + PlayerPlat& plat = *_vm->_plat; + + playSequence(makeRid(1, getSequenceId(kGSPullOutDevice, plat._pos))); + + if (plat._idleFacing != kDirIdleLeft) { + _vm->_gameSys->insertSequence(makeRid(1, 0x7D5), plat._id, + makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id, + kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY); + plat._sequenceId = 0x7D5; + plat._sequenceDatNum = 1; + } else { + _vm->_gameSys->insertSequence(makeRid(1, 0x7D4), plat._id, + makeRid(plat._sequenceDatNum, plat._sequenceId), plat._id, + kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY); + plat._sequenceId = 0x7D4; + plat._sequenceDatNum = 1; + } + + int newSequenceId = getSequenceId(kGSUseDevice, Common::Point(0, 0)); + _vm->_gameSys->insertSequence(makeRid(1, newSequenceId), _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = newSequenceId; + _sequenceDatNum = 1; +} + +void PlayerGnap::initBrainPulseRndValue() { + _brainPulseRndValue = 2 * _vm->getRandom(10); +} + +void PlayerGnap::playSequence(int sequenceId) { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = 300; + idle(); + _vm->_gameSys->insertSequence(sequenceId, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = ridToEntryIndex(sequenceId); + _sequenceDatNum = ridToDatIndex(sequenceId); +} + +void PlayerGnap::updateIdleSequence() { + if (_actionStatus < 0) { + if (_vm->_timers[2] > 0) { + if (_vm->_timers[3] == 0) { + _vm->_timers[2] = 60; + _vm->_timers[3] = 300; + if (_idleFacing == kDirBottomRight) { + switch (_vm->getRandom(5)) { + case 0: + playSequence(0x107A6); + break; + case 1: + playSequence(0x107AA); + break; + case 2: + playSequence(0x10841); + break; + default: + playSequence(0x108A2); + break; + } + } else if (_idleFacing == kDirBottomLeft) { + if (_vm->getRandom(5) > 2) + playSequence(0x10832); + else + playSequence(0x10842); + } + } + } else { + _vm->_timers[2] = _vm->getRandom(30) + 20; + if (_idleFacing == kDirBottomRight) { + _vm->_gameSys->insertSequence(0x107BD, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = 0x7BD; + _sequenceDatNum = 1; + } else if (_idleFacing == kDirBottomLeft) { + _vm->_gameSys->insertSequence(0x107BE, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = 0x7BE; + _sequenceDatNum = 1; + } + } + } else { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = 300; + } +} + +void PlayerGnap::updateIdleSequence2() { + if (_actionStatus < 0) { + if (_vm->_timers[2] > 0) { + if (_vm->_timers[3] == 0) { + _vm->_timers[2] = 60; + _vm->_timers[3] = 300; + if (_idleFacing == kDirBottomRight) { + playSequence(0x107AA); + } else if (_idleFacing == kDirBottomLeft) { + playSequence(0x10832); + } + } + } else { + _vm->_timers[2] = _vm->getRandom(30) + 20; + if (_idleFacing == kDirBottomRight) { + _vm->_gameSys->insertSequence(0x107BD, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = 0x7BD; + _sequenceDatNum = 1; + } else if (_idleFacing == kDirBottomLeft) { + _vm->_gameSys->insertSequence(0x107BE, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = 0x7BE; + _sequenceDatNum = 1; + } + } + } else { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = 300; + } +} + +void PlayerGnap::initPos(int gridX, int gridY, Facing facing) { + _vm->_timers[2] = 30; + _vm->_timers[3] = 300; + _pos = Common::Point(gridX, gridY); + if (facing == kDirIdleLeft) + _idleFacing = kDirBottomRight; + else + _idleFacing = facing; + + if (_idleFacing == kDirBottomLeft) { + _sequenceId = 0x7B8; + } else { + _sequenceId = 0x7B5; + _idleFacing = kDirBottomRight; + } + _id = 20 * _pos.y; + _sequenceDatNum = 1; + _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y, + 0, 0, + kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); +} + +int PlayerGnap::getWalkSequenceId(int deltaX, int deltaY) { + static const int walkSequenceIds[9] = { + 0x7B2, 0x000, 0x7B4, + 0x7AD, 0x000, 0x7AE, + 0x7B1, 0x000, 0x7B3 + }; + + int id = 3 * (deltaX + 1) + deltaY + 1; + assert(id >= 0 && id < 9); + + return walkSequenceIds[id]; +} + +bool PlayerGnap::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) { + PlayerPlat& plat = *_vm->_plat; + int datNum = flags & 3; + + _vm->_timers[2] = 200; + _vm->_timers[3] = 300; + + int gridX = gridPos.x; + if (gridX < 0) + gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75; + + int gridY = gridPos.y; + if (gridY < 0) + gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48; + + _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1); + _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1); + + if (animationIndex >= 0 && _walkDestX == plat._pos.x && _walkDestY == plat._pos.y) + plat.makeRoom(); + + bool done = findPath1(_pos.x, _pos.y, 0); + + if (!done) + done = findPath2(_pos.x, _pos.y, 0); + + if (!done) + done = findPath3(_pos.x, _pos.y); + + if (!done) + done = findPath4(_pos.x, _pos.y); + + idle(); + + int gnapSequenceId = _sequenceId; + int gnapId = _id; + int gnapSequenceDatNum = _sequenceDatNum; + + debugC(kDebugBasic, "_gnap->_walkNodesCount: %d", _walkNodesCount); + + for (int index = 0; index < _walkNodesCount; ++index) { + _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1; + if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) { + if (index % 2) { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AB), _walkNodes[index]._id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7AB; + gnapSequenceId = 0x7AB; + } else { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AC), _walkNodes[index]._id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7AC; + gnapSequenceId = 0x7AC; + } + } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) { + if (index % 2) { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7AF), _walkNodes[index]._id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7AF; + gnapSequenceId = 0x7AF; + } else { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7B0), _walkNodes[index]._id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7B0; + gnapSequenceId = 0x7B0; + } + } else { + if (_walkNodes[index]._deltaY == -1) + _walkNodes[index]._id -= 10; + else + _walkNodes[index]._id += 10; + int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY); + _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = newSequenceId; + gnapSequenceId = newSequenceId; + } + gnapId = _walkNodes[index]._id; + gnapSequenceDatNum = datNum; + } + + if (flags & 8) { + if (_walkNodesCount > 0) { + _sequenceId = gnapSequenceId; + _id = gnapId; + _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY); + _sequenceDatNum = datNum; + if (animationIndex >= 0) + _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex); + } else if (animationIndex >= 0) { + _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex); + _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0); + } + } else { + if (sequenceId >= 0 && sequenceId != -1) { + _sequenceId = ridToEntryIndex(sequenceId); + _sequenceDatNum = ridToDatIndex(sequenceId); + if (_sequenceId == 0x7B9) { + _idleFacing = kDirBottomRight; + } else { + switch (_sequenceId) { + case 0x7BA: + _idleFacing = kDirBottomLeft; + break; + case 0x7BB: + _idleFacing = kDirUpRight; + break; + case 0x7BC: + _idleFacing = kDirUpLeft; + break; + } + } + } else { + if (_walkNodesCount > 0) { + _sequenceId = getWalkStopSequenceId(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY); + _idleFacing = getWalkFacing(_walkNodes[_walkNodesCount - 1]._deltaX, _walkNodes[_walkNodesCount - 1]._deltaY); + } else if (gridX >= 0 || gridY >= 0) { + switch (_idleFacing) { + case kDirBottomRight: + _sequenceId = 0x7B9; + break; + case kDirBottomLeft: + _sequenceId = 0x7BA; + break; + case kDirUpRight: + _sequenceId = 0x7BB; + break; + default: + _sequenceId = 0x7BC; + break; + } + } else { + int dirX = _vm->_leftClickMouseX - (_vm->_gridMinX + 75 * _pos.x); + int dirY = _vm->_leftClickMouseY - (_vm->_gridMinY + 48 * _pos.y); + if (dirX == 0) + dirX = 1; + if (dirY == 0) + dirY = 1; + _sequenceId = getWalkStopSequenceId(dirX / abs(dirX), dirY / abs(dirY)); + _idleFacing = getWalkFacing(dirX / abs(dirX), dirY / abs(dirY)); + } + _sequenceDatNum = datNum; + } + + if (animationIndex < 0) { + _id = 20 * _walkDestY + 1; + } else { + _id = _walkNodesCount + animationIndex + 20 * _walkDestY; + _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _walkNodesCount + animationIndex + 20 * _walkDestY, animationIndex); + } + + if (flags & 4) { + _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 0, 0); + } else { + _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id, + makeRid(gnapSequenceDatNum, gnapSequenceId), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY); + } + } + + _pos = Common::Point(_walkDestX, _walkDestY); + + return done; +} + +int PlayerGnap::getShowSequenceId(int index, int gridX, int gridY) { + int sequenceId; + Facing facing = _idleFacing; + + if (gridY > 0 && gridX > 0) { + if (_pos.y > gridY) { + if (_pos.x > gridX) + _idleFacing = kDirUpLeft; + else + _idleFacing = kDirUpRight; + } else { + if (_pos.x > gridX) + _idleFacing = kDirUpLeft; + else + _idleFacing = kDirUpRight; + } + } else if (_idleFacing != kDirBottomRight && _idleFacing != kDirUpRight) { + _idleFacing = kDirUpLeft; + } else { + _idleFacing = kDirUpRight; + } + + switch (index) { + case 0: + if (_idleFacing == kDirUpRight) + sequenceId = 0x8A0; + else + sequenceId = 0x8A1; + break; + case 1: + if (_idleFacing == kDirUpRight) + sequenceId = 0x880; + else + sequenceId = 0x895; + break; + case 2: + if (_idleFacing == kDirUpRight) + sequenceId = 0x884; + else + sequenceId = 0x899; + break; + //Skip 3 + case 4: + if (_idleFacing == kDirUpRight) + sequenceId = 0x881; + else + sequenceId = 0x896; + break; + case 5: + if (_idleFacing == kDirUpRight) + sequenceId = 0x883; + else + sequenceId = 0x898; + break; + case 6: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87E; + else + sequenceId = 0x893; + break; + case 7: + if (_idleFacing == kDirUpRight) + sequenceId = 0x848; + else + sequenceId = 0x890; + break; + case 8: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87D; + else + sequenceId = 0x892; + break; + case 9: + if (_idleFacing == kDirUpRight) + sequenceId = 0x882; + else + sequenceId = 0x897; + break; + case 10: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87C; + else + sequenceId = 0x891; + break; + case 11: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87C; + else + sequenceId = 0x891; + break; + case 12: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87D; + else + sequenceId = 0x892; + break; + case 13: + if (_idleFacing == kDirUpRight) + sequenceId = 0x888; + else + sequenceId = 0x89D; + break; + case 14: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87F; + else + sequenceId = 0x894; + break; + case 15: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87B; + else + sequenceId = 0x8A3; + break; + case 16: + if (_idleFacing == kDirUpRight) + sequenceId = 0x877; + else + sequenceId = 0x88C; + break; + //Skip 17 + case 18: + sequenceId = 0x887; + break; + case 19: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87A; + else + sequenceId = 0x88F; + break; + case 20: + if (_idleFacing == kDirUpRight) + sequenceId = 0x878; + else + sequenceId = 0x88D; + break; + case 21: + if (_idleFacing == kDirUpRight) + sequenceId = 0x879; + else + sequenceId = 0x88E; + break; + case 22: + if (_idleFacing == kDirUpRight) + sequenceId = 0x88A; + else + sequenceId = 0x89F; + break; + case 23: + if (_idleFacing == kDirUpRight) + sequenceId = 0x889; + else + sequenceId = 0x89E; + break; + case 24: + if (_idleFacing == kDirUpRight) + sequenceId = 0x886; + else + sequenceId = 0x89B; + break; + case 25: + if (_idleFacing == kDirUpRight) + sequenceId = 0x87A; + else + sequenceId = 0x88F; + break; + //Skip 26 + //Skip 27 + //Skip 28 + //Skip 29 + default: + _idleFacing = facing; + sequenceId = getSequenceId(kGSImpossible, Common::Point(0, 0)); + break; + } + + return sequenceId; +} + +void PlayerGnap::idle() { + if (_sequenceDatNum == 1 && + (_sequenceId == 0x7A6 || _sequenceId == 0x7AA || + _sequenceId == 0x832 || _sequenceId == 0x841 || + _sequenceId == 0x842 || _sequenceId == 0x8A2 || + _sequenceId == 0x833 || _sequenceId == 0x834 || + _sequenceId == 0x885 || _sequenceId == 0x7A8 || + _sequenceId == 0x831 || _sequenceId == 0x89A)) { + _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0)); + _sequenceDatNum = 1; + } +} + +void PlayerGnap::actionIdle(int sequenceId) { + if (_sequenceId != -1 && ridToDatIndex(sequenceId) == _sequenceDatNum && ridToEntryIndex(sequenceId) == _sequenceId) { + _vm->_gameSys->insertSequence(getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqSyncExists, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = getSequenceId(kGSIdle, Common::Point(0, 0)); + _sequenceDatNum = 1; + } +} + +void PlayerGnap::playImpossible(Common::Point gridPos) { + playSequence(getSequenceId(kGSImpossible, gridPos) | 0x10000); +} + +void PlayerGnap::playScratchingHead(Common::Point gridPos) { + playSequence(getSequenceId(kGSScratchingHead, gridPos) | 0x10000); +} + +void PlayerGnap::playMoan1(Common::Point gridPos) { + playSequence(getSequenceId(kGSMoan1, gridPos) | 0x10000); +} + +void PlayerGnap::playMoan2(Common::Point gridPos) { + playSequence(getSequenceId(kGSMoan2, gridPos) | 0x10000); +} + +void PlayerGnap::playBrainPulsating(Common::Point gridPos) { + playSequence(getSequenceId(kGSBrainPulsating, gridPos) | 0x10000); +} + +void PlayerGnap::playPullOutDevice(Common::Point gridPos) { + playSequence(getSequenceId(kGSPullOutDevice, gridPos) | 0x10000); +} + +void PlayerGnap::playPullOutDeviceNonWorking(Common::Point gridPos) { + playSequence(getSequenceId(kGSPullOutDeviceNonWorking, gridPos) | 0x10000); +} + +void PlayerGnap::playUseDevice(Common::Point gridPos) { + playSequence(getSequenceId(kGSUseDevice, gridPos) | 0x10000); +} + +void PlayerGnap::playIdle(Common::Point gridPos) { + playSequence(getSequenceId(kGSIdle, gridPos) | 0x10000); +} + +void PlayerGnap::playShowItem(int itemIndex, int gridLookX, int gridLookY) { + playSequence(getShowSequenceId(itemIndex, gridLookX, gridLookY) | 0x10000); +} + +void PlayerGnap::playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY) { + PlayerPlat& plat = *_vm->_plat; + + if (plat._pos == destPos) + plat.makeRoom(); + walkTo(destPos, -1, -1, 1); + playShowItem(_vm->_grabCursorSpriteIndex, gridLookX, gridLookY); +} + +bool PlayerGnap::doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback) { + PlayerPlat& plat = *_vm->_plat; + bool result = false; + + if (_actionStatus <= -1 && plat._actionStatus <= -1) { + _actionStatus = 100; + Common::Point checkPt = plat._pos + Common::Point(gridX, gridY); + if (_vm->isPointBlocked(checkPt) && (_pos != checkPt)) { + plat.walkStep(); + checkPt = plat._pos + Common::Point(gridX, gridY); + } + + if (!_vm->isPointBlocked(checkPt) && (_pos != checkPt)) { + walkTo(checkPt, 0, 0x107B9, 1); + while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->doCallback(callback); + _vm->gameUpdateTick(); + } + _vm->_gameSys->setAnimation(0, 0, 0); + if (_pos == plat._pos + Common::Point(gridX, gridY)) { + _vm->_gameSys->setAnimation(platSequenceId, plat._id, 1); + plat.playSequence(platSequenceId); + while (_vm->_gameSys->getAnimationStatus(1) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->doCallback(callback); + _vm->gameUpdateTick(); + } + result = true; + } + } + _actionStatus = -1; + } + return result; +} + +void PlayerGnap::useDisguiseOnPlatypus() { + _vm->_gameSys->setAnimation(0x10846, _id, 0); + playSequence(0x10846); + while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + _vm->_newSceneNum = 47; + _vm->_isLeavingScene = true; + _vm->_sceneDone = true; + _vm->setFlag(kGFPlatypusDisguised); +} + +/************************************************************************************************/ + +PlayerPlat::PlayerPlat(GnapEngine * vm) : Character(vm) {} + +int PlayerPlat::getSequenceId(int kind, Common::Point gridPos) { + // The original had 3 parameters, all always set to 0. + // The code to handle the other values has been removed. + + int sequenceId = 0x7CB; + + if (_idleFacing != kDirIdleLeft) { + sequenceId = 0x7CC; + _idleFacing = kDirIdleRight; + } + + return sequenceId | 0x10000; +} + +void PlayerPlat::playSequence(int sequenceId) { + _vm->_gameSys->insertSequence(sequenceId, _id, + makeRid(_sequenceDatNum, _sequenceId), _id, + kSeqScale | kSeqSyncWait, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); + _sequenceId = ridToEntryIndex(sequenceId); + _sequenceDatNum = ridToDatIndex(sequenceId); +} + +void PlayerPlat::updateIdleSequence() { + if (_actionStatus < 0 && _vm->_gnap->_actionStatus < 0) { + if (_vm->_timers[0] > 0) { + if (_vm->_timers[1] == 0) { + _vm->_timers[1] = _vm->getRandom(20) + 30; + int rnd = _vm->getRandom(10); + if (_idleFacing != kDirIdleLeft) { + if (rnd != 0 || _sequenceId != 0x7CA) { + if (rnd != 1 || _sequenceId != 0x7CA) + playSequence(0x107CA); + else + playSequence(0x10845); + } else { + playSequence(0x107CC); + } + } else if (rnd != 0 || _sequenceId != 0x7C9) { + if (rnd != 1 || _sequenceId != 0x7C9) { + if (rnd != 2 || _sequenceId != 0x7C9) + playSequence(0x107C9); + else + playSequence(0x108A4); + } else { + playSequence(0x10844); + } + } else { + playSequence(0x107CB); + } + } + } else { + _vm->_timers[0] = _vm->getRandom(75) + 75; + makeRoom(); + } + } else { + _vm->_timers[0] = 100; + _vm->_timers[1] = 35; + } +} + +void PlayerPlat::updateIdleSequence2() { + PlayerGnap& gnap = *_vm->_gnap; + + if (_actionStatus < 0 && gnap._actionStatus < 0) { + if (_vm->_timers[0]) { + if (!_vm->_timers[1]) { + _vm->_timers[1] = _vm->getRandom(20) + 30; + if (_idleFacing != kDirIdleLeft) { + if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7CA) + playSequence(0x107CA); + else + playSequence(0x107CC); + } else { + if (_vm->getRandom(10) >= 2 || _sequenceId != 0x7C9) { + playSequence(0x107C9); + } else { + playSequence(0x107CB); + } + } + } + } else { + _vm->_timers[0] = _vm->getRandom(75) + 75; + makeRoom(); + } + } else { + _vm->_timers[0] = 100; + _vm->_timers[1] = 35; + } +} + +void PlayerPlat::initPos(int gridX, int gridY, Facing facing) { + _vm->_timers[0] = 50; + _vm->_timers[1] = 20; + _pos = Common::Point(gridX, gridY); + if (facing == kDirIdleLeft) + _idleFacing = kDirIdleLeft; + else + _idleFacing = facing; + if (_idleFacing == kDirIdleRight) { + _sequenceId = 0x7D1; + } else { + _sequenceId = 0x7C1; + _idleFacing = kDirIdleLeft; + } + _id = 20 * _pos.y; + _sequenceDatNum = 1; + _vm->_gameSys->insertSequence(makeRid(1, _sequenceId), 20 * _pos.y, + 0, 0, + kSeqScale, 0, 75 * _pos.x - _gridX, 48 * _pos.y - _gridY); +} + +int PlayerPlat::getWalkSequenceId(int deltaX, int deltaY) { + static const int walkSequenceIds[9] = { + 0x7C5, 0x000, 0x7C8, + 0x7C4, 0x000, 0x7C7, + 0x7C3, 0x000, 0x7C6 + }; + + int id = 3 * (deltaX + 1) + deltaY + 1; + assert(id >= 0 && id < 9); + + return walkSequenceIds[id]; +} + +bool PlayerPlat::walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) { + // Note: flags is always 1. The code could be simplified. + + int datNum = flags & 3; + PlayerGnap& gnap = *_vm->_gnap; + + _vm->_timers[1] = 60; + + int gridX = gridPos.x; + if (gridX < 0) + gridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75; + + int gridY = gridPos.y; + if (gridY < 0) + gridY = (_vm->_leftClickMouseY - _vm->_gridMinY + 24) / 48; + + _walkDestX = CLIP(gridX, 0, _vm->_gridMaxX - 1); + _walkDestY = CLIP(gridY, 0, _vm->_gridMaxY - 1); + + if (animationIndex >= 0 && gnap._pos == Common::Point(_walkDestX, _walkDestY)) + gnap.walkStep(); + + bool done = findPath1(_pos.x, _pos.y, 0); + + if (!done) + done = findPath2(_pos.x, _pos.y, 0); + + if (!done) + done = findPath3(_pos.x, _pos.y); + + if (!done) + done = findPath4(_pos.x, _pos.y); + + int platSequenceId = _sequenceId; + int platId = _id; + int platSequenceDatNum = _sequenceDatNum; + + for (int index = 0; index < _walkNodesCount; ++index) { + _walkNodes[index]._id = index + 20 * _walkNodes[index]._gridY1; + if (_walkNodes[index]._deltaX == 1 && _walkNodes[index]._deltaY == 0) { + if (index % 2) { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CD), _walkNodes[index]._id, + makeRid(platSequenceDatNum, platSequenceId), platId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7CD; + platSequenceId = 0x7CD; + } else { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CE), _walkNodes[index]._id, + makeRid(platSequenceDatNum, platSequenceId), platId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7CE; + platSequenceId = 0x7CE; + } + } else if (_walkNodes[index]._deltaX == -1 && _walkNodes[index]._deltaY == 0) { + if (index % 2) { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7CF), _walkNodes[index]._id, + makeRid(platSequenceDatNum, platSequenceId), platId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7CF; + platSequenceId = 0x7CF; + } else { + _vm->_gameSys->insertSequence(makeRid(datNum, 0x7D0), _walkNodes[index]._id, + makeRid(platSequenceDatNum, platSequenceId), platId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = 0x7D0; + platSequenceId = 0x7D0; + } + } else { + if (_walkNodes[index]._deltaY == -1) + _walkNodes[index]._id -= 10; + else + _walkNodes[index]._id += 10; + int newSequenceId = getWalkSequenceId(_walkNodes[index]._deltaX, _walkNodes[index]._deltaY); + _vm->_gameSys->insertSequence(makeRid(datNum, newSequenceId), _walkNodes[index]._id, + makeRid(platSequenceDatNum, platSequenceId), platId, + kSeqScale | kSeqSyncWait, 0, 75 * _walkNodes[index]._gridX1 - _gridX, 48 * _walkNodes[index]._gridY1 - _gridY); + _walkNodes[index]._sequenceId = newSequenceId; + platSequenceId = newSequenceId; + } + platId = _walkNodes[index]._id; + platSequenceDatNum = datNum; + } + + if (flags & 8) { + if (_walkNodesCount > 0) { + _sequenceId = platSequenceId; + _id = platId; + _sequenceDatNum = datNum; + if (_walkNodes[_walkNodesCount - 1]._deltaX > 0) + _idleFacing = kDirIdleLeft; + else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0) + _idleFacing = kDirIdleRight; + else if (_walkNodes[_walkNodesCount - 1]._gridX1 % 2) + _idleFacing = kDirIdleRight; + else + _idleFacing = kDirIdleLeft; + if (animationIndex >= 0) + _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), _id, animationIndex); + } else if (animationIndex >= 0) { + _vm->_gameSys->setAnimation(0x107D3, 1, animationIndex); + _vm->_gameSys->insertSequence(0x107D3, 1, 0, 0, kSeqNone, 0, 0, 0); + } + } else { + if (sequenceId >= 0 && sequenceId != -1) { + _sequenceId = ridToEntryIndex(sequenceId); + _sequenceDatNum = ridToDatIndex(sequenceId); + if (_sequenceId == 0x7C2) { + _idleFacing = kDirIdleLeft; + } else if (_sequenceId == 0x7D2) { + _idleFacing = kDirIdleRight; + } + } else { + if (_walkNodesCount > 0) { + if (_walkNodes[_walkNodesCount - 1]._deltaX > 0) { + _sequenceId = 0x7C2; + _idleFacing = kDirIdleLeft; + } else if (_walkNodes[_walkNodesCount - 1]._deltaX < 0) { + _sequenceId = 0x7D2; + _idleFacing = kDirIdleRight; + } else if (_walkNodes[0]._deltaX > 0) { + _sequenceId = 0x7C2; + _idleFacing = kDirIdleLeft; + } else if (_walkNodes[0]._deltaX < 0) { + _sequenceId = 0x7D2; + _idleFacing = kDirIdleRight; + } else { + _sequenceId = 0x7D2; + _idleFacing = kDirIdleRight; + } + } else if (_idleFacing != kDirIdleLeft) { + _sequenceId = 0x7D2; + } else { + _sequenceId = 0x7C2; + } + _sequenceDatNum = datNum; + } + + if (animationIndex < 0) { + _id = 20 * _walkDestY; + } else { + _id = animationIndex + 20 * _walkDestY; + _vm->_gameSys->setAnimation(makeRid(_sequenceDatNum, _sequenceId), animationIndex + 20 * _walkDestY, animationIndex); + } + + if (flags & 4) + _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id, + makeRid(platSequenceDatNum, platSequenceId), platId, + 9, 0, 0, 0); + else + _vm->_gameSys->insertSequence(makeRid(_sequenceDatNum, _sequenceId), _id, + makeRid(platSequenceDatNum, platSequenceId), platId, + 9, 0, 75 * _walkDestX - _gridX, 48 * _walkDestY - _gridY); + } + + _pos = Common::Point(_walkDestX, _walkDestY); + + return done; +} +} // End of namespace Gnap diff --git a/engines/gnap/character.h b/engines/gnap/character.h new file mode 100644 index 0000000000..27e98be15c --- /dev/null +++ b/engines/gnap/character.h @@ -0,0 +1,146 @@ +/* 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. + * + */ + +#ifndef GNAP_CHARACTER_H +#define GNAP_CHARACTER_H + +namespace Gnap { + +class GnapEngine; + +enum Facing { + kDirIdleLeft = 0, + kDirBottomRight = 1, + kDirBottomLeft = 3, + kDirIdleRight = 4, + kDirUpLeft = 5, + kDirUpRight = 7 +}; + +struct GridStruct { + int _deltaX, _deltaY; + int _gridX1, _gridY1; + int _sequenceId; + int _id; +}; + +const int kMaxGridStructs = 30; + +class Character { +public: + Character(GnapEngine *vm); + virtual ~Character(); + + void walkStep(); + + virtual int getSequenceId(int kind, Common::Point gridPos) = 0; + virtual void playSequence(int sequenceId) = 0; + virtual void updateIdleSequence() = 0; + virtual void updateIdleSequence2() = 0; + virtual void initPos(int gridX, int gridY, Facing facing) = 0; + virtual int getWalkSequenceId(int deltaX, int deltaY) = 0; + virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags) = 0; + + Common::Point _pos; + Facing _idleFacing; + int _actionStatus; + int _sequenceId; + int _sequenceDatNum; + int _id; + int _gridX; + int _gridY; + int _walkNodesCount; + GridStruct _walkNodes[kMaxGridStructs]; + int _walkDestX, _walkDestY; + int _walkDeltaX, _walkDeltaY, _walkDirX, _walkDirY, _walkDirXIncr, _walkDirYIncr; + +protected: + GnapEngine *_vm; +}; + +class PlayerGnap : public Character { +public: + PlayerGnap(GnapEngine *vm); + virtual int getSequenceId(int kind, Common::Point gridPos); + virtual void initPos(int gridX, int gridY, Facing facing); + virtual void playSequence(int sequenceId); + virtual void updateIdleSequence(); + virtual void updateIdleSequence2(); + virtual int getWalkSequenceId(int deltaX, int deltaY); + virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags); + + void actionIdle(int sequenceId); + bool doPlatypusAction(int gridX, int gridY, int platSequenceId, int callback); + int getShowSequenceId(int index, int gridX, int gridY); + Facing getWalkFacing(int deltaX, int deltaY); + int getWalkStopSequenceId(int deltaX, int deltaY); + void idle(); + void initBrainPulseRndValue(); + void kissPlatypus(int callback); + void playBrainPulsating(Common::Point gridPos = Common::Point(0, 0)); + void playIdle(Common::Point gridPos = Common::Point(0, 0)); + void playImpossible(Common::Point gridPos = Common::Point(0, 0)); + void playMoan1(Common::Point gridPos = Common::Point(0, 0)); + void playMoan2(Common::Point gridPos = Common::Point(0, 0)); + void playPullOutDevice(Common::Point gridPos = Common::Point(0, 0)); + void playPullOutDeviceNonWorking(Common::Point gridPos = Common::Point(0, 0)); + void playScratchingHead(Common::Point gridPos = Common::Point(0, 0)); + void playShowCurrItem(Common::Point destPos, int gridLookX, int gridLookY); + void playShowItem(int itemIndex, int gridLookX, int gridLookY); + void playUseDevice(Common::Point gridPos = Common::Point(0, 0)); + void useDeviceOnPlatypus(); + void useDisguiseOnPlatypus(); + void useJointOnPlatypus(); + + int _brainPulseNum; + int _brainPulseRndValue; + +private: + bool findPath1(int gridX, int gridY, int index); + bool findPath2(int gridX, int gridY, int index); + bool findPath3(int gridX, int gridY); + bool findPath4(int gridX, int gridY); +}; + +class PlayerPlat : public Character { +public: + PlayerPlat(GnapEngine *vm); + virtual ~PlayerPlat() {} + virtual int getSequenceId(int kind = 0, Common::Point gridPos = Common::Point(0, 0)); + virtual void initPos(int gridX, int gridY, Facing facing); + virtual void playSequence(int sequenceId); + virtual void updateIdleSequence(); + virtual void updateIdleSequence2(); + virtual int getWalkSequenceId(int deltaX, int deltaY); + virtual bool walkTo(Common::Point gridPos, int animationIndex, int sequenceId, int flags); + + void makeRoom(); + +private: + bool findPath1(int gridX, int gridY, int index); + bool findPath2(int gridX, int gridY, int index); + bool findPath3(int gridX, int gridY); + bool findPath4(int gridX, int gridY); +}; +} // End of namespace Gnap + +#endif // GNAP_CHARACTER_H diff --git a/engines/gnap/configure.engine b/engines/gnap/configure.engine new file mode 100644 index 0000000000..7aa538fd2c --- /dev/null +++ b/engines/gnap/configure.engine @@ -0,0 +1,3 @@ +# This file is included from the main "configure" script +# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] +add_engine gnap "UFOs" no diff --git a/engines/gnap/datarchive.cpp b/engines/gnap/datarchive.cpp new file mode 100644 index 0000000000..c74766bd03 --- /dev/null +++ b/engines/gnap/datarchive.cpp @@ -0,0 +1,124 @@ +/* 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. + * + */ + +#include "common/dcl.h" +#include "common/file.h" +#include "common/stream.h" +#include "common/substream.h" + +#include "gnap/gnap.h" +#include "gnap/datarchive.h" + +#include "engines/util.h" + +namespace Gnap { + +// DatArchive + +DatArchive::DatArchive(const char *filename) { + _fd = new Common::File(); + if (!_fd->open(filename)) + error("DatArchive::DatArchive() Could not open %s", filename); + _fd->skip(8); // Skip signature + _fd->skip(2); // Skip unknown + _fd->skip(2); // Skip unknown + _entriesCount = _fd->readUint32LE(); + debugC(kDebugBasic, "_entriesCount: %d", _entriesCount); + _fd->skip(4); // Skip unknown + _entries = new DatEntry[_entriesCount]; + for (int i = 0; i < _entriesCount; ++i) { + _entries[i]._ofs = _fd->readUint32LE(); + _entries[i]._outSize1 = _fd->readUint32LE(); + _entries[i]._type = _fd->readUint32LE(); + _entries[i]._outSize2 = _fd->readUint32LE(); + } +} + +DatArchive::~DatArchive() { + _fd->close(); + delete _fd; + delete[] _entries; +} + +byte *DatArchive::load(int index) { + _fd->seek(_entries[index]._ofs); + debugC(kDebugBasic, "_entries[index].outSize2: %d; _entries[index].outSize1: %d", _entries[index]._outSize2, _entries[index]._outSize1); + byte *buffer = new byte[_entries[index]._outSize1]; + if (!Common::decompressDCL(_fd, buffer, _entries[index]._outSize2, _entries[index]._outSize1)) + error("DatArchive::load() Error during decompression of entry %d", index); + return buffer; +} + +// DatManager + +DatManager::DatManager() { + for (int i = 0; i < kMaxDatArchives; ++i) + _datArchives[i] = nullptr; +} + +DatManager::~DatManager() { + for (int i = 0; i < kMaxDatArchives; ++i) + delete _datArchives[i]; +} + +void DatManager::open(int index, const char *filename) { + close(index); + _datArchives[index] = new DatArchive(filename); + warning("Loading %s - %d", filename, index); +} + +void DatManager::close(int index) { + delete _datArchives[index]; + _datArchives[index] = nullptr; +} + +byte *DatManager::loadResource(int resourceId) { + const int datIndex = ridToDatIndex(resourceId); + const int entryIndex = ridToEntryIndex(resourceId); + return _datArchives[datIndex] ? _datArchives[datIndex]->load(entryIndex) : 0; +} + +uint32 DatManager::getResourceType(int resourceId) { + const int datIndex = ridToDatIndex(resourceId); + const int entryIndex = ridToEntryIndex(resourceId); + return _datArchives[datIndex] ? _datArchives[datIndex]->getEntryType(entryIndex) : 0; +} + +uint32 DatManager::getResourceSize(int resourceId) { + const int datIndex = ridToDatIndex(resourceId); + const int entryIndex = ridToEntryIndex(resourceId); + return _datArchives[datIndex] ? _datArchives[datIndex]->getEntrySize(entryIndex) : 0; +} + +int ridToDatIndex(int resourceId) { + return (resourceId & 0xFFFF0000) >> 16; +} + +int ridToEntryIndex(int resourceId) { + return resourceId & 0xFFFF; +} + +int makeRid(int datIndex, int entryIndex) { + return (datIndex << 16) | entryIndex; +} + +} // End of namespace Gnap diff --git a/engines/gnap/datarchive.h b/engines/gnap/datarchive.h new file mode 100644 index 0000000000..e9220f8e6f --- /dev/null +++ b/engines/gnap/datarchive.h @@ -0,0 +1,80 @@ +/* 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. + * + */ + +#ifndef GNAP_DATARCHIVE_H +#define GNAP_DATARCHIVE_H + +#include "common/array.h" +#include "common/events.h" +#include "common/file.h" +#include "common/memstream.h" +#include "common/random.h" +#include "common/str.h" +#include "common/substream.h" +#include "common/system.h" +#include "engines/engine.h" + +namespace Gnap { + +struct DatEntry { + uint32 _ofs; + uint32 _outSize1; + uint32 _type; + uint32 _outSize2; +}; + +class DatArchive { +public: + DatArchive(const char *filename); + ~DatArchive(); + byte *load(int index); + int getCount() const { return _entriesCount; } + uint32 getEntryType(int index) { return _entries[index]._type; } + uint32 getEntrySize(int index) { return _entries[index]._outSize1; } +protected: + Common::File *_fd; + int _entriesCount; + DatEntry *_entries; +}; + +const int kMaxDatArchives = 2; + +class DatManager { +public: + DatManager(); + ~DatManager(); + void open(int index, const char *filename); + void close(int index); + byte *loadResource(int resourceId); + uint32 getResourceType(int resourceId); + uint32 getResourceSize(int resourceId); +protected: + DatArchive *_datArchives[kMaxDatArchives]; +}; + +int ridToDatIndex(int resourceId); +int ridToEntryIndex(int resourceId); +int makeRid(int datIndex, int entryIndex); + +} // End of namespace Gnap + +#endif // GNAP_DATARCHIVE_H diff --git a/engines/gnap/debugger.cpp b/engines/gnap/debugger.cpp new file mode 100644 index 0000000000..07f3f6714c --- /dev/null +++ b/engines/gnap/debugger.cpp @@ -0,0 +1,42 @@ +/* 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. + * + */ + +#include "gnap/debugger.h" +#include "gnap/gnap.h" + +namespace Gnap { + +Debugger::Debugger(GnapEngine *vm) : GUI::Debugger(), _vm(vm) { + // Register methods + registerCmd("hotspots", WRAP_METHOD(Debugger, Cmd_Hotspots)); + + // Set fields + _showHotspotNumber = false; +} + +bool Debugger::Cmd_Hotspots(int argc, const char **argv) { + _showHotspotNumber ^= 1; + + return true; +} + +} // End of namespace Gnap diff --git a/engines/gnap/debugger.h b/engines/gnap/debugger.h new file mode 100644 index 0000000000..ac83cc5504 --- /dev/null +++ b/engines/gnap/debugger.h @@ -0,0 +1,54 @@ +/* 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. + * + */ + +#ifndef GNAP_DEBUGGER_H +#define GNAP_DEBUGGER_H + +#include "common/scummsys.h" +#include "gui/debugger.h" + +namespace Gnap { + +class GnapEngine; + +class Debugger : public GUI::Debugger { +private: + GnapEngine *_vm; +public: + /* + * Specifies whether to show the hotspot IDs + */ + bool _showHotspotNumber; +protected: + /** + * List the active hotspots during the current time period + */ + bool Cmd_Hotspots(int argc, const char **argv); + +public: + Debugger(GnapEngine *vm); + virtual ~Debugger() {} +}; + +} // End of namespace Gnap + +#endif diff --git a/engines/gnap/detection.cpp b/engines/gnap/detection.cpp new file mode 100644 index 0000000000..a7e9eece4a --- /dev/null +++ b/engines/gnap/detection.cpp @@ -0,0 +1,197 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" + +#include "common/config-manager.h" +#include "engines/advancedDetector.h" +#include "common/savefile.h" +#include "common/system.h" +#include "base/plugins.h" +#include "graphics/thumbnail.h" + +static const PlainGameDescriptor gnapGames[] = { + { "gnap", "Gnap" }, + { 0, 0 } +}; + +namespace Gnap { + +static const ADGameDescription gameDescriptions[] = { + { + "gnap", "", + { + {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12515823}, + AD_LISTEND + }, + Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO0() + }, + { + "gnap", "", + { + {"stock_n.dat", 0, "46819043d019a2f36b727cc2bdd6980f", 12995485}, + AD_LISTEND + }, + Common::RU_RUS, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO0() + }, + + AD_TABLE_END_MARKER +}; + +} // End of namespace Gnap + +class GnapMetaEngine : public AdvancedMetaEngine { +public: + GnapMetaEngine() : AdvancedMetaEngine(Gnap::gameDescriptions, sizeof(ADGameDescription), gnapGames) { + _singleId = "gnap"; + _maxScanDepth = 3; + } + + virtual const char *getName() const { + return "Gnap"; + } + + virtual const char *getOriginalCopyright() const { + return "Gnap (C) Artech Digital Entertainment 1997"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; + virtual int getMaximumSaveSlot() const; + virtual SaveStateList listSaves(const char *target) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; + virtual void removeSaveState(const char *target, int slot) const; +}; + +bool GnapMetaEngine::hasFeature(MetaEngineFeature f) const { + return + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate); +} + +bool Gnap::GnapEngine::hasFeature(EngineFeature f) const { + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); +} + +void GnapMetaEngine::removeSaveState(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + g_system->getSavefileManager()->removeSavefile(fileName); +} + +int GnapMetaEngine::getMaximumSaveSlot() const { return 99; } + +SaveStateList GnapMetaEngine::listSaves(const char *target) const { + Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); + Common::StringArray filenames; + Common::String saveDesc; + Common::String pattern = Common::String::format("%s.0##", target); + Gnap::GnapSavegameHeader header; + + filenames = saveFileMan->listSavefiles(pattern); + + SaveStateList saveList; + for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { + const char *ext = strrchr(file->c_str(), '.'); + int slot = ext ? atoi(ext + 1) : -1; + + if (slot >= 0 && slot < getMaximumSaveSlot()) { + Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(*file); + + if (in) { + Gnap::GnapEngine::readSavegameHeader(in, header); + saveList.push_back(SaveStateDescriptor(slot, header._saveName)); + + if (header._thumbnail) { + header._thumbnail->free(); + delete header._thumbnail; + } + delete in; + } + } + } + + // Sort saves based on slot number. + Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator()); + return saveList; +} + +SaveStateDescriptor GnapMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + Common::String fileName = Common::String::format("%s.%03d", target, slot); + Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName); + if (file) { + char saveIdentBuffer[5]; + file->read(saveIdentBuffer, 5); + + int32 version = file->readByte(); + if (version > GNAP_SAVEGAME_VERSION) { + delete file; + return SaveStateDescriptor(); + } + + char saveName[256]; + char ch; + int i = 0; + while ((ch = (char)file->readByte()) != '\0') + saveName[i++] = ch; + + SaveStateDescriptor desc(slot, saveName); + + if (version != 1) { + Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*file); + desc.setThumbnail(thumbnail); + } + + int year = file->readSint16LE(); + int month = file->readSint16LE(); + int day = file->readSint16LE(); + int hour = file->readSint16LE(); + int minutes = file->readSint16LE(); + + desc.setSaveDate(year, month, day); + desc.setSaveTime(hour, minutes); + + delete file; + return desc; + } + + return SaveStateDescriptor(); +} + +bool GnapMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new Gnap::GnapEngine(syst, desc); + } + return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(GNAP) + REGISTER_PLUGIN_DYNAMIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine); +#else + REGISTER_PLUGIN_STATIC(GNAP, PLUGIN_TYPE_ENGINE, GnapMetaEngine); +#endif diff --git a/engines/gnap/fontdata.h b/engines/gnap/fontdata.h new file mode 100644 index 0000000000..ef39df960e --- /dev/null +++ b/engines/gnap/fontdata.h @@ -0,0 +1,849 @@ +/* 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. + * + */ + +#ifndef GNAP_FONTDATA_H +#define GNAP_FONTDATA_H + +namespace Gnap { + +struct FONT_CHAR_INFO { + const byte _width; // width, in bits (or pixels), of the character + const uint16 _offset; // offset of the character's bitmap, in bytes, into the the FONT_INFO's data array +}; + +/* +** Font data for DejaVu Sans 9pt +*/ + +/* Character bitmaps for DejaVu Sans 9pt */ +const byte _dejaVuSans9ptCharBitmaps[] = { + /* @0 ' ' (5 pixels wide) */ + 0x00, 0x00, /* */ + 0x00, 0x00, /* */ + 0x00, 0x00, /* */ + 0x00, 0x00, /* */ + 0x00, 0x00, /* */ + + /* @10 '!' (1 pixels wide) */ + 0x1B, 0xF0, /* ## ###### */ + + /* @12 '"' (3 pixels wide) */ + 0x00, 0x70, /* ### */ + 0x00, 0x00, /* */ + 0x00, 0x70, /* ### */ + + /* @18 '#' (8 pixels wide) */ + 0x04, 0x00, /* # */ + 0x14, 0x80, /* # # # */ + 0x0F, 0x80, /* ##### */ + 0x04, 0xE0, /* # ### */ + 0x1C, 0x80, /* ### # */ + 0x07, 0xC0, /* ##### */ + 0x04, 0xA0, /* # # # */ + 0x00, 0x80, /* # */ + + /* @34 '$' (5 pixels wide) */ + 0x09, 0xC0, /* # ### */ + 0x11, 0x20, /* # # # */ + 0x7F, 0xF0, /* ########### */ + 0x12, 0x20, /* # # # */ + 0x0E, 0x40, /* ### # */ + + /* @44 '%' (10 pixels wide) */ + 0x00, 0xE0, /* ### */ + 0x01, 0x10, /* # # */ + 0x11, 0x10, /* # # # */ + 0x0C, 0xE0, /* ## ### */ + 0x03, 0x00, /* ## */ + 0x01, 0x80, /* ## */ + 0x0E, 0x60, /* ### ## */ + 0x11, 0x10, /* # # # */ + 0x11, 0x00, /* # # */ + 0x0E, 0x00, /* ### */ + + /* @64 '&' (8 pixels wide) */ + 0x0E, 0x00, /* ### */ + 0x19, 0xE0, /* ## #### */ + 0x10, 0x90, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x12, 0x20, /* # # # */ + 0x0C, 0x00, /* ## */ + 0x14, 0x00, /* # # */ + 0x13, 0x00, /* # ## */ + + /* @80 ''' (1 pixels wide) */ + 0x00, 0x70, /* ### */ + + /* @82 '(' (3 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x38, 0x38, /* ### ### */ + 0x20, 0x08, /* # # */ + + /* @88 ')' (3 pixels wide) */ + 0x20, 0x08, /* # # */ + 0x38, 0x38, /* ### ### */ + 0x07, 0xC0, /* ##### */ + + /* @94 '*' (5 pixels wide) */ + 0x01, 0x20, /* # # */ + 0x00, 0xC0, /* ## */ + 0x03, 0xF0, /* ###### */ + 0x00, 0xC0, /* ## */ + 0x01, 0x20, /* # # */ + + /* @104 '+' (7 pixels wide) */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x1F, 0xC0, /* ####### */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + + /* @118 ',' (1 pixels wide) */ + 0x38, 0x00, /* ### */ + + /* @120 '-' (3 pixels wide) */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + + /* @126 '.' (1 pixels wide) */ + 0x18, 0x00, /* ## */ + + /* @128 '/' (4 pixels wide) */ + 0x30, 0x00, /* ## */ + 0x0E, 0x00, /* ### */ + 0x01, 0xC0, /* ### */ + 0x00, 0x30, /* ## */ + + /* @136 '0' (6 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x18, 0x30, /* ## ## */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x18, 0x30, /* ## ## */ + 0x07, 0xC0, /* ##### */ + + /* @148 '1' (5 pixels wide) */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x1F, 0xF0, /* ######### */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + + /* @158 '2' (6 pixels wide) */ + 0x10, 0x20, /* # # */ + 0x18, 0x10, /* ## # */ + 0x14, 0x10, /* # # # */ + 0x12, 0x10, /* # # # */ + 0x11, 0x30, /* # # ## */ + 0x10, 0xE0, /* # ### */ + + /* @170 '3' (6 pixels wide) */ + 0x08, 0x20, /* # # */ + 0x10, 0x10, /* # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x0E, 0xE0, /* ### ### */ + + /* @182 '4' (6 pixels wide) */ + 0x06, 0x00, /* ## */ + 0x05, 0x80, /* # ## */ + 0x04, 0x40, /* # # */ + 0x04, 0x30, /* # ## */ + 0x1F, 0xF0, /* ######### */ + 0x04, 0x00, /* # */ + + /* @194 '5' (6 pixels wide) */ + 0x08, 0xF0, /* # #### */ + 0x10, 0x90, /* # # # */ + 0x10, 0x90, /* # # # */ + 0x10, 0x90, /* # # # */ + 0x19, 0x90, /* ## ## # */ + 0x0F, 0x00, /* #### */ + + /* @206 '6' (6 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x19, 0x20, /* ## # # */ + 0x10, 0x90, /* # # # */ + 0x10, 0x90, /* # # # */ + 0x19, 0x90, /* ## ## # */ + 0x0F, 0x20, /* #### # */ + + /* @218 '7' (6 pixels wide) */ + 0x00, 0x10, /* # */ + 0x10, 0x10, /* # # */ + 0x0C, 0x10, /* ## # */ + 0x03, 0x10, /* ## # */ + 0x00, 0xD0, /* ## # */ + 0x00, 0x30, /* ## */ + + /* @230 '8' (6 pixels wide) */ + 0x0E, 0xE0, /* ### ### */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x0E, 0xE0, /* ### ### */ + + /* @242 '9' (6 pixels wide) */ + 0x09, 0xE0, /* # #### */ + 0x13, 0x30, /* # ## ## */ + 0x12, 0x10, /* # # # */ + 0x12, 0x10, /* # # # */ + 0x09, 0x30, /* # # ## */ + 0x07, 0xC0, /* ##### */ + + /* @254 ':' (1 pixels wide) */ + 0x19, 0x80, /* ## ## */ + + /* @256 ';' (1 pixels wide) */ + 0x39, 0x80, /* ### ## */ + + /* @258 '<' (8 pixels wide) */ + 0x03, 0x00, /* ## */ + 0x03, 0x00, /* ## */ + 0x03, 0x00, /* ## */ + 0x04, 0x80, /* # # */ + 0x04, 0x80, /* # # */ + 0x04, 0x80, /* # # */ + 0x0C, 0xC0, /* ## ## */ + 0x08, 0x40, /* # # */ + + /* @274 '=' (8 pixels wide) */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + 0x05, 0x00, /* # # */ + + /* @290 '>' (8 pixels wide) */ + 0x08, 0x40, /* # # */ + 0x0C, 0xC0, /* ## ## */ + 0x04, 0x80, /* # # */ + 0x04, 0x80, /* # # */ + 0x04, 0x80, /* # # */ + 0x03, 0x00, /* ## */ + 0x03, 0x00, /* ## */ + 0x03, 0x00, /* ## */ + + /* @306 '?' (5 pixels wide) */ + 0x00, 0x20, /* # */ + 0x00, 0x10, /* # */ + 0x1B, 0x10, /* ## ## # */ + 0x00, 0x90, /* # # */ + 0x00, 0x60, /* ## */ + + /* @316 '@' (11 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x10, 0x40, /* # # */ + 0x20, 0x20, /* # # */ + 0x47, 0x10, /* # ### # */ + 0x48, 0x90, /* # # # # */ + 0x48, 0x90, /* # # # # */ + 0x48, 0x90, /* # # # # */ + 0x4F, 0x90, /* # ##### # */ + 0x28, 0x20, /* # # # */ + 0x04, 0x60, /* # ## */ + 0x03, 0x80, /* ### */ + + /* @338 'A' (8 pixels wide) */ + 0x10, 0x00, /* # */ + 0x0E, 0x00, /* ### */ + 0x05, 0xC0, /* # ### */ + 0x04, 0x30, /* # ## */ + 0x04, 0x30, /* # ## */ + 0x05, 0xC0, /* # ### */ + 0x0E, 0x00, /* ### */ + 0x10, 0x00, /* # */ + + /* @354 'B' (6 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x0E, 0xE0, /* ### ### */ + + /* @366 'C' (6 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x08, 0x20, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x08, 0x20, /* # # */ + + /* @378 'D' (7 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x08, 0x20, /* # # */ + 0x07, 0xC0, /* ##### */ + + /* @392 'E' (6 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + + /* @404 'F' (5 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + + /* @414 'G' (7 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x08, 0x20, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x0F, 0x20, /* #### # */ + + /* @428 'H' (7 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x01, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x1F, 0xF0, /* ######### */ + + /* @442 'I' (1 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + + /* @444 'J' (3 pixels wide) */ + 0x40, 0x00, /* # */ + 0x40, 0x00, /* # */ + 0x3F, 0xF0, /* ########## */ + + /* @450 'K' (6 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x01, 0x00, /* # */ + 0x02, 0x80, /* # # */ + 0x04, 0x40, /* # # */ + 0x08, 0x20, /* # # */ + 0x10, 0x10, /* # # */ + + /* @462 'L' (5 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + + /* @472 'M' (8 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x00, 0x60, /* ## */ + 0x01, 0x80, /* ## */ + 0x06, 0x00, /* ## */ + 0x06, 0x00, /* ## */ + 0x01, 0x80, /* ## */ + 0x00, 0x60, /* ## */ + 0x1F, 0xF0, /* ######### */ + + /* @488 'N' (7 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x00, 0x30, /* ## */ + 0x00, 0xC0, /* ## */ + 0x01, 0x00, /* # */ + 0x06, 0x00, /* ## */ + 0x18, 0x00, /* ## */ + 0x1F, 0xF0, /* ######### */ + + /* @502 'O' (7 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x08, 0x20, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x08, 0x20, /* # # */ + 0x07, 0xC0, /* ##### */ + + /* @516 'P' (6 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x00, 0xE0, /* ### */ + + /* @528 'Q' (7 pixels wide) */ + 0x07, 0xC0, /* ##### */ + 0x08, 0x20, /* # # */ + 0x10, 0x10, /* # # */ + 0x10, 0x10, /* # # */ + 0x30, 0x10, /* ## # */ + 0x48, 0x20, /* # # # */ + 0x07, 0xC0, /* ##### */ + + /* @542 'R' (7 pixels wide) */ + 0x1F, 0xF0, /* ######### */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x01, 0x10, /* # # */ + 0x03, 0x10, /* ## # */ + 0x0C, 0xE0, /* ## ### */ + 0x10, 0x00, /* # */ + + /* @556 'S' (6 pixels wide) */ + 0x08, 0xE0, /* # ### */ + 0x11, 0x90, /* # ## # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x0E, 0x20, /* ### # */ + + /* @568 'T' (7 pixels wide) */ + 0x00, 0x10, /* # */ + 0x00, 0x10, /* # */ + 0x00, 0x10, /* # */ + 0x1F, 0xF0, /* ######### */ + 0x00, 0x10, /* # */ + 0x00, 0x10, /* # */ + 0x00, 0x10, /* # */ + + /* @582 'U' (7 pixels wide) */ + 0x0F, 0xF0, /* ######## */ + 0x18, 0x00, /* ## */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x18, 0x00, /* ## */ + 0x0F, 0xF0, /* ######## */ + + /* @596 'V' (8 pixels wide) */ + 0x00, 0x30, /* ## */ + 0x01, 0xC0, /* ### */ + 0x06, 0x00, /* ## */ + 0x18, 0x00, /* ## */ + 0x18, 0x00, /* ## */ + 0x06, 0x00, /* ## */ + 0x01, 0xC0, /* ### */ + 0x00, 0x30, /* ## */ + + /* @612 'W' (11 pixels wide) */ + 0x00, 0x10, /* # */ + 0x00, 0xE0, /* ### */ + 0x07, 0x00, /* ### */ + 0x18, 0x00, /* ## */ + 0x07, 0x80, /* #### */ + 0x00, 0x70, /* ### */ + 0x07, 0x80, /* #### */ + 0x18, 0x00, /* ## */ + 0x07, 0x00, /* ### */ + 0x00, 0xE0, /* ### */ + 0x00, 0x10, /* # */ + + /* @634 'X' (7 pixels wide) */ + 0x10, 0x10, /* # # */ + 0x08, 0x30, /* # ## */ + 0x06, 0xC0, /* ## ## */ + 0x01, 0x00, /* # */ + 0x06, 0xC0, /* ## ## */ + 0x08, 0x30, /* # ## */ + 0x10, 0x10, /* # # */ + + /* @648 'Y' (7 pixels wide) */ + 0x00, 0x10, /* # */ + 0x00, 0x60, /* ## */ + 0x01, 0x80, /* ## */ + 0x1E, 0x00, /* #### */ + 0x01, 0x80, /* ## */ + 0x00, 0x60, /* ## */ + 0x00, 0x10, /* # */ + + /* @662 'Z' (7 pixels wide) */ + 0x18, 0x10, /* ## # */ + 0x14, 0x10, /* # # # */ + 0x12, 0x10, /* # # # */ + 0x11, 0x10, /* # # # */ + 0x10, 0x90, /* # # # */ + 0x10, 0x50, /* # # # */ + 0x10, 0x30, /* # ## */ + + /* @676 '[' (2 pixels wide) */ + 0x7F, 0xF0, /* ########### */ + 0x40, 0x10, /* # # */ + + /* @680 '\' (4 pixels wide) */ + 0x00, 0x30, /* ## */ + 0x01, 0xC0, /* ### */ + 0x0E, 0x00, /* ### */ + 0x30, 0x00, /* ## */ + + /* @688 ']' (2 pixels wide) */ + 0x40, 0x10, /* # # */ + 0x7F, 0xF0, /* ########### */ + + /* @692 '^' (6 pixels wide) */ + 0x00, 0x40, /* # */ + 0x00, 0x20, /* # */ + 0x00, 0x10, /* # */ + 0x00, 0x10, /* # */ + 0x00, 0x20, /* # */ + 0x00, 0x40, /* # */ + + /* @704 '_' (6 pixels wide) */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + 0x80, 0x00, /* # */ + + /* @716 '`' (2 pixels wide) */ + 0x00, 0x08, /* # */ + 0x00, 0x10, /* # */ + + /* @720 'a' (6 pixels wide) */ + 0x0C, 0x80, /* ## # */ + 0x12, 0x40, /* # # # */ + 0x12, 0x40, /* # # # */ + 0x12, 0x40, /* # # # */ + 0x0A, 0x40, /* # # # */ + 0x1F, 0x80, /* ###### */ + + /* @732 'b' (6 pixels wide) */ + 0x1F, 0xF8, /* ########## */ + 0x18, 0xC0, /* ## ## */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + 0x18, 0xC0, /* ## ## */ + 0x0F, 0x80, /* ##### */ + + /* @744 'c' (5 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x18, 0xC0, /* ## ## */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + 0x08, 0x80, /* # # */ + + /* @754 'd' (6 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x18, 0xC0, /* ## ## */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + 0x18, 0xC0, /* ## ## */ + 0x1F, 0xF8, /* ########## */ + + /* @766 'e' (6 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x0A, 0xC0, /* # # ## */ + 0x12, 0x40, /* # # # */ + 0x12, 0x40, /* # # # */ + 0x12, 0xC0, /* # # ## */ + 0x0B, 0x80, /* # ### */ + + /* @778 'f' (4 pixels wide) */ + 0x00, 0x40, /* # */ + 0x1F, 0xF0, /* ######### */ + 0x00, 0x48, /* # # */ + 0x00, 0x48, /* # # */ + + /* @786 'g' (6 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x58, 0xC0, /* # ## ## */ + 0x90, 0x40, /* # # # */ + 0x90, 0x40, /* # # # */ + 0xD8, 0xC0, /* ## ## ## */ + 0x7F, 0xC0, /* ######### */ + + /* @798 'h' (6 pixels wide) */ + 0x1F, 0xF8, /* ########## */ + 0x00, 0x80, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x1F, 0x80, /* ###### */ + + /* @810 'i' (1 pixels wide) */ + 0x1F, 0xD0, /* ####### # */ + + /* @812 'j' (2 pixels wide) */ + 0x80, 0x00, /* # */ + 0xFF, 0xD0, /* ########## # */ + + /* @816 'k' (5 pixels wide) */ + 0x1F, 0xF8, /* ########## */ + 0x02, 0x00, /* # */ + 0x05, 0x00, /* # # */ + 0x08, 0x80, /* # # */ + 0x10, 0x40, /* # # */ + + /* @826 'l' (1 pixels wide) */ + 0x1F, 0xF8, /* ########## */ + + /* @828 'm' (9 pixels wide) */ + 0x1F, 0xC0, /* ####### */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x1F, 0x80, /* ###### */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x1F, 0x80, /* ###### */ + + /* @846 'n' (6 pixels wide) */ + 0x1F, 0xC0, /* ####### */ + 0x00, 0x80, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + 0x1F, 0x80, /* ###### */ + + /* @858 'o' (6 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x18, 0xC0, /* ## ## */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + 0x18, 0xC0, /* ## ## */ + 0x0F, 0x80, /* ##### */ + + /* @870 'p' (6 pixels wide) */ + 0xFF, 0xC0, /* ########## */ + 0x18, 0xC0, /* ## ## */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + 0x18, 0xC0, /* ## ## */ + 0x0F, 0x80, /* ##### */ + + /* @882 'q' (6 pixels wide) */ + 0x0F, 0x80, /* ##### */ + 0x18, 0xC0, /* ## ## */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + 0x18, 0xC0, /* ## ## */ + 0xFF, 0xC0, /* ########## */ + + /* @894 'r' (4 pixels wide) */ + 0x1F, 0xC0, /* ####### */ + 0x00, 0x80, /* # */ + 0x00, 0x40, /* # */ + 0x00, 0x40, /* # */ + + /* @902 's' (5 pixels wide) */ + 0x09, 0x80, /* # ## */ + 0x12, 0x40, /* # # # */ + 0x12, 0x40, /* # # # */ + 0x12, 0x40, /* # # # */ + 0x0C, 0x80, /* ## # */ + + /* @912 't' (4 pixels wide) */ + 0x00, 0x40, /* # */ + 0x1F, 0xF0, /* ######### */ + 0x10, 0x40, /* # # */ + 0x10, 0x40, /* # # */ + + /* @920 'u' (6 pixels wide) */ + 0x0F, 0xC0, /* ###### */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x10, 0x00, /* # */ + 0x08, 0x00, /* # */ + 0x1F, 0xC0, /* ####### */ + + /* @932 'v' (6 pixels wide) */ + 0x00, 0xC0, /* ## */ + 0x07, 0x00, /* ### */ + 0x18, 0x00, /* ## */ + 0x18, 0x00, /* ## */ + 0x07, 0x00, /* ### */ + 0x00, 0xC0, /* ## */ + + /* @944 'w' (9 pixels wide) */ + 0x00, 0xC0, /* ## */ + 0x07, 0x00, /* ### */ + 0x18, 0x00, /* ## */ + 0x07, 0x00, /* ### */ + 0x00, 0xC0, /* ## */ + 0x07, 0x00, /* ### */ + 0x18, 0x00, /* ## */ + 0x07, 0x00, /* ### */ + 0x00, 0xC0, /* ## */ + + /* @962 'x' (6 pixels wide) */ + 0x10, 0x40, /* # # */ + 0x0D, 0x80, /* ## ## */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x0D, 0x80, /* ## ## */ + 0x10, 0x40, /* # # */ + + /* @974 'y' (6 pixels wide) */ + 0x80, 0xC0, /* # ## */ + 0x83, 0x00, /* # ## */ + 0x4C, 0x00, /* # ## */ + 0x38, 0x00, /* ### */ + 0x07, 0x00, /* ### */ + 0x00, 0xC0, /* ## */ + + /* @986 'z' (5 pixels wide) */ + 0x18, 0x40, /* ## # */ + 0x14, 0x40, /* # # # */ + 0x12, 0x40, /* # # # */ + 0x11, 0x40, /* # # # */ + 0x10, 0xC0, /* # ## */ + + /* @996 '{' (5 pixels wide) */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x7D, 0xF0, /* ##### ##### */ + 0x40, 0x10, /* # # */ + 0x40, 0x10, /* # # */ + + /* @1006 '|' (1 pixels wide) */ + 0xFF, 0xF0, /* ############ */ + + /* @1008 '}' (5 pixels wide) */ + 0x40, 0x10, /* # # */ + 0x40, 0x10, /* # # */ + 0x7D, 0xF0, /* ##### ##### */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + + /* @1018 '~' (8 pixels wide) */ + 0x02, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x01, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x02, 0x00, /* # */ + 0x01, 0x00, /* # */ +}; + +/* Character descriptors for DejaVu Sans 9pt */ +/* { [Char width in bits], [Offset into dejaVuSans9ptCharBitmaps in bytes] } */ +const FONT_CHAR_INFO _dejaVuSans9ptCharDescriptors[] = { + {5, 0}, /* */ + {1, 10}, /* ! */ + {3, 12}, /* " */ + {8, 18}, /* # */ + {5, 34}, /* $ */ + {10, 44}, /* % */ + {8, 64}, /* & */ + {1, 80}, /* ' */ + {3, 82}, /* ( */ + {3, 88}, /* ) */ + {5, 94}, /* * */ + {7, 104}, /* + */ + {1, 118}, /* , */ + {3, 120}, /* - */ + {1, 126}, /* . */ + {4, 128}, /* / */ + {6, 136}, /* 0 */ + {5, 148}, /* 1 */ + {6, 158}, /* 2 */ + {6, 170}, /* 3 */ + {6, 182}, /* 4 */ + {6, 194}, /* 5 */ + {6, 206}, /* 6 */ + {6, 218}, /* 7 */ + {6, 230}, /* 8 */ + {6, 242}, /* 9 */ + {1, 254}, /* : */ + {1, 256}, /* ; */ + {8, 258}, /* < */ + {8, 274}, /* = */ + {8, 290}, /* > */ + {5, 306}, /* ? */ + {11, 316}, /* @ */ + {8, 338}, /* A */ + {6, 354}, /* B */ + {6, 366}, /* C */ + {7, 378}, /* D */ + {6, 392}, /* E */ + {5, 404}, /* F */ + {7, 414}, /* G */ + {7, 428}, /* H */ + {1, 442}, /* I */ + {3, 444}, /* J */ + {6, 450}, /* K */ + {5, 462}, /* L */ + {8, 472}, /* M */ + {7, 488}, /* N */ + {7, 502}, /* O */ + {6, 516}, /* P */ + {7, 528}, /* Q */ + {7, 542}, /* R */ + {6, 556}, /* S */ + {7, 568}, /* T */ + {7, 582}, /* U */ + {8, 596}, /* V */ + {11, 612}, /* W */ + {7, 634}, /* X */ + {7, 648}, /* Y */ + {7, 662}, /* Z */ + {2, 676}, /* [ */ + {4, 680}, /* \ */ + {2, 688}, /* ] */ + {6, 692}, /* ^ */ + {6, 704}, /* _ */ + {2, 716}, /* ` */ + {6, 720}, /* a */ + {6, 732}, /* b */ + {5, 744}, /* c */ + {6, 754}, /* d */ + {6, 766}, /* e */ + {4, 778}, /* f */ + {6, 786}, /* g */ + {6, 798}, /* h */ + {1, 810}, /* i */ + {2, 812}, /* j */ + {5, 816}, /* k */ + {1, 826}, /* l */ + {9, 828}, /* m */ + {6, 846}, /* n */ + {6, 858}, /* o */ + {6, 870}, /* p */ + {6, 882}, /* q */ + {4, 894}, /* r */ + {5, 902}, /* s */ + {4, 912}, /* t */ + {6, 920}, /* u */ + {6, 932}, /* v */ + {9, 944}, /* w */ + {6, 962}, /* x */ + {6, 974}, /* y */ + {5, 986}, /* z */ + {5, 996}, /* { */ + {1, 1006}, /* | */ + {5, 1008}, /* } */ + {8, 1018}, /* ~ */ +}; + +} // End of namespace Gnap + +#endif // GNAP_RESOURCE_H diff --git a/engines/gnap/gamesys.cpp b/engines/gnap/gamesys.cpp new file mode 100644 index 0000000000..26af3fb8ab --- /dev/null +++ b/engines/gnap/gamesys.cpp @@ -0,0 +1,1248 @@ +/* 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. + * + */ + +#include "gnap/gamesys.h" +#include "gnap/fontdata.h" +#include "graphics/fontman.h" +#include "graphics/font.h" +#include "image/bmp.h" + +namespace Gnap { + +void GfxItem::testUpdRect(const Common::Rect &updRect) { + Common::Rect intersectingRect; + if (!_updFlag && _prevFrame._spriteId != -1 && + _updRectsCount < 20 && intersectRect(intersectingRect, _prevFrame._rect, updRect)) + _updRects[_updRectsCount++] = intersectingRect; +} + +// GameSys + +GameSys::GameSys(GnapEngine *vm) : _vm(vm) { + _newSpriteDrawItemsCount = 0; + _removeSequenceItemsCount = 0; + _removeSpriteDrawItemsCount = 0; + _grabSpriteId = -1; + _grabSpriteChanged = false; + _reqRemoveSequenceItem = false; + _removeSequenceItemSequenceId = -1; + _removeSequenceItemValue = 0; + _gfxItemsCount = 0; + _animationsCount = 0; + _backgroundImageValue3 = 0; + _backgroundImageValue1 = 0; + _backgroundImageValue4 = 1000; + _backgroundImageValue2 = 1000; + _gameSysClock = 0; + _lastUpdateClock = 0; + _backgroundSurface = nullptr; + _frontSurface = nullptr; + for (int i = 0; i < kMaxAnimations; ++i) { + _animations[i]._sequenceId = -1; + _animations[i]._id = 0; + _animations[i]._status = 0; + } + _screenRect = Common::Rect(0, 0, 800, 600); +} + +GameSys::~GameSys() { +} + +void GameSys::insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y) { + debugC(kDebugBasic, "GameSys::insertSequence() [%08X, %d] -> [%08X, %d] (%d, %d)", sequenceId, id, sequenceId2, id2, x, y); + Sequence sequence; + SequenceResource *sequenceResource = _vm->_sequenceCache->get(sequenceId); + sequenceResource->_sequenceId = sequenceId; + sequence._sequenceId = sequenceId; + sequence._id = id != -1 ? id : sequenceResource->_defaultId; + sequence._sequenceId2 = sequenceId2 != (int32)0x80000000 ? sequenceId2 : sequenceResource->_sequenceId2; + sequence._id2 = id2 != -1 ? id2 : sequenceResource->_defaultId2; + sequence._flags = flags != -1 ? flags : sequenceResource->_flags; + sequence._totalDuration = totalDuration != -1 ? totalDuration : sequenceResource->_totalDuration; + sequence._x = (x < 10000 && x > -10000) ? x : sequenceResource->_xOffs; + sequence._y = (y < 10000 && y > -10000) ? y : sequenceResource->_yOffs; + _fatSequenceItems.push_back(sequence); +} + +void GameSys::insertDirtyRect(const Common::Rect &rect) { + _dirtyRects.push_back(rect); +} + +void GameSys::removeSequence(int sequenceId, int id, bool resetFl) { + //WaitForSingleObject(removeSequence2Mutex, INFINITE); + if (_removeSequenceItemsCount < kMaxSequenceItems) { + _removeSequenceItems[_removeSequenceItemsCount]._sequenceId = sequenceId; + _removeSequenceItems[_removeSequenceItemsCount]._id = id; + _removeSequenceItems[_removeSequenceItemsCount]._forceFrameReset = resetFl; + ++_removeSequenceItemsCount; + //ResetEvent(removeSequenceItemsEvent); + //ReleaseMutex(removeSequence2Mutex); + //WaitForSingleObject(removeSequenceItemsEvent, INFINITE); + } +} + +void GameSys::invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2) { + //WaitForSingleObject(grabSpriteMutex, INFINITE); + _grabSpriteId = id; + _grabSpriteRect = rect; + _grabSpriteSurface2 = surface2; + _grabSpriteSurface1 = surface1; + //ResetEvent(grabSpriteEvent); + _grabSpriteChanged = true; + //ReleaseMutex(grabSpriteMutex); + //WaitForSingleObject(grabSpriteEvent, INFINITE); +} + +void GameSys::requestClear2(bool resetFl) { + _fatSequenceItems.clear(); + _seqItems.clear(); + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + gfxItem->_sequenceId = -1; + gfxItem->_animation = nullptr; + if (resetFl) { + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._spriteId = -1; + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + } else { + gfxItem->_updFlag = false; + } + } + _lastUpdateClock = 0; + _gameSysClock = 0; +} + +void GameSys::requestClear1() { + _gfxItemsCount = 0; + _fatSequenceItems.clear(); + _seqItems.clear(); + _lastUpdateClock = 0; + _gameSysClock = 0; +} + +void GameSys::requestRemoveSequence(int sequenceId, int id) { + //WaitForSingleObject(removeSequence2Mutex, INFINITE); + _reqRemoveSequenceItem = true; + _removeSequenceItemSequenceId = sequenceId; + _removeSequenceItemValue = id; + + handleReqRemoveSequenceItem(); //CHECKME? + + //ResetEvent(reqClearEvent); + //ReleaseMutex(removeSequence2Mutex); + //WaitForSingleObject(reqClearEvent, INFINITE); +} + +void GameSys::waitForUpdate() { + //ResetEvent(updateEvent); + //WaitForSingleObject(updateEvent, INFINITE); +} + +int GameSys::isSequenceActive(int sequenceId, int id) { + for (uint i = 0; i < _seqItems.size(); ++i) + if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id) + return true; + return false; +} + +void GameSys::setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7) { + debugC(kDebugBasic, "GameSys::setBackgroundSurface() Setting background image"); + + _backgroundSurface = surface; + if (!_backgroundSurface) { + return; + } + + if (!_frontSurface || _frontSurface->w != surface->w || _frontSurface->h != surface->h) { + debugC(kDebugBasic, "GameSys::setBackgroundSurface() Creating background working surface"); + if (_frontSurface) + _frontSurface->free(); + delete _frontSurface; + _frontSurface = new Graphics::Surface(); + _frontSurface->create(surface->w, surface->h, surface->format); + } + + memcpy(_frontSurface->getPixels(), surface->getPixels(), surface->pitch * surface->h); + _vm->_system->copyRectToScreen(_frontSurface->getPixels(), _frontSurface->pitch, 0, 0, _frontSurface->w, _frontSurface->h); + + _backgroundImageValue1 = a4; + _backgroundImageValue3 = a6; + _backgroundImageValue2 = a5; + _backgroundImageValue4 = a7; + _lastUpdateClock = 0; + _gameSysClock = 0; +} + +void GameSys::setScaleValues(int a1, int a2, int a3, int a4) { + _backgroundImageValue1 = a1; + _backgroundImageValue3 = a3; + _backgroundImageValue2 = a2; + _backgroundImageValue4 = a4; +} + +void GameSys::insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id) { + if (surface && _newSpriteDrawItemsCount < kMaxSpriteDrawItems) { + _newSpriteDrawItems[_newSpriteDrawItemsCount]._id = id; + _newSpriteDrawItems[_newSpriteDrawItemsCount]._rect = Common::Rect(x, y, x + surface->w, y + surface->h); + _newSpriteDrawItems[_newSpriteDrawItemsCount]._surface = surface; + ++_newSpriteDrawItemsCount; + } +} + +void GameSys::removeSpriteDrawItem(Graphics::Surface *surface, int id) { + if (surface && _removeSpriteDrawItemsCount < kMaxSpriteDrawItems) { + _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._id = id; + _removeSpriteDrawItems[_removeSpriteDrawItemsCount]._surface = surface; + ++_removeSpriteDrawItemsCount; + } +} + +void GameSys::drawSpriteToBackground(int x, int y, int resourceId) { + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + uint32 *sourcePalette = spriteResource->_palette; + byte *sourcePixels = spriteResource->_pixels; + int spriteWidth = spriteResource->_width; + int spriteHeight = spriteResource->_height; + Common::Rect dstRect(0, 0, spriteWidth, spriteHeight); + blitSprite32(_backgroundSurface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, spriteResource->_transparent); + _vm->_spriteCache->release(resourceId); + + // Add dirty rect so the modified background is redrawn + insertDirtyRect(Common::Rect(x, y, x + spriteWidth, y + spriteHeight)); +} + +Graphics::Surface *GameSys::allocSurface(int width, int height) { + Graphics::Surface *surface = new Graphics::Surface(); + surface->create(width, height, _backgroundSurface->format); + surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0xFFFFFF00); + return surface; +} + +Graphics::Surface *GameSys::createSurface(int resourceId) { + debugC(kDebugBasic, "GameSys::createSurface() resourceId: %08X", resourceId); + + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + Graphics::Surface *surface = allocSurface(spriteResource->_width, spriteResource->_height); + _vm->_spriteCache->release(resourceId); + + drawSpriteToSurface(surface, 0, 0, resourceId); + + return surface; +} + +void GameSys::drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId) { + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + uint32 *sourcePalette = spriteResource->_palette; + byte *sourcePixels = spriteResource->_pixels; + Common::Rect dstRect(0, 0, spriteResource->_width, spriteResource->_height); + blitSprite32(surface, x, y, sourcePixels, spriteResource->_width, dstRect, sourcePalette, true); + _vm->_spriteCache->release(resourceId); +} + +void GameSys::drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text) { + bool doDirty = false; + + if (!surface) { + surface = _backgroundSurface; + doDirty = true; + } + + uint32 color = surface->format.RGBToColor(r, g, b); + if (_vm->_font) { + _vm->_font->drawString(surface, text, x, y, _vm->_font->getStringWidth(text), color); + + if (doDirty) + insertDirtyRect(Common::Rect(x, y, x + _vm->_font->getStringWidth(text), y + _vm->_font->getFontHeight())); + } else { + for (const char *cp = text; *cp != 0; ++cp) { + byte c = *cp; + if (c < 32 || c > 127) + c = (byte)'_'; + c -= 32; + int w = _dejaVuSans9ptCharDescriptors[c]._width; + const byte *data = _dejaVuSans9ptCharBitmaps + _dejaVuSans9ptCharDescriptors[c]._offset; + for (int xc = 0; xc < w; ++xc) { + for (int yc = 15; yc >= 0; --yc) { + byte *dst = (byte *)surface->getBasePtr(x + xc, y + yc); + if (data[1 - (yc >> 3)] & (1 << (yc & 7))) + WRITE_LE_UINT32(dst, color); + } + data += 2; + } + x += w + 1; + } + + if (doDirty) + insertDirtyRect(Common::Rect(x, y, x + getTextWidth(text), y + 16)); + } +} + +int GameSys::getTextHeight(const char *text) { + byte height = 0; + for (const char *cp = text; *cp != 0; ++cp) { + byte c = *cp; + if (c < 32 || c > 127) + c = (byte)'_'; + c -= 32; + height = MAX(height, _dejaVuSans9ptCharDescriptors[c]._width); + } + return height; +} + +int GameSys::getTextWidth(const char *text) { + int width = 0; + for (const char *cp = text; *cp != 0; ++cp) { + byte c = *cp; + if (c < 32 || c > 127) + c = (byte)'_'; + c -= 32; + width += _dejaVuSans9ptCharDescriptors[c]._width + 1; + } + return width; +} + +void GameSys::fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b) { + Common::Rect rect(x, y, x + width, y + height); + if (!surface) { + _backgroundSurface->fillRect(rect, _backgroundSurface->format.RGBToColor(r, g, b)); + insertDirtyRect(rect); + } else { + surface->fillRect(rect, surface->format.RGBToColor(r, g, b)); + } +} + +void GameSys::setAnimation(int sequenceId, int id, int animationIndex) { + if (animationIndex < kMaxAnimations) { + _animations[animationIndex]._sequenceId = sequenceId; + _animations[animationIndex]._id = id; + _animations[animationIndex]._status = 0; + } +} + +int GameSys::getAnimationStatus(int animationIndex) { + int result = -1; + if (animationIndex < kMaxAnimations) + result = _animations[animationIndex]._status; + return result; +} + +int GameSys::getSpriteWidthById(int resourceId) { + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + const int width = spriteResource->_width; + _vm->_spriteCache->release(resourceId); + return width; +} + +int GameSys::getSpriteHeightById(int resourceId) { + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + const int height = spriteResource->_height; + _vm->_spriteCache->release(resourceId); + return height; +} + +Graphics::Surface *GameSys::loadBitmap(int resourceId) { + debugC(kDebugBasic, "GameSys::loadBitmap() resourceId: %08X", resourceId); + if (_vm->_dat->getResourceType(resourceId) != 1) + return nullptr; + byte *resourceData = _vm->_dat->loadResource(resourceId); + uint32 resourceSize = _vm->_dat->getResourceSize(resourceId); + Common::MemoryReadStream stream(resourceData, resourceSize, DisposeAfterUse::NO); + Graphics::Surface *bmpSurface; + Image::BitmapDecoder bmp; + if (!bmp.loadStream(stream)) + error("GameSys::loadBitmap() Could not load bitmap resource %08X", resourceId); + bmpSurface = bmp.getSurface()->convertTo(_vm->_system->getScreenFormat()); + delete[] resourceData; + return bmpSurface; +} + +void GameSys::drawBitmap(int resourceId) { + Graphics::Surface *bmpSurface = loadBitmap(resourceId); + if (!bmpSurface || !_backgroundSurface) { + debugC(kDebugBasic, "GameSys::drawBitmap() Error loading the bitmap"); + return; + } + if (bmpSurface->format != _backgroundSurface->format || + bmpSurface->w != _backgroundSurface->w || bmpSurface->h != _backgroundSurface->h) { + debugC(kDebugBasic, "GameSys::drawBitmap() Different bitmap properties than current background"); + } else { + byte *src = (byte *)bmpSurface->getPixels(); + byte *dst = (byte *)_backgroundSurface->getPixels(); + const int pitch = bmpSurface->pitch; + int height = bmpSurface->h; + while (height--) { + memcpy(dst, src, pitch); + src += pitch; + dst += pitch; + } + } + bmpSurface->free(); + delete bmpSurface; + + insertDirtyRect(Common::Rect(0, 0, 800, 600)); +} + +Sequence *GameSys::seqFind(int sequenceId, int id, int *outIndex) { + for (uint i = 0; i < _seqItems.size(); ++i) + if (_seqItems[i]._sequenceId == sequenceId && _seqItems[i]._id == id) { + if (outIndex) + *outIndex = i; + return &_seqItems[i]; + } + return nullptr; +} + +int GameSys::seqLocateGfx(int sequenceId, int id, int *outGfxIndex) { + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) { + if (outGfxIndex) + *outGfxIndex = i; + return gfxItem->_sequenceId; + } + if (gfxItem->_id > id) { + if (outGfxIndex) + *outGfxIndex = i; + return 0; + } + } + if (outGfxIndex) + *outGfxIndex = _gfxItemsCount; + return 0; +} + +void GameSys::seqInsertGfx(int index, int duration) { + Sequence *seqItem = &_seqItems[index]; + SequenceResource *sequenceResource = _vm->_sequenceCache->get(seqItem->_sequenceId); + + if (sequenceResource->_animationsCount > 50 - _gfxItemsCount) + return; + + int gfxIndex; + seqLocateGfx(seqItem->_sequenceId, seqItem->_id, &gfxIndex); + + if (gfxIndex != _gfxItemsCount) + memmove(&_gfxItems[gfxIndex + sequenceResource->_animationsCount], &_gfxItems[gfxIndex], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex)); + _gfxItemsCount += sequenceResource->_animationsCount; + + for (int i = 0; i < sequenceResource->_animationsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i + gfxIndex]; + SequenceAnimation *animation = &sequenceResource->_animations[i]; + + debugC(kDebugBasic, "GameSys::seqInsertGfx() seqItem->sequenceId: %08X", seqItem->_sequenceId); + + gfxItem->_sequenceId = seqItem->_sequenceId; + gfxItem->_id = seqItem->_id; + gfxItem->_animation = animation; + gfxItem->_currFrameNum = 0; + gfxItem->_flags = 0; + gfxItem->_delayTicks = seqItem->_totalDuration + animation->_additionalDelay; + gfxItem->_updFlag = false; + gfxItem->_updRectsCount = 0; + gfxItem->_prevFrame._duration = 0; + gfxItem->_prevFrame._spriteId = -1; + gfxItem->_prevFrame._soundId = -1; + int totalDuration = duration; + if ((seqItem->_flags & 4) && totalDuration > 0) { + gfxItem->_prevFrame._duration = 1; + if (gfxItem->_delayTicks <= totalDuration) + gfxItem->_delayTicks = 0; + else + gfxItem->_delayTicks -= totalDuration + 1; + gfxItem->_updFlag = false; + } else if (gfxItem->_delayTicks <= totalDuration) { + int j; + totalDuration -= gfxItem->_delayTicks; + gfxItem->_delayTicks = 0; + for (j = gfxItem->_currFrameNum; j < animation->_framesCount && animation->frames[j]._duration <= totalDuration; ++j) { + if (animation->frames[j]._soundId != -1) + _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[j]._soundId); + totalDuration -= animation->frames[j]._duration; + } + if (animation->_framesCount > j) + gfxItem->_currFrame = animation->frames[j++]; + else + gfxItem->_currFrame = animation->frames[j - 1]; + if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0)) + gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y); + // Update sprite scaling + if ((seqItem->_flags & 1) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) { + int scaleValue = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) * + (_backgroundImageValue4 - _backgroundImageValue2) / + (_backgroundImageValue3 - _backgroundImageValue1); + gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - scaleValue * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000; + gfxItem->_currFrame._rect.right = scaleValue * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left; + gfxItem->_currFrame._isScaled = true; + } + gfxItem->_currFrame._duration -= totalDuration; + if (gfxItem->_currFrame._soundId != -1) + _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId); + gfxItem->_currFrameNum = j; + gfxItem->_updFlag = true; + } else { + gfxItem->_delayTicks -= totalDuration + 1; + gfxItem->_updFlag = false; + } + } + + for (int k = 0; k < kMaxAnimations; ++k) { + if (_animations[k]._sequenceId != -1 && _animations[k]._sequenceId == seqItem->_sequenceId && _animations[k]._id == seqItem->_id) { + _animations[k]._status = 1; + break; + } + } +} + +void GameSys::seqRemoveGfx(int sequenceId, int id) { + int gfxIndex; + if (seqLocateGfx(sequenceId, id, &gfxIndex)) { + GfxItem *gfxItem = &_gfxItems[gfxIndex]; + while (gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) { + if (gfxItem->_prevFrame._spriteId == -1) { + --_gfxItemsCount; + if (gfxIndex != _gfxItemsCount) + memmove(&_gfxItems[gfxIndex], &_gfxItems[gfxIndex + 1], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex)); + } else { + gfxItem->_sequenceId = -1; + gfxItem->_animation = nullptr; + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._spriteId = -1; + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + ++gfxIndex; + gfxItem = &_gfxItems[gfxIndex]; + } + } + } +} + +bool GameSys::updateSequenceDuration(int sequenceId, int id, int *outDuration) { + bool found = false; + int duration = 0x7FFFFFFF; + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id) { + found = true; + SequenceAnimation *animation = gfxItem->_animation; + if (animation) { + if (gfxItem->_currFrameNum < animation->_framesCount) + return false; + if (gfxItem->_updFlag) { + if (gfxItem->_currFrame._duration > 0) + return false; + if (-gfxItem->_currFrame._duration < duration) + duration = -gfxItem->_currFrame._duration; + } else { + if (gfxItem->_prevFrame._duration > 0) + return false; + if (-gfxItem->_prevFrame._duration < duration) + duration = -gfxItem->_prevFrame._duration; + } + } + } + } + if (found) + *outDuration = duration; + return found; +} + +void GameSys::updateAnimationsStatus(int sequenceId, int id) { + Animation *foundAnimation = nullptr; + for (int animationIndex = 0; animationIndex < kMaxAnimations; ++animationIndex) { + Animation *animation = &_animations[animationIndex]; + if (animation->_sequenceId != -1 && animation->_sequenceId == sequenceId && animation->_id == id) { + foundAnimation = animation; + break; + } + } + + if (!foundAnimation) + return; + + bool foundSequence = false; + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + SequenceAnimation *animation = gfxItem->_animation; + if (gfxItem->_sequenceId == sequenceId && gfxItem->_id == id && animation) { + foundSequence = true; + if (animation->_framesCount > gfxItem->_currFrameNum || + (gfxItem->_updFlag && gfxItem->_currFrame._duration > 1) || + gfxItem->_prevFrame._duration > 1) + foundSequence = false; + break; + } + } + + if (foundSequence) { + foundAnimation->_sequenceId = -1; + foundAnimation->_status = 2; + } +} + +void GameSys::restoreBackgroundRect(const Common::Rect &rect) { + Common::Rect clipRect; + if (!intersectRect(clipRect, rect, _screenRect)) + return; + byte *src = (byte *)_backgroundSurface->getBasePtr(clipRect.left, clipRect.top); + byte *dst = (byte *)_frontSurface->getBasePtr(clipRect.left, clipRect.top); + const int bytes = _backgroundSurface->format.bytesPerPixel * clipRect.width(); + int height = clipRect.height(); + while (height--) { + memcpy(dst, src, bytes); + src += _backgroundSurface->pitch; + dst += _frontSurface->pitch; + } +} + +void GameSys::blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface, + Common::Rect &sourceRect, bool transparent) { + + const int sourcePitch = sourceSurface->pitch; + byte *dst = (byte *)destSurface->getBasePtr(x, y); + byte *src = (byte *)sourceSurface->getBasePtr(sourceRect.left, sourceRect.top); + int width = sourceRect.width(); + int height = sourceRect.height(); + while (height--) { + byte *rsrc = src; + byte *rdst = dst; + for (int xc = 0; xc < width; ++xc) { + uint32 pixel = READ_LE_UINT32(rsrc); + if (!transparent || pixel != 0xFFFFFF00) + WRITE_LE_UINT32(rdst, pixel); + rsrc += 4; + rdst += 4; + } + dst += destSurface->pitch; + src += sourcePitch; + } +} + +void GameSys::blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels, + int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent) { + + const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC; + byte *dst = (byte *)destSurface->getBasePtr(x, y); + byte *src = sourcePixels + sourceRect.left + sourcePitch * sourceRect.top; + int width = sourceRect.width(); + int height = sourceRect.height(); + while (height--) { + byte *rdst = dst; + for (int xc = 0; xc < width; ++xc) { + byte srcPixel = src[xc]; + if (!transparent || srcPixel) { + uint32 rgb = sourcePalette[srcPixel]; + rdst[0] = 0xFF; + rdst[1] = rgb & 0x000000FF; + rdst[2] = (rgb & 0x0000FF00) >> 8; + rdst[3] = (rgb & 0x00FF0000) >> 16; + } + rdst += 4; + } + dst += destSurface->pitch; + src += sourcePitch; + } +} + +void GameSys::blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect, + Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette) { + + if (frameRect.height() <= 0 || frameRect.width() <= 0) + return; + + const int ys = ((sourceRect.bottom - sourceRect.top - 1) << 16) / (frameRect.bottom - frameRect.top - 1); + const int xs = ((sourceRect.right - sourceRect.left - 1) << 16) / (frameRect.right - frameRect.left - 1); + const int destPitch = destSurface->pitch; + const int sourcePitch = (sourceWidth + 3) & 0xFFFFFFFC; + + if (!frameRect.equals(destRect)) { + byte *dst = (byte *)destSurface->getBasePtr(destRect.left, destRect.top); + byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left; + const int height = destRect.bottom - destRect.top; + const int width = destRect.right - destRect.left; + int yi = ys * (destRect.top - frameRect.top); + byte *hsrc = src + sourcePitch * ((yi + 0x8000) >> 16); + for (int i = 0; i < height; ++i) { + byte *wdst = dst; + int xi = xs * (destRect.left - frameRect.left); + byte *wsrc = hsrc + ((xi + 0x8000) >> 16); + for (int j = 0; j < width; ++j) { + byte srcPixel = *wsrc; + if (srcPixel) { + uint32 rgb = sourcePalette[srcPixel]; + wdst[0] = 0xFF; + wdst[1] = rgb & 0x000000FF; + wdst[2] = (rgb & 0x0000FF00) >> 8; + wdst[3] = (rgb & 0x00FF0000) >> 16; + } + wdst += 4; + xi += xs; + wsrc = hsrc + ((xi + 0x8000) >> 16); + } + dst += destPitch; + yi += ys; + hsrc = src + sourcePitch * ((yi + 0x8000) >> 16); + } + } else { + byte *dst = (byte *)destSurface->getBasePtr(frameRect.left, frameRect.top); + byte *src = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left; + const int height = frameRect.bottom - frameRect.top; + const int width = frameRect.right - frameRect.left; + byte *hsrc = sourcePixels + sourcePitch * sourceRect.top + sourceRect.left; + int yi = 0; + for (int i = 0; i < height; ++i) { + byte *wdst = dst; + byte *wsrc = hsrc; + int xi = 0; + for (int j = 0; j < width; ++j) { + byte srcPixel = *wsrc; + if (srcPixel) { + uint32 rgb = sourcePalette[srcPixel]; + wdst[0] = 0xFF; + wdst[1] = rgb & 0x000000FF; + wdst[2] = (rgb & 0x0000FF00) >> 8; + wdst[3] = (rgb & 0x00FF0000) >> 16; + } + wdst += 4; + xi += xs; + wsrc = hsrc + ((xi + 0x8000) >> 16); + } + dst += destPitch; + yi += ys; + hsrc = src + sourcePitch * ((yi + 0x8000) >> 16); + } + } + +} + +void GameSys::seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect) { + debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() rect: (%d, %d, %d, %d)", + frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom); + + Common::Rect srcRect = subRect ? *subRect : frame._rect; + Common::Rect clipRect; + + if (!intersectRect(clipRect, srcRect, _screenRect)) { + debugC(kDebugBasic, "GameSys::seqDrawStaticFrame() Surface not inside screen"); + return; + } + + const int x = clipRect.left, y = clipRect.top; + + clipRect.translate(-frame._rect.left, -frame._rect.top); + + // TODO Save transparent flag somewhere + blitSurface32(_frontSurface, x, y, surface, clipRect, true); +} + +void GameSys::seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect) { + debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() spriteId: %04X; rect: (%d, %d, %d, %d)", + frame._spriteId, frame._rect.left, frame._rect.top, frame._rect.right, frame._rect.bottom); + + Common::Rect srcRect = subRect ? *subRect : frame._rect; + Common::Rect clipRect; + + if (!intersectRect(clipRect, srcRect, _screenRect)) { + debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() Sprite not inside screen"); + return; + } + + uint32 *sourcePalette = spriteResource->_palette; + byte *sourcePixels = spriteResource->_pixels; + + const int x = clipRect.left, y = clipRect.top; + + debugC(kDebugBasic, "GameSys::seqDrawSpriteFrame() destX: %d; destY: %d; frame.isScaled: %d", x, y, frame._isScaled ? 1 : 0); + + // 32bit sprite drawing + if (frame._isScaled) { + Common::Rect sourceRect(0, 0, spriteResource->_width, spriteResource->_height); + blitSpriteScaled32(_frontSurface, frame._rect, clipRect, sourcePixels, spriteResource->_width, sourceRect, sourcePalette); + } else { + clipRect.translate(-frame._rect.left, -frame._rect.top); + blitSprite32(_frontSurface, x, y, sourcePixels, spriteResource->_width, clipRect, sourcePalette, true); + } +} + +void GameSys::drawSprites() { + debugC(kDebugBasic, "GameSys::drawSprites() _gfxItemsCount: %d", _gfxItemsCount); + + // Restore dirty background and collect rects to be redrawn for all sprites + // which aren't marked to be redrawn yet + Common::Rect intersectingRect; + for (uint i = 0; i < _dirtyRects.size(); ++i) { + restoreBackgroundRect(_dirtyRects[i]); + for (int j = 0; j < _gfxItemsCount; ++j) + _gfxItems[j].testUpdRect(_dirtyRects[i]); + } + + for (int k = 0; k < _gfxItemsCount; ++k) { + GfxItem *gfxItem2 = &_gfxItems[k]; + + if (!gfxItem2->_updFlag) + continue; + + if (gfxItem2->_prevFrame._spriteId != -1) { + bool transparent = false; + if (gfxItem2->_currFrame._spriteId != -1) { + if (gfxItem2->_flags) { + transparent = true; + } else { + int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId; + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + transparent = spriteResource->_transparent; + _vm->_spriteCache->release(resourceId); + } + } + if (gfxItem2->_currFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || !transparent) { + restoreBackgroundRect(gfxItem2->_prevFrame._rect); + for (int l = 0; l < _gfxItemsCount; ++l) + _gfxItems[l].testUpdRect(gfxItem2->_prevFrame._rect); + } + } + + if (gfxItem2->_currFrame._spriteId != -1) { + bool transparent = false; + if (gfxItem2->_flags) { + transparent = true; + } else { + int resourceId = (gfxItem2->_sequenceId & 0xFFFF0000) | gfxItem2->_currFrame._spriteId; + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + transparent = spriteResource->_transparent; + _vm->_spriteCache->release(resourceId); + } + if (gfxItem2->_prevFrame._spriteId == -1 || !gfxItem2->_prevFrame._rect.equals(gfxItem2->_currFrame._rect) || transparent) { + for (int l = k; l < _gfxItemsCount; ++l) + _gfxItems[l].testUpdRect(gfxItem2->_currFrame._rect); + } + } + } + + for (int m = 0; m < _gfxItemsCount; ++m) { + GfxItem *gfxItem5 = &_gfxItems[m]; + + debugC(kDebugBasic, "DrawGfxItem(%d) updFlag: %d; currFrame.spriteId: %04X; updRectsCount: %d; flags: %04X; sequenceId: %08X", + m, gfxItem5->_updFlag, gfxItem5->_currFrame._spriteId, gfxItem5->_updRectsCount, gfxItem5->_flags, gfxItem5->_sequenceId); + + if (gfxItem5->_updFlag) { + if (gfxItem5->_currFrame._spriteId != -1) { + if (gfxItem5->_flags) { + seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_currFrame, nullptr); + } else { + int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_currFrame._spriteId; + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + seqDrawSpriteFrame(spriteResource, gfxItem5->_currFrame, nullptr); + _vm->_spriteCache->release(resourceId); + } + } + } else if (gfxItem5->_updRectsCount > 0) { + if (gfxItem5->_flags) { + for (int n = 0; n < gfxItem5->_updRectsCount; ++n) + seqDrawStaticFrame(gfxItem5->_surface, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]); + } else { + int resourceId = (gfxItem5->_sequenceId & 0xFFFF0000) | gfxItem5->_prevFrame._spriteId; + SpriteResource *spriteResource = _vm->_spriteCache->get(resourceId); + for (int n = 0; n < gfxItem5->_updRectsCount; ++n) + seqDrawSpriteFrame(spriteResource, gfxItem5->_prevFrame, &gfxItem5->_updRects[n]); + _vm->_spriteCache->release(resourceId); + } + } + } + + debugC(kDebugBasic, "GameSys::drawSprites() OK"); +} + +void GameSys::updateRect(const Common::Rect &r) { + debugC(kDebugBasic, "GameSys::updateRect() %d, %d, %d, %d [%d, %d]", r.left, r.top, r.right, r.bottom, r.width(), r.height()); + if (r.width() > 0 && r.height() > 0) { + byte *pixels = (byte *)_frontSurface->getBasePtr(r.left, r.top); + _vm->_system->copyRectToScreen(pixels, _frontSurface->pitch, r.left, r.top, + r.width(), r.height()); + } +} + +void GameSys::updateScreen() { + debugC(kDebugBasic, "GameSys::updateScreen()"); + + for (uint i = 0; i < _dirtyRects.size(); ++i) + updateRect(_dirtyRects[i]); + + if (_dirtyRects.size() > 0) { + _dirtyRects.clear(); + _lastUpdateClock = 0; + _gameSysClock = 0; + } + + Common::Rect dstRect, srcRect, rcSrc2; + + for (int j = 0; j < _gfxItemsCount; ++j) { + + GfxItem *gfxItem = &_gfxItems[j]; + + if (!gfxItem->_updFlag) + continue; + + if (gfxItem->_prevFrame._spriteId == -1 || + !intersectRect(srcRect, _screenRect, gfxItem->_prevFrame._rect)) { + if (gfxItem->_currFrame._spriteId != -1 && intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect)) + updateRect(rcSrc2); + } else if (gfxItem->_currFrame._spriteId != -1 && + intersectRect(rcSrc2, _screenRect, gfxItem->_currFrame._rect)) { + updateRect(srcRect); + updateRect(rcSrc2); + } + gfxItem->_prevFrame = gfxItem->_currFrame; + } + + updateRect(Common::Rect(0, 0, 800, 600)); + + debugC(kDebugBasic, "GameSys::updateScreen() OK"); +} + +void GameSys::handleReqRemoveSequenceItem() { + if (_reqRemoveSequenceItem) { + int gfxIndex2; + _reqRemoveSequenceItem = false; + if (seqFind(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2)) + _seqItems.remove_at(gfxIndex2); + if (seqLocateGfx(_removeSequenceItemSequenceId, _removeSequenceItemValue, &gfxIndex2)) { + int gfxIndex2a = gfxIndex2; + for (GfxItem *gfxItem = &_gfxItems[gfxIndex2a]; + gfxIndex2a < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItemSequenceId && gfxItem->_id == _removeSequenceItemValue; + gfxItem = &_gfxItems[gfxIndex2a]) + ++gfxIndex2a; + _gfxItemsCount -= gfxIndex2a - gfxIndex2; + if (_gfxItemsCount != gfxIndex2) + memmove(&_gfxItems[gfxIndex2], &_gfxItems[gfxIndex2a], sizeof(GfxItem) * (_gfxItemsCount - gfxIndex2)); + } + } +} + +void GameSys::handleReqRemoveSequenceItems() { + if (_removeSequenceItemsCount > 0) { + for (int i = 0; i < _removeSequenceItemsCount; ++i) { + int gfxIndex; + if (seqFind(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex)) + _seqItems.remove_at(gfxIndex); + seqLocateGfx(_removeSequenceItems[i]._sequenceId, _removeSequenceItems[i]._id, &gfxIndex); + for (GfxItem *gfxItem = &_gfxItems[gfxIndex]; + gfxIndex < _gfxItemsCount && gfxItem->_sequenceId == _removeSequenceItems[i]._sequenceId && gfxItem->_id == _removeSequenceItems[i]._id; + gfxItem = &_gfxItems[gfxIndex]) { + gfxItem->_sequenceId = -1; + gfxItem->_animation = nullptr; + if (_removeSequenceItems[i]._forceFrameReset) { + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._spriteId = -1; + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + } else { + gfxItem->_updFlag = false; + } + ++gfxIndex; + } + } + _removeSequenceItemsCount = 0; + } +} + +void GameSys::handleReqRemoveSpriteDrawItems() { + if (_removeSpriteDrawItemsCount > 0) { + for (int j = 0; j < _removeSpriteDrawItemsCount; ++j) { + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags + && gfxItem->_id == _removeSpriteDrawItems[j]._id && _removeSpriteDrawItems[j]._surface == gfxItem->_surface) { + gfxItem->_flags = 0; + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._spriteId = -1; + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + } + } + } + _removeSpriteDrawItemsCount = 0; + } +} + +void GameSys::fatUpdateFrame() { + debugC(kDebugBasic, "GameSys::fatUpdateFrame()"); + + int32 clockDelta = _gameSysClock - _lastUpdateClock; + _lastUpdateClock = _gameSysClock; + + debugC(kDebugBasic, "GameSys::fatUpdateFrame() clockDelta: %d", clockDelta); + + if (clockDelta <= 0) + return; + + int duration, currFrameNum; + + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + SequenceAnimation *animation = gfxItem->_animation; + if ((gfxItem->_sequenceId != -1 && animation) || gfxItem->_prevFrame._spriteId != -1 || gfxItem->_prevFrame._duration > 0) { + if (gfxItem->_sequenceId != -1 && !gfxItem->_updFlag) { + Sequence *seqItem = seqFind(gfxItem->_sequenceId, gfxItem->_id, nullptr); + if (!animation) { + gfxItem->_sequenceId = -1; + gfxItem->_animation = nullptr; + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._spriteId = -1; + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + } else if (!seqItem) { + gfxItem->_animation = nullptr; + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._spriteId = -1; + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + } else if ((seqItem->_flags & 4) && clockDelta > 1) { + if (gfxItem->_delayTicks < clockDelta) { + duration = clockDelta - gfxItem->_delayTicks; + gfxItem->_delayTicks = 0; + if (gfxItem->_prevFrame._duration <= duration) + gfxItem->_prevFrame._duration = 1; + else + gfxItem->_prevFrame._duration -= duration; + } else { + gfxItem->_delayTicks -= clockDelta; + } + gfxItem->_updFlag = false; + } else if (gfxItem->_delayTicks < clockDelta) { + duration = clockDelta - gfxItem->_delayTicks; + gfxItem->_delayTicks = 0; + if (gfxItem->_prevFrame._duration <= duration) { + bool v20 = false; + if (gfxItem->_prevFrame._duration > 0) { + duration -= gfxItem->_prevFrame._duration; + gfxItem->_prevFrame._duration = -duration; + } else { + gfxItem->_prevFrame._duration = 0; + v20 = true; + } + currFrameNum = gfxItem->_currFrameNum; + if (animation->_framesCount > currFrameNum) { + while (animation->_framesCount > currFrameNum && + animation->frames[currFrameNum]._duration <= duration) { + if (animation->frames[currFrameNum]._soundId != -1) + _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | animation->frames[currFrameNum]._soundId); + duration -= animation->frames[currFrameNum]._duration; + ++currFrameNum; + } + if (animation->_framesCount > currFrameNum) + gfxItem->_currFrame = animation->frames[currFrameNum++]; + else + gfxItem->_currFrame = animation->frames[currFrameNum - 1]; + if (gfxItem->_currFrame._spriteId != -1 && (seqItem->_x != 0 || seqItem->_y != 0)) + gfxItem->_currFrame._rect.translate(seqItem->_x, seqItem->_y); + // Update sprite scaling + if ((seqItem->_flags & 1) && gfxItem->_currFrame._rect.bottom >= _backgroundImageValue1 && gfxItem->_currFrame._rect.bottom <= _backgroundImageValue3) { + int v17 = _backgroundImageValue2 + (gfxItem->_currFrame._rect.bottom - _backgroundImageValue1) * + (_backgroundImageValue4 - _backgroundImageValue2) / + (_backgroundImageValue3 - _backgroundImageValue1); + gfxItem->_currFrame._rect.top = gfxItem->_currFrame._rect.bottom - v17 * (gfxItem->_currFrame._rect.bottom - gfxItem->_currFrame._rect.top) / 1000; + gfxItem->_currFrame._rect.right = v17 * (gfxItem->_currFrame._rect.right - gfxItem->_currFrame._rect.left) / 1000 + gfxItem->_currFrame._rect.left; + gfxItem->_currFrame._isScaled = true; + } + gfxItem->_currFrame._duration -= duration; + if (gfxItem->_currFrame._soundId != -1) + _soundIds.push_back((gfxItem->_sequenceId & 0xFFFF0000) | gfxItem->_currFrame._soundId); + gfxItem->_currFrameNum = currFrameNum; + gfxItem->_updFlag = true; + } else if (v20 && gfxItem->_prevFrame._spriteId == -1) { + --_gfxItemsCount; + if (_gfxItemsCount != i) + memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i)); + --i; + } else { + gfxItem->_updFlag = false; + } + } else { + gfxItem->_prevFrame._duration -= duration; + gfxItem->_updFlag = false; + } + } else { + gfxItem->_delayTicks -= clockDelta; + gfxItem->_updFlag = false; + } + } + } else { + --_gfxItemsCount; + if (_gfxItemsCount != i) + memmove(&_gfxItems[i], &_gfxItems[i + 1], sizeof(GfxItem) * (_gfxItemsCount - i)); + --i; + } + } + + if (_newSpriteDrawItemsCount > 0) { + debugC(kDebugBasic, "_newSpriteDrawItemsCount: %d", _newSpriteDrawItemsCount); + for (int k = 0; k < _newSpriteDrawItemsCount; ++k) { + if (_gfxItemsCount < 50) { + int insertIndex; + seqLocateGfx(-1, _newSpriteDrawItems[k]._id, &insertIndex); + if (_gfxItemsCount != insertIndex) + memmove(&_gfxItems[insertIndex + 1], &_gfxItems[insertIndex], sizeof(GfxItem) * (_gfxItemsCount - insertIndex)); + ++_gfxItemsCount; + GfxItem *gfxItem = &_gfxItems[insertIndex]; + gfxItem->_sequenceId = -1; + gfxItem->_id = _newSpriteDrawItems[k]._id; + gfxItem->_animation = nullptr; + gfxItem->_currFrameNum = 0; + gfxItem->_flags = 1; + gfxItem->_delayTicks = 0; + gfxItem->_updFlag = true; + gfxItem->_updRectsCount = 0; + gfxItem->_surface = _newSpriteDrawItems[k]._surface; + gfxItem->_prevFrame._duration = 0; + gfxItem->_prevFrame._spriteId = -1; + gfxItem->_prevFrame._soundId = -1; + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._isScaled = false; + gfxItem->_currFrame._rect = _newSpriteDrawItems[k]._rect; + gfxItem->_currFrame._spriteId = _newSpriteDrawItems[k]._surface ? 0xCAFEBABE : -1;// TODO + gfxItem->_currFrame._soundId = -1; + } + } + _newSpriteDrawItemsCount = 0; + } + + if (_grabSpriteChanged) { + for (int i = 0; i < _gfxItemsCount; ++i) { + GfxItem *gfxItem = &_gfxItems[i]; + if (gfxItem->_sequenceId == -1 && !gfxItem->_animation && gfxItem->_flags + && gfxItem->_id == _grabSpriteId && gfxItem->_surface == _grabSpriteSurface1) { + gfxItem->_currFrame._duration = 0; + gfxItem->_currFrame._isScaled = false; + gfxItem->_currFrame._rect = _grabSpriteRect; + gfxItem->_currFrame._spriteId = _grabSpriteSurface2 ? 1 : -1;// TODO + gfxItem->_currFrame._soundId = -1; + gfxItem->_updFlag = true; + gfxItem->_surface = _grabSpriteSurface2; + break; + } + } + _grabSpriteChanged = false; + } + + debugC(kDebugBasic, "GameSys::fatUpdateFrame() _fatSequenceItems.size(): %d", _fatSequenceItems.size()); + + for (uint i = 0; i < _fatSequenceItems.size(); ++i) { + Sequence *seqItem = &_fatSequenceItems[i]; + if (((seqItem->_flags & 8) || (seqItem->_flags & 0x20)) && seqItem->_sequenceId2 != -1) { + duration = 0; + if (((seqItem->_flags & 0x20) && seqLocateGfx(seqItem->_sequenceId2, seqItem->_id2, nullptr)) || + updateSequenceDuration(seqItem->_sequenceId2, seqItem->_id2, &duration)) { + int index = -1; + bool found = false; + if (seqItem->_sequenceId2 == seqItem->_sequenceId && seqItem->_id == seqItem->_id2 && + seqFind(seqItem->_sequenceId, seqItem->_id, &index)) { + _seqItems[index] = *seqItem; + found = true; + } else if (_seqItems.size() < 50) { + index = _seqItems.size(); + _seqItems.push_back(*seqItem); + found = true; + } + if (found) { + seqRemoveGfx(seqItem->_sequenceId2, seqItem->_id2); + seqRemoveGfx(seqItem->_sequenceId, seqItem->_id); + _fatSequenceItems.remove_at(i); + --i; + seqInsertGfx(index, duration); + } + } + } else { + if (seqItem->_totalDuration < clockDelta) { + int index; + bool found = false; + duration = clockDelta - seqItem->_totalDuration; + seqItem->_totalDuration = 0; + if (seqFind(seqItem->_sequenceId, seqItem->_id, &index)) { + _seqItems[index] = *seqItem; + found = true; + } else if (_seqItems.size() < 50) { + index = _seqItems.size(); + _seqItems.push_back(*seqItem); + found = true; + } + if (found) { + seqRemoveGfx(seqItem->_sequenceId, seqItem->_id); + _fatSequenceItems.remove_at(i); + --i; + seqInsertGfx(index, duration - 1); + } + } else { + seqItem->_totalDuration -= clockDelta; + } + } + } + + debugC(kDebugBasic, "GameSys::fatUpdateFrame() _seqItems.size(): %d", _seqItems.size()); + + for (uint i = 0; i < _seqItems.size(); ++i) { + Sequence *seqItem = &_seqItems[i]; + if (seqLocateGfx(seqItem->_sequenceId, seqItem->_id, nullptr)) { + updateAnimationsStatus(seqItem->_sequenceId, seqItem->_id); + if (seqItem->_flags & 2) { + int gfxDuration; + if (updateSequenceDuration(seqItem->_sequenceId, seqItem->_id, &gfxDuration)) { + seqRemoveGfx(seqItem->_sequenceId, seqItem->_id); + seqInsertGfx(i, gfxDuration); + } + } + } else { + _seqItems.remove_at(i); + --i; + } + } +} + +void GameSys::fatUpdate() { + debugC(kDebugBasic, "GameSys::fatUpdate() _gfxItemsCount: %d", _gfxItemsCount); + + for (int i = 0; i < _gfxItemsCount; ++i) { + _gfxItems[i]._updFlag = false; + _gfxItems[i]._updRectsCount = 0; + } + + handleReqRemoveSequenceItem(); + handleReqRemoveSequenceItems(); + handleReqRemoveSpriteDrawItems(); + + fatUpdateFrame(); +} + +void GameSys::updatePlaySounds() { + for (uint i = 0; i < _soundIds.size(); ++i) + _vm->playSound(_soundIds[i], false); + _soundIds.clear(); +} + +bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2) { + if (r1.intersects(r2)) { + intersectingRect = r1.findIntersectingRect(r2); + return true; + } else + return false; +} + +} // End of namespace Gnap diff --git a/engines/gnap/gamesys.h b/engines/gnap/gamesys.h new file mode 100644 index 0000000000..98014f1bac --- /dev/null +++ b/engines/gnap/gamesys.h @@ -0,0 +1,211 @@ +/* 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. + * + */ + +#ifndef GNAP_GAMESYS_H +#define GNAP_GAMESYS_H + +#include "gnap/gnap.h" +#include "gnap/resource.h" +#include "common/array.h" +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Gnap { + +const int kMaxSequenceItems = 40; +const int kMaxSpriteDrawItems = 30; +const int kMaxSoundIds = 50; +const int kMaxSeqItems = 50; +const int kMaxUpdRects = 20; +const int kMaxGfxItems = 50; +const int kMaxAnimations = 12; + +enum { + kSeqNone = 0x00, + kSeqScale = 0x01, // Enable scaling + kSeqLoop = 0x02, // Loop + kSeqUnk = 0x04, // Unknown + kSeqSyncWait = 0x08, // Start if other sequence is done + kSeqSyncExists = 0x20 // Start if other sequence exists +}; + +struct Sequence { + int32 _sequenceId; + int32 _id; + int32 _sequenceId2; + int32 _id2; + uint32 _flags; + int32 _totalDuration; + int16 _x, _y; +}; + +struct SpriteDrawItem { + int _id; + Common::Rect _rect; + Graphics::Surface *_surface; +}; + +struct RemoveSequenceItem { + int _sequenceId; + int _id; + bool _forceFrameReset; +}; + +struct RemoveSpriteDrawItem { + int _id; + Graphics::Surface *_surface; +}; + +struct GfxItem { + int _sequenceId; + int _id; + int _flags; + SequenceAnimation *_animation; + int _currFrameNum; + int _delayTicks; + bool _updFlag; + int _updRectsCount; + Graphics::Surface *_surface; + Common::Rect _updRects[kMaxUpdRects]; + SequenceFrame _prevFrame; + SequenceFrame _currFrame; + void testUpdRect(const Common::Rect &updRect); +}; + +struct Animation { + int _sequenceId; + int _id; + int _status; +}; + +class GameSys { +public: + GameSys(GnapEngine *vm); + ~GameSys(); + void insertSequence(int sequenceId, int id, int sequenceId2, int id2, int flags, int totalDuration, int16 x, int16 y); + void insertDirtyRect(const Common::Rect &rect); + void removeSequence(int sequenceId, int id, bool resetFl); + void invalidateGrabCursorSprite(int id, Common::Rect &rect, Graphics::Surface *surface1, Graphics::Surface *surface2); + void requestClear2(bool resetFl); + void requestClear1(); + void requestRemoveSequence(int sequenceId, int id); + void waitForUpdate(); + int isSequenceActive(int sequenceId, int id); + void setBackgroundSurface(Graphics::Surface *surface, int a4, int a5, int a6, int a7); + void setScaleValues(int a1, int a2, int a3, int a4); + void insertSpriteDrawItem(Graphics::Surface *surface, int x, int y, int id); + void removeSpriteDrawItem(Graphics::Surface *surface, int id); + void drawSpriteToBackground(int x, int y, int resourceId); + Graphics::Surface *allocSurface(int width, int height); + Graphics::Surface *createSurface(int resourceId); + void drawSpriteToSurface(Graphics::Surface *surface, int x, int y, int resourceId); + void drawTextToSurface(Graphics::Surface *surface, int x, int y, byte r, byte g, byte b, const char *text); + int getTextHeight(const char *text); + int getTextWidth(const char *text); + void fillSurface(Graphics::Surface *surface, int x, int y, int width, int height, byte r, byte g, byte b); + void setAnimation(int sequenceId, int id, int animationIndex); + int getAnimationStatus(int animationIndex); + int getSpriteWidthById(int resourceId); + int getSpriteHeightById(int resourceId); + Graphics::Surface *loadBitmap(int resourceId); + void drawBitmap(int resourceId); +public: + GnapEngine *_vm; + + Common::Array<Common::Rect> _dirtyRects; + + SpriteDrawItem _newSpriteDrawItems[kMaxSpriteDrawItems]; + int _newSpriteDrawItemsCount; + + RemoveSequenceItem _removeSequenceItems[kMaxSequenceItems]; + int _removeSequenceItemsCount; + + RemoveSpriteDrawItem _removeSpriteDrawItems[kMaxSpriteDrawItems]; + int _removeSpriteDrawItemsCount; + + int _grabSpriteId; + Common::Rect _grabSpriteRect; + bool _grabSpriteChanged; + Graphics::Surface *_grabSpriteSurface1, *_grabSpriteSurface2; + + bool _reqRemoveSequenceItem; + int _removeSequenceItemSequenceId, _removeSequenceItemValue; + + Common::Array<int> _soundIds; + + //////////////////////////////////////////////////////////////////////////// + + Common::Array<Sequence> _seqItems; + Common::Array<Sequence> _fatSequenceItems; + + GfxItem _gfxItems[kMaxGfxItems]; + int _gfxItemsCount; + + Animation _animations[kMaxAnimations]; + int _animationsCount; + + int _backgroundImageValue3, _backgroundImageValue1; + int _backgroundImageValue4, _backgroundImageValue2; + + int32 _gameSysClock, _lastUpdateClock; + + Graphics::Surface *_backgroundSurface; + Graphics::Surface *_frontSurface; + Common::Rect _screenRect; + + Sequence *seqFind(int sequenceId, int id, int *outIndex); + int seqLocateGfx(int sequenceId, int id, int *outGfxIndex); + void seqInsertGfx(int index, int duration); + void seqRemoveGfx(int sequenceId, int id); + bool updateSequenceDuration(int sequenceId, int id, int *outDuration); + void updateAnimationsStatus(int sequenceId, int id); + + void restoreBackgroundRect(const Common::Rect &rect); + + void blitSurface32(Graphics::Surface *destSurface, int x, int y, Graphics::Surface *sourceSurface, + Common::Rect &sourceRect, bool transparent); + void blitSprite32(Graphics::Surface *destSurface, int x, int y, byte *sourcePixels, + int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette, bool transparent); + void blitSpriteScaled32(Graphics::Surface *destSurface, Common::Rect &frameRect, + Common::Rect &destRect, byte *sourcePixels, int sourceWidth, Common::Rect &sourceRect, uint32 *sourcePalette); + + void seqDrawStaticFrame(Graphics::Surface *surface, SequenceFrame &frame, Common::Rect *subRect); + void seqDrawSpriteFrame(SpriteResource *spriteResource, SequenceFrame &frame, Common::Rect *subRect); + + void drawSprites(); + void updateRect(const Common::Rect &r); + void updateScreen(); + + void handleReqRemoveSequenceItem(); + void handleReqRemoveSequenceItems(); + void handleReqRemoveSpriteDrawItems(); + void fatUpdateFrame(); + void fatUpdate(); + void updatePlaySounds(); + +}; + +bool intersectRect(Common::Rect &intersectingRect, const Common::Rect &r1, const Common::Rect &r2); + +} // End of namespace Gnap + +#endif // GNAP_GAMESYS_H diff --git a/engines/gnap/gnap.cpp b/engines/gnap/gnap.cpp new file mode 100644 index 0000000000..8acc3eedae --- /dev/null +++ b/engines/gnap/gnap.cpp @@ -0,0 +1,1164 @@ +/* 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. + * + */ + +#include "graphics/cursorman.h" +#include "gnap/gnap.h" +#include "gnap/datarchive.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/sound.h" + +#include "common/config-manager.h" +#include "common/debug-channels.h" +#include "common/timer.h" + +#include "engines/util.h" + +namespace Gnap { + +static const int kCursors[] = { + LOOK_CURSOR, + GRAB_CURSOR, + TALK_CURSOR, + PLAT_CURSOR +}; + +static const int kDisabledCursors[] = { + NOLOOK_CURSOR, + NOGRAB_CURSOR, + NOTALK_CURSOR, + NOPLAT_CURSOR +}; + +static const char *kCursorNames[] = { + "LOOK_CURSOR", + "GRAB_CURSOR", + "TALK_CURSOR", + "PLAT_CURSOR", + "NOLOOK_CURSOR", + "NOGRAB_CURSOR", + "NOTALK_CURSOR", + "NOPLAT_CURSOR", + "EXIT_L_CURSOR", + "EXIT_R_CURSOR", + "EXIT_U_CURSOR", + "EXIT_D_CURSOR", + "EXIT_NE_CURSOR", + "EXIT_NW_CURSOR", + "EXIT_SE_CURSOR", + "EXIT_SW_CURSOR", + "WAIT_CURSOR" +}; + + +static const int kCursorSpriteIds[30] = { + 0x005, 0x008, 0x00A, 0x004, 0x009, 0x003, + 0x006, 0x007, 0x00D, 0x00F, 0x00B, 0x00C, + 0x019, 0x01C, 0x015, 0x014, 0x010, 0x01A, + 0x018, 0x013, 0x011, 0x012, 0x01B, 0x016, + 0x017, 0x01D, 0x01E, 0x01F, 0x76A, 0x76B +}; + +static const char *kSceneNames[] = { + "open", "pigpn", "truck", "creek", "mafrm", "frbrn", "inbrn", "crash", + "porch", "barbk", "kitch", "bar", "juke", "wash", "john", "jkbox", + "brawl", "stret", "frtoy", "intoy", "frgro", "park", "cash", "ingro", + "frcir", "booth", "circ", "outcl", "incln", "monk", "elcir", "beer", + "pig2", "trk2", "creek", "frbrn", "inbrn", "mafrm", "infrm", "efair", + "fair", "souv", "chick", "ship", "kiss", "disco", "boot", "can", + "can2", "drive", "tung", "puss", "space", "phone", "can3" +}; + +GnapEngine::GnapEngine(OSystem *syst, const ADGameDescription *gd) : + Engine(syst), _gameDescription(gd) { + + _random = new Common::RandomSource("gnap"); + DebugMan.addDebugChannel(kDebugBasic, "basic", "Basic debug level"); + + Engine::syncSoundSettings(); + _scene = nullptr; + _music = nullptr; + _tempThumbnail = nullptr; + + _wasSavegameLoaded = false; + for (int i = 0; i < kMaxTimers; ++i) + _savedTimers[i] = _timers[i] = 0; + + _isWaiting = false; + _sceneWaiting = false; + + _mousePos = Common::Point(0, 0); + _currGrabCursorX = _currGrabCursorY = 0; +} + +GnapEngine::~GnapEngine() { + delete _random; + delete _music; + delete _tempThumbnail; +} + +Common::Error GnapEngine::run() { + // Initialize the graphics mode to RGBA8888 + Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); + initGraphics(800, 600, true, &format); + + // We do not support color conversion yet + if (_system->getScreenFormat() != format) + return Common::kUnsupportedColorMode; + + _lastUpdateClock = 0; + + // >>>>> Variable initialization + _cursorIndex = -1; + _verbCursor = 1; + + _loadGameSlot = -1; + if (ConfMan.hasKey("save_slot")) + _loadGameSlot = ConfMan.getInt("save_slot"); + + invClear(); + clearFlags(); + + _grabCursorSprite = nullptr; + _newGrabCursorSpriteIndex = -1; + _backgroundSurface = nullptr; + _isStockDatLoaded = false; + _gameDone = false; + _isPaused = false; + _pauseSprite = nullptr; + + //////////////////////////////////////////////////////////////////////////// + + _exe = new Common::PEResources(); + if (!_exe->loadFromEXE("ufos.exe")) + error("Could not load ufos.exe"); + +#ifdef USE_FREETYPE2 + Common::SeekableReadStream *stream = _exe->getResource(Common::kPEFont, 2000); + _font = Graphics::loadTTFFont(*stream, 24); + if (!_font) + warning("Unable to load font"); +#else + _font = nullptr; +#endif + + _dat = new DatManager(); + _spriteCache = new SpriteCache(_dat); + _soundCache = new SoundCache(_dat); + _sequenceCache = new SequenceCache(_dat); + _gameSys = new GameSys(this); + _soundMan = new SoundMan(this); + _debugger = new Debugger(this); + _gnap = new PlayerGnap(this); + _plat = new PlayerPlat(this); + + _menuBackgroundSurface = nullptr; + + initGlobalSceneVars(); + mainLoop(); + + delete _plat; + delete _gnap; + delete _soundMan; + delete _gameSys; + delete _sequenceCache; + delete _soundCache; + delete _spriteCache; + delete _dat; + delete _debugger; + delete _font; + delete _exe; + + return Common::kNoError; +} + +void GnapEngine::updateEvents() { + Common::Event event; + + while (_eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + // Check for debugger + if (event.kbd.keycode == Common::KEYCODE_d && (event.kbd.flags & Common::KBD_CTRL)) { + // Attach to the debugger + _debugger->attach(); + _debugger->onFrame(); + } + + _keyPressState[event.kbd.keycode] = 1; + _keyDownState[event.kbd.keycode] = 1; + break; + case Common::EVENT_KEYUP: + _keyDownState[event.kbd.keycode] = 0; + break; + case Common::EVENT_MOUSEMOVE: + _mousePos = event.mouse; + break; + case Common::EVENT_LBUTTONUP: + _mouseButtonState._left = false; + break; + case Common::EVENT_LBUTTONDOWN: + _leftClickMouseX = event.mouse.x; + _leftClickMouseY = event.mouse.y; + _mouseButtonState._left = true; + _mouseClickState._left = true; + break; + case Common::EVENT_RBUTTONUP: + _mouseButtonState._right = false; + break; + case Common::EVENT_RBUTTONDOWN: + _mouseButtonState._right = true; + _mouseClickState._right = true; + break; + case Common::EVENT_QUIT: + quitGame(); + break; + default: + break; + } + } +} + +void GnapEngine::gameUpdateTick() { + updateEvents(); + + if (shouldQuit()) { + _gameDone = true; + _sceneDone = true; + } + + int currClock = _system->getMillis(); + if (currClock >= _lastUpdateClock + 66) { + _gameSys->fatUpdate(); + _gameSys->drawSprites(); + _gameSys->updateScreen(); + _gameSys->updatePlaySounds(); + _gameSys->_gameSysClock++; + updateTimers(); + _lastUpdateClock = currClock; + } + + _soundMan->update(); + _system->updateScreen(); + _system->delayMillis(5); +} + +void GnapEngine::saveTimers() { + for (int i = 0; i < kMaxTimers; ++i ) + _savedTimers[i] = _timers[i]; +} + +void GnapEngine::restoreTimers() { + for (int i = 0; i < kMaxTimers; ++i ) + _timers[i] = _savedTimers[i]; +} + +void GnapEngine::pauseGame() { + if (!_isPaused) { + saveTimers(); + hideCursor(); + setGrabCursorSprite(-1); + _pauseSprite = _gameSys->createSurface(0x1076C); + _gameSys->insertSpriteDrawItem(_pauseSprite, (800 - _pauseSprite->w) / 2, (600 - _pauseSprite->h) / 2, 356); + _lastUpdateClock = 0; + gameUpdateTick(); + playMidi("pause.mid"); + _isPaused = true; + } +} + +void GnapEngine::resumeGame() { + if (_isPaused) { + restoreTimers(); + _gameSys->removeSpriteDrawItem(_pauseSprite, 356); + _lastUpdateClock = 0; + gameUpdateTick(); + deleteSurface(&_pauseSprite); + stopMidi(); + _isPaused = false; + clearAllKeyStatus1(); + _mouseClickState._left = false; + _mouseClickState._right = false; + showCursor(); + _gameSys->_gameSysClock = 0; + _gameSys->_lastUpdateClock = 0; + } +} + +void GnapEngine::updatePause() { + while (_isPaused && !_gameDone) { + gameUpdateTick(); + if (isKeyStatus1(Common::KEYCODE_p)) { + clearKeyStatus1(Common::KEYCODE_p); + resumeGame(); + } + } +} + +int GnapEngine::getRandom(int max) { + return _random->getRandomNumber(max - 1); +} + +int GnapEngine::readSavegameDescription(int savegameNum, Common::String &description) { + description = Common::String::format("Savegame %d", savegameNum); + return 0; +} + +int GnapEngine::loadSavegame(int savegameNum) { + return 1; +} + +void GnapEngine::delayTicks(int val, int idx = 0, bool updateCursor = false) { + int startTick = _timers[idx]; + + _timers[idx] = val; + + while (_timers[idx] && !_gameDone) { + gameUpdateTick(); + + if (updateCursor) + updateGrabCursorSprite(0, 0); + } + + startTick -= _timers[idx]; + if (startTick < 0) + startTick = 0; + + _timers[idx] = startTick; +} + +void GnapEngine::delayTicksA(int val, int idx) { + delayTicks(val, idx); +} + +void GnapEngine::delayTicksCursor(int val) { + delayTicks(val, 0, true); +} + +void GnapEngine::setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags, + int16 walkX, int16 walkY) { + _hotspots[index]._rect = Common::Rect(x1, y1, x2, y2); + _hotspots[index]._flags = flags; + _hotspotsWalkPos[index] = Common::Point(walkX, walkY); +} + +int GnapEngine::getHotspotIndexAtPos(Common::Point pos) { + for (int i = 0; i < _hotspotsCount; ++i) { + if (!_hotspots[i].isFlag(SF_DISABLED) && _hotspots[i].isPointInside(pos)) + return i; + } + return -1; +} + +void GnapEngine::updateCursorByHotspot() { + if (!_isWaiting) { + int hotspotIndex = getHotspotIndexAtPos(_mousePos); + + if (_debugger->_showHotspotNumber) { + // NOTE This causes some display glitches + char t[256]; + sprintf(t, "hotspot = %2d", hotspotIndex); + if (!_font) + _gameSys->fillSurface(nullptr, 10, 10, 80, 16, 0, 0, 0); + else + _gameSys->fillSurface(nullptr, 8, 9, _font->getStringWidth(t) + 10, _font->getFontHeight() + 2, 0, 0, 0); + _gameSys->drawTextToSurface(nullptr, 10, 10, 255, 255, 255, t); + } + + if (hotspotIndex < 0) + setCursor(kDisabledCursors[_verbCursor]); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_L_CURSOR) + setCursor(EXIT_L_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_R_CURSOR) + setCursor(EXIT_R_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_U_CURSOR) + setCursor(EXIT_U_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_D_CURSOR) + setCursor(EXIT_D_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NE_CURSOR) + setCursor(EXIT_NE_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_NW_CURSOR) + setCursor(EXIT_NW_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SE_CURSOR) + setCursor(EXIT_SE_CURSOR); + else if (_hotspots[hotspotIndex]._flags & SF_EXIT_SW_CURSOR) + setCursor(EXIT_SW_CURSOR); + else if (_hotspots[hotspotIndex]._flags & (1 << _verbCursor)) + setCursor(kCursors[_verbCursor]); + else + setCursor(kDisabledCursors[_verbCursor]); + } + // Update platypus hotspot + _hotspots[0]._rect = Common::Rect(_gridMinX + 75 * _plat->_pos.x - 30, _gridMinY + 48 * _plat->_pos.y - 100 + , _gridMinX + 75 * _plat->_pos.x + 30, _gridMinY + 48 * _plat->_pos.y); +} + +int GnapEngine::getClickedHotspotId() { + int result = -1; + if (_isWaiting) + _mouseClickState._left = false; + else if (_mouseClickState._left) { + int hotspotIndex = getHotspotIndexAtPos(Common::Point(_leftClickMouseX, _leftClickMouseY)); + if (hotspotIndex >= 0) { + _mouseClickState._left = false; + _timers[3] = 300; + result = hotspotIndex; + } + } + return result; +} + +int GnapEngine::getInventoryItemSpriteNum(int index) { + return kCursorSpriteIds[index]; +} + +void GnapEngine::updateMouseCursor() { + if (_mouseClickState._right) { + // Switch through the verb cursors + _mouseClickState._right = false; + _timers[3] = 300; + _verbCursor = (_verbCursor + 1) % 4; + if (!isFlag(kGFPlatypus) && _verbCursor == PLAT_CURSOR && _cursorValue == 1) + _verbCursor = (_verbCursor + 1) % 4; + if (!_isWaiting) + setCursor(kDisabledCursors[_verbCursor]); + setGrabCursorSprite(-1); + } + if (_isWaiting && ((_gnap->_actionStatus < 0 && _plat->_actionStatus < 0) || _sceneWaiting)) { + setCursor(kDisabledCursors[_verbCursor]); + _isWaiting = false; + } else if (!_isWaiting && (_gnap->_actionStatus >= 0 || _plat->_actionStatus >= 0) && !_sceneWaiting) { + setCursor(WAIT_CURSOR); + _isWaiting = true; + } +} + +void GnapEngine::setVerbCursor(int verbCursor) { + _verbCursor = verbCursor; + if (!_isWaiting) + setCursor(kDisabledCursors[_verbCursor]); +} + +void GnapEngine::setCursor(int cursorIndex) { + if (_cursorIndex != cursorIndex) { + const char *cursorName = kCursorNames[cursorIndex]; + Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, Common::WinResourceID(cursorName)); + if (cursorGroup) { + Graphics::Cursor *cursor = cursorGroup->cursors[0].cursor; + CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), + cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor()); + CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256); + delete cursorGroup; + } + _cursorIndex = cursorIndex; + } +} + +void GnapEngine::showCursor() { + CursorMan.showMouse(true); +} + +void GnapEngine::hideCursor() { + CursorMan.showMouse(false); +} + +void GnapEngine::setGrabCursorSprite(int index) { + freeGrabCursorSprite(); + if (index >= 0) { + createGrabCursorSprite(makeRid(1, kCursorSpriteIds[index])); + setVerbCursor(GRAB_CURSOR); + } + _grabCursorSpriteIndex = index; +} + +void GnapEngine::createGrabCursorSprite(int spriteId) { + _grabCursorSprite = _gameSys->createSurface(spriteId); + _gameSys->insertSpriteDrawItem(_grabCursorSprite, + _mousePos.x - (_grabCursorSprite->w / 2), + _mousePos.y - (_grabCursorSprite->h / 2), + 300); + delayTicks(5); +} + +void GnapEngine::freeGrabCursorSprite() { + if (_grabCursorSprite) { + _gameSys->removeSpriteDrawItem(_grabCursorSprite, 300); + _gameSys->removeSpriteDrawItem(_grabCursorSprite, 301); + delayTicks(5); + deleteSurface(&_grabCursorSprite); + } +} + +void GnapEngine::updateGrabCursorSprite(int x, int y) { + if (_grabCursorSprite) { + int newGrabCursorX = _mousePos.x - (_grabCursorSprite->w / 2) - x; + int newGrabCursorY = _mousePos.y - (_grabCursorSprite->h / 2) - y; + if (_currGrabCursorX != newGrabCursorX || _currGrabCursorY != newGrabCursorY) { + _currGrabCursorX = newGrabCursorX; + _currGrabCursorY = newGrabCursorY; + Common::Rect rect(newGrabCursorX, newGrabCursorY, + newGrabCursorX + _grabCursorSprite->w, newGrabCursorY + _grabCursorSprite->h); + _gameSys->invalidateGrabCursorSprite(300, rect, _grabCursorSprite, _grabCursorSprite); + } + } +} + +void GnapEngine::invClear() { + _inventory = 0; +} + +void GnapEngine::invAdd(int itemId) { + _inventory |= (1 << itemId); +} + +void GnapEngine::invRemove(int itemId) { + _inventory &= ~(1 << itemId); +} + +bool GnapEngine::invHas(int itemId) { + return (_inventory & (1 << itemId)) != 0; +} + +void GnapEngine::clearFlags() { + _gameFlags = 0; +} + +void GnapEngine::setFlag(int num) { + _gameFlags |= (1 << num); +} + +void GnapEngine::clearFlag(int num) { + _gameFlags &= ~(1 << num); +} + +bool GnapEngine::isFlag(int num) { + return (_gameFlags & (1 << num)) != 0; +} + +Graphics::Surface *GnapEngine::addFullScreenSprite(int resourceId, int id) { + _fullScreenSpriteId = id; + _fullScreenSprite = _gameSys->createSurface(resourceId); + _gameSys->insertSpriteDrawItem(_fullScreenSprite, 0, 0, id); + return _fullScreenSprite; +} + +void GnapEngine::removeFullScreenSprite() { + _gameSys->removeSpriteDrawItem(_fullScreenSprite, _fullScreenSpriteId); + deleteSurface(&_fullScreenSprite); +} + +void GnapEngine::showFullScreenSprite(int resourceId) { + hideCursor(); + setGrabCursorSprite(-1); + addFullScreenSprite(resourceId, 256); + while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE) + && !isKeyStatus1(Common::KEYCODE_SPACE) && !isKeyStatus1(Common::KEYCODE_RETURN) && !_gameDone) { + gameUpdateTick(); + } + _mouseClickState._left = false; + clearKeyStatus1(Common::KEYCODE_ESCAPE); + clearKeyStatus1(Common::KEYCODE_RETURN); + clearKeyStatus1(Common::KEYCODE_SPACE); + removeFullScreenSprite(); + showCursor(); +} + +void GnapEngine::queueInsertDeviceIcon() { + _gameSys->insertSequence(0x10849, 20, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1); +} + +void GnapEngine::insertDeviceIconActive() { + _gameSys->insertSequence(0x1084A, 21, 0, 0, kSeqNone, 0, _deviceX1, _deviceY1); +} + +void GnapEngine::removeDeviceIconActive() { + _gameSys->removeSequence(0x1084A, 21, true); +} + +void GnapEngine::setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2) { + _deviceX1 = x1; + _deviceX2 = x2; + _deviceY1 = y1; + _deviceY2 = y2; + if (x1 == -1) + _deviceX1 = 730; + if (x2 == -1) + _deviceX2 = 780; + if (y1 == -1) + _deviceY1 = 14; + if (y2 == -1) + _deviceY2 = 79; + + _hotspots[hotspotIndex]._rect = Common::Rect(_deviceX1, _deviceY1, _deviceX2, _deviceY2); + _hotspots[hotspotIndex]._flags = SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; +} + +int GnapEngine::getSequenceTotalDuration(int resourceId) { + SequenceResource *sequenceResource = _sequenceCache->get(resourceId); + int maxValue = 0; + for (int i = 0; i < sequenceResource->_animationsCount; ++i) { + SequenceAnimation *animation = &sequenceResource->_animations[i]; + if (animation->_additionalDelay + animation->_maxTotalDuration > maxValue) + maxValue = animation->_additionalDelay + animation->_maxTotalDuration; + } + int totalDuration = maxValue + sequenceResource->_totalDuration; + _sequenceCache->release(resourceId); + return totalDuration; +} + +bool GnapEngine::isSoundPlaying(int resourceId) { + return _soundMan->isSoundPlaying(resourceId); +} + +void GnapEngine::playSound(int resourceId, bool looping) { + debugC(kDebugBasic, "playSound(%08X, %d)", resourceId, looping); + _soundMan->playSound(resourceId, looping); +} + +void GnapEngine::stopSound(int resourceId) { + _soundMan->stopSound(resourceId); +} + +void GnapEngine::setSoundVolume(int resourceId, int volume) { + _soundMan->setSoundVolume(resourceId, volume); +} + +void GnapEngine::updateTimers() { + for (int i = 0; i < kMaxTimers; ++i) + if (_timers[i] > 0) + --_timers[i]; +} + +void GnapEngine::initGameFlags(int num) { + invClear(); + invAdd(kItemMagazine); + switch (num) { + case 1: + setFlag(kGFPlatypusTalkingToAssistant); + break; + case 2: + clearFlags(); + break; + case 3: + invAdd(kItemDiceQuarterHole); + clearFlags(); + break; + case 4: + invAdd(kItemDiceQuarterHole); + invAdd(kItemHorn); + invAdd(kItemLightbulb); + clearFlags(); + setFlag(kGFPlatypus); + setFlag(kGFMudTaken); + setFlag(kGFNeedleTaken); + setFlag(kGFTwigTaken); + setFlag(kGFUnk04); + setFlag(kGFKeysTaken); + setFlag(kGFGrassTaken); + setFlag(kGFBarnPadlockOpen); + break; + } +} + +void GnapEngine::loadStockDat() { + if (!_isStockDatLoaded) { + _isStockDatLoaded = true; + _dat->open(1, "stock_n.dat"); + // The pre-loading of data is skipped as it's no longer required on modern hardware + } +} + +void GnapEngine::mainLoop() { + _newCursorValue = 1; + _cursorValue = -1; + _newSceneNum = 0; + _currentSceneNum = 55; + _prevSceneNum = 55; + invClear(); + clearFlags(); + _grabCursorSpriteIndex = -1; + _grabCursorSprite = nullptr; + + loadStockDat(); + + if (_loadGameSlot != -1) { + // Load a savegame + int slot = _loadGameSlot; + _loadGameSlot = -1; + loadGameState(slot); + _wasSavegameLoaded = true; + + showCursor(); + } + + while (!_gameDone) { + debugC(kDebugBasic, "New scene: %d", _newSceneNum); + + _prevSceneNum = _currentSceneNum; + _currentSceneNum = _newSceneNum; + + debugC(kDebugBasic, "GnapEngine::mainLoop() _prevSceneNum: %d; _currentSceneNum: %d", _prevSceneNum, _currentSceneNum); + + if (_newCursorValue != _cursorValue) { + debugC(kDebugBasic, "_newCursorValue: %d", _newCursorValue); + _cursorValue = _newCursorValue; + if (!_wasSavegameLoaded) + initGameFlags(_cursorValue); + } + + _sceneSavegameLoaded = _wasSavegameLoaded; + _wasSavegameLoaded = false; + + initScene(); + + runSceneLogic(); + afterScene(); + + _soundMan->stopAll(); + + // Force purge all resources + _sequenceCache->purge(true); + _soundCache->purge(true); + _spriteCache->purge(true); + } + + if (_backgroundSurface) + deleteSurface(&_backgroundSurface); + + _dat->close(1); +} + +void GnapEngine::initScene() { + Common::String datFilename; + + _isLeavingScene = false; + _sceneDone = false; + _newSceneNum = 55; + _gnap->_actionStatus = -1; + _plat->_actionStatus = -1; + _gnap->initBrainPulseRndValue(); + hideCursor(); + clearAllKeyStatus1(); + _mouseClickState._left = false; + _mouseClickState._right = false; + _sceneClickedHotspot = -1; + + datFilename = Common::String::format("%s_n.dat", kSceneNames[_currentSceneNum]); + + debugC(kDebugBasic, "GnapEngine::initScene() datFilename: %s", datFilename.c_str()); + + _dat->open(0, datFilename.c_str()); + + int backgroundId = initSceneLogic(); + + if (!_backgroundSurface) { + if (_currentSceneNum != 0) + _backgroundSurface = _gameSys->loadBitmap(makeRid(1, 0x8AA)); + else + _backgroundSurface = _gameSys->loadBitmap(makeRid(0, backgroundId)); + _gameSys->setBackgroundSurface(_backgroundSurface, 0, 500, 1, 1000); + } + + if (_currentSceneNum != 0 && _currentSceneNum != 16 && _currentSceneNum != 47 && + _currentSceneNum != 48 && _currentSceneNum != 54) { + _gameSys->drawBitmap(backgroundId); + } + + if ((_cursorValue == 4 && isFlag(kGFGnapControlsToyUFO)) || _currentSceneNum == 41) + playSound(makeRid(1, 0x8F6), true); + +} + +void GnapEngine::endSceneInit() { + showCursor(); + if (_newGrabCursorSpriteIndex >= 0) + setGrabCursorSprite(_newGrabCursorSpriteIndex); +} + +void GnapEngine::afterScene() { + if (_gameDone) + return; + + if (_newCursorValue == _cursorValue && _newSceneNum != 0 && _newSceneNum != 16 && + _newSceneNum != 47 && _newSceneNum != 48 && _newSceneNum != 54 && _newSceneNum != 49 && + _newSceneNum != 50 && _newSceneNum != 51 && _newSceneNum != 52) + _newGrabCursorSpriteIndex = _grabCursorSpriteIndex; + else + _newGrabCursorSpriteIndex = -1; + + setGrabCursorSprite(-1); + + _gameSys->requestClear2(false); + _gameSys->requestClear1(); + _gameSys->waitForUpdate(); + + _gameSys->requestClear2(false); + _gameSys->requestClear1(); + _gameSys->waitForUpdate(); + + screenEffect(0, 0, 0, 0); + + _dat->close(0); + + for (int animationIndex = 0; animationIndex < 12; ++animationIndex) + _gameSys->setAnimation(0, 0, animationIndex); + + clearKeyStatus1(Common::KEYCODE_p); + + _mouseClickState._left = false; + _mouseClickState._right = false; + +} + +void GnapEngine::checkGameKeys() { + if (isKeyStatus1(Common::KEYCODE_p)) { + clearKeyStatus1(Common::KEYCODE_p); + pauseGame(); + updatePause(); + } +} + +void GnapEngine::startSoundTimerA(int timerIndex) { + _soundTimerIndexA = timerIndex; + _timers[timerIndex] = getRandom(50) + 100; +} + +int GnapEngine::playSoundA() { + static const int kSoundIdsA[] = { + 0x93E, 0x93F, 0x941, 0x942, 0x943, 0x944, + 0x945, 0x946, 0x947, 0x948, 0x949 + }; + + int soundId = -1; + + if (!_timers[_soundTimerIndexA]) { + _timers[_soundTimerIndexA] = getRandom(50) + 100; + soundId = kSoundIdsA[getRandom(11)]; + playSound(soundId | 0x10000, false); + } + return soundId; +} + +void GnapEngine::startSoundTimerB(int timerIndex) { + _soundTimerIndexB = timerIndex; + _timers[timerIndex] = getRandom(50) + 150; +} + +int GnapEngine::playSoundB() { + static const int kSoundIdsB[] = { + 0x93D, 0x929, 0x92A, 0x92B, 0x92C, 0x92D, + 0x92E, 0x92F, 0x930, 0x931, 0x932, 0x933, + 0x934, 0x935, 0x936, 0x937, 0x938, 0x939, + 0x93A + }; + + int soundId = -1; + + if (!_timers[_soundTimerIndexB]) { + _timers[_soundTimerIndexB] = getRandom(50) + 150; + soundId = kSoundIdsB[getRandom(19)]; + playSound(soundId | 0x10000, false); + } + return soundId; +} + +void GnapEngine::startSoundTimerC(int timerIndex) { + _soundTimerIndexC = timerIndex; + _timers[timerIndex] = getRandom(50) + 150; +} + +int GnapEngine::playSoundC() { + static const int kSoundIdsC[] = { + 0x918, 0x91F, 0x920, 0x922, 0x923, 0x924, + 0x926 + }; + + int soundId = -1; + + if (!_timers[_soundTimerIndexC]) { + _timers[_soundTimerIndexC] = getRandom(50) + 150; + soundId = kSoundIdsC[getRandom(7)] ; + playSound(soundId | 0x10000, false); + } + return soundId; +} + +void GnapEngine::startIdleTimer(int timerIndex) { + _idleTimerIndex = timerIndex; + _timers[timerIndex] = 3000; +} + +void GnapEngine::updateIdleTimer() { + if (!_timers[_idleTimerIndex]) { + _timers[_idleTimerIndex] = 3000; + _gameSys->insertSequence(0x1088B, 255, 0, 0, kSeqNone, 0, 0, 75); + } +} + +void GnapEngine::screenEffect(int dir, byte r, byte g, byte b) { + if (dir == 1) { + for (int y = 300; y < 600 && !_gameDone; y += 50) { + _gameSys->fillSurface(nullptr, 0, y, 800, 50, r, g, b); + _gameSys->fillSurface(nullptr, 0, 549 - y + 1, 800, 50, r, g, b); + gameUpdateTick(); + _system->delayMillis(50); + } + } else { + for (int y = 0; y < 300 && !_gameDone; y += 50) { + _gameSys->fillSurface(nullptr, 0, y, 800, 50, r, g, b); + _gameSys->fillSurface(nullptr, 0, 549 - y + 1, 800, 50, r, g, b); + gameUpdateTick(); + _system->delayMillis(50); + } + } +} + +bool GnapEngine::isKeyStatus1(int key) { + return _keyPressState[key] != 0; +} + +bool GnapEngine::isKeyStatus2(int key) { + return _keyDownState[key] != 0; +} + +void GnapEngine::clearKeyStatus1(int key) { + _keyPressState[key] = 0; + _keyDownState[key] = 0; +} + +void GnapEngine::clearAllKeyStatus1() { + _keyStatus1[0] = 0; + _keyStatus1[1] = 0; + memset(_keyPressState, 0, sizeof(_keyPressState)); + memset(_keyDownState, 0, sizeof(_keyDownState)); +} + +void GnapEngine::deleteSurface(Graphics::Surface **surface) { + if (surface && *surface) { + (*surface)->free(); + delete *surface; + *surface = nullptr; + } +} + +bool GnapEngine::testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2) { + if (_mouseClickState._left && someStatus == _gnap->_actionStatus) { + _isLeavingScene = false; + _gameSys->setAnimation(0, 0, animationIndex); + _gnap->_actionStatus = -1; + _plat->_actionStatus = -1; + _gnap->walkTo(Common::Point(gridX1, gridY1), -1, -1, 1); + _plat->walkTo(Common::Point(gridX2, gridY2), -1, -1, 1); + _mouseClickState._left = false; + return true; + } + return false; +} + +void GnapEngine::doCallback(int callback) { + switch (callback) { + case 8: + case 10: + case 20: + _scene->updateAnimationsCb(); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// + +void GnapEngine::initGlobalSceneVars() { + // Shared by scenes 17 && 18 + _s18GarbageCanPos = 8; + + // Toy UFO + _toyUfoId = 0; + _toyUfoActionStatus = -1; + _toyUfoX = 0; + _toyUfoY = 50; +} + +void GnapEngine::playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3) { + setGrabCursorSprite(-1); + _gameSys->setAnimation(sequenceId2, _gnap->_id, 0); + _gameSys->insertSequence(sequenceId2, _gnap->_id, + makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id, + kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8)); + _gnap->_sequenceId = sequenceId2; + _gnap->_sequenceDatNum = 0; + while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone) + gameUpdateTick(); + hideCursor(); + addFullScreenSprite(fullScreenSpriteId, 255); + _gameSys->setAnimation(sequenceId1, 256, 0); + _gameSys->insertSequence(sequenceId1, 256, 0, 0, kSeqNone, 0, 0, 0); + while (_gameSys->getAnimationStatus(0) != 2 && !_gameDone) + gameUpdateTick(); + _gameSys->setAnimation(sequenceId3, _gnap->_id, 0); + _gameSys->insertSequence(sequenceId3, _gnap->_id, + makeRid(_gnap->_sequenceDatNum, _gnap->_sequenceId), _gnap->_id, + kSeqSyncWait, 0, 15 * (5 * _gnap->_pos.x - 25), 48 * (_gnap->_pos.y - 8)); + removeFullScreenSprite(); + showCursor(); + _gnap->_sequenceId = sequenceId3; +} + +void GnapEngine::toyUfoSetStatus(int flagNum) { + clearFlag(kGFUnk16); + clearFlag(kGFJointTaken); + clearFlag(kGFUnk18); + clearFlag(kGFGroceryStoreHatTaken); + setFlag(flagNum); +} + +int GnapEngine::toyUfoGetSequenceId() { + if (isFlag(kGFUnk16)) + return 0x84E; + if (isFlag(kGFJointTaken)) + return 0x84B; + if (isFlag(kGFUnk18)) + return 0x84D; + if (isFlag(kGFGroceryStoreHatTaken)) + return 0x84C; + return 0x84E; +} + +bool GnapEngine::toyUfoCheckTimer() { + if (!isFlag(kGFGnapControlsToyUFO) || isFlag(kGFUnk18) || _timers[9] || + _toyUfoSequenceId == 0x870 || _toyUfoSequenceId == 0x871 || _toyUfoSequenceId == 0x872 || _toyUfoSequenceId == 0x873) + return false; + _sceneDone = true; + _newSceneNum = 41; + return true; +} + +void GnapEngine::toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex) { + GridStruct flyNodes[34]; + + if (destX == -1) + destX = _leftClickMouseX; + + if (destY == -1) + destY = _leftClickMouseY; + + int clippedDestX = CLIP(destX, minX, maxX); + int clippedDestY = CLIP(destY, minY, maxY); + int dirX = 0, dirY = 0; // 0, -1 or 1 + + if (clippedDestX != _toyUfoX) + dirX = (clippedDestX - _toyUfoX) / ABS(clippedDestX - _toyUfoX); + + if (clippedDestY != _toyUfoY) + dirY = (clippedDestY - _toyUfoY) / ABS(clippedDestY - _toyUfoY); + + int deltaX = ABS(clippedDestX - _toyUfoX); + int deltaY = ABS(clippedDestY - _toyUfoY); + + int i = 0; + if (deltaY > deltaX) { + int flyDirYIncr = 32; + int gridDistY = deltaY / flyDirYIncr; + int curMove = 0; + while (curMove < deltaY && i < 34) { + if (gridDistY - 5 >= i) { + flyDirYIncr = MIN(36, 8 * i + 8); + } else { + flyDirYIncr = MAX(6, flyDirYIncr - 3); + } + curMove += flyDirYIncr; + flyNodes[i]._gridX1 = _toyUfoX + dirX * deltaX * curMove / deltaY; + flyNodes[i]._gridY1 = _toyUfoY + dirY * curMove; + ++i; + } + } else { + int flyDirXIncr = 36; + int gridDistX = deltaX / flyDirXIncr; + int curMove = 0; + while (curMove < deltaX && i < 34) { + if (gridDistX - 5 >= i) { + flyDirXIncr = MIN(38, 8 * i + 8); + } else { + flyDirXIncr = MAX(6, flyDirXIncr - 3); + } + curMove += flyDirXIncr; + flyNodes[i]._gridX1 = _toyUfoX + dirX * curMove; + flyNodes[i]._gridY1 = _toyUfoY + dirY * deltaY * curMove / deltaX; + ++i; + } + } + + int nodesCount = i - 1; + + _toyUfoX = clippedDestX; + _toyUfoY = clippedDestY; + + if (nodesCount > 0) { + int seqId = 0; + if (isFlag(kGFUnk16)) + seqId = 0x867; + else if (isFlag(kGFJointTaken)) + seqId = 0x84F; + else if (isFlag(kGFUnk18)) + seqId = 0x85F; + else if (isFlag(kGFGroceryStoreHatTaken)) + seqId = 0x857; + else + error("Unhandled flag in GnapEngine::toyUfoFlyTo(): 0x%x", _gameFlags); + flyNodes[0]._sequenceId = seqId; + flyNodes[0]._id = 0; + _gameSys->insertSequence(seqId | 0x10000, 0, + _toyUfoSequenceId | 0x10000, _toyUfoId, + kSeqSyncWait, 0, flyNodes[0]._gridX1 - 365, flyNodes[0]._gridY1 - 128); + for (i = 1; i < nodesCount; ++i) { + flyNodes[i]._sequenceId = seqId + (i % 8); + flyNodes[i]._id = i; + _gameSys->insertSequence(flyNodes[i]._sequenceId | 0x10000, flyNodes[i]._id, + flyNodes[i - 1]._sequenceId | 0x10000, flyNodes[i - 1]._id, + kSeqSyncWait, 0, + flyNodes[i]._gridX1 - 365, flyNodes[i]._gridY1 - 128); + } + + _toyUfoSequenceId = flyNodes[nodesCount - 1]._sequenceId; + _toyUfoId = flyNodes[nodesCount - 1]._id; + + if (animationIndex >= 0) + _gameSys->setAnimation(_toyUfoSequenceId | 0x10000, _toyUfoId, animationIndex); + + } +} + +void GnapEngine::playMidi(const char *name) { + if (_music) + return; + + _music = new MusicPlayer(name); + _music->playSMF(true); +} + +void GnapEngine::stopMidi() { + if (_music) { + _music->stop(); + delete _music; + _music = nullptr; + } +} +} // End of namespace Gnap diff --git a/engines/gnap/gnap.h b/engines/gnap/gnap.h new file mode 100644 index 0000000000..f5b7797914 --- /dev/null +++ b/engines/gnap/gnap.h @@ -0,0 +1,477 @@ +/* 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. + * + */ + +#ifndef GNAP_GNAP_H +#define GNAP_GNAP_H + +#include "common/array.h" +#include "common/events.h" +#include "common/file.h" +#include "common/memstream.h" +#include "common/random.h" +#include "common/savefile.h" +#include "common/serializer.h" +#include "common/str.h" +#include "common/substream.h" +#include "common/system.h" +#include "common/winexe.h" +#include "common/winexe_pe.h" +#include "engines/engine.h" +#include "graphics/pixelformat.h" +#include "graphics/wincursor.h" +#include "graphics/fontman.h" +#include "graphics/font.h" +#include "graphics/fonts/ttf.h" + +#include "gnap/debugger.h" +#include "gnap/resource.h" +#include "gnap/scenes/scenecore.h" +#include "gnap/character.h" +#include "gnap/music.h" + +struct ADGameDescription; + +namespace Gnap { + +class DatManager; +class SequenceResource; +class SpriteResource; +class GameSys; +class SoundMan; +class MusicPlayer; + +#define GNAP_SAVEGAME_VERSION 2 + +struct MouseButtonState { + bool _left; + bool _right; + MouseButtonState() : _left(false), _right(false) { + } +}; + +struct Hotspot { + Common::Rect _rect; + uint16 _flags; + + bool isPointInside(Common::Point pos) const { + return _rect.contains(pos); + } + + bool isFlag(uint16 flag) const { + return (_flags & flag) != 0; + } + + void clearRect() { + _rect = Common::Rect(0, 0, 0, 0); + } +}; + +const int kMaxTimers = 10; + +enum GnapDebugChannels { + kDebugBasic = 1 << 0, + kDebugMusic = 1 << 1 +}; + +enum { + SF_NONE = 0x0000, + SF_LOOK_CURSOR = 0x0001, + SF_GRAB_CURSOR = 0x0002, + SF_TALK_CURSOR = 0x0004, + SF_PLAT_CURSOR = 0x0008, + SF_DISABLED = 0x0010, + SF_WALKABLE = 0x0020, + SF_EXIT_L_CURSOR = 0x0040, + SF_EXIT_R_CURSOR = 0x0080, + SF_EXIT_U_CURSOR = 0x0100, + SF_EXIT_D_CURSOR = 0x0200, + SF_EXIT_NW_CURSOR = 0x0400, + SF_EXIT_NE_CURSOR = 0x0800, + SF_EXIT_SW_CURSOR = 0x1000, + SF_EXIT_SE_CURSOR = 0x2000 +}; + +enum { + LOOK_CURSOR = 0, + GRAB_CURSOR = 1, + TALK_CURSOR = 2, + PLAT_CURSOR = 3, + NOLOOK_CURSOR = 4, + NOGRAB_CURSOR = 5, + NOTALK_CURSOR = 6, + NOPLAT_CURSOR = 7, + EXIT_L_CURSOR = 8, + EXIT_R_CURSOR = 9, + EXIT_U_CURSOR = 10, + EXIT_D_CURSOR = 11, + EXIT_NE_CURSOR = 12, + EXIT_NW_CURSOR = 13, + EXIT_SE_CURSOR = 14, + EXIT_SW_CURSOR = 15, + WAIT_CURSOR = 16 +}; + +enum { + kGSPullOutDevice = 0, + kGSPullOutDeviceNonWorking = 1, + kGSIdle = 2, + kGSBrainPulsating = 3, + kGSImpossible = 4, + kGSScratchingHead = 5, + kGSDeflect = 6, + kGSUseDevice = 7, + kGSMoan1 = 8, + kGSMoan2 = 9 +}; + +enum { + kItemMagazine = 0, + kItemMud = 1, + kItemGrass = 2, + kItemDisguise = 3, + kItemNeedle = 4, + kItemTwig = 5, + kItemGas = 6, + kItemKeys = 7, + kItemDice = 8, + kItemTongs = 9, + kItemQuarter = 10, + kItemQuarterWithHole = 11, + kItemDiceQuarterHole = 12, + kItemWrench = 13, + kItemCowboyHat = 14, + kItemGroceryStoreHat = 15, + kItemBanana = 16, + kItemTickets = 17, + kItemPicture = 18, + kItemEmptyBucket = 19, + kItemBucketWithBeer = 20, + kItemBucketWithPill = 21, + kItemPill = 22, + kItemHorn = 23, + kItemJoint = 24, + kItemChickenBucket = 25, + kItemGum = 26, + kItemSpring = 27, + kItemLightbulb = 28, + kItemCereals = 29 +}; + +enum { + kGFPlatypus = 0, + kGFMudTaken = 1, + kGFNeedleTaken = 2, + kGFTwigTaken = 3, + kGFUnk04 = 4, + kGFKeysTaken = 5, + kGFGrassTaken = 6, + kGFBarnPadlockOpen = 7, + kGFTruckFilledWithGas = 8, + kGFTruckKeysUsed = 9, + kGFPlatypusDisguised = 10, + kGFSceneFlag1 = 11, + kGFGnapControlsToyUFO = 12, + kGFUnk13 = 13, // Tongue Fight Won? + kGFUnk14 = 14, + kGFSpringTaken = 15, + kGFUnk16 = 16, + kGFJointTaken = 17, + kGFUnk18 = 18, + kGFGroceryStoreHatTaken = 19, + kGFPictureTaken = 20, + kGFUnk21 = 21, + kGFUnk22 = 22, + kGFUnk23 = 23, + kGFUnk24 = 24, + kGFUnk25 = 25, + kGFPlatypusTalkingToAssistant = 26, + kGFUnk27 = 27, + kGFUnk28 = 28, + kGFGasTaken = 29, + kGFUnk30 = 30, + kGFUnk31 = 31 +}; + +struct GnapSavegameHeader { + uint8 _version; + Common::String _saveName; + Graphics::Surface *_thumbnail; + int _year, _month, _day; + int _hour, _minute; +}; + +class GnapEngine : public Engine { +protected: + Common::Error run(); + virtual bool hasFeature(EngineFeature f) const; +public: + GnapEngine(OSystem *syst, const ADGameDescription *gd); + ~GnapEngine(); +private: + const ADGameDescription *_gameDescription; + Graphics::PixelFormat _pixelFormat; + int _loadGameSlot; + +public: + Common::RandomSource *_random; + Common::PEResources *_exe; + + DatManager *_dat; + SpriteCache *_spriteCache; + SoundCache *_soundCache; + SequenceCache *_sequenceCache; + GameSys *_gameSys; + SoundMan *_soundMan; + Debugger *_debugger; + Scene *_scene; + PlayerGnap *_gnap; + PlayerPlat *_plat; + MusicPlayer *_music; + Graphics::Font *_font; + + Common::MemoryWriteStreamDynamic *_tempThumbnail; + + int _lastUpdateClock; + bool _gameDone; + + byte _keyPressState[512]; + byte _keyDownState[512]; + + bool _isPaused; + Graphics::Surface *_pauseSprite; + int _timers[kMaxTimers], _savedTimers[kMaxTimers]; + + MouseButtonState _mouseButtonState; + MouseButtonState _mouseClickState; + + uint32 _keyStatus1[2]; + + bool _sceneSavegameLoaded, _wasSavegameLoaded; + + Graphics::Surface *_backgroundSurface; + int _prevSceneNum, _currentSceneNum, _newSceneNum; + bool _sceneDone, _sceneWaiting; + + uint32 _inventory, _gameFlags; + + Hotspot _hotspots[20]; + Common::Point _hotspotsWalkPos[20]; + int _hotspotsCount; + int _sceneClickedHotspot; + + bool _isWaiting; + bool _isLeavingScene; + + bool _isStockDatLoaded; + + int _newCursorValue, _cursorValue; + + int _verbCursor, _cursorIndex; + Common::Point _mousePos; + int _leftClickMouseX, _leftClickMouseY; + + Graphics::Surface *_grabCursorSprite; + int _currGrabCursorX, _currGrabCursorY; + int _grabCursorSpriteIndex, _newGrabCursorSpriteIndex; + + Graphics::Surface *_fullScreenSprite; + int _fullScreenSpriteId; + + int _deviceX1, _deviceY1, _deviceX2, _deviceY2; + + int _soundTimerIndexA; + int _soundTimerIndexB; + int _soundTimerIndexC; + int _idleTimerIndex; + + void updateEvents(); + void gameUpdateTick(); + void saveTimers(); + void restoreTimers(); + + void pauseGame(); + void resumeGame(); + void updatePause(); + + int getRandom(int max); + + int readSavegameDescription(int savegameNum, Common::String &description); + int loadSavegame(int savegameNum); + Common::Error saveGameState(int slot, const Common::String &desc); + Common::Error loadGameState(int slot); + Common::String generateSaveName(int slot); + void synchronize(Common::Serializer &s); + void writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header); + static bool readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header); + + void delayTicks(int val, int idx, bool updateCursor); + void delayTicksA(int val, int idx); + void delayTicksCursor(int val); + + void setHotspot(int index, int16 x1, int16 y1, int16 x2, int16 y2, uint16 flags = 0, + int16 walkX = -1, int16 walkY = -1); + int getHotspotIndexAtPos(Common::Point pos); + void updateCursorByHotspot(); + int getClickedHotspotId(); + + int getInventoryItemSpriteNum(int index); + + void updateMouseCursor(); + void setVerbCursor(int verbCursor); + void setCursor(int cursorIndex); + void showCursor(); + void hideCursor(); + + void setGrabCursorSprite(int index); + void createGrabCursorSprite(int spriteId); + void freeGrabCursorSprite(); + void updateGrabCursorSprite(int x, int y); + + void invClear(); + void invAdd(int itemId); + void invRemove(int itemId); + bool invHas(int itemId); + + void clearFlags(); + void setFlag(int num); + void clearFlag(int num); + bool isFlag(int num); + + Graphics::Surface *addFullScreenSprite(int resourceId, int id); + void removeFullScreenSprite(); + void showFullScreenSprite(int resourceId); + + void queueInsertDeviceIcon(); + void insertDeviceIconActive(); + void removeDeviceIconActive(); + void setDeviceHotspot(int hotspotIndex, int x1, int y1, int x2, int y2); + + int getSequenceTotalDuration(int resourceId); + + bool isSoundPlaying(int resourceId); + void playSound(int resourceId, bool looping); + void stopSound(int resourceId); + void setSoundVolume(int resourceId, int volume); + + void updateTimers(); + + void initGameFlags(int num); + void loadStockDat(); + + void mainLoop(); + void initScene(); + void endSceneInit(); + void afterScene(); + + int initSceneLogic(); + void runSceneLogic(); + + void checkGameKeys(); + + void startSoundTimerA(int timerIndex); + int playSoundA(); + void startSoundTimerB(int timerIndex); + int playSoundB(); + void startSoundTimerC(int timerIndex); + int playSoundC(); + void startIdleTimer(int timerIndex); + void updateIdleTimer(); + + void screenEffect(int dir, byte r, byte g, byte b); + + bool isKeyStatus1(int key); + bool isKeyStatus2(int key); + void clearKeyStatus1(int key); + void clearAllKeyStatus1(); + + void deleteSurface(Graphics::Surface **surface); + + // Menu + int _menuStatus; + int _menuSpritesIndex; + bool _menuDone; + Graphics::Surface *_menuBackgroundSurface; + Graphics::Surface *_menuQuitQuerySprite; + Graphics::Surface *_largeSprite; + Graphics::Surface *_menuSaveLoadSprite; + Graphics::Surface *_menuSprite2; + Graphics::Surface *_menuSprite1; + char _savegameFilenames[7][30]; + Graphics::Surface *_savegameSprites[7]; + Graphics::Surface *_spriteHandle; + Graphics::Surface *_cursorSprite; + int _menuInventoryIndices[30]; + Graphics::Surface *_menuInventorySprites[30]; + int _savegameIndex; + void createMenuSprite(); + void freeMenuSprite(); + void initMenuHotspots1(); + void initMenuHotspots2(); + void initMenuQuitQueryHotspots(); + void initSaveLoadHotspots(); + void drawInventoryFrames(); + void insertInventorySprites(); + void removeInventorySprites(); + void runMenu(); + void updateMenuStatusInventory(); + void updateMenuStatusMainMenu(); + void updateMenuStatusSaveGame(); + void updateMenuStatusLoadGame(); + void updateMenuStatusQueryQuit(); + + // Grid common + int _gridMinX, _gridMinY; + int _gridMaxX, _gridMaxY; + bool isPointBlocked(int gridX, int gridY); + bool isPointBlocked(Common::Point gridPos); + void initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY); + bool testWalk(int animationIndex, int someStatus, int gridX1, int gridY1, int gridX2, int gridY2); + + // Gnap + void doCallback(int callback); + + // Scenes + int _toyUfoNextSequenceId, _toyUfoSequenceId; + int _toyUfoId; + int _toyUfoActionStatus; + int _toyUfoX; + int _toyUfoY; + + void initGlobalSceneVars(); + void playSequences(int fullScreenSpriteId, int sequenceId1, int sequenceId2, int sequenceId3); + + // Shared by scenes 17 & 18 + int _s18GarbageCanPos; + + // Scene 4x + void toyUfoSetStatus(int flagNum); + int toyUfoGetSequenceId(); + bool toyUfoCheckTimer(); + void toyUfoFlyTo(int destX, int destY, int minX, int maxX, int minY, int maxY, int animationIndex); + + void playMidi(const char *name); + void stopMidi(); +}; + +} // End of namespace Gnap + +#endif // GNAP_GNAP_H diff --git a/engines/gnap/grid.cpp b/engines/gnap/grid.cpp new file mode 100644 index 0000000000..aa6da71395 --- /dev/null +++ b/engines/gnap/grid.cpp @@ -0,0 +1,995 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/datarchive.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" + +namespace Gnap { + +void GnapEngine::initSceneGrid(int gridMinX, int gridMinY, int gridMaxX, int gridMaxY) { + _gridMinX = gridMinX; + _gridMinY = gridMinY; + _gridMaxX = gridMaxX; + _gridMaxY = gridMaxY; + _gnap->_gridX = 410 - gridMinX; + _gnap->_gridY = 450 - gridMinY; + _plat->_gridX = 396 - gridMinX; + _plat->_gridY = 347 - gridMinY; +} + +bool GnapEngine::isPointBlocked(Common::Point gridPos) { + return isPointBlocked(gridPos.x, gridPos.y); +} + +bool GnapEngine::isPointBlocked(int gridX, int gridY) { + + if (gridX < 0 || gridX >= _gridMaxX || gridY < 0 || gridY >= _gridMaxY) + return true; + + if ((_gnap->_pos == Common::Point(gridX, gridY)) || (_plat->_pos == Common::Point(gridX, gridY))) + return true; + + Common::Point pos = Common::Point(_gridMinX + 75 * gridX, _gridMinY + 48 * gridY); + + for (int i = 0; i < _hotspotsCount; ++i) { + if (_hotspots[i].isPointInside(pos) && !(_hotspots[i]._flags & SF_WALKABLE)) + return true; + } + + return false; +} + +/******************************************************************************/ + +int PlayerGnap::getWalkStopSequenceId(int deltaX, int deltaY) { + static const int gnapWalkStopSequenceIds[9] = { + 0x7BC, 0x7BA, 0x7BA, + 0x7BC, 0x000, 0x7BA, + 0x7BB, 0x7B9, 0x7B9 + }; + + int id = 3 * (deltaX + 1) + deltaY + 1; + assert (id >= 0 && id < 9 ); + return gnapWalkStopSequenceIds[id]; +} + +Facing PlayerGnap::getWalkFacing(int deltaX, int deltaY) { + static const Facing gnapWalkFacings[9] = { + kDirUpLeft, kDirBottomLeft, kDirBottomLeft, + kDirUpLeft, kDirIdleLeft, kDirBottomLeft, + kDirUpRight, kDirBottomRight, kDirBottomRight + }; + + int id = 3 * (deltaX + 1) + deltaY + 1; + assert (id >= 0 && id < 9 ); + return gnapWalkFacings[id]; +} + +bool PlayerGnap::findPath1(int gridX, int gridY, int index) { + _walkNodesCount = index; + _walkDirXIncr = 0; + _walkDirYIncr = 0; + _walkDeltaX = ABS(_walkDestX - gridX); + _walkDeltaY = ABS(_walkDestY - gridY); + + if (_walkDeltaX) + _walkDirX = (_walkDestX - gridX) / _walkDeltaX; + else + _walkDirX = 0; + + if (_walkDeltaY) + _walkDirY = (_walkDestY - gridY) / _walkDeltaY; + else + _walkDirY = 0; + + while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirXIncr; + ++_walkDirYIncr; + } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) { + if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else + return false; + } else { + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else + return false; + } + ++_walkNodesCount; + } + + while (_walkDirXIncr < _walkDeltaX) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = _walkDestY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = _walkDestX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else + return false; + } + + return true; +} + +bool PlayerGnap::findPath2(int gridX, int gridY, int index) { + _walkNodesCount = index; + _walkDirXIncr = 0; + _walkDirYIncr = 0; + _walkDeltaX = ABS(_walkDestX - gridX); + _walkDeltaY = ABS(_walkDestY - gridY); + + if (_walkDeltaX) + _walkDirX = (_walkDestX - gridX) / _walkDeltaX; + else + _walkDirX = 0; + + if (_walkDeltaY) + _walkDirY = (_walkDestY - gridY) / _walkDeltaY; + else + _walkDirY = 0; + + while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) { + _walkNodes[_walkNodesCount]._gridX1 = gridX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirXIncr; + ++_walkDirYIncr; + } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) { + if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else + return false; + } else { + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else + return false; + } + ++_walkNodesCount; + } + + while (_walkDirXIncr < _walkDeltaX) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = _walkDestY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = _walkDestX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else + return false; + } + + return true; +} + +bool PlayerGnap::findPath3(int gridX, int gridY) { + int gridIncr = 1; + bool done = false; + + while (!done && gridIncr < _vm->_gridMaxX) { + if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath1(gridX + gridIncr, gridY, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX + i; + _walkNodes[i]._gridY1 = gridY; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath1(gridX - gridIncr, gridY, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX - i; + _walkNodes[i]._gridY1 = gridY; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath1(gridX, gridY + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX; + _walkNodes[i]._gridY1 = gridY + i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath1(gridX, gridY - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX; + _walkNodes[i]._gridY1 = gridY - i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath1(gridX + gridIncr, gridY + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX + i; + _walkNodes[i]._gridY1 = gridY + i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath1(gridX - gridIncr, gridY + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX - i; + _walkNodes[i]._gridY1 = gridY + i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath1(gridX + gridIncr, gridY - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX + i; + _walkNodes[i]._gridY1 = gridY - i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath1(gridX - gridIncr, gridY - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX - i; + _walkNodes[i]._gridY1 = gridY - i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX + gridIncr, gridY) && findPath2(gridX + gridIncr, gridY, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX + i; + _walkNodes[i]._gridY1 = gridY; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX - gridIncr, gridY) && findPath2(gridX - gridIncr, gridY, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX - i; + _walkNodes[i]._gridY1 = gridY; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX, gridY + gridIncr) && findPath2(gridX, gridY + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX; + _walkNodes[i]._gridY1 = gridY + i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX, gridY - gridIncr) && findPath2(gridX, gridY - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX; + _walkNodes[i]._gridY1 = gridY - i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX + gridIncr, gridY + gridIncr) && findPath2(gridX + gridIncr, gridY + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX + i; + _walkNodes[i]._gridY1 = gridY + i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX - gridIncr, gridY + gridIncr) && findPath2(gridX - gridIncr, gridY + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX - i; + _walkNodes[i]._gridY1 = gridY + i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX + gridIncr, gridY - gridIncr) && findPath2(gridX + gridIncr, gridY - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX + i; + _walkNodes[i]._gridY1 = gridY - i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(gridX - gridIncr, gridY - gridIncr) && findPath2(gridX - gridIncr, gridY - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = gridX - i; + _walkNodes[i]._gridY1 = gridY - i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + ++gridIncr; + } + + return done; +} + +bool PlayerGnap::findPath4(int gridX, int gridY) { + bool result = false; + + _walkNodesCount = 0; + _walkDirXIncr = 0; + _walkDirYIncr = 0; + _walkDeltaX = ABS(_walkDestX - gridX); + _walkDeltaY = ABS(_walkDestY - gridY); + + if (_walkDeltaX) + _walkDirX = (_walkDestX - gridX) / _walkDeltaX; + else + _walkDirX = 0; + + if (_walkDeltaY) + _walkDirY = (_walkDestY - gridY) / _walkDeltaY; + else + _walkDirY = 0; + + while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirXIncr; + ++_walkDirYIncr; + } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) { + if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else { + _walkDeltaX = _walkDirXIncr; + _walkDeltaY = _walkDirYIncr; + --_walkNodesCount; + } + } else { + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else { + _walkDeltaX = _walkDirXIncr; + _walkDeltaY = _walkDirYIncr; + --_walkNodesCount; + } + } + ++_walkNodesCount; + } + + while (_walkDirXIncr < _walkDeltaX) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = _walkDestY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else { + _walkDeltaX = _walkDirXIncr; + } + } + + while (_walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = _walkDestX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else { + _walkDeltaY = _walkDirYIncr; + } + } + + if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) { + _walkDestX = gridX + _walkDirX * _walkDirXIncr; + _walkDestY = gridY + _walkDirY * _walkDirYIncr; + result = false; + } else { + result = true; + } + + return result; +} + +/******************************************************************************/ + +bool PlayerPlat::findPath1(int gridX, int gridY, int index) { + _walkNodesCount = index; + _walkDirXIncr = 0; + _walkDirYIncr = 0; + _walkDeltaX = ABS(_walkDestX - gridX); + _walkDeltaY = ABS(_walkDestY - gridY); + + if (_walkDeltaX) + _walkDirX = (_walkDestX - gridX) / _walkDeltaX; + else + _walkDirX = 0; + + if (_walkDeltaY) + _walkDirY = (_walkDestY - gridY) / _walkDeltaY; + else + _walkDirY = 0; + + while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirXIncr; + ++_walkDirYIncr; + } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) { + if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else + return false; + } else { + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else + return false; + } + ++_walkNodesCount; + } + + while (_walkDirXIncr < _walkDeltaX) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = _walkDestY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = _walkDestX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else + return false; + } + + return true; +} + +bool PlayerPlat::findPath2(int gridX, int gridY, int index) { + _walkNodesCount = index; + _walkDirXIncr = 0; + _walkDirYIncr = 0; + _walkDeltaX = ABS(_walkDestX - gridX); + _walkDeltaY = ABS(_walkDestY - gridY); + + if (_walkDeltaX) + _walkDirX = (_walkDestX - gridX) / _walkDeltaX; + else + _walkDirX = 0; + + if (_walkDeltaY) + _walkDirY = (_walkDestY - gridY) / _walkDeltaY; + else + _walkDirY = 0; + + while (_walkDeltaY < _walkDeltaX - _walkDirXIncr) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, gridY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDeltaX < _walkDeltaY - _walkDirYIncr) { + _walkNodes[_walkNodesCount]._gridX1 = gridX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(gridX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirXIncr; + ++_walkDirYIncr; + } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) { + if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else + return false; + } else { + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else + return false; + } + ++_walkNodesCount; + } + + while (_walkDirXIncr < _walkDeltaX) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = _walkDestY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else + return false; + } + + while (_walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = _walkDestX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else + return false; + } + + return true; +} + +bool PlayerPlat::findPath3(int gridX, int gridY) { + int gridIncr = 1; + bool done = false; + + while (!done && gridIncr < _vm->_gridMaxX) { + if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath1(_pos.x + gridIncr, _pos.y, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x + i; + _walkNodes[i]._gridY1 = _pos.y; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath1(_pos.x - gridIncr, _pos.y, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x - i; + _walkNodes[i]._gridY1 = _pos.y; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath1(_pos.x, _pos.y + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x; + _walkNodes[i]._gridY1 = _pos.y + i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath1(_pos.x, _pos.y - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x; + _walkNodes[i]._gridY1 = _pos.y - i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath1(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x + i; + _walkNodes[i]._gridY1 = _pos.y + i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath1(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x - i; + _walkNodes[i]._gridY1 = _pos.y + i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath1(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x + i; + _walkNodes[i]._gridY1 = _pos.y - i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath1(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x - i; + _walkNodes[i]._gridY1 = _pos.y - i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y) && findPath2(_pos.x + gridIncr, _pos.y, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x + i; + _walkNodes[i]._gridY1 = _pos.y; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y) && findPath2(_pos.x - gridIncr, _pos.y, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x - i; + _walkNodes[i]._gridY1 = _pos.y; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 0; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x, _pos.y + gridIncr) && findPath2(_pos.x, _pos.y + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x; + _walkNodes[i]._gridY1 = _pos.y + i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x, _pos.y - gridIncr) && findPath2(_pos.x, _pos.y - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x; + _walkNodes[i]._gridY1 = _pos.y - i; + _walkNodes[i]._deltaX = 0; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y + gridIncr) && findPath2(_pos.x + gridIncr, _pos.y + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x + i; + _walkNodes[i]._gridY1 = _pos.y + i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y + gridIncr) && findPath2(_pos.x - gridIncr, _pos.y + gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x - i; + _walkNodes[i]._gridY1 = _pos.y + i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = 1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x + gridIncr, _pos.y - gridIncr) && findPath2(_pos.x + gridIncr, _pos.y - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x + i; + _walkNodes[i]._gridY1 = _pos.y - i; + _walkNodes[i]._deltaX = 1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + if (!_vm->isPointBlocked(_pos.x - gridIncr, _pos.y - gridIncr) && findPath2(_pos.x - gridIncr, _pos.y - gridIncr, gridIncr)) { + for (int i = 0; i < gridIncr; ++i) { + _walkNodes[i]._gridX1 = _pos.x - i; + _walkNodes[i]._gridY1 = _pos.y - i; + _walkNodes[i]._deltaX = -1; + _walkNodes[i]._deltaY = -1; + } + done = true; + break; + } + ++gridIncr; + } + + return done; +} + +bool PlayerPlat::findPath4(int gridX, int gridY) { + bool result = false; + + _walkNodesCount = 0; + _walkDirXIncr = 0; + _walkDirYIncr = 0; + _walkDeltaX = ABS(_walkDestX - gridX); + _walkDeltaY = ABS(_walkDestY - gridY); + + if (_walkDeltaX) + _walkDirX = (_walkDestX - gridX) / _walkDeltaX; + else + _walkDirX = 0; + + if (_walkDeltaY) + _walkDirY = (_walkDestY - gridY) / _walkDeltaY; + else + _walkDirY = 0; + + while (_walkDirXIncr < _walkDeltaX && _walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirXIncr; + ++_walkDirYIncr; + } else if (_walkDeltaY - _walkDirYIncr > _walkDeltaX - _walkDirXIncr) { + if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else { + _walkDeltaX = _walkDirXIncr; + _walkDeltaY = _walkDirYIncr; + --_walkNodesCount; + } + } else { + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + } else if (!_vm->isPointBlocked(_walkNodes[_walkNodesCount]._gridX1, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + } else { + _walkDeltaX = _walkDirXIncr; + _walkDeltaY = _walkDirYIncr; + --_walkNodesCount; + } + } + ++_walkNodesCount; + } + + while (_walkDirXIncr < _walkDeltaX) { + _walkNodes[_walkNodesCount]._gridX1 = gridX + _walkDirX * _walkDirXIncr; + _walkNodes[_walkNodesCount]._gridY1 = _walkDestY; + if (!_vm->isPointBlocked(_walkDirX + _walkNodes[_walkNodesCount]._gridX1, _walkDestY)) { + _walkNodes[_walkNodesCount]._deltaX = _walkDirX; + _walkNodes[_walkNodesCount]._deltaY = 0; + ++_walkDirXIncr; + ++_walkNodesCount; + } else { + _walkDeltaX = _walkDirXIncr; + } + } + + while (_walkDirYIncr < _walkDeltaY) { + _walkNodes[_walkNodesCount]._gridX1 = _walkDestX; + _walkNodes[_walkNodesCount]._gridY1 = gridY + _walkDirY * _walkDirYIncr; + if (!_vm->isPointBlocked(_walkDestX, _walkDirY + _walkNodes[_walkNodesCount]._gridY1)) { + _walkNodes[_walkNodesCount]._deltaX = 0; + _walkNodes[_walkNodesCount]._deltaY = _walkDirY; + ++_walkDirYIncr; + ++_walkNodesCount; + } else { + _walkDeltaY = _walkDirYIncr; + } + } + + if (gridX + _walkDirX * _walkDirXIncr != _walkDestX || gridY + _walkDirY * _walkDirYIncr != _walkDestY) { + _walkDestX = gridX + _walkDirX * _walkDirXIncr; + _walkDestY = gridY + _walkDirY * _walkDirYIncr; + result = false; + } else { + result = true; + } + + return result; +} + +void PlayerPlat::makeRoom() { + int rndGridX, rndGridY; + do { + rndGridY = _vm->getRandom(_vm->_gridMaxY); + rndGridX = _vm->getRandom(_vm->_gridMaxX); + } while (ABS(rndGridX - _pos.x) > 4 || ABS(rndGridY - _pos.y) > 3 || + _vm->isPointBlocked(rndGridX, rndGridY)); + walkTo(Common::Point(rndGridX, rndGridY), -1, -1, 1); +} + +} // End of namespace Gnap diff --git a/engines/gnap/menu.cpp b/engines/gnap/menu.cpp new file mode 100644 index 0000000000..2bfe7300df --- /dev/null +++ b/engines/gnap/menu.cpp @@ -0,0 +1,888 @@ +/* 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. + * + */ + +#include "common/config-manager.h" +#include "common/savefile.h" +#include "common/translation.h" + +#include "gui/saveload.h" +#include "graphics/thumbnail.h" + +#include "gnap/gnap.h" +#include "gnap/datarchive.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" + +namespace Gnap { + +void GnapEngine::createMenuSprite() { + _menuBackgroundSurface = _gameSys->createSurface(0x10002); +} + +void GnapEngine::freeMenuSprite() { + _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260); + delayTicksCursor(5); + deleteSurface(&_menuBackgroundSurface); +} + +void GnapEngine::initMenuHotspots1() { + int curId = 0; + + for (int i = 0; i < 3; ++i) { + int top = 74 * i + 69; + for (int j = 0; j < 3; ++j) { + int left = 87 * j + 262; + _hotspots[curId]._rect = Common::Rect(left, top, left + 79, top + 66); + _hotspots[curId]._flags = SF_NONE; + ++curId; + } + } + + _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + + ++curId; + _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580); + _hotspots[curId]._flags = SF_NONE; + + ++curId; + _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599); + _hotspots[curId]._flags = SF_NONE; + + _hotspotsCount = curId + 1; +} + +void GnapEngine::initMenuHotspots2() { + int curId = 0; + + for (int i = 0; i < 4; ++i) { + int top = 48 * i + 85; + _hotspots[curId]._rect = Common::Rect(312, top, 465, top + 37); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + ++curId; + } + + _hotspots[curId]._rect = Common::Rect(500, 72, 527, 99); + _hotspots[curId]._flags = SF_DISABLED; + + ++curId; + _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + + ++curId; + _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580); + _hotspots[curId]._flags = SF_NONE; + + ++curId; + _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599); + _hotspots[curId]._flags = SF_NONE; + + _hotspotsCount = curId + 1; +} + +void GnapEngine::initMenuQuitQueryHotspots() { + _hotspots[0]._rect = Common::Rect(311, 197, 377, 237); + _hotspots[0]._flags = SF_GRAB_CURSOR; + + _hotspots[1]._rect = Common::Rect(403, 197, 469, 237); + _hotspots[1]._flags = SF_GRAB_CURSOR; + + _hotspots[2]._rect = Common::Rect(330, 350, 430, 460); + _hotspots[2]._flags = SF_GRAB_CURSOR; + + _hotspots[3]._rect = Common::Rect(180, 15, 620, 580); + _hotspots[3]._flags = SF_NONE; + + _hotspots[4]._rect = Common::Rect(0, 0, 799, 599); + _hotspots[4]._flags = SF_NONE; + + _hotspotsCount = 5; +} + +void GnapEngine::initSaveLoadHotspots() { + int curId = 0; + + for (int i = 0; i < 7; ++i ) { + int top = 31 * i + 74; + _hotspots[curId]._rect = Common::Rect(288, top, 379, top + 22); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + ++curId; + } + + if (_menuStatus == 2) { + _hotspots[curId]._rect = Common::Rect(416, 160, 499, 188); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + ++curId; + } + + _hotspots[curId]._rect = Common::Rect(416, 213, 499, 241); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + + ++curId; + _hotspots[curId]._rect = Common::Rect(330, 350, 430, 460); + _hotspots[curId]._flags = SF_GRAB_CURSOR; + + ++curId; + _hotspots[curId]._rect = Common::Rect(180, 15, 620, 580); + _hotspots[curId]._flags = SF_NONE; + + ++curId; + _hotspots[curId]._rect = Common::Rect(0, 0, 799, 599); + _hotspots[curId]._flags = SF_NONE; + + _hotspotsCount = curId + 1; +} + +void GnapEngine::drawInventoryFrames() { + for (int i = 0; i < 9; ++i) + _gameSys->drawSpriteToSurface(_menuBackgroundSurface, _hotspots[i]._rect.left - 93, _hotspots[i]._rect.top, 0x10001); +} + +void GnapEngine::insertInventorySprites() { + for (int i = 0; i < 9; ++i) { + _menuInventoryIndices[i] = -1; + _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261); + _menuInventorySprites[i] = 0; + } + + _menuSpritesIndex = 0; + + for (int index = 0; index < 30 && _menuSpritesIndex < 9; ++index) { + if (invHas(index)) { + _gameSys->drawSpriteToSurface(_menuBackgroundSurface, + _hotspots[_menuSpritesIndex]._rect.left - 93, _hotspots[_menuSpritesIndex]._rect.top, 0x10000); + _menuInventorySprites[_menuSpritesIndex] = _gameSys->createSurface(getInventoryItemSpriteNum(index) | 0x10000); + if (index != _grabCursorSpriteIndex) { + _menuInventoryIndices[_menuSpritesIndex] = index; + _gameSys->insertSpriteDrawItem(_menuInventorySprites[_menuSpritesIndex], + _hotspots[_menuSpritesIndex]._rect.left + ((79 - _menuInventorySprites[_menuSpritesIndex]->w) / 2), + _hotspots[_menuSpritesIndex]._rect.top + ((66 - _menuInventorySprites[_menuSpritesIndex]->h) / 2), + 261); + } + _hotspots[_menuSpritesIndex]._flags = SF_GRAB_CURSOR; + ++_menuSpritesIndex; + } + } +} + +void GnapEngine::removeInventorySprites() { + for (int i = 0; i < _menuSpritesIndex; ++i) + if (_menuInventorySprites[i]) + _gameSys->removeSpriteDrawItem(_menuInventorySprites[i], 261); + delayTicksCursor(5); + for (int j = 0; j < _menuSpritesIndex; ++j) { + if (_menuInventorySprites[j]) { + deleteSurface(&_menuInventorySprites[j]); + _menuInventorySprites[j] = 0; + _menuInventoryIndices[j] = -1; + } + } + _menuSpritesIndex = 0; +} + +void GnapEngine::runMenu() { + _spriteHandle = nullptr; + _cursorSprite = nullptr; + _menuSprite1 = nullptr; + _menuSprite2 = nullptr; + _menuSaveLoadSprite = nullptr; + _menuQuitQuerySprite = nullptr; + + _menuStatus = 0; + _menuDone = false; + + delete _tempThumbnail; + _tempThumbnail = new Common::MemoryWriteStreamDynamic; + Graphics::saveThumbnail(*_tempThumbnail); + + createMenuSprite(); + insertDeviceIconActive(); + + for (int i = 0; i < 7; ++i) { + _savegameFilenames[i][0] = 0; + _savegameSprites[i] = nullptr; + } + + if (_menuStatus == 0) { + invAdd(kItemMagazine); + setGrabCursorSprite(-1); + hideCursor(); + initMenuHotspots1(); + drawInventoryFrames(); + insertInventorySprites(); + _gameSys->insertSpriteDrawItem(_menuBackgroundSurface, 93, 0, 260); + showCursor(); + // SetCursorPos(400, 300); + setVerbCursor(GRAB_CURSOR); + // pollMessages(); + } + + _timers[2] = 10; + + while (!isKeyStatus1(Common::KEYCODE_BACKSPACE) && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !_sceneDone && !_menuDone) { + updateCursorByHotspot(); + + switch (_menuStatus) { + case 0: + updateMenuStatusInventory(); + break; + case 1: + updateMenuStatusMainMenu(); + break; + case 2: + updateMenuStatusSaveGame(); + break; + case 3: + updateMenuStatusLoadGame(); + break; + case 4: + updateMenuStatusQueryQuit(); + break; + } + + gameUpdateTick(); + } + + removeInventorySprites(); + if (_spriteHandle) + _gameSys->removeSpriteDrawItem(_spriteHandle, 261); + if (_menuSprite1) + _gameSys->removeSpriteDrawItem(_menuSprite1, 262); + if (_menuSprite2) + _gameSys->removeSpriteDrawItem(_menuSprite2, 262); + for (int i = 0; i < 7; ++i) + if (_savegameSprites[i]) + _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263); + if (_cursorSprite) + _gameSys->removeSpriteDrawItem(_cursorSprite, 264); + if (_menuSaveLoadSprite) + _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262); + if (_menuQuitQuerySprite) + _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262); + if (_menuBackgroundSurface) + _gameSys->removeSpriteDrawItem(_menuBackgroundSurface, 260); + + delayTicksCursor(5); + + deleteSurface(&_spriteHandle); + deleteSurface(&_menuSprite1); + deleteSurface(&_menuSprite2); + for (int i = 0; i < 7; ++i) + deleteSurface(&_savegameSprites[i]); + deleteSurface(&_cursorSprite); + deleteSurface(&_menuSaveLoadSprite); + deleteSurface(&_menuQuitQuerySprite); + + _sceneClickedHotspot = -1; + + _timers[2] = getRandom(20) + 30; + _timers[3] = getRandom(200) + 50; + _timers[0] = getRandom(75) + 75; + _timers[1] = getRandom(20) + 30; + + clearAllKeyStatus1(); + + _mouseClickState._left = false; + + removeDeviceIconActive(); + + freeMenuSprite();//??? CHECKME +} + +void GnapEngine::updateMenuStatusInventory() { + static const struct { + int item1, item2, resultItem; + } kCombineItems[] = { + {kItemGrass, kItemMud, kItemDisguise}, + {kItemDice, kItemQuarterWithHole, kItemDiceQuarterHole}, + {kItemPill, kItemBucketWithBeer, kItemBucketWithPill} + }; + + updateGrabCursorSprite(0, 0); + _hotspots[0]._rect = Common::Rect(262, 69, 341, 135); + _sceneClickedHotspot = -1; + if (_timers[2] == 0) + _sceneClickedHotspot = getClickedHotspotId(); + if (_sceneClickedHotspot == -1 || _sceneClickedHotspot >= _menuSpritesIndex) { + if (_sceneClickedHotspot == _hotspotsCount - 3) { + if (_grabCursorSpriteIndex == -1) { + _timers[2] = 10; + playSound(0x108F4, false); + _menuStatus = 1; + Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom); + drawInventoryFrames(); + initMenuHotspots2(); + removeInventorySprites(); + if (!_menuSprite1) + _menuSprite1 = _gameSys->createSurface(0x104F8); + _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262); + _gameSys->insertDirtyRect(dirtyRect); + } else { + playSound(0x108F5, false); + } + } else if (_sceneClickedHotspot == _hotspotsCount - 1) { + _timers[2] = 10; + playSound(0x108F5, false); + _menuDone = true; + } + } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex == -1) { + _gameSys->removeSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], 261); + setGrabCursorSprite(_menuInventoryIndices[_sceneClickedHotspot]); + _menuInventoryIndices[_sceneClickedHotspot] = -1; + } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] == -1 && _grabCursorSpriteIndex != -1) { + _menuInventoryIndices[_sceneClickedHotspot] = _grabCursorSpriteIndex; + _gameSys->insertSpriteDrawItem(_menuInventorySprites[_sceneClickedHotspot], + _hotspots[_sceneClickedHotspot]._rect.left + ((79 - _menuInventorySprites[_sceneClickedHotspot]->w) / 2), + _hotspots[_sceneClickedHotspot]._rect.top + (66 - _menuInventorySprites[_sceneClickedHotspot]->h) / 2, + 261); + setGrabCursorSprite(-1); + } else if (_sceneClickedHotspot != -1 && _menuInventoryIndices[_sceneClickedHotspot] != -1 && _grabCursorSpriteIndex != -1) { + int combineIndex = -1; + for (int i = 0; i < ARRAYSIZE(kCombineItems); ++i) { + if ((_grabCursorSpriteIndex == kCombineItems[i].item1 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item2) || + (_grabCursorSpriteIndex == kCombineItems[i].item2 && _menuInventoryIndices[_sceneClickedHotspot] == kCombineItems[i].item1)) { + combineIndex = i; + break; + } + } + if (combineIndex >= 0) { + invRemove(kCombineItems[combineIndex].item1); + invRemove(kCombineItems[combineIndex].item2); + invAdd(kCombineItems[combineIndex].resultItem); + playSound(0x108AE, false); + deleteSurface(&_spriteHandle); // CHECKME + _spriteHandle = _gameSys->createSurface(0x10001); + _gameSys->insertSpriteDrawItem(_spriteHandle, _hotspots[_menuSpritesIndex - 1]._rect.left, _hotspots[_menuSpritesIndex - 1]._rect.top, 261); + setGrabCursorSprite(kCombineItems[combineIndex].resultItem); + removeInventorySprites(); + insertInventorySprites(); + delayTicksCursor(5); + } else { + playSound(0x108F5, false); + } + } +} + +void GnapEngine::updateMenuStatusMainMenu() { + _hotspots[0]._rect = Common::Rect(312, 85, 465, 122); + _sceneClickedHotspot = -1; + if (!_timers[2]) + _sceneClickedHotspot = getClickedHotspotId(); + + if (_sceneClickedHotspot != 1 && _sceneClickedHotspot != 0) { + if (_sceneClickedHotspot != 2 && _hotspotsCount - 1 != _sceneClickedHotspot) { + if (_sceneClickedHotspot == 3) { + // Quit + _timers[2] = 10; + playSound(0x108F4, false); + _gameSys->removeSpriteDrawItem(_menuSprite1, 262); + initMenuQuitQueryHotspots(); + _menuStatus = 4; + if (!_menuQuitQuerySprite) + _menuQuitQuerySprite = _gameSys->createSurface(0x104FC); + _gameSys->insertSpriteDrawItem(_menuQuitQuerySprite, 254, 93, 262); + } else if (_sceneClickedHotspot == 4) { + // Pause ? + playSound(0x108F4, false); + Common::Rect dirtyRect(0, 0, 799, 599); + hideCursor(); + _largeSprite = _gameSys->allocSurface(800, 600); + + for (int i = 0; i < 3; ++i) { + _timers[2] = 10; + + if (i == 0) { + _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078D); + _gameSys->insertSpriteDrawItem(_largeSprite, 0, 0, 300); + playMidi("pause.mid"); + } else if (i == 1) { + _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078E); + _gameSys->insertDirtyRect(dirtyRect); + } else if (i == 2) { + _gameSys->drawSpriteToSurface(_largeSprite, 0, 0, 0x1078F); + _gameSys->insertDirtyRect(dirtyRect); + } + + while (!_mouseClickState._left && !isKeyStatus1(Common::KEYCODE_ESCAPE) && !isKeyStatus1(Common::KEYCODE_RETURN) + && !isKeyStatus1(Common::KEYCODE_SPACE) && !_timers[2] && !_gameDone) + gameUpdateTick(); + + playSound(0x108F5, false); + _mouseClickState._left = false; + clearKeyStatus1(Common::KEYCODE_ESCAPE); + clearKeyStatus1(Common::KEYCODE_RETURN); + clearKeyStatus1(Common::KEYCODE_SPACE); + } + + _gameSys->removeSpriteDrawItem(_largeSprite, 300); + delayTicksCursor(5); + deleteSurface(&_largeSprite); + showCursor(); + } else if (_hotspotsCount - 3 == _sceneClickedHotspot) { + // Button - Return to the inventory + _timers[2] = 10; + playSound(0x108F4, false); + initMenuHotspots1(); + _menuStatus = 0; + if (_menuSprite1) + _gameSys->removeSpriteDrawItem(_menuSprite1, 262); + insertInventorySprites(); + Common::Rect dirtyRect(_hotspots[0]._rect.left, _hotspots[0]._rect.top, _hotspots[2]._rect.right, _hotspots[_hotspotsCount - 4]._rect.bottom); + _gameSys->insertDirtyRect(dirtyRect); + } + } else { + // Resume + playSound(0x108F5, false); + _menuDone = true; + } + } else { + // Save / Load +#if 1 + _timers[2] = 10; + playSound(0x108F4, false); + + if (_sceneClickedHotspot == 1) { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); + int16 savegameId = dialog->runModalWithCurrentTarget(); + Common::String savegameDescription = dialog->getResultString(); + delete dialog; + + if (savegameId != -1) { + saveGameState(savegameId, savegameDescription); + } + } else { + GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); + int16 savegameId = dialog->runModalWithCurrentTarget(); + delete dialog; + + if (savegameId != -1) { + loadGameState(savegameId); + _wasSavegameLoaded = true; + _menuDone = true; + _sceneDone = true; + playSound(0x108F4, false); + } else { + playSound(0x108F5, false); + } + } + } +#else + // NOTE: + // This is the code for the original behavior. + // It's currently not working prolery, but could be + // fixed to replace the ScummVM screens currently + // used. + _timers[2] = 10; + playSound(0x108F4, false); + _gameSys->removeSpriteDrawItem(_menuSprite1, 262); + if (_menuSaveLoadSprite) + deleteSurface(&_menuSaveLoadSprite); + if (_sceneClickedHotspot == 1) { + // Save + _menuStatus = 2; + initSaveLoadHotspots(); + _menuSaveLoadSprite = _gameSys->createSurface(0x104FB); + } else { + // Load + _menuStatus = 3; + initSaveLoadHotspots(); + _menuSaveLoadSprite = _gameSys->createSurface(0x104FA); + } + _gameSys->insertSpriteDrawItem(_menuSaveLoadSprite, 403, 72, 262); + if (!_menuSprite2) + _menuSprite2 = _gameSys->createSurface(0x104F9); + _gameSys->insertSpriteDrawItem(_menuSprite2, 277, 66, 262); + for (int i = 0; i < 7; ++i) { + Common::String savegameDescription; + if (!_savegameSprites[i]) + _savegameSprites[i] = _gameSys->allocSurface(111, 40); + if (readSavegameDescription(i + 1, savegameDescription) == 0) + strncpy(_savegameFilenames[i], savegameDescription.c_str(), 40); + _gameSys->drawTextToSurface(_savegameSprites[i], 0, 0, 255, 0, 0, _savegameFilenames[i]); + _gameSys->insertSpriteDrawItem(_savegameSprites[i], 288, _hotspots[i].top, 263); + } + _savegameIndex = -1; + } +#endif +} + +Common::Error GnapEngine::saveGameState(int slot, const Common::String &desc) { + Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving( + generateSaveName(slot)); + if (!out) + return Common::kCreatingFileFailed; + + GnapSavegameHeader header; + header._saveName = desc; + writeSavegameHeader(out, header); + + Common::Serializer s(nullptr, out); + synchronize(s); + + out->finalize(); + delete out; + + return Common::kNoError; +} + +void GnapEngine::synchronize(Common::Serializer &s) { + if (s.isSaving()) { + s.syncAsSint32LE(_currentSceneNum); + s.syncAsSint32LE(_prevSceneNum); + s.syncAsSint32LE(_cursorValue); + s.syncAsUint32LE(_inventory); + s.syncAsUint32LE(_gameFlags); + } else { + s.syncAsSint32LE(_newSceneNum); + s.syncAsSint32LE(_currentSceneNum); + s.syncAsSint32LE(_newCursorValue); + s.syncAsUint32LE(_inventory); + s.syncAsUint32LE(_gameFlags); + + if (isFlag(kGFUnk24)) + _timers[9] = 600; + } +} + +const char *const SAVEGAME_STR = "GNAP"; +#define SAVEGAME_STR_SIZE 4 +void GnapEngine::writeSavegameHeader(Common::OutSaveFile *out, GnapSavegameHeader &header) { + // Write out a savegame header + out->write(SAVEGAME_STR, SAVEGAME_STR_SIZE + 1); + + out->writeByte(GNAP_SAVEGAME_VERSION); + + // Write savegame name + out->writeString(header._saveName); + out->writeByte('\0'); + + // This implies the menu is used + // If we want to save/load at any time, then a check should be added + out->write(_tempThumbnail->getData(), _tempThumbnail->size()); + + // Write out the save date/time + TimeDate td; + g_system->getTimeAndDate(td); + out->writeSint16LE(td.tm_year + 1900); + out->writeSint16LE(td.tm_mon + 1); + out->writeSint16LE(td.tm_mday); + out->writeSint16LE(td.tm_hour); + out->writeSint16LE(td.tm_min); +} + +bool GnapEngine::readSavegameHeader(Common::InSaveFile *in, GnapSavegameHeader &header) { + char saveIdentBuffer[SAVEGAME_STR_SIZE + 1]; + header._thumbnail = nullptr; + + // Validate the header Id + in->read(saveIdentBuffer, SAVEGAME_STR_SIZE + 1); + if (strncmp(saveIdentBuffer, SAVEGAME_STR, SAVEGAME_STR_SIZE)) + return false; + + header._version = in->readByte(); + if (header._version > GNAP_SAVEGAME_VERSION) + return false; + + // Read in the string + header._saveName.clear(); + char ch; + while ((ch = (char)in->readByte()) != '\0') + header._saveName += ch; + + // Get the thumbnail, saved in v2 or later + if (header._version == 1) + header._thumbnail = nullptr; + else { + header._thumbnail = Graphics::loadThumbnail(*in); + if (!header._thumbnail) + return false; + } + + // Read in save date/time + header._year = in->readSint16LE(); + header._month = in->readSint16LE(); + header._day = in->readSint16LE(); + header._hour = in->readSint16LE(); + header._minute = in->readSint16LE(); + + return true; +} + +Common::Error GnapEngine::loadGameState(int slot) { + Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading( + generateSaveName(slot)); + if (!saveFile) + return Common::kReadingFailed; + + Common::Serializer s(saveFile, nullptr); + + // Load the savegame header + GnapSavegameHeader header; + if (!readSavegameHeader(saveFile, header)) + error("Invalid savegame"); + + if (header._thumbnail) { + header._thumbnail->free(); + delete header._thumbnail; + } + + synchronize(s); + delete saveFile; + + _loadGameSlot = slot; + return Common::kNoError; +} + +Common::String GnapEngine::generateSaveName(int slot) { + return Common::String::format("%s.%03d", _targetName.c_str(), slot); +} + +void GnapEngine::updateMenuStatusSaveGame() { +#if 0 + // NOTE: + // This is the code for the original screen game. + // It could be eventually fixed and could replace + // the ScummVM screens currently used. + + char v43[30]; + int v46; + v43[0] = '\0'; + _hotspots[0]._x1 = 288; + _hotspots[0]._y1 = 74; + _hotspots[0]._x2 = 379; + _hotspots[0]._y2 = 96; + _sceneClickedHotspot = -1; + + if (!_timers[2]) + _sceneClickedHotspot = getClickedHotspotId(); + + if (_hotspotsCount - 3 == _sceneClickedHotspot) { + // Button + _timers[2] = 10; + playSound(0x108F4, false); + _menuStatus = 1; + warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);"); + } else if (_hotspotsCount - 4 == _sceneClickedHotspot) { + // Cancel + _timers[2] = 10; + playSound(0x108F5, false); + _menuStatus = 1; + if (strcmp(v43, _savegameFilenames[_savegameIndex]) && _savegameIndex != -1) { + strcpy(_savegameFilenames[_savegameIndex], v43); + if (_savegameSprites[_savegameIndex] != nullptr) { + _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263); + delayTicksCursor(5); + warning("memFreeHandle(_savegameSprites[_savegameIndex]);"); + } + int v16 = _gameSys->getSpriteWidthById(0x104F9); + warning("_savegameSprites[_savegameIndex] = allocSprite(v16, 40, 128, 0);"); + } + } else if (_hotspotsCount - 5 == _sceneClickedHotspot) { + // OK + _timers[2] = 10; + playSound(0x108F4, false); + if (_savegameIndex != -1) + warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);"); + _menuStatus = 1; + } else if (_hotspotsCount - 1 == _sceneClickedHotspot) { + // in background + _menuDone = true; + } else if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) { + // Savegame name + _timers[2] = 10; + playSound(0x108F4, false); + if (strcmp(v43, _savegameFilenames[_savegameIndex]) & (_savegameIndex != -1)) { + strcpy(_savegameFilenames[_savegameIndex], v43); + if (_savegameSprites[_savegameIndex] != nullptr) { + _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263); + delayTicksCursor(5); + warning("memFreeHandle(_savegameSprites[_savegameIndex]);"); + } + int v18 = _gameSys->getSpriteWidthById(0x104F9); + _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v18, 40); + _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]); + _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263); + } + _savegameIndex = _sceneClickedHotspot; + v46 = strlen(_savegameFilenames[_sceneClickedHotspot]); + strcpy(v43, _savegameFilenames[_sceneClickedHotspot]); + if (_cursorSprite == nullptr) { + int v19 = _gameSys->getTextHeight("_"); + int v20 = _gameSys->getTextWidth("_"); + _cursorSprite = _gameSys->allocSurface(v20, v19); + _gameSys->drawTextToSurface(_cursorSprite, 0, 0, 255, 0, 0, "_"); + } else { + _gameSys->removeSpriteDrawItem(_cursorSprite, 264); + } + int v21 = _hotspots[_savegameIndex]._x2; + int v22 = v21 - _gameSys->getTextWidth("_"); + if (v22 > _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288) { + int v25 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) + 288; + _gameSys->insertSpriteDrawItem(_cursorSprite, v25, _hotspots[_savegameIndex]._y1, 264); + } else { + int v23 = _hotspots[_savegameIndex]._x2; + int v24 = v23 - _gameSys->getTextWidth("_"); + _gameSys->insertSpriteDrawItem(_cursorSprite, v24, _hotspots[_savegameIndex]._y1, 264); + } + } + + updateEvents(); + Common::Event event; + _eventMan->pollEvent(event); + + Common::KeyCode keycode = event.kbd.keycode; + if (_savegameIndex != -1 && keycode) { + if ((keycode < Common::KEYCODE_a || keycode > Common::KEYCODE_z) && (keycode < Common::KEYCODE_0 || keycode > Common::KEYCODE_9) && keycode != Common::KEYCODE_SPACE) { + if (keycode == Common::KEYCODE_BACKSPACE) { + if (v46 > 0) + --v46; + _savegameFilenames[_savegameIndex][v46] = '\0'; + if (_savegameSprites[_savegameIndex] != nullptr) { + _gameSys->removeSpriteDrawItem(_savegameSprites[_savegameIndex], 263); + warning("memFreeHandle(_savegameSprites[_savegameIndex]);"); + } + int v32 = _gameSys->getSpriteWidthById(0x104F9); + _savegameSprites[_savegameIndex] = _gameSys->allocSurface(v32, 40); + _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]); + _gameSys->insertSpriteDrawItem(_savegameSprites[_savegameIndex], 288, _hotspots[_savegameIndex]._y1, 263); + _gameSys->removeSpriteDrawItem(_cursorSprite, 264); + int v33 = _hotspots[_savegameIndex]._y1; + int v34 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]); + _gameSys->insertSpriteDrawItem(_cursorSprite, _hotspots[_savegameIndex]._x1 + v34, v33, 264); + } else if (keycode == Common::KEYCODE_RETURN) { + _menuStatus = 1; + warning("writeSavegame(_savegameIndex + 1, (int)&_savegameFilenames[30 * _savegameIndex], 1);"); + } + } else { + _savegameFilenames[_savegameIndex][v46] = event.kbd.ascii; + if (v46 < 28) + ++v46; + _savegameFilenames[_savegameIndex][v46] = '\0'; + if (_gameSys->getTextWidth(_savegameFilenames[_savegameIndex]) > 91) { + --v46; + _savegameFilenames[_savegameIndex][v46] = '\0'; + } + _gameSys->drawTextToSurface(_savegameSprites[_savegameIndex], 0, 0, 255, 0, 0, _savegameFilenames[_savegameIndex]); + int v26 = _gameSys->getTextWidth(_savegameFilenames[_savegameIndex]); + Common::Rect rect; + rect.right = _hotspots[_savegameIndex]._x1 + v26; + int v27 = rect.right; + rect.left = v27 - 2 * _gameSys->getTextWidth("W"); + rect.top = _hotspots[_savegameIndex]._y1; + rect.bottom = _hotspots[_savegameIndex]._y2; + _gameSys->insertDirtyRect(rect); + _gameSys->removeSpriteDrawItem(_cursorSprite, 264); + int v28 = _hotspots[_savegameIndex]._x2; + int v29 = _gameSys->getTextWidth("_"); + if (v28 - v29 > rect.right) + _gameSys->insertSpriteDrawItem(_cursorSprite, rect.right, rect.top, 264); + else { + int v30 = _hotspots[_savegameIndex]._x2; + int v31 = v30 - _gameSys->getTextWidth("_"); + _gameSys->insertSpriteDrawItem(_cursorSprite, v31, rect.top, 264); + } + clearKeyStatus1(8); + } + } + +// warning("keybChar = 0;"); + if (_menuStatus == 1 || _menuDone) { + _gameSys->removeSpriteDrawItem(_menuSprite2, 262); + _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262); + for (int i = 0; i < 7; ++i) + _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263); + _gameSys->removeSpriteDrawItem(_cursorSprite, 264); + if (!_menuDone) { + initMenuHotspots2(); + _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262); + } + } +#endif +} + +void GnapEngine::updateMenuStatusLoadGame() { + _hotspots[0]._rect = Common::Rect(288, 74, 379, 96); + _sceneClickedHotspot = -1; + if (!_timers[2]) + _sceneClickedHotspot = getClickedHotspotId(); + if (_sceneClickedHotspot != -1 && _hotspotsCount - 2 != _sceneClickedHotspot) { + _timers[2] = 10; + if (_hotspotsCount - 4 <= _sceneClickedHotspot) { + playSound(0x108F5, false); + _gameSys->removeSpriteDrawItem(_menuSprite2, 262); + _gameSys->removeSpriteDrawItem(_menuSaveLoadSprite, 262); + for (int i = 0; i < 7; ++i) + _gameSys->removeSpriteDrawItem(_savegameSprites[i], 263); + if (_hotspotsCount - 1 == _sceneClickedHotspot) { + _menuDone = true; + } else { + _menuStatus = 1; + initMenuHotspots2(); + _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262); + } + } else if (loadSavegame(_sceneClickedHotspot + 1)) { + playSound(0x108F5, false); + } else { + playSound(0x108F4, false); + _sceneDone = true; + } + } +} + +void GnapEngine::updateMenuStatusQueryQuit() { + _hotspots[0]._rect = Common::Rect(311, 197, 377, 237); + _sceneClickedHotspot = -1; + + if (!_timers[2]) + _sceneClickedHotspot = getClickedHotspotId(); + + /* _sceneClickedHotspot + 0 Yes + 1 No + 2 Button + 3 Display + 4 Background + */ + + if (_sceneClickedHotspot == 0) { + // Quit the game + playSound(0x108F5, false); + _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262); + _sceneDone = true; + _gameDone = true; + } else if (_sceneClickedHotspot == 4) { + // Exit the device + playSound(0x108F4, false); + _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262); + _menuDone = true; + } else if (_sceneClickedHotspot != -1) { + // Return to the main menu + playSound(0x108F4, false); + _gameSys->removeSpriteDrawItem(_menuQuitQuerySprite, 262); + _timers[2] = 10; + _menuStatus = 1; + initMenuHotspots2(); + _gameSys->insertSpriteDrawItem(_menuSprite1, 288, 79, 262); + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/module.mk b/engines/gnap/module.mk new file mode 100644 index 0000000000..ab507cbf94 --- /dev/null +++ b/engines/gnap/module.mk @@ -0,0 +1,32 @@ +MODULE := engines/gnap + +MODULE_OBJS := \ + character.o \ + datarchive.o \ + debugger.o \ + detection.o \ + gamesys.o \ + gnap.o \ + grid.o \ + menu.o \ + music.o \ + resource.o \ + sound.o \ + scenes/arcade.o \ + scenes/groupcs.o \ + scenes/group0.o \ + scenes/group1.o \ + scenes/group2.o \ + scenes/group3.o \ + scenes/group4.o \ + scenes/group5.o \ + scenes/intro.o \ + scenes/scenecore.o + +# This module can be built as a plugin +ifeq ($(ENABLE_GNAP), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/gnap/music.cpp b/engines/gnap/music.cpp new file mode 100644 index 0000000000..af33786a8f --- /dev/null +++ b/engines/gnap/music.cpp @@ -0,0 +1,104 @@ +/* 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. + * + */ + +// MIDI and digital music class + +#include "audio/mididrv.h" +#include "audio/midiparser.h" +#include "common/debug.h" +#include "common/file.h" + +#include "gnap/music.h" +#include "gnap/gnap.h" + +namespace Gnap { + +MusicPlayer::MusicPlayer(const char *filename) : _filename(filename) { + + MidiPlayer::createDriver(); + + int ret = _driver->open(); + if (ret == 0) { + if (_nativeMT32) + _driver->sendMT32Reset(); + else + _driver->sendGMReset(); + + _driver->setTimerCallback(this, &timerCallback); + } +} + +void MusicPlayer::sendToChannel(byte channel, uint32 b) { + if (!_channelsTable[channel]) { + _channelsTable[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + // If a new channel is allocated during the playback, make sure + // its volume is correctly initialized. + if (_channelsTable[channel]) + _channelsTable[channel]->volume(_channelsVolume[channel] * _masterVolume / 255); + } + + if (_channelsTable[channel]) + _channelsTable[channel]->send(b); +} + +void MusicPlayer::playSMF(bool loop) { + Common::StackLock lock(_mutex); + + stop(); + + // Load MIDI resource data + Common::File musicFile; + musicFile.open(_filename); + if (!musicFile.isOpen()) { + debugC(2, kDebugMusic, "Cannot open music file %s", _filename.c_str()); + return; + } + int midiMusicSize = musicFile.size(); + free(_midiData); + _midiData = (byte *)malloc(midiMusicSize); + musicFile.read(_midiData, midiMusicSize); + musicFile.close(); + + MidiParser *parser = MidiParser::createParser_SMF(); + if (parser->loadMusic(_midiData, midiMusicSize)) { + parser->setTrack(0); + parser->setMidiDriver(this); + parser->setTimerRate(_driver->getBaseTempo()); + parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + + _parser = parser; + + syncVolume(); + + _isLooping = loop; + _isPlaying = true; + } else { + debugC(2, kDebugMusic, "Cannot play music file %s", _filename.c_str()); + delete parser; + } +} + +void MusicPlayer::stop() { + Audio::MidiPlayer::stop(); +} + +} // End of namespace Gnap diff --git a/engines/gnap/music.h b/engines/gnap/music.h new file mode 100644 index 0000000000..c5938937eb --- /dev/null +++ b/engines/gnap/music.h @@ -0,0 +1,50 @@ +/* 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. + * + */ + +// Music class + +#ifndef GNAP_MUSIC_H +#define GNAP_MUSIC_H + +#include "audio/midiplayer.h" + +namespace Gnap { + +// Taken from Draci, which took it from MADE, which took it from SAGA. + +class MusicPlayer : public Audio::MidiPlayer { +public: + MusicPlayer(const char *filename); + + void playSMF(bool loop); + void stop(); + + // Overload Audio::MidiPlayer method + virtual void sendToChannel(byte channel, uint32 b); + +protected: + Common::String _filename; +}; + +} // End of namespace Gnap + +#endif diff --git a/engines/gnap/resource.cpp b/engines/gnap/resource.cpp new file mode 100644 index 0000000000..8244213a7f --- /dev/null +++ b/engines/gnap/resource.cpp @@ -0,0 +1,121 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/resource.h" + +namespace Gnap { + +// SequenceFrame + +void SequenceFrame::loadFromStream(Common::MemoryReadStream &stream) { + _duration = stream.readUint16LE(); + _isScaled = (stream.readUint16LE() != 0); + _rect.left = stream.readUint32LE(); + _rect.top = stream.readUint32LE(); + _rect.right = stream.readUint32LE(); + _rect.bottom = stream.readUint32LE(); + _spriteId = stream.readUint32LE(); + _soundId = stream.readUint32LE(); + + // Skip an unused value + stream.readUint32LE(); + + debugC(kDebugBasic, "SequenceFrame() spriteId: %d; soundId: %d", _spriteId, _soundId); +} + +// SequenceAnimation + +void SequenceAnimation::loadFromStream(Common::MemoryReadStream &stream) { + // Skip two unused values + stream.readUint32LE(); + + _additionalDelay = stream.readUint32LE(); + _framesCount = stream.readUint16LE(); + _maxTotalDuration = stream.readUint16LE(); + debugC(kDebugBasic, "SequenceAnimation() framesCount: %d", _framesCount); + frames = new SequenceFrame[_framesCount]; + for (int i = 0; i < _framesCount; ++i) + frames[i].loadFromStream(stream); +} + +// SequenceResource +SequenceResource::SequenceResource(byte *data, uint32 size) { + Common::MemoryReadStream stream(data, size, DisposeAfterUse::NO); + + // Skip an unused value + stream.readUint32LE(); + + _sequenceId = stream.readUint32LE(); + _defaultId = stream.readUint32LE(); + _sequenceId2 = stream.readUint32LE(); + _defaultId2 = stream.readUint32LE(); + _flags = stream.readUint32LE(); + _totalDuration = stream.readUint32LE(); + _xOffs = stream.readUint16LE(); + _yOffs = stream.readUint16LE(); + _animationsCount = stream.readUint32LE(); + _animations = new SequenceAnimation[_animationsCount]; + debugC(kDebugBasic, "SequenceResource() _animationsCount: %d", _animationsCount); + for (int i = 0; i < _animationsCount; ++i) { + uint32 animationOffs = stream.readUint32LE(); + debugC(kDebugBasic, "animationOffs: %08X", animationOffs); + uint32 oldOffs = stream.pos(); + stream.seek(animationOffs); + _animations[i].loadFromStream(stream); + stream.seek(oldOffs); + } +} + +SequenceResource::~SequenceResource() { + delete[] _animations; +} + +// SpriteResource +SpriteResource::SpriteResource(byte *data, uint32 size) { + _data = data; + _width = READ_LE_UINT16(_data); + _height = READ_LE_UINT16(_data + 2); + _unknownVal1 = READ_LE_UINT16(_data + 4); + _unknownVal2 = READ_LE_UINT16(_data + 6); + _transparent = (READ_LE_UINT16(_data + 8) != 0); + _colorsCount = READ_LE_UINT16(_data + 10); + _palette = (uint32 *)(_data + 12); + _pixels = _data + 12 + _colorsCount * 4; + debugC(kDebugBasic, "SpriteResource() width: %d; height: %d; colorsCount: %d", _width, _height, _colorsCount); +} + +SpriteResource::~SpriteResource() { + delete[] _data; +} + +// SoundResource +SoundResource::SoundResource(byte *data, uint32 size) { + _data = data; + _size = size; +} + +SoundResource::~SoundResource() { + delete[] _data; +} + +} // End of namespace Gnap diff --git a/engines/gnap/resource.h b/engines/gnap/resource.h new file mode 100644 index 0000000000..29bd31c88f --- /dev/null +++ b/engines/gnap/resource.h @@ -0,0 +1,189 @@ +/* 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. + * + */ + +#ifndef GNAP_RESOURCE_H +#define GNAP_RESOURCE_H + +#include "common/array.h" +#include "common/events.h" +#include "common/file.h" +#include "common/memstream.h" +#include "common/str.h" +#include "common/stream.h" +#include "common/substream.h" +#include "common/system.h" + +#include "graphics/surface.h" + +#include "gnap/datarchive.h" + +namespace Gnap { + +enum { + kResTypeSprite = 0, + kResTypeBitmap = 1, + kResTypeSound = 2, + kResTypeSequence = 3 +}; + +struct SequenceFrame { + int16 _duration; + bool _isScaled; + Common::Rect _rect; + int32 _spriteId; + int32 _soundId; + void loadFromStream(Common::MemoryReadStream &stream); +}; + +struct SequenceAnimation { + int32 _additionalDelay; + int16 _framesCount; + int16 _maxTotalDuration; + SequenceFrame *frames; + SequenceAnimation() : frames(nullptr) {} + ~SequenceAnimation() { delete[] frames; } + void loadFromStream(Common::MemoryReadStream &stream); +}; + +class SequenceResource { +public: + SequenceResource(byte *data, uint32 size); + ~SequenceResource(); +public: + int32 _sequenceId; + int32 _defaultId; + int32 _sequenceId2; + uint32 _defaultId2; + uint32 _flags; + int32 _totalDuration; + int16 _xOffs; + int16 _yOffs; + int32 _animationsCount; + SequenceAnimation *_animations; +}; + +class SpriteResource { +public: + SpriteResource(byte *data, uint32 size); + ~SpriteResource(); +public: + byte *_data; + byte *_pixels; + uint32 *_palette; + int16 _width, _height; + uint16 _unknownVal1; + uint16 _unknownVal2; + bool _transparent; + uint16 _colorsCount; +}; + +class SoundResource { +public: + SoundResource(byte *data, uint32 size); + ~SoundResource(); +public: + byte *_data; + uint32 _size; +}; + +template <class ResourceClass, int ResourceType, bool FreeAfterLoad> +class ResourceCacheTemplate { +public: + + ResourceCacheTemplate(DatManager *dat) : _dat(dat) { + } + + ~ResourceCacheTemplate() { + } + + ResourceClass *get(int resourceId) { + Resource *resource = find(resourceId); + if (!resource) { + debug(9, "Loading resource type %d with ID %08X from disk", ResourceType, resourceId); + resource = new Resource(load(resourceId)); + _cache[resourceId] = resource; + } else { + debug(9, "Resource type %d with ID %08X was in cache", ResourceType, resourceId); + } + resource->_isLocked = true; + return resource->_obj; + } + + void release(int resourceId) { + Resource *resource = find(resourceId); + if (resource) + resource->_isLocked = false; + } + + void purge(bool force = false) { + for (CacheMapIterator it = _cache.begin(); it != _cache.end(); ++it) { + Resource *resource = it->_value; + if (force || !resource->_isLocked) { + delete resource; + _cache.erase(it); + } + } + } + +protected: + + struct Resource { + ResourceClass *_obj; + bool _isLocked; + Resource(ResourceClass *obj) : _obj(obj), _isLocked(false) {} + ~Resource() { delete _obj; } + }; + + typedef Common::HashMap<int, Resource *> CacheMap; + typedef typename CacheMap::iterator CacheMapIterator; + + DatManager *_dat; + CacheMap _cache; + + Resource *find(int resourceId) { + CacheMapIterator it = _cache.find(resourceId); + if (it != _cache.end()) + return it->_value; + return nullptr; + } + + ResourceClass *load(int resourceId) { + if (_dat->getResourceType(resourceId) != ResourceType) + error("ResourceCache::load() Wrong resource type: Expected %d, got %d", ResourceType, _dat->getResourceType(resourceId)); + + byte *resourceData = _dat->loadResource(resourceId); + uint32 resourceSize = _dat->getResourceSize(resourceId); + ResourceClass *obj = new ResourceClass(resourceData, resourceSize); + if (FreeAfterLoad) + delete[] resourceData; + return obj; + } + +}; + +typedef ResourceCacheTemplate<SpriteResource, kResTypeSprite, false> SpriteCache; +typedef ResourceCacheTemplate<SoundResource, kResTypeSound, false> SoundCache; +typedef ResourceCacheTemplate<SequenceResource, kResTypeSequence, true> SequenceCache; + +} // End of namespace Gnap + +#endif // GNAP_RESOURCE_H diff --git a/engines/gnap/scenes/arcade.cpp b/engines/gnap/scenes/arcade.cpp new file mode 100644 index 0000000000..571fdbf85f --- /dev/null +++ b/engines/gnap/scenes/arcade.cpp @@ -0,0 +1,2713 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/arcade.h" + +namespace Gnap { + +static const ObstacleDef kObstacleDefs[] = { + {0xB4, 15}, {0xCB, 14}, {0xCD, 13}, {0xCF, 15}, {0xBA, 14}, + {0xCD, 13}, {0xCF, 12}, {0xCB, 15}, {0xBD, 13}, {0xCF, 12}, + {0xCD, 11}, {0xCB, 15}, {0xB7, 12}, {0xCD, 11}, {0xCB, 10}, + {0xCF, 15}, {0xCF, 14}, {0xBD, 13}, {0xCF, 12}, {0xCD, 11}, + {0xCB, 15}, {0xCB, 13}, {0xB4, 12}, {0xCB, 11}, {0xCD, 10}, + {0xCF, 15}, {0xCD, 12}, {0xBA, 12}, {0xCD, 12}, {0xCF, 12}, + {0xCB, 15}, {0xCB, 9}, {0xCD, 9}, {0xCF, 9}, {0xCD, 9}, + {0xCB, 9}, {0xCD, 9}, {0xCF, 5}, {0xBD, 13}, {0xCF, 8}, + {0xCB, 8}, {0xCD, 15}, {0xB4, 1}, {0xBD, 7}, {0xCF, 7}, + {0xCD, 7}, {0xCB, 7}, {0xCD, 7}, {0xCF, 15}, {0xCF, 15} +}; + +Scene49::Scene49(GnapEngine *vm) : Scene(vm) { + _scoreBarFlash = false; + _scoreBarPos = -1; + _scoreLevel = -1; + _obstacleIndex = -1; + _truckSequenceId = -1; + _truckId = -1; + _truckLaneNum = -1; + + for (int i = 0; i < 5; i++) { + _obstacles[i]._currSequenceId = -1; + _obstacles[i]._closerSequenceId = -1; + _obstacles[i]._passedSequenceId = -1; + _obstacles[i]._splashSequenceId = -1; + _obstacles[i]._collisionSequenceId = -1; + _obstacles[i]._prevId = -1; + _obstacles[i]._currId = -1; + _obstacles[i]._laneNum = -1; + } +} + +int Scene49::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + for (int i = 0; i < 5; ++i) + gameSys.setAnimation(0, 0, i + 2); + _vm->_timers[2] = 0; + _vm->_timers[0] = 0; + _vm->_timers[1] = 0; + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + return 0xD5; +} + +void Scene49::updateHotspots() { + _vm->_hotspotsCount = 0; +} + +void Scene49::checkObstacles() { + if (_vm->_timers[2] == 0) { + if (_vm->_timers[3] == 0) { + for (int i = 0; i < 5; ++i) + clearObstacle(i); + } + + for (int j = 0; j < 5; ++j) { + if (_obstacles[j]._currSequenceId == 0) { + _vm->_timers[3] = 35; + _obstacles[j]._currSequenceId = kObstacleDefs[_obstacleIndex]._sequenceId; + switch (_obstacles[j]._currSequenceId) { + case 0xB4: + _obstacles[j]._laneNum = 1; + _obstacles[j]._closerSequenceId = 180; + _obstacles[j]._passedSequenceId = 181; + _obstacles[j]._splashSequenceId = 182; + _obstacles[j]._collisionSequenceId = 192; + break; + case 0xB7: + _obstacles[j]._laneNum = 2; + _obstacles[j]._closerSequenceId = 183; + _obstacles[j]._passedSequenceId = 184; + _obstacles[j]._splashSequenceId = 185; + _obstacles[j]._collisionSequenceId = 193; + break; + case 0xBD: + _obstacles[j]._laneNum = 3; + _obstacles[j]._closerSequenceId = 189; + _obstacles[j]._passedSequenceId = 190; + _obstacles[j]._splashSequenceId = 191; + _obstacles[j]._collisionSequenceId = 195; + break; + case 0xBA: + _obstacles[j]._laneNum = 2; + _obstacles[j]._closerSequenceId = 186; + _obstacles[j]._passedSequenceId = 187; + _obstacles[j]._splashSequenceId = 188; + _obstacles[j]._collisionSequenceId = 194; + break; + case 0xCB: + _obstacles[j]._laneNum = 1; + _obstacles[j]._closerSequenceId = 203; + _obstacles[j]._passedSequenceId = 204; + _obstacles[j]._splashSequenceId = 0; + _obstacles[j]._collisionSequenceId = 209; + break; + case 0xCD: + _obstacles[j]._laneNum = 2; + _obstacles[j]._closerSequenceId = 205; + _obstacles[j]._passedSequenceId = 206; + _obstacles[j]._splashSequenceId = 0; + _obstacles[j]._collisionSequenceId = 210; + break; + case 0xCF: + _obstacles[j]._laneNum = 3; + _obstacles[j]._closerSequenceId = 207; + _obstacles[j]._passedSequenceId = 208; + _obstacles[j]._splashSequenceId = 0; + _obstacles[j]._collisionSequenceId = 211; + break; + } + _obstacles[j]._prevId = _truckId; + _obstacles[j]._currId = _obstacles[j]._prevId; + _vm->_gameSys->setAnimation(_obstacles[j]._currSequenceId, _obstacles[j]._currId, j + 2); + _vm->_gameSys->insertSequence(_obstacles[j]._currSequenceId, _obstacles[j]._currId, 0, 0, kSeqNone, 0, 0, -50); + _vm->_timers[2] = kObstacleDefs[_obstacleIndex]._ticks; + ++_obstacleIndex; + if (_obstacleIndex == 50) + _obstacleIndex = 0; + break; + } + } + } +} + +void Scene49::updateObstacle(int id) { + GameSys& gameSys = *_vm->_gameSys; + + Scene49Obstacle &obstacle = _obstacles[id]; + obstacle._currId = obstacle._prevId; + + switch (obstacle._laneNum) { + case 1: + obstacle._prevId = _truckId + 1; + break; + case 2: + if (_truckLaneNum != 2 && _truckLaneNum != 3) + obstacle._prevId = _truckId - 1; + else + obstacle._prevId = _truckId + 1; + break; + case 3: + if (_truckLaneNum != 1 && _truckLaneNum != 2) + obstacle._prevId = _truckId; + else + obstacle._prevId = _truckId - 1; + break; + } + + if (obstacle._currSequenceId == obstacle._closerSequenceId) { + if (_truckLaneNum == obstacle._laneNum) { + if (obstacle._splashSequenceId) { + gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2); + gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId, + obstacle._currSequenceId, obstacle._currId, + kSeqSyncWait, 0, 0, -50); + obstacle._currSequenceId = obstacle._collisionSequenceId; + _vm->playSound(0xE0, false); + increaseScore(30); + } else if ((obstacle._laneNum == 1 && _truckSequenceId == 0xB0) || + (obstacle._laneNum == 2 && (_truckSequenceId == 0xB1 || _truckSequenceId == 0xB2)) || + (obstacle._laneNum == 3 && _truckSequenceId == 0xB3)) { + gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2); + gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId, + obstacle._currSequenceId, obstacle._currId, + kSeqSyncWait, 0, 0, -50); + obstacle._currSequenceId = obstacle._passedSequenceId; + } else { + gameSys.setAnimation(obstacle._collisionSequenceId, 256, 0); + gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2); + gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId, + obstacle._currSequenceId, obstacle._currId, + kSeqSyncWait, 0, 0, -50); + gameSys.insertSequence(obstacle._collisionSequenceId, 256, + _truckSequenceId, _truckId, + kSeqSyncExists, 0, 0, -50); + _truckSequenceId = obstacle._collisionSequenceId; + _truckId = 256; + obstacle._currSequenceId = obstacle._passedSequenceId; + _vm->playSound(0xE1, false); + decreaseScore(30); + } + } else { + gameSys.setAnimation(obstacle._passedSequenceId, obstacle._prevId, id + 2); + gameSys.insertSequence(obstacle._passedSequenceId, obstacle._prevId, + obstacle._currSequenceId, obstacle._currId, + kSeqSyncWait, 0, 0, -50); + obstacle._currSequenceId = obstacle._passedSequenceId; + } + } else if (obstacle._currSequenceId == obstacle._passedSequenceId) { + if (_truckLaneNum == obstacle._laneNum) { + if (obstacle._splashSequenceId) { + gameSys.setAnimation(obstacle._collisionSequenceId, obstacle._prevId, id + 2); + gameSys.insertSequence(obstacle._collisionSequenceId, obstacle._prevId, + obstacle._currSequenceId, obstacle._currId, + kSeqSyncWait, 0, 0, -50); + obstacle._currSequenceId = obstacle._collisionSequenceId; + _vm->playSound(0xE0, false); + increaseScore(30); + } + } else if (obstacle._splashSequenceId) { + gameSys.setAnimation(obstacle._splashSequenceId, obstacle._prevId, id + 2); + gameSys.insertSequence(obstacle._splashSequenceId, obstacle._prevId, + obstacle._currSequenceId, obstacle._currId, + kSeqSyncWait, 0, 0, -50); + obstacle._currSequenceId = obstacle._splashSequenceId; + } + } else { + gameSys.setAnimation(0, 0, id + 2); + clearObstacle(id); + } +} + +void Scene49::increaseScore(int amount) { + if (_scoreBarPos + amount <= 556) { + _scoreBarPos += amount; + _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 255, 0, 0); + } + + _scoreLevel = (_scoreBarPos + amount >= 556) ? 1 : 0; +} + +void Scene49::decreaseScore(int amount) { + if (_scoreBarPos >= 226 && _scoreLevel == 0) { + if (_scoreBarFlash) + refreshScoreBar(); + _vm->_gameSys->fillSurface(nullptr, _scoreBarPos, 508, amount, 22, 89, 0, 5); + _scoreBarPos -= amount; + _scoreLevel = 0; + } +} + +void Scene49::refreshScoreBar() { + if (_scoreBarFlash) + _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 255, 0, 0); + else + _vm->_gameSys->fillSurface(nullptr, 226, 508, 330, 22, 89, 0, 5); + _scoreBarFlash = !_scoreBarFlash; +} + +void Scene49::clearObstacle(int index) { + _obstacles[index]._currSequenceId = 0; + _obstacles[index]._closerSequenceId = 0; + _obstacles[index]._passedSequenceId = 0; + _obstacles[index]._splashSequenceId = 0; + _obstacles[index]._collisionSequenceId = 0; + _obstacles[index]._prevId = 0; + _obstacles[index]._currId = 0; + _obstacles[index]._laneNum = 0; +} + +void Scene49::run() { + GameSys& gameSys = *_vm->_gameSys; + + bool animToggle6 = false; + bool animToggle5 = false; + bool animToggle4 = false; + bool animToggle3 = false; + bool streetAnimToggle = false; + bool bgAnimToggle = false; + + _vm->playSound(0xE2, true); + _vm->setSoundVolume(0xE2, 75); + + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + + _scoreBarPos = 196; + _scoreLevel = 0; + _scoreBarFlash = false; + + switch (_vm->getRandom(3)) { + case 0: + _truckSequenceId = 0xAD; + _truckLaneNum = 1; + break; + case 1: + _truckSequenceId = 0xAE; + _truckLaneNum = 2; + break; + case 2: + _truckSequenceId = 0xAF; + _truckLaneNum = 3; + break; + } + + int bgWidth1 = gameSys.getSpriteWidthById(0x5E); + int bgX1 = 600; + + int bgWidth2 = gameSys.getSpriteWidthById(0x5F); + int bgX2 = 400; + + int bgWidth3 = gameSys.getSpriteWidthById(4); + int bgX3 = 700; + + int bgWidth4 = gameSys.getSpriteWidthById(5); + int bgX4 = 500; + + int bgWidth5 = gameSys.getSpriteWidthById(6); + int bgX5 = 300; + + int bgWidth6 = gameSys.getSpriteWidthById(7); + int bgX6 = 100; + + gameSys.setAnimation(0xC8, 251, 1); + gameSys.setAnimation(_truckSequenceId, 256, 0); + gameSys.insertSequence(0xC9, 256, 0, 0, kSeqNone, 0, 600, 85); + gameSys.insertSequence(0xCA, 257, 0, 0, kSeqNone, 0, 400, 100); + gameSys.insertSequence(0xC4, 256, 0, 0, kSeqNone, 0, 700, 140); + gameSys.insertSequence(0xC5, 257, 0, 0, kSeqNone, 0, 500, 160); + gameSys.insertSequence(0xC6, 258, 0, 0, kSeqNone, 0, 300, 140); + gameSys.insertSequence(0xC7, 259, 0, 0, kSeqNone, 0, 100, 140); + gameSys.insertSequence(0xC8, 251, 0, 0, kSeqNone, 0, 0, -50); + gameSys.insertSequence(_truckSequenceId, 256, 0, 0, kSeqNone, 0, 0, -50); + + _vm->_timers[0] = 2; + + for (int i = 0; i < 5; ++i) + clearObstacle(i); + + _obstacleIndex = 0; + + _vm->_timers[2] = _vm->getRandom(20) + 10; + + _truckId = 256; + _vm->_timers[3] = 35; + + while (!_vm->_sceneDone) { + if (_vm->_timers[0] == 0) { + // Update background animations (clouds etc.) + --bgX1; + bgX2 -= 2; + bgX3 -= 5; + --bgX4; + --bgX5; + --bgX6; + if (bgX1 <= -bgWidth1) + bgX1 = 799; + if (bgX2 <= -bgWidth2) + bgX2 = 799; + if (bgX3 <= -bgWidth3) + bgX3 = 799; + if (bgX4 <= -bgWidth4) + bgX4 = 799; + if (bgX5 <= -bgWidth5) + bgX5 = 799; + if (bgX6 <= -bgWidth6) + bgX6 = 799; + bgAnimToggle = !bgAnimToggle; + gameSys.insertSequence(0xC9, (bgAnimToggle ? 1 : 0) + 256, 0xC9, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX1, 85); + gameSys.insertSequence(0xCA, (bgAnimToggle ? 1 : 0) + 257, 0xCA, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX2, 100); + gameSys.insertSequence(0xC4, (bgAnimToggle ? 1 : 0) + 256, 0xC4, (bgAnimToggle ? 0 : 1) + 256, kSeqSyncWait, 0, bgX3, 140); + gameSys.insertSequence(0xC5, (bgAnimToggle ? 1 : 0) + 257, 0xC5, (bgAnimToggle ? 0 : 1) + 257, kSeqSyncWait, 0, bgX4, 160); + gameSys.insertSequence(0xC6, (bgAnimToggle ? 1 : 0) + 258, 0xC6, (bgAnimToggle ? 0 : 1) + 258, kSeqSyncWait, 0, bgX5, 140); + gameSys.insertSequence(0xC7, (bgAnimToggle ? 1 : 0) + 259, 0xC7, (bgAnimToggle ? 0 : 1) + 259, kSeqSyncWait, 0, bgX6, 140); + _vm->_timers[0] = 2; + } + + if (gameSys.getAnimationStatus(1) == 2) { + streetAnimToggle = !streetAnimToggle; + gameSys.setAnimation(0xC8, (streetAnimToggle ? 1 : 0) + 251, 1); + gameSys.insertSequence(0xC8, (streetAnimToggle ? 1 : 0) + 251, 200, (streetAnimToggle ? 0 : 1) + 251, kSeqSyncWait, 0, 0, -50); + } + + checkObstacles(); + + if (gameSys.getAnimationStatus(0) == 2) { + switch (_truckSequenceId) { + case 0xB1: + _truckLaneNum = 1; + break; + case 0xB0: + case 0xB3: + _truckLaneNum = 2; + break; + case 0xB2: + _truckLaneNum = 3; + break; + } + animToggle3 = !animToggle3; + if (_truckLaneNum == 1) { + gameSys.setAnimation(0xAD, (animToggle3 ? 1 : 0) + 256, 0); + gameSys.insertSequence(0xAD, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50); + _truckSequenceId = 0xAD; + } else if (_truckLaneNum == 2) { + gameSys.setAnimation(0xAE, (animToggle3 ? 1 : 0) + 256, 0); + gameSys.insertSequence(0xAE, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50); + _truckSequenceId = 0xAE; + } else { + gameSys.setAnimation(0xAF, (animToggle3 ? 1 : 0) + 256, 0); + gameSys.insertSequence(0xAF, (animToggle3 ? 1 : 0) + 256, _truckSequenceId, _truckId, kSeqSyncWait, 0, 0, -50); + _truckSequenceId = 0xAF; + } + _truckId = (animToggle3 ? 1 : 0) + 256; + if (_scoreLevel == 1) { + if (!gameSys.isSequenceActive(0xD4, 266)) { + gameSys.setAnimation(0xD4, 266, 8); + gameSys.insertSequence(0xD4, 266, 0, 0, kSeqNone, 0, 0, -50); + } + ++_scoreLevel; + _vm->_timers[1] = 2; + animToggle4 = false; + animToggle5 = false; + animToggle6 = false; + _scoreBarFlash = false; + } + } + + if (_scoreLevel != 0 && !_vm->_timers[1]) { + refreshScoreBar(); + _vm->_timers[1] = 8; + if (animToggle6) { + if (animToggle5) { + if (animToggle4 && !gameSys.isSequenceActive(212, 266)) + gameSys.insertSequence(212, 266, 0, 0, kSeqNone, 0, 0, -50); + animToggle4 = !animToggle4; + } + animToggle5 = !animToggle5; + } + animToggle6 = !animToggle6; + } + + updateAnimations(); + + if (clearKeyStatus()) { + _vm->_sceneDone = true; + _vm->_newSceneNum = 2; + _vm->_newCursorValue = 1; + } + + if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) { + // Steer right + if (_truckSequenceId == 0xB3) + _truckLaneNum = 2; + if (_truckSequenceId == 0xB1) + _truckLaneNum = 1; + if (_truckLaneNum != 3 && _truckLaneNum != 2) { + if (_scoreLevel) { + _vm->_sceneDone = true; + _vm->_newSceneNum = 47; + } + } else { + int steerSequenceId = (_truckLaneNum == 3) ? 0xB3 : 0xB1; + if (_truckSequenceId == 0xAE || _truckSequenceId == 0xAF) { + gameSys.setAnimation(steerSequenceId, 256, 0); + gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50); + _truckSequenceId = steerSequenceId; + _truckId = 256; + } + } + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + } + + if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) { + // Steer left + if (_truckSequenceId == 0xB0) + _truckLaneNum = 2; + if (_truckSequenceId == 0xB2) + _truckLaneNum = 3; + if (_truckLaneNum == 1 || _truckLaneNum == 2) { + int steerSequenceId = (_truckLaneNum == 1) ? 0xB0 : 0xB2; + if (_truckSequenceId == 0xAD || _truckSequenceId == 0xAE) { + gameSys.setAnimation(steerSequenceId, 256, 0); + gameSys.insertSequence(steerSequenceId, 256, _truckSequenceId, _truckId, kSeqSyncExists, 0, 0, -50); + _truckSequenceId = steerSequenceId; + _truckId = 256; + } + } + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + } + _vm->gameUpdateTick(); + } + _vm->stopSound(0xE2); +} + +void Scene49::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + + for (int i = 0; i < 5; ++i) { + if (gameSys.getAnimationStatus(i + 2) == 2) { + if (_obstacles[i]._currSequenceId) + updateObstacle(i); + } + } + + if (gameSys.getAnimationStatus(8) == 2) { + _vm->_sceneDone = true; + _vm->_newSceneNum = 47; + } +} + +/*****************************************************************************/ + +Scene50::Scene50(GnapEngine *vm) : Scene(vm) { + _fightDone = false; + + _roundNum = -1; + _timeRemaining = -1; + _leftTongueRoundsWon = -1; + _rightTongueRoundsWon = -1; + _leftTongueSequenceId = -1; + _leftTongueId = -1; + _leftTongueNextSequenceId = -1; + _leftTongueNextId = -1; + _rightTongueSequenceId = -1; + _rightTongueId = -1; + _rightTongueNextSequenceId = -1; + _rightTongueNextId = -1; + _leftTongueEnergy = -1; + _rightTongueEnergy = -1; + + _timesPlayed = 0; + _timesPlayedModifier = 0; + _attackCounter = 0; + _leftTongueEnergyBarPos = 10; + _leftTongueNextIdCtr = 0; + _rightTongueEnergyBarPos = 10; + _rightTongueNextIdCtr = 0; +} + +int Scene50::init() { + return 0xC7; +} + +void Scene50::updateHotspots() { + _vm->_hotspotsCount = 0; +} + +bool Scene50::tongueWinsRound(int tongueNum) { + if (tongueNum == 1) + ++_leftTongueRoundsWon; + else + ++_rightTongueRoundsWon; + playWinBadgeAnim(tongueNum); + bool fightOver = _rightTongueRoundsWon == 2 || _leftTongueRoundsWon == 2; + playWinAnim(tongueNum, fightOver); + return fightOver; +} + +void Scene50::playWinAnim(int tongueNum, bool fightOver) { + if (tongueNum == 1) { + if (fightOver) { + _vm->_gameSys->insertSequence(0xAD, 140, 0xAC, 140, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0); + _leftTongueSequenceId = 0xB4; + _rightTongueSequenceId = 0xBC; + _rightTongueId = 100; + _leftTongueId = 100; + _vm->_gameSys->setAnimation(0xB4, 100, 6); + _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5); + waitForAnim(6); + waitForAnim(5); + _vm->invAdd(kItemGum); + _vm->setFlag(kGFUnk13); + } else { + _vm->_gameSys->insertSequence(0xB4, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xBD, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xBC, 100, 0xBD, 100, kSeqSyncWait, 0, 0, 0); + _leftTongueSequenceId = 0xB4; + _rightTongueSequenceId = 0xBC; + _rightTongueId = 100; + _leftTongueId = 100; + _vm->_gameSys->setAnimation(0xB4, 100, 6); + _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5); + waitForAnim(6); + waitForAnim(5); + } + } else { + _vm->_gameSys->insertSequence(0xBE, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->setAnimation(0xBE, 100, 5); + waitForAnim(5); + _vm->_gameSys->insertSequence(0xBF, 100, 0xBE, 100, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xB5, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _rightTongueSequenceId = 0xBF; + _leftTongueSequenceId = 0xB5; + _rightTongueId = 100; + _leftTongueId = 100; + _vm->_gameSys->setAnimation(0xB5, 100, 6); + _vm->_gameSys->setAnimation(_rightTongueSequenceId, 100, 5); + waitForAnim(6); + waitForAnim(5); + } + _vm->delayTicksA(1, 7); +} + +void Scene50::delayTicks() { + _vm->delayTicksA(3, 7); +} + +void Scene50::initRound() { + _leftTongueEnergy = 10; + _rightTongueEnergy = 10; + _fightDone = false; + _vm->_timers[3] = getRightTongueActionTicks(); + _vm->_timers[4] = 0; + _vm->_timers[6] = 0; + _vm->_gameSys->fillSurface(nullptr, 91, 73, 260, 30, 212, 0, 0); + _vm->_gameSys->fillSurface(nullptr, 450, 73, 260, 30, 212, 0, 0); + _timeRemaining = 40; + drawCountdown(40); +} + +bool Scene50::updateCountdown() { + if (!_vm->_timers[5]) { + --_timeRemaining; + if (_timeRemaining < 0) { + return true; + } else { + _vm->_timers[5] = 15; + drawCountdown(_timeRemaining); + } + } + return false; +} + +void Scene50::drawCountdown(int value) { + char str[8]; + sprintf(str, "%02d", value); + _vm->_gameSys->fillSurface(nullptr, 371, 505, 50, 27, 0, 0, 0); + _vm->_gameSys->drawTextToSurface(nullptr, 381, 504, 255, 255, 255, str); +} + +void Scene50::playTonguesIdle() { + _vm->_gameSys->insertSequence(0xBA, 100, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xC2, 100, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0); + _leftTongueSequenceId = 0xBA; + _rightTongueSequenceId = 0xC2; + _rightTongueNextSequenceId = -1; + _leftTongueNextSequenceId = -1; + _leftTongueId = 100; + _rightTongueId = 100; + _vm->_gameSys->setAnimation(0xC2, 100, 5); + _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6); +} + +void Scene50::playRoundAnim(int roundNum) { + int sequenceId = 0; + + switch (roundNum) { + case 1: + sequenceId = 0xAF; + break; + case 2: + sequenceId = 0xB0; + break; + case 3: + sequenceId = 0xB1; + break; + } + + _vm->_gameSys->insertSequence(sequenceId, 256, 0, 0, kSeqNone, 0, 0, 0); + _vm->_gameSys->setAnimation(sequenceId, 256, 7); + waitForAnim(7); + + _vm->_gameSys->insertSequence(0xAB, 256, sequenceId, 256, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->setAnimation(0xAB, 256, 7); + waitForAnim(7); +} + +bool Scene50::updateEnergyBars(int newLeftBarPos, int newRightBarPos) { + if (newLeftBarPos != _leftTongueEnergyBarPos) { + if (newLeftBarPos < 0) + newLeftBarPos = 0; + _leftTongueEnergyBarPos = newLeftBarPos; + _vm->_gameSys->fillSurface(nullptr, 26 * newLeftBarPos + 91, 73, 260 - 26 * newLeftBarPos, 30, 0, 0, 0); + } + + if (newRightBarPos != _rightTongueEnergyBarPos) { + if (newRightBarPos < 0) + newRightBarPos = 0; + _rightTongueEnergyBarPos = newRightBarPos; + if (newRightBarPos != 10) + _vm->_gameSys->fillSurface(nullptr, 26 * (9 - newRightBarPos) + 450, 73, 26, 30, 0, 0, 0); + } + + if (newLeftBarPos * newRightBarPos > 0) + return false; + + _leftTongueEnergyBarPos = 10; + _rightTongueEnergyBarPos = 10; + return true; +} + +void Scene50::waitForAnim(int animationIndex) { + GameSys& gameSys = *_vm->_gameSys; + + while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + gameSys.setAnimation(0, 0, animationIndex); +} + +int Scene50::checkInput() { + int sequenceId = -1; + + if (_vm->isKeyStatus1(Common::KEYCODE_RIGHT)) { + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + sequenceId = 0xB6; + } else if (_vm->isKeyStatus1(Common::KEYCODE_LEFT)) { + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + sequenceId = 0xB3; + } else if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) { + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _fightDone = true; + } + + return sequenceId; +} + +int Scene50::getRightTongueAction() { + int sequenceId = -1; + + if (!_vm->_timers[3]) { + _vm->_timers[3] = getRightTongueActionTicks(); + if (_rightTongueEnergy >= _leftTongueEnergy) { + switch (_vm->getRandom(5)) { + case 0: + sequenceId = 0xBE; + break; + case 1: + sequenceId = 0xBE; + break; + case 2: + sequenceId = 0xBB; + break; + case 3: + sequenceId = 0xBB; + break; + case 4: + sequenceId = 0xBB; + break; + } + } else { + switch (_vm->getRandom(4)) { + case 0: + sequenceId = 0xBE; + break; + case 1: + sequenceId = 0xBB; + break; + case 2: + sequenceId = 0xBE; + break; + case 3: + sequenceId = 0xBE; + break; + } + } + } + + return sequenceId; +} + +void Scene50::updateAnimations() { + if (!_vm->_timers[4]) + _attackCounter = 0; + + if (_vm->_gameSys->getAnimationStatus(5) == 2) { + if (_rightTongueSequenceId == 0xBE) { + if (_leftTongueSequenceId != 0xB3 && _leftTongueSequenceId != 0xB8) + _rightTongueNextSequenceId = 0xBF; + else + _rightTongueNextSequenceId = 0xC0; + } + if (_rightTongueNextSequenceId == -1) + _rightTongueNextSequenceId = 0xC2; + if (_rightTongueNextSequenceId == 0xBF) { + _leftTongueNextId = getLeftTongueNextId(); + _rightTongueNextId = getRightTongueNextId(); + _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5); + _vm->_gameSys->setAnimation(0xB9, _leftTongueNextId, 6); + _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xB9, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncExists, 0, 0, 0); + _rightTongueSequenceId = _rightTongueNextSequenceId; + _rightTongueNextSequenceId = -1; + _leftTongueSequenceId = 0xB9; + _leftTongueNextSequenceId = -1; + _rightTongueId = _rightTongueNextId; + _leftTongueId = _leftTongueNextId; + _leftTongueEnergy -= _vm->getRandom(1) + 1; + } else { + _rightTongueNextId = getRightTongueNextId(); + _vm->_gameSys->setAnimation(_rightTongueNextSequenceId, _rightTongueNextId, 5); + _vm->_gameSys->insertSequence(_rightTongueNextSequenceId, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncWait, 0, 0, 0); + _rightTongueSequenceId = _rightTongueNextSequenceId; + _rightTongueNextSequenceId = -1; + _rightTongueId = _rightTongueNextId; + } + } + + if (_vm->_gameSys->getAnimationStatus(6) == 2) { + if (_leftTongueSequenceId == 0xB6) { + ++_attackCounter; + if (_timesPlayedModifier + 3 <= _attackCounter) { + _leftTongueNextSequenceId = 0xB8; + } else { + _vm->_timers[4] = 20; + if (_rightTongueSequenceId != 0xBB && _rightTongueSequenceId != 0xC0 && _vm->getRandom(7) != _roundNum) + _leftTongueNextSequenceId = 0xB7; + else + _leftTongueNextSequenceId = 0xB8; + } + } + if (_leftTongueNextSequenceId == 0xB3) + --_attackCounter; + if (_leftTongueNextSequenceId == -1) + _leftTongueNextSequenceId = 0xBA; + if (_leftTongueNextSequenceId == 0xB7) { + _leftTongueNextId = getLeftTongueNextId(); + _rightTongueNextId = getRightTongueNextId(); + _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6); + _vm->_gameSys->setAnimation(0xC1, _rightTongueNextId, 5); + _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xC1, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0); + _leftTongueSequenceId = _leftTongueNextSequenceId; + _leftTongueNextSequenceId = -1; + _rightTongueSequenceId = 0xC1; + _rightTongueNextSequenceId = -1; + _rightTongueId = _rightTongueNextId; + _leftTongueId = _leftTongueNextId; + --_rightTongueEnergy; + } else if (_leftTongueNextSequenceId != 0xB8 || _rightTongueSequenceId != 0xC2) { + _leftTongueNextId = getLeftTongueNextId(); + _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6); + _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _leftTongueSequenceId = _leftTongueNextSequenceId; + _leftTongueNextSequenceId = -1; + _leftTongueId = _leftTongueNextId; + } else { + _leftTongueNextId = getLeftTongueNextId(); + _rightTongueNextId = getRightTongueNextId(); + _vm->_gameSys->setAnimation(0xBB, _rightTongueNextId, 5); + _vm->_gameSys->setAnimation(_leftTongueNextSequenceId, _leftTongueNextId, 6); + _vm->_gameSys->insertSequence(_leftTongueNextSequenceId, _leftTongueNextId, _leftTongueSequenceId, _leftTongueId, kSeqSyncWait, 0, 0, 0); + _vm->_gameSys->insertSequence(0xBB, _rightTongueNextId, _rightTongueSequenceId, _rightTongueId, kSeqSyncExists, 0, 0, 0); + _rightTongueSequenceId = 0xBB; + _rightTongueId = _rightTongueNextId; + _rightTongueNextSequenceId = -1; + _leftTongueSequenceId = _leftTongueNextSequenceId; + _leftTongueNextSequenceId = -1; + _leftTongueId = _leftTongueNextId; + } + } +} + +int Scene50::getRightTongueActionTicks() { + return 15 - 5 * _roundNum + 1; +} + +int Scene50::getLeftTongueNextId() { + _leftTongueNextIdCtr = (_leftTongueNextIdCtr + 1) % 3; + return _leftTongueNextIdCtr + 100; +} + +int Scene50::getRightTongueNextId() { + _rightTongueNextIdCtr = (_rightTongueNextIdCtr + 1) % 3; + return _rightTongueNextIdCtr + 100; +} + +void Scene50::playWinBadgeAnim(int tongueNum) { + int sequenceId; + + if (tongueNum == 1) { + if (_leftTongueRoundsWon == 1) + sequenceId = 0xC3; + else + sequenceId = 0xC4; + } else { + if (_rightTongueRoundsWon == 1) + sequenceId = 0xC5; + else + sequenceId = 0xC6; + } + + _vm->_gameSys->setAnimation(sequenceId, 120, 7); + _vm->_gameSys->insertSequence(sequenceId, 120, 0, 0, kSeqNone, 0, 0, 0); + waitForAnim(7); +} + +void Scene50::run() { + ++_timesPlayed; + _timesPlayedModifier = _timesPlayed / 4; + _leftTongueRoundsWon = 0; + _rightTongueRoundsWon = 0; + // initFont(); + _leftTongueSequenceId = 186; + _rightTongueSequenceId = 194; + _rightTongueNextSequenceId = -1; + _leftTongueNextSequenceId = -1; + _leftTongueId = 100; + _rightTongueId = 100; + + _vm->_gameSys->setAnimation(194, 100, 5); + _vm->_gameSys->setAnimation(_leftTongueSequenceId, _leftTongueId, 6); + _vm->_gameSys->insertSequence(_leftTongueSequenceId, _leftTongueId, 0, 0, kSeqNone, 0, 0, 0); + _vm->_gameSys->insertSequence(_rightTongueSequenceId, _rightTongueId, 0, 0, kSeqNone, 0, 0, 0); + _vm->_gameSys->insertSequence(172, 140, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + + initRound(); + + _roundNum = 1; + + _vm->setGrabCursorSprite(-1); + _vm->hideCursor(); + + _vm->delayTicksA(1, 7); + + playRoundAnim(_roundNum); + + _vm->_timers[5] = 15; + + while (!_fightDone && !_vm->_gameDone) { + int playerSequenceId = checkInput(); + if (playerSequenceId != -1) + _leftTongueNextSequenceId = playerSequenceId; + + int rightSequenceId = getRightTongueAction(); + if (rightSequenceId != -1) + _rightTongueNextSequenceId = rightSequenceId; + + updateAnimations(); + + if (updateCountdown() || + updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy)) { + bool v0; + if (_rightTongueEnergy < _leftTongueEnergy) + v0 = tongueWinsRound(1); + else + v0 = tongueWinsRound(2); + if (v0) { + delayTicks(); + _fightDone = true; + } else { + ++_roundNum; + initRound(); + playTonguesIdle(); + updateEnergyBars(_leftTongueEnergy, _rightTongueEnergy); + playRoundAnim(_roundNum); + _vm->_timers[5] = 15; + } + } + _vm->gameUpdateTick(); + } + + _vm->_gameSys->setAnimation(0, 0, 7); + _vm->_gameSys->setAnimation(0, 0, 6); + _vm->_gameSys->setAnimation(0, 0, 5); + _vm->_gameSys->setAnimation(0, 0, 3); + + _vm->showCursor(); +} + +/*****************************************************************************/ + +static const int kDigitSequenceIds[] = { + 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, + 0xCF, 0xD0, 0xD1, 0xD2, 0xD3 +}; + +static const int kDigitPositions[4] = { + 0, 34, 83, 119 +}; + +/* + 0xBA Falling banana peel + 0xBC Banana peel goes away + 0xBD Falling coin + 0xBE Fallen coin + 0xC0 Falling banknote + 0xB6 Platypus tripping (right) + 0xB7 Platypus tripping (left) + 0x76 Platypus jumping (right) +*/ + +Scene51::Scene51(GnapEngine *vm) : Scene(vm) { + _dropLoseCash = false; + + _cashAmount = -1; + _guySequenceId = -1; + _guyNextSequenceId = -1; + _itemsCaughtCtr = -1; + _dropSpeedTicks = -1; + _nextDropItemKind = -1; + _itemInsertX = -1; + _itemInsertDirection = -1; + _platypusNextSequenceId = -1; + _platypusJumpSequenceId = -1; + _itemsCtr = -1; + _itemsCtr1 = -1; + _itemsCtr2 = -1; + + for (int i = 0; i < 4; i++) { + _digits[i] = 0; + _digitSequenceIds[i] = -1; + } + + for (int i = 0; i < 6; i++) { + _items[i]._currSequenceId = -1; + _items[i]._droppedSequenceId = 0; + _items[i]._x = 0; + _items[i]._y = 0; + _items[i]._collisionX = 0; + _items[i]._canCatch = false; + _items[i]._isCollision = false; + _items[i]._x2 = 0; + _items[i]._id = -1; + } +} + +int Scene51::init() { + _vm->_gameSys->setAnimation(0, 0, 0); + for (int i = 0; i < 6; ++i) + _vm->_gameSys->setAnimation(0, 0, i + 1); + return 0xD4; +} + +void Scene51::updateHotspots() { + _vm->_hotspotsCount = 0; +} + +void Scene51::clearItem(Scene51Item *item) { + item->_currSequenceId = 0; + item->_droppedSequenceId = 0; + item->_x = 0; + item->_y = 0; + item->_x2 = 0; + item->_collisionX = 0; + item->_canCatch = false; +} + +void Scene51::dropNextItem() { + if (_vm->_timers[0]) + return; + + int index = 0; + while (index < 6 && _items[index]._currSequenceId) + ++index; + + if (index == 6) + return; + + switch (_nextDropItemKind) { + case 0: + if (_vm->getRandom(10) != 0 || _itemsCtr2 >= 2) { + _items[index]._currSequenceId = 0xBD; + } else { + --_itemsCtr1; + _items[index]._currSequenceId = 0xBA; + ++_itemsCtr2; + } + break; + + case 1: + if (_vm->getRandom(8) != 0 || _itemsCtr2 >= 2) { + if (_vm->getRandom(5) == 0) { + if (_itemInsertDirection) + _itemInsertX -= 70; + else + _itemInsertX += 70; + } + _items[index]._currSequenceId = 0xBD; + } else { + --_itemsCtr1; + _items[index]._currSequenceId = 0xBA; + ++_itemsCtr2; + } + break; + + case 2: + if (_vm->getRandom(6) != 0 || _itemsCtr2 >= 2) { + _items[index]._currSequenceId = 0xBD; + } else { + --_itemsCtr1; + _items[index]._currSequenceId = 0xBA; + ++_itemsCtr2; + } + break; + + case 3: + case 4: + if (_itemsCtr == 0) + _itemsCtr1 = 3; + _items[index]._currSequenceId = 0xC0; + break; + + case 5: + case 6: + if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) { + if (_vm->getRandom(5) != 0) + _items[index]._currSequenceId = 0xBD; + else + _items[index]._currSequenceId = 0xC0; + } else { + --_itemsCtr1; + _items[index]._currSequenceId = 0xBA; + ++_itemsCtr2; + } + break; + + case 7: + if (_vm->getRandom(5) != 0 || _itemsCtr2 >= 2) { + if (_vm->getRandom(5) == 0) { + if (_itemInsertDirection) + _itemInsertX -= 40; + else + _itemInsertX += 40; + } + if (_vm->getRandom(9) != 0) + _items[index]._currSequenceId = 0xBD; + else + _items[index]._currSequenceId = 0xC0; + } else { + --_itemsCtr1; + _items[index]._currSequenceId = 0xBA; + ++_itemsCtr2; + } + break; + + default: + if (_vm->getRandom(4) != 0 || _itemsCtr2 >= 2) { + if (_vm->getRandom(9) != 0) + _items[index]._currSequenceId = 0xBD; + else + _items[index]._currSequenceId = 0xC0; + } else { + --_itemsCtr1; + _items[index]._currSequenceId = 0xBA; + ++_itemsCtr2; + } + break; + } + + if (_itemInsertDirection) { + _itemInsertX -= 73; + if (_itemInsertX < 129) { + _itemInsertX += 146; + _itemInsertDirection = 0; + } + } else { + _itemInsertX += 73; + if (_itemInsertX > 685) { + _itemInsertX -= 146; + _itemInsertDirection = 1; + } + } + + if (_itemInsertX > 685) + _itemInsertX = 685; + + if (_itemInsertX < 129) + _itemInsertX = 129; + + if (_items[index]._currSequenceId == 0xBA) { + _items[index]._x2 = _vm->getRandom(350) + 200; + _items[index]._x = _items[index]._x2 - 362; + _items[index]._y = 15; + _items[index]._id = 249 - index; + } else { + _items[index]._collisionX = _itemInsertX; + _items[index]._x = _items[index]._collisionX - 395; + if (_items[index]._currSequenceId == 0xC0) + _items[index]._x -= 65; + _items[index]._id = index + 250; + _items[index]._canCatch = true; + } + + _vm->_gameSys->setAnimation(_items[index]._currSequenceId, _items[index]._id, index + 1); + _vm->_gameSys->insertSequence(_items[index]._currSequenceId, _items[index]._id, 0, 0, + kSeqNone, 0, _items[index]._x, _items[index]._y); + + _vm->_timers[0] = _dropSpeedTicks; + + if (_nextDropItemKind >= 3) + _vm->_timers[0] = 20; + + if (_nextDropItemKind >= 5) + _vm->_timers[0] = 5; + + if (_nextDropItemKind == 8) + _vm->_timers[0] = 4; + + ++_itemsCtr; +} + +void Scene51::updateItemAnimations() { + for (int i = 0; i < 6; ++i) { + if (_vm->_gameSys->getAnimationStatus(i + 1) == 2) + updateItemAnimation(&_items[i], i); + } +} + +int Scene51::checkCollision(int sequenceId) { + if (!isJumping(sequenceId)) + return false; + + bool jumpingLeft = false, jumpingRight = false; + int v8 = 0, v4 = 0; + int result = 0; + + bool checkFl = false; + for (int i = 0; i < 6; i++) + checkFl |= _items[i]._isCollision; + + if (!checkFl) + return false; + + if (isJumpingRight(sequenceId)) { + v8 = getPosRight(sequenceId); + v4 = getPosRight(sequenceId + 1); + jumpingRight = true; + } else if (isJumpingLeft(sequenceId)) { + v4 = getPosLeft(sequenceId - 1) + 33; + v8 = getPosLeft(sequenceId) + 33; + jumpingLeft = true; + } + + if (jumpingRight || jumpingLeft) { + int v5 = 0; + int i; + for (i = 0; i < 6; ++i) { + if (_items[i]._isCollision) { + if (jumpingRight && _items[i]._x2 > v8 && _items[i]._x2 < v4) { + v5 = v8 - 359; + if (v5 == 0) + v5 = 1; + _platypusNextSequenceId = 0xB6; + break; + } else if (jumpingLeft && _items[i]._x2 < v4 && _items[i]._x2 > v8) { + v5 = v8 - 344; + if (v5 == 0) + v5 = 1; + _platypusNextSequenceId = 0xB7; + break; + } + } + } + if (v5) { + _vm->_gameSys->setAnimation(0xBC, _items[i]._id, i + 1); + _vm->_gameSys->insertSequence(0xBC, _items[i]._id, _items[i]._currSequenceId, _items[i]._id, kSeqSyncWait, 0, _items[i]._x, 15); + _items[i]._isCollision = false; + _items[i]._currSequenceId = 0xBC; + --_itemsCtr2; + } + result = v5; + } + + return result; +} + +void Scene51::updateItemAnimation(Scene51Item *item, int index) { + + switch (item->_currSequenceId) { + case 0xBD: + case 0xC0: + case 0xC1: + // Falling coin and banknote + if (!itemIsCaught(item)) { + if (_dropLoseCash) { + if (item->_currSequenceId == 0xBD) + _cashAmount -= 2; + else + _cashAmount -= 25; + if (_cashAmount < 0) + _cashAmount = 0; + updateCash(_cashAmount); + } + item->_droppedSequenceId = item->_currSequenceId + 1; + if (item->_currSequenceId != 0xC0) { + item->_canCatch = false; + _dropLoseCash = true; + _itemsCtr = 0; + _vm->_timers[0] = 10; + } + if (item->_droppedSequenceId) { + _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1); + _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y); + item->_currSequenceId = item->_droppedSequenceId; + item->_y = 0; + } + } else { + _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true); + _vm->_gameSys->setAnimation(0, 0, index + 1); + _vm->playSound(0xDA, false); + if (incCashAmount(item->_currSequenceId) == 1995) { + winMinigame(); + _vm->_sceneDone = true; + } else { + clearItem(item); + ++_itemsCaughtCtr; + if (_itemsCaughtCtr == 5) + --_dropSpeedTicks; + if (_itemsCaughtCtr == 8) + --_dropSpeedTicks; + if (_itemsCaughtCtr == 11) + --_dropSpeedTicks; + if (_itemsCaughtCtr == 14) + --_dropSpeedTicks; + if (_itemsCaughtCtr >= 15 && _dropSpeedTicks > 4) + --_dropSpeedTicks; + if (_itemsCtr1 <= _itemsCaughtCtr) { + ++_nextDropItemKind; + _dropSpeedTicks = 10; + _itemsCtr = 0; + _itemsCtr1 = 20; + _dropLoseCash = false; + _itemsCaughtCtr = 0; + removeCollidedItems(); + } + } + } + break; + + case 0xBE: + // Fallen coin + item->_droppedSequenceId = item->_currSequenceId + 1; + if (item->_droppedSequenceId) { + _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1); + _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y); + item->_currSequenceId = item->_droppedSequenceId; + item->_y = 0; + } + break; + + case 0xBF: + case 0xC2: + // Bouncing coin and banknote + _vm->_gameSys->setAnimation(0, 0, index + 1); + _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true); + clearItem(item); + break; + + case 0xBA: + // Falling banana peel + item->_droppedSequenceId = 0xBB; + item->_y = 15; + if (item->_droppedSequenceId) { + _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1); + _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y); + item->_currSequenceId = item->_droppedSequenceId; + item->_y = 0; + } + break; + + case 0xBB: + item->_isCollision = true; + item->_droppedSequenceId = 0; + _vm->_gameSys->setAnimation(0, 0, index + 1); + break; + + case 0xBC: + _vm->_gameSys->removeSequence(item->_currSequenceId, item->_id, true); + _vm->_gameSys->setAnimation(0, 0, index + 1); + clearItem(item); + break; + + default: + if (item->_droppedSequenceId) { + _vm->_gameSys->setAnimation(item->_droppedSequenceId, item->_id, index + 1); + _vm->_gameSys->insertSequence(item->_droppedSequenceId, item->_id, item->_currSequenceId, item->_id, kSeqSyncWait, 0, item->_x, item->_y); + item->_currSequenceId = item->_droppedSequenceId; + item->_y = 0; + } + break; + } +} + +void Scene51::removeCollidedItems() { + for (int i = 0; i < 6; ++i) { + if (_items[i]._isCollision) { + _vm->_gameSys->removeSequence(_items[i]._currSequenceId, _items[i]._id, true); + _vm->_gameSys->setAnimation(0, 0, i + 1); + clearItem(&_items[i]); + } + } + _itemsCtr2 = 0; +} + +int Scene51::itemIsCaught(Scene51Item *item) { + if (!item->_canCatch) + return 0; + + if (isJumpingRight(_platypusJumpSequenceId)) { + int v4 = getPosRight(_platypusJumpSequenceId) + 97; + if (item->_collisionX < v4 && v4 - item->_collisionX < 56) + return 1; + } else { + int v2 = getPosLeft(_platypusJumpSequenceId); + if (item->_collisionX > v2 && item->_collisionX - v2 < 56) + return 1; + } + + if (item->_currSequenceId == 0xC1) { + int v3 = item->_collisionX + 100; + if (isJumpingRight(_platypusJumpSequenceId)) { + if (ABS(getPosRight(_platypusJumpSequenceId) + 46 - v3) < 56) + return 1; + } else if (ABS(getPosLeft(_platypusJumpSequenceId) + 46 - v3) < 56) { + return 1; + } + } + + return 0; +} + +bool Scene51::isJumpingRight(int sequenceId) { + return sequenceId >= 0x76 && sequenceId <= 0x95; +} + +bool Scene51::isJumpingLeft(int sequenceId) { + return sequenceId >= 0x96 && sequenceId <= 0xB5; +} + +bool Scene51::isJumping(int sequenceId) { + return sequenceId >= 0x76 && sequenceId <= 0xB5; +} + +void Scene51::waitForAnim(int animationIndex) { + while (_vm->_gameSys->getAnimationStatus(animationIndex) != 2 && _vm->_gameDone) { + updateItemAnimations(); + _vm->gameUpdateTick(); + } +} + +int Scene51::getPosRight(int sequenceId) { + static const int kRightPosTbl[] = { + 131, 159, 178, 195, 203, 219, 238, 254, + 246, 274, 293, 310, 318, 334, 353, 369, + 362, 390, 409, 426, 434, 450, 469, 485, + 477, 505, 524, 541, 549, 565, 584, 600 + }; + + if (sequenceId >= 118 && sequenceId <= 149) + return kRightPosTbl[sequenceId - 118]; + return -1; +} + +int Scene51::getPosLeft(int sequenceId) { + static const int kLeftPosTbl[] = { + 580, 566, 550, 536, 526, 504, 488, 469, + 460, 446, 430, 416, 406, 384, 368, 349, + 342, 328, 312, 298, 288, 266, 250, 231, + 220, 206, 190, 176, 166, 144, 128, 109 + }; + + if (sequenceId >= 150 && sequenceId <= 181) + return kLeftPosTbl[sequenceId - 150]; + return -1; +} + +void Scene51::playIntroAnim() { + int soundCtr = 0; + + _platypusSequenceId = 0x76; + _platypusNextSequenceId = 0x76; + + for (int i = 0; i < 6; ++i) + clearItem(&_items[i]); + + _items[0]._currSequenceId = 0xBA; + _items[0]._x2 = 320; + _items[0]._x = -42; + _items[0]._y = 15; + _items[0]._id = 249; + _items[0]._isCollision = true; + + _vm->_gameSys->insertSequence(_platypusSequenceId, 256, 0, 0, kSeqNone, 0, -179, 0); + _vm->_gameSys->insertSequence(0xBA, 249, 0, 0, kSeqNone, 0, _items[0]._x, _items[0]._y); + _vm->_gameSys->setAnimation(0xBA, 249, 1); + _vm->_gameSys->setAnimation(_platypusSequenceId, 256, 0); + + while (_platypusSequenceId < 0x80) { + waitForAnim(0); + ++_platypusNextSequenceId; + _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0); + _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, -179, 0); + _platypusSequenceId = _platypusNextSequenceId; + ++soundCtr; + if (soundCtr % 4 == 0) + _vm->playSound(0xD6, false); + } + + _platypusNextSequenceId = 0x75; + + while (_platypusSequenceId != 0x84) { + waitForAnim(0); + ++_platypusNextSequenceId; + int oldSequenceId = _platypusNextSequenceId; + int v0 = checkCollision(_platypusNextSequenceId); + _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0); + _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, v0, 0); + _platypusSequenceId = _platypusNextSequenceId; + if (v0) { + _platypusNextSequenceId = oldSequenceId; + } else { + ++soundCtr; + if (soundCtr % 4 == 0) + _vm->playSound(0xD6, false); + } + } + waitForAnim(0); +} + +void Scene51::updateGuyAnimation() { + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 60; + + switch (_vm->getRandom(5)) { + case 0: + _guyNextSequenceId = 0xC3; + break; + case 1: + _guyNextSequenceId = 0xC4; + break; + case 2: + _guyNextSequenceId = 0xC5; + break; + case 3: + _guyNextSequenceId = 0xC6; + break; + case 4: + _guyNextSequenceId = 0xC7; + break; + } + + _vm->_gameSys->insertSequence(_guyNextSequenceId, 39, _guySequenceId, 39, kSeqSyncWait, 0, 0, 0); + _guySequenceId = _guyNextSequenceId; + _guyNextSequenceId = -1; + } +} + +int Scene51::incCashAmount(int sequenceId) { + switch (sequenceId) { + case 0xBD: + _cashAmount += 10; + break; + case 0xC0: + case 0xC1: + _cashAmount += 100; + break; + case 0xB6: + case 0xB7: + _cashAmount -= 10 * _vm->getRandom(5) + 50; + if (_cashAmount < 0) + _cashAmount = 0; + break; + } + if (_cashAmount > 1995) + _cashAmount = 1995; + updateCash(_cashAmount); + return _cashAmount; +} + +void Scene51::winMinigame() { + updateCash(1995); + _vm->playSound(0xDA, false); + _vm->delayTicksA(1, 5); + _vm->_newSceneNum = 48; + _vm->invRemove(kItemBanana); +} + +void Scene51::playCashAppearAnim() { + _vm->_gameSys->setAnimation(0xC8, 252, 0); + _vm->_gameSys->insertSequence(0xC8, 252, 0, 0, kSeqNone, 0, -20, -20); + + while (_vm->_gameSys->getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); +} + +void Scene51::updateCash(int amount) { + drawDigit(amount / 1000, 0); + drawDigit(amount / 100 % 10, 1); + drawDigit(amount / 10 % 10, 2); + drawDigit(amount % 10, 3); +} + +void Scene51::drawDigit(int digit, int position) { + if (digit != _digits[position]) { + _vm->_gameSys->insertSequence(kDigitSequenceIds[digit], 253 + position, + _digitSequenceIds[position], 253 + position, + kSeqSyncWait, 0, kDigitPositions[position] - 20, -20); + _digitSequenceIds[position] = kDigitSequenceIds[digit]; + _digits[position] = digit; + } +} + +void Scene51::initCashDisplay() { + for (int position = 0; position < 4; ++position) { + _digits[position] = 0; + _digitSequenceIds[position] = kDigitSequenceIds[0]; + _vm->_gameSys->insertSequence(kDigitSequenceIds[0], 253 + position, 0, 0, kSeqNone, 0, kDigitPositions[position] - 20, -20); + } + _cashAmount = 0; +} + +void Scene51::run() { + int soundCtr = 0; + bool isIdle = true; + + _itemsCtr = 0; + _vm->_newSceneNum = _vm->_prevSceneNum; + _cashAmount = 0; + _platypusJumpSequenceId = 0x84; + _vm->endSceneInit(); + + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + + _guySequenceId = 0xC3; + _guyNextSequenceId = -1; + + _vm->_gameSys->insertSequence(0xC3, 39, 0, 0, kSeqNone, 0, 0, 0); + _vm->_timers[4] = _vm->getRandom(20) + 60; + + playCashAppearAnim(); + initCashDisplay(); + playIntroAnim(); + + _platypusNextSequenceId = 0x74; + _vm->_gameSys->setAnimation(0x74, 256, 0); + _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0); + _platypusSequenceId = _platypusNextSequenceId; + + _itemInsertDirection = 0; + _itemInsertX = 685; + _dropSpeedTicks = 10; + _nextDropItemKind = 0; + + for (int i = 0; i < 6; ++i) + clearItem(&_items[i]); + + _itemInsertX = _vm->getRandom(556) + 129; + _vm->_timers[0] = 15; + + _itemsCaughtCtr = 0; + _dropLoseCash = false; + _itemsCtr1 = 20; + + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + + bool isCollision = false; + bool startWalk = true; + + while (!_vm->_sceneDone) { + if (clearKeyStatus()) + _vm->_sceneDone = true; + + _vm->gameUpdateTick(); + + updateGuyAnimation(); + dropNextItem(); + updateItemAnimations(); + + if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + if (isJumpingRight(_platypusJumpSequenceId)) { + waitForAnim(0); + _vm->_gameSys->setAnimation(0xB8, 256, 0); + _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0); + _platypusSequenceId = 0xB8; + waitForAnim(0); + _platypusNextSequenceId += 6; + if (_platypusNextSequenceId > 0x95) + _platypusNextSequenceId = 0x95; + _platypusJumpSequenceId = _platypusNextSequenceId; + } else { + waitForAnim(0); + _vm->_gameSys->setAnimation(0xB9, 256, 0); + _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0); + _platypusSequenceId = 0xB9; + waitForAnim(0); + _platypusNextSequenceId += 6; + if (_platypusNextSequenceId > 0xB5) + _platypusNextSequenceId = 0xB5; + _platypusJumpSequenceId = _platypusNextSequenceId; + } + isIdle = false; + } + + while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT) && _platypusNextSequenceId != 0x96 && !_vm->_gameDone) { + if (_platypusNextSequenceId == 0xB6) + _platypusNextSequenceId = 0x76; + updateItemAnimations(); + if (startWalk) { + _platypusNextSequenceId = 0x86; + startWalk = false; + } + + if (_vm->_gameSys->getAnimationStatus(0) == 2) { + int collisionX = checkCollision(_platypusNextSequenceId); + if (collisionX) + incCashAmount(_platypusNextSequenceId); + _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0); + _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0); + _platypusSequenceId = _platypusNextSequenceId; + if (collisionX) { + isCollision = true; + ++_platypusJumpSequenceId; + _platypusNextSequenceId = _platypusJumpSequenceId; + } else { + _platypusJumpSequenceId = _platypusNextSequenceId; + } + if (isJumpingRight(_platypusJumpSequenceId)) { + ++_platypusNextSequenceId; + if (!isCollision) { + if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + waitForAnim(0); + _vm->_gameSys->setAnimation(0xB8, 256, 0); + _vm->_gameSys->insertSequence(0xB8, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 348, 0); + _platypusSequenceId = 0xB8; + waitForAnim(0); + _platypusNextSequenceId += 6; + if (_platypusNextSequenceId > 0x95) + _platypusNextSequenceId = 0x95; + _platypusJumpSequenceId = _platypusNextSequenceId; + } else { + ++soundCtr; + if (soundCtr % 4 == 0) + _vm->playSound(0xD6, false); + } + } + } else { + _platypusNextSequenceId = 150 - (_platypusJumpSequenceId - 150); + } + isCollision = false; + isIdle = false; + } + _vm->gameUpdateTick(); + } + + while (_vm->isKeyStatus2(Common::KEYCODE_LEFT) && _platypusNextSequenceId != 0xB6 && !_vm->_gameDone) { + updateItemAnimations(); + if (startWalk) { + _platypusNextSequenceId = 0xA5; + startWalk = false; + } + + if (_vm->_gameSys->getAnimationStatus(0) == 2) { + int collisionX = checkCollision(_platypusNextSequenceId); + if (collisionX) + incCashAmount(_platypusNextSequenceId); + _vm->_gameSys->setAnimation(_platypusNextSequenceId, 256, 0); + _vm->_gameSys->insertSequence(_platypusNextSequenceId, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, collisionX, 0); + _platypusSequenceId = _platypusNextSequenceId; + if (collisionX) { + isCollision = true; + ++_platypusJumpSequenceId; + _platypusNextSequenceId = _platypusJumpSequenceId; + } else { + _platypusJumpSequenceId = _platypusNextSequenceId; + } + if (isJumpingLeft(_platypusJumpSequenceId)) { + ++_platypusNextSequenceId; + if (!isCollision) { + if (_vm->isKeyStatus2(Common::KEYCODE_UP) || _vm->isKeyStatus2(Common::KEYCODE_SPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + waitForAnim(0); + _vm->_gameSys->setAnimation(0xB9, 256, 0); + _vm->_gameSys->insertSequence(0xB9, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 338, 0); + _platypusSequenceId = 0xB9; + waitForAnim(0); + _platypusNextSequenceId += 6; + if (_platypusNextSequenceId > 0xB5) + _platypusNextSequenceId = 0xB5; + _platypusJumpSequenceId = _platypusNextSequenceId; + } else { + ++soundCtr; + if (soundCtr % 4 == 0) + _vm->playSound(0xD6, false); + } + } + } else { + _platypusNextSequenceId = 182 - (_platypusJumpSequenceId - 118); + } + isCollision = false; + isIdle = false; + } + _vm->gameUpdateTick(); + } + + if (!isIdle && _vm->_gameSys->getAnimationStatus(0) == 2) { + if (isJumpingRight(_platypusJumpSequenceId)) { + _vm->_gameSys->setAnimation(0x74, 256, 0); + _vm->_gameSys->insertSequence(0x74, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosRight(_platypusJumpSequenceId) - 362, 0); + _platypusSequenceId = 0x74; + } else { + _vm->_gameSys->setAnimation(0x75, 256, 0); + _vm->_gameSys->insertSequence(0x75, 256, _platypusSequenceId, 256, kSeqSyncWait, 0, getPosLeft(_platypusJumpSequenceId) - 341, 0); + _platypusSequenceId = 0x75; + } + waitForAnim(0); + isIdle = true; + } + } + + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + + _vm->_gameSys->setAnimation(0, 0, 0); + for (int i = 0; i < 6; ++i) + _vm->_gameSys->setAnimation(0, 0, i + 1); + + _vm->showCursor(); +} + +/*****************************************************************************/ + +Scene52::Scene52(GnapEngine *vm) : Scene(vm) { + _gameScore = 0; + _aliensInitialized = false; + _alienDirection = 0; + _soundToggle = false; +} + +int Scene52::init() { + initAnims(); + return 0x2B; +} + +void Scene52::updateHotspots() { + _vm->_hotspotsCount = 0; +} + +void Scene52::update() { + for (int rowNum = 0; rowNum < 7 && !_vm->_gameDone; ++rowNum) { + _vm->gameUpdateTick(); + if (_vm->_gameSys->getAnimationStatus(_alienRowAnims[rowNum]) == 2) { + updateAlienRow(rowNum); + rowNum = 0; + } + } + + if (_liveAlienRows == 0 && !_alienSingle) { + _alienWave = false; + _vm->playSound(0x30, false); + ++_alienCounter; + if (_alienCounter != 3) { + _vm->_timers[0] = 50; + _vm->_timers[2] = 100; + _alienRowDownCtr = 0; + _alienSingle = true; + } + } + + if (_alienSingle && !_vm->_timers[0]) { + initAliens(); + _alienSingle = false; + _vm->_timers[2] = 5; + _alienWave = true; + } + + if ((_alienRowDownCtr || _liveAlienRows == 0) && !_alienSingle) { + moveDownAlienRow(); + _alienRowDownCtr = 0; + } + + if (_vm->isKeyStatus1(Common::KEYCODE_UP) || _vm->isKeyStatus1(Common::KEYCODE_SPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_UP); + if (!_aliensCount) + fireShipCannon(_shipPosX); + } + + if (_shipCannonFiring) + updateShipCannon(); + + fireAlienCannon(); + updateAlienCannons(); + + if (_aliensCount == 1) { + _alienWave = false; + _vm->_timers[3] = 20; + _vm->_timers[2] = 100; + ++_aliensCount; + } + + if (_aliensCount && !_vm->_timers[3]) { + updateAliens(); + loseShip(); + if (_shipsLeft != 0) { + _vm->_timers[3] = 40; + while (_vm->_timers[3] && !_vm->_gameDone) { + updateAlienCannons(); + if (_shipCannonFiring) + updateShipCannon(); + _vm->gameUpdateTick(); + } + initAliens(); + _shipPosX = (800 - _shipMidX) / 2; + _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7); + _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom); + _ufoSequenceId = _nextUfoSequenceId; + _vm->_timers[2] = 5; + _alienWave = true; + } else { + _vm->_sceneDone = true; + } + } + + if (_vm->_timers[1] || getFreeShipCannon() == -1) { + _nextUfoSequenceId = 34; + if (_ufoSequenceId != 34) + _shipFlag = true; + } else { + _nextUfoSequenceId = 34; + if (_ufoSequenceId != 34) + _shipFlag = true; + } + + if (_shipFlag) { + if (_vm->_gameSys->getAnimationStatus(7) == 2) { + _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7); + _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom); + _ufoSequenceId = _nextUfoSequenceId; + } + _shipFlag = false; + } + + if (_alienWave && !_vm->_timers[0]) { + playSound(); + int v0 = _alienSpeed; + if (_alienSpeed >= 10) + v0 = 10; + int v1 = v0; + if (v0 < 2) + v1 = 2; + _vm->_timers[0] = v1; + } +} + +void Scene52::initShipCannon(int bottomY) { + _shipCannonFired = false; + _shipCannonWidth = MAX(_vm->_gameSys->getSpriteWidthById(14), _vm->_gameSys->getSpriteWidthById(16)); + _shipCannonHeight = MAX(_vm->_gameSys->getSpriteHeightById(14), _vm->_gameSys->getSpriteHeightById(16)); + _shipCannonTopY = bottomY - _shipCannonHeight; + _shipCannonFiring = false; +} + +void Scene52::initAlienCannons() { + for (int i = 0; i < 3; ++i) { + _alienCannonIds[i] = 0; + _alienCannonFired[i] = 0; + } + _alienCannonSequenceIds[0] = 30; + _alienCannonSequenceIds[1] = 31; + _alienCannonSequenceIds[2] = 32; +} + +void Scene52::fireShipCannon(int posX) { + if (_vm->_timers[1]) + return; + + int cannonNum = getFreeShipCannon(); + if (cannonNum != -1) { + _shipCannonPosX = _shipMidX / 2 + posX - _shipCannonWidth / 2; + _shipCannonPosY = _shipCannonTopY; + _vm->_gameSys->setAnimation(0x23, cannonNum + 256, cannonNum + 8); + _vm->_gameSys->insertSequence(0x23, cannonNum + 256, 0, 0, kSeqNone, 0, _shipCannonPosX, _shipCannonPosY); + _vm->playSound(0x2D, false); + if (shipCannonHitShield(cannonNum)) { + _vm->_gameSys->setAnimation(0, 0, cannonNum + 8); + _vm->_gameSys->removeSequence(0x23, cannonNum + 256, true); + } else { + _shipCannonFired = true; + _shipCannonPosY -= 13; + _shipCannonFiring = true; + } + _vm->_timers[1] = 5; + } +} + +void Scene52::fireAlienCannon() { + if (_vm->_timers[2]) + return; + + int cannonNum = getFreeAlienCannon(); + if (cannonNum != -1) { + int alienX1 = _alienLeftX + _alienRowXOfs[0]; + int alienX2 = _alienLeftX + _alienRowXOfs[0] + 5 * _alienWidth - (_alienWidth / 2 - 15); + _alienCannonPosX[cannonNum] = _vm->getRandom(alienX2 - alienX1) + alienX1; + _alienCannonPosY[cannonNum] = 104; + _alienCannonFired[cannonNum] = 1; + _vm->_gameSys->setAnimation(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, cannonNum + 9); + _vm->_gameSys->insertSequence(_alienCannonSequenceIds[cannonNum], _alienCannonIds[cannonNum] + 256, 0, 0, + kSeqNone, 0, _alienCannonPosX[cannonNum], _alienCannonPosY[cannonNum]); + _alienCannonPosY[cannonNum] -= 13; + _vm->_timers[2] = 5; + } +} + +int Scene52::getFreeShipCannon() { + if (!_shipCannonFired) + return 0; + return -1; +} + +int Scene52::getFreeAlienCannon() { + for (int i = 0; i < 3; ++i) + if (!_alienCannonFired[i]) + return i; + return -1; +} + +void Scene52::updateShipCannon() { + if (_shipCannonFired && _vm->_gameSys->getAnimationStatus(8) == 2) { + _shipCannonPosY -= 13; + if (_shipCannonPosY - 13 >= 135) { + if (updateHitAlien()) { + _vm->_gameSys->setAnimation(0, 0, 8); + _vm->_gameSys->removeSequence(35, 256, true); + _shipCannonFired = false; + drawScore(_gameScore); + } else { + _vm->_gameSys->setAnimation(35, 256, 8); + _vm->_gameSys->insertSequence(35, 256, 35, 256, kSeqSyncWait, 0, _shipCannonPosX, _shipCannonPosY); + _shipCannonPosY -= 13; + } + } else { + _vm->_gameSys->setAnimation(0, 0, 8); + _vm->_gameSys->removeSequence(35, 256, true); + _shipCannonFired = false; + } + } +} + +void Scene52::updateAlienCannons() { + for (int i = 0; i < 3; ++i) { + if (_alienCannonFired[i] && _vm->_gameSys->getAnimationStatus(i + 9) == 2) { + _alienCannonPosY[i] += 13; + if (_shipCannonHeight + _alienCannonPosY[i] + 13 <= 550) { + if (alienCannonHitShip(i)) { + _vm->_gameSys->setAnimation(0, 0, i + 9); + _alienCannonFired[i] = 0; + shipExplode(); + } else if (alienCannonHitShield(i)) { + _alienCannonFired[i] = 0; + } else { + _vm->_gameSys->insertSequence(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, 0, 0, + kSeqNone, 0, _alienCannonPosX[i], _alienCannonPosY[i]); + _vm->_gameSys->setAnimation(_alienCannonSequenceIds[i], 1 - _alienCannonIds[i] + 256, i + 9); + _alienCannonIds[i] = 1 - _alienCannonIds[i]; + _alienCannonPosY[i] += 13; + } + } else { + _vm->_gameSys->setAnimation(0, 0, i + 9); + _alienCannonFired[i] = 0; + } + } + } +} + +void Scene52::initAliens() { + if (!_aliensInitialized) { + initAlienSize(); + _aliensInitialized = true; + } + + _liveAlienRows = 0; + _alienSpeed = 0; + _bottomAlienFlag = false; + _aliensCount = 0; + _alienSingle = false; + _alienRowDownCtr = 0; + + initShields(); + + _alienRowKind[0] = -1; + _alienRowKind[1] = -1; + _alienRowKind[2] = -1; + _alienRowKind[3] = -1; + _alienRowKind[4] = _vm->getRandom(2) != 0 ? 24 : 27; + _alienRowKind[5] = _vm->getRandom(2) != 0 ? 25 : 28; + _alienRowKind[6] = _vm->getRandom(2) != 0 ? 26 : 29; + + for (int i = 0; i < 7; ++i) { + _alienRowAnims[i] = i; + _alienRowXOfs[i] = 0; + initAlienRowKind(i, _alienRowKind[i]); + insertAlienRow(i); + } +} + +void Scene52::initAlienRowKind(int rowNum, int alienKind) { + for (int i = 0; i < 5; ++i) + _items[rowNum][i] = alienKind; +} + +void Scene52::insertAlienRow(int rowNum) { + if (_alienRowKind[rowNum] >= 0) { + insertAlienRowAliens(rowNum); + _alienRowIds[rowNum] = 256; + _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]); + ++_liveAlienRows; + } +} + +void Scene52::insertAlienRowAliens(int rowNum) { + int xOffs = _alienLeftX; + int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10; + for (int i = 0; i < 5; ++i) { + if (_items[rowNum][i] >= 0) { + _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, 0, 0, kSeqNone, 0, xOffs, yOffs); + ++_alienSpeed; + } + xOffs += _alienWidth; + } +} + +void Scene52::updateAlienRow(int rowNum) { + if (_alienRowKind[rowNum] != -1 && !checkAlienRow(rowNum)) { + updateAlienRowXOfs(); + _alienRowIds[rowNum] = -1; + int xOffs = _alienLeftX + _alienRowXOfs[rowNum]; + int yOffs = _alienTopY - 52 * rowNum - _alienHeight + 10; + for (int i = 0; i < 5; ++i) { + if (_items[rowNum][i] >= 0) { + _vm->_gameSys->insertSequence(_items[rowNum][i], i + 256, _items[rowNum][i], i + 256, kSeqSyncWait, 0, xOffs, yOffs); + if (_alienRowIds[rowNum] == -1) + _alienRowIds[rowNum] = i + 256; + } else if (_items[rowNum][i] == -2) { + _vm->_gameSys->removeSequence(_alienRowKind[rowNum], i + 256, true); + _items[rowNum][i] = -1; + --_alienSpeed; + } + xOffs += _alienWidth; + } + if (_alienRowIds[rowNum] == -1) { + _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]); + // MessageBoxA(0, "No live aliens!", "Error 3:", 0x30u); + } else { + _vm->_gameSys->setAnimation(_alienRowKind[rowNum], _alienRowIds[rowNum], _alienRowAnims[rowNum]); + } + if (rowNum == 1) { + for (int j = 0; j < 3; ++j) { + if (_shieldSpriteIds[j] != -1) { + _vm->_gameSys->fillSurface(nullptr, _shieldPosX[j], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0); + _shieldSpriteIds[j] = -1; + } + } + } + if (rowNum == 0 && _bottomAlienFlag) + shipExplode(); + } +} + +void Scene52::moveDownAlienRow() { + int v2[5], v3, v1, v0, v4; + + for (int i = 0; i < 5; ++i) + v2[i] = _items[0][i]; + + v3 = _alienRowIds[0]; + v1 = _alienRowAnims[0]; + v0 = _alienRowKind[0]; + v4 = _alienRowXOfs[0]; + + for (int j = 0; j < 7; ++j) { + for (int i = 0; i < 5; ++i) + _items[j][i] = _items[j + 1][i]; + _alienRowIds[j] = _alienRowIds[j + 1]; + _alienRowAnims[j] = _alienRowAnims[j + 1]; + _alienRowKind[j] = _alienRowKind[j + 1]; + _alienRowXOfs[j] = _alienRowXOfs[j + 1]; + } + + for (int i = 0; i < 5; ++i) + _items[6][i] = v2[i]; + + _alienRowIds[6] = v3; + _alienRowAnims[6] = v1; + _alienRowKind[6] = v0; + _alienRowXOfs[6] = v4; + + updateAlien(6); + initAlienRowKind(6, _alienRowKind[6]); + insertAlienRow(6); + + _bottomAlienFlag = _alienRowKind[0] > -1; +} + +int Scene52::updateHitAlien() { + int result = 0, rowNum, ya; + + int y = _shipCannonTopY - _shipCannonPosY; + + if (y == 26) { + rowNum = 1; + ya = _shipCannonPosY + 26; + } else { + if (y % 52) + return 0; + rowNum = y / 52 + 1; + ya = _shipCannonPosY; + } + + if (rowNum < 7) { + int hitAlienNum = getHitAlienNum(rowNum); + if (hitAlienNum != -1 && _items[rowNum][hitAlienNum] >= 0) { + _gameScore = ((_items[rowNum][hitAlienNum] - 24) % 3 + _gameScore + 1) % 1000; + _items[rowNum][hitAlienNum] = -2; + _vm->playSound(0x2C, false); + _vm->_gameSys->insertSequence(0x21, 266, 0, 0, + kSeqNone, 0, _alienLeftX + hitAlienNum * _alienWidth + _alienRowXOfs[rowNum] - 10, ya - _alienHeight); + result = 1; + } + } + + return result; +} + +int Scene52::getHitAlienNum(int rowNum) { + int result = -1; + + int v3 = _alienLeftX + _alienRowXOfs[rowNum]; + + if (_shipCannonPosX >= v3) { + int v8 = _alienWidth / 2 - 15; + if (v3 + 5 * _alienWidth - v8 >= _shipCannonPosX) { + int v4 = v3 + _alienWidth; + if (_shipCannonPosX >= v4 - v8) { + int v5 = v4 + _alienWidth; + if (_shipCannonPosX >= v5 - v8) { + int v6 = v5 + _alienWidth; + if (_shipCannonPosX >= v6 - v8) { + int v7 = v6 + _alienWidth; + if (_shipCannonPosX >= v7 - v8) { + if (_shipCannonPosX >= v7 + _alienWidth - v8) + result = -1; + else + result = 4; + } else { + result = 3; + } + } else { + result = 2; + } + } else { + result = 1; + } + } else { + result = 0; + } + } else { + result = -1; + } + } else { + result = -1; + } + return result; +} + +int Scene52::alienCannonHitShip(int cannonNum) { + int result = 0; + + if (_aliensCount) { + result = 0; + } else { + int cannonY = _alienCannonPosY[cannonNum] - 13; + if (_arcadeScreenBottom <= cannonY) { + if (_shipMidY + _arcadeScreenBottom > cannonY) { + if (_alienCannonPosX[cannonNum] >= _shipPosX) + result = _alienCannonPosX[cannonNum] < _shipMidX + _shipPosX; + else + result = 0; + } else { + result = 0; + } + } else { + result = 0; + } + } + return result; +} + +int Scene52::alienCannonHitShield(int cannonNum) { + int result = 0; + + int v3 = _alienCannonPosY[cannonNum] + 39; + if (_arcadeScreenBottom - 44 > v3) + return 0; + + if (_arcadeScreenBottom <= v3) + return 0; + + if (_alienCannonPosX[cannonNum] < _shieldPosX[0]) + return 0; + + if (_alienCannonPosX[cannonNum] > _shieldPosX[2] + 33) + return 0; + + int shieldNum = -1; + if (_alienCannonPosX[cannonNum] < _shieldPosX[0] + 33) + shieldNum = 0; + + if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1]) + return 0; + + if (shieldNum < 0 && _alienCannonPosX[cannonNum] < _shieldPosX[1] + 33) + shieldNum = 1; + + if (shieldNum < 0) { + if (_alienCannonPosX[cannonNum] < _shieldPosX[2]) + return 0; + shieldNum = 2; + } + + if (_shieldSpriteIds[shieldNum] == -1) { + result = 0; + } else { + ++_shieldSpriteIds[shieldNum]; + if (_shieldSpriteIds[shieldNum] <= 21) { + _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]); + } else { + _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0); + _shieldSpriteIds[shieldNum] = -1; + } + _vm->_gameSys->setAnimation(0, 0, cannonNum + 9); + _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _alienCannonPosX[cannonNum] - 18, _arcadeScreenBottom - 44); + _vm->playSound(0x2C, false); + result = 1; + } + + return result; +} + +bool Scene52::shipCannonHitShield(int cannonNum) { + bool result = false; + + if (_shipCannonPosX < _shieldPosX[0]) + return result; + + if (_shipCannonPosX > _shieldPosX[2] + 33) + return result; + + int shieldNum = -1; + if (_shipCannonPosX < _shieldPosX[0] + 33) + shieldNum = 0; + + if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1]) + return result; + + if (shieldNum < 0 && _shipCannonPosX < _shieldPosX[1] + 33) + shieldNum = 1; + + if (shieldNum < 0) { + if (_shipCannonPosX < _shieldPosX[2]) + return result; + shieldNum = 2; + } + + if (_shieldSpriteIds[shieldNum] == -1) { + result = false; + } else { + ++_shieldSpriteIds[shieldNum]; + if (_shieldSpriteIds[shieldNum] <= 21) { + _vm->_gameSys->drawSpriteToBackground(_shieldPosX[shieldNum], _arcadeScreenBottom - 44, _shieldSpriteIds[shieldNum]); + } else { + _vm->_gameSys->fillSurface(nullptr, _shieldPosX[shieldNum], _arcadeScreenBottom - 44, 33, 44, 0, 0, 0); + _shieldSpriteIds[shieldNum] = -1; + } + _vm->_gameSys->insertSequence(0x21, shieldNum + 257, 0, 0, kSeqNone, 0, _shipCannonPosX - 18, _arcadeScreenBottom - 44); + _vm->playSound(0x2C, false); + result = true; + } + + return result; +} + +bool Scene52::shipCannonHitAlien() { + bool result = false; + + if (_aliensCount || checkAlienRow(0)) + return false; + + int alienNextX = _alienLeftX + _alienRowXOfs[0]; + if (_shipMidX + _shipPosX >= alienNextX) { + int startX = _alienWidth / 2 - 15; + if (alienNextX + 5 * _alienWidth - startX >= _shipPosX) { + int alienNextDeltaX = alienNextX + _alienWidth; + if (_items[0][0] <= -1 || alienNextDeltaX - startX <= _shipPosX) { + alienNextDeltaX += _alienWidth; + if (_items[0][1] <= -1 || alienNextDeltaX - startX <= _shipPosX) { + alienNextDeltaX += _alienWidth; + if (_items[0][2] <= -1 || alienNextDeltaX - startX <= _shipPosX) { + alienNextDeltaX += _alienWidth; + if (_items[0][3] <= -1 || alienNextDeltaX - startX <= _shipPosX) { + alienNextDeltaX += _alienWidth; + result = _items[0][4] > -1 && alienNextDeltaX - startX > _shipPosX; + } else { + result = true; + } + } else { + result = true; + } + } else { + result = true; + } + } else { + result = true; + } + } else { + result = false; + } + } else { + result = false; + } + + return result; +} + +void Scene52::shipExplode() { + if (!_aliensCount) { + _vm->_gameSys->setAnimation(0, 0, 7); + _vm->_gameSys->removeSequence(_ufoSequenceId, 256, true); + _vm->playSound(0x2C, false); + _vm->_gameSys->insertSequence(0x21, 266, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom); + _aliensCount = 1; + _vm->playSound(0x31, false); + } +} + +bool Scene52::checkAlienRow(int rowNum) { + for (int i = 0; i < 5; ++i) { + if (_items[rowNum][i] >= 0) + return false; + } + + bool found = false; + for (int j = 0; j < 5; ++j) + if (_items[rowNum][j] == -2) { + _vm->_gameSys->removeSequence(_alienRowKind[rowNum], j + 256, true); + _items[rowNum][j] = -1; + --_alienSpeed; + found = true; + } + + if (found) { + _vm->_gameSys->setAnimation(0, 0, _alienRowAnims[rowNum]); + --_liveAlienRows; + } + + if (_liveAlienRows < 0) + _liveAlienRows = 0; + + return true; +} + +void Scene52::updateAlienRowXOfs() { + int amount = 2 * (3 - _liveAlienRows) + 1; + + if (_alienSpeed == 2) + amount *= 4; + else if (_alienSpeed == 1) + amount *= 10; + + if (_alienDirection) { + for (int i = 0; i < 7; ++i) { + _alienRowXOfs[i] -= amount; + if (_alienRowXOfs[i] <= -100) { + _alienRowXOfs[i] = -100; + _alienDirection = 0; + ++_alienRowDownCtr; + } + } + } else { + for (int j = 0; j < 7; ++j) { + _alienRowXOfs[j] += amount; + if (_alienRowXOfs[j] >= 100) { + _alienRowXOfs[j] = 100; + _alienDirection = 1; + ++_alienRowDownCtr; + } + } + } +} + +void Scene52::initAlienSize() { + _alienWidth = _vm->_gameSys->getSpriteWidthById(0); + if (_vm->_gameSys->getSpriteWidthById(1) > _alienWidth) + _alienWidth = _vm->_gameSys->getSpriteWidthById(1); + if (_vm->_gameSys->getSpriteWidthById(4) > _alienWidth) + _alienWidth = _vm->_gameSys->getSpriteWidthById(4); + if (_vm->_gameSys->getSpriteWidthById(5) > _alienWidth) + _alienWidth = _vm->_gameSys->getSpriteWidthById(5); + if (_vm->_gameSys->getSpriteWidthById(12) > _alienWidth) + _alienWidth = _vm->_gameSys->getSpriteWidthById(12); + if (_vm->_gameSys->getSpriteWidthById(13) > _alienWidth) + _alienWidth = _vm->_gameSys->getSpriteWidthById(13); + + _alienHeight = _vm->_gameSys->getSpriteHeightById(0); + if (_vm->_gameSys->getSpriteHeightById(1) > _alienHeight) + _alienHeight = _vm->_gameSys->getSpriteHeightById(1); + if (_vm->_gameSys->getSpriteHeightById(4) > _alienHeight) + _alienHeight = _vm->_gameSys->getSpriteHeightById(4); + if (_vm->_gameSys->getSpriteHeightById(5) > _alienHeight) + _alienHeight = _vm->_gameSys->getSpriteHeightById(5); + if (_vm->_gameSys->getSpriteHeightById(12) > _alienHeight) + _alienHeight = _vm->_gameSys->getSpriteHeightById(12); + if (_vm->_gameSys->getSpriteHeightById(13) > _alienHeight) + _alienHeight = _vm->_gameSys->getSpriteHeightById(13); + + _alienTopY = _shipCannonTopY + 52; + _alienLeftX = (800 - 5 * _alienWidth) / 2; +} + +void Scene52::playSound() { + if (_soundToggle) { + _vm->playSound(0x2F, false); + _soundToggle = false; + } else { + _vm->playSound(0x2E, false); + _soundToggle = true; + } +} + +void Scene52::updateAliens() { + for (int i = 0; i < 7; ++i) + updateAlien(i); +} + +void Scene52::updateAlien(int rowNum) { + if (_alienRowKind[rowNum] >= 0 && !checkAlienRow(rowNum)) { + for (int i = 0; i < 5; ++i) { + if (_items[rowNum][i] >= 0) + _items[rowNum][i] = -2; + } + checkAlienRow(rowNum); + } +} + +void Scene52::loseShip() { + --_shipsLeft; + if (_shipsLeft == 2) { + _vm->_gameSys->fillSurface(nullptr, 120, 140, _shipMidX, _shipMidY, 0, 0, 0); + } else if (_shipsLeft == 1) { + _vm->_gameSys->fillSurface(nullptr, 120, 185, _shipMidX, _shipMidY, 0, 0, 0); + } +} + +void Scene52::initShields() { + for (int i = 0; i < 3; ++i) { + _vm->_gameSys->drawSpriteToBackground(_shieldPosX[i], _arcadeScreenBottom - 44, 17); + _shieldSpriteIds[i] = 17; + } +} + +void Scene52::initAnims() { + for (int i = 0; i < 7; ++i) + _vm->_gameSys->setAnimation(0, 0, i); + _vm->_gameSys->setAnimation(0, 0, 7); + for (int j = 0; j < 1; ++j) + _vm->_gameSys->setAnimation(0, 0, j + 8); + for (int k = 0; k < 3; ++k) + _vm->_gameSys->setAnimation(0, 0, k + 9); +} + +void Scene52::drawScore(int score) { + char str[4]; + sprintf(str, "%03d", score); + _vm->_gameSys->fillSurface(nullptr, 420, 80, 48, 30, 0, 0, 0); + _vm->_gameSys->drawTextToSurface(nullptr, 420, 80, 255, 255, 255, str); +} + +void Scene52::run() { + _vm->_timers[1] = 0; + + _vm->hideCursor(); + + _gameScore = 0; + _vm->_gameSys->drawTextToSurface(nullptr, 300, 80, 255, 255, 255, "SCORE"); + _vm->_gameSys->drawTextToSurface(nullptr, 468, 80, 255, 255, 255, "0"); + + drawScore(0); + + _shipMidX = 33; + _shipMidY = _vm->_gameSys->getSpriteHeightById(15); + _shipPosX = (800 - _shipMidX) / 2; + _arcadeScreenBottom = 496; + _arcadeScreenRight = 595 - _shipMidX; + _arcadeScreenLeft = 210; + _shipsLeft = 3; + _alienCounter = 0; + + _shieldPosX[0] = 247; + _shieldPosX[1] = 387; + _shieldPosX[2] = 525; + + for (int i = 0; i < 3; ++i) + _shieldSpriteIds[i] = -1; + + _vm->_gameSys->drawSpriteToBackground(120, 140, 0xF); + _vm->_gameSys->drawSpriteToBackground(120, 185, 0xF); + + initShipCannon(_arcadeScreenBottom); + initAlienCannons(); + initAliens(); + + _nextUfoSequenceId = 0x22; + _vm->_gameSys->setAnimation(0x22, 256, 7); + _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, 0, 0, kSeqNone, 0, _shipPosX, _arcadeScreenBottom); + + _ufoSequenceId = _nextUfoSequenceId; + + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + + _vm->_timers[2] = 5; + _shipFlag = false; + + _vm->_timers[0] = 10; + _alienWave = true; + + while (!_vm->_sceneDone) { + _vm->gameUpdateTick(); + + while (_vm->isKeyStatus2(Common::KEYCODE_RIGHT)) { + update(); + if (_vm->_gameSys->getAnimationStatus(7) == 2) { + if (_shipPosX < _arcadeScreenRight) { + _shipPosX += 15; + if (_shipPosX > _arcadeScreenRight) + _shipPosX = _arcadeScreenRight; + _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7); + _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom); + _ufoSequenceId = _nextUfoSequenceId; + if (_bottomAlienFlag && shipCannonHitAlien()) + shipExplode(); + } + break; + } + } + + while (_vm->isKeyStatus2(Common::KEYCODE_LEFT)) { + update(); + if (_vm->_gameSys->getAnimationStatus(7) == 2) { + if (_shipPosX > _arcadeScreenLeft) { + _shipPosX -= 15; + if (_shipPosX < _arcadeScreenLeft) + _shipPosX = _arcadeScreenLeft; + _vm->_gameSys->setAnimation(_nextUfoSequenceId, 256, 7); + _vm->_gameSys->insertSequence(_nextUfoSequenceId, 256, _ufoSequenceId, 256, kSeqSyncWait, 0, _shipPosX, _arcadeScreenBottom); + _ufoSequenceId = _nextUfoSequenceId; + if (_bottomAlienFlag && shipCannonHitAlien()) + shipExplode(); + } + break; + } + } + + update(); + + if (clearKeyStatus()) { + _alienWave = false; + _vm->_gameSys->waitForUpdate(); + initAnims(); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->_sceneDone = true; + } + } + _vm->_gameSys->waitForUpdate(); +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/arcade.h b/engines/gnap/scenes/arcade.h new file mode 100644 index 0000000000..b99d26158f --- /dev/null +++ b/engines/gnap/scenes/arcade.h @@ -0,0 +1,290 @@ +/* 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. + * + */ + +#ifndef GNAP_ARCADE_H +#define GNAP_ARCADE_H + +#include "gnap/debugger.h" + +namespace Gnap { + +class GnapEngine; +class CutScene; + +struct Scene49Obstacle { + int _currSequenceId; + int _closerSequenceId; + int _passedSequenceId; + int _splashSequenceId; + int _collisionSequenceId; + int _prevId; + int _currId; + int _laneNum; +}; + +struct ObstacleDef { + int _sequenceId; + int _ticks; +}; + +class Scene49: public Scene { +public: + Scene49(GnapEngine *vm); + ~Scene49() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _scoreBarPos; + int _scoreLevel; + bool _scoreBarFlash; + int _obstacleIndex; + Scene49Obstacle _obstacles[5]; + int _truckSequenceId; + int _truckId; + int _truckLaneNum; + + void checkObstacles(); + void updateObstacle(int id); + void increaseScore(int amount); + void decreaseScore(int amount); + void refreshScoreBar(); + void clearObstacle(int index); +}; + +/*****************************************************************************/ + +class Scene50: public Scene { +public: + Scene50(GnapEngine *vm); + ~Scene50() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + bool _fightDone; + int _timesPlayed; + int _timesPlayedModifier; + int _attackCounter; + int _roundNum; + int _timeRemaining; + int _leftTongueRoundsWon; + int _rightTongueRoundsWon; + int _leftTongueEnergyBarPos; + int _rightTongueEnergyBarPos; + int _leftTongueSequenceId; + int _leftTongueId; + int _leftTongueNextSequenceId; + int _leftTongueNextId; + int _leftTongueNextIdCtr; + int _rightTongueSequenceId; + int _rightTongueId; + int _rightTongueNextSequenceId; + int _rightTongueNextId; + int _rightTongueNextIdCtr; + int _leftTongueEnergy; + int _rightTongueEnergy; + + bool tongueWinsRound(int tongueNum); + void playWinAnim(int tongueNum, bool fightOver); + void delayTicks(); + void initRound(); + bool updateCountdown(); + void drawCountdown(int value); + void playTonguesIdle(); + void playRoundAnim(int roundNum); + bool updateEnergyBars(int newLeftBarPos, int newRightBarPos); + void waitForAnim(int animationIndex); + int checkInput(); + int getRightTongueAction(); + int getRightTongueActionTicks(); + int getLeftTongueNextId(); + int getRightTongueNextId(); + void playWinBadgeAnim(int tongueNum); +}; + +/*****************************************************************************/ + +struct Scene51Item { + int _currSequenceId; + int _droppedSequenceId; + int _x, _y; + int _collisionX; + bool _canCatch; + bool _isCollision; + int _x2; + int _id; +}; + +class Scene51: public Scene { +public: + Scene51(GnapEngine *vm); + ~Scene51() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations() {}; + virtual void updateAnimationsCb() {}; + +private: + bool _dropLoseCash; + + int _cashAmount; + int _digits[4]; + int _digitSequenceIds[4]; + int _guySequenceId; + int _guyNextSequenceId; + int _itemsCaughtCtr; + int _dropSpeedTicks; + int _nextDropItemKind; + int _itemInsertX; + int _itemInsertDirection; + int _platypusSequenceId; + int _platypusNextSequenceId; + int _platypusJumpSequenceId; + int _itemsCtr; + int _itemsCtr1; + int _itemsCtr2; + + Scene51Item _items[6]; + + void clearItem(Scene51Item *item); + void dropNextItem(); + void updateItemAnimations(); + int checkCollision(int sequenceId); + void updateItemAnimation(Scene51Item *item, int index); + void removeCollidedItems(); + int itemIsCaught(Scene51Item *item); + bool isJumpingRight(int sequenceId); + bool isJumpingLeft(int sequenceId); + bool isJumping(int sequenceId); + void waitForAnim(int animationIndex); + int getPosRight(int sequenceId); + int getPosLeft(int sequenceId); + void playIntroAnim(); + void updateGuyAnimation(); + int incCashAmount(int sequenceId); + void winMinigame(); + void playCashAppearAnim(); + void updateCash(int amount); + void drawDigit(int digit, int position); + void initCashDisplay(); +}; + +/*****************************************************************************/ + +class Scene52: public Scene { +public: + Scene52(GnapEngine *vm); + ~Scene52() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations() {}; + virtual void updateAnimationsCb() {}; + +private: + int _liveAlienRows; + int _gameScore; + bool _soundToggle; + int _arcadeScreenLeft; + int _arcadeScreenRight; + int _arcadeScreenBottom; + int _shipsLeft; + int _shieldSpriteIds[3]; + int _shieldPosX[3]; + int _shipPosX; + int _shipCannonPosX, _shipCannonPosY; + bool _shipCannonFiring; + bool _shipCannonFired; + int _shipCannonWidth, _shipCannonHeight; + int _shipCannonTopY; + int _shipMidX, _shipMidY; + bool _shipFlag; + bool _aliensInitialized; + int _alienSpeed, _alienDirection; + int _alienWidth, _alienHeight; + int _alienLeftX, _alienTopY; + int _alienRowDownCtr; + int _alienRowKind[7]; + int _alienRowAnims[7]; + int _alienRowIds[7]; + int _alienRowXOfs[7]; + int _alienCannonFired[3]; + int _alienCannonPosX[3]; + int _alienCannonPosY[3]; + int _alienCannonSequenceIds[3]; + int _alienCannonIds[3]; + bool _alienWave, _alienSingle; + int _alienCounter; + bool _bottomAlienFlag; + int _aliensCount; + int _items[8][5]; + int _nextUfoSequenceId, _ufoSequenceId; + + void update(); + void initShipCannon(int bottomY); + void initAlienCannons(); + void fireShipCannon(int posX); + void fireAlienCannon(); + int getFreeShipCannon(); + int getFreeAlienCannon(); + void updateShipCannon(); + void updateAlienCannons(); + void initAliens(); + void initAlienRowKind(int rowNum, int alienKind); + void insertAlienRow(int rowNum); + void insertAlienRowAliens(int rowNum); + void updateAlienRow(int rowNum); + void moveDownAlienRow(); + int updateHitAlien(); + int getHitAlienNum(int rowNum); + int alienCannonHitShip(int cannonNum); + int alienCannonHitShield(int cannonNum); + bool shipCannonHitShield(int cannonNum); + bool shipCannonHitAlien(); + void shipExplode(); + bool checkAlienRow(int rowNum); + void updateAlienRowXOfs(); + void initAlienSize(); + void playSound(); + void updateAliens(); + void updateAlien(int rowNum); + void loseShip(); + void initShields(); + void initAnims(); + void drawScore(int score); +}; + +} // End of namespace Gnap + +#endif // GNAP_ARCADE_H diff --git a/engines/gnap/scenes/group0.cpp b/engines/gnap/scenes/group0.cpp new file mode 100644 index 0000000000..e55b08eac3 --- /dev/null +++ b/engines/gnap/scenes/group0.cpp @@ -0,0 +1,3570 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/character.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/group0.h" + +namespace Gnap { + +Scene01::Scene01(GnapEngine *vm) : Scene(vm) { + _pigsIdCtr = 0; + _smokeIdCtr = 0; + _spaceshipSurface = nullptr; +} + +Scene01::~Scene01() { + delete _spaceshipSurface; +} + +int Scene01::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 3); + return 0x88; +} + +void Scene01::updateHotspots() { + _vm->setHotspot(kHS01Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS01ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6); + _vm->setHotspot(kHS01Mud, 138, 282, 204, 318, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5); + _vm->setHotspot(kHS01Pigs, 408, 234, 578, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 4); + _vm->setHotspot(kHS01Spaceship, 0, 200, 94, 292, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6); + _vm->setHotspot(kHS01WalkArea1, 0, 0, 162, 426); + _vm->setHotspot(kHS01WalkArea2, 162, 0, 237, 396); + _vm->setHotspot(kHS01WalkArea3, 237, 0, 319, 363); + _vm->setHotspot(kHS01WalkArea4, 520, 0, 800, 404); + _vm->setHotspot(kHS01WalkArea5, 300, 447, 800, 600); + _vm->setHotspot(kHS01WalkArea6, 678, 0, 800, 404); + _vm->setHotspot(kHS01WalkArea7, 0, 0, 520, 351); + _vm->setHotspot(kHS01WalkArea8, 0, 546, 300, 600); + _vm->setDeviceHotspot(kHS01Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS01Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + if (_vm->isFlag(kGFMudTaken)) + _vm->_hotspots[kHS01Mud]._flags = SF_WALKABLE | SF_DISABLED; + _vm->_hotspotsCount = 14; +} + +void Scene01::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1091C, true); + _vm->startSoundTimerC(5); + + gameSys.setAnimation(134, 20, 4); + gameSys.insertSequence(134, 20, 0, 0, kSeqNone, 0, 0, 0); + + gameSys.setAnimation(0x7F, 40, 2); + gameSys.insertSequence(0x7F, 40, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[4] = _vm->getRandom(100) + 300; + + if (!_vm->isFlag(kGFMudTaken)) + gameSys.insertSequence(129, 40, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + if (_vm->_prevSceneNum == 2) { + gnap.initPos(11, 6, kDirBottomLeft); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(12, 6, kDirIdleRight); + _vm->endSceneInit(); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(8, 6), -1, 0x107B9, 1); + } else { + gnap.initPos(1, 6, kDirBottomRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(1, 7, kDirIdleLeft); + _vm->endSceneInit(); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + _vm->testWalk(0, 3, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS01Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS01Platypus: + if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) { + if (_vm->_grabCursorSpriteIndex == kItemDisguise) { + gnap.useDisguiseOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFKeysTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS01Spaceship: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 0, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap._idleFacing = kDirUpLeft; + if (gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1)) + gnap._actionStatus = kAS01LookSpaceship; + break; + case GRAB_CURSOR: + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS01Mud: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(3, 3)); + break; + case GRAB_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 3)) | 0x10000, 1); + gnap._actionStatus = kAS01TakeMud; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS01Pigs: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 7, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1); + gnap._actionStatus = kAS01LookPigs; + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(7, 2)) | 0x10000, 1); + gnap._actionStatus = kAS01UsePigs; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(7, 2)) | 0x10000, 1); + gnap._actionStatus = kAS01LookPigs; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS01ExitTruck: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107AB, 1); + gnap._actionStatus = kAS01LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), -1, 0x107CD, 1); + _vm->_newSceneNum = 2; + } + break; + + case kHS01WalkArea1: + case kHS01WalkArea2: + case kHS01WalkArea3: + case kHS01WalkArea4: + case kHS01WalkArea5: + case kHS01WalkArea6: + case kHS01WalkArea7: + case kHS01WalkArea8: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1091C)) + _vm->playSound(0x1091C, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (_vm->_timers[4] == 0) { + // Update bird animation + _vm->_timers[4] = _vm->getRandom(100) + 300; + if (_vm->getRandom(1) == 0) + gameSys.insertSequence(0x84, 180, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x83, 180, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene01::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS01LookSpaceship: + _spaceshipSurface = gameSys.createSurface(47); + gameSys.insertSpriteDrawItem(_spaceshipSurface, 0, 0, 255); + gameSys.setAnimation(133, 256, 0); + gameSys.insertSequence(133, 256, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = kAS01LookSpaceshipDone; + break; + + case kAS01LookSpaceshipDone: + gameSys.removeSequence(133, 256, true); + gameSys.removeSpriteDrawItem(_spaceshipSurface, 255); + _vm->deleteSurface(&_spaceshipSurface); + gnap._actionStatus = -1; + break; + + case kAS01LeaveScene: + _vm->_sceneDone = true; + break; + + case kAS01TakeMud: + gnap.playPullOutDevice(Common::Point(2, 3)); + gnap.playUseDevice(); + gameSys.insertSequence(128, 40, 129, 40, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(128, 40, 3); + gnap._actionStatus = -1; + break; + + case kAS01LookPigs: + _vm->playSound(0x8A, false); + _vm->playSound(0x8B, false); + _vm->playSound(0x8C, false); + gnap._actionStatus = -1; + break; + + case kAS01UsePigs: + gnap.playPullOutDevice(Common::Point(7, 2)); + gnap.playUseDevice(); + gameSys.insertSequence(135, 39, 0, 0, kSeqNone, 25, _vm->getRandom(140) - 40, 0); + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + gameSys.setAnimation(0, 0, 3); + _vm->invAdd(kItemMud); + _vm->setGrabCursorSprite(kItemMud); + _vm->setFlag(kGFMudTaken); + updateHotspots(); + } + + if (gameSys.getAnimationStatus(4) == 2) { + _smokeIdCtr = (_smokeIdCtr + 1) % 2; + gameSys.setAnimation(0x86, _smokeIdCtr + 20, 4); + gameSys.insertSequence(0x86, _smokeIdCtr + 20, + 0x86, (_smokeIdCtr + 1) % 2 + 20, + kSeqSyncWait, 0, 0, 0); + } + + if (gameSys.getAnimationStatus(2) == 2) { + _pigsIdCtr = (_pigsIdCtr + 1) % 2; + gameSys.setAnimation(0x7F, _pigsIdCtr + 40, 2); + gameSys.insertSequence(0x7F, _pigsIdCtr + 40, + 0x7F, (_pigsIdCtr + 1) % 2 + 40, + kSeqSyncWait, 0, 0, 0); + } +} + +/*****************************************************************************/ + +Scene02::Scene02(GnapEngine *vm) : Scene(vm) { + _truckGrillCtr = 0; + _nextChickenSequenceId = 0; + _currChickenSequenceId = 0; + _gnapTruckSequenceId = 0; +} + +int Scene02::init() { + _vm->_gameSys->setAnimation(0, 0, 0); + return _vm->isFlag(kGFTruckKeysUsed) ? 0x15A : 0x15B; +} + +void Scene02::updateHotspots() { + _vm->setHotspot(kHS02Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE); + _vm->setHotspot(kHS02Chicken, 606, 455, 702, 568, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8); + _vm->setHotspot(kHS02Truck1, 385, 258, 464, 304, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 5); + _vm->setHotspot(kHS02Truck2, 316, 224, 390, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 6); + _vm->setHotspot(kHS02TruckGrill, 156, 318, 246, 390, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 7); + _vm->setHotspot(kHS02ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 5); + _vm->setHotspot(kHS02ExitBarn, 610, 0, 800, 164, SF_EXIT_U_CURSOR, 10, 5); + _vm->setHotspot(kHS02ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8); + _vm->setHotspot(kHS02ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8); + _vm->setHotspot(kHS02WalkArea1, 92, 140, 304, 430, 0, 3, 1); + _vm->setHotspot(kHS02WalkArea2, 0, 0, 800, 380); + _vm->setHotspot(kHS02WalkArea3, 0, 0, 386, 445); + _vm->setHotspot(kHS02WalkArea4, 386, 0, 509, 410); + _vm->setDeviceHotspot(kHS02Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS02Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + _vm->_hotspotsCount = 14; +} + +void Scene02::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1091C, true); + _vm->startSoundTimerC(6); + + _currChickenSequenceId = 0x14B; + gameSys.setAnimation(0x14B, 179, 2); + gameSys.insertSequence(0x14B, 179, 0, 0, kSeqNone, 0, 0, 0); + + _nextChickenSequenceId = -1; + _vm->_timers[5] = _vm->getRandom(20) + 30; + _vm->_timers[4] = _vm->getRandom(100) + 300; + + _vm->queueInsertDeviceIcon(); + + switch (_vm->_prevSceneNum) { + case 3: + gnap.initPos(11, 6, kDirBottomLeft); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(12, 6, kDirIdleRight); + _vm->endSceneInit(); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(9, 6), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1); + break; + case 4: + gnap.initPos(_vm->_hotspotsWalkPos[6].x, _vm->_hotspotsWalkPos[6].y, kDirBottomLeft); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(_vm->_hotspotsWalkPos[6].x + 1, _vm->_hotspotsWalkPos[6].y, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(7, 6), 0, 0x107B9, 1); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(8, 6), 1, 0x107C2, 1); + updateHotspots(); + gameSys.waitForUpdate(); + break; + case 47: + _vm->clearFlag(kGFUnk25); + gnap.initPos(5, 6, kDirBottomLeft); + plat.initPos(6, 7, kDirIdleRight); + _vm->endSceneInit(); + break; + case 49: + gnap.initPos(5, 6, kDirBottomRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(6, 7, kDirIdleLeft); + _vm->endSceneInit(); + break; + default: + gnap.initPos(-1, 6, kDirBottomRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(-1, 7, kDirIdleLeft); + _vm->endSceneInit(); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + break; + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 6, 7, 6, 8, 6); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS02Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS02Platypus: + if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) { + if (_vm->_grabCursorSpriteIndex == kItemDisguise) { + gnap.useDisguiseOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFKeysTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS02Chicken: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemTwig) { + gnap._idleFacing = kDirUpRight; + Common::Point destPos = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1); + gnap.walkTo(destPos, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS02UseTwigWithChicken; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(0, 1), 9, 8); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(Common::Point(9, 8)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirBottomRight; + if (gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1)) + gnap._actionStatus = kAS02GrabChicken; + else + gnap._actionStatus = -1; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS02TalkChicken; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS02Truck1: + case kHS02Truck2: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemKeys) { + if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) { + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemKeys); + if (_vm->isFlag(kGFTruckFilledWithGas)) + gnap._actionStatus = kAS02UseTruckGas; + else + gnap._actionStatus = kAS02UseTruckNoGas; + } + } else if (_vm->_grabCursorSpriteIndex == kItemGas) { + _vm->_hotspots[kHS02WalkArea4]._flags |= SF_WALKABLE; + if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) + gnap._actionStatus = kAS02UseGasWithTruck; + _vm->_hotspots[kHS02WalkArea4]._flags &= ~SF_WALKABLE; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 2, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(2, 2)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFTruckKeysUsed)) { + if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) { + if (_vm->isFlag(kGFTruckFilledWithGas)) + gnap._actionStatus = kAS02UseTruckGas; + else + gnap._actionStatus = kAS02UseTruckNoGas; + } + } else { + gnap._idleFacing = kDirIdleRight; + if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 2)) | 0x10000, 1)) + gnap._actionStatus = kAS02UseTruckNoKeys; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS02TruckGrill: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[4], 2, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(Common::Point(2, 4)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS02GrabTruckGrill; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS02ExitHouse: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[6], 0, 0x107AD, 1); + gnap._actionStatus = kAS02LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), -1, 0x107C1, 1); + updateHotspots(); + _vm->_newSceneNum = 4; + } + break; + + case kHS02ExitBarn: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, 0x107AD, 1); + gnap._actionStatus = kAS02LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[7] + Common::Point(1, 0), -1, 0x107C1, 1); + updateHotspots(); + _vm->_newSceneNum = 5; + } + break; + + case kHS02ExitCreek: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1); + gnap._actionStatus = kAS02LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[8], -1, 0x107CD, 1); + _vm->_newSceneNum = 3; + } + break; + + case kHS02ExitPigpen: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[9], 0, 0x107AF, 1); + gnap._actionStatus = kAS02LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[9], -1, 0x107CF, 1); + _vm->_newSceneNum = 1; + } + break; + + case kHS02WalkArea1: + case kHS02WalkArea2: + case kHS02WalkArea3: + case kHS02WalkArea4: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1091C)) + _vm->playSound(0x1091C, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + // Update bird animation + _vm->_timers[4] = _vm->getRandom(100) + 300; + if (_vm->getRandom(2) != 0) + gameSys.insertSequence(0x156, 256, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x154, 256, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != 7 && gnap._actionStatus != 8) { + if (_vm->getRandom(6) != 0) { + _nextChickenSequenceId = 0x14B; + _vm->_timers[5] = _vm->getRandom(20) + 30; + } else { + _nextChickenSequenceId = 0x14D; + _vm->_timers[5] = _vm->getRandom(20) + 50; + } + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene02::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + switch (gnap._actionStatus) { + case kAS02UseTruckNoKeys: + gameSys.insertSequence(0x14E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x14E, gnap._id, 0); + gnap._sequenceId = 0x14E; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS02UseTruckNoKeysDone; + break; + case kAS02UseGasWithTruck: + gameSys.insertSequence(0x151, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x151, gnap._id, 0); + gnap._sequenceId = 0x151; + gnap._sequenceDatNum = 0; + _vm->invRemove(kItemGas); + _vm->setGrabCursorSprite(-1); + _vm->setFlag(kGFTruckFilledWithGas); + gnap._actionStatus = kAS02UseGasWithTruckDone; + break; + case kAS02UseTruckGas: + _vm->_timers[5] = 9999; + _vm->_timers[4] = 9999; + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + if (!_vm->isFlag(kGFTruckKeysUsed)) { + gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.waitForUpdate(); + _vm->setFlag(kGFTruckKeysUsed); + gnap._sequenceId = 0x14F; + gnap._sequenceDatNum = 0; + _vm->invRemove(kItemKeys); + _vm->setGrabCursorSprite(-1); + } + _vm->_newSceneNum = 47; + _vm->_sceneDone = true; + break; + case kAS02UseTruckNoGas: + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + _vm->_timers[4] = 250; + if (!_vm->isFlag(kGFTruckKeysUsed)) { + gameSys.insertSequence(0x14F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.waitForUpdate(); + _vm->setFlag(kGFTruckKeysUsed); + gnap._sequenceId = 0x14F; + gnap._sequenceDatNum = 0; + _vm->invRemove(kItemKeys); + _vm->setGrabCursorSprite(-1); + } + _vm->_newSceneNum = 47; + _vm->_sceneDone = true; + _vm->setFlag(kGFUnk25); + break; + case kAS02GrabTruckGrill: + switch (_truckGrillCtr) { + case 0: + _gnapTruckSequenceId = 0x158; + break; + case 1: + _gnapTruckSequenceId = 0x159; + break; + case 2: + _gnapTruckSequenceId = 0x157; + break; + } + _truckGrillCtr = (_truckGrillCtr + 1) % 3; + gameSys.insertSequence(_gnapTruckSequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_gnapTruckSequenceId, gnap._id, 0); + gnap._sequenceId = _gnapTruckSequenceId; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + break; + case kAS02LeaveScene: + _vm->_sceneDone = true; + break; + case kAS02TalkChicken: + _nextChickenSequenceId = 0x14C; + break; + case kAS02GrabChicken: + _nextChickenSequenceId = 0x150; + _vm->_timers[2] = 100; + break; + case kAS02GrabChickenDone: + gameSys.insertSequence(0x107B5, gnap._id, 0x150, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + _currChickenSequenceId = 0x14B; + gameSys.setAnimation(0x14B, 179, 2); + gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = -1; + _vm->_timers[5] = 30; + break; + case kAS02UseTwigWithChicken: + gnap.playShowItem(5, 0, 0); + gameSys.insertSequence(0x155, 179, _currChickenSequenceId, 179, kSeqSyncExists, 0, 0, 0); + _currChickenSequenceId = 0x155; + _nextChickenSequenceId = -1; + gnap._actionStatus = -1; + break; + case kAS02UseTruckNoKeysDone: + case kAS02UseGasWithTruckDone: + default: + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + if (_nextChickenSequenceId == 0x150) { + gameSys.setAnimation(_nextChickenSequenceId, 179, 0); + gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(_currChickenSequenceId, 179, true); + _nextChickenSequenceId = -1; + _currChickenSequenceId = -1; + gnap._actionStatus = kAS02GrabChickenDone; + _vm->_timers[5] = 500; + } else if (_nextChickenSequenceId == 0x14C) { + gameSys.setAnimation(_nextChickenSequenceId, 179, 2); + gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0); + _currChickenSequenceId = _nextChickenSequenceId; + _nextChickenSequenceId = -1; + gnap._actionStatus = -1; + } else if (_nextChickenSequenceId != -1) { + gameSys.setAnimation(_nextChickenSequenceId, 179, 2); + gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0); + _currChickenSequenceId = _nextChickenSequenceId; + _nextChickenSequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene03::Scene03(GnapEngine *vm) : Scene(vm) { + _nextPlatSequenceId = -1; + _platypusScared = false; + _platypusHypnotized = false; + _nextFrogSequenceId = -1; + _currFrogSequenceId = -1; +} + +int Scene03::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 5); + return 0x1CC; +} + +void Scene03::updateHotspots() { + _vm->setHotspot(kHS03Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS03Grass, 646, 408, 722, 458, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6); + _vm->setHotspot(kHS03ExitTruck, 218, 64, 371, 224, SF_EXIT_U_CURSOR | SF_WALKABLE, 4, 4); + _vm->setHotspot(kHS03Creek, 187, 499, 319, 587, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7); + _vm->setHotspot(kHS03TrappedPlatypus, 450, 256, 661, 414, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 5); + _vm->setHotspot(kHS03WalkAreas1, 0, 500, 300, 600); + _vm->setHotspot(kHS03WalkAreas2, 300, 447, 800, 600); + _vm->setHotspot(kHS03PlatypusWalkArea, 235, 0, 800, 600); + _vm->setHotspot(kHS03WalkAreas3, 0, 0, 800, 354); + _vm->setDeviceHotspot(kHS03Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS03Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + if (_vm->isFlag(kGFGrassTaken)) + _vm->_hotspots[kHS03Grass]._flags = SF_WALKABLE | SF_DISABLED; + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS03TrappedPlatypus]._flags = SF_DISABLED; + if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized) + _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE; + _vm->_hotspotsCount = 10; +} + +void Scene03::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x10925, true); + _vm->startSoundTimerC(7); + + gameSys.insertSequence(0x1CA, 251, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x1CB, 251, 0, 0, kSeqLoop, 0, 0, 0); + + _platypusHypnotized = false; + gnap.initPos(3, 4, kDirBottomRight); + + gameSys.insertSequence(0x1C6, 253, 0, 0, kSeqNone, 0, 0, 0); + + _currFrogSequenceId = 0x1C6; + _nextFrogSequenceId = -1; + gameSys.setAnimation(0x1C6, 253, 2); + + _vm->_timers[6] = _vm->getRandom(20) + 30; + _vm->_timers[4] = _vm->getRandom(100) + 300; + _vm->_timers[5] = _vm->getRandom(100) + 200; + + if (_vm->isFlag(kGFPlatypus)) { + plat.initPos(5, 4, kDirIdleLeft); + } else { + _vm->_timers[1] = _vm->getRandom(40) + 20; + gameSys.setAnimation(0x1C2, 99, 1); + gameSys.insertSequence(0x1C2, 99, 0, 0, kSeqNone, 0, 0, 0); + plat._sequenceId = 0x1C2; + plat._sequenceDatNum = 0; + } + + gameSys.insertSequence(0x1C4, 255, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFGrassTaken)) + gameSys.insertSequence(0x1B2, 253, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + _vm->endSceneInit(); + + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(4, 7), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(3, 6), -1, 0x107B9, 1); + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS03Platypus: + if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) { + if (_vm->_grabCursorSpriteIndex == kItemDisguise) { + gnap.useDisguiseOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFKeysTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS03Grass: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFGrassTaken)) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(9, 6)); + break; + case GRAB_CURSOR: + gnap.playPullOutDevice(Common::Point(9, 6)); + gnap.playUseDevice(); + gameSys.insertSequence(0x1B3, 253, 0x1B2, 253, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x1B3, 253, 5); + _vm->_hotspots[kHS03Grass]._flags |= SF_WALKABLE | SF_DISABLED; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS03ExitTruck: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107AD, 1); + gnap._actionStatus = kAS03LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[2], -1, 0x107C2, 1); + _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE; + if (_vm->_cursorValue == 1) + _vm->_newSceneNum = 2; + else + _vm->_newSceneNum = 33; + } + break; + + case kHS03Creek: + if (gnap._actionStatus == -1) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(Common::Point(2, 8)); + break; + case GRAB_CURSOR: + if (!_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS03PlatypusWalkArea]._flags |= SF_WALKABLE; + if (gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[3] + Common::Point(1, 1)) | 0x10000, 1)) + gnap._actionStatus = kAS03GrabCreek; + if (!_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS03PlatypusWalkArea]._flags &= ~SF_WALKABLE; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS03TrappedPlatypus: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypus)) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(8, 4)); + break; + case GRAB_CURSOR: + if (_platypusHypnotized) { + gnap.walkTo(Common::Point(7, 6), 0, 0x107B5, 1); + gnap._actionStatus = kAS03FreePlatypus; + } else { + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + if (_platypusScared) + gnap._actionStatus = kAS03GrabScaredPlatypus; + else + gnap._actionStatus = kAS03GrabPlatypus; + } + break; + case TALK_CURSOR: + if (_platypusHypnotized) { + gnap.playBrainPulsating(Common::Point(8, 4)); + } else { + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + if (_platypusScared) + gnap._actionStatus = kAS03HypnotizeScaredPlat; + else + gnap._actionStatus = kAS03HypnotizePlat; + } + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS03Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS03WalkAreas1: + case kHS03WalkAreas2: + case kHS03WalkAreas3: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + case kHS03PlatypusWalkArea: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypus) || _platypusHypnotized) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } else { + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107B5, 1); + if (_platypusScared) + gnap._actionStatus = kAS03GrabScaredPlatypus; + else + gnap._actionStatus = kAS03GrabPlatypus; + } + } + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x10925)) + _vm->playSound(0x10925, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[1] && !_platypusScared) { + _vm->_timers[1] = _vm->getRandom(40) + 20; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && !_vm->isFlag(kGFPlatypus) && !_platypusHypnotized) + _nextPlatSequenceId = 450; + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(20) + 30; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextFrogSequenceId == -1) { + if (_vm->getRandom(5) == 1) + _nextFrogSequenceId = 0x1C6; + else + _nextFrogSequenceId = 0x1C7; + } + } + if (!_vm->_timers[4]) { + // Update bird animation + _vm->_timers[4] = _vm->getRandom(100) + 300; + if (gnap._actionStatus < 0 && plat._actionStatus < 0) + gameSys.insertSequence(_vm->getRandom(2) != 0 ? 0x1C8 : 0x1C3, 253, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(100) + 200; + if (gnap._actionStatus < 0 && plat._actionStatus < 0) { + gameSys.setAnimation(0x1C5, 253, 4); + gameSys.insertSequence(0x1C5, 253, 0, 0, kSeqNone, 0, 0, 0); + } + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[5] = _vm->getRandom(100) + 200; + _vm->_timers[4] = _vm->getRandom(100) + 300; + _vm->_timers[6] = _vm->getRandom(20) + 30; + } + + _vm->gameUpdateTick(); + } +} + +void Scene03::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS03LeaveScene: + _vm->_sceneDone = true; + break; + case kAS03FreePlatypus: + _nextPlatSequenceId = 0x1BC; + break; + case kAS03FreePlatypusDone: + gnap._actionStatus = -1; + plat._pos = Common::Point(6, 6); + plat._idleFacing = kDirIdleRight; + plat._id = 120; + gameSys.insertSequence(0x107CA, plat._id, 0x1BC, 99, + kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY); + gameSys.insertSequence(0x1B7, 99, 0, 0, kSeqNone, 0, 0, 0); + plat._sequenceDatNum = 1; + plat._sequenceId = 0x7CA; + _vm->setFlag(kGFPlatypus); + _nextPlatSequenceId = -1; + updateHotspots(); + break; + case kAS03HypnotizePlat: + gnap.playBrainPulsating(); + _vm->addFullScreenSprite(0x106, 255); + gameSys.setAnimation(0x1C9, 256, 1); + gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->removeFullScreenSprite(); + gameSys.setAnimation(0x1BA, 99, 1); + gameSys.insertSequence(0x1BA, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0); + plat._sequenceDatNum = 0; + plat._sequenceId = 0x1BA; + gnap._actionStatus = -1; + _platypusHypnotized = true; + updateHotspots(); + break; + case kAS03HypnotizeScaredPlat: + gnap.playBrainPulsating(); + gameSys.insertSequence(0x1BF, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncExists, 0, 0, 0); + gameSys.setAnimation(0x1BF, 99, 1); + while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->addFullScreenSprite(0x106, 255); + gameSys.setAnimation(0x1C9, 256, 1); + gameSys.insertSequence(0x1C9, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->removeFullScreenSprite(); + gameSys.setAnimation(0x1BA, 99, 1); + gameSys.insertSequence(0x1BA, 99, 447, 99, kSeqSyncWait, 0, 0, 0); + plat._sequenceDatNum = 0; + plat._sequenceId = 0x1BA; + gnap._actionStatus = -1; + _platypusHypnotized = true; + updateHotspots(); + break; + case kAS03GrabPlatypus: + _nextPlatSequenceId = 0x1BD; + _platypusHypnotized = false; + break; + case kAS03GrabScaredPlatypus: + _nextPlatSequenceId = 0x1C0; + _platypusHypnotized = false; + break; + case kAS03GrabCreek: + gameSys.insertSequence(0x1B4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x1B4, gnap._id, 0); + gnap._sequenceId = 0x1B4; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS03GrabCreekDone; + break; + default: + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + if (_nextPlatSequenceId == 0x1BD || _nextPlatSequenceId == 0x1C0) { + gameSys.setAnimation(0, 0, 1); + _platypusScared = true; + gameSys.insertSequence(0x1B5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(_nextPlatSequenceId, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x1B5; + gnap._sequenceDatNum = 0; + gnap._idleFacing = kDirIdleLeft; + plat._sequenceId = _nextPlatSequenceId; + plat._sequenceDatNum = 0; + gameSys.setAnimation(_nextPlatSequenceId, 99, 1); + _nextPlatSequenceId = -1; + gnap._actionStatus = -1; + } else if (_nextPlatSequenceId == 0x1BC) { + gnap._pos = Common::Point(3, 6); + gameSys.insertSequence(0x1B6, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x1BC, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x1BC, 99, 0); + gnap._id = 20 * gnap._pos.y; + gnap._sequenceId = 0x1B6; + gnap._sequenceDatNum = 0; + gnap._idleFacing = kDirIdleLeft; + gnap._actionStatus = kAS03FreePlatypusDone; + _nextPlatSequenceId = -1; + } else if (_nextPlatSequenceId == 0x1C2 && !_platypusScared) { + gameSys.setAnimation(0, 0, 1); + gameSys.insertSequence(0x1C2, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0x1C2; + plat._sequenceDatNum = 0; + gameSys.setAnimation(0x1C2, 99, 1); + _nextPlatSequenceId = -1; + } else if (_nextPlatSequenceId == -1 && _platypusScared && !_platypusHypnotized) { + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0x1BE, 99, 1); + gameSys.insertSequence(0x1BE, 99, plat._sequenceId | (plat._sequenceDatNum << 16), 99, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0x1BE; + plat._sequenceDatNum = 0; + _nextPlatSequenceId = -1; + } + } + + if (gameSys.getAnimationStatus(2) == 2 && _nextFrogSequenceId != -1) { + gameSys.setAnimation(_nextFrogSequenceId, 253, 2); + gameSys.insertSequence(_nextFrogSequenceId, 253, _currFrogSequenceId, 253, kSeqSyncWait, 0, 0, 0); + _currFrogSequenceId = _nextFrogSequenceId; + _nextFrogSequenceId = -1; + } + + if (gameSys.getAnimationStatus(5) == 2) { + gameSys.setAnimation(0, 0, 5); + _vm->invAdd(kItemGrass); + _vm->setGrabCursorSprite(kItemGrass); + _vm->setFlag(kGFGrassTaken); + updateHotspots(); + } +} + +/*****************************************************************************/ + +Scene04::Scene04(GnapEngine *vm) : Scene(vm) { + _dogIdCtr = 0; + _triedWindow = false; + _nextDogSequenceId = -1; + _currDogSequenceId = -1; +} + +int Scene04::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + return 0x214; +} + +void Scene04::updateHotspots() { + _vm->setHotspot(kHS04Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS04Twig, 690, 394, 769, 452, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 6); + _vm->setHotspot(kHS04Dog, 550, 442, 680, 552, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8); + _vm->setHotspot(kHS04Axe, 574, 342, 680, 412, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7); + _vm->setHotspot(kHS04Door, 300, 244, 386, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7); + _vm->setHotspot(kHS04ExitTruck, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS04Window, 121, 295, 237, 342, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7); + _vm->setHotspot(kHS04ExitBarn, 585, 154, 800, 276, SF_EXIT_U_CURSOR, 10, 8); + _vm->setHotspot(kHS04WalkArea1, 0, 0, 562, 461); + _vm->setHotspot(kHS04WalkArea2, 562, 0, 800, 500); + _vm->setDeviceHotspot(kHS04Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS04Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + if (_vm->isFlag(kGFTwigTaken)) + _vm->_hotspots[kHS04Twig]._flags = SF_WALKABLE | SF_DISABLED; + if (_vm->isFlag(kGFPlatypusTalkingToAssistant) || _vm->_cursorValue == 1) + _vm->_hotspots[kHS04Axe]._flags = SF_DISABLED; + _vm->_hotspotsCount = 11; +} + +void Scene04::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1091C, true); + _vm->startSoundTimerC(4); + + gameSys.insertSequence(0x210, 139 - _dogIdCtr, 0, 0, kSeqNone, 0, 0, 0); + + _currDogSequenceId = 0x210; + _nextDogSequenceId = -1; + + gameSys.setAnimation(0x210, 139 - _dogIdCtr, 3); + _dogIdCtr = (_dogIdCtr + 1) % 2; + _vm->_timers[6] = _vm->getRandom(20) + 60; + _vm->_timers[5] = _vm->getRandom(150) + 300; + _vm->_timers[7] = _vm->getRandom(150) + 200; + _vm->_timers[8] = _vm->getRandom(150) + 400; + + if (!_vm->isFlag(kGFPlatypusTalkingToAssistant) && _vm->_cursorValue == 4) + gameSys.insertSequence(0x212, 100, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFTwigTaken)) + gameSys.insertSequence(0x1FE, 100, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFPlatypusDisguised)) { + _vm->_timers[3] = 300; + _vm->setGrabCursorSprite(kItemKeys); + gnap._pos = Common::Point(4, 7); + gnap._id = 140; + plat._pos = Common::Point(6, 7); + plat._id = 141; + gameSys.insertSequence(0x107B5, 140, 0, 0, kSeqNone, 0, 300 - gnap._gridX, 336 - gnap._gridY); + gameSys.insertSequence(0x20C, 141, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x208, 121, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x209, 121, 0x208, 121, kSeqSyncWait, 0, 0, 0); + _vm->endSceneInit(); + _vm->invRemove(kItemDisguise); + _vm->invAdd(kItemKeys); + _vm->setFlag(kGFKeysTaken); + _vm->clearFlag(kGFPlatypusDisguised); + plat._sequenceId = 0x20C; + plat._sequenceDatNum = 0; + plat._idleFacing = kDirBottomRight; + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + gameSys.waitForUpdate(); + } else { + gameSys.insertSequence(0x209, 121, 0, 0, kSeqNone, 0, 0, 0); + if (_vm->_prevSceneNum == 2) { + gnap.initPos(5, 11, kDirUpRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(6, 11, kDirUpLeft); + _vm->endSceneInit(); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(6, 9), -1, 0x107BA, 1); + } else if (_vm->_prevSceneNum == 38) { + gnap.initPos(5, 7, kDirBottomRight); + plat.initPos(4, 7, kDirIdleLeft); + _vm->endSceneInit(); + } else { + gnap.initPos(12, 9, kDirBottomRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(12, 8, kDirIdleLeft); + _vm->endSceneInit(); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(9, 9), -1, 0x107BA, 1); + } + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 4, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS04Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS04Platypus: + if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) { + if (_vm->_grabCursorSpriteIndex == kItemDisguise) { + gnap.useDisguiseOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFKeysTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + if (_vm->_cursorValue == 4) + gnap.kissPlatypus(0); + else + gnap.playMoan1(plat._pos); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS04Twig: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 9, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(_vm->_hotspotsWalkPos[1]); + break; + case GRAB_CURSOR: + gnap.playPullOutDevice(_vm->_hotspotsWalkPos[1]); + gnap.playUseDevice(_vm->_hotspotsWalkPos[1]); + gameSys.insertSequence(0x1FD, 100, 510, 100, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x1FD, 100, 2); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS04Axe: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[3], 9, 5); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(_vm->_hotspotsWalkPos[3]); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS04GrabAxe; + _vm->setFlag(kGFPlatypusTalkingToAssistant); + updateHotspots(); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS04Dog: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 9, 7); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (gnap.walkTo(gnap._pos, 0, -1, 1)) { + gnap.playMoan2(_vm->_hotspotsWalkPos[2]); + _nextDogSequenceId = 0x20F; + } + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirBottomRight; + if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1)) + gnap._actionStatus = kAS04GrabDog; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirBottomRight; + if (gnap.walkTo(gnap._pos, 0, -1, 1)) { + gnap.playBrainPulsating(_vm->_hotspotsWalkPos[2]); + _nextDogSequenceId = 0x20E; + } + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS04Door: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 4, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case PLAT_CURSOR: + gnap.playScratchingHead(Common::Point(4, 3)); + break; + case GRAB_CURSOR: + if (_vm->_cursorValue == 1) { + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1); + gnap._actionStatus = kAS04OpenDoor; + _vm->_timers[5] = 300; + gnap._idleFacing = kDirUpLeft; + } else { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107BC, 1); + gnap._actionStatus = kAS04LeaveScene; + _vm->_newSceneNum = 38; + } + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS04ExitTruck: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107AE, 1); + gnap._actionStatus = kAS04LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[5], -1, 0x107C7, 1); + if (_vm->_cursorValue == 1) + _vm->_newSceneNum = 2; + else + _vm->_newSceneNum = 33; + } + break; + + case kHS04Window: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 3); + } else if (_vm->isFlag(kGFKeysTaken)) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (gnap.walkTo(_vm->_hotspotsWalkPos[7], 0, gnap.getSequenceId(kGSIdle, Common::Point(10, 2)) | 0x10000, 1)) { + if (_triedWindow) { + gnap._actionStatus = kAS04GetKeyAnother; + } else { + gnap._actionStatus = kAS04GetKeyFirst; + _triedWindow = true; + } + } + break; + case GRAB_CURSOR: + gnap.playScratchingHead(_vm->_hotspotsWalkPos[7]); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS04ExitBarn: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[8], 0, 0x107AB, 1); + gnap._actionStatus = kAS04LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[8] + Common::Point(0, 1), -1, 0x107C1, 1); + if (_vm->_cursorValue == 1) + _vm->_newSceneNum = 5; + else + _vm->_newSceneNum = 35; + } + break; + + case kHS04WalkArea1: + case kHS04WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1091C)) + _vm->playSound(0x1091C, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) + plat.updateIdleSequence2(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence2(); + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(150) + 300; + if (gnap._actionStatus < 0) + gameSys.insertSequence(0x20D, 79, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[7]) { + _vm->_timers[7] = _vm->getRandom(150) + 200; + gameSys.insertSequence(0x1FC, 59, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(20) + 60; + if (_nextDogSequenceId == -1) + _nextDogSequenceId = 0x210; + } + if (!_vm->_timers[8]) { + _vm->_timers[8] = _vm->getRandom(150) + 400; + gameSys.insertSequence(0x213, 20, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene04::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS04LeaveScene: + _vm->_sceneDone = true; + break; + case kAS04OpenDoor: + gameSys.insertSequence(0x205, gnap._id, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x207, 121, 521, 121, kSeqSyncWait, 0, 0, 0); + gnap._pos = Common::Point(6, 7); + gameSys.insertSequence(0x107B5, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, _vm->getSequenceTotalDuration(0x205) - 1, 450 - gnap._gridX, 336 - gnap._gridY); + gameSys.setAnimation(0x107B5, gnap._id, 0); + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + gnap._actionStatus = kAS04OpenDoorDone; + break; + case kAS04OpenDoorDone: + gameSys.insertSequence(0x209, 121, 0x207, 121, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = -1; + break; + case kAS04GetKeyFirst: + gameSys.insertSequence(0x204, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x204, gnap._id, 0); + gnap._sequenceId = 0x204; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS04GetKeyFirst2; + break; + case kAS04GetKeyFirst2: + gameSys.insertSequence(0x206, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x20B, 256, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0x20B, 256, 0); + gnap._sequenceId = 0x206; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS04GetKeyFirstDone; + break; + case kAS04GetKeyFirstDone: + gameSys.requestRemoveSequence(0x1FF, 256); + gameSys.requestRemoveSequence(0x20B, 256); + gameSys.insertSequence(0x107B5, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._idleFacing = kDirBottomRight; + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + gnap._actionStatus = -1; + break; + case kAS04GetKeyAnother: + gameSys.insertSequence(0x202, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x202, gnap._id, 0); + gnap._sequenceId = 0x202; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS04GetKeyAnother2; + break; + case kAS04GetKeyAnother2: + gameSys.insertSequence(0x203, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x1FF, 256, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x20A, 256, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0x20A, 256, 0); + gnap._sequenceId = 0x203; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS04GetKeyAnotherDone; + break; + case kAS04GetKeyAnotherDone: + gameSys.removeSequence(0x1FF, 256, true); + gameSys.removeSequence(0x20A, 256, true); + gameSys.insertSequence(0x107B5, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), 255, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + gnap._idleFacing = kDirBottomRight; + gnap._actionStatus = -1; + break; + case kAS04GrabDog: + _nextDogSequenceId = 0x201; + break; + case kAS04GrabAxe: + gameSys.insertSequence(0x211, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.requestRemoveSequence(0x212, 100); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x211; + gnap._actionStatus = -1; + break; + default: + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + gameSys.setAnimation(0, 0, 2); + _vm->invAdd(kItemTwig); + _vm->setGrabCursorSprite(kItemTwig); + _vm->setFlag(kGFTwigTaken); + updateHotspots(); + } + + if (gameSys.getAnimationStatus(3) == 2) { + if (_nextDogSequenceId == 0x201) { + gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr, + _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2, + kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3); + _dogIdCtr = (_dogIdCtr + 1) % 2; + _currDogSequenceId = 0x201; + gnap._sequenceId = 0x200; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + _vm->_timers[6] = _vm->getRandom(20) + 60; + _nextDogSequenceId = -1; + } else if (_nextDogSequenceId != -1) { + gameSys.insertSequence(_nextDogSequenceId, 139 - _dogIdCtr, + _currDogSequenceId, 139 - (_dogIdCtr + 1) % 2, + kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextDogSequenceId, 139 - _dogIdCtr, 3); + _dogIdCtr = (_dogIdCtr + 1) % 2; + _currDogSequenceId = _nextDogSequenceId; + _nextDogSequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene05::Scene05(GnapEngine *vm) : Scene(vm) { + _nextChickenSequenceId = -1; + _currChickenSequenceId = -1; +} + +int Scene05::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 3); + return _vm->isFlag(kGFBarnPadlockOpen) ? 0x151 : 0x150; +} + +void Scene05::updateHotspots() { + _vm->setHotspot(kHS05Platypus, 0, 0, 0, 0, SF_DISABLED | SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS05Haystack, 236, 366, 372, 442, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7); + _vm->setHotspot(kHS05Padlock, 386, 230, 626, 481, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7); + _vm->setHotspot(kHS05Ladder, 108, 222, 207, 444, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7); + _vm->setHotspot(kHS05ExitHouse, 0, 395, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8); + _vm->setHotspot(kHS05Chicken, 612, 462, 722, 564, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8); + _vm->setHotspot(kHS05WalkArea1, 104, 0, 421, 480); + _vm->setHotspot(kHS05WalkArea2, 422, 0, 800, 487); + _vm->setHotspot(kHS05WalkArea3, 0, 0, 104, 499); + _vm->setDeviceHotspot(kHS05Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS05Platypus]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + if (_vm->isFlag(kGFBarnPadlockOpen)) + _vm->_hotspots[kHS05Padlock]._flags = SF_EXIT_U_CURSOR; + _vm->_hotspotsCount = 10; +} + +void Scene05::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1091C, true); + _vm->startSoundTimerC(7); + + _currChickenSequenceId = 0x142; + gameSys.setAnimation(0x142, 100, 3); + gameSys.insertSequence(0x142, 100, 0, 0, kSeqNone, 0, 0, 0); + + _nextChickenSequenceId = -1; + + _vm->_timers[5] = _vm->getRandom(10) + 30; + _vm->_timers[6] = _vm->getRandom(150) + 300; + + if (_vm->isFlag(kGFBarnPadlockOpen)) + gameSys.insertSequence(0x14A, 141, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + if (_vm->_prevSceneNum != 6 && _vm->_prevSceneNum != 36) { + gnap.initPos(-1, 8, kDirBottomRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(-1, 9, kDirIdleLeft); + _vm->endSceneInit(); + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(Common::Point(2, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 9), -1, 0x107B9, 1); + } else { + gnap.initPos(6, 8, kDirBottomRight); + if (_vm->isFlag(kGFPlatypus)) + plat.initPos(7, 9, kDirIdleLeft); + _vm->endSceneInit(); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 12, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS05Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS05Platypus: + if (gnap._actionStatus < 0 && _vm->isFlag(kGFPlatypus)) { + if (_vm->_grabCursorSpriteIndex == kItemDisguise) { + gnap.useDisguiseOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFKeysTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS05Haystack: + if (gnap._actionStatus < 0 && plat._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[1] + Common::Point(-2, 0), 4, 5); + } else if (_vm->isFlag(kGFNeedleTaken)) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(_vm->_hotspotsWalkPos[1] + Common::Point(0, -1)); + break; + case GRAB_CURSOR: + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (_vm->isFlag(kGFPlatypus)) { + gnap.useDeviceOnPlatypus(); + if (plat.walkTo(_vm->_hotspotsWalkPos[1], 1, 0x107C2, 1)) { + plat._actionStatus = kAS05PlatSearchHaystack; + plat._idleFacing = kDirIdleRight; + } + if (gnap._pos.x == 4 && (gnap._pos.y == 8 || gnap._pos.y == 7)) + gnap.walkStep(); + gnap.playIdle(plat._pos); + } + break; + } + } + } + break; + + case kHS05Chicken: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemTwig) { + gnap._idleFacing = kDirUpRight; + Common::Point checkPt = _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1); + gnap.walkTo(checkPt, 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS05UseTwigWithChicken; + } else if (_vm->_grabCursorSpriteIndex >= 0) + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot] + Common::Point(0, 1), 9, 7); + else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(Common::Point(9, 7)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS05GrabChicken; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS05TalkChicken; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS05Ladder: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 2, 5); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(Common::Point(2, 4)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirBottomLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS05GrabLadder; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS05Padlock: + if (_vm->isFlag(kGFBarnPadlockOpen)) { + _vm->_isLeavingScene = true; + Common::Point destPt = _vm->_hotspotsWalkPos[2] + Common::Point(- 1, 1); + gnap.walkTo(destPt, 0, -1, 1); + gnap._actionStatus = kAS05EnterBarn; + if (_vm->_cursorValue == 1) + _vm->_newSceneNum = 6; + else + _vm->_newSceneNum = 36; + } else if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemNeedle) { + if (gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, + gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1)) + gnap._actionStatus = kAS05PickPadlock; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 7, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(7, 4)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS05TryPickPadlock; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS05ExitHouse: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AF, 1); + gnap._actionStatus = kAS05LeaveScene; + if (_vm->isFlag(kGFPlatypus)) + plat.walkTo(_vm->_hotspotsWalkPos[4] + Common::Point(0, 1), -1, 0x107C7, 1); + if (_vm->_cursorValue == 1) + _vm->_newSceneNum = 4; + else + _vm->_newSceneNum = 37; + } + break; + + case kHS05WalkArea1: + case kHS05WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + case kHS05WalkArea3: + // Nothing + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1091C)) + _vm->playSound(0x1091C, true); + + if (!_vm->_isLeavingScene) { + if (_vm->isFlag(kGFPlatypus)) + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(20) + 30; + if (gnap._actionStatus != kAS05TalkChicken && _nextChickenSequenceId == -1) { + if (_vm->getRandom(4) != 0) + _nextChickenSequenceId = 0x142; + else + _nextChickenSequenceId = 0x143; + } + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(150) + 300; + if (gnap._actionStatus < 0) + gameSys.insertSequence(0x149, 39, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[5] = _vm->getRandom(20) + 30; + } + + _vm->gameUpdateTick(); + } +} + +void Scene05::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS05LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS05TryPickPadlock: + gameSys.insertSequence(0x148, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x148; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + break; + case kAS05PickPadlock: + gameSys.setAnimation(0x147, gnap._id, 0); + gameSys.insertSequence(0x147, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x147; + gnap._sequenceDatNum = 0; + _vm->setFlag(kGFBarnPadlockOpen); + _vm->setFlag(kGFSceneFlag1); + _vm->setGrabCursorSprite(-1); + _vm->_newSceneNum = 6; + _vm->_timers[2] = 100; + _vm->invRemove(kItemNeedle); + gnap._actionStatus = kAS05LeaveScene; + break; + case kAS05TalkChicken: + _nextChickenSequenceId = 0x144; + gnap._actionStatus = -1; + break; + case kAS05GrabChicken: + _nextChickenSequenceId = 0x14B; + break; + case kAS05GrabLadder: + while (gameSys.isSequenceActive(0x149, 39) && !_vm->_gameDone) + _vm->gameUpdateTick(); + gameSys.insertSequence(0x14E, gnap._id + 1, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x14D; + gnap._sequenceDatNum = 0; + _vm->_timers[2] = 200; + _vm->_timers[6] = 300; + gnap._actionStatus = -1; + break; + case kAS05EnterBarn: + gameSys.insertSequence(0x107B1, 1, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gameSys.setAnimation(0x107B1, 1, 0); + gnap._actionStatus = kAS05LeaveScene; + break; + case kAS05UseTwigWithChicken: + gnap.playShowItem(5, 0, 0); + _nextChickenSequenceId = 0x14F; + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + PlayerPlat& plat = *_vm->_plat; + if (plat._sequenceId == 0x146) { + plat._pos = Common::Point(4, 8); + gameSys.insertSequence(0x107C1, 160, 0x146, 256, kSeqSyncWait, 0, 300 - plat._gridX, 384 - plat._gridY); + plat._sequenceId = 0x7C1; + plat._sequenceDatNum = 1; + plat._id = 20 * plat._pos.y; + _vm->invAdd(kItemNeedle); + _vm->setFlag(kGFNeedleTaken); + _vm->setGrabCursorSprite(kItemNeedle); + _vm->showCursor(); + _vm->_timers[1] = 30; + plat._actionStatus = -1; + } + if (plat._actionStatus == kAS05PlatSearchHaystack) { + gameSys.setAnimation(0, 0, 1); + gameSys.insertSequence(0x145, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x146, 256, 0x145, plat._id, kSeqSyncWait, 0, 0, 0); + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + plat._sequenceId = 0x146; + plat._sequenceDatNum = 0; + gameSys.setAnimation(0x146, 256, 1); + _vm->_timers[1] = 300; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + if (_nextChickenSequenceId == 0x14B) { + gameSys.setAnimation(_nextChickenSequenceId, 100, 3); + gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x14C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x14C; + _currChickenSequenceId = _nextChickenSequenceId; + _nextChickenSequenceId = -1; + gnap._actionStatus = -1; + } else if (_nextChickenSequenceId != -1) { + gameSys.setAnimation(_nextChickenSequenceId, 100, 3); + gameSys.insertSequence(_nextChickenSequenceId, 100, _currChickenSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currChickenSequenceId = _nextChickenSequenceId; + _nextChickenSequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene06::Scene06(GnapEngine *vm) : Scene(vm) { + _horseTurnedBack = false; + _nextPlatSequenceId = -1; + _nextHorseSequenceId = -1; + _currHorseSequenceId = -1; +} + +int Scene06::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + if (_vm->isFlag(kGFSceneFlag1)) { + _vm->playSound(0x11B, false); + _vm->clearFlag(kGFSceneFlag1); + } + return 0x101; +} + +void Scene06::updateHotspots() { + _vm->setHotspot(kHS06Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS06Gas, 300, 120, 440, 232, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7); + _vm->setHotspot(kHS06Ladder, 497, 222, 614, 492, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8); + _vm->setHotspot(kHS06Horse, 90, 226, 259, 376, SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7); + _vm->setHotspot(kHS06ExitOutsideBarn, 226, 580, 688, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10); + _vm->setHotspot(kHS06WalkArea1, 0, 0, 200, 515); + _vm->setHotspot(kHS06WalkArea2, 200, 0, 285, 499); + _vm->setHotspot(kHS06WalkArea3, 688, 0, 800, 499); + _vm->setHotspot(kHS06WalkArea4, 475, 469, 800, 505); + _vm->setHotspot(kHS06WalkArea5, 0, 0, 800, 504); + _vm->setDeviceHotspot(kHS06Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFGasTaken)) + _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED; + if (_vm->_cursorValue == 4) { + _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED; + _vm->_hotspots[kHS06Gas]._flags = SF_DISABLED; + } + _vm->_hotspotsCount = 11; +} + +void Scene06::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + bool triedDeviceOnGas = false; + + _vm->startSoundTimerC(7); + + _horseTurnedBack = false; + gameSys.insertSequence(0xF1, 120, 0, 0, kSeqNone, 0, 0, 0); + + _currHorseSequenceId = 0xF1; + _nextHorseSequenceId = -1; + + gameSys.setAnimation(0xF1, 120, 2); + _vm->_timers[4] = _vm->getRandom(40) + 25; + + if (_vm->isFlag(kGFUnk04)) + gameSys.insertSequence(0xF7, 20, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0xF8, 20, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFGasTaken) && _vm->_cursorValue != 4) + gameSys.insertSequence(0xFE, 20, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + gnap.initPos(5, 12, kDirBottomRight); + plat.initPos(6, 12, kDirIdleLeft); + _vm->endSceneInit(); + + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1); + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 5, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS06Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS06Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemDisguise) { + gnap.useDisguiseOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFKeysTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS06Gas: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 5, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(5, 0)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFUnk04)) { + gnap.playImpossible(); + } else if (triedDeviceOnGas) { + _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107BC, 1); + _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS06TryToGetGas; + } else { + triedDeviceOnGas = true; + gnap.playPullOutDeviceNonWorking(_vm->_hotspotsWalkPos[1]); + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + if (_vm->isFlag(kGFUnk04)) + gnap.playImpossible(); + else + gnap.playScratchingHead(Common::Point(5, 0)); + break; + } + } + } + break; + + case kHS06Ladder: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(8, 4)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFGasTaken)) + gnap.playImpossible(); + else { + gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, 0x107BB, 1); + gnap._actionStatus = kAS06TryToClimbLadder; + _vm->setFlag(kGFGasTaken); + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS06Horse: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemTwig && _horseTurnedBack) { + _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1); + _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE; + gnap._idleFacing = kDirUpLeft; + plat.walkTo(Common::Point(6, 8), 1, 0x107C2, 1); + plat._idleFacing = kDirIdleLeft; + gnap._actionStatus = kAS06UseTwigOnHorse; + _vm->setGrabCursorSprite(-1); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 3, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(3, 2)); + break; + case TALK_CURSOR: + if (_horseTurnedBack) { + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(3, 2)) | 0x10000, 1); + } else { + gnap._idleFacing = kDirBottomLeft; + _vm->_hotspots[kHS06WalkArea5]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + _vm->_hotspots[kHS06WalkArea5]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS06TalkToHorse; + } + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS06ExitOutsideBarn: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[4], 0, 0x107AE, 1); + gnap._actionStatus = kAS06LeaveScene; + if (_vm->_cursorValue == 1) + _vm->_newSceneNum = 5; + else + _vm->_newSceneNum = 35; + } + break; + + case kHS06WalkArea1: + case kHS06WalkArea2: + case kHS06WalkArea3: + case kHS06WalkArea4: + case kHS06WalkArea5: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(40) + 25; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHorseSequenceId == -1) { + if (_horseTurnedBack) { + _nextHorseSequenceId = 0xF5; + } else { + switch (_vm->getRandom(5)) { + case 0: + case 1: + case 2: + _nextHorseSequenceId = 0xF1; + break; + case 3: + _nextHorseSequenceId = 0xF3; + break; + case 4: + _nextHorseSequenceId = 0xF4; + break; + } + } + } + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene06::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS06LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS06TryToGetGas: + gameSys.insertSequence(0xFC, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0xFC; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + break; + case kAS06TryToClimbLadder: + gameSys.insertSequence(0xFF, 20, 0xFE, 20, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0xFD, gnap._id, 0); + gameSys.insertSequence(0xFD, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0xFD; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS06TryToClimbLadderDone; + break; + case kAS06TryToClimbLadderDone: + gnap._pos = Common::Point(6, 7); + gnap._actionStatus = -1; + break; + case kAS06TalkToHorse: + _nextHorseSequenceId = 0xF6; + break; + case kAS06UseTwigOnHorse: + _nextPlatSequenceId = 0xFB; + break; + default: + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + if (plat._sequenceId == 0xFA) { + gameSys.setAnimation(0, 0, 1); + _vm->invAdd(kItemGas); + _vm->setFlag(kGFGasTaken); + _vm->_hotspots[kHS06Ladder]._flags = SF_DISABLED; + _vm->setGrabCursorSprite(kItemGas); + plat._actionStatus = -1; + plat._pos = Common::Point(6, 8); + gameSys.insertSequence(0x107C1, plat._id, 0, 0, kSeqNone, 0, 450 - plat._gridX, 384 - plat._gridY); + plat._sequenceId = 0x7C1; + plat._sequenceDatNum = 1; + _vm->setFlag(kGFUnk04); + gnap._actionStatus = -1; + _vm->showCursor(); + } + if (_nextPlatSequenceId == 0xFB) { + gameSys.setAnimation(0, 0, 1); + _nextHorseSequenceId = 0xF2; + plat._actionStatus = 6; + } + } + + if (gameSys.getAnimationStatus(2) == 2 && _nextHorseSequenceId != -1) { + switch (_nextHorseSequenceId) { + case 0xF2: + _vm->setGrabCursorSprite(-1); + _vm->hideCursor(); + gameSys.setAnimation(0xFA, 256, 1); + gameSys.insertSequence(0xF2, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x100, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0xF7, 20, 0xF8, 20, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0xFB, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0xFA, 256, 0xFB, plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0xFA; + plat._sequenceDatNum = 0; + gameSys.insertSequence(0x107B7, gnap._id, 0x100, gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B7; + gnap._sequenceDatNum = 1; + _currHorseSequenceId = _nextHorseSequenceId; + _nextHorseSequenceId = -1; + _nextPlatSequenceId = -1; + _vm->invRemove(kItemTwig); + break; + case 0xF6: + gameSys.setAnimation(_nextHorseSequenceId, 120, 2); + gameSys.insertSequence(0xF6, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0); + _horseTurnedBack = true; + _currHorseSequenceId = _nextHorseSequenceId; + _nextHorseSequenceId = -1; + gnap._actionStatus = -1; + break; + default: + gameSys.setAnimation(_nextHorseSequenceId, 120, 2); + gameSys.insertSequence(_nextHorseSequenceId, 120, _currHorseSequenceId, 120, kSeqSyncWait, 0, 0, 0); + _currHorseSequenceId = _nextHorseSequenceId; + _nextHorseSequenceId = -1; + break; + } + } +} + +/*****************************************************************************/ + +Scene07::Scene07(GnapEngine *vm) : Scene(vm) { +} + +int Scene07::init() { + return 0x92; +} + +void Scene07::updateHotspots() { + _vm->setHotspot(kHS07Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS07ExitHouse, 700, 125, 799, 290, SF_EXIT_NE_CURSOR); + _vm->setHotspot(kHS07Dice, 200, 290, 270, 360, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS07WalkArea1, 0, 0, 325, 445); + _vm->setHotspot(kHS07WalkArea2, 325, 0, 799, 445, _vm->_isLeavingScene ? SF_WALKABLE : SF_NONE); + _vm->setHotspot(kHS07WalkArea3, 160, 0, 325, 495); + _vm->setDeviceHotspot(kHS07Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypus)) + _vm->_hotspots[kHS07Dice]._flags = SF_DISABLED; + _vm->_hotspotsCount = 7; +} + +void Scene07::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + gameSys.insertSequence(0x8C, 1, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x90, 1, 0, 0, kSeqLoop, 0, 0, 0); + + _vm->invRemove(kItemGas); + _vm->invRemove(kItemNeedle); + + if (!_vm->isFlag(kGFPlatypus)) + gameSys.insertSequence(0x8D, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->_prevSceneNum == 8) { + gnap.initPos(7, 7, kDirBottomLeft); + plat.initPos(9, 7, kDirIdleRight); + _vm->endSceneInit(); + } else { + gnap._pos = Common::Point(6, 7); + gnap._id = 140; + gnap._sequenceId = 0x8F; + gnap._sequenceDatNum = 0; + gnap._idleFacing = kDirBottomRight; + gameSys.insertSequence(0x8F, 140, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gnap._actionStatus = kAS07Wait; + plat._pos = Common::Point(3, 8); + plat._id = 160; + plat._sequenceId = 0x91; + plat._sequenceDatNum = 0; + plat._idleFacing = kDirIdleLeft; + gameSys.insertSequence(0x91, 160, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + } + + _vm->_timers[3] = 600; + _vm->_timers[4] = _vm->getRandom(40) + 50; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x10919)) + _vm->playSound(0x10919, true); + + if (_vm->testWalk(0, 1, 8, 7, 6, 7)) + updateHotspots(); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS07Platypus: + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + break; + + case kHS07ExitHouse: + _vm->_isLeavingScene = true; + if (gnap._pos.x > 8) + gnap.walkTo(Common::Point(gnap._pos.x, 7), 0, 0x107AD, 1); + else + gnap.walkTo(Common::Point(8, 7), 0, 0x107AD, 1); + gnap._actionStatus = kAS07LeaveScene; + break; + + case kHS07Dice: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(4, 8), 3, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + break; + case GRAB_CURSOR: + _vm->setFlag(kGFPlatypus); + _vm->invAdd(kItemDice); + updateHotspots(); + gnap.playPullOutDevice(Common::Point(3, 3)); + gameSys.setAnimation(0x8E, 1, 2); + gameSys.insertSequence(0x8E, 1, 141, 1, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0)) | 0x10000, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = gnap.getSequenceId(kGSUseDevice, Common::Point(0, 0)); + gnap._sequenceDatNum = 1; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS07Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(40) + 50; + } + break; + + case kHS07WalkArea1: + case kHS07WalkArea2: + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + case kHS07WalkArea3: + // Nothing + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + gnap.updateIdleSequence(); + if (plat._actionStatus < 0 && gnap._actionStatus < 0) { + if (_vm->_timers[0]) { + if (!_vm->_timers[1]) { + _vm->_timers[1] = _vm->getRandom(20) + 30; + int gnapRandomValue = _vm->getRandom(20); + if (plat._idleFacing != kDirIdleLeft) { + if (gnapRandomValue == 0 && plat._sequenceId == 0x7CA) + plat.playSequence(0x107CC); + else if (gnapRandomValue == 1 && plat._sequenceId == 0x7CA) + plat.playSequence(0x10845); + else if (plat._pos.y == 9) + plat.playSequence(0x107CA); + } else if (gnapRandomValue == 0 && plat._sequenceId == 0x7C9) + plat.playSequence(0x107CB); + else if (gnapRandomValue == 1 && plat._sequenceId == 0x7C9) + plat.playSequence(0x10844); + else if (plat._pos.y == 9) + plat.playSequence(0x107C9); + gameSys.setAnimation(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, 1); + } + } else { + _vm->_timers[0] = _vm->getRandom(75) + 75; + plat.makeRoom(); + } + } else { + _vm->_timers[0] = 100; + _vm->_timers[1] = 35; + } + playRandomSound(4); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(40) + 50; + } + _vm->gameUpdateTick(); + } +} + +void Scene07::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS07LeaveScene: + _vm->_newSceneNum = 8; + _vm->_sceneDone = true; + break; + } + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(2) == 2) { + gameSys.setAnimation(0, 0, 2); + _vm->setGrabCursorSprite(kItemDice); + } +} + +/*****************************************************************************/ + +Scene08::Scene08(GnapEngine *vm) : Scene(vm) { + _nextDogSequenceId = -1; + _currDogSequenceId = -1; + _nextManSequenceId = -1; + _currManSequenceId = -1; +} + +int Scene08::init() { + return 0x150; +} + +void Scene08::updateHotspots() { + _vm->setHotspot(kH08SPlatypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS08ExitBackdoor, 0, 280, 10, 400, SF_EXIT_L_CURSOR | SF_WALKABLE); + _vm->setHotspot(kHS08ExitCrash, 200, 590, 400, 599, SF_EXIT_D_CURSOR | SF_WALKABLE); + _vm->setHotspot(kHS08Man, 510, 150, 610, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS08Door, 350, 170, 500, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS08Meat, 405, 450, 480, 485, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS08Bone, 200, 405, 270, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS08Toy, 540, 430, 615, 465, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS08WalkArea1, 290, 340, -1, -1); + _vm->setHotspot(kHS08WalkArea2, 0, 0, 799, 420); + _vm->setDeviceHotspot(kHS08Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFBarnPadlockOpen)) + _vm->_hotspots[kHS08Meat]._flags = SF_WALKABLE | SF_DISABLED; + if (_vm->isFlag(kGFTruckFilledWithGas)) + _vm->_hotspots[kHS08Bone]._flags = SF_WALKABLE | SF_DISABLED; + if (_vm->isFlag(kGFTruckKeysUsed)) + _vm->_hotspots[kHS08Toy]._flags = SF_WALKABLE | SF_DISABLED; + _vm->_hotspotsCount = 11; +} + +void Scene08::updateAnimationsCb() { + GameSys& gameSys = *_vm->_gameSys; + + if (gameSys.getAnimationStatus(3) == 2) { + gameSys.setAnimation(_nextDogSequenceId, 100, 3); + gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currDogSequenceId = _nextDogSequenceId; + if ( _nextDogSequenceId != 0x135 ) + _nextDogSequenceId = 0x134; + } +} + +void Scene08::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(0x14F, 1, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x14E, 256, 0, 0, kSeqNone, 0, 0, 0); + + _currDogSequenceId = 0x135; + _nextDogSequenceId = 0x135; + + gameSys.setAnimation(0x135, 100, 3); + gameSys.insertSequence(_currDogSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0); + + _currManSequenceId = 0x140; + _nextManSequenceId = -1; + + gameSys.setAnimation(0x140, 100, 2); + gameSys.insertSequence(_currManSequenceId, 100, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[4] = _vm->getRandom(50) + 75; + + if (!_vm->isFlag(kGFBarnPadlockOpen)) + gameSys.insertSequence(0x144, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFTruckFilledWithGas)) + gameSys.insertSequence(0x145, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFTruckKeysUsed)) + gameSys.insertSequence(0x146, 1, 0, 0, kSeqNone, 0, 0, 0); + + gnap.initPos(-1, 8, kDirBottomRight); + plat.initPos(-1, 7, kDirIdleLeft); + + _vm->endSceneInit(); + + gnap.walkTo(Common::Point(1, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1); + + _vm->_timers[5] = _vm->getRandom(40) + 50; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x10919)) + _vm->playSound(0x10919, true); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS08Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(50) + 75; + _vm->_timers[5] = _vm->getRandom(40) + 50; + } + break; + + case kH08SPlatypus: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFSceneFlag1)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.actionIdle(0x14D); + gnap.kissPlatypus(8); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + } + break; + + case kHS08ExitBackdoor: + _vm->_isLeavingScene = true; + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(0, 6), 0, 0x107AF, 1); + gnap._actionStatus = kAS08LeaveScene; + plat.walkTo(Common::Point(0, 7), 1, 0x107CF, 1); + _vm->_newSceneNum = 9; + break; + + case kHS08ExitCrash: + _vm->_isLeavingScene = true; + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(3, 9), 0, 0x107AE, 1); + gnap._actionStatus = kAS08LeaveScene; + plat.walkTo(Common::Point(4, 9), 1, 0x107C1, 1); + _vm->_newSceneNum = 7; + break; + + case kHS08Man: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(6, 6), 7, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1); + gnap._actionStatus = kAS08LookMan; + gnap._idleFacing = kDirUpRight; + break; + case GRAB_CURSOR: + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(8, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS08TalkMan; + break; + case PLAT_CURSOR: + gnap.actionIdle(0x14D); + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(6, 6), 1, 0x107C2, 1); + plat._actionStatus = kAS08PlatWithMan; + plat._idleFacing = kDirIdleLeft; + gnap.playIdle(Common::Point(6, 6)); + break; + } + } + break; + + case kHS08Door: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(4, 7), 5, 0); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gnap._actionStatus = kAS08GrabDog; + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 0)); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gnap._actionStatus = kAS08LookDog; + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 1); + gnap._actionStatus = kAS08GrabDog; + gnap._idleFacing = kDirUpRight; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS08TalkDog; + break; + case PLAT_CURSOR: + _vm->setFlag(kGFSceneFlag1); + gnap.actionIdle(0x14D); + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(3, 7), 1, 0x107C2, 1); + plat._actionStatus = kAS08PlatWithDog; + plat._idleFacing = kDirIdleLeft; + gnap.playIdle(Common::Point(3, 7)); + break; + } + } + break; + + case kHS08Meat: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(6, 8), 5, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 7)); + break; + case GRAB_CURSOR: + if (_currDogSequenceId == 0x135) { + gnap.playScratchingHead(Common::Point(6, 7)); + } else { + gnap.actionIdle(0x14D); + gnap.playPullOutDevice(Common::Point(6, 7)); + gnap.playUseDevice(); + _nextDogSequenceId = 0x149; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS08Bone: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(2, 7), 3, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(3, 6)); + break; + case GRAB_CURSOR: + if (_currDogSequenceId == 0x135) { + gnap.playScratchingHead(Common::Point(3, 6)); + } else { + gnap.actionIdle(0x14D); + gnap.playPullOutDevice(Common::Point(3, 6)); + gnap.playUseDevice(); + _nextDogSequenceId = 0x14A; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS08Toy: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(8, 7), 7, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(7, 6)); + break; + case GRAB_CURSOR: + if (_currDogSequenceId == 0x135) { + gnap.playScratchingHead(Common::Point(7, 6)); + } else { + gnap.actionIdle(0x14D); + gnap.playPullOutDevice(Common::Point(7, 6)); + gnap.playUseDevice(); + _nextDogSequenceId = 0x14B; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS08WalkArea1: + case kHS08WalkArea2: + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(-1, 6), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.actionIdle(0x14D); + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(50) + 125; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextManSequenceId == -1 && + (_currDogSequenceId == 0x134 || _currDogSequenceId == 0x135)) { + int _gnapRandomValue = _vm->getRandom(4); + switch (_gnapRandomValue) { + case 0: + _nextManSequenceId = 0x138; + break; + case 1: + _nextManSequenceId = 0x136; + break; + case 2: + _nextManSequenceId = 0x13B; + break; + case 3: + _nextManSequenceId = 0x13A; + break; + } + } + } + playRandomSound(5); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(50) + 75; + _vm->_timers[5] = _vm->getRandom(40) + 50; + } + + _vm->gameUpdateTick(); + } +} + +void Scene08::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS08LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS08TalkMan: + _nextManSequenceId = 0x13F; + gnap._actionStatus = -1; + break; + case kAS08LookMan: + _nextManSequenceId = 0x140; + gnap._actionStatus = -1; + break; + case kAS08LookDog: + _nextManSequenceId = 0x137; + gnap._actionStatus = -1; + break; + case kAS08GrabDog: + if (_currDogSequenceId == 0x135) + _nextDogSequenceId = 0x133; + else + _nextDogSequenceId = 0x13C; + gnap._actionStatus = -1; + break; + case kAS08TalkDog: + if (_currDogSequenceId == 0x135) + _nextDogSequenceId = 0x133; + else + _nextDogSequenceId = 0x13C; + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + switch (plat._actionStatus) { + case kAS08PlatWithDog: + _nextDogSequenceId = 0x147; + break; + case kAS08PlatWithMan: + _nextManSequenceId = 0x140; + plat._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2 && _nextManSequenceId != -1) { + gameSys.setAnimation(_nextManSequenceId, 100, 2); + gameSys.insertSequence(_nextManSequenceId, 100, _currManSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currManSequenceId = _nextManSequenceId; + _nextManSequenceId = -1; + } + + if (gameSys.getAnimationStatus(3) == 2) { + if (_currDogSequenceId == 0x147) + plat._actionStatus = -1; + if (_currDogSequenceId == 0x149 || _currDogSequenceId == 0x14A || _currDogSequenceId == 0x14B) { + if (_vm->getRandom(2) != 0) + _nextManSequenceId = 0x13D; + else + _nextManSequenceId = 0x13E; + } else if (_currDogSequenceId == 0x133) + _nextManSequenceId = 0x139; + if (_nextDogSequenceId == 0x149 || _nextDogSequenceId == 0x14A || _nextDogSequenceId == 0x14B) { + gameSys.setAnimation(_nextDogSequenceId, 100, 3); + gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0); + switch (_nextDogSequenceId) { + case 0x149: + _vm->setFlag(kGFBarnPadlockOpen); + _vm->_hotspots[kHS08Meat]._flags = SF_DISABLED | SF_WALKABLE; + gameSys.removeSequence(0x144, 1, true); + break; + case 0x14A: + _vm->setFlag(kGFTruckFilledWithGas); + _vm->_hotspots[kHS08Bone]._flags = SF_DISABLED | SF_WALKABLE; + gameSys.removeSequence(0x145, 1, true); + break; + case 0x14B: + _vm->setFlag(kGFTruckKeysUsed); + _vm->_hotspots[kHS08Toy]._flags = SF_DISABLED | SF_WALKABLE; + gameSys.removeSequence(0x146, 1, true); + break; + } + _currDogSequenceId = _nextDogSequenceId; + _nextDogSequenceId = 0x134; + } else if (_nextDogSequenceId == 0x147) { + gameSys.setAnimation(_nextDogSequenceId, 100, 3); + gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x148, 160, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + _currDogSequenceId = _nextDogSequenceId; + _nextDogSequenceId = 0x134; + plat._pos = Common::Point(1, 8); + plat._id = 160; + plat._sequenceId = 0x148; + plat._idleFacing = kDirIdleRight; + plat._sequenceDatNum = 0; + if (gnap._pos == Common::Point(1, 8)) + gnap.walkStep(); + } else if (_nextDogSequenceId != -1) { + gameSys.setAnimation(_nextDogSequenceId, 100, 3); + gameSys.insertSequence(_nextDogSequenceId, 100, _currDogSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currDogSequenceId = _nextDogSequenceId; + if (_nextDogSequenceId != 0x135) + _nextDogSequenceId = 0x134; + if (_currDogSequenceId == 0x133) { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + gameSys.insertSequence(0x14D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x14D; + gnap._idleFacing = kDirUpRight; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + } + } + } +} + +/*****************************************************************************/ + +Scene09::Scene09(GnapEngine *vm) : Scene(vm) { +} + +int Scene09::init() { + return 0x4E; +} + +void Scene09::updateHotspots() { + _vm->setHotspot(kHS09Platypus, 0, 200, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS09ExitKitchen, 280, 200, 380, 400, SF_EXIT_U_CURSOR); + _vm->setHotspot(kHS09ExitHouse, 790, 200, 799, 450, SF_EXIT_R_CURSOR | SF_WALKABLE); + _vm->setHotspot(kHS09Trash, 440, 310, 680, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS09WalkArea1, 0, 0, 799, 400); + _vm->setHotspot(kHS09WalkArea2, 0, 0, 630, 450); + _vm->setHotspot(kHS09WalkArea2, 0, 0, 175, 495); + _vm->setDeviceHotspot(kHS09Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 8; +} + +void Scene09::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(0x4D, 1, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->_prevSceneNum == 8) { + gnap.initPos(11, 8, kDirBottomLeft); + plat.initPos(12, 7, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1); + } else { + gnap.initPos(4, 7, kDirBottomRight); + plat.initPos(5, 7, kDirIdleLeft); + _vm->endSceneInit(); + } + + _vm->_timers[4] = _vm->getRandom(150) + 50; + _vm->_timers[5] = _vm->getRandom(40) + 50; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x10919)) + _vm->playSound(0x10919, true); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS09Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(150) + 50; + _vm->_timers[5] = _vm->getRandom(40) + 50; + } + break; + + case kHS09Platypus: + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + break; + + case kHS09ExitKitchen: + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 10; + gnap.walkTo(Common::Point(4, 7), 0, 0x107BF, 1); + gnap._actionStatus = kAS09LeaveScene; + plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1); + plat._idleFacing = kDirIdleRight; + break; + + case kHS09ExitHouse: + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 8; + gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1); + gnap._actionStatus = kAS09LeaveScene; + plat.walkTo(Common::Point(10, -1), -1, 0x107CD, 1); + plat._idleFacing = kDirIdleRight; + break; + + case kHS09Trash: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(9, 6), 8, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(8, 3)); + break; + case GRAB_CURSOR: + gnap._actionStatus = kAS09SearchTrash; + gnap.walkTo(Common::Point(9, 6), 0, 0x107BC, 1); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS09WalkArea1: + case kHS09WalkArea2: + case kHS09WalkArea3: + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene && gnap._actionStatus != 1 && gnap._actionStatus != 2) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(150) + 100; + if (_vm->_timers[4] & 1) + gameSys.insertSequence(0x49, 1, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x4A, 1, 0, 0, kSeqNone, 0, 0, 0); + } + playRandomSound(5); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(150) + 50; + _vm->_timers[5] = _vm->getRandom(40) + 50; + } + + _vm->gameUpdateTick(); + } +} + +void Scene09::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS09LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS09SearchTrash: + gameSys.setAnimation(0x4C, 120, 0); + gameSys.insertSequence(0x4C, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0x4B, 2, true); + gnap._sequenceId = 0x4C; + gnap._id = 120; + gnap._idleFacing = kDirUpLeft; + gnap._sequenceDatNum = 0; + gnap._pos = Common::Point(9, 6); + gnap._actionStatus = kAS09SearchTrashDone; + break; + case kAS09SearchTrashDone: + gameSys.insertSequence(0x4B, 2, 0, 0, kSeqNone, 0, 0, 0); + _vm->_timers[2] = 360; + _vm->_timers[4] = _vm->getRandom(150) + 100; + gnap._actionStatus = -1; + break; + } + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/group0.h b/engines/gnap/scenes/group0.h new file mode 100644 index 0000000000..e06380926d --- /dev/null +++ b/engines/gnap/scenes/group0.h @@ -0,0 +1,401 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUP0_H +#define GNAP_GROUP0_H + +#include "gnap/debugger.h" + +namespace Gnap { + +enum { + kHS01Platypus = 0, + kHS01ExitTruck = 1, + kHS01Mud = 2, + kHS01Pigs = 3, + kHS01Spaceship = 4, + kHS01Device = 5, + kHS01WalkArea1 = 6, + kHS01WalkArea2 = 7, + kHS01WalkArea3 = 8, + kHS01WalkArea4 = 9, + kHS01WalkArea5 = 10, + kHS01WalkArea6 = 11, + kHS01WalkArea7 = 12, + kHS01WalkArea8 = 13 +}; + +enum { + kHS02Platypus = 0, + kHS02Chicken = 1, + kHS02Truck1 = 2, + kHS02Truck2 = 3, + kHS02TruckGrill = 4, + kHS02Device = 5, + kHS02ExitHouse = 6, + kHS02ExitBarn = 7, + kHS02ExitCreek = 8, + kHS02ExitPigpen = 9, + kHS02WalkArea1 = 10, + kHS02WalkArea2 = 11, + kHS02WalkArea3 = 12, + kHS02WalkArea4 = 13 +}; + +enum { + kHS03Platypus = 0, + kHS03Grass = 1, + kHS03ExitTruck = 2, + kHS03Creek = 3, + kHS03TrappedPlatypus = 4, + kHS03Device = 5, + kHS03WalkAreas1 = 6, + kHS03WalkAreas2 = 7, + kHS03PlatypusWalkArea = 8, + kHS03WalkAreas3 = 9 +}; + +enum { + kHS04Platypus = 0, + kHS04Twig = 1, + kHS04Dog = 2, + kHS04Axe = 3, + kHS04Door = 4, + kHS04ExitTruck = 5, + kHS04Device = 6, + kHS04Window = 7, + kHS04ExitBarn = 8, + kHS04WalkArea1 = 9, + kHS04WalkArea2 = 10 +}; + +enum { + kHS05Platypus = 0, + kHS05Haystack = 1, + kHS05Padlock = 2, + kHS05Ladder = 3, + kHS05ExitHouse = 4, + kHS05Chicken = 5, + kHS05Device = 6, + kHS05WalkArea1 = 7, + kHS05WalkArea2 = 8, + kHS05WalkArea3 = 9 +}; + +enum { + kHS06Platypus = 0, + kHS06Gas = 1, + kHS06Ladder = 2, + kHS06Horse = 3, + kHS06ExitOutsideBarn = 4, + kHS06Device = 5, + kHS06WalkArea1 = 6, + kHS06WalkArea2 = 7, + kHS06WalkArea3 = 8, + kHS06WalkArea4 = 9, + kHS06WalkArea5 = 10 +}; + +enum { + kHS07Platypus = 0, + kHS07ExitHouse = 1, + kHS07Dice = 2, + kHS07Device = 3, + kHS07WalkArea1 = 4, + kHS07WalkArea2 = 5, + kHS07WalkArea3 = 6 +}; + +enum { + kH08SPlatypus = 0, + kHS08ExitBackdoor = 1, + kHS08ExitCrash = 2, + kHS08Man = 3, + kHS08Door = 4, + kHS08Meat = 5, + kHS08Bone = 6, + kHS08Toy = 7, + kHS08WalkArea1 = 8, + kHS08Device = 9, + kHS08WalkArea2 = 10 +}; + +enum { + kHS09Platypus = 0, + kHS09ExitKitchen = 1, + kHS09ExitHouse = 2, + kHS09Trash = 3, + kHS09Device = 4, + kHS09WalkArea1 = 5, + kHS09WalkArea2 = 6, + kHS09WalkArea3 = 7 +}; + +enum { + kAS01LookSpaceship = 1, + kAS01LookSpaceshipDone = 2, + kAS01LeaveScene = 3, + kAS01TakeMud = 5, + kAS01LookPigs = 6, + kAS01UsePigs = 7 +}; + +enum { + kAS02UseTruckNoKeys = 0, + kAS02UseGasWithTruck = 1, + kAS02UseTruckGas = 2, + kAS02UseTruckNoGas = 3, + kAS02GrabTruckGrill = 5, + kAS02LeaveScene = 6, + kAS02TalkChicken = 7, + kAS02GrabChicken = 8, + kAS02GrabChickenDone = 9, + kAS02UseTruckNoKeysDone = 11, + kAS02UseGasWithTruckDone = 12, + kAS02UseTwigWithChicken = 16 +}; + +enum { + kAS03LeaveScene = 0, + kAS03FreePlatypus = 1, + kAS03HypnotizePlat = 2, + kAS03HypnotizeScaredPlat= 3, + kAS03FreePlatypusDone = 4, + kAS03GrabPlatypus = 5, + kAS03GrabCreek = 6, + kAS03GrabCreekDone = 7, + kAS03GrabScaredPlatypus = 8 +}; + +enum { + kAS04OpenDoor = 1, + kAS04GetKeyFirst = 2, + kAS04GetKeyAnother = 3, + kAS04LeaveScene = 4, + kAS04GetKeyFirstDone = 6, + kAS04GetKeyFirst2 = 7, + kAS04GetKeyAnother2 = 8, + kAS04GetKeyAnotherDone = 9, + kAS04OpenDoorDone = 10, + kAS04GrabDog = 12, + kAS04GrabAxe = 13 +}; + +enum { + kAS05PlatSearchHaystack = 0, + kAS05TryPickPadlock = 1, + kAS05PickPadlock = 2, + kAS05TalkChicken = 3, + kAS05GrabChicken = 4, + kAS05GrabLadder = 5, + kAS05EnterBarn = 6, + kAS05UseTwigWithChicken = 11, + kAS05LeaveScene = 12 +}; + +enum { + kAS06TryToGetGas = 0, + kAS06TryToClimbLadder = 1, + kAS06TryToClimbLadderDone = 2, + kAS06TalkToHorse = 3, + kAS06UseTwigOnHorse = 4, + kAS06LeaveScene = 5 +}; + +enum { + kAS07Wait = 0, + kAS07LeaveScene = 1 +}; + +enum { + kAS08LeaveScene = 0, + kAS08TalkMan = 1, + kAS08LookMan = 2, + kAS08LookDog = 3, + kAS08GrabDog = 4, + kAS08TalkDog = 5, + kAS08PlatWithMan = 6, + kAS08PlatWithDog = 7 +}; + +enum { + kAS09LeaveScene = 0, + kAS09SearchTrash = 1, + kAS09SearchTrashDone = 2 +}; + +/*****************************************************************************/ + +class GnapEngine; +class CutScene; + +class Scene01: public Scene { +public: + Scene01(GnapEngine *vm); + virtual ~Scene01(); + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} + +private: + int _pigsIdCtr; + int _smokeIdCtr; + Graphics::Surface *_spaceshipSurface; +}; + +class Scene02: public Scene { +public: + Scene02(GnapEngine *vm); + virtual ~Scene02() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} + +private: + int _truckGrillCtr; + int _nextChickenSequenceId; + int _currChickenSequenceId; + int _gnapTruckSequenceId; +}; + +class Scene03: public Scene { +public: + Scene03(GnapEngine *vm); + virtual ~Scene03() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} + +private: + bool _platypusHypnotized; + bool _platypusScared; + int _nextPlatSequenceId; + int _nextFrogSequenceId; + int _currFrogSequenceId; +}; + +class Scene04: public Scene { +public: + Scene04(GnapEngine *vm); + virtual ~Scene04() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} + +private: + bool _triedWindow; + int _dogIdCtr; + int _nextDogSequenceId; + int _currDogSequenceId; +}; + +class Scene05: public Scene { +public: + Scene05(GnapEngine *vm); + virtual ~Scene05() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} + +private: + int _nextChickenSequenceId; + int _currChickenSequenceId; +}; + +class Scene06: public Scene { +public: + Scene06(GnapEngine *vm); + virtual ~Scene06() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} + +private: + bool _horseTurnedBack; + int _nextPlatSequenceId; + int _nextHorseSequenceId; + int _currHorseSequenceId; +}; + +class Scene07: public Scene { +public: + Scene07(GnapEngine *vm); + virtual ~Scene07() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} +}; + +class Scene08: public Scene { +public: + Scene08(GnapEngine *vm); + virtual ~Scene08() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb(); + +private: + int _nextDogSequenceId; + int _currDogSequenceId; + int _nextManSequenceId; + int _currManSequenceId; +}; + +class Scene09: public Scene { +public: + Scene09(GnapEngine *vm); + virtual ~Scene09() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {} +}; + +} // End of namespace Gnap + +#endif // GNAP_GROUP0_H diff --git a/engines/gnap/scenes/group1.cpp b/engines/gnap/scenes/group1.cpp new file mode 100644 index 0000000000..f76d04c64d --- /dev/null +++ b/engines/gnap/scenes/group1.cpp @@ -0,0 +1,4496 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/group1.h" + +namespace Gnap { + +Scene10::Scene10(GnapEngine *vm) : Scene(vm) { + _nextCookSequenceId = -1; + _currCookSequenceId = -1; +} + +int Scene10::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + return 0x10F; +} + +void Scene10::updateHotspots() { + _vm->setHotspot(kHS10Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS10ExitBar, 0, 75, 85, 455, SF_EXIT_NW_CURSOR); + _vm->setHotspot(kHS10ExitBackdoor, 75, 590, 500, 599, SF_EXIT_D_CURSOR | SF_WALKABLE); + _vm->setHotspot(kHS10Cook, 370, 205, 495, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS10Tongs, 250, 290, 350, 337, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS10Box, 510, 275, 565, 330, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS10Oven, 690, 280, 799, 420, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS10WalkArea1, 59, 0, 495, 460); + _vm->setHotspot(kHS10WalkArea2, 495, 0, 650, 420); + _vm->setHotspot(kHS10WalkArea3, 651, 0, 725, 400); + _vm->setHotspot(kHS10WalkArea4, 725, 0, 799, 441); + _vm->setDeviceHotspot(kHS10Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 12; +} + +void Scene10::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _currCookSequenceId = 0x103; + + gameSys.setAnimation(0x103, 100, 2); + gameSys.insertSequence(0x103, 100, 0, 0, kSeqNone, 0, 0, 0); + + _nextCookSequenceId = 0x106; + if (!_vm->isFlag(kGFMudTaken)) + gameSys.insertSequence(0x107, 100, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + if (_vm->_prevSceneNum == 9) { + gnap.initPos(11, 8, kDirBottomLeft); + plat.initPos(12, 7, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(9, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1); + } else { + gnap.initPos(-1, 7, kDirBottomRight); + plat.initPos(-2, 8, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(1, 7), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + } + + _vm->_timers[4] = _vm->getRandom(80) + 150; + _vm->_timers[5] = _vm->getRandom(100) + 100; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1091E)) + _vm->playSound(0x1091E, true); + + if (!_vm->isSoundPlaying(0x1091A)) + _vm->playSound(0x1091A, true); + + _vm->updateMouseCursor(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS10Platypus: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFMudTaken)) + gnap.playMoan1(plat._pos); + else + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(10); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + } + break; + + case kHS10ExitBar: + _vm->_isLeavingScene = true; + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(0, 7), 0, 0x107AF, 1); + gnap._actionStatus = kAS10LeaveScene; + plat.walkTo(Common::Point(0, 7), -1, 0x107CF, 1); + _vm->_newSceneNum = 11; + break; + + case kHS10ExitBackdoor: + _vm->_isLeavingScene = true; + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(2, 9), 0, 0x107AE, 1); + gnap._actionStatus = kAS10LeaveScene; + plat.walkTo(Common::Point(3, 9), -1, 0x107C7, 1); + _vm->_newSceneNum = 9; + break; + + case kHS10Cook: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(4, 8), 6, 0); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gnap._actionStatus = kAS10AnnoyCook; + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 0)); + break; + case GRAB_CURSOR: + gnap.playImpossible(); + gnap._idleFacing = kDirBottomRight; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(4, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS10AnnoyCook; + break; + case PLAT_CURSOR: + gnap.actionIdle(0x10C); + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(4, 6), -1, -1, 1); + gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1); + gnap._actionStatus = kAS10AnnoyCook; + break; + } + } + break; + + case kHS10Tongs: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(3, 7), 4, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFMudTaken)) + gnap.playMoan2(Common::Point(-1, -1)); + else + gnap.playScratchingHead(Common::Point(4, 3)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFMudTaken)) + gnap.playMoan2(Common::Point(-1, -1)); + else { + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1); + gnap._actionStatus = kAS10AnnoyCook; + } + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (_vm->isFlag(kGFMudTaken)) + gnap.playMoan2(Common::Point(-1, -1)); + else { + gnap.actionIdle(0x10C); + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(3, 7), -1, -1, 1); + gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1); + gnap._actionStatus = kAS10AnnoyCook; + } + break; + } + } + break; + + case kHS10Box: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(7, 6), 6, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(7, 3)); + break; + case GRAB_CURSOR: + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(4, 8), 0, 0x107BB, 1); + gnap._actionStatus = kAS10AnnoyCook; + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (_vm->isFlag(kGFMudTaken)) + gnap.playMoan2(Common::Point(-1, -1)); + else { + _vm->invAdd(kItemTongs); + _vm->setFlag(kGFMudTaken); + gnap.actionIdle(0x10C); + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(7, 6), 1, 0x107D2, 1); + plat._actionStatus = kAS10PlatWithBox; + plat._idleFacing = kDirIdleRight; + _vm->_largeSprite = gameSys.createSurface(0xC3); + gnap.playIdle(Common::Point(7, 6)); + } + break; + } + } + break; + + case kHS10Oven: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(9, 6), 10, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(10, 5)) | 0x10000); + break; + case GRAB_CURSOR: + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(9, 6), 0, 0x107BB, 1); + gameSys.insertSequence(0x10E, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x10E; + gnap._id = 120; + gnap._idleFacing = kDirUpRight; + gnap._sequenceDatNum = 0; + gnap._pos = Common::Point(9, 6); + _vm->_timers[2] = 360; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS10WalkArea1: + case kHS10WalkArea2: + case kHS10WalkArea3: + case kHS10WalkArea4: + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + case kHS10Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.actionIdle(0x10C); + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(80) + 150; + _vm->playSound(0x12B, false); + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(100) + 100; + int _gnapRandomValue = _vm->getRandom(4); + if (_gnapRandomValue) { + int sequenceId; + if (_gnapRandomValue == 1) { + sequenceId = 0x8A5; + } else if (_gnapRandomValue == 2) { + sequenceId = 0x8A6; + } else { + sequenceId = 0x8A7; + } + gameSys.insertSequence(sequenceId | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene10::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS10LeaveScene: + _vm->_sceneDone = true; + break; + case kAS10AnnoyCook: + _nextCookSequenceId = 0x105; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + switch (plat._actionStatus) { + case kAS10PlatWithBox: + _nextCookSequenceId = 0x109; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2 && _nextCookSequenceId != -1) { + + switch (_nextCookSequenceId) { + case 0x109: + plat._pos = Common::Point(4, 8); + gameSys.insertSequence(0x109, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x107C9, 160, + plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, + kSeqSyncWait, _vm->getSequenceTotalDuration(0x109) + _vm->getSequenceTotalDuration(0x10A) + _vm->getSequenceTotalDuration(0x10843), + 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY); + gameSys.removeSequence(0x107, 100, true); + _currCookSequenceId = 0x109; + _nextCookSequenceId = 0x843; + plat._sequenceId = 0x7C9; + plat._id = 160; + plat._idleFacing = kDirIdleLeft; + plat._sequenceDatNum = 1; + break; + case 0x843: + _vm->hideCursor(); + gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300); + gameSys.insertSequence(0x10843, 301, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currCookSequenceId = 0x843; + _nextCookSequenceId = 0x10A; + break; + case 0x10A: + gameSys.insertSequence(_nextCookSequenceId, 100, 0x10843, 301, kSeqSyncWait, 0, 0, 0); + _currCookSequenceId = _nextCookSequenceId; + _nextCookSequenceId = 0x104; + _vm->showCursor(); + gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300); + _vm->delayTicksCursor(5); + _vm->deleteSurface(&_vm->_largeSprite); + _vm->setGrabCursorSprite(kItemTongs); + if (plat._actionStatus == kAS10PlatWithBox) + plat._actionStatus = -1; + if (gnap._pos == Common::Point(4, 8)) + gnap.walkStep(); + break; + default: + gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currCookSequenceId = _nextCookSequenceId; + break; + } + + switch (_currCookSequenceId) { + case 0x106: + if (gnap._actionStatus >= 0 || plat._actionStatus >= 0) + _nextCookSequenceId = 0x106; + else { + int rnd = _vm->getRandom(7); + switch (rnd) { + case 0: + _nextCookSequenceId = 0x104; + break; + case 1: + _nextCookSequenceId = 0x103; + break; + case 2: + _nextCookSequenceId = 0x106; + gameSys.insertSequence(0x10D, 1, 0, 0, kSeqNone, 0, 0, 0); + break; + default: + _nextCookSequenceId = 0x106; + } + } + break; + case 0x103: + if (gnap._actionStatus >= 0 || plat._actionStatus >= 0) + _nextCookSequenceId = 0x106; + else if (_vm->getRandom(7) == 0) + _nextCookSequenceId = 0x104; + else + _nextCookSequenceId = 0x106; + break; + case 0x104: + if (gnap._actionStatus >= 0 || plat._actionStatus >= 0) + _nextCookSequenceId = 0x106; + else if (_vm->getRandom(7) == 0) + _nextCookSequenceId = 0x103; + else + _nextCookSequenceId = 0x106; + break; + case 0x105: + if (gnap._actionStatus >= 0 || plat._actionStatus >= 0) + _nextCookSequenceId = 0x106; + else { + int rnd = _vm->getRandom(7); + switch (rnd) { + case 0: + _nextCookSequenceId = 0x104; + break; + case 1: + _nextCookSequenceId = 0x103; + break; + default: + _nextCookSequenceId = 0x106; + } + } + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = 300; + gameSys.insertSequence(0x10C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x10C; + gnap._idleFacing = kDirUpRight; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + plat._actionStatus = -1; + break; + } + if (_currCookSequenceId == 0x843) + gameSys.setAnimation(_currCookSequenceId | 0x10000, 301, 2); + else + gameSys.setAnimation(_currCookSequenceId, 100, 2); + } +} + +void Scene10::updateAnimationsCb() { + GameSys& gameSys = *_vm->_gameSys; + + if (gameSys.getAnimationStatus(2) == 2) { + gameSys.setAnimation(_nextCookSequenceId, 100, 2); + gameSys.insertSequence(_nextCookSequenceId, 100, _currCookSequenceId, 100, kSeqSyncWait, 0, 0, 0); + _currCookSequenceId = _nextCookSequenceId; + _nextCookSequenceId = 0x106; + } +} + +/*****************************************************************************/ + +Scene11::Scene11(GnapEngine *vm) : Scene(vm) { + _billardBallCtr = 0; + _nextHookGuySequenceId = -1; + _currHookGuySequenceId = -1; + _nextGoggleGuySequenceId = -1; + _currGoggleGuySequenceId = -1; +} + +int Scene11::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 3); + gameSys.setAnimation(0, 0, 2); + if (_vm->_prevSceneNum == 10 || _vm->_prevSceneNum == 13) { + _vm->playSound(0x108EC, false); + _vm->playSound(0x10928, false); + } + return 0x209; +} + +void Scene11::updateHotspots() { + _vm->setHotspot(kHS11Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS11ExitKitchen, 420, 140, 520, 345, SF_EXIT_U_CURSOR); + _vm->setHotspot(kHS11ExitToilet, 666, 130, 740, 364, SF_EXIT_R_CURSOR); + _vm->setHotspot(kHS11ExitLeft, 0, 350, 10, 599, SF_EXIT_L_CURSOR | SF_WALKABLE); + _vm->setHotspot(kHS11GoggleGuy, 90, 185, 185, 340, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS11HookGuy, 210, 240, 340, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS11Billard, 640, 475, 700, 530, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS11WalkArea1, 0, 0, 365, 453); + _vm->setHotspot(kHS11WalkArea2, 0, 0, 629, 353); + _vm->setHotspot(kHS11WalkArea3, 629, 0, 799, 364); + _vm->setHotspot(kHS11WalkArea4, 735, 0, 799, 397); + _vm->setHotspot(kHS11WalkArea5, 510, 540, 799, 599); + _vm->setDeviceHotspot(kHS11Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 13; +} + +void Scene11::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + bool flag = true; + + _vm->_timers[7] = 50; + _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED; + + _currGoggleGuySequenceId = 0x1F9; + _currHookGuySequenceId = 0x201; + + switch (_vm->_prevSceneNum) { + case 13: + gnap.initPos(8, 5, kDirBottomLeft); + plat.initPos(9, 6, kDirIdleRight); + break; + case 47: + gnap.initPos(8, 5, kDirBottomLeft); + plat.initPos(9, 5, kDirIdleRight); + _currGoggleGuySequenceId = 0x1FA; + _currHookGuySequenceId = 0x1FF; + _vm->_timers[7] = 180; + break; + case 12: + gnap.initPos(-1, 9, kDirBottomRight); + plat.initPos(-2, 8, kDirIdleLeft); + break; + default: + gnap.initPos(6, 6, kDirBottomLeft); + plat.initPos(6, 5, kDirIdleRight); + break; + } + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(_currHookGuySequenceId, 120, 0, 0, kSeqNone, 0, 0, 0); + + _nextHookGuySequenceId = -1; + + gameSys.setAnimation(_currHookGuySequenceId, 120, 3); + gameSys.insertSequence(_currGoggleGuySequenceId, 121, 0, 0, kSeqNone, 0, 0, 0); + + _nextGoggleGuySequenceId = -1; + + gameSys.setAnimation(_currGoggleGuySequenceId, 121, 2); + + _vm->_timers[5] = _vm->getRandom(100) + 75; + _vm->_timers[4] = _vm->getRandom(40) + 20; + _vm->_timers[6] = _vm->getRandom(100) + 100; + _vm->endSceneInit(); + + if (_vm->_prevSceneNum == 12) { + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + } + + gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, 40, 0, 0); + + while (!_vm->_sceneDone) { + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS11Platypus: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + } + break; + + case kHS11ExitKitchen: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(6, 5), 0, 0x107BF, 1); + gnap._actionStatus = kAS11LeaveScene; + plat.walkTo(Common::Point(6, 6), -1, -1, 1); + _vm->_newSceneNum = 10; + break; + + case kHS11ExitToilet: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(8, 5), 0, 0x107BF, 1); + gnap._actionStatus = kAS11LeaveScene; + plat.walkTo(Common::Point(8, 6), -1, -1, 1); + _vm->_newSceneNum = 13; + break; + + case kHS11ExitLeft: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(-1, 8), 0, 0x107AF, 1); + gnap._actionStatus = kAS11LeaveScene; + plat.walkTo(Common::Point(-1, 9), -1, 0x107CF, 1); + _vm->_newSceneNum = 12; + break; + + case kHS11GoggleGuy: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemMagazine) { + gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1); + gnap._actionStatus = kAS11ShowMagazineToGoggleGuy; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(3, 7), 2, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 6)); + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS11TalkGoggleGuy; + break; + } + } + } + break; + + case kHS11HookGuy: + if (gnap._actionStatus < 0) { + gnap._idleFacing = kDirUpRight; + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 9); + gnap._actionStatus = kAS11ShowItemToHookGuy; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 4, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(3, 6)) | 0x10000); + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1); + gnap._actionStatus = kAS11GrabHookGuy; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirBottomLeft; + gnap.walkTo(Common::Point(5, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS11TalkHookGuy; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS11Billard: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(Common::Point(9, 8)); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(9, 8)); + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(9, 8), 0, 0x107BA, 1); + gnap._actionStatus = kAS11GrabBillardBall; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(Common::Point(9, 8)); + break; + } + } + } + break; + + case kHS11WalkArea1: + case kHS11WalkArea2: + case kHS11WalkArea3: + case kHS11WalkArea4: + case kHS11WalkArea5: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + case kHS11Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + if (flag && !_vm->_timers[7]) { + flag = false; + gameSys.setAnimation(0x207, 257, 4); + gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, 0, 0, 0); + } + plat.updateIdleSequence2(); + gnap.updateIdleSequence2(); + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(100) + 75; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextGoggleGuySequenceId == -1) { + if (_vm->getRandom(2)) + _nextGoggleGuySequenceId = 0x1F6; + else + _nextGoggleGuySequenceId = 0x1F9; + } + } + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(40) + 20; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextHookGuySequenceId == -1) { + if (_currHookGuySequenceId == 0x201) { + switch (_vm->getRandom(7)) { + case 0: + _nextHookGuySequenceId = 0x200; + break; + case 1: + _nextHookGuySequenceId = 0x205; + break; + case 2: + _nextHookGuySequenceId = 0x202; + break; + default: + _nextHookGuySequenceId = 0x201; + break; + } + } else { + _nextHookGuySequenceId = 0x201; + } + } + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(100) + 100; + int _gnapRandomValue = _vm->getRandom(3); + switch (_gnapRandomValue) { + case 0: + gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + break; + case 1: + gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + break; + case 2: + gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + break; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[5] = _vm->getRandom(50) + 75; + _vm->_timers[4] = _vm->getRandom(40) + 20; + } + + _vm->gameUpdateTick(); + } +} + +void Scene11::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + if (gnap._actionStatus != kAS11GrabBillardBall) + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS11LeaveScene: + _vm->_sceneDone = true; + break; + case kAS11ShowMagazineToGoggleGuy: + _nextGoggleGuySequenceId = 0x1F7; + break; + case kAS11TalkGoggleGuy: + _nextGoggleGuySequenceId = 0x1FB; + break; + case kAS11GrabHookGuy: + _nextHookGuySequenceId = 0x204; + break; + case kAS11ShowItemToHookGuy: + _nextHookGuySequenceId = 0x203; + break; + case kAS11TalkHookGuy: + _nextHookGuySequenceId = 0x206; + break; + case kAS11GrabBillardBall: + if (gameSys.getAnimationStatus(2) == 2 && gameSys.getAnimationStatus(3) == 2) { + gameSys.setAnimation(0, 0, 0); + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + gameSys.insertSequence(0x1F4, 255, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x1F4; + gnap._id = 255; + gnap._sequenceDatNum = 0; + gameSys.removeSequence(0x207, 257, true); + gameSys.removeSequence(0x208, 256, true); + _nextGoggleGuySequenceId = 0x1F8; + _vm->_timers[5] = _vm->getRandom(100) + 75; + gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2); + _currGoggleGuySequenceId = _nextGoggleGuySequenceId; + _nextGoggleGuySequenceId = -1; + switch (_billardBallCtr) { + case 0: + _nextHookGuySequenceId = 0x1FC; + break; + case 1: + _nextHookGuySequenceId = 0x1FD; + break; + default: + _nextHookGuySequenceId = 0x1FE; + break; + } + ++_billardBallCtr; + gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextHookGuySequenceId, 120, 3); + _currHookGuySequenceId = _nextHookGuySequenceId; + _nextHookGuySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(40) + 20; + gameSys.insertSequence(0x208, 256, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1F4) - 5, 0, 0); + _vm->_hotspots[kHS11Billard]._flags |= SF_DISABLED; + gameSys.setAnimation(0x207, 257, 4); + gameSys.insertSequence(0x207, 257, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(0x1FE), 0, 0); + gnap._actionStatus = -1; + } + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2 && _nextGoggleGuySequenceId != -1) { + _vm->_timers[5] = _vm->getRandom(100) + 75; + gameSys.insertSequence(_nextGoggleGuySequenceId, 121, _currGoggleGuySequenceId, 121, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextGoggleGuySequenceId, 121, 2); + _currGoggleGuySequenceId = _nextGoggleGuySequenceId; + _nextGoggleGuySequenceId = -1; + if (gnap._actionStatus >= 1 && gnap._actionStatus <= 4) + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(3) == 2) { + if (_nextHookGuySequenceId == 0x204) { + gameSys.setAnimation(_nextHookGuySequenceId, 120, 3); + gameSys.insertSequence(0x204, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x1F5, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + _currHookGuySequenceId = 0x204; + _nextHookGuySequenceId = -1; + gnap._sequenceId = 0x1F5; + gnap._sequenceDatNum = 0; + _vm->_timers[4] = _vm->getRandom(40) + 20; + _vm->_timers[2] = _vm->getRandom(20) + 70; + _vm->_timers[3] = _vm->getRandom(50) + 200; + if (gnap._actionStatus == kAS11GrabHookGuy) + gnap._actionStatus = -1; + } else if (_nextHookGuySequenceId != -1) { + gameSys.insertSequence(_nextHookGuySequenceId, 120, _currHookGuySequenceId, 120, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextHookGuySequenceId, 120, 3); + _currHookGuySequenceId = _nextHookGuySequenceId; + _nextHookGuySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(40) + 20; + if (gnap._actionStatus >= 6 && gnap._actionStatus <= 9) + gnap._actionStatus = -1; + } + } + + if (gameSys.getAnimationStatus(4) == 2) { + gameSys.setAnimation(0, 0, 4); + _vm->_hotspots[kHS11Billard]._flags &= ~SF_DISABLED; + } +} + +/*****************************************************************************/ + +Scene12::Scene12(GnapEngine *vm) : Scene(vm) { + _nextBeardGuySequenceId = -1; + _currBeardGuySequenceId = -1; + _nextToothGuySequenceId = -1; + _currToothGuySequenceId = -1; + _nextBarkeeperSequenceId = -1; + _currBarkeeperSequenceId = -1; +} + +int Scene12::init() { + return 0x209; +} + +void Scene12::updateHotspots() { + _vm->setHotspot(kHS12Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS12ExitRight, 790, 360, 799, 599, SF_EXIT_R_CURSOR); + _vm->setHotspot(kHS12ToothGuy, 80, 180, 160, 380, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS12Barkeeper, 490, 175, 580, 238, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS12BeardGuy, 620, 215, 720, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS12Jukebox, 300, 170, 410, 355, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS12WalkArea1, 0, 0, 260, 460); + _vm->setHotspot(kHS12WalkArea2, 0, 0, 380, 410); + _vm->setHotspot(kHS12WalkArea3, 0, 0, 799, 395); + _vm->setHotspot(kHS12WalkArea4, 585, 0, 799, 455); + _vm->setDeviceHotspot(kHS12Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 11; +} + +void Scene12::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + int v18 = 1; + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(0x207, 256, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x200, 50, 0, 0, kSeqNone, 0, 0, 0); + + _currToothGuySequenceId = 0x200; + _nextToothGuySequenceId = -1; + + gameSys.setAnimation(0x200, 50, 2); + gameSys.insertSequence(0x202, 50, 0, 0, kSeqNone, 0, 0, 0); + + _currBeardGuySequenceId = 0x202; + _nextBeardGuySequenceId = -1; + + gameSys.setAnimation(0x202, 50, 4); + gameSys.insertSequence(0x203, 50, 0, 0, kSeqNone, 0, 0, 0); + + _currBarkeeperSequenceId = 0x203; + _nextBarkeeperSequenceId = -1; + + gameSys.setAnimation(0x203, 50, 3); + + _vm->_timers[4] = 30; + _vm->_timers[6] = _vm->getRandom(30) + 20; + _vm->_timers[5] = _vm->getRandom(30) + 20; + _vm->_timers[7] = _vm->getRandom(100) + 100; + + if (_vm->_prevSceneNum == 15) { + gnap.initPos(5, 6, kDirBottomRight); + plat.initPos(3, 7, kDirIdleLeft); + _vm->endSceneInit(); + } else { + gnap.initPos(11, 8, kDirBottomLeft); + plat.initPos(12, 8, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1); + } + + while (!_vm->_sceneDone) { + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + _vm->updateGrabCursorSprite(0, 0); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS12Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS12Platypus: + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + break; + + case kHS12ExitRight: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(10, -1), 0, 0x107AB, 1); + gnap._actionStatus = kAS12LeaveScene; + plat.walkTo(Common::Point(10, -1), -1, -1, 1); + _vm->_newSceneNum = 11; + break; + + case kHS12ToothGuy: + if (_vm->_grabCursorSpriteIndex == kItemQuarter) { + _vm->_largeSprite = gameSys.createSurface(0x141); + gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9); + gnap._idleFacing = kDirUpLeft; + gnap._actionStatus = kAS12QuarterToToothGuy; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0); + _vm->setGrabCursorSprite(-1); + } else if (_vm->_grabCursorSpriteIndex == kItemQuarterWithHole) { + gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9); + gnap._idleFacing = kDirUpLeft; + gnap._actionStatus = kAS12QuarterWithHoleToToothGuy; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 9); + gnap._idleFacing = kDirUpLeft; + gnap._actionStatus = kAS12ShowItemToToothGuy; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 2)); + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(3, 7), 0, 0x107BC, 1); + gnap._actionStatus = kAS12GrabToothGuy; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(Common::Point(3, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS12TalkToothGuy; + break; + case PLAT_CURSOR: + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(3, 7), 1, 0x107D2, 1); + plat._actionStatus = kAS12PlatWithToothGuy; + plat._idleFacing = kDirIdleRight; + gnap.playIdle(Common::Point(2, 7)); + break; + } + } + break; + + case kHS12Barkeeper: + if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) { + gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS12QuarterWithBarkeeper; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 9); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS12ShowItemToBarkeeper; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 7, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.walkTo(Common::Point(6, 6), 0, 0x107BB, 1); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS12LookBarkeeper; + break; + case GRAB_CURSOR: + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(6, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS12TalkBarkeeper; + break; + case PLAT_CURSOR: + gnap.playPullOutDevice(plat._pos); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gnap._actionStatus = kAS12PlatWithBarkeeper; + break; + } + } + break; + + case kHS12BeardGuy: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 9); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS12ShowItemToBeardGuy; + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS12LookBeardGuy; + break; + case GRAB_CURSOR: + // NOTE Bug in the original. It has 9 as flags which seems wrong here. + gnap.walkTo(Common::Point(7, 6), 0, 0x107BB, 1); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS12GrabBeardGuy; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS12TalkBeardGuy; + break; + case PLAT_CURSOR: + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(7, 6), 1, 0x107C2, 1); + plat._actionStatus = kAS12PlatWithBeardGuy; + plat._idleFacing = kDirIdleLeft; + gnap.playIdle(Common::Point(7, 6)); + break; + } + } + break; + + case kHS12Jukebox: + _vm->_newSceneNum = 15; + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(5, 6), 0, 0x107BC, 1); + gnap._actionStatus = kAS12LeaveScene; + break; + + case kHS12WalkArea1: + case kHS12WalkArea2: + case kHS12WalkArea3: + case kHS12WalkArea4: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = 15; + if (_nextToothGuySequenceId == -1) { + if (v18 == 0 && _currBeardGuySequenceId == 0x202 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0) { + if (_vm->getRandom(2) != 0) + _nextToothGuySequenceId = 0x1EC; + else + _nextToothGuySequenceId = 0x204; + } else if (_currToothGuySequenceId != 0x200) + _nextToothGuySequenceId = 0x200; + v18 = (v18 + 1) % 15; + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(30) + 20; + if (_nextBarkeeperSequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) { + if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBeardGuySequenceId == 0x202 && gnap._actionStatus < 0 && plat._actionStatus < 0) { + if (_vm->getRandom(2) != 0) + _nextBarkeeperSequenceId = 0x208; + else + _nextBarkeeperSequenceId = 0x1FB; + } else + _nextBarkeeperSequenceId = 0x203; + v18 = (v18 + 1) % 15; + } + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(30) + 15; + if (_nextBeardGuySequenceId == -1 && gnap._actionStatus < 0 && plat._actionStatus < 0) { + if (v18 == 0 && _currToothGuySequenceId == 0x200 && _currBarkeeperSequenceId == 0x203 && gnap._actionStatus < 0 && plat._actionStatus < 0) + _nextBeardGuySequenceId = 0x1F2; + else + _nextBeardGuySequenceId = 0x202; + v18 = (v18 + 1) % 15; + } + } + if (!_vm->_timers[7]) { + _vm->_timers[7] = _vm->getRandom(100) + 100; + int _gnapRandomValue = _vm->getRandom(3); + switch (_gnapRandomValue) { + case 0: + gameSys.insertSequence(0x8A5 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + break; + case 1: + gameSys.insertSequence(0x8A7 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + break; + case 2: + gameSys.insertSequence(0x8A6 | 0x10000, 179, 0, 0, kSeqNone, 0, 0, 0); + break; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = 30; + _vm->_timers[5] = _vm->getRandom(30) + 20; + _vm->_timers[6] = _vm->getRandom(30) + 20; + } + + _vm->gameUpdateTick(); + } +} + +void Scene12::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS12LeaveScene: + _vm->_sceneDone = true; + break; + case kAS12TalkToothGuy: + if (_vm->isKeyStatus1(Common::KEYCODE_j)) { + // Easter egg + _vm->clearKeyStatus1(Common::KEYCODE_j); + _nextToothGuySequenceId = 0x206; + } else { + _nextToothGuySequenceId = 0x1EE; + } + break; + case 3: + break; + case kAS12GrabToothGuy: + if (_vm->isKeyStatus1(Common::KEYCODE_j)) { + _vm->clearKeyStatus1(Common::KEYCODE_j); + _nextToothGuySequenceId = 0x206; + } else { + _nextToothGuySequenceId = 0x1EF; + } + break; + case kAS12ShowItemToToothGuy: + if (_vm->isKeyStatus1(Common::KEYCODE_j)) { + _vm->clearKeyStatus1(Common::KEYCODE_j); + _nextToothGuySequenceId = 0x206; + } else { + _nextToothGuySequenceId = 0x1ED; + } + break; + case kAS12QuarterWithHoleToToothGuy: + if (_vm->isKeyStatus1(Common::KEYCODE_j)) { + _vm->clearKeyStatus1(Common::KEYCODE_j); + _nextToothGuySequenceId = 0x206; + } else { + _nextToothGuySequenceId = 0x1EA; + } + break; + case kAS12QuarterToToothGuy: + if (_vm->isKeyStatus1(Common::KEYCODE_j)) { + _vm->clearKeyStatus1(Common::KEYCODE_j); + _nextToothGuySequenceId = 0x206; + } else { + _nextToothGuySequenceId = 0x1E9; + } + break; + case kAS12QuarterToToothGuyDone: + gnap._actionStatus = -1; + _vm->showCursor(); + gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300); + _vm->deleteSurface(&_vm->_largeSprite); + _vm->setGrabCursorSprite(kItemQuarterWithHole); + break; + case kAS12TalkBeardGuy: + _nextBeardGuySequenceId = 0x1F4; + break; + case kAS12LookBeardGuy: + _nextBeardGuySequenceId = 0x1F3; + break; + case kAS12GrabBeardGuy: + _nextBeardGuySequenceId = 0x1F1; + break; + case kAS12ShowItemToBeardGuy: + _nextBeardGuySequenceId = 0x1F0; + break; + case kAS12TalkBarkeeper: + if (_vm->getRandom(2) != 0) + _nextBarkeeperSequenceId = 0x1FD; + else + _nextBarkeeperSequenceId = 0x1FF; + break; + case kAS12LookBarkeeper: + _nextBarkeeperSequenceId = 0x1F8; + break; + case 14: + _nextBarkeeperSequenceId = 0x1F6; + break; + case kAS12ShowItemToBarkeeper: + _nextBarkeeperSequenceId = 0x1F5; + break; + case kAS12QuarterWithBarkeeper: + _nextBarkeeperSequenceId = 0x1FA; + break; + case kAS12PlatWithBarkeeper: + _nextBarkeeperSequenceId = 0x1F9; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + switch (plat._actionStatus) { + case kAS12PlatWithToothGuy: + _nextToothGuySequenceId = 0x1EB; + break; + case kAS12PlatWithBeardGuy: + _nextBeardGuySequenceId = 0x1F3; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + if (_currToothGuySequenceId == 0x1E9) { + gameSys.setAnimation(0, 0, 2); + _vm->hideCursor(); + gameSys.setAnimation(0x10843, 301, 0); + gnap._actionStatus = kAS12QuarterToToothGuyDone; + gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300); + gameSys.insertSequence(0x10843, 301, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x107B7, gnap._id, 0x10843, 301, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B7; + gnap._sequenceDatNum = 1; + _vm->setFlag(kGFTwigTaken); + _vm->invAdd(kItemQuarterWithHole); + _vm->invRemove(kItemQuarter); + } + if (_nextToothGuySequenceId == 0x1EF) { + gameSys.setAnimation(_nextToothGuySequenceId, 50, 2); + gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + _currToothGuySequenceId = _nextToothGuySequenceId; + _nextToothGuySequenceId = -1; + gnap._sequenceId = 0x205; + gnap._sequenceDatNum = 0; + _vm->_timers[4] = 40; + _vm->_timers[2] = _vm->getRandom(20) + 70; + _vm->_timers[3] = _vm->getRandom(50) + 200; + if (gnap._actionStatus == kAS12GrabToothGuy) + gnap._actionStatus = -1; + } else if (_nextToothGuySequenceId != -1) { + gameSys.insertSequence(_nextToothGuySequenceId, 50, _currToothGuySequenceId, 50, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextToothGuySequenceId, 50, 2); + _currToothGuySequenceId = _nextToothGuySequenceId; + _nextToothGuySequenceId = -1; + _vm->_timers[4] = 50; + if (gnap._actionStatus >= kAS12TalkToothGuy && gnap._actionStatus <= kAS12QuarterToToothGuy && _currToothGuySequenceId != 0x1E9 && + _currToothGuySequenceId != 0x1EC && _currToothGuySequenceId != 0x200) + gnap._actionStatus = -1; + if (plat._actionStatus == kAS12PlatWithToothGuy) + plat._actionStatus = -1; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + if (gnap._actionStatus == kAS12PlatWithBarkeeper && _currBarkeeperSequenceId == 0x1F9) { + gnap._actionStatus = -1; + gnap.playIdle(Common::Point(7, 6)); + _vm->_timers[5] = 0; + } + if (_nextBarkeeperSequenceId != -1) { + gameSys.insertSequence(_nextBarkeeperSequenceId, 50, _currBarkeeperSequenceId, 50, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextBarkeeperSequenceId, 50, 3); + _currBarkeeperSequenceId = _nextBarkeeperSequenceId; + _nextBarkeeperSequenceId = -1; + _vm->_timers[5] = _vm->getRandom(30) + 20; + if (gnap._actionStatus >= kAS12TalkBarkeeper && gnap._actionStatus <= kAS12QuarterWithBarkeeper && _currBarkeeperSequenceId != 0x203 && + _currBarkeeperSequenceId != 0x1FB && _currBarkeeperSequenceId != 0x208) + gnap._actionStatus = -1; + } + } + + if (gameSys.getAnimationStatus(4) == 2 && _nextBeardGuySequenceId != -1) { + gameSys.insertSequence(_nextBeardGuySequenceId, 50, _currBeardGuySequenceId, 50, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextBeardGuySequenceId, 50, 4); + _currBeardGuySequenceId = _nextBeardGuySequenceId; + _nextBeardGuySequenceId = -1; + _vm->_timers[6] = _vm->getRandom(30) + 20; + if (gnap._actionStatus >= kAS12TalkBeardGuy && gnap._actionStatus <= kAS12ShowItemToBeardGuy && _currBeardGuySequenceId != 0x202 && _currBeardGuySequenceId != 0x1F2) + gnap._actionStatus = -1; + if (plat._actionStatus == kAS12PlatWithBeardGuy) + plat._actionStatus = -1; + } +} + +/*****************************************************************************/ + +Scene13::Scene13(GnapEngine *vm) : Scene(vm) { + _backToiletCtr = -1; +} + +int Scene13::init() { + _vm->playSound(0x108EC, false); + return 0xAC; +} + +void Scene13::updateHotspots() { + _vm->setHotspot(kHS13Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS13ExitBar, 113, 160, 170, 455, SF_EXIT_L_CURSOR); + _vm->setHotspot(kHS13BackToilet, 385, 195, 478, 367, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS13FrontToilet, 497, 182, 545, 432, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS13Urinal, 680, 265, 760, 445, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS13Scribble, 560, 270, 660, 370, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS13Sink, 310, 520, 560, 599, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS13WalkArea1, 268, 270, 325, 385); + _vm->setHotspot(kHS13WalkArea2, 0, 0, 52, 599); + _vm->setHotspot(kHS13WalkArea3, 0, 0, 113, 550); + _vm->setHotspot(kHS13WalkArea4, 0, 0, 226, 438); + _vm->setHotspot(kHS13WalkArea5, 0, 0, 268, 400); + _vm->setHotspot(kHS13WalkArea6, 0, 0, 799, 367); + _vm->setHotspot(kHS13WalkArea7, 478, 0, 799, 401); + _vm->setHotspot(kHS13WalkArea8, 545, 0, 799, 473); + _vm->setHotspot(kHS13WalkArea9, 0, 549, 799, 599); + _vm->setDeviceHotspot(kHS13Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 17; +} + +void Scene13::showScribble() { + GameSys& gameSys = *_vm->_gameSys; + + _vm->hideCursor(); + _vm->_largeSprite = gameSys.createSurface(0x6F); + gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300); + while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) && + !_vm->isKeyStatus1(Common::KEYCODE_SPACE) && !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->_mouseClickState._left = false; + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_RETURN); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300); + _vm->deleteSurface(&_vm->_largeSprite); + _vm->showCursor(); +} + +void Scene13::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + int currSoundId = 0; + + _vm->queueInsertDeviceIcon(); + gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->_prevSceneNum == 14) { + gnap.initPos(6, 6, kDirBottomLeft); + plat.initPos(9, 8, kDirIdleLeft); + } else { + gnap.initPos(3, 7, kDirBottomRight); + plat.initPos(2, 7, kDirIdleLeft); + } + + _vm->endSceneInit(); + + _vm->_timers[4] = _vm->getRandom(20) + 20; + _vm->_timers[5] = _vm->getRandom(50) + 50; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1091A)) + _vm->playSound(0x1091A, true); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS13Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 20; + _vm->_timers[5] = _vm->getRandom(50) + 50; + } + break; + + case kHS13Platypus: + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + break; + } + break; + + case kHS13ExitBar: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(2, 7), 0, 0x107C0, 1); + gnap._actionStatus = kAS13LeaveScene; + plat.walkTo(Common::Point(2, 8), -1, -1, 1); + if (_vm->isFlag(kGFUnk14) || _vm->isFlag(kGFSpringTaken)) { + _vm->_newSceneNum = 11; + } else { + _vm->setFlag(kGFSpringTaken); + _vm->_newSceneNum = 47; + } + break; + + case kHS13BackToilet: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(5, 5), 6, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case GRAB_CURSOR: + case TALK_CURSOR: + if (gnap._pos == Common::Point(5, 5)) { + _backToiletCtr = MIN(5, _backToiletCtr + 1); + gameSys.setAnimation(_backToiletCtr + 0xA3, gnap._id, 0); + gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqScale | kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS13Wait; + gnap._sequenceId = _backToiletCtr + 0xA3; + gnap._idleFacing = kDirUpRight; + gnap._sequenceDatNum = 0; + } else { + gnap.walkTo(Common::Point(5, 5), 0, 0x107BB, 1); + gnap._actionStatus = kAS13BackToilet; + gnap._idleFacing = kDirUpRight; + } + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS13FrontToilet: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(6, 7), 7, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case GRAB_CURSOR: + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.walkTo(Common::Point(6, 7), 0, 0xA9, 5); + gnap._actionStatus = kAS13FrontToilet; + gnap._idleFacing = kDirBottomRight; + break; + } + } + break; + + case kHS13Scribble: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(7, 7), 8, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1); + gnap._actionStatus = kAS13LookScribble; + gnap._idleFacing = kDirUpRight; + break; + case GRAB_CURSOR: + gnap.playScratchingHead(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(7, 7), -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)), 1); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS13Urinal: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(8, 7), 9, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(9, 6))); + gnap.walkTo(gnap._pos, 0, -1, 1); + gnap._actionStatus = kAS13Wait; + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(8, 7), 0, -1, 1); + gnap._actionStatus = kAS13GrabUrinal; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS13Sink: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playSequence(gnap.getSequenceId(kGSDeflect, Common::Point(5, 9))); + gnap.walkTo(gnap._pos, 0, -1, 1); + gnap._actionStatus = kAS13Wait; + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(4, 8), 0, 0x107B9, 1); + gnap._actionStatus = kAS13GrabSink; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS13WalkArea2: + case kHS13WalkArea3: + case kHS13WalkArea4: + case kHS13WalkArea5: + case kHS13WalkArea6: + case kHS13WalkArea7: + case kHS13WalkArea8: + case kHS13WalkArea9: + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + case kHS13WalkArea1: + // Nothing + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + if (plat._pos.y == 5 || plat._pos.y == 6) + plat.walkTo(Common::Point(-1, 7), -1, -1, 1); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 20; + switch (_vm->getRandom(5)) { + case 0: + _vm->playSound(0xD2, false); + break; + case 1: + _vm->playSound(0xD3, false); + break; + case 2: + _vm->playSound(0xD4, false); + break; + case 3: + _vm->playSound(0xD5, false); + break; + case 4: + _vm->playSound(0xD6, false); + break; + } + } + if (!_vm->_timers[5]) { + int newSoundId; + _vm->_timers[5] = _vm->getRandom(50) + 50; + switch (_vm->getRandom(7)) { + case 0: + newSoundId = 0xD7; + _vm->_timers[5] = 2 * _vm->getRandom(50) + 100; + break; + case 1: + case 2: + newSoundId = 0xCF; + break; + case 3: + case 4: + newSoundId = 0xD0; + break; + default: + newSoundId = 0xD1; + break; + } + if (newSoundId != currSoundId) { + _vm->playSound(newSoundId, false); + currSoundId = newSoundId; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 20; + _vm->_timers[5] = _vm->getRandom(50) + 50; + } + + _vm->gameUpdateTick(); + } +} + +void Scene13::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS13LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS13BackToilet: + _backToiletCtr = MIN(5, _backToiletCtr + 1); + gameSys.insertSequence(_backToiletCtr + 0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 9, 0, 0, 0); + gnap._sequenceId = _backToiletCtr + 0xA3; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + break; + case kAS13FrontToilet: + _vm->_sceneDone = true; + _vm->_newSceneNum = 14; + break; + case kAS13LookScribble: + gnap._actionStatus = -1; + showScribble(); + break; + case kAS13GrabSink: + gameSys.setAnimation(0xAB, 160, 0); + gameSys.insertSequence(0xAB, 160, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0xAA, 256, true); + gnap._sequenceId = 0xAB; + gnap._id = 160; + gnap._idleFacing = kDirBottomRight; + gnap._sequenceDatNum = 0; + gnap._pos = Common::Point(4, 8); + _vm->_timers[2] = 360; + gnap._actionStatus = kAS13GrabSinkDone; + break; + case kAS13GrabSinkDone: + gameSys.insertSequence(0xAA, 256, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = -1; + break; + case kAS13Wait: + gnap._actionStatus = -1; + break; + case kAS13GrabUrinal: + gameSys.setAnimation(0xA2, 120, 0); + gameSys.insertSequence(0xA2, 120, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0xA2; + gnap._id = 120; + gnap._idleFacing = kDirBottomLeft; + gnap._sequenceDatNum = 0; + gnap._pos = Common::Point(4, 6); + _vm->_timers[2] = 360; + gnap._actionStatus = kAS13Wait; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + _vm->_plat->_actionStatus = -1; + } +} + +/*****************************************************************************/ + +Scene14::Scene14(GnapEngine *vm) : Scene(vm) { +} + +int Scene14::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + return 0x27; +} + +void Scene14::updateHotspots() { + _vm->setHotspot(kHS14Platypus, 0, 0, 0, 0); + _vm->setHotspot(kHS14Exit, 0, 590, 799, 599, SF_EXIT_D_CURSOR); + _vm->setHotspot(kHS14Coin, 330, 390, 375, 440, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS14Toilet, 225, 250, 510, 500, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setDeviceHotspot(kHS14Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFNeedleTaken)) + _vm->_hotspots[kHS14Coin]._flags = SF_DISABLED; + _vm->_hotspotsCount = 5; +} + +void Scene14::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + _vm->_largeSprite = nullptr; + _vm->queueInsertDeviceIcon(); + + if (!_vm->isFlag(kGFNeedleTaken)) + gameSys.insertSequence(0x23, 10, 0, 0, kSeqNone, 0, 0, 0); + + _vm->endSceneInit(); + + if (!_vm->isFlag(kGFNeedleTaken) && _vm->invHas(kItemTongs)) + _vm->_largeSprite = gameSys.createSurface(1); + + if (!_vm->isFlag(kGFNeedleTaken)) { + gameSys.insertSequence(0x24, 10, 0x23, 10, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x24; + _vm->_timers[2] = _vm->getRandom(40) + 50; + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS14Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS14Exit: + _vm->_sceneDone = true; + _vm->_newSceneNum = 13; + break; + + case kHS14Coin: + if (_vm->_grabCursorSpriteIndex == kItemTongs) { + _vm->invAdd(kItemQuarter); + _vm->setFlag(kGFNeedleTaken); + _vm->setGrabCursorSprite(-1); + _vm->hideCursor(); + gameSys.setAnimation(0x26, 10, 0); + gameSys.insertSequence(0x26, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + _vm->playSound(0x108E9, false); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + _vm->playSound(0x108E9, false); + break; + case GRAB_CURSOR: + gameSys.insertSequence(0x25, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x23, 10, 0x25, 10, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x23; + break; + case TALK_CURSOR: + _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false); + break; + case PLAT_CURSOR: + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + break; + } + } + break; + + case kHS14Toilet: + if (_vm->_grabCursorSpriteIndex >= 0) { + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case GRAB_CURSOR: + _vm->playSound(0x108B1, false); + break; + case TALK_CURSOR: + _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false); + break; + case PLAT_CURSOR: + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + break; + } + } + break; + + default: + _vm->_mouseClickState._left = false; + break; + } + + updateAnimations(); + _vm->checkGameKeys(); + + if (!_vm->isFlag(kGFNeedleTaken) && !_vm->_timers[2]) { + gameSys.insertSequence(0x24, 10, gnap._sequenceId, 10, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x24; + _vm->_timers[2] = _vm->getRandom(40) + 50; + } + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } + + if (_vm->_largeSprite) + _vm->deleteSurface(&_vm->_largeSprite); +} + +void Scene14::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300); + gameSys.setAnimation(0x10843, 301, 1); + gameSys.insertSequence(0x10843, 301, 0x26, 10, kSeqSyncWait, 0, 0, 0); + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + _vm->_sceneDone = true; + _vm->_newSceneNum = 13; + _vm->_grabCursorSpriteIndex = kItemQuarter; + } +} + +/*****************************************************************************/ + +Scene15::Scene15(GnapEngine *vm) : Scene(vm) { + _nextRecordSequenceId = -1; + _currRecordSequenceId = -1; + _nextSlotSequenceId = -1; + _currSlotSequenceId = -1; + _nextUpperButtonSequenceId = -1; + _currUpperButtonSequenceId = -1; + _nextLowerButtonSequenceId = -1; + _currLowerButtonSequenceId = -1; +} + +int Scene15::init() { + return 0xDD; +} + +void Scene15::updateHotspots() { + _vm->setHotspot(kHS15Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS15Exit, 50, 590, 750, 599, SF_EXIT_D_CURSOR); + _vm->setHotspot(kHS15Button1, 210, 425, 260, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15Button2, 280, 425, 325, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15Button3, 340, 425, 385, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15Button4, 400, 425, 445, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15Button5, 460, 425, 510, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15Button6, 520, 425, 560, 475, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15ButtonA, 205, 480, 250, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15ButtonB, 270, 480, 320, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15ButtonC, 335, 480, 380, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15ButtonD, 395, 480, 445, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15ButtonE, 460, 480, 505, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15ButtonF, 515, 480, 560, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15CoinSlot, 585, 475, 620, 535, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS15PlayButton, 622, 431, 650, 482, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setDeviceHotspot(kHS15Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 17; +} + +void Scene15::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + _currSlotSequenceId = -1; + _currUpperButtonSequenceId = -1; + _currLowerButtonSequenceId = -1; + _nextSlotSequenceId = -1; + _nextUpperButtonSequenceId = -1; + _nextLowerButtonSequenceId = -1; + _currRecordSequenceId = 0xD5; + _nextRecordSequenceId = -1; + + gameSys.setAnimation(0xD5, 1, 0); + gameSys.insertSequence(_currRecordSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + _vm->endSceneInit(); + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_hotspots[kHS15Platypus].clearRect(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS15Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS15Exit: + _vm->_newSceneNum = 12; + _vm->_isLeavingScene = true; + break; + + case kHS15CoinSlot: + if (_vm->_grabCursorSpriteIndex == kItemQuarter || _vm->_grabCursorSpriteIndex == kItemQuarterWithHole) { + _nextSlotSequenceId = 0xDC; // Insert coin + } else if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) { + _nextSlotSequenceId = 0xDB; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case GRAB_CURSOR: + _vm->playSound(0x108E9, false); + break; + case TALK_CURSOR: + _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false); + break; + case PLAT_CURSOR: + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + break; + } + } + break; + + case kHS15PlayButton: + if (_vm->_grabCursorSpriteIndex >= 0) { + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13)) + _vm->playSound(0x108E9, false); + else + _nextSlotSequenceId = 0xDA; + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFGnapControlsToyUFO) || _vm->isFlag(kGFUnk13)) + _nextSlotSequenceId = 0xD9; + else + _nextSlotSequenceId = 0xDA; + break; + case TALK_CURSOR: + _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false); + break; + case PLAT_CURSOR: + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + break; + } + } + break; + + case kHS15Button1: + case kHS15Button2: + case kHS15Button3: + case kHS15Button4: + case kHS15Button5: + case kHS15Button6: + if (_vm->_grabCursorSpriteIndex >= 0) { + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + _vm->playSound(0x108E9, false); + break; + case GRAB_CURSOR: + _nextUpperButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5; + break; + case TALK_CURSOR: + _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false); + break; + case PLAT_CURSOR: + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + break; + } + } + break; + + case kHS15ButtonA: + case kHS15ButtonB: + case kHS15ButtonC: + case kHS15ButtonD: + case kHS15ButtonE: + case kHS15ButtonF: + if (_vm->_grabCursorSpriteIndex >= 0) { + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + _vm->playSound(0x108E9, false); + break; + case GRAB_CURSOR: + _nextLowerButtonSequenceId = _vm->_sceneClickedHotspot + 0xC5; + break; + case TALK_CURSOR: + _vm->playSound((_vm->getRandom(5) + 0x8D5) | 0x10000, false); + break; + case PLAT_CURSOR: + gameSys.insertSequence(0x107A8, 1, 0, 0, kSeqNone, 0, 900 - gnap._gridX, 576 - gnap._gridY); + break; + } + } + break; + + default: + _vm->_mouseClickState._left = false; + break; + + } + + updateAnimations(); + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene15::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + + if (gameSys.getAnimationStatus(0) == 2) { + if (_vm->_isLeavingScene) { + _vm->_sceneDone = true; + } else if (_nextSlotSequenceId != -1) { + gameSys.setAnimation(_nextSlotSequenceId, 1, 0); + gameSys.insertSequence(_nextSlotSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + _currSlotSequenceId = _nextSlotSequenceId; + _nextSlotSequenceId = -1; + switch (_currSlotSequenceId) { + case 0xDC: + if (_vm->_grabCursorSpriteIndex == kItemQuarter) { + _vm->invRemove(kItemQuarter); + } else { + _vm->invRemove(kItemQuarterWithHole); + _vm->setFlag(kGFUnk13); + } + _vm->setGrabCursorSprite(-1); + break; + case 0xDB: + _vm->setFlag(kGFUnk14); + _vm->setGrabCursorSprite(-1); + _nextSlotSequenceId = 0xD8; + break; + case 0xD9: + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->clearFlag(kGFGnapControlsToyUFO); + _vm->invAdd(kItemQuarter); + _vm->_newGrabCursorSpriteIndex = kItemQuarter; + } else if (_vm->isFlag(kGFUnk13)) { + _vm->clearFlag(kGFUnk13); + _vm->invAdd(kItemQuarterWithHole); + _vm->_newGrabCursorSpriteIndex = kItemQuarterWithHole; + } + _vm->_newSceneNum = 12; + _vm->_isLeavingScene = true; + break; + case 0xD8: + case 0xDA: + if (_currUpperButtonSequenceId != -1) { + gameSys.removeSequence(_currUpperButtonSequenceId, 1, true); + _currUpperButtonSequenceId = -1; + } + if (_currLowerButtonSequenceId != -1) { + gameSys.removeSequence(_currLowerButtonSequenceId, 1, true); + _currLowerButtonSequenceId = -1; + } + break; + } + } else if (_nextRecordSequenceId != -1) { + gameSys.setAnimation(_nextRecordSequenceId, 1, 0); + gameSys.insertSequence(_nextRecordSequenceId, 1, _currRecordSequenceId, 1, kSeqSyncWait, 0, 0, 0); + _currRecordSequenceId = _nextRecordSequenceId; + _nextRecordSequenceId = -1; + if (_currRecordSequenceId == 0xD3) { + _vm->invRemove(kItemDiceQuarterHole); + _vm->_newSceneNum = 16; + _vm->_isLeavingScene = true; + } + gameSys.removeSequence(_currUpperButtonSequenceId, 1, true); + _currUpperButtonSequenceId = -1; + gameSys.removeSequence(_currLowerButtonSequenceId, 1, true); + _currLowerButtonSequenceId = -1; + } else if (_nextUpperButtonSequenceId != -1) { + gameSys.setAnimation(_nextUpperButtonSequenceId, 1, 0); + if (_currUpperButtonSequenceId == -1) + gameSys.insertSequence(_nextUpperButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(_nextUpperButtonSequenceId, 1, _currUpperButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0); + _currUpperButtonSequenceId = _nextUpperButtonSequenceId; + _nextUpperButtonSequenceId = -1; + if (_currLowerButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) { + if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE) + _nextRecordSequenceId = 0xD3; + else + _nextRecordSequenceId = 0xD4; + } + } else if (_nextLowerButtonSequenceId != -1) { + gameSys.setAnimation(_nextLowerButtonSequenceId, 1, 0); + if (_currLowerButtonSequenceId == -1) + gameSys.insertSequence(_nextLowerButtonSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(_nextLowerButtonSequenceId, 1, _currLowerButtonSequenceId, 1, kSeqSyncWait, 0, 0, 0); + _currLowerButtonSequenceId = _nextLowerButtonSequenceId; + _nextLowerButtonSequenceId = -1; + if (_currUpperButtonSequenceId != -1 && _vm->isFlag(kGFUnk14)) { + if (_currUpperButtonSequenceId == 0xCC && _currLowerButtonSequenceId == 0xCE) + _nextRecordSequenceId = 0xD3; + else + _nextRecordSequenceId = 0xD4; + } + } + } +} + +/*****************************************************************************/ + +Scene17::Scene17(GnapEngine *vm) : Scene(vm) { + _platTryGetWrenchCtr = 0; + _wrenchCtr = 2; + _nextCarWindowSequenceId = -1; + _nextWrenchSequenceId = -1; + _canTryGetWrench = true; + _platPhoneCtr = 0; + _nextPhoneSequenceId = -1; + _currPhoneSequenceId = -1; +} + +int Scene17::init() { + return 0x263; +} + +void Scene17::updateHotspots() { + _vm->setHotspot(kHS17Platypus, 1, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS17Phone1, 61, 280, 97, 322, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7); + _vm->setHotspot(kHS17Phone2, 80, 204, 178, 468, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7); + _vm->setHotspot(kHS17ExitGrubCity, 196, 207, 280, 304, SF_EXIT_U_CURSOR, 3, 5); + _vm->setHotspot(kHS17ExitToyStore, 567, 211, 716, 322, SF_EXIT_U_CURSOR, 5, 6); + _vm->setHotspot(kHS17Wrench, 586, 455, 681, 547, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7); + _vm->setHotspot(kHS17WalkArea1, 0, 0, 800, 434); + _vm->setHotspot(kHS17WalkArea2, 541, 0, 800, 600); + _vm->setHotspot(kHS17WalkArea3, 0, 204, 173, 468); + _vm->setDeviceHotspot(kHS17Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFGrassTaken)) + _vm->_hotspots[kHS17Wrench]._flags = SF_NONE; + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + _vm->_hotspots[kHS17Device]._flags = SF_DISABLED; + _vm->_hotspots[kHS17Platypus]._flags = SF_DISABLED; + } + _vm->_hotspotsCount = 10; +} + +void Scene17::update() { + _vm->gameUpdateTick(); + _vm->updateMouseCursor(); + _vm->updateGrabCursorSprite(0, 0); + if (_vm->_mouseClickState._left) { + _vm->_gnap->walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } +} + +void Scene17::platHangUpPhone() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + int savedGnapActionStatus = gnap._actionStatus; + + if (plat._actionStatus == kAS17PlatPhoningAssistant) { + gnap._actionStatus = kAS17PlatHangUpPhone; + _vm->updateMouseCursor(); + _platPhoneCtr = 0; + plat._actionStatus = -1; + gameSys.setAnimation(0x257, 254, 4); + gameSys.insertSequence(0x257, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0); + while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + gameSys.setAnimation(0x25B, plat._id, 1); + gameSys.insertSequence(0x25B, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0x25B; + plat._sequenceDatNum = 0; + _currPhoneSequenceId = -1; + _nextPhoneSequenceId = -1; + _vm->clearFlag(kGFPlatypusTalkingToAssistant); + while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + gnap._actionStatus = savedGnapActionStatus; + _vm->updateMouseCursor(); + } + updateHotspots(); +} + +void Scene17::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x10940, true); + _vm->startSoundTimerA(8); + _vm->_sceneWaiting = false; + _vm->_timers[4] = _vm->getRandom(100) + 200; + _vm->_timers[3] = 200; + _vm->_timers[5] = _vm->getRandom(30) + 80; + _vm->_timers[6] = _vm->getRandom(30) + 200; + _vm->_timers[7] = _vm->getRandom(100) + 100; + + if (_vm->isFlag(kGFTruckKeysUsed)) { + gameSys.insertSequence(0x25F, 20, 0, 0, kSeqNone, 0, 0, 0); + } else { + if (_vm->_s18GarbageCanPos >= 8) { + gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 97, 1); + } else if (_vm->_s18GarbageCanPos >= 6) { + gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 68, 2); + } else if (_vm->_s18GarbageCanPos >= 5) { + gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, 23, -1); + } else if (_vm->_s18GarbageCanPos >= 4) { + gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -11, -5); + } else { + gameSys.insertSequence(0x260, 20, 0, 0, kSeqNone, 0, -54, -8); + } + } + + if (_vm->isFlag(kGFGroceryStoreHatTaken)) + gameSys.insertSequence(0x262, 1, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFGrassTaken)) + _currWrenchSequenceId = 0x22D; + else + _currWrenchSequenceId = 0x22F; + + _currCarWindowSequenceId = 0x244; + + if (_vm->isFlag(kGFUnk14)) + gameSys.insertSequence(0x261, 1, 0, 0, kSeqNone, 0, 0, 0); + + gameSys.setAnimation(_currWrenchSequenceId, 40, 2); + gameSys.insertSequence(_currWrenchSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGrassTaken)) { + gameSys.setAnimation(0, 0, 3); + } else { + gameSys.setAnimation(_currCarWindowSequenceId, 40, 3); + gameSys.insertSequence(_currCarWindowSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0); + } + + _canTryGetWrench = true; + + if (_vm->isFlag(kGFUnk18)) + gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->_prevSceneNum == 53 || _vm->_prevSceneNum == 18 || _vm->_prevSceneNum == 20 || _vm->_prevSceneNum == 19) { + if (_vm->_prevSceneNum == 20) { + gnap.initPos(4, 6, kDirBottomRight); + plat.initPos(5, 6, kDirIdleLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1); + } else if (_vm->isFlag(kGFUnk27)) { + gnap.initPos(3, 9, kDirUpLeft); + plat._pos = _vm->_hotspotsWalkPos[2]; + plat._id = 20 * _vm->_hotspotsWalkPos[2].y; + gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x257, 254, 0, 0, kSeqNone, 0, 0, 0); + plat._sequenceId = 0x25A; + plat._sequenceDatNum = 0; + _vm->endSceneInit(); + _vm->clearFlag(kGFSpringTaken); + _vm->clearFlag(kGFUnk16); + plat._actionStatus = kAS17PlatPhoningAssistant; + platHangUpPhone(); + gameSys.setAnimation(0, 0, 4); + _vm->clearFlag(kGFPlatypusTalkingToAssistant); + _vm->clearFlag(kGFUnk27); + updateHotspots(); + } else if (_vm->isFlag(kGFUnk25)) { + _vm->clearFlag(kGFSpringTaken); + _vm->clearFlag(kGFUnk16); + plat.initPos(7, 9, kDirIdleLeft); + gnap._pos = _vm->_hotspotsWalkPos[2]; + gnap._id = 20 * _vm->_hotspotsWalkPos[2].y; + gameSys.insertSequence(601, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 601; + gnap._actionStatus = kAS17GnapHangUpPhone; + _vm->clearFlag(kGFUnk25); + gameSys.insertSequence(0x251, 254, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + gameSys.setAnimation(0x257, 254, 0); + gameSys.insertSequence(0x257, 254, 0x251, 254, kSeqSyncWait, 0, 0, 0); + } else if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + _vm->clearFlag(kGFSpringTaken); + _vm->clearFlag(kGFUnk16); + _vm->_sceneWaiting = true; + gnap.initPos(3, 9, kDirUpLeft); + plat._pos = _vm->_hotspotsWalkPos[2]; + plat._id = 20 * _vm->_hotspotsWalkPos[2].y; + _currPhoneSequenceId = 0x251; + gameSys.insertSequence(0x25A, 20 * _vm->_hotspotsWalkPos[2].y, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0); + plat._sequenceId = 0x25A; + plat._sequenceDatNum = 0; + _vm->endSceneInit(); + gameSys.setAnimation(_currPhoneSequenceId, 254, 1); + plat._actionStatus = kAS17PlatPhoningAssistant; + updateHotspots(); + } else if (_vm->_prevSceneNum == 18) { + gnap.initPos(6, 6, kDirBottomRight); + plat.initPos(5, 6, kDirIdleLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1); + } else { + if (_vm->isFlag(kGFSpringTaken)) { + gnap.initPos(_vm->_hotspotsWalkPos[2].x, _vm->_hotspotsWalkPos[2].y, kDirBottomRight); + plat.initPos(1, 9, kDirIdleLeft); + _vm->endSceneInit(); + } else { + gnap.initPos(3, 7, kDirBottomRight); + plat.initPos(1, 7, kDirIdleLeft); + _vm->endSceneInit(); + } + _vm->clearFlag(kGFSpringTaken); + _vm->clearFlag(kGFUnk16); + _vm->endSceneInit(); + } + } else { + gnap._pos = Common::Point(3, 6); + gnap._id = 120; + gnap._sequenceId = 0x23D; + gnap._sequenceDatNum = 0; + gnap._idleFacing = kDirBottomRight; + gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0, 0, kSeqNone, 0, 0, 0); + plat._pos = Common::Point(-1, 8); + plat._id = 160; + gameSys.insertSequence(0x241, 160, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x107C1, plat._id, 0x241, plat._id, + kSeqScale | kSeqSyncWait, 0, 75 * plat._pos.x - plat._gridX, 48 * plat._pos.y - plat._gridY); + gameSys.insertSequence(0x22C, 2, 0, 0, kSeqNone, 0, 0, 0); + _vm->delayTicksA(2, 9); + _vm->endSceneInit(); + plat._sequenceId = 0x7C1; + plat._sequenceDatNum = 1; + plat._idleFacing = kDirBottomRight; + plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS17Device: + if (gnap._actionStatus < 0 || gnap._actionStatus == 3) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS17Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + if (_vm->isFlag(kGFGrassTaken)) { + gnap.useJointOnPlatypus(); + } else { + gnap.useDeviceOnPlatypus(); + plat.walkTo(_vm->_hotspotsWalkPos[6], 1, 0x107C2, 1); + gnap.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 0, 0x107BA, 1); + plat._actionStatus = kAS17GetWrench1; + gnap._actionStatus = kAS17GetWrench1; + _vm->_timers[5] = _vm->getRandom(30) + 80; + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemJoint); + } + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playScratchingHead(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case GRAB_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS17Wrench: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFGrassTaken)) { + gnap.playImpossible(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 8, 7); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + case GRAB_CURSOR: + gnap.playScratchingHead(Common::Point(8, 7)); + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (_canTryGetWrench) { + platHangUpPhone(); + gnap.useDeviceOnPlatypus(); + plat.walkTo(_vm->_hotspotsWalkPos[6] + Common::Point(1, 0), 1, 0x107C2, 1); + plat._actionStatus = kAS17TryGetWrench; + gnap._actionStatus = kAS17TryGetWrench; + _vm->_timers[5] = _vm->getRandom(30) + 80; + } else + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS17Phone1: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) { + gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS17PutCoinIntoPhone; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 3)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFUnk18)) { + platHangUpPhone(); + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[2]) | 0x10000, 1); + gnap._actionStatus = kAS17GetCoinFromPhone; + } else + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (_vm->isFlag(kGFUnk18)) { + platHangUpPhone(); + _vm->_isLeavingScene = true; + gnap.useDeviceOnPlatypus(); + plat._idleFacing = kDirUpLeft; + plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1); + _vm->setFlag(kGFUnk16); + plat._actionStatus = kAS17PlatUsePhone; + gnap._actionStatus = kAS17PlatUsePhone; + } else + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS17Phone2: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) { + gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS17PutCoinIntoPhone; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[2], 1, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 3)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFUnk18)) { + platHangUpPhone(); + _vm->_isLeavingScene = true; + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[2], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS17GnapUsePhone; + _vm->setFlag(kGFSpringTaken); + } else + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (_vm->isFlag(kGFUnk18)) { + platHangUpPhone(); + _vm->_isLeavingScene = true; + gnap.useDeviceOnPlatypus(); + plat._idleFacing = kDirUpLeft; + plat.walkTo(_vm->_hotspotsWalkPos[2], 1, 0x107C2, 1); + _vm->setFlag(kGFUnk16); + plat._actionStatus = kAS17PlatUsePhone; + gnap._actionStatus = kAS17PlatUsePhone; + } else + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS17ExitToyStore: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 18; + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[5], 0, 0x107BB, 1); + gnap._actionStatus = kAS17LeaveScene; + if (plat._actionStatus != kAS17PlatPhoningAssistant) + plat.walkTo(_vm->_hotspotsWalkPos[5] + Common::Point(-1, 0), -1, 0x107C2, 1); + } + break; + + case kHS17ExitGrubCity: + if (gnap._actionStatus < 0) { + platHangUpPhone(); + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 20; + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[3], 0, 0x107BC, 1); + gnap._actionStatus = kAS17LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[3] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS17WalkArea1: + case kHS17WalkArea2: + case kHS17WalkArea3: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = 0; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x10940)) + _vm->playSound(0x10940, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence2(); + gnap.updateIdleSequence2(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(100) + 200; + if (gnap._actionStatus < 0 && plat._actionStatus < 0) + gameSys.insertSequence(0x22B, 21, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[7]) { + _vm->_timers[7] = _vm->getRandom(100) + 100; + if (gnap._actionStatus < 0 && plat._actionStatus < 0) { + switch (_vm->getRandom(3)) { + case 0: + gameSys.insertSequence(0x25C, 255, 0, 0, kSeqNone, 0, 0, 0); + break; + case 1: + gameSys.insertSequence(0x25D, 255, 0, 0, kSeqNone, 0, 0, 0); + break; + case 2: + gameSys.insertSequence(0x25E, 255, 0, 0, kSeqNone, 0, 0, 0); + break; + } + } + } + if (plat._actionStatus < 0 && !_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(30) + 80; + if (_vm->isFlag(kGFGrassTaken) && _nextWrenchSequenceId == -1) { + _nextWrenchSequenceId = 0x236; + } else if (_canTryGetWrench) { + switch (_vm->getRandom(6)) { + case 0: + _nextWrenchSequenceId = 0x231; + break; + case 1: + _nextWrenchSequenceId = 0x232; + break; + case 2: + case 3: + _nextWrenchSequenceId = 0x23C; + break; + case 4: + case 5: + _nextWrenchSequenceId = 0x22E; + break; + } + } else { + --_wrenchCtr; + if (_wrenchCtr) { + switch (_vm->getRandom(6)) { + case 0: + _nextWrenchSequenceId = 0x237; + break; + case 1: + _nextWrenchSequenceId = 0x238; + break; + case 2: + _nextWrenchSequenceId = 0x239; + break; + case 3: + _nextWrenchSequenceId = 0x23A; + break; + case 4: + _nextWrenchSequenceId = 0x23B; + break; + case 5: + _nextWrenchSequenceId = 0x235; + break; + } + } else { + _wrenchCtr = 2; + _nextWrenchSequenceId = 0x235; + } + } + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(30) + 200; + if (_nextCarWindowSequenceId == -1 && !_vm->isFlag(kGFGrassTaken)) + _nextCarWindowSequenceId = 0x246; + } + _vm->playSoundA(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene17::updateAnimations() { + static const int kPlatPhoneSequenceIds[] = { + 0x251, 0x252, 0x253, 0x254, 0x255, 0x256, 0x257 + }; + + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS17GetWrench1: + gnap._actionStatus = kAS17GetWrenchGnapReady; + break; + case kAS17GetCoinFromPhone: + gnap.playPullOutDevice(Common::Point(1, 3)); + gnap.playUseDevice(); + gameSys.setAnimation(0x250, 100, 0); + gameSys.insertSequence(0x250, 100, 591, 100, kSeqSyncWait, 0, 0, 0); + _vm->invAdd(kItemDiceQuarterHole); + _vm->clearFlag(kGFUnk18); + gnap._actionStatus = kAS17GetCoinFromPhoneDone; + break; + case kAS17GetCoinFromPhoneDone: + _vm->setGrabCursorSprite(kItemDiceQuarterHole); + gnap._actionStatus = -1; + break; + case kAS17PutCoinIntoPhone: + gameSys.setAnimation(0x24C, gnap._id, 0); + gameSys.insertSequence(0x24C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x24C; + _vm->invRemove(kItemDiceQuarterHole); + _vm->setGrabCursorSprite(-1); + _vm->setFlag(kGFUnk18); + gnap._actionStatus = kAS17PutCoinIntoPhoneDone; + break; + case kAS17PutCoinIntoPhoneDone: + gameSys.insertSequence(0x24F, 100, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = -1; + break; + case kAS17GnapUsePhone: + gameSys.setAnimation(0x24D, gnap._id, 0); + gameSys.insertSequence(0x24D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS17LeaveScene; + _vm->_newSceneNum = 53; + break; + case kAS17GnapHangUpPhone: + gameSys.insertSequence(0x258, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x258; + gnap._actionStatus = -1; + break; + case kAS17LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + switch (plat._actionStatus) { + case kAS17TryGetWrench: + plat._actionStatus = -1; + ++_platTryGetWrenchCtr; + if (_platTryGetWrenchCtr % 2 != 0) + _nextWrenchSequenceId = 0x233; + else + _nextWrenchSequenceId = 0x234; + _canTryGetWrench = false; + break; + case kAS17GetWrench1: + _nextWrenchSequenceId = 0x230; + break; + case kAS17GetWrench2: + _nextCarWindowSequenceId = 0x249; + break; + case kAS17GetWrenchDone: + plat._actionStatus = -1; + _vm->invAdd(kItemWrench); + _vm->setGrabCursorSprite(kItemWrench); + break; + case kAS17PlatUsePhone: + gameSys.setAnimation(0x24E, plat._id, 1); + gameSys.insertSequence(0x24E, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceDatNum = 0; + plat._sequenceId = 0x24E; + plat._actionStatus = kAS17LeaveScene; + _vm->_newSceneNum = 53; + break; + case kAS17PlatPhoningAssistant: + ++_platPhoneCtr; + if (_platPhoneCtr >= 7) { + _platPhoneCtr = 0; + _nextPhoneSequenceId = -1; + _currPhoneSequenceId = -1; + gameSys.insertSequence(0x25B, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceDatNum = 0; + plat._sequenceId = 0x25B; + plat._actionStatus = -1; + _vm->clearFlag(kGFPlatypusTalkingToAssistant); + _vm->_sceneWaiting = false; + updateHotspots(); + } else { + _nextPhoneSequenceId = kPlatPhoneSequenceIds[_platPhoneCtr]; + gameSys.setAnimation(_nextPhoneSequenceId, 254, 1); + gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x25A, plat._id, 0x25A, plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceDatNum = 0; + plat._sequenceId = 0x25A; + _currPhoneSequenceId = _nextPhoneSequenceId; + } + break; + case kAS17LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + switch (_nextWrenchSequenceId) { + case 0x233: + gnap._actionStatus = -1; + gameSys.insertSequence(0x243, plat._id, + plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, + kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currWrenchSequenceId = _nextWrenchSequenceId; + _nextWrenchSequenceId = -1; + plat._sequenceId = 0x243; + plat._sequenceDatNum = 0; + gameSys.setAnimation(0x243, plat._id, 1); + break; + case 0x234: + gnap._actionStatus = -1; + gameSys.insertSequence(0x242, plat._id, + plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, + kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currWrenchSequenceId = _nextWrenchSequenceId; + _nextWrenchSequenceId = -1; + plat._sequenceId = 0x242; + plat._sequenceDatNum = 0; + gameSys.setAnimation(0x242, plat._id, 1); + break; + case 0x231: + if (_vm->getRandom(2) != 0) + _nextCarWindowSequenceId = 0x245; + else + _nextCarWindowSequenceId = 0x248; + gameSys.setAnimation(0, 0, 2); + break; + case 0x232: + _nextCarWindowSequenceId = 0x247; + gameSys.setAnimation(0, 0, 2); + break; + case 0x22E: + case 0x235: + if (_nextWrenchSequenceId == 0x235) + _vm->_hotspots[kHS17Wrench]._flags &= ~SF_DISABLED; + else + _vm->_hotspots[kHS17Wrench]._flags |= SF_DISABLED; + _canTryGetWrench = !_canTryGetWrench; + gameSys.setAnimation(_nextWrenchSequenceId, 40, 2); + gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currWrenchSequenceId = _nextWrenchSequenceId; + _nextWrenchSequenceId = -1; + break; + case 0x230: + if (gnap._actionStatus == kAS17GetWrenchGnapReady) { + gameSys.setAnimation(0, 0, 2); + if (_canTryGetWrench) { + gameSys.insertSequence(0x22E, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currWrenchSequenceId = 0x22E; + _canTryGetWrench = false; + } + gameSys.setAnimation(0x23F, plat._id, 1); + gameSys.insertSequence(0x10875, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x23F, plat._id, + plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, + kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 1; + plat._sequenceDatNum = 0; + gnap._sequenceId = 0x875; + plat._sequenceId = 0x23F; + gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1); + plat._actionStatus = kAS17GetWrench2; + } + break; + default: + if (_nextWrenchSequenceId != -1) { + gameSys.setAnimation(_nextWrenchSequenceId, 40, 2); + gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currWrenchSequenceId = _nextWrenchSequenceId; + _nextWrenchSequenceId = -1; + } + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_nextCarWindowSequenceId) { + case 0x246: + gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3); + gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currCarWindowSequenceId = _nextCarWindowSequenceId; + _nextCarWindowSequenceId = -1; + break; + case 0x245: + case 0x247: + case 0x248: + gameSys.setAnimation(_nextWrenchSequenceId, 40, 2); + gameSys.insertSequence(_nextWrenchSequenceId, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(2) != 2) + update(); + gameSys.setAnimation(_nextCarWindowSequenceId, 40, 3); + gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currCarWindowSequenceId = _nextCarWindowSequenceId; + _nextCarWindowSequenceId = -1; + _currWrenchSequenceId = _nextWrenchSequenceId; + _nextWrenchSequenceId = -1; + break; + case 0x249: + gameSys.setAnimation(0x230, 40, 2); + gameSys.setAnimation(0x240, plat._id, 1); + gameSys.insertSequence(0x230, 40, _currWrenchSequenceId, 40, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(_nextCarWindowSequenceId, 40, _currCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x240, plat._id, plat._sequenceId, plat._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x23E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x23E; + gnap._sequenceDatNum = 0; + plat._sequenceId = 0x240; + plat._sequenceDatNum = 0; + gameSys.setAnimation(0x24A, 40, 3); + gameSys.insertSequence(0x24A, 40, _nextCarWindowSequenceId, 40, kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(2) != 2) { + update(); + if (gameSys.getAnimationStatus(3) == 2) { + gameSys.setAnimation(0x24A, 40, 3); + gameSys.insertSequence(0x24A, 40, 586, 40, kSeqSyncWait, 0, 0, 0); + } + } + gameSys.insertSequence(0x22D, 40, 560, 40, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x24B, 40, 3); + gameSys.insertSequence(0x24B, 40, 586, 40, kSeqSyncWait, 0, 0, 0); + _currCarWindowSequenceId = 0x24B; + _nextCarWindowSequenceId = -1; + _currWrenchSequenceId = 0x22D; + _nextWrenchSequenceId = -1; + _vm->setFlag(kGFGrassTaken); + gnap._actionStatus = -1; + plat._actionStatus = 2; + updateHotspots(); + _vm->_timers[5] = _vm->getRandom(30) + 80; + break; + } + } + +} + +/*****************************************************************************/ + +static const int kScene18SequenceIds[] = { + 0x219, 0x21A, 0x21B, 0x21C, 0x21D +}; + +Scene18::Scene18(GnapEngine *vm) : Scene(vm) { + _cowboyHatSurface = nullptr; + + _platPhoneCtr = 0; + _platPhoneIter = 0; + _nextPhoneSequenceId = -1; + _currPhoneSequenceId = -1; +} + +Scene18::~Scene18() { + delete _cowboyHatSurface; +} + +int Scene18::init() { + _vm->_gameSys->setAnimation(0, 0, 3); + return 0x222; +} + +void Scene18::updateHotspots() { + _vm->setHotspot(kHS18Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS18GarbageCan, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos - 35, _vm->_gridMinY + 230, _vm->_gridMinX + 75 * _vm->_s18GarbageCanPos + 35, _vm->_gridMinY + 318, + SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, _vm->_s18GarbageCanPos, 7); + _vm->setHotspot(kHS18ExitToyStore, 460, 238, 592, 442, SF_EXIT_U_CURSOR, 7, 7); + _vm->setHotspot(kHS18ExitPhoneBooth, 275, 585, 525, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10); + _vm->setHotspot(kHS18ExitGrubCity, 0, 350, 15, 600, SF_EXIT_L_CURSOR, 0, 9); + _vm->setHotspot(kHS18HydrantTopValve, 100, 345, 182, 410, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 8); + _vm->setHotspot(kHS18HydrantRightValve, 168, 423, 224, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7); + _vm->setHotspot(kHS18CowboyHat, 184, 63, 289, 171, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7); + _vm->setHotspot(kHS18WalkArea1, 0, 0, 800, 448); + _vm->setHotspot(kHS18WalkArea2, 0, 0, 214, 515); + _vm->setDeviceHotspot(kHS18Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFTruckFilledWithGas)) { + if (_vm->isFlag(kGFTruckKeysUsed)) { + _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED; + _vm->_hotspots[kHS18HydrantRightValve]._rect.left = 148; + _vm->_hotspots[kHS18HydrantRightValve]._rect.top = 403; + _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED; + _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7); + } else { + _vm->_hotspots[kHS18HydrantTopValve]._rect.top = 246; + } + } else if (_vm->isFlag(kGFBarnPadlockOpen)) { + _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED; + _vm->_hotspots[kHS18HydrantTopValve]._rect.left = 105; + _vm->_hotspots[kHS18HydrantTopValve]._rect.right = 192; + } else if (_vm->isFlag(kGFTruckKeysUsed)) { + _vm->_hotspots[kHS18GarbageCan]._rect = Common::Rect(115, 365, 168, 470); + _vm->_hotspots[kHS18GarbageCan]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + _vm->_hotspotsWalkPos[kHS18GarbageCan] = Common::Point(3, 7); + } + if (_vm->isFlag(kGFPlatypusDisguised)) + _vm->_hotspots[kHS18GarbageCan]._flags = SF_DISABLED; + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + _vm->_hotspots[kHS18Device]._flags = SF_DISABLED; + _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED; + _vm->_hotspots[kHS18HydrantRightValve]._flags = SF_DISABLED; + _vm->_hotspots[kHS18Platypus]._flags = SF_DISABLED; + } + if (_vm->isFlag(kGFUnk14)) { + _vm->_hotspots[kHS18HydrantTopValve]._flags = SF_DISABLED; + _vm->_hotspots[kHS18CowboyHat]._flags = SF_DISABLED; + } + _vm->_hotspotsCount = 11; +} + +void Scene18::gnapCarryGarbageCanTo(int gridX) { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + int gnapSeqId, gnapId, gnapDatNum, gnapGridX; + int destGridX, direction; + + int curGridX = (_vm->_leftClickMouseX - _vm->_gridMinX + 37) / 75; + + if (curGridX >= gnap._pos.x) + destGridX = curGridX - 1; + else + destGridX = curGridX + 1; + + if (gridX < 0) + gridX = 4; + + if (destGridX <= gridX) + destGridX = gridX; + + int nextGridX = _vm->_gridMaxX - 1; + if (nextGridX >= destGridX) + nextGridX = destGridX; + + if (nextGridX == gnap._pos.x) { + gnapSeqId = gnap._sequenceId; + gnapId = gnap._id; + gnapDatNum = gnap._sequenceDatNum; + gnapGridX = gnap._pos.x; + if (gnap._pos.x <= curGridX) + direction = 1; + else + direction = -1; + } else { + PlayerPlat& plat = *_vm->_plat; + if (gnap._pos.y == plat._pos.y) { + if (nextGridX >= gnap._pos.x) { + if (nextGridX >= plat._pos.x && gnap._pos.x <= plat._pos.x) + plat.makeRoom(); + } else if (nextGridX <= plat._pos.x && gnap._pos.x >= plat._pos.x) { + plat.makeRoom(); + } + } + gnapSeqId = gnap._sequenceId; + gnapId = gnap._id; + gnapDatNum = gnap._sequenceDatNum; + gnapGridX = gnap._pos.x; + int seqId; + if (nextGridX < gnap._pos.x) { + direction = -1; + seqId = 0x204; + } else { + direction = 1; + seqId = 0x203; + } + + int seqId2 = 20 * gnap._pos.y + 1; + do { + if (_vm->isPointBlocked(gnapGridX + direction, gnap._pos.y)) + break; + seqId2 += direction; + gameSys.insertSequence(seqId, seqId2, + gnapSeqId | (gnapDatNum << 16), gnapId, + kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnapSeqId = seqId; + gnapId = seqId2; + gnapDatNum = 0; + gnapGridX += direction; + } while (nextGridX != gnapGridX); + } + + if (direction == 1) + gnap._sequenceId = 0x20A; + else + gnap._sequenceId = 0x209; + gnap._sequenceDatNum = 0; + + if (direction == 1) + gnap._idleFacing = kDirBottomRight; + else + gnap._idleFacing = kDirBottomLeft; + + gnap._id = 20 * gnap._pos.y + 1; + + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gameSys.insertSequence(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + gnapSeqId | (gnapDatNum << 16), gnapId, + kSeqScale | kSeqSyncWait, 0, 75 * gnapGridX - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + + gnap._pos.x = gnapGridX; +} + +void Scene18::putDownGarbageCan(int animationIndex) { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (animationIndex >= 0) { + while (gameSys.getAnimationStatus(animationIndex) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + } + if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight) + _vm->_s18GarbageCanPos = gnap._pos.x - 1; + else + _vm->_s18GarbageCanPos = gnap._pos.x + 1; + _vm->clearFlag(kGFPlatypusDisguised); + updateHotspots(); + if (gnap._idleFacing != kDirIdleLeft && gnap._idleFacing != kDirBottomRight && gnap._idleFacing != kDirUpRight) { + gameSys.insertSequence(0x107BA, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7BA; + } else { + gameSys.insertSequence(0x107B9, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B9; + } + gnap._sequenceDatNum = 1; + gameSys.insertSequence(0x1FB, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0); + gameSys.setAnimation(0x1FA, 19, 4); + gameSys.insertSequence(0x1FA, 19, 507, 19, kSeqSyncWait, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0); + while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); +} + +void Scene18::platEndPhoning(bool platFl) { + GameSys& gameSys = *_vm->_gameSys; + PlayerPlat& plat = *_vm->_plat; + + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + _platPhoneIter = 0; + _platPhoneCtr = 0; + plat._actionStatus = -1; + if (_currPhoneSequenceId != -1) { + gameSys.setAnimation(0x21E, 254, 3); + gameSys.insertSequence(0x21E, 254, _currPhoneSequenceId, 254, kSeqSyncExists, 0, 0, 0); + while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + } + gameSys.removeSequence(0x21F, 254, true); + gameSys.setAnimation(0, 0, 3); + _vm->clearFlag(kGFPlatypusTalkingToAssistant); + if (platFl) { + plat._actionStatus = kAS18PlatComesHere; + _vm->_timers[6] = 50; + _vm->_sceneWaiting = true; + } + _currPhoneSequenceId = -1; + _nextPhoneSequenceId = -1; + updateHotspots(); + } +} + +void Scene18::closeHydrantValve() { + PlayerGnap& gnap = *_vm->_gnap; + + gnap._actionStatus = kAS18LeaveScene; + _vm->updateMouseCursor(); + if (_vm->isFlag(kGFTruckFilledWithGas)) { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1); + if (_vm->isFlag(kGFTruckKeysUsed)) { + gnap._actionStatus = kAS18CloseRightValveWithGarbageCan; + waitForGnapAction(); + } else { + gnap._actionStatus = kAS18CloseRightValveNoGarbageCan; + waitForGnapAction(); + } + } else if (_vm->isFlag(kGFBarnPadlockOpen)) { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1); + gnap._actionStatus = kAS18CloseTopValve; + waitForGnapAction(); + } +} + +void Scene18::waitForGnapAction() { + PlayerGnap& gnap = *_vm->_gnap; + + while (gnap._actionStatus >= 0 && !_vm->_gameDone) { + updateAnimations(); + _vm->gameUpdateTick(); + } +} + +void Scene18::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _cowboyHatSurface = nullptr; + + _vm->playSound(0x10940, true); + _vm->startSoundTimerA(4); + _vm->_timers[5] = _vm->getRandom(100) + 100; + _vm->queueInsertDeviceIcon(); + _vm->clearFlag(kGFPlatypusDisguised); + + if (!_vm->isFlag(kGFUnk14)) + gameSys.insertSequence(0x1F8, 19, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFTruckKeysUsed)) { + if (_vm->isFlag(kGFTruckFilledWithGas)) { + gameSys.insertSequence(0x214, 39, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0); + _vm->playSound(0x22B, true); + } else { + gameSys.insertSequence(0x1F9, 19, 0, 0, kSeqNone, 0, 0, 0); + } + } else { + gameSys.insertSequence(0x1FA, 19, 0, 0, kSeqNone, 0, 15 * (5 * _vm->_s18GarbageCanPos - 40), 0); + if (_vm->isFlag(kGFTruckFilledWithGas)) { + gameSys.insertSequence(0x212, 39, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x20D, 39, 0, 0, kSeqLoop, 0, 0, 0); + _vm->playSound(0x22B, true); + } else if (_vm->isFlag(kGFBarnPadlockOpen)) { + gameSys.insertSequence(0x20E, 39, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x217, 39, 0, 0, kSeqLoop, 0, 0, 0); + _vm->playSound(0x22B, true); + } + } + + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + if (_vm->_prevSceneNum == 17) + gnap.initPos(4, 11, kDirBottomRight); + else + gnap.initPos(4, 7, kDirBottomRight); + _platPhoneCtr = _vm->getRandom(5); + if (_vm->isFlag(kGFUnk27)) { + gameSys.insertSequence(0x21E, 254, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + _currPhoneSequenceId = -1; + platEndPhoning(true); + _vm->clearFlag(kGFUnk27); + } else { + _currPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr]; + _platPhoneIter = 0; + gameSys.insertSequence(0x21F, 254, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(_currPhoneSequenceId, 254, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + } + if (_vm->isFlag(kGFUnk27)) { + platEndPhoning(true); + _vm->clearFlag(kGFUnk27); + } else { + gameSys.setAnimation(_currPhoneSequenceId, 254, 3); + } + gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1); + } else { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->clearFlag(kGFGnapControlsToyUFO); + _vm->setGrabCursorSprite(kItemCowboyHat); + _vm->_prevSceneNum = 19; + } + if (_vm->_prevSceneNum == 17) { + gnap.initPos(4, 11, kDirBottomRight); + plat.initPos(5, 11, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(4, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1); + } else if (_vm->_prevSceneNum == 19) { + gnap.initPos(7, 7, kDirBottomRight); + plat.initPos(8, 7, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1); + } else { + gnap.initPos(-1, 10, kDirBottomRight); + plat.initPos(-1, 10, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(3, 7), -1, 0x107B9, 1); + plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1); + } + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 20, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS18Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS18Platypus: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, plat._pos.x, plat._pos.y); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS18CowboyHat: + if (gnap._actionStatus == kAS18StandingOnHydrant) { + gnap._actionStatus = kAS18GrabCowboyHat; + _vm->_sceneWaiting = false; + } else if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18CowboyHat], 3, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(3, 2)); + break; + case GRAB_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18CowboyHat], 0, gnap.getSequenceId(kGSPullOutDeviceNonWorking, Common::Point(3, 2)) | 0x10000, 1); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS18GarbageCan: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFUnk14)) { + if (_vm->_grabCursorSpriteIndex >= 0) + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 1, 5); + else + gnap.playImpossible(); + } else { + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) + platEndPhoning(true); + if (_vm->_grabCursorSpriteIndex >= 0) { + if (!_vm->isFlag(kGFTruckKeysUsed)) { + Common::Point destPos; + destPos.x = _vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1); + destPos.y = _vm->_hotspotsWalkPos[kHS18GarbageCan].y; + gnap.playShowCurrItem(destPos, _vm->_hotspotsWalkPos[kHS18GarbageCan].x, _vm->_hotspotsWalkPos[kHS18GarbageCan].y); + } else + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18GarbageCan], 2, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (!_vm->isFlag(kGFTruckKeysUsed)) + gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS18GarbageCan].x - (gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), _vm->_hotspotsWalkPos[kHS18GarbageCan].y)); + else if (!_vm->isFlag(kGFTruckFilledWithGas)) + gnap.playScratchingHead(Common::Point(2, 4)); + break; + case GRAB_CURSOR: + if (!_vm->isFlag(kGFTruckKeysUsed)) { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan] + Common::Point((gnap._pos.x < _vm->_s18GarbageCanPos ? 1 : -1), 0), + -1, -1, 1); + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(_vm->_s18GarbageCanPos, gnap._pos.y)) | 0x10000, 1); + gnap._actionStatus = kAS18GrabGarbageCanFromStreet; + } else if (!_vm->isFlag(kGFTruckFilledWithGas)) { + if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS18GarbageCan], 0, -1, 1)) + gnap._actionStatus = kAS18GrabGarbageCanFromHydrant; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + } + break; + + case kHS18HydrantTopValve: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + // While carrying garbage can + if (_vm->_grabCursorSpriteIndex >= 0) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 0, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + gnap.playScratchingHead(); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFTruckFilledWithGas)) { + gnapCarryGarbageCanTo(2); + gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant; + } else if (!_vm->isFlag(kGFBarnPadlockOpen)) { + gnapCarryGarbageCanTo(2); + gnap._actionStatus = kAS18PutGarbageCanOnHydrant; + } else { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + gnap.playImpossible(); + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + gnap.playImpossible(); + break; + } + } + } else { + if (_vm->_grabCursorSpriteIndex == kItemWrench) { + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1); + gnap._actionStatus = kAS18OpenTopValve; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 1, 5); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 5)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFBarnPadlockOpen)) { + _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BA, 1); + _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS18CloseTopValve; + } else + gnap.playImpossible(); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + } + break; + + case kHS18HydrantRightValve: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFUnk14)) { + if (_vm->_grabCursorSpriteIndex == -1) { + gnap.playImpossible(); + } else { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5); + } + } else { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } + if (_vm->_grabCursorSpriteIndex == kItemWrench) { + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, Common::Point(2, 8)) | 0x10000, 1); + if (_vm->isFlag(kGFTruckKeysUsed)) + gnap._actionStatus = kAS18OpenRightValveWithGarbageCan; + else + gnap._actionStatus = kAS18OpenRightValveNoGarbageCan; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 1, 5); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 5)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFTruckFilledWithGas)) { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1); + if (_vm->isFlag(kGFTruckKeysUsed)) + gnap._actionStatus = kAS18CloseRightValveWithGarbageCan; + else + gnap._actionStatus = kAS18CloseRightValveNoGarbageCan; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + } + break; + + case kHS18ExitToyStore: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } + if (_vm->isFlag(kGFPictureTaken)) { + gnap.playImpossible(); + } else { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 19; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore], 0, 0x107C0, 1); + gnap._actionStatus = kAS18LeaveScene; + if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) + plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitToyStore] + Common::Point(1, 0), -1, 0x107C2, 1); + } + } + break; + + case kHS18ExitPhoneBooth: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } + closeHydrantValve(); + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 17; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth], 0, 0x107AE, 1); + gnap._actionStatus = kAS18LeaveScene; + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) + _vm->setFlag(kGFUnk27); + else + plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitPhoneBooth] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS18ExitGrubCity: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } + closeHydrantValve(); + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 20; + _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity], 0, 0x107B2, 1); + gnap._actionStatus = kAS18LeaveScene; + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) + platEndPhoning(false); + else + plat.walkTo(_vm->_hotspotsWalkPos[kHS18ExitGrubCity] + Common::Point(0, -1), -1, 0x107CF, 1); + _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE; + } + break; + + case kHS18WalkArea1: + case kHS18WalkArea2: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + _vm->_mouseClickState._left = false; + } + break; + + default: + if (gnap._actionStatus != kAS18StandingOnHydrant && _vm->_mouseClickState._left) { + if (_vm->isFlag(kGFPlatypusDisguised)) { + gnapCarryGarbageCanTo(-1); + putDownGarbageCan(0); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x10940)) + _vm->playSound(0x10940, true); + + if ((_vm->isFlag(kGFTruckFilledWithGas) || _vm->isFlag(kGFBarnPadlockOpen)) && !_vm->isSoundPlaying(0x22B) && + gnap._actionStatus != kAS18OpenRightValveNoGarbageCanDone && gnap._actionStatus != kAS18OpenRightValveNoGarbageCan && + gnap._actionStatus != kAS18OpenTopValve && gnap._actionStatus != kAS18OpenTopValveDone && + gnap._actionStatus != kAS18OpenRightValveWithGarbageCan && gnap._actionStatus != kAS18OpenRightValveWithGarbageCanDone) + _vm->playSound(0x22B, true); + + if (!_vm->_isLeavingScene) { + if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + if (plat._actionStatus == kAS18PlatComesHere) { + if (!_vm->_timers[6]) { + plat._actionStatus = -1; + _vm->_sceneWaiting = false; + plat.initPos(-1, 10, kDirIdleLeft); + plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1); + _vm->clearFlag(kGFPlatypusTalkingToAssistant); + } + } else { + _vm->_hotspots[kHS18WalkArea1]._rect.bottom += 48; + _vm->_hotspots[kHS18WalkArea2]._rect.left += 75; + plat.updateIdleSequence(); + _vm->_hotspots[kHS18WalkArea2]._rect.left -= 75; + _vm->_hotspots[kHS18WalkArea1]._rect.bottom -= 48; + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(100) + 100; + if (gnap._actionStatus < 0) { + if (_vm->getRandom(2) == 1) + gameSys.insertSequence(0x220, 255, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x221, 255, 0, 0, kSeqNone, 0, 0, 0); + } + } + _vm->playSoundA(); + } + if (!_vm->isFlag(kGFPlatypusDisguised)) + gnap.updateIdleSequence(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } + + if (_vm->isFlag(kGFGnapControlsToyUFO)) + _vm->deleteSurface(&_cowboyHatSurface); +} + +void Scene18::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS18GrabGarbageCanFromStreet: + if (gnap._idleFacing != kDirUpRight && gnap._idleFacing != kDirBottomRight) { + gameSys.insertSequence(0x1FC, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - 675, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x1FC; + } else { + gameSys.insertSequence(0x1FD, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - 525, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x1FD; + } + gameSys.removeSequence(0x1FA, 19, true); + _vm->setFlag(kGFPlatypusDisguised); + updateHotspots(); + gnap._actionStatus = -1; + break; + case kAS18GrabGarbageCanFromHydrant: + gameSys.insertSequence(0x1FE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0x1F9, 19, true); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x1FE; + _vm->clearFlag(kGFTruckKeysUsed); + _vm->setFlag(kGFPlatypusDisguised); + updateHotspots(); + gnap._actionStatus = -1; + break; + case kAS18CloseRightValveNoGarbageCan: + gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0x20D, 39, true); + gameSys.removeSequence(0x212, 39, true); + gameSys.removeSequence(0x211, 39, true); + _vm->stopSound(0x22B); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x205; + _vm->clearFlag(kGFTruckFilledWithGas); + _vm->invAdd(kItemWrench); + _vm->setGrabCursorSprite(kItemWrench); + updateHotspots(); + gnap._actionStatus = -1; + break; + case kAS18OpenTopValve: + _vm->setFlag(kGFBarnPadlockOpen); + updateHotspots(); + gnap.playPullOutDevice(Common::Point(2, 7)); + gnap.playUseDevice(); + gameSys.insertSequence(0x20C, 19, 0, 0, kSeqNone, 0, 0, 0); + _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantTopValve], 0, 0x107BB, 1); + _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS18OpenTopValveDone; + break; + case kAS18OpenTopValveDone: + _vm->setGrabCursorSprite(-1); + gameSys.insertSequence(0x208, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x216, 39, 0, 0, kSeqNone, 21, 0, 0); + gameSys.removeSequence(0x20C, 19, true); + gameSys.setAnimation(0x217, 39, 5); + gameSys.insertSequence(0x217, 39, 0x216, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->playSound(0x22B, true); + gameSys.insertSequence(0x20E, 39, 0, 0, kSeqNone, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x208; + _vm->invRemove(kItemWrench); + _vm->setGrabCursorSprite(-1); + gnap._actionStatus = -1; + break; + case kAS18CloseTopValve: + gameSys.insertSequence(0x206, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0x20E, 39, true); + gameSys.removeSequence(0x216, 39, true); + gameSys.removeSequence(0x217, 39, true); + _vm->stopSound(0x22B); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x206; + _vm->clearFlag(kGFBarnPadlockOpen); + _vm->invAdd(kItemWrench); + _vm->setGrabCursorSprite(kItemWrench); + updateHotspots(); + gnap._actionStatus = -1; + break; + case kAS18GrabCowboyHat: + gameSys.setAnimation(0x200, gnap._id, 0); + gameSys.insertSequence(0x200, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x200; + gnap._actionStatus = kAS18GrabCowboyHatDone; + break; + case kAS18GrabCowboyHatDone: + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + _cowboyHatSurface = _vm->addFullScreenSprite(0x1D2, 255); + gameSys.setAnimation(0x218, 256, 0); + gameSys.insertSequence(0x218, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->_newSceneNum = 18; + _vm->invAdd(kItemCowboyHat); + _vm->invAdd(kItemWrench); + _vm->setFlag(kGFGnapControlsToyUFO); + _vm->setFlag(kGFUnk14); + _vm->clearFlag(kGFTruckFilledWithGas); + _vm->setFlag(kGFTruckKeysUsed); + _vm->setFlag(kGFUnk14); // Useless, already set + updateHotspots(); + gnap._actionStatus = kAS18LeaveScene; + break; + case kAS18LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS18PutGarbageCanOnRunningHydrant: + _vm->setFlag(kGFTruckKeysUsed); + _vm->clearFlag(kGFPlatypusDisguised); + gameSys.requestRemoveSequence(0x211, 39); + gameSys.requestRemoveSequence(0x212, 39); + gameSys.insertSequence(0x210, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + _vm->stopSound(0x22B); + gameSys.setAnimation(0x210, gnap._id, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x210; + gnap._actionStatus = kAS18PutGarbageCanOnRunningHydrant2; + break; + case kAS18PutGarbageCanOnRunningHydrant2: + _vm->playSound(0x22B, true); + gameSys.setAnimation(0x1FF, gnap._id, 0); + gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x1FF; + _vm->_sceneWaiting = true; + gnap._actionStatus = kAS18StandingOnHydrant; + break; + case kAS18StandingOnHydrant: + gameSys.setAnimation(0x1FF, gnap._id, 0); + gameSys.insertSequence(0x1FF, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + break; + case kAS18OpenRightValveNoGarbageCan: + case kAS18OpenRightValveWithGarbageCan: + _vm->setFlag(kGFTruckFilledWithGas); + updateHotspots(); + gnap.playPullOutDevice(Common::Point(2, 7)); + gnap.playUseDevice(); + gameSys.insertSequence(0x20B, 19, 0, 0, kSeqNone, 0, 0, 0); + _vm->_hotspots[kHS18WalkArea2]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS18HydrantRightValve], 0, 0x107BA, 1); + _vm->_hotspots[kHS18WalkArea2]._flags &= ~SF_WALKABLE; + if (gnap._actionStatus == kAS18OpenRightValveNoGarbageCan) + gnap._actionStatus = kAS18OpenRightValveNoGarbageCanDone; + else + gnap._actionStatus = kAS18OpenRightValveWithGarbageCanDone; + break; + case kAS18OpenRightValveWithGarbageCanDone: + _vm->setGrabCursorSprite(-1); + gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x213, 39, 0, 0, kSeqNone, 21, 0, 0); + gameSys.requestRemoveSequence(0x1F9, 19); + gameSys.removeSequence(0x20B, 19, true); + gameSys.setAnimation(0x213, 39, 5); + gameSys.insertSequence(0x214, 39, 0x213, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->playSound(0x22B, true); + gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x207; + _vm->invRemove(kItemWrench); + gnap._actionStatus = -1; + break; + case kAS18OpenRightValveNoGarbageCanDone: + _vm->setGrabCursorSprite(-1); + gameSys.insertSequence(0x207, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x211, 39, 0, 0, kSeqNone, 21, 0, 0); + gameSys.removeSequence(0x20B, 19, true); + gameSys.setAnimation(0x211, 39, 5); + gameSys.insertSequence(0x212, 39, 0x211, 39, kSeqLoop | kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(5) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->playSound(0x22B, true); + gameSys.insertSequence(0x20D, 39, 0, 0, kSeqNone, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x207; + _vm->invRemove(kItemWrench); + gnap._actionStatus = -1; + break; + case kAS18CloseRightValveWithGarbageCan: + gameSys.insertSequence(0x205, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0x20D, 39, true); + gameSys.insertSequence(0x215, 39, 0x214, 39, kSeqSyncWait, 0, 0, 0); + _vm->stopSound(0x22B); + gameSys.setAnimation(0x1F9, 19, 0); + gameSys.insertSequence(0x1F9, 19, 0x215, 39, kSeqSyncWait, 0, 0, 0); + _vm->clearFlag(kGFTruckFilledWithGas); + _vm->invAdd(kItemWrench); + _vm->setGrabCursorSprite(kItemWrench); + gameSys.insertSequence(0x107B5, gnap._id, 517, gnap._id, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + updateHotspots(); + gnap._sequenceDatNum = 1; + gnap._sequenceId = 0x7B5; + gnap._actionStatus = kAS18CloseRightValveWithGarbageCanDone; + break; + case kAS18CloseRightValveWithGarbageCanDone: + gnap._actionStatus = -1; + break; + case kAS18PutGarbageCanOnHydrant: + _vm->setFlag(kGFTruckKeysUsed); + _vm->clearFlag(kGFPlatypusDisguised); + gameSys.insertSequence(0x20F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x20F, gnap._id, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x20F; + gnap._actionStatus = kAS18PutGarbageCanOnHydrantDone; + break; + case kAS18PutGarbageCanOnHydrantDone: + gameSys.insertSequence(0x1F9, 19, 0x20F, gnap._id, kSeqNone, 0, 0, 0); + updateHotspots(); + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + gameSys.setAnimation(0, 0, 3); + ++_platPhoneIter; + if (_platPhoneIter <= 4) { + ++_platPhoneCtr; + _nextPhoneSequenceId = kScene18SequenceIds[_platPhoneCtr % 5]; + gameSys.setAnimation(_nextPhoneSequenceId, 254, 3); + gameSys.insertSequence(_nextPhoneSequenceId, 254, _currPhoneSequenceId, 254, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x21F, 254, 0x21F, 254, kSeqSyncWait, 0, 0, 0); + _currPhoneSequenceId = _nextPhoneSequenceId; + } else { + platEndPhoning(true); + } + } +} + +/*****************************************************************************/ + +static const int kS19ShopAssistantSequenceIds[] = { + 0x6F, 0x70, 0x71, 0x72, 0x73 +}; + +Scene19::Scene19(GnapEngine *vm) : Scene(vm) { + _toyGrabCtr = 0; + _pictureSurface = 0; + _shopAssistantCtr = 0; + _pictureSurface = nullptr; +} + +Scene19::~Scene19() { + delete _pictureSurface; +} + +int Scene19::init() { + _vm->playSound(0x79, false); + return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x77 : 0x76; +} + +void Scene19::updateHotspots() { + _vm->setHotspot(kHS19Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS19ExitOutsideToyStore, 36, 154, 142, 338, SF_EXIT_NW_CURSOR, 4, 6); + _vm->setHotspot(kHS19Picture, 471, 237, 525, 283, SF_DISABLED, 7, 2); + _vm->setHotspot(kHS19ShopAssistant, 411, 151, 575, 279, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7); + _vm->setHotspot(kHS19Phone, 647, 166, 693, 234, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0); + _vm->setHotspot(kHS19Toy1, 181, 11, 319, 149, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 0); + _vm->setHotspot(kHS19Toy2, 284, 85, 611, 216, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 0); + _vm->setHotspot(kHS19Toy3, 666, 38, 755, 154, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 0); + _vm->setHotspot(kHS19Toy4, 154, 206, 285, 327, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 3); + _vm->setHotspot(kHS19Toy5, 494, 301, 570, 448, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 5); + _vm->setHotspot(kHS19Toy6, 0, 320, 188, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 6); + _vm->setHotspot(kHS19Toy7, 597, 434, 800, 600, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 8); + _vm->setHotspot(kHS19WalkArea1, 0, 0, 170, 600); + _vm->setHotspot(kHS19WalkArea2, 622, 0, 800, 600); + _vm->setHotspot(kHS19WalkArea3, 0, 0, 800, 437); + _vm->setDeviceHotspot(kHS19Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + _vm->_hotspots[kHS19Toy1]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Toy2]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Toy3]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Toy4]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Toy5]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Toy6]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Toy7]._flags = SF_DISABLED; + _vm->_hotspots[kHS19ShopAssistant]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Phone]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Platypus]._flags = SF_DISABLED; + _vm->_hotspots[kHS19Picture]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + } + _vm->_hotspotsCount = 16; +} + +void Scene19::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + _toyGrabCtr = 0; + _pictureSurface = nullptr; + + gameSys.insertSequence(0x74, 254, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x75, 254, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFPictureTaken)) + gameSys.insertSequence(0x69, 19, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + gnap.initPos(3, 6, kDirBottomRight); + _currShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_vm->getRandom(5)]; + _nextShopAssistantSequenceId = _currShopAssistantSequenceId; + gameSys.setAnimation(_currShopAssistantSequenceId, 20, 4); + gameSys.insertSequence(0x6E, 254, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0); + _shopAssistantCtr = 0; + _vm->endSceneInit(); + gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1); + updateHotspots(); + } else { + _currShopAssistantSequenceId = 0x6D; + _nextShopAssistantSequenceId = -1; + gameSys.setAnimation(0x6D, 20, 4); + gameSys.insertSequence(_currShopAssistantSequenceId, 20, 0, 0, kSeqNone, 0, 0, 0); + _vm->_timers[6] = _vm->getRandom(40) + 50; + gnap.initPos(3, 6, kDirBottomRight); + plat.initPos(4, 6, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(4, 9), -1, 0x107B9, 1); + plat.walkTo(Common::Point(5, 9), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 5, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS19Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS19Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS19ExitOutsideToyStore: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 18; + _vm->_hotspots[kHS19WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[1], 0, 0x107B2, 1); + gnap._actionStatus = kAS19LeaveScene; + if (_vm->isFlag(kGFPlatypusTalkingToAssistant)) + _vm->setFlag(kGFUnk27); + else + plat.walkTo(_vm->_hotspotsWalkPos[1] + Common::Point(1, 0), -1, 0x107C5, 1); + _vm->_hotspots[kHS19WalkArea1]._flags &= ~SF_WALKABLE; + } + break; + + case kHS19Picture: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 2)); + break; + case GRAB_CURSOR: + if (!_vm->isFlag(kGFPictureTaken)) { + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]) | 0x10000, 1); + gnap._actionStatus = kAS19GrabPicture; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS19ShopAssistant: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 6, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 2)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS19TalkShopAssistant; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS19Toy1: + case kHS19Toy2: + case kHS19Toy3: + case kHS19Toy4: + case kHS19Toy5: + case kHS19Toy6: + case kHS19Toy7: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]); + break; + case GRAB_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1); + gnap.playIdle(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot]); + gnap._actionStatus = kAS19GrabToy; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS19Phone: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 9, 1); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(9, 1)); + break; + case GRAB_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], 0, -1, 1); + gnap.playIdle(Common::Point(8, 2)); + gnap._actionStatus = kAS19UsePhone; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS19WalkArea1: + case kHS19WalkArea2: + case kHS19WalkArea3: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = 0; + } + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + gnap.updateIdleSequence(); + if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) { + plat.updateIdleSequence(); + if (!_vm->_timers[6] && _nextShopAssistantSequenceId == -1) { + _vm->_timers[6] = _vm->getRandom(40) + 50; + if (_vm->getRandom(4) != 0) { + _nextShopAssistantSequenceId = 0x64; + } else if (_vm->isFlag(kGFPictureTaken)) { + _nextShopAssistantSequenceId = 0x64; + } else { + _nextShopAssistantSequenceId = 0x6C; + } + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } + + if (_pictureSurface) + _vm->deleteSurface(&_pictureSurface); +} + +void Scene19::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS19UsePhone: + _nextShopAssistantSequenceId = 0x67; + break; + case kAS19GrabToy: + ++_toyGrabCtr; + switch (_toyGrabCtr) { + case 1: + _nextShopAssistantSequenceId = 0x62; + break; + case 2: + _nextShopAssistantSequenceId = 0x6B; + break; + case 3: + _nextShopAssistantSequenceId = 0x66; + break; + default: + _nextShopAssistantSequenceId = 0x65; + break; + } + break; + case kAS19GrabPicture: + gnap.playPullOutDevice(Common::Point(6, 2)); + gnap.playUseDevice(); + gameSys.setAnimation(0x68, 19, 0); + gameSys.insertSequence(0x68, 19, 105, 19, kSeqSyncWait, 0, 0, 0); + _vm->invAdd(kItemPicture); + _vm->setFlag(kGFPictureTaken); + updateHotspots(); + gnap._actionStatus = kAS19GrabPictureDone; + break; + case kAS19GrabPictureDone: + _vm->setGrabCursorSprite(-1); + _vm->hideCursor(); + _pictureSurface = _vm->addFullScreenSprite(0xF, 255); + gameSys.setAnimation(0x61, 256, 0); + gameSys.insertSequence(0x61, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + _vm->setFlag(kGFUnk27); + _vm->showCursor(); + _vm->_newSceneNum = 17; + _vm->_isLeavingScene = true; + _vm->_sceneDone = true; + _nextShopAssistantSequenceId = -1; + break; + case kAS19TalkShopAssistant: + _nextShopAssistantSequenceId = 0x6D; + gnap._actionStatus = -1; + break; + case kAS19LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(4) == 2) { + switch (_nextShopAssistantSequenceId) { + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + _shopAssistantCtr = (_shopAssistantCtr + 1) % 5; + _nextShopAssistantSequenceId = kS19ShopAssistantSequenceIds[_shopAssistantCtr]; + gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4); + gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x6E, 254, 0x6E, 254, kSeqSyncWait, 0, 0, 0); + _currShopAssistantSequenceId = _nextShopAssistantSequenceId; + break; + case 0x62: + case 0x66: + case 0x6B: + gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4); + gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currShopAssistantSequenceId = _nextShopAssistantSequenceId; + _nextShopAssistantSequenceId = -1; + _vm->_timers[5] = 10; + while (_vm->_timers[5] && !_vm->_gameDone) + _vm->gameUpdateTick(); + + gnap.playIdle(Common::Point(6, 2)); + gnap._actionStatus = -1; + break; + case 0x67: + gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4); + gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currShopAssistantSequenceId = _nextShopAssistantSequenceId; + _nextShopAssistantSequenceId = -1; + gnap._actionStatus = -1; + break; + case 0x65: + gnap.playIdle(Common::Point(6, 2)); + gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 0); + gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currShopAssistantSequenceId = _nextShopAssistantSequenceId; + _nextShopAssistantSequenceId = -1; + _vm->_newSceneNum = 18; + gnap._actionStatus = kAS19LeaveScene; + break; + case 0x6D: + gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4); + gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x69, 19, 0x69, 19, kSeqSyncWait, _vm->getSequenceTotalDuration(_nextShopAssistantSequenceId), 0, 0); + _currShopAssistantSequenceId = _nextShopAssistantSequenceId; + _nextShopAssistantSequenceId = -1; + break; + case 0x64: + case 0x6C: + gameSys.setAnimation(_nextShopAssistantSequenceId, 20, 4); + gameSys.insertSequence(_nextShopAssistantSequenceId, 20, _currShopAssistantSequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currShopAssistantSequenceId = _nextShopAssistantSequenceId; + _nextShopAssistantSequenceId = -1; + break; + } + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/group1.h b/engines/gnap/scenes/group1.h new file mode 100644 index 0000000000..30771d017a --- /dev/null +++ b/engines/gnap/scenes/group1.h @@ -0,0 +1,454 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUP1_H +#define GNAP_GROUP1_H + +#include "gnap/debugger.h" + +namespace Gnap { + +enum { + kHS10Platypus = 0, + kHS10ExitBar = 1, + kHS10ExitBackdoor = 2, + kHS10Cook = 3, + kHS10Tongs = 4, + kHS10Box = 5, + kHS10Oven = 6, + kHS10WalkArea1 = 7, + kHS10Device = 8, + kHS10WalkArea2 = 9, + kHS10WalkArea3 = 10, + kHS10WalkArea4 = 11 +}; + +enum { + kHS11Platypus = 0, + kHS11ExitKitchen = 1, + kHS11ExitToilet = 2, + kHS11ExitLeft = 3, + kHS11GoggleGuy = 4, + kHS11HookGuy = 5, + kHS11Billard = 6, + kHS11WalkArea1 = 7, + kHS11Device = 8, + kHS11WalkArea2 = 9, + kHS11WalkArea3 = 10, + kHS11WalkArea4 = 11, + kHS11WalkArea5 = 12 +}; + +enum { + kHS12Platypus = 0, + kHS12ExitRight = 1, + kHS12ToothGuy = 2, + kHS12Barkeeper = 3, + kHS12BeardGuy = 4, + kHS12Jukebox = 5, + kHS12WalkArea1 = 6, + kHS12Device = 7, + kHS12WalkArea2 = 8, + kHS12WalkArea3 = 9, + kHS12WalkArea4 = 10 +}; + +enum { + kHS13Platypus = 0, + kHS13ExitBar = 1, + kHS13WalkArea1 = 2, + kHS13BackToilet = 3, + kHS13FrontToilet= 4, + kHS13Urinal = 5, + kHS13Scribble = 6, + kHS13Sink = 7, + kHS13WalkArea2 = 8, + kHS13Device = 9, + kHS13WalkArea3 = 10, + kHS13WalkArea4 = 11, + kHS13WalkArea5 = 12, + kHS13WalkArea6 = 13, + kHS13WalkArea7 = 14, + kHS13WalkArea8 = 15, + kHS13WalkArea9 = 16 +}; + +enum { + kHS14Platypus = 0, + kHS14Exit = 1, + kHS14Coin = 2, + kHS14Toilet = 3, + kHS14Device = 4 +}; + +enum { + kHS15Platypus = 0, + kHS15Exit = 1, + kHS15Button1 = 2, + kHS15Button2 = 3, + kHS15Button3 = 4, + kHS15Button4 = 5, + kHS15Button5 = 6, + kHS15Button6 = 7, + kHS15ButtonA = 8, + kHS15ButtonB = 9, + kHS15ButtonC = 10, + kHS15ButtonD = 11, + kHS15ButtonE = 12, + kHS15ButtonF = 13, + kHS15CoinSlot = 14, + kHS15PlayButton = 15, + kHS15Device = 16 +}; + +enum { + kHS17Platypus = 0, + kHS17Phone1 = 1, + kHS17Phone2 = 2, + kHS17ExitGrubCity = 3, + kHS17Device = 4, + kHS17ExitToyStore = 5, + kHS17Wrench = 6, + kHS17WalkArea1 = 7, + kHS17WalkArea2 = 8, + kHS17WalkArea3 = 9 +}; + +enum { + kHS18Platypus = 0, + kHS18GarbageCan = 1, + kHS18Device = 2, + kHS18ExitToyStore = 3, + kHS18ExitPhoneBooth = 4, + kHS18ExitGrubCity = 5, + kHS18HydrantTopValve = 6, + kHS18HydrantRightValve = 7, + kHS18CowboyHat = 8, + kHS18WalkArea1 = 9, + kHS18WalkArea2 = 10 +}; + +enum { + kHS19Platypus = 0, + kHS19ExitOutsideToyStore= 1, + kHS19Device = 2, + kHS19Picture = 3, + kHS19ShopAssistant = 4, + kHS19Toy1 = 5, + kHS19Toy2 = 6, + kHS19Toy3 = 7, + kHS19Phone = 8, + kHS19Toy4 = 9, + kHS19Toy5 = 10, + kHS19Toy6 = 11, + kHS19Toy7 = 12, + kHS19WalkArea1 = 13, + kHS19WalkArea2 = 14, + kHS19WalkArea3 = 15 +}; + +enum { + kAS10LeaveScene = 0, + kAS10AnnoyCook = 1, + kAS10PlatWithBox = 4 +}; + +enum { + kAS11LeaveScene = 0, + kAS11ShowMagazineToGoggleGuy = 3, + kAS11TalkGoggleGuy = 4, + kAS11GrabHookGuy = 6, + kAS11ShowItemToHookGuy = 8, + kAS11TalkHookGuy = 9, + kAS11GrabBillardBall = 11 +}; + +enum { + kAS12LeaveScene = 0, + kAS12QuarterToToothGuyDone = 1, + kAS12TalkToothGuy = 2, + kAS12GrabToothGuy = 4, + kAS12ShowItemToToothGuy = 5, + kAS12QuarterWithHoleToToothGuy = 6, + kAS12QuarterToToothGuy = 7, + kAS12TalkBeardGuy = 8, + kAS12LookBeardGuy = 9, + kAS12GrabBeardGuy = 10, + kAS12ShowItemToBeardGuy = 11, + kAS12TalkBarkeeper = 12, + kAS12LookBarkeeper = 13, + kAS12ShowItemToBarkeeper = 15, + kAS12QuarterWithBarkeeper = 16, + kAS12PlatWithBarkeeper = 17, + kAS12PlatWithToothGuy = 18, + kAS12PlatWithBeardGuy = 19 +}; + +enum { + kAS13LeaveScene = 0, + kAS13BackToilet = 1, + kAS13FrontToilet = 2, + kAS13LookScribble = 6, + kAS13GrabSink = 7, + kAS13GrabSinkDone = 8, + kAS13Wait = 12, + kAS13GrabUrinal = 13 +}; + +enum { + kAS17TryGetWrench = 0, + kAS17GetWrench2 = 1, + kAS17GetWrenchDone = 2, + kAS17GetWrench1 = 3, + kAS17PlatUsePhone = 4, + kAS17PutCoinIntoPhone = 5, + kAS17GetCoinFromPhone = 6, + kAS17GetCoinFromPhoneDone = 7, + kAS17PutCoinIntoPhoneDone = 8, + kAS17GnapUsePhone = 9, + kAS17GetWrenchGnapReady = 10, + kAS17GnapHangUpPhone = 11, + kAS17PlatPhoningAssistant = 12, + kAS17PlatHangUpPhone = 14, + kAS17LeaveScene = 15 +}; + +enum { + kAS18OpenRightValveNoGarbageCanDone = 0, + kAS18OpenRightValveNoGarbageCan = 1, + kAS18CloseRightValveNoGarbageCan = 2, + kAS18OpenTopValveDone = 3, + kAS18OpenTopValve = 4, + kAS18CloseTopValve = 5, + kAS18GrabGarbageCanFromStreet = 6, + kAS18GrabCowboyHat = 7, + kAS18GrabGarbageCanFromHydrant = 8, + kAS18PutGarbageCanOnRunningHydrant = 9, + kAS18PutGarbageCanOnRunningHydrant2 = 10, + kAS18GrabCowboyHatDone = 11, + kAS18StandingOnHydrant = 12, + kAS18OpenRightValveWithGarbageCan = 13, + kAS18OpenRightValveWithGarbageCanDone = 14, + kAS18CloseRightValveWithGarbageCan = 15, + kAS18PutGarbageCanOnHydrant = 16, + kAS18PutGarbageCanOnHydrantDone = 17, + kAS18PlatComesHere = 18, + kAS18CloseRightValveWithGarbageCanDone = 19, + kAS18LeaveScene = 20 +}; + +enum { + kAS19UsePhone = 0, + kAS19GrabToy = 1, + kAS19GrabPicture = 2, + kAS19GrabPictureDone = 3, + kAS19TalkShopAssistant = 4, + kAS19LeaveScene = 5 +}; + +/*****************************************************************************/ + +class GnapEngine; +class CutScene; + +class Scene10: public Scene { +public: + Scene10(GnapEngine *vm); + virtual ~Scene10() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb(); + +private: + int _nextCookSequenceId; + int _currCookSequenceId; +}; + +class Scene11: public Scene { +public: + Scene11(GnapEngine *vm); + virtual ~Scene11() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _billardBallCtr; + int _nextHookGuySequenceId; + int _currHookGuySequenceId; + int _nextGoggleGuySequenceId; + int _currGoggleGuySequenceId; +}; + +class Scene12: public Scene { +public: + Scene12(GnapEngine *vm); + virtual ~Scene12() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _nextBeardGuySequenceId; + int _currBeardGuySequenceId; + int _nextToothGuySequenceId; + int _currToothGuySequenceId; + int _nextBarkeeperSequenceId; + int _currBarkeeperSequenceId; +}; + +class Scene13: public Scene { +public: + Scene13(GnapEngine *vm); + virtual ~Scene13() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _backToiletCtr; + + void showScribble(); +}; + +class Scene14: public Scene { +public: + Scene14(GnapEngine *vm); + virtual ~Scene14() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; +}; + +class Scene15: public Scene { +public: + Scene15(GnapEngine *vm); + virtual ~Scene15() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _nextRecordSequenceId; + int _currRecordSequenceId; + int _nextSlotSequenceId; + int _currSlotSequenceId; + int _nextUpperButtonSequenceId; + int _currUpperButtonSequenceId; + int _nextLowerButtonSequenceId; + int _currLowerButtonSequenceId; +}; + +class Scene17: public Scene { +public: + Scene17(GnapEngine *vm); + virtual ~Scene17() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + bool _canTryGetWrench; + int _wrenchCtr; + int _platPhoneCtr; + int _platTryGetWrenchCtr; + int _nextPhoneSequenceId; + int _currPhoneSequenceId; + int _nextWrenchSequenceId; + int _currWrenchSequenceId; + int _nextCarWindowSequenceId; + int _currCarWindowSequenceId; + + void update(); + void platHangUpPhone(); +}; + +class Scene18: public Scene { +public: + Scene18(GnapEngine *vm); + virtual ~Scene18(); + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + Graphics::Surface *_cowboyHatSurface; + + int _platPhoneCtr; + int _platPhoneIter; + int _nextPhoneSequenceId; + int _currPhoneSequenceId; + + void gnapCarryGarbageCanTo(int a5); + void putDownGarbageCan(int animationIndex); + void platEndPhoning(bool platFl); + void closeHydrantValve(); + void waitForGnapAction(); +}; + +class Scene19: public Scene { +public: + Scene19(GnapEngine *vm); + virtual ~Scene19(); + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currShopAssistantSequenceId; + int _nextShopAssistantSequenceId; + int _toyGrabCtr; + int _shopAssistantCtr; + + Graphics::Surface *_pictureSurface; +}; + +} // End of namespace Gnap + +#endif // GNAP_GROUP1_H diff --git a/engines/gnap/scenes/group2.cpp b/engines/gnap/scenes/group2.cpp new file mode 100644 index 0000000000..020b3d151c --- /dev/null +++ b/engines/gnap/scenes/group2.cpp @@ -0,0 +1,3418 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/group2.h" + +namespace Gnap { + +Scene20::Scene20(GnapEngine *vm) : Scene(vm) { + _stonerGuyCtr = 3; + _stonerGuyShowingJoint = false; + _groceryStoreGuyCtr = 0; +} + +int Scene20::init() { + return 0x186; +} + +void Scene20::updateHotspots() { + _vm->setHotspot(kHS20Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS20GroceryStoreHat, 114, 441, 174, 486, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 7); + _vm->setHotspot(kHS20ExitParkingLot, 0, 300, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7); + _vm->setHotspot(kHS20StonerGuy, 276, 290, 386, 450, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8); + _vm->setHotspot(kHS20GroceryStoreGuy, 123, 282, 258, 462, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7); + _vm->setHotspot(kHS20ExitInsideGrubCity, 519, 250, 581, 413, SF_EXIT_L_CURSOR, 8, 7); + _vm->setHotspot(kHS20ExitOutsideCircusWorld, 660, 222, 798, 442, SF_EXIT_NE_CURSOR, 9, 6); + _vm->setHotspot(kHS20ExitOutsideToyStore, 785, 350, 800, 600, SF_EXIT_R_CURSOR, 11, 8); + _vm->setHotspot(kHS20ExitPhone, 250, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 10); + _vm->setHotspot(kHS20WalkArea1, 0, 0, 800, 468); + _vm->setHotspot(kHS20WalkArea2, 605, 0, 800, 600); + _vm->setDeviceHotspot(kHS20Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 12; +} + +void Scene20::updateAnimationsCb() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(2) == 2) { + switch (_nextStonerGuySequenceId) { + case 0x16B: + if (!_vm->_timers[4]) { + _stonerGuyShowingJoint = false; + gameSys.insertSequence(0x16B, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = 0x16B; + _nextStonerGuySequenceId = -1; + } + break; + case 0x16A: + // Grab joint + gnap.playPullOutDevice(Common::Point(4, 4)); + gnap.playUseDevice(); + gameSys.setAnimation(0x16A, 21, 0); + gameSys.insertSequence(0x16A, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = 0x16A; + _nextStonerGuySequenceId = -1; + _vm->invAdd(kItemJoint); + _vm->setFlag(kGFJointTaken); + _stonerGuyShowingJoint = false; + gnap._actionStatus = kAS20GrabJointDone; + break; + case 0x16E: + gameSys.setAnimation(0x16E, 21, 2); + gameSys.insertSequence(0x16E, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = 0x16E; + _nextStonerGuySequenceId = -1; + _nextGroceryStoreGuySequenceId = 0x175; + break; + case 0x16D: + gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2); + gameSys.setAnimation(_nextStonerGuySequenceId, 21, 0); + gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = _nextStonerGuySequenceId; + _nextStonerGuySequenceId = -1; + gnap._actionStatus = kAS20ActionDone; + break; + case 0x16F: + gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2); + gameSys.setAnimation(0x17A, 20, 3); + gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x17A, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currGroceryStoreGuySequenceId = 0x17A; + _nextGroceryStoreGuySequenceId = -1; + _currStonerGuySequenceId = _nextStonerGuySequenceId; + _nextStonerGuySequenceId = -1; + break; + case 0x171: + _stonerGuyCtr = (_stonerGuyCtr + 1) % 3; + switch (_stonerGuyCtr) { + case 1: + _nextStonerGuySequenceId = 0x171; + break; + case 2: + _nextStonerGuySequenceId = 0x172; + break; + case 3: + _nextStonerGuySequenceId = 0x173; + break; + default: + _nextStonerGuySequenceId = 0x171; + break; + } + gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x17C, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x17C, 20, 3); + gameSys.setAnimation(_nextStonerGuySequenceId, 21, 2); + _currGroceryStoreGuySequenceId = 0x17C; + _nextGroceryStoreGuySequenceId = -1; + _currStonerGuySequenceId = _nextStonerGuySequenceId; + _nextStonerGuySequenceId = -1; + break; + default: + _nextStonerGuySequenceId = 0x16C; + gameSys.setAnimation(0x16C, 21, 2); + gameSys.insertSequence(_nextStonerGuySequenceId, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = _nextStonerGuySequenceId; + _nextStonerGuySequenceId = -1; + break; + } + } +} + +void Scene20::stopSounds() { + _vm->stopSound(0x18E); + _vm->stopSound(0x18F); + _vm->stopSound(0x190); + _vm->stopSound(0x191); + _vm->stopSound(0x194); + _vm->stopSound(0x195); + _vm->stopSound(0x192); + _vm->stopSound(0x193); + _vm->stopSound(0x196); + _vm->stopSound(0x197); + _vm->stopSound(0x198); + _vm->stopSound(0x199); + _vm->stopSound(0x19A); +} + +void Scene20::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x10940, true); + _vm->startSoundTimerA(8); + + _stonerGuyShowingJoint = false; + _vm->_timers[7] = _vm->getRandom(100) + 100; + + _stonerGuyCtr = (_stonerGuyCtr + 1) % 3; + switch (_stonerGuyCtr) { + case 1: + _currStonerGuySequenceId = 0x171; + break; + case 2: + _currStonerGuySequenceId = 0x172; + break; + case 3: + _currStonerGuySequenceId = 0x173; + break; + } + + _nextStonerGuySequenceId = -1; + gameSys.setAnimation(_currStonerGuySequenceId, 21, 2); + gameSys.insertSequence(_currStonerGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[6] = _vm->getRandom(20) + 30; + + _currGroceryStoreGuySequenceId = 0x17C; + _nextGroceryStoreGuySequenceId = -1; + gameSys.setAnimation(0x17C, 20, 3); + gameSys.insertSequence(0x17C, 20, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[5] = _vm->getRandom(50) + 130; + if (_vm->isFlag(kGFGroceryStoreHatTaken)) + gameSys.insertSequence(0x17F, 20, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x174, 20, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFSceneFlag1)) { + _vm->clearFlag(kGFSceneFlag1); + _vm->endSceneInit(); + gameSys.setAnimation(0x182, 140, 0); + gameSys.insertSequence(0x182, 140, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + gnap.initPos(11, 8, kDirBottomLeft); + plat.initPos(11, 9, kDirIdleRight); + gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1); + } else { + switch (_vm->_prevSceneNum) { + case 17: + gnap.initPos(5, 11, kDirBottomRight); + plat.initPos(6, 11, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1); + break; + case 18: + gnap.initPos(11, 8, kDirBottomLeft); + plat.initPos(11, 9, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(6, 9), -1, 0x107C2, 1); + break; + case 21: + gnap.initPos(-1, 8, kDirBottomLeft); + plat.initPos(-1, 9, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1); + break; + case 22: + gnap.initPos(7, 6, kDirBottomRight); + plat.initPos(8, 6, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1); + break; + default: + gnap.initPos(8, 6, kDirBottomLeft); + plat.initPos(9, 6, kDirIdleRight); + _vm->endSceneInit(); + _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE; + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 9), -1, 0x107C2, 1); + _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE; + break; + } + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + _vm->testWalk(0, 1, 7, 9, 8, 9); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS20Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS20Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(20); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS20ExitParkingLot: + if (gnap._actionStatus < 0) { + if (_stonerGuyShowingJoint) + _vm->_timers[4] = 0; + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 21; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot], 0, 0x107AF, 1); + gnap._actionStatus = kAS20LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitParkingLot] + Common::Point(0, 1), -1, 0x107CF, 1); + plat._idleFacing = kDirIdleRight; + } + break; + + case kHS20ExitPhone: + if (gnap._actionStatus < 0) { + if (_stonerGuyShowingJoint) + _vm->_timers[4] = 0; + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 17; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone], 0, 0x107AE, 1); + gnap._actionStatus = kAS20LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitPhone] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS20ExitOutsideToyStore: + if (gnap._actionStatus < 0) { + if (_stonerGuyShowingJoint) + _vm->_timers[4] = 0; + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 18; + _vm->_hotspots[kHS20WalkArea2]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore], 0, 0x107AB, 1); + gnap._actionStatus = kAS20LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideToyStore] + Common::Point(0, 1), -1, 0x107CD, 1); + _vm->_hotspots[kHS20WalkArea2]._flags &= ~SF_WALKABLE; + } + break; + + case kHS20ExitInsideGrubCity: + if (gnap._actionStatus < 0) { + if (_stonerGuyShowingJoint) + _vm->_timers[4] = 0; + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 22; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(0, - 1), 0, 0x107BB, 1); + gnap._actionStatus = kAS20LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitInsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1); + plat._idleFacing = kDirIdleRight; + } + break; + + case kHS20ExitOutsideCircusWorld: + if (gnap._actionStatus < 0) { + if (_stonerGuyShowingJoint) + _vm->_timers[4] = 0; + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 24; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld], 0, 0x107BB, 1); + gnap._actionStatus = kAS20LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS20ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS20StonerGuy: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20StonerGuy], 5, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(Common::Point(5, 4)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + if (_stonerGuyShowingJoint) + gnap._actionStatus = kAS20GrabJoint; + else + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20StonerGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + if (_vm->isFlag(kGFJointTaken)) + gnap._actionStatus = kAS20TalkStonerGuyNoJoint; + else + gnap._actionStatus = kAS20TalkStonerGuyHasJoint; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS20GroceryStoreGuy: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 2, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(2, 3)); + break; + case GRAB_CURSOR: + _stonerGuyShowingJoint = false; + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS20GrabGroceryStoreGuy; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS20TalkGroceryStoreGuy; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS20GroceryStoreHat: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemCowboyHat) { + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS20SwitchGroceryStoreHat; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS20GroceryStoreHat], 1, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(1, 6)); + break; + case GRAB_CURSOR: + _stonerGuyShowingJoint = false; + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS20GroceryStoreGuy], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS20GrabGroceryStoreHat; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS20WalkArea1: + case kHS20WalkArea2: + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x10940)) + _vm->playSound(0x10940, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) { + _vm->_hotspots[kHS20WalkArea1]._rect.bottom += 48; + plat.updateIdleSequence(); + _vm->_hotspots[kHS20WalkArea1]._rect.bottom -= 48; + } + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (gnap._actionStatus < 0 && !_vm->_timers[5] && _nextGroceryStoreGuySequenceId == -1) { + _vm->_timers[5] = _vm->getRandom(50) + 130; + if (_vm->getRandom(4) != 0) + _nextGroceryStoreGuySequenceId = 0x17C; + else + _nextGroceryStoreGuySequenceId = 0x17A; + } + if (!_vm->_timers[7]) { + _vm->_timers[7] = _vm->getRandom(100) + 100; + if (gnap._actionStatus < 0 && plat._actionStatus < 0) { + switch (_vm->getRandom(3)) { + case 0: + gameSys.insertSequence(0x183, 253, 0, 0, kSeqNone, 0, 0, 0); + break; + case 1: + gameSys.insertSequence(0x184, 253, 0, 0, kSeqNone, 0, 0, 0); + break; + case 2: + gameSys.insertSequence(0x185, 253, 0, 0, kSeqNone, 0, 0, 0); + break; + } + } + } + _vm->playSoundA(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + _vm->gameUpdateTick(); + } +} + +void Scene20::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS20LeaveScene: + _vm->_sceneDone = true; + break; + case kAS20TalkStonerGuyNoJoint: + gameSys.setAnimation(0x170, 21, 2); + gameSys.setAnimation(0x17B, 20, 3); + gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0); + _vm->stopSound(0x1A1); + stopSounds(); + _currGroceryStoreGuySequenceId = 0x17B; + _currStonerGuySequenceId = 0x170; + _nextGroceryStoreGuySequenceId = -1; + _nextStonerGuySequenceId = 0x16E; + _vm->_timers[5] = 100; + _vm->_timers[6] = 100; + break; + case kAS20TalkStonerGuyHasJoint: + gameSys.setAnimation(0x168, 21, 2); + gameSys.setAnimation(379, 20, 3); + gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x168, 21, 0x170, 21, kSeqSyncWait, 0, 0, 0); + _vm->stopSound(0x1A1); + stopSounds(); + _currGroceryStoreGuySequenceId = 0x17B; + _currStonerGuySequenceId = 0x168; + _nextGroceryStoreGuySequenceId = -1; + _nextStonerGuySequenceId = 0x16B; + _vm->_timers[5] = 200; + _vm->_timers[6] = 200; + _vm->_timers[4] = 100; + _stonerGuyShowingJoint = true; + gnap._actionStatus = -1; + break; + case kAS20GrabJoint: + _nextStonerGuySequenceId = 0x16A; + break; + case kAS20ActionDone: + gnap._actionStatus = -1; + break; + case kAS20TalkGroceryStoreGuy: + gameSys.setAnimation(0x170, 21, 2); + gameSys.setAnimation(0x17B, 20, 3); + gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0); + _vm->stopSound(0x1A1); + stopSounds(); + _currGroceryStoreGuySequenceId = 0x17B; + _currStonerGuySequenceId = 0x170; + _groceryStoreGuyCtr = (_groceryStoreGuyCtr + 1) % 2; + if (_groceryStoreGuyCtr != 0) + _nextGroceryStoreGuySequenceId = 0x176; + else + _nextGroceryStoreGuySequenceId = 0x177; + _vm->_timers[5] = 100; + _vm->_timers[6] = 100; + break; + case kAS20GrabGroceryStoreGuy: + gameSys.setAnimation(0x170, 21, 2); + gameSys.setAnimation(0x17B, 20, 3); + gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0); + _vm->stopSound(0x1A1); + stopSounds(); + _currGroceryStoreGuySequenceId = 0x17B; + _currStonerGuySequenceId = 0x170; + _vm->_timers[5] = 120; + _vm->_timers[6] = 120; + _nextGroceryStoreGuySequenceId = 0x178; + break; + case kAS20GrabGroceryStoreHat: + gameSys.setAnimation(0x170, 21, 2); + gameSys.setAnimation(0x17B, 20, 3); + gameSys.insertSequence(0x17B, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x170, 21, _currStonerGuySequenceId, 21, kSeqSyncExists, 0, 0, 0); + _vm->stopSound(0x1A1); + stopSounds(); + _currGroceryStoreGuySequenceId = 0x17B; + _currStonerGuySequenceId = 0x170; + _nextGroceryStoreGuySequenceId = 0x179; + break; + case kAS20SwitchGroceryStoreHat: + _vm->setGrabCursorSprite(-1); + gameSys.setAnimation(0x180, gnap._id, 0); + gameSys.insertSequence(0x180, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x180; + gnap._sequenceDatNum = 0; + _vm->invRemove(kItemCowboyHat); + _vm->invAdd(kItemGroceryStoreHat); + gnap._actionStatus = kAS20SwitchGroceryStoreHatDone; + break; + case kAS20SwitchGroceryStoreHatDone: + gameSys.insertSequence(0x17F, 20, 372, 20, kSeqSyncWait, 0, 0, 0); + _vm->setFlag(kGFGroceryStoreHatTaken); + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + _vm->addFullScreenSprite(0x12C, 255); + gameSys.setAnimation(0x181, 256, 0); + gameSys.insertSequence(0x181, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->removeFullScreenSprite(); + _vm->showCursor(); + _vm->setGrabCursorSprite(kItemGroceryStoreHat); + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(Common::Point(3, 8), -1, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = -1; + break; + case kAS20GrabJointDone: + _vm->setGrabCursorSprite(kItemJoint); + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_nextGroceryStoreGuySequenceId) { + case 0x176: + case 0x177: + gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3); + gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId; + _nextGroceryStoreGuySequenceId = -1; + _nextStonerGuySequenceId = 0x16D; + break; + case 0x178: + gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3); + gameSys.setAnimation(0x17D, gnap._id, 0); + gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x17D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x17D; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS20ActionDone; + gameSys.setAnimation(0x16D, 21, 2); + gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = 0x16D; + _currGroceryStoreGuySequenceId = 0x178; + _nextGroceryStoreGuySequenceId = -1; + _nextStonerGuySequenceId = -1; + break; + case 0x179: + gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3); + gameSys.setAnimation(0x16D, 21, 0); + gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x17E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x17E; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS20ActionDone; + gameSys.setAnimation(0x16D, 21, 2); + gameSys.insertSequence(0x16D, 21, _currStonerGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currStonerGuySequenceId = 0x16D; + _currGroceryStoreGuySequenceId = 377; + _nextGroceryStoreGuySequenceId = -1; + _nextStonerGuySequenceId = -1; + gnap.walkTo(Common::Point(4, 8), -1, 0x107BB, 1); + break; + case 0x17C: + gameSys.setAnimation(0, 0, 3); + _nextStonerGuySequenceId = 0x171; + break; + case 0x17A: + gameSys.setAnimation(0, 0, 3); + _nextStonerGuySequenceId = 0x16F; + break; + case 0x175: + gameSys.setAnimation(0x175, 20, 0); + gameSys.setAnimation(0x175, 20, 3); + gameSys.insertSequence(0x175, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currGroceryStoreGuySequenceId = 0x175; + _nextGroceryStoreGuySequenceId = -1; + gnap._actionStatus = kAS20ActionDone; + break; + default: + if (_nextGroceryStoreGuySequenceId != -1) { + gameSys.setAnimation(_nextGroceryStoreGuySequenceId, 20, 3); + gameSys.insertSequence(_nextGroceryStoreGuySequenceId, 20, _currGroceryStoreGuySequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currGroceryStoreGuySequenceId = _nextGroceryStoreGuySequenceId; + _nextGroceryStoreGuySequenceId = -1; + } + break; + } + } + + updateAnimationsCb(); +} + +/*****************************************************************************/ + +Scene21::Scene21(GnapEngine *vm) : Scene(vm) { + _currOldLadySequenceId = -1; + _nextOldLadySequenceId = -1; +} + +int Scene21::init() { + _vm->_gameSys->setAnimation(0, 0, 3); + + return _vm->isFlag(kGFTwigTaken) ? 0x94 : 0x93; +} + +void Scene21::updateHotspots() { + _vm->setHotspot(kHS21Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS21Banana, 94, 394, 146, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 2, 6); + _vm->setHotspot(kHS21OldLady, 402, 220, 528, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7); + _vm->setHotspot(kHS21ExitOutsideGrubCity, 522, 498, 800, 600, SF_EXIT_SE_CURSOR | SF_WALKABLE, 5, 10); + _vm->setHotspot(kHS21WalkArea1, 0, 0, 800, 440); + _vm->setHotspot(kHS21WalkArea2, 698, 0, 800, 600); + _vm->setDeviceHotspot(kHS21Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFUnk04) || !_vm->isFlag(kGFTwigTaken)) + _vm->_hotspots[kHS21Banana]._flags = SF_WALKABLE | SF_DISABLED; + if (_vm->isFlag(kGFTwigTaken)) + _vm->_hotspots[kHS21OldLady]._flags = SF_DISABLED; + _vm->_hotspotsCount = 7; +} + +void Scene21::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x10940, true); + _vm->startSoundTimerA(6); + _vm->_timers[5] = _vm->getRandom(100) + 100; + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFTwigTaken)) { + if (_vm->isFlag(kGFKeysTaken)) { + gnap.initPos(5, 8, kDirBottomRight); + plat.initPos(6, 8, kDirIdleLeft); + gameSys.insertSequence(0x8E, 2, 0, 0, kSeqNone, 0, 0, 0); + if (!_vm->isFlag(kGFUnk04)) + gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + _vm->clearFlag(kGFKeysTaken); + } else { + gnap.initPos(5, 11, kDirBottomRight); + plat.initPos(6, 11, kDirIdleLeft); + if (!_vm->isFlag(kGFUnk04)) + gameSys.insertSequence(0x8D, 59, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + } + } else { + gnap.initPos(5, 11, kDirBottomRight); + plat.initPos(6, 11, kDirIdleLeft); + _currOldLadySequenceId = 0x89; + gameSys.setAnimation(0x89, 79, 3); + gameSys.insertSequence(_currOldLadySequenceId, 79, 0, 0, kSeqNone, 0, 0, 0); + _nextOldLadySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(30) + 50; + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS21Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS21Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS21Banana: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 2, 5); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(2, 5)); + break; + case GRAB_CURSOR: + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS21Banana]) | 0x10000, 1); + gnap.playPullOutDevice(Common::Point(2, 5)); + gnap.playUseDevice(); + gnap._actionStatus = kAS21GrabBanana; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + break; + } + } + } + break; + + case kHS21OldLady: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemGroceryStoreHat) { + _vm->_newSceneNum = 47; + gnap.walkTo(Common::Point(4, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS21UseHatWithOldLady; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(4, 6), 7, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(7, 4)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpLeft; + _vm->_hotspots[kHS21WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(Common::Point(7, 6), 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS21GrabOldLady; + _vm->_hotspots[kHS21WalkArea1]._flags &= ~SF_WALKABLE; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS21OldLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS21TalkOldLady; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS21ExitOutsideGrubCity: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 20; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity], 0, 0x107B3, 1); + gnap._actionStatus = kAS21LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS21ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS21WalkArea1: + case kHS21WalkArea2: + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x10940)) + _vm->playSound(0x10940, true); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->isFlag(kGFTwigTaken) && !_vm->_timers[4] && _nextOldLadySequenceId == -1 && gnap._actionStatus == -1) { + _vm->_timers[4] = _vm->getRandom(30) + 50; + switch (_vm->getRandom(5)) { + case 0: + _nextOldLadySequenceId = 0x88; + break; + case 1: + _nextOldLadySequenceId = 0x8A; + break; + default: + _nextOldLadySequenceId = 0x89; + break; + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(100) + 100; + gameSys.insertSequence(0x92, 255, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundA(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene21::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS21TalkOldLady: + _nextOldLadySequenceId = 0x8B; + gnap._actionStatus = -1; + break; + case kAS21GrabBanana: + gameSys.setAnimation(0x8C, 59, 0); + gameSys.insertSequence(0x8C, 59, 141, 59, kSeqSyncWait, 0, 0, 0); + _vm->setFlag(kGFUnk04); + _vm->invAdd(kItemBanana); + updateHotspots(); + gnap._actionStatus = kAS21GrabBananaDone; + break; + case kAS21GrabBananaDone: + _vm->setGrabCursorSprite(kItemBanana); + gnap._actionStatus = -1; + break; + case kAS21GrabOldLady: + _vm->_timers[4] = _vm->getRandom(30) + 50; + _nextOldLadySequenceId = 0x87; + break; + case kAS21UseHatWithOldLady: + gameSys.setAnimation(0x8F, gnap._id, 0); + gameSys.insertSequence(0x8F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x8F; + gnap._actionStatus = kAS21UseHatWithOldLadyDone; + _vm->invAdd(kItemTickets); + _vm->invRemove(kItemGroceryStoreHat); + _vm->setGrabCursorSprite(-1); + break; + case kAS21UseHatWithOldLadyDone: + _nextOldLadySequenceId = 0x91; + break; + case kAS21LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextOldLadySequenceId != -1) { + if (_nextOldLadySequenceId == 0x87) { + gameSys.setAnimation(_nextOldLadySequenceId, 79, 3); + gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x86, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x86; + gnap._sequenceDatNum = 0; + gnap._actionStatus = -1; + _currOldLadySequenceId = _nextOldLadySequenceId; + _nextOldLadySequenceId = -1; + } else if (_nextOldLadySequenceId == 0x91) { + gameSys.setAnimation(0x91, 79, 0); + gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS21LeaveScene; + _currOldLadySequenceId = _nextOldLadySequenceId; + _nextOldLadySequenceId = -1; + } else { + gameSys.setAnimation(_nextOldLadySequenceId, 79, 3); + gameSys.insertSequence(_nextOldLadySequenceId, 79, _currOldLadySequenceId, 79, kSeqSyncWait, 0, 0, 0); + _currOldLadySequenceId = _nextOldLadySequenceId; + _nextOldLadySequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene22::Scene22(GnapEngine *vm) : Scene(vm) { + _caughtBefore = false; + _cashierCtr = 3; +} + +int Scene22::init() { + return 0x5E; +} + +void Scene22::updateHotspots() { + _vm->setHotspot(kHS22Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS22ExitOutsideGrubCity, 0, 180, 184, 472, SF_EXIT_L_CURSOR, 3, 6); + _vm->setHotspot(kHS22ExitBackGrubCity, 785, 405, 800, 585, SF_EXIT_R_CURSOR, 11, 9); + _vm->setHotspot(kHS22Cashier, 578, 230, 660, 376, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8); + _vm->setHotspot(kHS22WalkArea1, 553, 0, 800, 542); + _vm->setHotspot(kHS22WalkArea2, 0, 0, 552, 488); + _vm->setDeviceHotspot(kHS22Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 7; +} + +void Scene22::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + gameSys.insertSequence(0x5D, 254, 0, 0, kSeqNone, 0, 0, 0); + + _currCashierSequenceId = 0x59; + _nextCashierSequenceId = -1; + + gameSys.setAnimation(0x59, 1, 3); + gameSys.insertSequence(_currCashierSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[6] = _vm->getRandom(30) + 20; + + _vm->queueInsertDeviceIcon(); + + if (_vm->_prevSceneNum == 20) { + gnap.initPos(2, 8, kDirBottomRight); + plat.initPos(1, 8, kDirIdleLeft); + _vm->endSceneInit(); + } else { + gnap.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y, kDirBottomRight); + plat.initPos(11, _vm->_hotspotsWalkPos[kHS22ExitBackGrubCity].y + 1, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(9, 8), -1, 0x107C2, 1); + } + + if (_vm->isFlag(kGFSceneFlag1)) { + int storeDetectiveSeqId; + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemCereals); + if (_caughtBefore) { + switch (_vm->getRandom(3)) { + case 0: + storeDetectiveSeqId = 0x55; + break; + case 1: + storeDetectiveSeqId = 0x56; + break; + default: + storeDetectiveSeqId = 0x57; + break; + } + } else { + _caughtBefore = true; + storeDetectiveSeqId = 0x54; + } + gameSys.waitForUpdate(); + gameSys.requestClear1(); + gameSys.drawSpriteToBackground(0, 0, 0x44); + gameSys.setAnimation(storeDetectiveSeqId, 256, 4); + gameSys.insertSequence(storeDetectiveSeqId, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(4) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + _vm->_sceneDone = true; + _vm->_newSceneNum = 20; + _caughtBefore = true; + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS22Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS22Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS22ExitOutsideGrubCity: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 20; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity], 0, 0x107AF, 1); + gnap._actionStatus = kAS22LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitOutsideGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1); + } + break; + + case kHS22ExitBackGrubCity: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 23; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity], 0, 0x107AB, 1); + gnap._actionStatus = kAS22LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS22ExitBackGrubCity] + Common::Point(0, 1), -1, 0x107C2, 1); + } + break; + + case kHS22Cashier: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS22Cashier], 8, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(8, 4)); + break; + case GRAB_CURSOR: + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS22Cashier], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS22TalkCashier; + break; + case PLAT_CURSOR: + gnap.useDeviceOnPlatypus(); + break; + } + } + } + break; + + case kHS22WalkArea1: + case kHS22WalkArea2: + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[6] && _nextCashierSequenceId == -1) { + _vm->_timers[6] = _vm->getRandom(30) + 20; + if (_vm->getRandom(8) != 0) { + _nextCashierSequenceId = 0x59; + } else { + _cashierCtr = (_cashierCtr + 1) % 3; + switch (_cashierCtr) { + case 1: + _nextCashierSequenceId = 0x58; + break; + case 2: + _nextCashierSequenceId = 0x5A; + break; + case 3: + _nextCashierSequenceId = 0x5B; + break; + default: + _nextCashierSequenceId = 0x58; + break; + } + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = 400; + _vm->_timers[1] = _vm->getRandom(20) + 30; + _vm->_timers[0] = _vm->getRandom(75) + 75; + } + + _vm->gameUpdateTick(); + } +} + +void Scene22::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS22LeaveScene: + _vm->_sceneDone = true; + break; + case kAS22TalkCashier: + _nextCashierSequenceId = 0x5C; + break; + } + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextCashierSequenceId != -1) { + gameSys.setAnimation(_nextCashierSequenceId, 1, 3); + gameSys.insertSequence(_nextCashierSequenceId, 1, _currCashierSequenceId, 1, kSeqSyncWait, 0, 0, 0); + _currCashierSequenceId = _nextCashierSequenceId; + _nextCashierSequenceId = -1; + } +} + +/*****************************************************************************/ + +Scene23::Scene23(GnapEngine *vm) : Scene(vm) { + _currStoreClerkSequenceId = -1; + _nextStoreClerkSequenceId = -1; +} + +int Scene23::init() { + return 0xC0; +} + +void Scene23::updateHotspots() { + _vm->setHotspot(kHS23Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS23ExitFrontGrubCity, 0, 250, 15, 550, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 7); + _vm->setHotspot(kHS23Cereals, 366, 332, 414, 408, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 7); + _vm->setHotspot(kHS23WalkArea1, 0, 0, 340, 460); + _vm->setHotspot(kHS23WalkArea2, 340, 0, 800, 501); + _vm->setDeviceHotspot(kHS23Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 6; +} + +void Scene23::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->_timers[4] = _vm->getRandom(100) + 200; + _vm->_timers[5] = _vm->getRandom(100) + 200; + + _currStoreClerkSequenceId = 0xB4; + _nextStoreClerkSequenceId = -1; + + gameSys.setAnimation(0xB4, 1, 4); + gameSys.insertSequence(_currStoreClerkSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + _vm->queueInsertDeviceIcon(); + + gnap.initPos(-1, 7, kDirBottomRight); + plat.initPos(-2, 7, kDirIdleLeft); + gameSys.insertSequence(0xBD, 255, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0xBF, 2, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + + plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1); + + if (_vm->isFlag(kGFUnk24)) { + gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1); + } else { + gnap.walkTo(Common::Point(2, 7), 0, 0x107B9, 1); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + _vm->playSequences(0x48, 0xBA, 0xBB, 0xBC); + _vm->setFlag(kGFUnk24); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 3, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS23Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS23Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS23Cereals: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS23Cereals], 5, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFSceneFlag1)) + gnap.playMoan2(); + else { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS23LookCereals; + } + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFSceneFlag1)) + gnap.playImpossible(); + else { + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS23Cereals], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + _vm->setFlag(kGFSceneFlag1); + gnap._actionStatus = kAS23GrabCereals; + _vm->invAdd(kItemCereals); + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS23ExitFrontGrubCity: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 22; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity], 0, 0x107AF, 1); + gnap._actionStatus = kAS23LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS23ExitFrontGrubCity] + Common::Point(0, -1), -1, 0x107C2, 1); + } + break; + + case kHS23WalkArea1: + case kHS23WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4] && gnap._actionStatus == -1) { + _vm->_timers[4] = _vm->getRandom(100) + 200; + switch (_vm->getRandom(4)) { + case 0: + gameSys.insertSequence(0xB7, 256, 0, 0, kSeqNone, 0, 0, 0); + break; + case 1: + gameSys.insertSequence(0xB8, 256, 0, 0, kSeqNone, 0, 0, 0); + break; + case 2: + case 3: + gameSys.insertSequence(0xB9, 256, 0, 0, kSeqNone, 0, 0, 0); + break; + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(100) + 200; + switch (_vm->getRandom(3)) { + case 0: + _vm->playSound(0xCE, false); + break; + case 1: + _vm->playSound(0xD0, false); + break; + case 2: + _vm->playSound(0xCF, false); + break; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene23::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS23LookCereals: + _vm->showFullScreenSprite(0x48); + gnap._actionStatus = -1; + break; + case kAS23GrabCereals: + gameSys.setAnimation(0xBE, gnap._id, 0); + gameSys.insertSequence(0xBE, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.requestRemoveSequence(0xBF, 2); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0xBE; + gnap._actionStatus = kAS23GrabCerealsDone; + break; + case kAS23GrabCerealsDone: + _vm->setGrabCursorSprite(kItemCereals); + gnap._actionStatus = -1; + break; + case kAS23LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(4) == 2 && _nextStoreClerkSequenceId == -1) { + switch (_vm->getRandom(8)) { + case 0: + case 1: + case 2: + _nextStoreClerkSequenceId = 0xB4; + break; + case 3: + case 4: + case 5: + _nextStoreClerkSequenceId = 0xB5; + break; + default: + _nextStoreClerkSequenceId = 0xB6; + break; + } + gameSys.setAnimation(_nextStoreClerkSequenceId, 1, 4); + gameSys.insertSequence(_nextStoreClerkSequenceId, 1, _currStoreClerkSequenceId, 1, kSeqSyncWait, 0, 0, 0); + _currStoreClerkSequenceId = _nextStoreClerkSequenceId; + _nextStoreClerkSequenceId = -1; + } +} + +/*****************************************************************************/ + +Scene24::Scene24(GnapEngine *vm) : Scene(vm) { + _currWomanSequenceId = -1; + _nextWomanSequenceId = -1; + _boySequenceId = -1; + _girlSequenceId = -1; +} + +int Scene24::init() { + return 0x3B; +} + +void Scene24::updateHotspots() { + _vm->setHotspot(kHS24Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS24ExitCircusWorld, 785, 128, 800, 600, SF_EXIT_R_CURSOR, 8, 7); + _vm->setHotspot(kHS24ExitOutsideGrubCity, 0, 213, 91, 600, SF_EXIT_NW_CURSOR, 1, 8); + _vm->setHotspot(kHS24WalkArea1, 0, 0, 0, 0); + _vm->setHotspot(kHS24WalkArea2, 530, 0, 800, 600); + _vm->setHotspot(kHS24WalkArea3, 0, 0, 800, 517); + _vm->setDeviceHotspot(kHS24Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 7; +} + +void Scene24::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + int counter = 0; + + _vm->playSound(0x10940, true); + _vm->startSoundTimerA(9); + + _vm->_timers[7] = _vm->getRandom(100) + 100; + + gameSys.insertSequence(0x2F, 256, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[4] = _vm->getRandom(20) + 50; + _vm->_timers[5] = _vm->getRandom(20) + 40; + _vm->_timers[6] = _vm->getRandom(50) + 30; + + gameSys.insertSequence(0x36, 20, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x30, 20, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x35, 20, 0, 0, kSeqNone, 0, 0, 0); + + _currWomanSequenceId = 0x35; + _girlSequenceId = 0x36; + _boySequenceId = 0x30; + + _vm->queueInsertDeviceIcon(); + + if (_vm->_prevSceneNum == 20) { + gnap.initPos(1, 8, kDirBottomRight); + plat.initPos(2, 8, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(1, 9), -1, 0x107B9, 1); + plat.walkTo(Common::Point(2, 9), -1, 0x107C2, 1); + } else { + gnap.initPos(8, 8, kDirBottomLeft); + plat.initPos(8, 8, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(2, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(3, 8), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + + case kHS24Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS24Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS24ExitCircusWorld: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 25; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld], 0, 0x107AB, 1); + gnap._actionStatus = kAS24LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS24ExitOutsideGrubCity: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 20; + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS24LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS24ExitOutsideGrubCity] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS24WalkArea1: + case kHS24WalkArea2: + case kHS24WalkArea3: + if (gnap._actionStatus == -1) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x10940)) + _vm->playSound(0x10940, true); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 50; + gameSys.insertSequence(0x37, 20, _girlSequenceId, 20, kSeqSyncWait, 0, 0, 0); + _girlSequenceId = 0x37; + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(20) + 40; + gameSys.insertSequence(0x31, 20, _boySequenceId, 20, kSeqSyncWait, 0, 0, 0); + _boySequenceId = 0x31; + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(50) + 30; + counter = (counter + 1) % 3; + switch (counter) { + case 0: + _nextWomanSequenceId = 0x32; + break; + case 1: + _nextWomanSequenceId = 0x33; + break; + case 2: + _nextWomanSequenceId = 0x34; + break; + } + gameSys.insertSequence(_nextWomanSequenceId, 20, _currWomanSequenceId, 20, kSeqSyncWait, 0, 0, 0); + _currWomanSequenceId = _nextWomanSequenceId; + } + if (!_vm->_timers[7]) { + _vm->_timers[7] = _vm->getRandom(100) + 100; + switch (_vm->getRandom(3)) { + case 0: + gameSys.insertSequence(0x38, 253, 0, 0, kSeqNone, 0, 0, 0); + break; + case 1: + gameSys.insertSequence(0x39, 253, 0, 0, kSeqNone, 0, 0, 0); + break; + case 2: + gameSys.insertSequence(0x3A, 253, 0, 0, kSeqNone, 0, 0, 0); + break; + } + } + _vm->playSoundA(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + _vm->gameUpdateTick(); + } +} + +void Scene24::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + if (gnap._actionStatus == kAS24LeaveScene) + _vm->_sceneDone = true; + gnap._actionStatus = -1; + } +} + +/*****************************************************************************/ + +Scene25::Scene25(GnapEngine *vm) : Scene(vm) { + _currTicketVendorSequenceId = -1; + _nextTicketVendorSequenceId = -1; +} + +int Scene25::init() { + return 0x62; +} + +void Scene25::updateHotspots() { + _vm->setHotspot(kHS25Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS25TicketVendor, 416, 94, 574, 324, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 5); + _vm->setHotspot(kHS25ExitOutsideCircusWorld, 0, 519, 205, 600, SF_EXIT_SW_CURSOR, 5, 10); + _vm->setHotspot(kHS25ExitInsideCircusWorld, 321, 70, 388, 350, SF_EXIT_NE_CURSOR, 3, 6); + _vm->setHotspot(kHS25Posters1, 0, 170, 106, 326, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7); + _vm->setHotspot(kHS25Posters2, 146, 192, 254, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 7); + _vm->setHotspot(kHS25Posters3, 606, 162, 654, 368, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 7); + _vm->setHotspot(kHS25Posters4, 708, 114, 754, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8); + _vm->setHotspot(kHS25WalkArea1, 0, 0, 800, 439); + _vm->setHotspot(kHS25WalkArea2, 585, 0, 800, 600); + _vm->setDeviceHotspot(kHS25Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 11; +} + +void Scene25::playAnims(int index) { + if (index > 4) + return; + + GameSys& gameSys = *_vm->_gameSys; + + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + switch (index) { + case 1: + _vm->_largeSprite = gameSys.createSurface(0x25); + break; + case 2: + _vm->_largeSprite = gameSys.createSurface(0x26); + break; + case 3: + _vm->_largeSprite = gameSys.createSurface(0x27); + break; + case 4: + _vm->_largeSprite = gameSys.createSurface(0x28); + break; + } + gameSys.insertSpriteDrawItem(_vm->_largeSprite, 0, 0, 300); + _vm->delayTicksCursor(5); + while (!_vm->_mouseClickState._left && !_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) && !_vm->isKeyStatus1(Common::KEYCODE_SPACE) && + !_vm->isKeyStatus1(Common::KEYCODE_RETURN) && !_vm->_gameDone) { + _vm->gameUpdateTick(); + } + _vm->_mouseClickState._left = false; + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_RETURN); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + gameSys.removeSpriteDrawItem(_vm->_largeSprite, 300); + _vm->delayTicksCursor(5); + _vm->deleteSurface(&_vm->_largeSprite); + _vm->showCursor(); +} + +void Scene25::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x10940, true); + _vm->startSoundTimerA(5); + + _currTicketVendorSequenceId = 0x52; + gameSys.setAnimation(0x52, 39, 3); + gameSys.insertSequence(_currTicketVendorSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0); + + _nextTicketVendorSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(20) + 20; + + _vm->queueInsertDeviceIcon(); + + if (_vm->_prevSceneNum == 24) { + gnap.initPos(5, 11, kDirUpLeft); + plat.initPos(6, 11, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 7), -1, 0x107BA, 1); + plat.walkTo(Common::Point(6, 7), -1, 0x107C2, 1); + } else { + gnap.initPos(5, 6, kDirBottomRight); + plat.initPos(6, 6, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS25Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS25Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS25TicketVendor: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemTickets) { + gnap._actionStatus = kAS25ShowTicketToVendor; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSIdle, Common::Point(9, 4)) | 0x10000, 1); + gnap.playPullOutDevice(); + gnap.playUseDevice(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS25TicketVendor], 6, 1); + _nextTicketVendorSequenceId = 0x5B; + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 1)); + _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x59 : 0x56; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS25TicketVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS25TalkTicketVendor; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS25ExitOutsideCircusWorld: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 24; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld], 0, 0x107B4, 1); + gnap._actionStatus = kAS25LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitOutsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS25ExitInsideCircusWorld: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFNeedleTaken)) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 26; + _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld], 0, 0x107B1, 1); + gnap._actionStatus = kAS25LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS25ExitInsideCircusWorld] + Common::Point(1, 0), -1, 0x107C2, 1); + _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE; + } else { + _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(Common::Point(4, 5), 0, 0x107BB, 1); + gnap._actionStatus = kAS25EnterCircusWihoutTicket; + _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE; + } + } + break; + + case kHS25Posters1: + case kHS25Posters2: + case kHS25Posters3: + case kHS25Posters4: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[_vm->_sceneClickedHotspot], -1, -1, 1); + if (_vm->_sceneClickedHotspot == 5 || _vm->_sceneClickedHotspot == 6) + gnap._idleFacing = kDirUpLeft; + else if (_vm->_sceneClickedHotspot == 8) + gnap._idleFacing = kDirBottomRight; + else + gnap._idleFacing = kDirUpRight; + gnap.playIdle(); + playAnims(8 - _vm->_sceneClickedHotspot + 1); + break; + case GRAB_CURSOR: + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playMoan2(); + break; + } + } + } + break; + + case kHS25WalkArea1: + case kHS25WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4] && _nextTicketVendorSequenceId == -1 && gnap._actionStatus == -1) { + _vm->_timers[4] = _vm->getRandom(20) + 20; + switch (_vm->getRandom(13)) { + case 0: + _nextTicketVendorSequenceId = 0x54; + break; + case 1: + _nextTicketVendorSequenceId = 0x58; + break; + case 2: + _nextTicketVendorSequenceId = 0x55; + break; + case 3: + _nextTicketVendorSequenceId = 0x5A; + break; + case 4: + case 5: + case 6: + case 7: + _nextTicketVendorSequenceId = 0x5B; + break; + case 8: + case 9: + case 10: + case 11: + _nextTicketVendorSequenceId = 0x5C; + break; + case 12: + _nextTicketVendorSequenceId = 0x5D; + break; + default: + _nextTicketVendorSequenceId = 0x52; + break; + } + } + _vm->playSoundA(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene25::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS25TalkTicketVendor: + _nextTicketVendorSequenceId = (_vm->getRandom(2) == 1) ? 0x57 : 0x5F; + gnap._actionStatus = -1; + break; + case kAS25EnterCircusWihoutTicket: + _nextTicketVendorSequenceId = 0x5E; + gameSys.setAnimation(0x5E, 39, 0); + gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3); + gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncExists, 0, 0, 0); + gameSys.insertSequence(0x60, 2, 0, 0, kSeqNone, 0, 0, 0); + _currTicketVendorSequenceId = _nextTicketVendorSequenceId; + _nextTicketVendorSequenceId = -1; + _vm->_hotspots[kHS25WalkArea1]._flags |= SF_WALKABLE; + gnap.playIdle(); + gnap.walkTo(_vm->_hotspotsWalkPos[3], -1, 0x107BB, 1); + _vm->_hotspots[kHS25WalkArea1]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS25EnterCircusWihoutTicketDone; + break; + case kAS25EnterCircusWihoutTicketDone: + gnap._actionStatus = -1; + break; + case kAS25ShowTicketToVendor: + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemTickets); + _vm->setFlag(kGFNeedleTaken); + gameSys.setAnimation(0x61, 40, 0); + gameSys.insertSequence(0x61, 40, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = kAS25ShowTicketToVendorDone; + break; + case kAS25ShowTicketToVendorDone: + _nextTicketVendorSequenceId = 0x53; + break; + case kAS25LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + if (_nextTicketVendorSequenceId == 0x53) { + gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0); + _currTicketVendorSequenceId = _nextTicketVendorSequenceId; + _nextTicketVendorSequenceId = -1; + gnap._actionStatus = -1; + } else if (_nextTicketVendorSequenceId != -1) { + gameSys.setAnimation(_nextTicketVendorSequenceId, 39, 3); + gameSys.insertSequence(_nextTicketVendorSequenceId, 39, _currTicketVendorSequenceId, 39, kSeqSyncWait, 0, 0, 0); + _currTicketVendorSequenceId = _nextTicketVendorSequenceId; + _nextTicketVendorSequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene26::Scene26(GnapEngine *vm) : Scene(vm) { + _currKidSequenceId = -1; + _nextKidSequenceId = -1; +} + +int Scene26::init() { + return _vm->isFlag(kGFUnk23) ? 0x61 : 0x60; +} + +void Scene26::updateHotspots() { + _vm->setHotspot(kHS26Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS26ExitOutsideCircusWorld, 0, 590, 300, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 1, 10); + _vm->setHotspot(kHS26ExitOutsideClown, 200, 265, 265, 350, SF_EXIT_U_CURSOR, 3, 8); + _vm->setHotspot(kHS26ExitArcade, 0, 295, 150, 400, SF_EXIT_NW_CURSOR, 2, 8); + _vm->setHotspot(kHS26ExitElephant, 270, 290, 485, 375, SF_EXIT_U_CURSOR, 5, 8); + _vm->setHotspot(kHS26ExitBeerStand, 530, 290, 620, 350, SF_EXIT_NE_CURSOR, 5, 8); + _vm->setHotspot(kHS26WalkArea1, 0, 0, 800, 500); + _vm->setHotspot(kHS26WalkArea2, 281, 0, 800, 600); + _vm->setDeviceHotspot(kHS26Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 9; +} + +void Scene26::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->startSoundTimerB(7); + _vm->playSound(0x1093B, true); + + _currKidSequenceId = 0x5B; + _nextKidSequenceId = -1; + gameSys.setAnimation(0x5B, 160, 3); + gameSys.insertSequence(_currKidSequenceId, 160, 0, 0, kSeqNone, 0, 0, 0); + + _vm->_timers[5] = _vm->getRandom(20) + 50; + _vm->_timers[4] = _vm->getRandom(20) + 50; + _vm->_timers[6] = _vm->getRandom(50) + 100; + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(0x58, 40, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x5C, 40, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x5D, 40, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0x5E, 40, 0, 0, kSeqLoop, 0, 0, 0); + + if (_vm->_prevSceneNum == 25) { + gnap.initPos(-1, 8, kDirBottomRight); + plat.initPos(-2, 8, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + } else { + gnap.initPos(2, 8, kDirBottomRight); + plat.initPos(3, 8, kDirIdleLeft); + _vm->endSceneInit(); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS26Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS26Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS26ExitOutsideCircusWorld: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 25; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideCircusWorld].y), 0, 0x107AE, 1); + gnap._actionStatus = kAS26LeaveScene; + } + break; + + case kHS26ExitOutsideClown: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 27; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitOutsideClown].y), 0, 0x107BC, 1); + gnap._actionStatus = kAS26LeaveScene; + } + break; + + case kHS26ExitArcade: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 29; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitArcade].y), 0, 0x107BC, 1); + gnap._actionStatus = kAS26LeaveScene; + } + break; + + case kHS26ExitElephant: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 30; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitElephant].y), 0, 0x107BC, 1); + gnap._actionStatus = kAS26LeaveScene; + } + break; + + case kHS26ExitBeerStand: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 31; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS26ExitBeerStand].y), 0, 0x107BB, 1); + gnap._actionStatus = kAS26LeaveScene; + } + break; + + case kHS26WalkArea1: + case kHS26WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1093B)) + _vm->playSound(0x1093B, true); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[5] && _nextKidSequenceId == -1) { + _vm->_timers[5] = _vm->getRandom(20) + 50; + if (_vm->getRandom(5) != 0) + _nextKidSequenceId = 0x5B; + else + _nextKidSequenceId = 0x5A; + } + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 130; + gameSys.insertSequence(0x59, 40, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[6]) { + _vm->_timers[6] = _vm->getRandom(50) + 100; + gameSys.insertSequence(0x5F, 40, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundB(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene26::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + if (gnap._actionStatus == kAS26LeaveScene) + _vm->_sceneDone = true; + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextKidSequenceId != -1) { + gameSys.insertSequence(_nextKidSequenceId, 160, _currKidSequenceId, 160, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextKidSequenceId, 160, 3); + _currKidSequenceId = _nextKidSequenceId; + _nextKidSequenceId = -1; + } +} + +/*****************************************************************************/ + +Scene27::Scene27(GnapEngine *vm) : Scene(vm) { + _nextJanitorSequenceId = -1; + _currJanitorSequenceId = -1; +} + +int Scene27::init() { + return 0xD5; +} + +void Scene27::updateHotspots() { + _vm->setHotspot(kHS27Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS27Janitor, 488, 204, 664, 450, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 8); + _vm->setHotspot(kHS27Bucket, 129, 406, 186, 453, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 6); + _vm->setHotspot(kHS27ExitCircus, 200, 585, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS27ExitArcade, 0, 0, 15, 600, SF_EXIT_L_CURSOR, 0, 6); + _vm->setHotspot(kHS27ExitBeerStand, 785, 0, 800, 600, SF_EXIT_R_CURSOR, 11, 7); + _vm->setHotspot(kHS27ExitClown, 340, 240, 460, 420, SF_EXIT_U_CURSOR, 6, 8); + _vm->setHotspot(kHS27WalkArea1, 0, 0, 800, 507); + _vm->setDeviceHotspot(kHS27Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFUnk13)) + _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED; + _vm->_hotspotsCount = 9; +} + +void Scene27::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1093B, true); + _vm->startSoundTimerB(4); + _vm->_timers[7] = _vm->getRandom(100) + 300; + _vm->queueInsertDeviceIcon(); + + if (!_vm->isFlag(kGFUnk13)) + gameSys.insertSequence(0xD3, 39, 0, 0, kSeqNone, 0, 0, 0); + + gameSys.insertSequence(0xCB, 39, 0, 0, kSeqNone, 0, 0, 0); + + _currJanitorSequenceId = 0xCB; + _nextJanitorSequenceId = -1; + + gameSys.setAnimation(0xCB, 39, 3); + _vm->_timers[5] = _vm->getRandom(20) + 60; + + switch (_vm->_prevSceneNum) { + case 26: + gnap.initPos(7, 12, kDirBottomRight); + plat.initPos(6, 12, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + break; + case 29: + gnap.initPos(-1, 8, kDirBottomRight); + plat.initPos(-1, 9, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(3, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(3, 9), -1, 0x107C2, 1); + break; + case 31: + gnap.initPos(12, 8, kDirBottomLeft); + plat.initPos(12, 9, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(8, 9), -1, 0x107C2, 1); + break; + default: + gnap.initPos(6, 8, kDirBottomRight); + plat.initPos(5, 9, kDirIdleLeft); + _vm->endSceneInit(); + break; + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + _vm->_sceneClickedHotspot = -1; + if (gnap._actionStatus < 0) + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS27Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS27Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS27Janitor: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemPicture) { + gnap._idleFacing = kDirUpLeft; + if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, 0x107BC, 1)) + gnap._actionStatus = kAS27ShowPictureToJanitor; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS27Janitor], 7, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 3)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS27Janitor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS27TalkJanitor; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS27Bucket: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 3, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(3, 3)); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS27Bucket]) | 0x10000, 1); + gnap._actionStatus = kAS27GrabBucket; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS27ExitCircus: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 26; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitCircus].y), 0, 0x107AE, 1); + gnap._actionStatus = kAS27LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitCircus] + Common::Point(1, 0), -1, 0x107C7, 1); + } + break; + + case kHS27ExitArcade: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 29; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitArcade].y), 0, 0x107AF, 1); + gnap._actionStatus = kAS27LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitArcade] + Common::Point(0, 1), -1, 0x107CF, 1); + } + break; + + case kHS27ExitBeerStand: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 31; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS27ExitBeerStand].y), 0, 0x107AB, 1); + gnap._actionStatus = kAS27LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitBeerStand] + Common::Point(0, 1), -1, 0x107CD, 1); + } + break; + + case kHS27ExitClown: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFPlatypus)) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 28; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown], 0, 0x107AD, 1); + gnap._actionStatus = kAS27LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS27ExitClown] + Common::Point(1, 0), -1, 0x107C4, 1); + } else { + _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS27ExitClown].x, 7), 0, 0x107BC, 1); + _vm->_hotspots[kHS27WalkArea1]._flags &= SF_WALKABLE; + gnap._actionStatus = kAS27TryEnterClownTent; + } + } + break; + + case kHS27WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1093B)) + _vm->playSound(0x1093B, true); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(20) + 60; + if (gnap._actionStatus < 0) { + if (_vm->getRandom(3) != 0) + _nextJanitorSequenceId = 0xCB; + else + _nextJanitorSequenceId = 0xCF; + } + } + if (!_vm->_timers[7]) { + _vm->_timers[7] = _vm->getRandom(100) + 300; + if (gnap._actionStatus < 0) + gameSys.insertSequence(0xD4, 120, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundB(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene27::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS27TalkJanitor: + switch (_vm->getRandom(3)) { + case 0: + _nextJanitorSequenceId = 0xCC; + break; + case 1: + _nextJanitorSequenceId = 0xCD; + break; + case 2: + _nextJanitorSequenceId = 0xCE; + break; + } + break; + case kAS27GrabBucket: + gnap.playPullOutDevice(); + gnap.playUseDevice(); + _vm->_hotspots[kHS27Bucket]._flags = SF_DISABLED; + _vm->invAdd(kItemEmptyBucket); + _vm->setFlag(kGFUnk13); + gameSys.setAnimation(0xD2, 39, 0); + gameSys.insertSequence(0xD2, 39, 211, 39, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS27GrabBucketDone; + break; + case kAS27GrabBucketDone: + _vm->setGrabCursorSprite(kItemEmptyBucket); + gnap._actionStatus = -1; + break; + case kAS27ShowPictureToJanitor: + _nextJanitorSequenceId = 0xD0; + break; + case kAS27TryEnterClownTent: + _nextJanitorSequenceId = 0xD1; + gameSys.insertSequence(0xD1, 39, _currJanitorSequenceId, 39, kSeqSyncExists, 0, 0, 0); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 3); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 0); + _currJanitorSequenceId = _nextJanitorSequenceId; + _nextJanitorSequenceId = -1; + gnap._actionStatus = kAS27TryEnterClownTentDone; + break; + case kAS27TryEnterClownTentDone: + _vm->_hotspots[kHS27WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[7].x, 9), -1, 0x107BC, 1); + _vm->_hotspots[kHS27WalkArea1]._flags &= ~SF_WALKABLE; + gnap._actionStatus = -1; + break; + case kAS27EnterClownTent: + gnap.walkTo(gnap._pos, 0, 0x107B2, 1); + gnap._actionStatus = kAS27LeaveScene; + break; + case kAS27LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_nextJanitorSequenceId) { + case -1: + _nextJanitorSequenceId = 0xCB; + gameSys.insertSequence(0xCB, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 3); + _currJanitorSequenceId = _nextJanitorSequenceId; + _nextJanitorSequenceId = -1; + break; + case 0xCC: + case 0xCD: + case 0xCE: + gnap._actionStatus = -1; + gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 3); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 0); + _currJanitorSequenceId = _nextJanitorSequenceId; + _nextJanitorSequenceId = -1; + break; + case 0xD0: + // Show picture to janitor + gnap.playPullOutDevice(); + gnap.playUseDevice(); + gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 0); + gnap._actionStatus = kAS27EnterClownTent; + _currJanitorSequenceId = _nextJanitorSequenceId; + _nextJanitorSequenceId = -1; + _vm->setFlag(kGFPlatypus); + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemPicture); + _vm->_newSceneNum = 28; + break; + default: + gameSys.insertSequence(_nextJanitorSequenceId, 39, _currJanitorSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextJanitorSequenceId, 39, 3); + _currJanitorSequenceId = _nextJanitorSequenceId; + _nextJanitorSequenceId = -1; + break; + } + } +} + +/*****************************************************************************/ + +Scene28::Scene28(GnapEngine *vm) : Scene(vm) { + _currClownSequenceId = -1; + _nextClownSequenceId = -1; + _clownTalkCtr = 0; +} + +int Scene28::init() { + return 0x125; +} + +void Scene28::updateHotspots() { + _vm->setHotspot(kHS28Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS28Horn, 148, 352, 215, 383, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 1, 7); + _vm->setHotspot(kHS28Clown, 130, 250, 285, 413, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 5); + _vm->setHotspot(kHS28ExitOutsideClown, 660, 190, 799, 400, SF_EXIT_R_CURSOR, 9, 6); + _vm->setHotspot(kHS28EmptyBucket, 582, 421, 643, 478, SF_WALKABLE | SF_DISABLED, 9, 7); + _vm->setHotspot(kHS28WalkArea1, 0, 0, 799, 523); + _vm->setHotspot(kHS28WalkArea2, 0, 0, 0, 0, 7, SF_DISABLED); + _vm->setDeviceHotspot(kHS28Device, -1, -1, -1, -1); + if (_vm->invHas(kItemHorn)) + _vm->_hotspots[kHS28Horn]._flags = SF_DISABLED; + if (_vm->isFlag(kGFUnk22)) + _vm->_hotspots[kHS28EmptyBucket]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + _vm->_hotspotsCount = 8; +} + +void Scene28::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1093C, true); + _nextClownSequenceId = -1; + _vm->queueInsertDeviceIcon(); + gameSys.insertSequence(0x124, 255, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFUnk22)) + gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFMudTaken)) { + if (_vm->isFlag(kGFUnk21)) { + gameSys.setAnimation(0x11C, 39, 3); + gameSys.insertSequence(0x11C, 39, 0, 0, kSeqNone, 0, 0, 0); + if (!_vm->invHas(kItemHorn)) + gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, 0, 0, 0); + _currClownSequenceId = 0x11C; + } else { + _currClownSequenceId = 0x11B; + gameSys.setAnimation(0x11B, 39, 3); + gameSys.insertSequence(_currClownSequenceId, 39, 0, 0, kSeqNone, 0, 0, 0); + _vm->_timers[4] = _vm->getRandom(20) + 80; + } + gnap.initPos(8, 8, kDirBottomLeft); + plat.initPos(9, 8, kDirIdleRight); + _vm->endSceneInit(); + } else { + gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0); + gnap.initPos(8, 8, kDirBottomLeft); + plat.initPos(9, 8, kDirIdleRight); + _vm->endSceneInit(); + _vm->playSequences(0xF7, 0x121, 0x122, 0x123); + _currClownSequenceId = 0x115; + _vm->setFlag(kGFMudTaken); + gameSys.setAnimation(0x115, 39, 3); + gameSys.insertSequence(_currClownSequenceId, 39, 0x11B, 39, kSeqSyncWait, 0, 0, 0); + _nextClownSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(20) + 80; + gnap._actionStatus = kAS28GnapWaiting; + while (gameSys.getAnimationStatus(3) != 2 && !_vm->_gameDone) { + _vm->gameUpdateTick(); + _vm->updateMouseCursor(); + } + gnap._actionStatus = -1; + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS28Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS28Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS28Horn: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(2, 8), 3, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(2, 4)); + break; + case GRAB_CURSOR: + if (_vm->isFlag(kGFUnk21)) { + if (!_vm->invHas(kItemHorn)) { + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28Horn]) | 0x10000, 1); + gnap._actionStatus = kAS28GrabHornSuccess; + } + } else { + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(Common::Point(2, 8), 0, 0x107BB, 1); + _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Horn], 0, 0x107BB, 1); + _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS28GrabHornFails; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS28Clown: + if (gnap._actionStatus < 0) { + if (_vm->isFlag(kGFUnk21)) { + if (_vm->_verbCursor == LOOK_CURSOR) + gnap.playScratchingHead(Common::Point(5, 2)); + else + gnap.playImpossible(); + } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithBeer) { + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1); + gnap.playPullOutDevice(); + gnap.playUseDevice(); + gnap._actionStatus = kAS28UseBeerBucketWithClown; + } else if (_vm->_grabCursorSpriteIndex == kItemBucketWithPill) { + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS28Clown], 0, 0x107BC, 1); + gnap.playPullOutDevice(); + gnap.playUseDevice(); + gnap._actionStatus = kAS28UsePillBucketWithClown; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS28Clown], 2, 4); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(5, 2)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS28TalkClown; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS28ExitOutsideClown: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 27; + _vm->_hotspots[kHS28WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown], 0, 0x107BF, 1); + gnap._actionStatus = kAS28LeaveScene; + _vm->_hotspots[kHS28WalkArea1]._flags &= ~SF_WALKABLE; + plat.walkTo(_vm->_hotspotsWalkPos[kHS28ExitOutsideClown] + Common::Point(-1, 0), -1, 0x107C2, 1); + } + break; + + case kHS28EmptyBucket: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 8, 6); + } else if (_vm->isFlag(kGFUnk21)) { + gnap.playImpossible(Common::Point(8, 6)); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(8, 6)); + break; + case GRAB_CURSOR: + gnap.walkTo(gnap._pos, 0, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS28EmptyBucket]) | 0x10000, 1); + gnap._actionStatus = kAS28GrabEmptyBucket; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS28WalkArea1: + case kHS28WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1093C)) + _vm->playSound(0x1093C, true); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 80; + if (gnap._actionStatus < 0 && !_vm->isFlag(kGFUnk21)) + _nextClownSequenceId = 0x114; + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene28::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS28UseBeerBucketWithClown: + _vm->setFlag(kGFUnk22); + _nextClownSequenceId = 0x113; + _vm->invRemove(kItemBucketWithBeer); + updateHotspots(); + break; + case kAS28UsePillBucketWithClown: + _nextClownSequenceId = 0x116; + _vm->invRemove(kItemBucketWithPill); + _vm->setFlag(kGFUnk22); + _vm->setFlag(kGFUnk21); + updateHotspots(); + break; + case kAS28GrabHornFails: + _nextClownSequenceId = 0x119; + break; + case kAS28GrabHornSuccess: + gnap.playPullOutDevice(); + gnap.playUseDevice(); + gameSys.setAnimation(0x117, 59, 0); + gameSys.insertSequence(0x117, 59, 280, 59, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS28GrabHornSuccessDone; + break; + case kAS28GrabHornSuccessDone: + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + _vm->addFullScreenSprite(0xF6, 255); + gameSys.setAnimation(0x120, 256, 0); + gameSys.insertSequence(0x120, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + + _vm->removeFullScreenSprite(); + _vm->showCursor(); + _vm->setGrabCursorSprite(kItemHorn); + _vm->invAdd(kItemHorn); + updateHotspots(); + gnap._actionStatus = -1; + break; + case kAS28GrabEmptyBucket: + gnap.playPullOutDevice(); + gnap.playUseDevice(); + gameSys.setAnimation(0x111, 99, 0); + gameSys.insertSequence(0x111, 99, 274, 99, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS28GrabEmptyBucketDone; + break; + case kAS28GrabEmptyBucketDone: + _vm->setGrabCursorSprite(kItemEmptyBucket); + _vm->clearFlag(kGFUnk22); + updateHotspots(); + _vm->invAdd(kItemEmptyBucket); + gnap._actionStatus = -1; + break; + case kAS28GrabHornFailsDone: + gameSys.insertSequence(0x107B5, gnap._id, 281, 39, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + gameSys.insertSequence(0x11B, 39, 0, 0, kSeqNone, 0, 0, 0); + _currClownSequenceId = 0x11B; + _nextClownSequenceId = -1; + gnap._actionStatus = -1; + gnap.walkTo(Common::Point(2, 8), -1, 0x107BB, 1); + break; + case kAS28TalkClown: + // The original was only using the first two sequences, + // due to a bug. + _clownTalkCtr = (_clownTalkCtr + 1) % 3; + if (_clownTalkCtr == 0) + _nextClownSequenceId = 0x11D; + else if (_clownTalkCtr == 1) + _nextClownSequenceId = 0x11E; + else if (_clownTalkCtr == 2) + _nextClownSequenceId = 0x11F; + break; + case kAS28GnapWaiting: + gnap._actionStatus = -1; + break; + case kAS28LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_nextClownSequenceId) { + case 0x113: + _vm->setGrabCursorSprite(-1); + gameSys.setAnimation(_nextClownSequenceId, 39, 0); + gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0); + gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x11B, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0); + _currClownSequenceId = 0x11B; + _nextClownSequenceId = -1; + gnap._actionStatus = kAS28GnapWaiting; + break; + case 0x116: + _vm->setGrabCursorSprite(-1); + gameSys.setAnimation(_nextClownSequenceId, 39, 0); + gameSys.insertSequence(0x112, 99, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0); + gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x11C, 39, _nextClownSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0x118, 59, 0, 0, kSeqNone, _vm->getSequenceTotalDuration(_nextClownSequenceId), 0, 0); + _currClownSequenceId = _nextClownSequenceId; + _nextClownSequenceId = -1; + gnap._actionStatus = kAS28GnapWaiting; + break; + case 0x11D: + case 0x11E: + case 0x11F: + gnap._actionStatus = -1; + break; + case 0x119: + gameSys.insertSequence(_nextClownSequenceId, 39, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextClownSequenceId, 39, 0); + gameSys.removeSequence(_currClownSequenceId, 39, true); + gnap._actionStatus = kAS28GrabHornFailsDone; + gnap._sequenceId = _nextClownSequenceId; + gnap._sequenceDatNum = 0; + _nextClownSequenceId = -1; + break; + } + if (_nextClownSequenceId != -1) { + gameSys.insertSequence(_nextClownSequenceId, 39, _currClownSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextClownSequenceId, 39, 3); + _currClownSequenceId = _nextClownSequenceId; + _nextClownSequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene29::Scene29(GnapEngine *vm) : Scene(vm) { + _currMonkeySequenceId = -1; + _nextMonkeySequenceId = -1; + _currManSequenceId = -1; + _nextManSequenceId = -1; +} + +int Scene29::init() { + return 0xF6; +} + +void Scene29::updateHotspots() { + _vm->setHotspot(kHS29Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS29Monkey, 410, 374, 518, 516, SF_WALKABLE | SF_DISABLED, 3, 7); + _vm->setHotspot(kHS29ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS29ExitOutsideClown, 785, 0, 800, 600, SF_EXIT_R_CURSOR | SF_WALKABLE, 11, 9); + _vm->setHotspot(kHS29Arcade, 88, 293, 155, 384, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8); + _vm->setHotspot(kHS29WalkArea1, 0, 0, 800, 478); + _vm->setDeviceHotspot(kHS29Device, -1, -1, -1, -1); + if (_vm->invHas(kItemHorn)) + _vm->_hotspots[kHS29Monkey]._flags = SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + _vm->_hotspotsCount = 7; +} + +void Scene29::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1093B, true); + _vm->startSoundTimerB(6); + _vm->queueInsertDeviceIcon(); + + if (_vm->invHas(kItemHorn)) { + _currMonkeySequenceId = 0xE8; + _nextMonkeySequenceId = -1; + gameSys.setAnimation(0xE8, 159, 4); + gameSys.insertSequence(_currMonkeySequenceId, 159, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0); + _currManSequenceId = 0xED; + _nextManSequenceId = -1; + gameSys.setAnimation(0xED, 39, 3); + _vm->_timers[4] = _vm->getRandom(20) + 60; + } else { + gameSys.insertSequence(0xF4, 19, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0, 0, 4); + gameSys.insertSequence(0xED, 39, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0, 0, 3); + } + + gameSys.insertSequence(0xF3, 39, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0xF5, 38, 0, 0, kSeqLoop, 0, 0, 0); + + if (_vm->_prevSceneNum == 27) { + gnap.initPos(12, 7, kDirBottomRight); + plat.initPos(12, 8, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 7), -1, 0x107B9, 1); + plat.walkTo(Common::Point(8, 8), -1, 0x107C2, 1); + } else { + gnap.initPos(-1, 7, kDirBottomRight); + plat.initPos(-2, 7, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 7), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS29Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS29Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS29Monkey: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemBanana) { + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Monkey], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS29UseBananaWithMonkey; + _vm->_newSceneNum = 51; + _vm->_isLeavingScene = true; + _vm->setGrabCursorSprite(-1); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Monkey], 5, 6); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(5, 6)); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(_vm->_hotspotsWalkPos[kHS29Monkey]); + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS29ExitCircus: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 26; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus], 0, 0x107AE, 1); + gnap._actionStatus = kAS29LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitCircus] + Common::Point(1, 0), -1, -1, 1); + } + break; + + case kHS29ExitOutsideClown: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 27; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown], 0, 0x107AB, 1); + gnap._actionStatus = kAS29LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS29ExitOutsideClown] + Common::Point(0, -1), -1, 0x107CD, 1); + } + break; + + case kHS29Arcade: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) { + _vm->setGrabCursorSprite(-1); + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 52; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS29Arcade], 0, -1, 1); + gnap.playIdle(_vm->_hotspotsWalkPos[kHS29Arcade]); + gnap._actionStatus = kAS29LeaveScene; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS29Arcade], 2, 3); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan2(); + break; + case GRAB_CURSOR: + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS29WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1093B)) + _vm->playSound(0x1093B, true); + + if (!_vm->_isLeavingScene) { + if (gnap._actionStatus < 0) { + gnap.updateIdleSequence(); + plat.updateIdleSequence(); + } + if (!_vm->_timers[4]) { + if (_vm->invHas(kItemHorn)) { + _vm->_timers[4] = _vm->getRandom(20) + 60; + if (gnap._actionStatus < 0) { + switch (_vm->getRandom(5)) { + case 0: + _nextManSequenceId = 0xED; + break; + case 1: + _nextManSequenceId = 0xEE; + break; + case 2: + _nextManSequenceId = 0xEF; + break; + case 3: + _nextManSequenceId = 0xF0; + break; + case 4: + _nextManSequenceId = 0xF1; + break; + } + } + } + } + _vm->playSoundB(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene29::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS29UseBananaWithMonkey: + _nextMonkeySequenceId = 0xE5; + break; + case kAS29LeaveScene: + _vm->_sceneDone = true; + break; + } + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextManSequenceId != -1) { + gameSys.insertSequence(_nextManSequenceId, 39, _currManSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextManSequenceId, 39, 3); + _currManSequenceId = _nextManSequenceId; + _nextManSequenceId = -1; + } + + if (gameSys.getAnimationStatus(4) == 2) { + if (_nextMonkeySequenceId == 0xE5) { + gameSys.insertSequence(0xF2, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0xF2; + gameSys.setAnimation(0xE6, 159, 0); + gameSys.setAnimation(0, 159, 4); + gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0xE6, 159, _nextMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = kAS29LeaveScene; + _currMonkeySequenceId = 0xE6; + _nextMonkeySequenceId = -1; + _vm->_timers[5] = 30; + while (_vm->_timers[5] && !_vm->_gameDone) + _vm->gameUpdateTick(); + + _vm->_plat->walkTo(Common::Point(0, 8), 1, 0x107CF, 1); + + while (gameSys.getAnimationStatus(1) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + } else if (_nextMonkeySequenceId == -1) { + switch (_vm->getRandom(6)) { + case 0: + _nextMonkeySequenceId = 0xE8; + break; + case 1: + _nextMonkeySequenceId = 0xE9; + break; + case 2: + _nextMonkeySequenceId = 0xEA; + break; + case 3: + _nextMonkeySequenceId = 0xEB; + break; + case 4: + _nextMonkeySequenceId = 0xEC; + break; + case 5: + _nextMonkeySequenceId = 0xE7; + break; + } + gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextMonkeySequenceId, 159, 4); + _currMonkeySequenceId = _nextMonkeySequenceId; + _nextMonkeySequenceId = -1; + } else { + gameSys.insertSequence(_nextMonkeySequenceId, 159, _currMonkeySequenceId, 159, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextMonkeySequenceId, 159, 4); + _currMonkeySequenceId = _nextMonkeySequenceId; + _nextMonkeySequenceId = -1; + } + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/group2.h b/engines/gnap/scenes/group2.h new file mode 100644 index 0000000000..8f56594f16 --- /dev/null +++ b/engines/gnap/scenes/group2.h @@ -0,0 +1,407 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUP2_H +#define GNAP_GROUP2_H + +#include "gnap/debugger.h" + +namespace Gnap { + +enum { + kHS20Platypus = 0, + kHS20GroceryStoreHat = 1, + kHS20ExitParkingLot = 2, + kHS20StonerGuy = 3, + kHS20GroceryStoreGuy = 4, + kHS20Device = 5, + kHS20ExitInsideGrubCity = 6, + kHS20ExitOutsideCircusWorld = 7, + kHS20ExitOutsideToyStore = 8, + kHS20ExitPhone = 9, + kHS20WalkArea1 = 10, + kHS20WalkArea2 = 11 +}; + +enum { + kHS21Platypus = 0, + kHS21Banana = 1, + kHS21OldLady = 2, + kHS21Device = 3, + kHS21ExitOutsideGrubCity = 4, + kHS21WalkArea1 = 5, + kHS21WalkArea2 = 6 +}; + +enum { + kHS22Platypus = 0, + kHS22ExitOutsideGrubCity = 1, + kHS22ExitBackGrubCity = 2, + kHS22Cashier = 3, + kHS22Device = 4, + kHS22WalkArea1 = 5, + kHS22WalkArea2 = 6 +}; + +enum { + kHS23Platypus = 0, + kHS23ExitFrontGrubCity = 1, + kHS23Device = 2, + kHS23Cereals = 3, + kHS23WalkArea1 = 4, + kHS23WalkArea2 = 5 +}; + +enum { + kHS24Platypus = 0, + kHS24ExitCircusWorld = 1, + kHS24ExitOutsideGrubCity = 2, + kHS24Device = 3, + kHS24WalkArea1 = 4, + kHS24WalkArea2 = 5, + kHS24WalkArea3 = 6 +}; + +enum { + kHS25Platypus = 0, + kHS25TicketVendor = 1, + kHS25ExitOutsideCircusWorld = 2, + kHS25ExitInsideCircusWorld = 3, + kHS25Device = 4, + kHS25Posters1 = 5, + kHS25Posters2 = 6, + kHS25Posters3 = 7, + kHS25Posters4 = 8, + kHS25WalkArea1 = 9, + kHS25WalkArea2 = 10 +}; + +enum { + kHS26Platypus = 0, + kHS26ExitOutsideCircusWorld = 1, + kHS26ExitOutsideClown = 2, + kHS26ExitArcade = 3, + kHS26ExitElephant = 4, + kHS26ExitBeerStand = 5, + kHS26Device = 6, + kHS26WalkArea1 = 7, + kHS26WalkArea2 = 8 +}; + +enum { + kHS27Platypus = 0, + kHS27Janitor = 1, + kHS27Device = 2, + kHS27Bucket = 3, + kHS27ExitCircus = 4, + kHS27ExitArcade = 5, + kHS27ExitBeerStand = 6, + kHS27ExitClown = 7, + kHS27WalkArea1 = 8 +}; + +enum { + kHS28Platypus = 0, + kHS28Horn = 1, + kHS28Clown = 2, + kHS28ExitOutsideClown = 3, + kHS28EmptyBucket = 4, + kHS28Device = 5, + kHS28WalkArea1 = 6, + kHS28WalkArea2 = 7 +}; + +enum { + kHS29Platypus = 0, + kHS29Monkey = 1, + kHS29Device = 2, + kHS29ExitCircus = 3, + kHS29ExitOutsideClown = 4, + kHS29Arcade = 5, + kHS29WalkArea1 = 6 +}; + +enum { + kAS20LeaveScene = 0, + kAS20TalkStonerGuyNoJoint = 2, + kAS20TalkStonerGuyHasJoint = 3, + kAS20GrabJoint = 4, + kAS20ActionDone = 5, + kAS20TalkGroceryStoreGuy = 6, + kAS20GrabGroceryStoreGuy = 9, + kAS20GrabGroceryStoreHat = 10, + kAS20SwitchGroceryStoreHat = 11, + kAS20SwitchGroceryStoreHatDone = 12, + kAS20GrabJointDone = 13 +}; + +enum { + kAS21TalkOldLady = 0, + kAS21GrabBanana = 1, + kAS21GrabBananaDone = 2, + kAS21GrabOldLady = 3, + kAS21UseHatWithOldLady = 4, + kAS21UseHatWithOldLadyDone = 5, + kAS21LeaveScene = 6 +}; + +enum { + kAS22LeaveScene = 0, + kAS22TalkCashier = 1 +}; + +enum { + kAS23LookCereals = 0, + kAS23GrabCereals = 1, + kAS23GrabCerealsDone = 2, + kAS23LeaveScene = 3 +}; + +enum { + kAS24LeaveScene = 0 +}; + +enum { + kAS25TalkTicketVendor = 0, + kAS25EnterCircusWihoutTicket = 1, + kAS25ShowTicketToVendor = 2, + kAS25ShowTicketToVendorDone = 3, + kAS25EnterCircusWihoutTicketDone = 4, + kAS25LeaveScene = 5 +}; + +enum { + kAS26LeaveScene = 0 +}; + +enum { + kAS27TalkJanitor = 0, + kAS27GrabBucket = 1, + kAS27GrabBucketDone = 2, + kAS27ShowPictureToJanitor = 3, + kAS27TryEnterClownTent = 4, + kAS27TryEnterClownTentDone = 5, + kAS27EnterClownTent = 6, + kAS27LeaveScene = 7 +}; + +enum { + kAS28UseBeerBucketWithClown = 0, + kAS28UsePillBucketWithClown = 1, + kAS28GrabHornFails = 2, + kAS28GrabEmptyBucket = 3, + kAS28GrabHornSuccess = 4, + kAS28GrabHornSuccessDone = 5, + kAS28GrabEmptyBucketDone = 6, + kAS28GrabHornFailsDone = 7, + kAS28TalkClown = 8, + kAS28GnapWaiting = 9, + kAS28LeaveScene = 10 +}; + +enum { + kAS29UseBananaWithMonkey = 0, + kAS29LeaveScene = 2 +}; + +class GnapEngine; +class CutScene; + +class Scene20: public Scene { +public: + Scene20(GnapEngine *vm); + virtual ~Scene20() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb(); + +private: + int _currStonerGuySequenceId; + int _nextStonerGuySequenceId; + int _currGroceryStoreGuySequenceId; + int _nextGroceryStoreGuySequenceId; + int _stonerGuyCtr; + int _groceryStoreGuyCtr; + bool _stonerGuyShowingJoint; + + void stopSounds(); +}; + +class Scene21: public Scene { +public: + Scene21(GnapEngine *vm); + virtual ~Scene21() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currOldLadySequenceId; + int _nextOldLadySequenceId; +}; + +class Scene22: public Scene { +public: + Scene22(GnapEngine *vm); + virtual ~Scene22() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currCashierSequenceId; + int _nextCashierSequenceId; + bool _caughtBefore; + int _cashierCtr; +}; + +class Scene23: public Scene { +public: + Scene23(GnapEngine *vm); + virtual ~Scene23() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currStoreClerkSequenceId; + int _nextStoreClerkSequenceId; +}; + +class Scene24: public Scene { +public: + Scene24(GnapEngine *vm); + virtual ~Scene24() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currWomanSequenceId; + int _nextWomanSequenceId; + int _boySequenceId; + int _girlSequenceId; +}; + +class Scene25: public Scene { +public: + Scene25(GnapEngine *vm); + virtual ~Scene25() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currTicketVendorSequenceId; + int _nextTicketVendorSequenceId; + + void playAnims(int index); +}; + +class Scene26: public Scene { +public: + Scene26(GnapEngine *vm); + virtual ~Scene26() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currKidSequenceId; + int _nextKidSequenceId; +}; + +class Scene27: public Scene { +public: + Scene27(GnapEngine *vm); + virtual ~Scene27() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _nextJanitorSequenceId; + int _currJanitorSequenceId; +}; + +class Scene28: public Scene { +public: + Scene28(GnapEngine *vm); + virtual ~Scene28() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currClownSequenceId; + int _nextClownSequenceId; + int _clownTalkCtr; +}; + +class Scene29: public Scene { +public: + Scene29(GnapEngine *vm); + virtual ~Scene29() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currMonkeySequenceId; + int _nextMonkeySequenceId; + int _currManSequenceId; + int _nextManSequenceId; +}; + +} // End of namespace Gnap + +#endif // GNAP_GROUP1_H diff --git a/engines/gnap/scenes/group3.cpp b/engines/gnap/scenes/group3.cpp new file mode 100644 index 0000000000..98a4f6c454 --- /dev/null +++ b/engines/gnap/scenes/group3.cpp @@ -0,0 +1,1612 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/group3.h" + +namespace Gnap { + +Scene30::Scene30(GnapEngine *vm) : Scene(vm) { + _kidSequenceId = -1; +} + +int Scene30::init() { + return _vm->isFlag(kGFUnk23) ? 0x10B : 0x10A; +} + +void Scene30::updateHotspots() { + _vm->setHotspot(kHS30Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS30PillMachine, 598, 342, 658, 426, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 9, 7); + _vm->setHotspot(kHS30ExitCircus, 100, 590 - _vm->_deviceY1, 700, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS30WalkArea1, 0, 0, 800, 514); + _vm->setDeviceHotspot(kHS30Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 5; +} + +void Scene30::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + bool hasTakenPill = false; + + _vm->playSound(0x1093B, true); + _vm->startSoundTimerB(6); + + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFUnk23)) + gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (!_vm->isFlag(kGFUnk13)) + gameSys.insertSequence(0x107, 1, 0, 0, kSeqNone, 0, 0, 0); + _vm->_timers[5] = _vm->getRandom(50) + 180; + + gameSys.insertSequence(0x101, 40, 0, 0, kSeqNone, 0, 0, 0); + _vm->_timers[4] = _vm->getRandom(100) + 300; + + _kidSequenceId = 0x101; + gnap.initPos(7, 12, kDirBottomRight); + plat.initPos(6, 12, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(7, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS30Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS30Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS30PillMachine: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole && !_vm->isFlag(kGFUnk23)) { + _vm->_hotspots[kHS30WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine], 0, 0x107BC, 1); + _vm->_hotspots[kHS30WalkArea1]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS30UsePillMachine; + hasTakenPill = true; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS30PillMachine], 8, 5); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.walkTo(Common::Point(9, 8), 0, 0x107BC, 1); + gnap._actionStatus = kAS30LookPillMachine; + break; + case GRAB_CURSOR: + gnap.playScratchingHead(Common::Point(8, 5)); + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(Common::Point(8, 5)); + break; + } + } + } + break; + + case kHS30ExitCircus: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + if (hasTakenPill) + _vm->_newSceneNum = 47; + else + _vm->_newSceneNum = 26; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS30ExitCircus].y), 0, 0x107AE, 1); + gnap._actionStatus = kAS30LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS30ExitCircus] + Common::Point(1, 0), -1, 0x107C2, 1); + } + break; + + case kHS30WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1093B)) + _vm->playSound(0x1093B, true); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(100) + 300; + if (gnap._actionStatus < 0) { + if (_vm->getRandom(5) == 1) { + gameSys.insertSequence(0xFF, 40, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x100, 40, _kidSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _kidSequenceId = 0x100; + } else { + gameSys.insertSequence(0xFE, 40, 0, 0, kSeqNone, 0, 0, 0); + } + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(50) + 180; + if (gnap._actionStatus < 0) { + if (!_vm->isFlag(kGFUnk23) || hasTakenPill) + gameSys.insertSequence(0x109, 20, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x108, 20, 0, 0, kSeqNone, 0, 0, 0); + } + } + _vm->playSoundB(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene30::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS30LeaveScene: + _vm->_sceneDone = true; + break; + case kAS30UsePillMachine: + _vm->setGrabCursorSprite(-1); + gameSys.setAnimation(0x105, gnap._id, 0); + gameSys.insertSequence(0x105, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x105; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS30UsePillMachine2; + break; + case kAS30UsePillMachine2: + _vm->hideCursor(); + _vm->setGrabCursorSprite(-1); + _vm->addFullScreenSprite(0x3F, 255); + gameSys.removeSequence(0x105, gnap._id, true); + gameSys.setAnimation(0x102, 256, 0); + gameSys.insertSequence(0x102, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + gameSys.setAnimation(0x103, gnap._id, 0); + gameSys.insertSequence(0x103, gnap._id, 0, 0, kSeqNone, 0, 0, 0); + _vm->removeFullScreenSprite(); + _vm->showCursor(); + gnap._actionStatus = kAS30UsePillMachine3; + _vm->invAdd(kItemPill); + _vm->setFlag(kGFUnk23); + break; + case kAS30UsePillMachine3: + gameSys.setAnimation(0x104, gnap._id, 0); + gameSys.insertSequence(0x104, gnap._id, makeRid(gnap._sequenceDatNum, 0x103), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x104; + gnap._sequenceDatNum = 0; + gnap._actionStatus = kAS30UsePillMachine4; + _vm->setGrabCursorSprite(kItemDiceQuarterHole); + break; + case kAS30UsePillMachine4: + gameSys.insertSequence(0x106, 1, 0, 0, kSeqNone, 0, 0, 0); + gnap.walkTo(_vm->_hotspotsWalkPos[kHS30PillMachine] + Common::Point(0, 1), -1, 0x107BC, 1); + gnap._actionStatus = -1; + break; + case kAS30LookPillMachine: + if (_vm->isFlag(kGFUnk23)) + _vm->showFullScreenSprite(0xE3); + else + _vm->showFullScreenSprite(0xE2); + gnap._actionStatus = -1; + break; + } + } +} + +/*****************************************************************************/ + +Scene31::Scene31(GnapEngine *vm) : Scene(vm) { + _beerGuyDistracted = false; + _currClerkSequenceId = -1; + _nextClerkSequenceId = -1; + _clerkMeasureCtr = -1; + _clerkMeasureMaxCtr = 3; +} + +int Scene31::init() { + return 0x105; +} + +void Scene31::updateHotspots() { + _vm->setHotspot(kHS31Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS31MeasuringClown, 34, 150, 256, 436, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 6); + _vm->setHotspot(kHS31BeerBarrel, 452, 182, 560, 306, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7); + _vm->setHotspot(kHS31ExitCircus, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS31ExitOutsideClown, 0, 0, 15, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8); + _vm->setHotspot(kHS31WalkArea1, 0, 0, 800, 480); + _vm->setDeviceHotspot(kHS31Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 7; +} + +void Scene31::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1093B, true); + _vm->startSoundTimerB(6); + _vm->queueInsertDeviceIcon(); + + _beerGuyDistracted = false; + gameSys.insertSequence(0xFB, 39, 0, 0, kSeqNone, 0, 0, 0); + + _currClerkSequenceId = 0xFB; + _nextClerkSequenceId = -1; + + gameSys.setAnimation(0xFB, 39, 3); + + _vm->_timers[4] = _vm->getRandom(20) + 60; + _vm->_timers[5] = _vm->getRandom(50) + 180; + + if (_vm->_prevSceneNum == 27) { + gnap.initPos(-1, 8, kDirBottomLeft); + plat.initPos(-1, 9, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(3, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(3, 9), -1, 0x107D2, 1); + } else { + gnap.initPos(7, 12, kDirBottomRight); + plat.initPos(6, 12, kDirIdleLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(7, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107D2, 1); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS31Device: + if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS31Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemJoint) { + gnap.useJointOnPlatypus(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS31MeasuringClown: + if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) { + if (gnap._actionStatus == kAS31PlatMeasuringClown) { + if (_vm->_verbCursor == LOOK_CURSOR) + gnap.playScratchingHead(Common::Point(2, 2)); + else + gnap.playImpossible(); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 2, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(2, 2)); + break; + case GRAB_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), -1, -1, 1); + _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 0, 0x107B9, 1); + _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE; + gnap._actionStatus = kAS31UseMeasuringClown; + _vm->_timers[4] = 300; + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + if (!_vm->invHas(kItemBucketWithBeer)) { + gnap.useDeviceOnPlatypus(); + plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown] + Common::Point(0, 1), 1, 0x107C2, 1); + _vm->_hotspots[kHS31WalkArea1]._flags |= SF_WALKABLE; + plat.walkTo(_vm->_hotspotsWalkPos[kHS31MeasuringClown], 1, 0x107C2, 1); + _vm->_hotspots[kHS31WalkArea1]._flags &= ~SF_WALKABLE; + plat._actionStatus = kAS31PlatMeasuringClown; + gnap._actionStatus = kAS31PlatMeasuringClown; + _vm->_timers[4] = 300; + } else + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS31BeerBarrel: + if (gnap._actionStatus < 0 || gnap._actionStatus == kAS31PlatMeasuringClown) { + if (_vm->_grabCursorSpriteIndex == kItemEmptyBucket && _beerGuyDistracted) { + _vm->setGrabCursorSprite(-1); + gnap.walkTo(gnap._pos, -1, gnap.getSequenceId(kGSIdle, _vm->_hotspotsWalkPos[kHS31BeerBarrel]) | 0x10000, 1); + _clerkMeasureMaxCtr += 5; + gameSys.insertSequence(0xF8, 59, 0, 0, kSeqNone, 0, 0, 0); + gnap.playPullOutDevice(Common::Point(6, 8)); + gnap.playUseDevice(); + gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1); + gnap._actionStatus = kAS31FillEmptyBucketWithBeer; + _vm->_timers[4] = 300; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 6, 2); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(6, 2)); + break; + case GRAB_CURSOR: + if (_beerGuyDistracted) { + gnap.playScratchingHead(Common::Point(6, 2)); + } else { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS31BeerBarrel], 0, 0x107BC, 1); + gnap._actionStatus = kAS31UseBeerBarrel; + gnap._idleFacing = kDirUpLeft; + } + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS31ExitCircus: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 26; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitCircus].y), 0, 0x107AE, 1); + gnap._actionStatus = kAS31LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitCircus] + Common::Point(1, 0), -1, -1, 1); + } + break; + + case kHS31ExitOutsideClown: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 27; + gnap.walkTo(Common::Point(-1, _vm->_hotspotsWalkPos[kHS31ExitOutsideClown].y), 0, 0x107AF, 1); + gnap._actionStatus = kAS31LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS31ExitOutsideClown] + Common::Point(0, 1), -1, 0x107CF, 1); + } + break; + + case kHS31WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1093B)) + _vm->playSound(0x1093B, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 60; + if (gnap._actionStatus < 0 && _nextClerkSequenceId == -1) { + switch (_vm->getRandom(6)){ + case 0: + _nextClerkSequenceId = 0xFF; + break; + case 1: + _nextClerkSequenceId = 0x100; + break; + case 2: + _nextClerkSequenceId = 0x101; + break; + default: + _nextClerkSequenceId = 0xFB; + break; + } + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(50) + 180; + if (gnap._actionStatus < 0) { + if (_vm->getRandom(2) != 0) + gameSys.insertSequence(0x104, 20, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x103, 20, 0, 0, kSeqNone, 0, 0, 0); + } + } + _vm->playSoundB(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene31::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS31UseBeerBarrel: + _nextClerkSequenceId = 0xFE; + break; + case kAS31FillEmptyBucketWithBeer: + gameSys.setAnimation(0x102, 59, 0); + gameSys.insertSequence(0x102, 59, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._pos = Common::Point(5, 7); + gnap._sequenceDatNum = 0; + gnap._sequenceId = 0x102; + gnap._id = 59; + gnap._actionStatus = kAS31FillEmptyBucketWithBeerDone; + break; + case kAS31FillEmptyBucketWithBeerDone: + gnap._idleFacing = kDirBottomLeft; + gnap.playPullOutDevice(); + gnap.playUseDevice(); + gameSys.insertSequence(0xF9, 59, 0xF8, 59, kSeqSyncWait, 0, 0, 0); + gnap._actionStatus = -1; + _vm->invAdd(kItemBucketWithBeer); + _vm->invRemove(kItemEmptyBucket); + _vm->setGrabCursorSprite(kItemBucketWithBeer); + break; + case kAS31UseMeasuringClown: + _nextClerkSequenceId = 0xFA; + _clerkMeasureMaxCtr = 1; + break; + case kAS31LeaveScene: + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + if (plat._actionStatus == kAS31PlatMeasuringClown) { + _vm->_sceneWaiting = true; + _beerGuyDistracted = true; + _nextClerkSequenceId = 0xFA; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_nextClerkSequenceId) { + case 0xFA: + gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.insertSequence(0xFC, 39, _nextClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0xFC, 39, 3); + _currClerkSequenceId = 0xFC; + _nextClerkSequenceId = 0xFC; + _clerkMeasureCtr = 0; + break; + case 0xFC: + ++_clerkMeasureCtr; + if (_clerkMeasureCtr >= _clerkMeasureMaxCtr) { + if (gnap._actionStatus != 5) + plat._actionStatus = -1; + _vm->_timers[0] = 40; + gameSys.insertSequence(0xFD, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0); + _currClerkSequenceId = 0xFD; + _nextClerkSequenceId = -1; + if (gnap._actionStatus != kAS31FillEmptyBucketWithBeerDone && gnap._actionStatus != kAS31FillEmptyBucketWithBeer) + gnap._actionStatus = -1; + _beerGuyDistracted = false; + _clerkMeasureMaxCtr = 3; + gameSys.setAnimation(0xFD, 39, 3); + _vm->_sceneWaiting = false; + } else { + gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0); + _currClerkSequenceId = _nextClerkSequenceId; + _nextClerkSequenceId = 0xFC; + gameSys.setAnimation(0xFC, 39, 3); + } + break; + case 0xFE: + gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextClerkSequenceId, 39, 3); + _currClerkSequenceId = _nextClerkSequenceId; + _nextClerkSequenceId = -1; + gnap._actionStatus = -1; + break; + default: + if (_nextClerkSequenceId != -1) { + gameSys.insertSequence(_nextClerkSequenceId, 39, _currClerkSequenceId, 39, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextClerkSequenceId, 39, 3); + _currClerkSequenceId = _nextClerkSequenceId; + _nextClerkSequenceId = -1; + } + break; + } + } +} + +/*****************************************************************************/ + +Scene32::Scene32(GnapEngine *vm) : Scene(vm) {} + +int Scene32::init() { + _vm->_gameSys->setAnimation(0, 0, 0); + return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0xF : 0x10; +} + +void Scene32::updateHotspots() { + _vm->setHotspot(kHS32Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS32ExitTruck, 780, 226, 800, 455, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 6); + _vm->setHotspot(kHS32WalkArea1, 0, 0, 162, 426); + _vm->setHotspot(kHS32WalkArea2, 162, 0, 237, 396); + _vm->setHotspot(kHS32WalkArea3, 237, 0, 319, 363); + _vm->setHotspot(kHS32WalkArea4, 520, 0, 800, 404); + _vm->setHotspot(kHS32WalkArea5, 300, 447, 800, 600); + _vm->setHotspot(kHS32WalkArea6, 678, 0, 800, 404); + _vm->setHotspot(kHS32WalkArea7, 0, 0, 520, 351); + _vm->setHotspot(kHS32WalkArea8, 0, 546, 300, 600); + _vm->setDeviceHotspot(kHS32Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 11; +} + +void Scene32::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1091C, true); + _vm->startSoundTimerC(5); + _vm->queueInsertDeviceIcon(); + _vm->_timers[4] = _vm->getRandom(100) + 300; + + if (_vm->_prevSceneNum == 33) { + gnap.initPos(11, 6, kDirBottomLeft); + plat.initPos(12, 6, kDirIdleRight); + _vm->endSceneInit(); + plat.walkTo(Common::Point(9, 6), -1, 0x107D2, 1); + gnap.walkTo(Common::Point(8, 6), -1, 0x107BA, 1); + } else { + gnap.initPos(1, 6, kDirBottomRight); + plat.initPos(1, 7, kDirIdleLeft); + _vm->endSceneInit(); + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS32Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS32Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS32ExitTruck: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->setGrabCursorSprite(-1); + gnap.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck], 0, 0x107AB, 1); + gnap._actionStatus = kAS32LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS32ExitTruck] + Common::Point(0, 1), -1, 0x107CD, 1); + _vm->_newSceneNum = 33; + } + break; + + case kHS32WalkArea1: + case kHS32WalkArea2: + case kHS32WalkArea3: + case kHS32WalkArea4: + case kHS32WalkArea5: + case kHS32WalkArea6: + case kHS32WalkArea7: + case kHS32WalkArea8: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = 0; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1091C)) + _vm->playSound(0x1091C, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(100) + 300; + if (_vm->getRandom(2) != 0) + gameSys.insertSequence(0x0E, 180, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x0D, 180, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + _vm->gameUpdateTick(); + } +} + +void Scene32::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + if (_vm->_gnap->_actionStatus == kAS32LeaveScene) + _vm->_sceneDone = true; + } +} + +/*****************************************************************************/ + +Scene33::Scene33(GnapEngine *vm) : Scene(vm) { + _currChickenSequenceId = -1; + _nextChickenSequenceId = -1; +} + +int Scene33::init() { + return _vm->isFlag(kGFPlatypusTalkingToAssistant) ? 0x84 : 0x85; +} + +void Scene33::updateHotspots() { + _vm->setHotspot(kHS33Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS33Chicken, 606, 455, 702, 568, SF_WALKABLE | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8); + _vm->setHotspot(kHS33ExitHouse, 480, 120, 556, 240, SF_EXIT_U_CURSOR, 7, 3); + _vm->setHotspot(kHS33ExitBarn, 610, 75, 800, 164, SF_EXIT_U_CURSOR, 10, 3); + _vm->setHotspot(kHS33ExitCreek, 780, 336, 800, 556, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8); + _vm->setHotspot(kHS33ExitPigpen, 0, 300, 20, 600, SF_EXIT_L_CURSOR | SF_WALKABLE, 0, 8); + _vm->setHotspot(kHS33WalkArea1, 120, 0, 514, 458); + _vm->setHotspot(kHS33WalkArea2, 0, 0, 800, 452); + _vm->setDeviceHotspot(kHS33Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 9; +} + +void Scene33::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->playSound(0x1091C, true); + _vm->startSoundTimerC(6); + _vm->queueInsertDeviceIcon(); + + _currChickenSequenceId = 0x7E; + gameSys.setAnimation(0x7E, 179, 2); + gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0); + _nextChickenSequenceId = -1; + _vm->_timers[5] = _vm->getRandom(20) + 30; + _vm->_timers[4] = _vm->getRandom(100) + 300; + + switch (_vm->_prevSceneNum) { + case 34: + gnap.initPos(11, 7, kDirBottomLeft); + plat.initPos(12, 7, kDirIdleRight); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 7), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 7), -1, 0x107D2, 1); + break; + case 37: + gnap.initPos(7, 7, kDirBottomRight); + plat.initPos(8, 7, kDirIdleLeft); + _vm->endSceneInit(); + break; + case 32: + gnap.initPos(-1, 6, kDirBottomRight); + plat.initPos(-1, 7, kDirIdleLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(2, 7), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + break; + default: + gnap.initPos(3, 7, kDirBottomRight); + plat.initPos(2, 7, kDirIdleLeft); + _vm->endSceneInit(); + break; + } + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + _vm->testWalk(0, 0, 7, 6, 8, 6); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS33Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + + case kHS33Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS33Chicken: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(7, 9), 9, 8); + } else { + switch (_vm->_verbCursor) { + case GRAB_CURSOR: + gnap._idleFacing = kDirBottomRight; + if (gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSIdle, Common::Point(0, 0)) | 0x10000, 1)) + gnap._actionStatus = kAS33UseChicken; + else + gnap._actionStatus = -1; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirBottomRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS33Chicken], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS33TalkChicken; + break; + case LOOK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS33ExitHouse: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap._actionStatus = kAS33LeaveScene; + _vm->_newSceneNum = 37; + if (gnap._pos.x > 6) + gnap.walkTo(gnap._pos, 0, 0x107AD, 1); + else + gnap.walkTo(Common::Point(6, 7), 0, 0x107B1, 1); + } + break; + + case kHS33ExitBarn: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap._actionStatus = kAS33LeaveScene; + _vm->_newSceneNum = 35; + if (gnap._pos.x > 7) + gnap.walkTo(gnap._pos, 0, 0x107AD, 1); + else + gnap.walkTo(Common::Point(7, 7), 0, 0x107B1, 1); + } + break; + + case kHS33ExitCreek: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], 0, 0x107AB, 1); + gnap._actionStatus = kAS33LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitCreek], -1, 0x107CD, 1); + _vm->_newSceneNum = 34; + } + break; + + case kHS33ExitPigpen: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], 0, 0x107AF, 1); + gnap._actionStatus = kAS33LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS33ExitPigpen], -1, 0x107CF, 1); + _vm->_newSceneNum = 32; + } + break; + + case kHS33WalkArea1: + case kHS33WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->isSoundPlaying(0x1091C)) + _vm->playSound(0x1091C, true); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(100) + 300; + if (_vm->getRandom(2) != 0) + gameSys.insertSequence(0x83, 256, 0, 0, kSeqNone, 0, 0, 0); + else + gameSys.insertSequence(0x82, 256, 0, 0, kSeqNone, 0, 0, 0); + } + if (!_vm->_timers[5] && _nextChickenSequenceId == -1 && gnap._actionStatus != kAS33TalkChicken && gnap._actionStatus != kAS33UseChicken) { + if (_vm->getRandom(6) != 0) { + _nextChickenSequenceId = 0x7E; + _vm->_timers[5] = _vm->getRandom(20) + 30; + } else { + _nextChickenSequenceId = 0x80; + _vm->_timers[5] = _vm->getRandom(20) + 50; + } + } + _vm->playSoundC(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + _vm->gameUpdateTick(); + } +} + +void Scene33::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + switch (gnap._actionStatus) { + case kAS33LeaveScene: + _vm->_sceneDone = true; + break; + case kAS33TalkChicken: + _nextChickenSequenceId = 0x7F; + break; + case kAS33UseChicken: + _nextChickenSequenceId = 0x81; + _vm->_timers[2] = 100; + break; + case kAS33UseChickenDone: + gameSys.insertSequence(0x107B5, gnap._id, 0x81, 179, kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceId = 0x7B5; + gnap._sequenceDatNum = 1; + _currChickenSequenceId = 0x7E; + gameSys.setAnimation(0x7E, 179, 2); + gameSys.insertSequence(_currChickenSequenceId, 179, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = -1; + _vm->_timers[5] = 30; + break; + default: + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + if (_nextChickenSequenceId == 0x81) { + gameSys.setAnimation(_nextChickenSequenceId, 179, 0); + gameSys.insertSequence(_nextChickenSequenceId, 179, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(_currChickenSequenceId, 179, true); + _nextChickenSequenceId = -1; + _currChickenSequenceId = -1; + gnap._actionStatus = kAS33UseChickenDone; + _vm->_timers[5] = 500; + } else if (_nextChickenSequenceId == 0x7F) { + gameSys.setAnimation(_nextChickenSequenceId, 179, 2); + gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0); + _currChickenSequenceId = _nextChickenSequenceId; + _nextChickenSequenceId = -1; + gnap._actionStatus = -1; + } else if (_nextChickenSequenceId != -1) { + gameSys.setAnimation(_nextChickenSequenceId, 179, 2); + gameSys.insertSequence(_nextChickenSequenceId, 179, _currChickenSequenceId, 179, kSeqSyncWait, 0, 0, 0); + _currChickenSequenceId = _nextChickenSequenceId; + _nextChickenSequenceId = -1; + } + } +} + +/*****************************************************************************/ + +Scene38::Scene38(GnapEngine *vm) : Scene(vm) { +} + +int Scene38::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + return 0xA5; +} + +void Scene38::updateHotspots() { + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->setHotspot(kHS38Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS38ExitHouse, 150, 585, 650, 600, SF_EXIT_D_CURSOR, 0, 8); + _vm->setHotspot(kHS38ExitCave, 430, 440, 655, 470, SF_WALKABLE, 0, 8); + _vm->setHotspot(kHS38TrapDoorLid1, 525, 265, 640, 350, SF_DISABLED); + _vm->setHotspot(kHS38TrapDoorLid2, 555, 350, 670, 430, SF_DISABLED); + _vm->setHotspot(kHS38HuntingTrophy, 170, 85, 250, 190, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8); + _vm->setHotspot(kHS38WalkArea1, 330, 270, 640, 380, SF_DISABLED | SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 0, 8); + _vm->setHotspot(kHS38WalkArea2, 0, 0, 799, 396); + _vm->setHotspot(kHS38WalkArea3, 0, 585, 799, 599, SF_WALKABLE | SF_DISABLED); + _vm->setHotspot(kHS38WalkArea4, 0, 0, 97, 445); + _vm->setHotspot(kHS38WalkArea5, 770, 0, 799, 445); + _vm->setHotspot(kHS38WalkArea6, 393, 0, 698, 445, SF_WALKABLE | SF_DISABLED); + _vm->setDeviceHotspot(kHS38Device, -1, -1, -1, -1); + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + _vm->_hotspots[kHS38Platypus]._flags = SF_WALKABLE | SF_DISABLED; + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR; + else if (gnap._actionStatus == kAS38HoldingHuntingTrophy) + _vm->_hotspots[kHS38ExitCave]._flags = SF_EXIT_D_CURSOR; + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_DISABLED; + else if (gnap._actionStatus == kAS38HoldingHuntingTrophy) + _vm->_hotspots[kHS38TrapDoorLid1]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_DISABLED; + else if (gnap._actionStatus == kAS38HoldingHuntingTrophy) + _vm->_hotspots[kHS38TrapDoorLid2]._flags = SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR; + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + _vm->_hotspots[kHS38WalkArea6]._flags = SF_NONE; + _vm->_hotspotsCount = 13; +} + +void Scene38::run() { + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + _vm->_gameSys->insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->_prevSceneNum == 39) { + gnap.initPos(3, 7, kDirBottomLeft); + plat.initPos(4, 7, kDirIdleRight); + } else { + gnap.initPos(3, 8, kDirBottomRight); + plat.initPos(4, 8, kDirIdleLeft); + } + _vm->endSceneInit(); + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS38Device: + _vm->runMenu(); + updateHotspots(); + break; + + case kHS38Platypus: + if (gnap._actionStatus == kAS38HoldingHuntingTrophy) { + gnap._actionStatus = kAS38ReleaseHuntingTrophy; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + break; + + case kHS38ExitHouse: + if (gnap._actionStatus == kAS38HoldingHuntingTrophy) { + gnap._actionStatus = kAS38ReleaseHuntingTrophy; + } else { + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(-1, -1), 0, 0x107AE, 1); + gnap._actionStatus = kAS38LeaveScene; + _vm->_newSceneNum = 37; + } + break; + + case kHS38ExitCave: + if (gnap._actionStatus == kAS38HoldingHuntingTrophy) { + gnap._actionStatus = kAS38ReleaseHuntingTrophy; + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + _vm->_isLeavingScene = true; + } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) { + _vm->_sceneWaiting = false; + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1); + _vm->_newSceneNum = 39; + gnap._actionStatus = kAS38ExitCave; + } + break; + + case kHS38TrapDoorLid1: + case kHS38TrapDoorLid2: + if (gnap._actionStatus == kAS38HoldingHuntingTrophy) { + if (_vm->_verbCursor == PLAT_CURSOR && plat._actionStatus != kAS38PlatypusHoldingTrapDoor) + gnap._actionStatus = kAS38UsePlatypusWithTrapDoor; + else + gnap._actionStatus = kAS38ReleaseHuntingTrophy; + } + break; + + case kHS38HuntingTrophy: + if (gnap._actionStatus != kAS38HoldingHuntingTrophy) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(3, 6), 2, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(); + break; + case GRAB_CURSOR: + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) + gnap.playImpossible(); + else { + gnap.walkTo(Common::Point(3, 6), 0, 0x107BB, 1); + plat.walkTo(Common::Point(4, 8), -1, -1, 1); + gnap._actionStatus = kAS38UseHuntingTrophy; + } + break; + case TALK_CURSOR: + gnap.playBrainPulsating(Common::Point(2, 0)); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS38WalkArea1: + // Nothing + break; + + case kHS38WalkArea2: + case kHS38WalkArea3: + case kHS38WalkArea4: + case kHS38WalkArea5: + case kHS38WalkArea6: + if (gnap._actionStatus == kAS38HoldingHuntingTrophy) + gnap._actionStatus = kAS38ReleaseHuntingTrophy; + else if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left) { + if (gnap._actionStatus == kAS38HoldingHuntingTrophy) + gnap._actionStatus = kAS38ReleaseHuntingTrophy; + else if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + plat.updateIdleSequence(); + gnap.updateIdleSequence(); + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene38::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case kAS38LeaveScene: + _vm->_sceneDone = true; + break; + case kAS38ExitCave: + gameSys.removeSequence(plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, true); + gameSys.insertSequence(0xA3, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0xA3; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0xA3, gnap._id, 0); + gnap._actionStatus = kAS38LeaveScene; + break; + case kAS38UseHuntingTrophy: + gameSys.removeSequence(0x9B, 0, true); + gameSys.insertSequence(0x9C, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x9C; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x9C, gnap._id, 0); + gnap._actionStatus = kAS38HoldingHuntingTrophy; + updateHotspots(); + break; + case kAS38HoldingHuntingTrophy: + if (plat._actionStatus != kAS38PlatypusHoldingTrapDoor) + _vm->_sceneWaiting = true; + if (gnap._sequenceId == 0xA4) { + gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x9D; + } else { + gameSys.insertSequence(0xA4, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0xA4; + } + gnap._sequenceDatNum = 0; + gameSys.setAnimation(gnap._sequenceId, gnap._id, 0); + break; + case kAS38ReleaseHuntingTrophy: + if (gnap._sequenceId == 0x9E) { + gameSys.insertSequence(0x9B, 0, 0, 0, kSeqNone, 0, 0, 0); + gnap._actionStatus = -1; + } else if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) { + gameSys.insertSequence(0xA0, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0xA0; + gnap._sequenceDatNum = 0; + gnap._pos = Common::Point(3, 6); + gnap._idleFacing = kDirBottomRight; + if (_vm->_isLeavingScene) { + _vm->_sceneWaiting = false; + gnap.walkTo(Common::Point(5, 7), 0, 0x107BB, 1); + _vm->_newSceneNum = 39; + gnap._actionStatus = kAS38ExitCave; + } else { + gnap._actionStatus = -1; + } + } else { + gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x9E; + gnap._sequenceDatNum = 0; + gnap._pos = Common::Point(3, 6); + gnap._idleFacing = kDirBottomRight; + gameSys.setAnimation(0x9E, gnap._id, 0); + _vm->_sceneWaiting = false; + updateHotspots(); + } + break; + case kAS38UsePlatypusWithTrapDoor: + _vm->_sceneWaiting = false; + gameSys.insertSequence(0x9F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x9F; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x9F, gnap._id, 0); + gnap._actionStatus = kAS38HoldingHuntingTrophy; + if (plat._idleFacing != kDirIdleLeft) + plat.playSequence(0x107D5); + else + plat.playSequence(0x107D4); + plat.walkTo(Common::Point(8, 7), -1, 0x107D2, 1); + gameSys.insertSequence(0xA1, gnap._id + 1, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0xA1; + plat._sequenceDatNum = 0; + plat._id = gnap._id + 1; + gameSys.setAnimation(0xA1, gnap._id + 1, 1); + plat._actionStatus = kAS38PlatypusHoldingTrapDoor; + updateHotspots(); + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + if (plat._actionStatus == kAS38PlatypusHoldingTrapDoor) { + gameSys.insertSequence(0xA2, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0xA2; + plat._sequenceDatNum = 0; + updateHotspots(); + _vm->_sceneWaiting = true; + } + } +} + +/*****************************************************************************/ + +Scene39::Scene39(GnapEngine *vm) : Scene(vm) { + _currGuySequenceId = -1; + _nextGuySequenceId = -1; +} + +int Scene39::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + return 0x35; +} + +void Scene39::updateHotspots() { + _vm->setHotspot(kHS39Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS39ExitInsideHouse, 0, 0, 140, 206, SF_EXIT_U_CURSOR, 4, 8); + _vm->setHotspot(kHS39ExitUfoParty, 360, 204, 480, 430, SF_EXIT_R_CURSOR, 6, 8); + _vm->setHotspot(kHS39Sign, 528, 232, 607, 397, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 3); + _vm->setHotspot(kHS39WalkArea1, 0, 0, 800, 466); + _vm->setHotspot(kHS39WalkArea2, 502, 466, 800, 600); + _vm->setDeviceHotspot(kHS39Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 7; +} + +void Scene39::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + // Bug in the original? Timer was never initialized. + _vm->_timers[5] = 0; + + _vm->queueInsertDeviceIcon(); + _currGuySequenceId = 0x33; + + gameSys.setAnimation(0x33, 21, 3); + gameSys.insertSequence(_currGuySequenceId, 21, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x34, 21, 0, 0, kSeqLoop, 0, 0, 0); + + _nextGuySequenceId = -1; + if (_vm->_prevSceneNum == 38) { + gnap.initPos(3, 7, kDirUpRight); + plat.initPos(2, 7, kDirUpLeft); + _vm->endSceneInit(); + } else { + gnap.initPos(4, 7, kDirBottomRight); + plat.initPos(5, 7, kDirIdleLeft); + _vm->endSceneInit(); + } + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) { + _vm->playSound(0x1094B, true); + _vm->setSoundVolume(0x1094B, 60); + } + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS39Device: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[5] = _vm->getRandom(20) + 50; + break; + + case kHS39Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS39ExitUfoParty: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_sceneDone = true; + gnap.walkTo(gnap._pos, 0, 0x107AB, 1); + gnap._actionStatus = kAS39LeaveScene; + _vm->_newSceneNum = 40; + } + break; + + case kHS39Sign: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[kHS39Sign], 0, -1, 1); + gnap.playIdle(_vm->_hotspotsWalkPos[kHS39Sign]); + _vm->showFullScreenSprite(0x1C); + break; + case GRAB_CURSOR: + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS39ExitInsideHouse: + if (gnap._actionStatus < 0) { + _vm->_sceneDone = true; + _vm->_isLeavingScene = true; + _vm->_newSceneNum = 38; + } + break; + + case kHS39WalkArea1: + case kHS39WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + _vm->_mouseClickState._left = false; + } + break; + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0) + gnap.updateIdleSequence(); + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(20) + 50; + switch (_vm->getRandom(4)) { + case 0: + _nextGuySequenceId = 0x30; + break; + case 1: + _nextGuySequenceId = 0x31; + break; + case 2: + _nextGuySequenceId = 0x32; + break; + case 3: + _nextGuySequenceId = 0x33; + break; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[5] = _vm->getRandom(20) + 50; + } + + _vm->gameUpdateTick(); + } +} + +void Scene39::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + if (gnap._actionStatus == kAS39LeaveScene) + _vm->_sceneDone = true; + else + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextGuySequenceId != -1) { + gameSys.setAnimation(_nextGuySequenceId, 21, 3); + gameSys.insertSequence(_nextGuySequenceId, 21, _currGuySequenceId, 21, kSeqSyncWait, 0, 0, 0); + _currGuySequenceId = _nextGuySequenceId; + _nextGuySequenceId = -1; + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/group3.h b/engines/gnap/scenes/group3.h new file mode 100644 index 0000000000..6fbbdd79aa --- /dev/null +++ b/engines/gnap/scenes/group3.h @@ -0,0 +1,240 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUP3_H +#define GNAP_GROUP3_H + +#include "gnap/debugger.h" + +namespace Gnap { + +enum { + kHS30Platypus = 0, + kHS30PillMachine = 1, + kHS30Device = 2, + kHS30ExitCircus = 3, + kHS30WalkArea1 = 4 +}; + +enum { + kHS31Platypus = 0, + kHS31MeasuringClown = 1, + kHS31BeerBarrel = 2, + kHS31Device = 3, + kHS31ExitCircus = 4, + kHS31ExitOutsideClown = 5, + kHS31WalkArea1 = 6 +}; + +enum { + kHS32Platypus = 0, + kHS32ExitTruck = 1, + kHS32Device = 2, + kHS32WalkArea1 = 3, + kHS32WalkArea2 = 4, + kHS32WalkArea3 = 5, + kHS32WalkArea4 = 6, + kHS32WalkArea5 = 7, + kHS32WalkArea6 = 8, + kHS32WalkArea7 = 9, + kHS32WalkArea8 = 10 +}; + +enum { + kHS33Platypus = 0, + kHS33Chicken = 1, + kHS33Device = 2, + kHS33ExitHouse = 3, + kHS33ExitBarn = 4, + kHS33ExitCreek = 5, + kHS33ExitPigpen = 6, + kHS33WalkArea1 = 7, + kHS33WalkArea2 = 8 +}; + +enum { + kHS38Platypus = 0, + kHS38ExitHouse = 1, + kHS38ExitCave = 2, + kHS38TrapDoorLid1 = 3, + kHS38TrapDoorLid2 = 4, + kHS38HuntingTrophy = 5, + kHS38WalkArea1 = 6, + kHS38Device = 7, + kHS38WalkArea2 = 8, + kHS38WalkArea3 = 9, + kHS38WalkArea4 = 10, + kHS38WalkArea5 = 11, + kHS38WalkArea6 = 12 +}; + +enum { + kHS39Platypus = 0, + kHS39ExitInsideHouse = 1, + kHS39ExitUfoParty = 2, + kHS39Sign = 3, + kHS39Device = 4, + kHS39WalkArea1 = 5, + kHS39WalkArea2 = 6 +}; + +enum { + kAS30LeaveScene = 0, + kAS30UsePillMachine = 1, + kAS30UsePillMachine2 = 2, + kAS30LookPillMachine = 3, + kAS30UsePillMachine3 = 4, + kAS30UsePillMachine4 = 5 +}; + +enum { + kAS31UseBeerBarrel = 1, + kAS31FillEmptyBucketWithBeer = 2, + kAS31FillEmptyBucketWithBeerDone = 3, + kAS31PlatMeasuringClown = 4, + kAS31UseMeasuringClown = 5, + kAS31LeaveScene = 6 +}; + +enum { + kAS32LeaveScene = 0 +}; + +enum { + kAS33LeaveScene = 0, + kAS33TalkChicken = 1, + kAS33UseChicken = 2, + kAS33UseChickenDone = 3 +}; + +enum { + kAS38LeaveScene = 0, + kAS38ExitCave = 1, + kAS38UseHuntingTrophy = 2, + kAS38HoldingHuntingTrophy = 3, + kAS38ReleaseHuntingTrophy = 4, + kAS38UsePlatypusWithTrapDoor = 5, + kAS38PlatypusHoldingTrapDoor = 6 +}; + +enum { + kAS39LeaveScene = 0 +}; + +/*****************************************************************************/ + +class GnapEngine; +class CutScene; + +class Scene30: public Scene { +public: + Scene30(GnapEngine *vm); + virtual ~Scene30() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _kidSequenceId; +}; + +class Scene31: public Scene { +public: + Scene31(GnapEngine *vm); + virtual ~Scene31() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + bool _beerGuyDistracted; + int _currClerkSequenceId; + int _nextClerkSequenceId; + int _clerkMeasureCtr; + int _clerkMeasureMaxCtr; +}; + +class Scene32: public Scene { +public: + Scene32(GnapEngine *vm); + virtual ~Scene32() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; +}; + +class Scene33: public Scene { +public: + Scene33(GnapEngine *vm); + virtual ~Scene33() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currChickenSequenceId; + int _nextChickenSequenceId; +}; + +class Scene38: public Scene { +public: + Scene38(GnapEngine *vm); + virtual ~Scene38() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; +}; + +class Scene39: public Scene { +public: + Scene39(GnapEngine *vm); + virtual ~Scene39() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currGuySequenceId; + int _nextGuySequenceId; +}; + +} // End of namespace Gnap + +#endif // GNAP_GROUP3_H diff --git a/engines/gnap/scenes/group4.cpp b/engines/gnap/scenes/group4.cpp new file mode 100644 index 0000000000..f37be2c25d --- /dev/null +++ b/engines/gnap/scenes/group4.cpp @@ -0,0 +1,2799 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/group4.h" + +namespace Gnap { + +Scene40::Scene40(GnapEngine *vm) : Scene(vm) { +} + +int Scene40::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + return _vm->isFlag(kGFUnk23) ? 0x01 : 0x00; +} + +void Scene40::updateHotspots() { + _vm->setHotspot(kHS40Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_DISABLED | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS40ExitCave, 169, 510, 264, 600, SF_EXIT_D_CURSOR, 0, 8); + _vm->setHotspot(kHS40ExitToyStand, 238, 297, 328, 376, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS40ExitBBQ, 328, 220, 401, 306, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS40ExitUfo, 421, 215, 501, 282, SF_EXIT_U_CURSOR, 0, 8); + _vm->setHotspot(kHS40ExitKissinBooth, 476, 284, 556, 345, SF_EXIT_R_CURSOR, 0, 8); + _vm->setHotspot(kHS40ExitDancefloor, 317, 455, 445, 600, SF_EXIT_D_CURSOR, 0, 8); + _vm->setHotspot(kHS40ExitShoe, 455, 346, 549, 417, SF_EXIT_D_CURSOR, 0, 8); + _vm->setDeviceHotspot(kHS40Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 9; +} + +void Scene40::run() { + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + _vm->endSceneInit(); + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) + _vm->playSound(0x1094B, true); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS40Device: + _vm->runMenu(); + updateHotspots(); + break; + + case kHS40Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS40ExitCave: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 39; + _vm->_sceneDone = true; + } + break; + + case kHS40ExitToyStand: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 41; + _vm->_sceneDone = true; + } + break; + + case kHS40ExitBBQ: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 42; + _vm->_sceneDone = true; + } + break; + + case kHS40ExitUfo: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 43; + _vm->_sceneDone = true; + } + break; + + case kHS40ExitKissinBooth: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 44; + _vm->_sceneDone = true; + } + break; + + case kHS40ExitDancefloor: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 45; + _vm->_sceneDone = true; + } + break; + + case kHS40ExitShoe: + if (gnap._actionStatus < 0) { + _vm->_newSceneNum = 46; + _vm->_sceneDone = true; + } + break; + + default: + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) + _vm->_mouseClickState._left = false; + break; + + } + + updateAnimations(); + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene40::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + if (gnap._actionStatus) + gnap._actionStatus = -1; + else + _vm->_sceneDone = true; + } +} + +/*****************************************************************************/ + +Scene41::Scene41(GnapEngine *vm) : Scene(vm) { + _currKidSequenceId = -1; + _nextKidSequenceId = -1; + _currToyVendorSequenceId = -1; + _nextToyVendorSequenceId = -1; +} + +int Scene41::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + return 0x129; +} + +void Scene41::updateHotspots() { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS41UfoExitLeft, 0, 0, 10, 500, SF_EXIT_L_CURSOR | SF_DISABLED); + _vm->setHotspot(kHS41UfoExitRight, 790, 0, 799, 500, SF_EXIT_R_CURSOR); + _vm->setHotspot(kHS41UfoWalkArea1, 0, 0, 800, 470, SF_DISABLED); + _vm->setDeviceHotspot(kHS41UfoDevice, -1, -1, -1, -1); + _vm->_hotspotsCount = 5; + } else { + _vm->setHotspot(kHS41Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS41ExitCave, 150, 590, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS41Exit, 0, 100, 10, 599, SF_EXIT_L_CURSOR | SF_DISABLED, 0, 8); + _vm->setHotspot(kHS41ExitBBQ, 790, 100, 799, 599, SF_EXIT_R_CURSOR | SF_WALKABLE, 10, 8); + _vm->setHotspot(kHS41ToyVendor, 320, 150, 430, 310, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS41Kid, 615, 340, 710, 460, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS41ToyUfo, 0, 0, 0, 0, SF_GRAB_CURSOR); + _vm->setHotspot(kHS41WalkArea1, 0, 0, 800, 470); + _vm->setDeviceHotspot(kHS41Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 9; + } +} + +void Scene41::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoX = 770; + if (_vm->_toyUfoY < 0 || _vm->_toyUfoY > 300) + _vm->_toyUfoY = 150; + if (!_vm->_timers[9]) + gnap._actionStatus = kAS41GiveBackToyUfo; + } else { + if (!_vm->isFlag(kGFUnk16) && !_vm->isFlag(kGFJointTaken) && !_vm->isFlag(kGFUnk18) && !_vm->isFlag(kGFGroceryStoreHatTaken)) + _vm->toyUfoSetStatus(kGFUnk16); + _vm->_toyUfoX = 600; + _vm->_toyUfoY = 200; + } + + _vm->_toyUfoId = 0; + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId(); + _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId; + + gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2); + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + gameSys.insertSequence(0x128, 0, 0, 0, kSeqLoop, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) + _currKidSequenceId = 0x11B; + else + _currKidSequenceId = 0x11D; + + _nextKidSequenceId = -1; + + gameSys.setAnimation(_currKidSequenceId, 1, 4); + gameSys.insertSequence(_currKidSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + _currToyVendorSequenceId = 0x118; + _nextToyVendorSequenceId = -1; + + gameSys.setAnimation(0x118, 1, 3); + gameSys.insertSequence(_currToyVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + gameSys.insertSequence(0x127, 2, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + gnap._sequenceId = 0x120; + gnap._sequenceDatNum = 0; + gnap._idleFacing = kDirUpRight; + gnap._pos = Common::Point(7, 7); + gnap._id = 140; + gameSys.insertSequence(0x120, 140, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + plat.initPos(8, 10, kDirBottomLeft); + _vm->endSceneInit(); + } else if (_vm->_prevSceneNum == 45) { + gnap.initPos(-1, 8, kDirUpRight); + plat.initPos(-2, 8, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + } else if (_vm->_prevSceneNum == 42) { + gnap.initPos(11, 8, kDirUpRight); + plat.initPos(11, 9, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1); + } else { + gnap.initPos(5, 8, kDirBottomRight); + plat.initPos(6, 8, kDirBottomLeft); + _vm->endSceneInit(); + } + + _vm->_timers[4] = _vm->getRandom(100) + 100; + _vm->_timers[5] = _vm->getRandom(30) + 20; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) + _vm->playSound(0x1094B, true); + + if (!_vm->isFlag(kGFGnapControlsToyUFO)) + _vm->_hotspots[kHS41ToyUfo]._rect = Common::Rect(_vm->_toyUfoX - 25, _vm->_toyUfoY - 20, _vm->_toyUfoX + 25, _vm->_toyUfoY + 20); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + switch (_vm->_sceneClickedHotspot) { + case kHS41UfoExitLeft: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene; + _vm->_newSceneNum = 45; + _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2); + } + break; + + case kHS41UfoExitRight: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = kAS41ToyUfoLeaveScene; + _vm->_newSceneNum = 42; + _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2); + } + break; + + case kHS41UfoDevice: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(100) + 100; + _vm->_timers[5] = _vm->getRandom(30) + 20; + break; + } + } else { + switch (_vm->_sceneClickedHotspot) { + case kHS41Device: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(100) + 100; + _vm->_timers[5] = _vm->getRandom(30) + 20; + break; + + case kHS41Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS41ExitCave: + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS41ExitCave], 0, 0x107AE, 1); + gnap._actionStatus = kAS41LeaveScene; + _vm->_newSceneNum = 40; + break; + + case kHS41Exit: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), 0, 0x107AF, 1); + gnap._actionStatus = kAS41LeaveScene; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41Exit].x, -1), -1, 0x107CF, 1); + _vm->_newSceneNum = 45; + break; + + case kHS41ExitBBQ: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), 0, 0x107AB, 1); + gnap._actionStatus = kAS41LeaveScene; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS41ExitBBQ].x, -1), -1, 0x107CD, 1); + _vm->_newSceneNum = 42; + break; + + case kHS41ToyVendor: + if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) { + gnap._actionStatus = kAS41UseQuarterWithToyVendor; + gnap.walkTo(Common::Point(4, 7), 0, 0x107BB, 9); + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(4, 7), 5, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(Common::Point(5, 0)); + break; + case GRAB_CURSOR: + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(4, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS41TalkToyVendor; + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS41Kid: + if (_vm->_grabCursorSpriteIndex == kItemChickenBucket) { + gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS41UseChickenBucketWithKid; + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(7, 7), 8, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(9, 0)); + break; + case GRAB_CURSOR: + gnap.walkTo(Common::Point(7, 7), 0, 0x107BB, 1); + gnap._idleFacing = kDirUpRight; + gnap._actionStatus = kAS41GrabKid; + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(7, 7), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS41ToyUfo: + if (_vm->_grabCursorSpriteIndex == kItemGum) { + gnap.playPullOutDevice(Common::Point(9, 0)); + gameSys.setAnimation(makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, 0); + gnap._actionStatus = kAS41UseGumWithToyUfo; + } + break; + + case kHS41WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + } + } + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + if (!_vm->_timers[9] && gnap._actionStatus < 0) { + gnap._actionStatus = kAS41GiveBackToyUfo; + if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x122) { + gameSys.insertSequence(0x123, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x123; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x123, gnap._id, 0); + } + } + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + _vm->_mouseClickState._left = false; + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + int sequenceId; + if (_vm->_leftClickMouseX >= 400) { + if (gnap._sequenceId == 0x11F || gnap._sequenceId == 0x120 || gnap._sequenceId == 0x123 || gnap._sequenceId == 0x126) + sequenceId = 0x120; + else if (_vm->_leftClickMouseX - _vm->_toyUfoX >= 400) + sequenceId = 0x126; + else + sequenceId = 0x123; + } else { + if (gnap._sequenceId == 0x121 || gnap._sequenceId == 0x125 || gnap._sequenceId == 0x122) + sequenceId = 0x122; + else if (_vm->_toyUfoX - _vm->_leftClickMouseX >= 400) + sequenceId = 0x125; + else + sequenceId = 0x121; + } + gameSys.insertSequence(sequenceId, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = sequenceId; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(sequenceId, gnap._id, 0); + _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + } + + updateAnimations(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(100) + 100; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextToyVendorSequenceId == -1) { + switch (_vm->getRandom(3)) { + case 0: + _nextToyVendorSequenceId = 0x113; + break; + case 1: + _nextToyVendorSequenceId = 0x117; + break; + case 2: + _nextToyVendorSequenceId = 0x119; + break; + } + if (_nextToyVendorSequenceId == _currToyVendorSequenceId) + _nextToyVendorSequenceId = -1; + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(30) + 20; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _vm->_toyUfoActionStatus == -1 && _nextKidSequenceId == -1) { + if (_vm->isFlag(kGFGnapControlsToyUFO)) + _nextKidSequenceId = 0x11B; + else if (_vm->getRandom(3) != 0) + _nextKidSequenceId = 0x11D; + else + _nextKidSequenceId = 0x11E; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(100) + 100; + _vm->_timers[5] = _vm->getRandom(30) + 20; + } + _vm->gameUpdateTick(); + } +} + +void Scene41::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + switch (gnap._actionStatus) { + case kAS41LeaveScene: + gameSys.setAnimation(0, 0, 0); + _vm->_sceneDone = true; + gnap._actionStatus = -1; + break; + case kAS41UseQuarterWithToyVendor: + gameSys.setAnimation(0, 0, 0); + _nextToyVendorSequenceId = 0x114; + gnap._actionStatus = -1; + break; + case kAS41TalkToyVendor: + gameSys.setAnimation(0, 0, 0); + _nextToyVendorSequenceId = 0x116; + gnap._actionStatus = -1; + break; + case kAS41UseGumWithToyUfo: + gameSys.setAnimation(0, 0, 0); + gnap.playUseDevice(Common::Point(9, 0)); + gnap._actionStatus = -1; + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemGum); + _vm->_toyUfoActionStatus = kAS41UfoGumAttached; + break; + case kAS41UseChickenBucketWithKid: + if (gameSys.getAnimationStatus(4) == 2) { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + _vm->setGrabCursorSprite(-1); + gameSys.insertSequence(0x11F, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x11F; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x11F, gnap._id, 0); + _nextKidSequenceId = 0x11A; + gameSys.insertSequence(0x11A, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextKidSequenceId, 1, 4); + _currKidSequenceId = _nextKidSequenceId; + _nextKidSequenceId = 0x11B; + _vm->_timers[5] = _vm->getRandom(30) + 20; + gnap._actionStatus = -1; + _vm->setFlag(kGFGnapControlsToyUFO); + updateHotspots(); + _vm->_timers[9] = 600; + } + break; + case kAS41GrabKid: + if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + gameSys.insertSequence(0x110, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x110; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x110, gnap._id, 0); + _nextToyVendorSequenceId = 0x111; + gameSys.insertSequence(0x111, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3); + _currToyVendorSequenceId = _nextToyVendorSequenceId; + _nextToyVendorSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(100) + 100; + _nextKidSequenceId = 0x10F; + gameSys.insertSequence(0x10F, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextKidSequenceId, 1, 4); + _currKidSequenceId = _nextKidSequenceId; + _nextKidSequenceId = -1; + _vm->_timers[5] = _vm->getRandom(30) + 20; + gnap._actionStatus = -1; + } + break; + case kAS41GiveBackToyUfo: + if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + gameSys.insertSequence(0x124, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x124; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x124, gnap._id, 0); + _nextToyVendorSequenceId = 0x112; + gameSys.insertSequence(0x112, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3); + _currToyVendorSequenceId = _nextToyVendorSequenceId; + _nextToyVendorSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(100) + 100; + _nextKidSequenceId = 0x11C; + gameSys.insertSequence(0x11C, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextKidSequenceId, 1, 4); + _currKidSequenceId = _nextKidSequenceId; + _nextKidSequenceId = -1; + _vm->_timers[5] = _vm->getRandom(30) + 20; + gnap._actionStatus = -1; + _vm->clearFlag(kGFGnapControlsToyUFO); + updateHotspots(); + } + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + switch (_vm->_toyUfoActionStatus) { + case kAS41ToyUfoLeaveScene: + _vm->_sceneDone = true; + break; + case kAS41UfoGumAttached: + _vm->_toyUfoNextSequenceId = 0x873; + gameSys.insertSequence(0x10873, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 365, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2); + _vm->toyUfoSetStatus(kGFJointTaken); + break; + default: + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + ++_vm->_toyUfoId; + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2); + break; + } + _vm->_toyUfoActionStatus = -1; + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextToyVendorSequenceId != -1) { + gameSys.insertSequence(_nextToyVendorSequenceId, 1, _currToyVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextToyVendorSequenceId, 1, 3); + _currToyVendorSequenceId = _nextToyVendorSequenceId; + _nextToyVendorSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(100) + 100; + } + + if (gameSys.getAnimationStatus(4) == 2 && _nextKidSequenceId != -1) { + gameSys.insertSequence(_nextKidSequenceId, 1, _currKidSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextKidSequenceId, 1, 4); + _currKidSequenceId = _nextKidSequenceId; + _nextKidSequenceId = -1; + _vm->_timers[5] = _vm->getRandom(30) + 20; + if (_currKidSequenceId == 0x11E) { + _vm->_toyUfoActionStatus = kAS41ToyUfoRefresh; + _vm->toyUfoFlyTo(_vm->getRandom(300) + 500, _vm->getRandom(225) + 75, 0, 799, 0, 300, 2); + } + } +} + +/*****************************************************************************/ + +Scene42::Scene42(GnapEngine *vm) : Scene(vm) { + _currBBQVendorSequenceId = -1; + _nextBBQVendorSequenceId = -1; +} + +int Scene42::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + if (_vm->isFlag(kGFPictureTaken) || (_vm->isFlag(kGFUnk18) && _vm->isFlag(kGFUnk23))) + return 0x153; + return 0x152; +} + +void Scene42::updateHotspots() { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS42UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR); + _vm->setHotspot(kHS42UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR); + _vm->setHotspot(kHS42UfoHotSauce, 335, 110, 440, 175, SF_DISABLED); + _vm->setDeviceHotspot(kHS42UfoDevice, -1, 534, -1, 599); + if ((_vm->isFlag(kGFPictureTaken) || _vm->isFlag(kGFUnk18)) && _vm->isFlag(kGFUnk23) && !_vm->isFlag(kGFUnk24)) + _vm->_hotspots[kHS42UfoHotSauce]._flags = SF_GRAB_CURSOR; + _vm->_hotspotsCount = 5; + } else { + _vm->setHotspot(kHS42Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS42ExitUfoParty, 150, 585, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS42ExitToyStand, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS42ExitUfo, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8); + _vm->setHotspot(kHS42BBQVendor, 410, 200, 520, 365, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 4, 8); + _vm->setHotspot(kHS42ChickenLeg, 530, 340, 620, 430, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 8, 7); + _vm->setHotspot(kHS42WalkArea1, 0, 0, 800, 445); + _vm->setHotspot(kHS42WalkArea2, 240, 0, 550, 495); + _vm->setDeviceHotspot(kHS42Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 9; + } +} + +void Scene42::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + + _currBBQVendorSequenceId = 0x14A; + _nextBBQVendorSequenceId = -1; + + gameSys.setAnimation(0x14A, 1, 2); + gameSys.insertSequence(_currBBQVendorSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoId = 0; + _vm->_toyUfoActionStatus = -1; + if (_vm->_prevSceneNum == 43 && _vm->isFlag(kGFUnk18)) { + _vm->_toyUfoSequenceId = 0x872; + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, 0, 0); + _vm->_toyUfoX = 317; + _vm->_toyUfoY = 61; + _vm->toyUfoSetStatus(kGFJointTaken); + _vm->setFlag(kGFPictureTaken); + _vm->_timers[9] = 600; + } else { + _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId(); + _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId; + if (_vm->_prevSceneNum == 41) + _vm->_toyUfoX = 30; + else + _vm->_toyUfoX = 770; + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + } + gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3); + _vm->endSceneInit(); + if (_vm->_toyUfoSequenceId == 0x872) + _vm->setGrabCursorSprite(-1); + } else if (_vm->_prevSceneNum == 41) { + gnap.initPos(-1, 8, kDirUpRight); + plat.initPos(-1, 9, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + } else if (_vm->_prevSceneNum == 43) { + gnap.initPos(11, 8, kDirUpRight); + plat.initPos(11, 9, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1); + } else { + gnap.initPos(5, 11, kDirUpRight); + plat.initPos(6, 11, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + } + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) + _vm->playSound(0x1094B, true); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + switch (_vm->_sceneClickedHotspot) { + case kHS42UfoExitLeft: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene; + _vm->_newSceneNum = 41; + _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3); + } + break; + + case kHS42UfoExitRight: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = kAS42ToyUfoLeaveScene; + _vm->_newSceneNum = 43; + _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3); + } + break; + + case kHS42UfoHotSauce: + if (_vm->isFlag(kGFJointTaken)) { + _vm->_toyUfoActionStatus = kAS42ToyUfoPickUpHotSauce; + _vm->toyUfoFlyTo(384, 77, 0, 799, 0, 300, 3); + _vm->_timers[9] = 600; + } else { + _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3); + } + break; + + case kHS42UfoDevice: + _vm->runMenu(); + updateHotspots(); + break; + } + } else { + switch (_vm->_sceneClickedHotspot) { + case kHS42Device: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 30; + break; + + case kHS42Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS42ExitUfoParty: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), 0, 0x107AE, 1); + gnap._actionStatus = kAS42LeaveScene; + plat.walkTo(Common::Point(plat._pos.x, _vm->_hotspotsWalkPos[kHS42ExitUfoParty].y), -1, 0x107C7, 1); + _vm->_newSceneNum = 40; + break; + + case kHS42ExitToyStand: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitToyStand].x, gnap._pos.y), 0, 0x107AF, 1); + gnap._actionStatus = kAS42LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitToyStand], -1, 0x107CF, 1); + _vm->_newSceneNum = 41; + break; + + case kHS42ExitUfo: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS42ExitUfo].x, gnap._pos.y), 0, 0x107AB, 1); + gnap._actionStatus = kAS42LeaveScene; + plat.walkTo(_vm->_hotspotsWalkPos[kHS42ExitUfo], -1, 0x107CD, 1); + _vm->_newSceneNum = 43; + break; + + case kHS42BBQVendor: + if (_vm->_grabCursorSpriteIndex == kItemDiceQuarterHole) { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, 0x107BB, 1); + gnap._actionStatus = kAS42UseQuarterWithBBQVendor; + if (plat._pos.y < 9) + plat.walkTo(Common::Point(plat._pos.x, 9), -1, -1, 1); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42BBQVendor], _vm->_hotspotsWalkPos[kHS42BBQVendor].x + 1, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42BBQVendor].x - 1, 0)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS42BBQVendor], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = kAS42TalkBBQVendor; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS42ChickenLeg: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS42ChickenLeg], _vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(_vm->_hotspotsWalkPos[kHS42ChickenLeg].x - 1, 0)); + break; + case GRAB_CURSOR: + gnap.walkTo(_vm->_hotspotsWalkPos[kHS42ChickenLeg], 0, 0x107BC, 1); + gnap._actionStatus = kAS42GrabChickenLeg; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS42WalkArea1: + case kHS42WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + } + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + _vm->_mouseClickState._left = false; + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoActionStatus = kAS42ToyUfoRefresh; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + } + + updateAnimations(); + + _vm->toyUfoCheckTimer(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 30; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextBBQVendorSequenceId == -1) { + switch (_vm->getRandom(8)) { + case 0: + _nextBBQVendorSequenceId = 0x14C; + break; + case 1: + case 2: + _nextBBQVendorSequenceId = 0x149; + break; + case 3: + case 4: + case 5: + case 6: + _nextBBQVendorSequenceId = 0x14D; + break; + case 7: + _nextBBQVendorSequenceId = 0x14A; + break; + } + if (_nextBBQVendorSequenceId == _currBBQVendorSequenceId && _nextBBQVendorSequenceId != 0x14D) + _nextBBQVendorSequenceId = -1; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 30; + } + + _vm->gameUpdateTick(); + } +} + +void Scene42::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + switch (gnap._actionStatus) { + case kAS42LeaveScene: + gameSys.setAnimation(0, 0, 0); + gnap._actionStatus = -1; + _vm->_sceneDone = true; + break; + case kAS42TalkBBQVendor: + gameSys.setAnimation(0, 0, 0); + gnap._actionStatus = -1; + _nextBBQVendorSequenceId = 0x14B; + break; + case kAS42UseQuarterWithBBQVendor: + case kAS42GrabChickenLeg: + if (gameSys.getAnimationStatus(2) == 2) { + int sequenceId; + if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor) { + _vm->invRemove(kItemDiceQuarterHole); + _vm->invAdd(kItemChickenBucket); + _vm->setGrabCursorSprite(-1); + sequenceId = 0x150; + _nextBBQVendorSequenceId = 0x148; + } else if (_vm->isFlag(kGFUnk27)) { + if (_vm->isFlag(kGFUnk28)) { + sequenceId = 0x7B7; + _nextBBQVendorSequenceId = 0x145; + } else { + _vm->setFlag(kGFUnk28); + sequenceId = 0x14F; + _nextBBQVendorSequenceId = 0x147; + } + } else { + _vm->setFlag(kGFUnk27); + sequenceId = 0x14E; + _nextBBQVendorSequenceId = 0x146; + } + if (sequenceId == 0x7B7) { + gameSys.insertSequence(0x107B7, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, _vm->getSequenceTotalDuration(_nextBBQVendorSequenceId), + 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + gnap._sequenceDatNum = 1; + } else { + gameSys.insertSequence(sequenceId, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 0, 0); + gnap._sequenceDatNum = 0; + } + gnap._sequenceId = sequenceId; + gameSys.setAnimation(sequenceId | (gnap._sequenceDatNum << 16), gnap._id, 0); + if (gnap._actionStatus == kAS42UseQuarterWithBBQVendor) + gnap._actionStatus = kAS42UseQuarterWithBBQVendorDone; + else + gnap._actionStatus = -1; + gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2); + _currBBQVendorSequenceId = _nextBBQVendorSequenceId; + if (_nextBBQVendorSequenceId == 0x145) + _nextBBQVendorSequenceId = 0x14A; + else + _nextBBQVendorSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(20) + 30; + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + } + break; + case kAS42UseQuarterWithBBQVendorDone: + gameSys.setAnimation(0, 0, 0); + _vm->setGrabCursorSprite(kItemChickenBucket); + gnap._actionStatus = -1; + break; + default: + gameSys.setAnimation(0, 0, 0); + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2 && _nextBBQVendorSequenceId != -1) { + gameSys.insertSequence(_nextBBQVendorSequenceId, 1, _currBBQVendorSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextBBQVendorSequenceId, 1, 2); + _currBBQVendorSequenceId = _nextBBQVendorSequenceId; + _nextBBQVendorSequenceId = -1; + _vm->_timers[4] = _vm->getRandom(20) + 30; + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_vm->_toyUfoActionStatus) { + case kAS42ToyUfoLeaveScene: + _vm->_sceneDone = true; + break; + case kAS42ToyUfoPickUpHotSauce: + gameSys.insertSequence(0x10870, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0); + _vm->setFlag(kGFUnk24); + updateHotspots(); + _vm->toyUfoSetStatus(kGFGroceryStoreHatTaken); + _vm->_toyUfoSequenceId = 0x870; + gameSys.setAnimation(0x10870, _vm->_toyUfoId, 3); + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoX = 0x181; + _vm->_toyUfoY = 53; + break; + default: + if (_vm->_toyUfoSequenceId == 0x872) { + _vm->hideCursor(); + _vm->addFullScreenSprite(0x13E, 255); + gameSys.setAnimation(0x151, 256, 0); + gameSys.insertSequence(0x151, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + _vm->removeFullScreenSprite(); + _vm->showCursor(); + } + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10, 3); + gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, (_vm->_toyUfoId + 1) % 10, + _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + _vm->_toyUfoId = (_vm->_toyUfoId + 1) % 10; + break; + } + _vm->_toyUfoActionStatus = -1; + } +} + +/*****************************************************************************/ + +Scene43::Scene43(GnapEngine *vm) : Scene(vm) { + _currTwoHeadedGuySequenceId = -1; + _nextTwoHeadedGuySequenceId = -1; +} + +int Scene43::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + return 0x13F; +} + +void Scene43::updateHotspots() { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS43UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR); + _vm->setHotspot(kHS43UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR); + _vm->setHotspot(kHS43UfoKey, 140, 170, 185, 260, SF_GRAB_CURSOR); + _vm->setHotspot(kHS43UfoBucket, 475, 290, 545, 365, SF_DISABLED); + _vm->setDeviceHotspot(kHS43UfoDevice, -1, 534, -1, 599); + if (_vm->isFlag(kGFGroceryStoreHatTaken)) + _vm->_hotspots[kHS43UfoBucket]._flags = SF_GRAB_CURSOR; + // NOTE Bug in the original. Key hotspot wasn't disabled. + if (_vm->isFlag(kGFUnk14)) + _vm->_hotspots[kHS43UfoKey]._flags = SF_DISABLED; + _vm->_hotspotsCount = 6; + } else { + _vm->setHotspot(kHS43Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS43ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS43ExitBBQ, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS43ExitKissinBooth, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8); + _vm->setHotspot(kHS43TwoHeadedGuy, 470, 240, 700, 470, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS43Key, 140, 170, 185, 260, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS43Ufo, 110, 0, 690, 350, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS43WalkArea1, 0, 0, 800, 445); + _vm->setHotspot(kHS43WalkArea2, 465, 0, 800, 493); + _vm->setDeviceHotspot(kHS43Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFUnk14)) + _vm->_hotspots[kHS43Key]._flags = SF_DISABLED; + _vm->_hotspotsCount = 10; + } +} + +void Scene43::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + + if (!_vm->isFlag(kGFUnk14)) + gameSys.insertSequence(0x1086F, 1, 0, 0, kSeqNone, 0, 0, 0); + + _currTwoHeadedGuySequenceId = 0x13C; + _nextTwoHeadedGuySequenceId = -1; + + gameSys.setAnimation(0x13C, 1, 2); + gameSys.insertSequence(_currTwoHeadedGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoId = 0; + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId(); + _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId; + if (_vm->_prevSceneNum == 42) + _vm->_toyUfoX = 30; + else + _vm->_toyUfoX = 770; + gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3); + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->endSceneInit(); + } else { + switch (_vm->_prevSceneNum) { + case 42: + gnap.initPos(-1, 8, kDirUpRight); + plat.initPos(-1, 9, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + break; + case 44: + gnap.initPos(11, 8, kDirUpRight); + plat.initPos(11, 9, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1); + break; + case 54: + gnap.initPos(4, 7, kDirBottomLeft); + plat.initPos(11, 8, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1); + break; + default: + gnap.initPos(5, 11, kDirUpRight); + plat.initPos(6, 11, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + break; + } + } + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) + _vm->playSound(0x1094B, true); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + switch (_vm->_sceneClickedHotspot) { + case kHS43UfoDevice: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(100) + 100; + break; + + case kHS43UfoExitLeft: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 4; + _vm->_newSceneNum = 42; + _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3); + } + break; + + case kHS43UfoExitRight: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 4; + _vm->_newSceneNum = 44; + _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3); + } + break; + + case kHS43UfoKey: + if (_vm->isFlag(kGFJointTaken)) { + _vm->_toyUfoActionStatus = 6; + _vm->toyUfoFlyTo(163, 145, 0, 799, 0, 300, 3); + } else { + _vm->_toyUfoActionStatus = 5; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3); + } + break; + + case kHS43UfoBucket: + _vm->_toyUfoActionStatus = 7; + _vm->toyUfoFlyTo(497, 143, 0, 799, 0, 300, 3); + _vm->_timers[9] = 600; + break; + } + } else { + switch (_vm->_sceneClickedHotspot) { + case kHS43Device: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(100) + 100; + break; + + case kHS43Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS43ExitUfoParty: + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], 0, 0x107AE, 1); + gnap._actionStatus = 0; + plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitUfoParty], -1, 0x107C7, 1); + _vm->_newSceneNum = 40; + break; + + case kHS43ExitBBQ: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitBBQ].x, gnap._pos.y), 0, 0x107AF, 1); + gnap._actionStatus = 0; + plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitBBQ], -1, 0x107CF, 1); + _vm->_newSceneNum = 42; + break; + + case kHS43ExitKissinBooth: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth].x, gnap._pos.y), 0, 0x107AB, 1); + gnap._actionStatus = 0; + plat.walkTo(_vm->_hotspotsWalkPos[kHS43ExitKissinBooth], -1, 0x107CD, 1); + _vm->_newSceneNum = 44; + break; + + case kHS43TwoHeadedGuy: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(6, 8), 7, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(7, 0)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(5, 8), 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = 2; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS43Key: + case kHS43Ufo: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(Common::Point(3, 7), 2, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(); + break; + case GRAB_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(Common::Point(3, 7), 0, 67515, 1); + gnap._actionStatus = 1; + break; + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS43WalkArea1: + case kHS43WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + } + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + _vm->_mouseClickState._left = false; + if (_vm->isFlag(kGFGnapControlsToyUFO) && (_vm->_toyUfoActionStatus == 5 || _vm->_toyUfoActionStatus == -1)) { + _vm->_toyUfoActionStatus = 5; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + } + + updateAnimations(); + + _vm->toyUfoCheckTimer(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + gnap.updateIdleSequence(); + if (!_vm->_timers[4] && (!_vm->isFlag(kGFGnapControlsToyUFO) || !_vm->isFlag(kGFGroceryStoreHatTaken))) { + _vm->_timers[4] = _vm->getRandom(100) + 100; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextTwoHeadedGuySequenceId == -1) { + switch (_vm->getRandom(5)) { + case 0: + _nextTwoHeadedGuySequenceId = 0x13C; + break; + case 1: + _nextTwoHeadedGuySequenceId = 0x134; + break; + case 2: + _nextTwoHeadedGuySequenceId = 0x135; + break; + case 3: + _nextTwoHeadedGuySequenceId = 0x136; + break; + case 4: + _nextTwoHeadedGuySequenceId = 0x13A; + break; + } + if (_nextTwoHeadedGuySequenceId == _currTwoHeadedGuySequenceId) + _nextTwoHeadedGuySequenceId = -1; + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(100) + 100; + } + + _vm->gameUpdateTick(); + } + + if (_vm->_newSceneNum == 54) + _vm->clearFlag(kGFGnapControlsToyUFO); +} + +void Scene43::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + switch (gnap._actionStatus) { + case 0: + gameSys.setAnimation(0, 0, 0); + _vm->_sceneDone = true; + break; + + case 1: + if (gameSys.getAnimationStatus(2) == 2) { + _vm->_timers[2] = _vm->getRandom(30) + 20; + _vm->_timers[3] = _vm->getRandom(50) + 200; + gameSys.insertSequence(0x13D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x13D; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x13D, gnap._id, 0); + _nextTwoHeadedGuySequenceId = 0x13B; + gameSys.insertSequence(0x13B, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2); + _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId; + _nextTwoHeadedGuySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(100) + 100; + gnap._actionStatus = -1; + } + break; + + default: + gameSys.setAnimation(0, 0, 0); + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + if (_currTwoHeadedGuySequenceId == 0x13A) { + if (_vm->isFlag(kGFGroceryStoreHatTaken)) { + _nextTwoHeadedGuySequenceId = 0x13E; + _vm->stopSound(0x108F6); + } else if (_vm->getRandom(2) != 0) { + _nextTwoHeadedGuySequenceId = 0x137; + } else { + _nextTwoHeadedGuySequenceId = 0x138; + } + } else if (_currTwoHeadedGuySequenceId == 0x13E) { + _vm->_sceneDone = true; + _vm->_newSceneNum = 54; + } + if (_nextTwoHeadedGuySequenceId != -1) { + gameSys.insertSequence(_nextTwoHeadedGuySequenceId, 1, _currTwoHeadedGuySequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextTwoHeadedGuySequenceId, 1, 2); + _currTwoHeadedGuySequenceId = _nextTwoHeadedGuySequenceId; + _nextTwoHeadedGuySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(100) + 100; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_vm->_toyUfoActionStatus) { + case 4: + _vm->_sceneDone = true; + _vm->_toyUfoActionStatus = -1; + break; + case 6: + gameSys.insertSequence(0x10871, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0); + gameSys.removeSequence(0x1086F, 1, true); + _vm->setFlag(kGFUnk14); + updateHotspots(); + _vm->toyUfoSetStatus(kGFUnk18); + _vm->_toyUfoSequenceId = 0x871; + gameSys.setAnimation(0x10871, _vm->_toyUfoId, 3); + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoX = 96; + _vm->_toyUfoY = 131; + break; + case 7: + gameSys.insertSequence(0x10874, _vm->_toyUfoId, _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, kSeqSyncWait, 0, 0, 0); + _vm->_toyUfoSequenceId = 0x874; + gameSys.setAnimation(0x10874, _vm->_toyUfoId, 3); + _vm->_toyUfoActionStatus = 8; + _vm->setFlag(kGFJointTaken); + gnap._actionStatus = 3; + break; + case 8: + _nextTwoHeadedGuySequenceId = 0x13A; + _vm->_toyUfoX = 514; + _vm->_toyUfoY = 125; + _vm->toyUfoFlyTo(835, 125, 0, 835, 0, 300, 3); + _vm->_toyUfoActionStatus = 9; + break; + case 9: + // Nothing + break; + default: + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, + _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + ++_vm->_toyUfoId; + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3); + _vm->_toyUfoActionStatus = -1; + break; + } + } +} + +/*****************************************************************************/ + +Scene44::Scene44(GnapEngine *vm) : Scene(vm) { + _nextSpringGuySequenceId = -1; + _nextKissingLadySequenceId = -1; + _currSpringGuySequenceId = -1; + _currKissingLadySequenceId = -1; +} + +int Scene44::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + gameSys.setAnimation(0, 0, 3); + return 0xFF; +} + +void Scene44::updateHotspots() { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS44UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR); + _vm->setHotspot(kHS44UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR); + _vm->setDeviceHotspot(kHS44UfoDevice, -1, 534, -1, 599); + _vm->_hotspotsCount = 4; + } else { + _vm->setHotspot(kHS44Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS44ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS44ExitUfo, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS44ExitShow, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8); + _vm->setHotspot(kHS44KissingLady, 300, 160, 400, 315, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 5, 7); + _vm->setHotspot(kHS44Spring, 580, 310, 635, 375, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8); + _vm->setHotspot(kHS44SpringGuy, 610, 375, 690, 515, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 7, 8); + _vm->setHotspot(kHS44WalkArea1, 0, 0, 800, 445); + _vm->setHotspot(kHS44WalkArea2, 617, 0, 800, 600); + _vm->setDeviceHotspot(kHS44Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFUnk13)) + _vm->_hotspots[kHS44KissingLady]._flags = SF_DISABLED; + if (_vm->isFlag(kGFSpringTaken)) + _vm->_hotspots[kHS44Spring]._flags = SF_DISABLED; + _vm->_hotspotsCount = 10; + } +} + +void Scene44::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(0xF7, 0, 0, 0, kSeqLoop, 0, 0, 0); + gameSys.insertSequence(0xFC, 256, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFSpringTaken)) + _currSpringGuySequenceId = 0xF8; + else + _currSpringGuySequenceId = 0xF9; + + _nextSpringGuySequenceId = -1; + gameSys.setAnimation(_currSpringGuySequenceId, 1, 4); + gameSys.insertSequence(_currSpringGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFUnk13)) { + if (_vm->_prevSceneNum != 50 || _vm->_sceneSavegameLoaded) { + _currKissingLadySequenceId = 0xF6; + _nextKissingLadySequenceId = -1; + } else { + _vm->setGrabCursorSprite(kItemGum); + _currKissingLadySequenceId = 0xF5; + _nextKissingLadySequenceId = 0xF6; + gameSys.setAnimation(0xF5, 1, 2); + } + } else { + _currKissingLadySequenceId = 0xEC; + _nextKissingLadySequenceId = -1; + gameSys.setAnimation(0xEC, 1, 2); + } + + gameSys.insertSequence(_currKissingLadySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoId = 0; + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId(); + _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId; + if (_vm->_prevSceneNum == 43) + _vm->_toyUfoX = 30; + else + _vm->_toyUfoX = 770; + gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 3); + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->endSceneInit(); + } else { + switch (_vm->_prevSceneNum) { + case 43: + gnap.initPos(-1, 8, kDirUpRight); + plat.initPos(-1, 7, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + break; + case 46: + gnap.initPos(11, 8, kDirUpRight); + plat.initPos(11, 8, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(7, 8), -1, 0x107D2, 1); + break; + case 50: + gnap.initPos(4, 8, kDirBottomRight); + if (_vm->_sceneSavegameLoaded) { + plat.initPos(_vm->_hotspotsWalkPos[4].x, _vm->_hotspotsWalkPos[4].y, kDirIdleRight); + } else if (!_vm->isFlag(kGFUnk13)) { + _vm->_timers[0] = 50; + _vm->_timers[1] = 20; + plat._pos = Common::Point(5, 8); + plat._sequenceId = 0xFD; + plat._idleFacing = kDirIdleLeft; + plat._id = 160; + plat._sequenceDatNum = 0; + gameSys.insertSequence(0xFD, 160, 0, 0, kSeqNone, 0, 0, 0); + } + _vm->endSceneInit(); + break; + default: + gnap.initPos(5, 11, kDirUpRight); + plat.initPos(6, 11, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(6, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(5, 8), -1, 0x107BA, 1); + break; + } + } + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) + _vm->playSound(0x1094B, true); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + switch (_vm->_sceneClickedHotspot) { + case kHS44UfoExitLeft: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 6; + _vm->_newSceneNum = 43; + _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 3); + } + break; + + case kHS44UfoExitRight: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 6; + _vm->_newSceneNum = 46; + _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 3); + } + break; + + case kHS44UfoDevice: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 20; + break; + } + } else if (_vm->_sceneClickedHotspot <= 9) { + switch (_vm->_sceneClickedHotspot) { + case kHS44Device: + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 20; + break; + + case kHS44Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS44ExitUfoParty: + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitUfoParty], 0, 0x107AE, 1); + gnap._actionStatus = 0; + _vm->_newSceneNum = 40; + break; + + case kHS44ExitUfo: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, gnap._pos.y), 0, 0x107AF, 1); + gnap._actionStatus = 0; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS44ExitUfo].x, plat._pos.y), -1, 0x107CF, 1); + _vm->_newSceneNum = 43; + break; + + case kHS44ExitShow: + _vm->_isLeavingScene = true; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS44ExitShow], 0, 0x107AB, 1); + gnap._actionStatus = 0; + _vm->_newSceneNum = 46; + break; + + case kHS44KissingLady: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap._actionStatus = 2; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, -1, 9); + gnap.playShowItem(_vm->_grabCursorSpriteIndex, _vm->_hotspotsWalkPos[kHS44KissingLady].x - 1, _vm->_hotspotsWalkPos[kHS44KissingLady].y); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(4, 3)); + break; + case GRAB_CURSOR: + gnap.playImpossible(); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS44KissingLady], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = 1; + break; + case PLAT_CURSOR: + gnap.useDeviceOnPlatypus(); + plat.walkTo(Common::Point(6, 7), 1, 0x107D2, 1); + if (gnap._pos == Common::Point(7, 7)) + gnap.walkStep(); + gnap.playIdle(Common::Point(5, 7)); + plat._actionStatus = 4; + break; + } + } + break; + + case kHS44Spring: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44Spring], 8, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(8, 7)); + break; + case GRAB_CURSOR: + gnap.playPullOutDevice(Common::Point(8, 0)); + gnap.playUseDevice(Common::Point(8, 0)); + _nextSpringGuySequenceId = 0xFB; + _vm->invAdd(kItemSpring); + _vm->setFlag(kGFSpringTaken); + updateHotspots(); + break; + case TALK_CURSOR: + gnap.playImpossible(); + break; + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS44SpringGuy: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS44SpringGuy], 8, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + if (_vm->isFlag(kGFSpringTaken)) + gnap.playMoan1(Common::Point(8, 7)); + else + gnap.playScratchingHead(Common::Point(8, 7)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS44SpringGuy], -1, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS44WalkArea1: + case kHS44WalkArea2: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + + } + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + _vm->_mouseClickState._left = false; + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoActionStatus = 7; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 3); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + } + + updateAnimations(); + _vm->toyUfoCheckTimer(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO) && _currKissingLadySequenceId != 0xF5) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(20) + 20; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextKissingLadySequenceId == -1) { + switch (_vm->getRandom(20)) { + case 0: + _nextKissingLadySequenceId = 0xED; + break; + case 1: + _nextKissingLadySequenceId = 0xEE; + break; + case 2: + _nextKissingLadySequenceId = 0xF0; + break; + case 3: + _nextKissingLadySequenceId = 0xF3; + break; + case 4: + _nextKissingLadySequenceId = 0xF4; + break; + default: + _nextKissingLadySequenceId = 0xEC; + break; + } + if (_nextKissingLadySequenceId != 0xEC && _nextKissingLadySequenceId == _currKissingLadySequenceId) + _nextKissingLadySequenceId = -1; + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(20) + 20; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSpringGuySequenceId == -1) { + if (_vm->getRandom(5) != 0) { + if (!_vm->isFlag(kGFSpringTaken)) + _nextSpringGuySequenceId = 0xF9; + } else { + if (_vm->isFlag(kGFSpringTaken)) + _nextSpringGuySequenceId = 0xF8; + else + _nextSpringGuySequenceId = 0xFA; + } + } + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + _vm->_timers[4] = _vm->getRandom(20) + 20; + } + + _vm->gameUpdateTick(); + } +} + +void Scene44::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case 0: + _vm->_sceneDone = true; + break; + case 1: + _nextKissingLadySequenceId = 0xEF; + break; + case 2: + _nextKissingLadySequenceId = 0xF2; + break; + } + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + switch (plat._actionStatus) { + case 4: + if (gameSys.getAnimationStatus(2) == 2) { + gameSys.insertSequence(0xFE, plat._id, plat._sequenceId | (plat._sequenceDatNum << 16), plat._id, kSeqSyncWait, 0, 0, 0); + plat._sequenceId = 0xFE; + plat._sequenceDatNum = 0; + gameSys.setAnimation(0xFE, plat._id, 1); + gameSys.removeSequence(_currKissingLadySequenceId, 1, true); + plat._actionStatus = 5; + } + break; + case 5: + _vm->_sceneDone = true; + _vm->_newSceneNum = 50; + break; + default: + plat._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(2) == 2) { + if (_nextKissingLadySequenceId == 0xF6) { + gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0); + plat.initPos(5, 8, kDirIdleLeft); + _currKissingLadySequenceId = _nextKissingLadySequenceId; + _nextKissingLadySequenceId = -1; + gameSys.setAnimation(0, 0, 2); + } else if (_nextKissingLadySequenceId != -1) { + gameSys.insertSequence(_nextKissingLadySequenceId, 1, _currKissingLadySequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextKissingLadySequenceId, 1, 2); + _currKissingLadySequenceId = _nextKissingLadySequenceId; + _nextKissingLadySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(20) + 20; + } + } + + if (gameSys.getAnimationStatus(4) == 2) { + if (_currSpringGuySequenceId == 0xFB) { + _vm->setGrabCursorSprite(kItemSpring); + _nextSpringGuySequenceId = 0xF8; + } + if (_nextSpringGuySequenceId != -1) { + gameSys.insertSequence(_nextSpringGuySequenceId, 1, _currSpringGuySequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextSpringGuySequenceId, 1, 4); + _currSpringGuySequenceId = _nextSpringGuySequenceId; + _nextSpringGuySequenceId = -1; + _vm->_timers[5] = _vm->getRandom(20) + 20; + } + } + + if (gameSys.getAnimationStatus(3) == 2) { + switch (_vm->_toyUfoActionStatus) { + case 6: + _vm->_sceneDone = true; + break; + default: + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, + _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + ++_vm->_toyUfoId; + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 3); + break; + } + _vm->_toyUfoActionStatus = -1; + } +} + +/*****************************************************************************/ + +Scene45::Scene45(GnapEngine *vm) : Scene(vm) { + _currDancerSequenceId = -1; +} + +int Scene45::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + gameSys.setAnimation(0, 0, 3); + gameSys.setAnimation(0, 0, 4); + gameSys.setAnimation(0, 0, 5); + return _vm->isFlag(kGFUnk23) ? 0xA2 : 0xA1; +} + +void Scene45::updateHotspots() { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS45UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR); + _vm->setHotspot(kHS45UfoExitRight, 794, 0, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED); + _vm->setDeviceHotspot(kHS45UfoDevice, -1, 534, -1, 599); + _vm->_hotspotsCount = 4; + } else { + _vm->setHotspot(kHS45Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS45ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS45ExitShoe, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS45ExitRight, 794, 100, 799, 599, SF_EXIT_R_CURSOR | SF_DISABLED, 10, 8); + _vm->setHotspot(kHS45ExitDiscoBall, 200, 0, 600, 10, SF_DISABLED); + _vm->setHotspot(kHS45DiscoBall, 370, 10, 470, 125, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 7); + _vm->setHotspot(kHS45WalkArea1, 0, 0, 800, 472); + _vm->setDeviceHotspot(kHS45Device, -1, -1, -1, -1); + if (_vm->isFlag(kGFUnk22)) { + _vm->_hotspots[kHS45Platypus]._flags = SF_DISABLED; + _vm->_hotspots[kHS45ExitUfoParty]._flags = SF_DISABLED; + _vm->_hotspots[kHS45ExitShoe]._flags = SF_DISABLED; + _vm->_hotspots[kHS45ExitRight]._flags = SF_DISABLED; + _vm->_hotspots[kHS45ExitDiscoBall]._flags = SF_EXIT_U_CURSOR; + } + if (_vm->isFlag(kGFUnk23) || _vm->isFlag(kGFUnk22)) + _vm->_hotspots[kHS45DiscoBall]._flags = SF_DISABLED; + _vm->_hotspotsCount = 8; + } +} + +void Scene45::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (!_vm->isSoundPlaying(0x1094A)) + _vm->playSound(0x1094A, true); + + _vm->queueInsertDeviceIcon(); + + gameSys.insertSequence(0x96, 1, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0x96, 1, 3); + gameSys.insertSequence(0x99, 1, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0x99, 1, 4); + _currDancerSequenceId = 0x8F; + gameSys.setAnimation(_currDancerSequenceId, 1, 2); + gameSys.insertSequence(_currDancerSequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoId = 0; + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId(); + _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId; + if (_vm->_prevSceneNum == 46) + _vm->_toyUfoX = 30; + else + _vm->_toyUfoX = 770; + gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 5); + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->endSceneInit(); + } else if (_vm->isFlag(kGFUnk22)) { + gnap._sequenceId = 0x9E; + gnap._sequenceDatNum = 0; + gnap._id = 1; + gameSys.setAnimation(0x9E, 1, 0); + gnap._actionStatus = 1; + gameSys.insertSequence(gnap._sequenceId, gnap._id, 0, 0, kSeqNone, 0, 0, 0); + plat.initPos(4, 8, kDirIdleLeft); + _vm->endSceneInit(); + } else if (_vm->_prevSceneNum == 46) { + gnap.initPos(-1, 8, kDirUpRight); + plat.initPos(-1, 9, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1); + } else if (_vm->_prevSceneNum == 41) { + gnap.initPos(11, 8, kDirUpRight); + plat.initPos(11, 9, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(4, 8), -1, 0x107D2, 1); + gnap.walkTo(Common::Point(10, 9), -1, 0x107BA, 1); + } else { + gnap.initPos(2, 11, kDirUpRight); + plat.initPos(6, 11, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(4, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 7), -1, 0x107B9, 1); + } + + if (!_vm->isFlag(kGFUnk21) && !_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setFlag(kGFUnk21); + _vm->setGrabCursorSprite(-1); + gameSys.setAnimation(0x9D, gnap._id, 0); + gameSys.insertSequence(0x9D, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) { + _vm->gameUpdateTick(); + if (gameSys.getAnimationStatus(2) == 2) { + gameSys.setAnimation(0, 0, 2); + int newSeqId = _vm->getRandom(7) + 0x8F; + gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(newSeqId, 1, 2); + _currDancerSequenceId = newSeqId; + } + if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) { + gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x96, 1, 3); + gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x99, 1, 4); + } + } + gnap._sequenceId = 0x9D; + gnap._sequenceDatNum = 0; + _vm->hideCursor(); + _vm->addFullScreenSprite(0x8A, 255); + gameSys.setAnimation(0xA0, 256, 0); + gameSys.insertSequence(0xA0, 256, 0, 0, kSeqNone, 0, 0, 0); + while (gameSys.getAnimationStatus(0) != 2 && !_vm->_gameDone) + _vm->gameUpdateTick(); + gameSys.setAnimation(0x107BD, gnap._id, 0); + gameSys.insertSequence(0x107BD, gnap._id, + makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, + kSeqSyncWait, 0, 75 * gnap._pos.x - gnap._gridX, 48 * gnap._pos.y - gnap._gridY); + _vm->removeFullScreenSprite(); + _vm->showCursor(); + gnap._sequenceId = 0x7BD; + gnap._sequenceDatNum = 1; + } + + plat.playSequence(0x9A); + gameSys.setAnimation(plat._sequenceId, plat._id, 1); + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094A)) + _vm->playSound(0x1094A, true); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + switch (_vm->_sceneClickedHotspot) { + case kHS45UfoExitLeft: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 2; + _vm->_newSceneNum = 46; + _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 5); + } + break; + + case kHS45UfoExitRight: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 2; + _vm->_newSceneNum = 41; + _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 5); + } + break; + + case kHS45UfoDevice: + _vm->runMenu(); + updateHotspots(); + break; + } + } else { + switch (_vm->_sceneClickedHotspot) { + case kHS45Device: + _vm->runMenu(); + updateHotspots(); + break; + + case kHS45Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + plat.playSequence(0x9A); + gameSys.setAnimation(plat._sequenceId, plat._id, 1); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS45ExitUfoParty: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS45ExitUfoParty].y), 0, 0x107AE, 1); + gnap._actionStatus = 0; + _vm->_newSceneNum = 40; + } + break; + + case kHS45ExitShoe: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, gnap._pos.y), 0, 0x107AF, 1); + gnap._actionStatus = 0; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitShoe].x, plat._pos.y), -1, 0x107CF, 1); + _vm->_newSceneNum = 46; + } + break; + + case kHS45ExitRight: + if (gnap._actionStatus < 0) { + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, gnap._pos.y), 0, 0x107AB, 1); + gnap._actionStatus = 0; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS45ExitRight].x, plat._pos.y), -1, 0x107CD, 1); + _vm->_newSceneNum = 41; + } + break; + + case kHS45ExitDiscoBall: + _vm->clearFlag(kGFUnk22); + _vm->setFlag(kGFUnk23); + _vm->_sceneDone = true; + _vm->_newSceneNum = 54; + break; + + case kHS45DiscoBall: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex == kItemSpring) { + gnap.walkTo(_vm->_hotspotsWalkPos[kHS45DiscoBall], 0, 0x9F, 5); + gnap._actionStatus = 1; + _vm->setGrabCursorSprite(-1); + _vm->invRemove(kItemSpring); + } else if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowItem(_vm->_grabCursorSpriteIndex, 5, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playScratchingHead(Common::Point(5, 0)); + break; + case GRAB_CURSOR: + case TALK_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + } + break; + + case kHS45WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + } + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + _vm->_mouseClickState._left = false; + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoActionStatus = 3; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 5); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + } + + updateAnimations(); + _vm->toyUfoCheckTimer(); + + if (!_vm->_isLeavingScene && gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + gnap.updateIdleSequence(); + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } + + _vm->_sceneWaiting = false; +} + +void Scene45::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case 0: + _vm->_sceneDone = true; + break; + case 1: + _vm->_sceneWaiting = true; + _vm->setFlag(kGFUnk22); + updateHotspots(); + gameSys.insertSequence(0x9E, gnap._id, makeRid(gnap._sequenceDatNum, gnap._sequenceId), gnap._id, kSeqSyncWait, 0, 0, 0); + gnap._sequenceId = 0x9E; + gnap._sequenceDatNum = 0; + gameSys.setAnimation(0x9E, gnap._id, 0); + break; + default: + gnap._actionStatus = -1; + break; + } + } + + if (gameSys.getAnimationStatus(1) == 2) { + gameSys.setAnimation(0, 0, 1); + if (_vm->getRandom(2) != 0) + plat.playSequence(0x9B); + else + plat.playSequence(0x9C); + gameSys.setAnimation(plat._sequenceId, plat._id, 1); + } + + if (gameSys.getAnimationStatus(2) == 2) { + gameSys.setAnimation(0, 0, 2); + int newSeqId = _vm->getRandom(7) + 0x8F; + gameSys.insertSequence(newSeqId, 1, _currDancerSequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(newSeqId, 1, 2); + _currDancerSequenceId = newSeqId; + } + + if (gameSys.getAnimationStatus(3) == 2 && gameSys.getAnimationStatus(4) == 2) { + gameSys.insertSequence(0x96, 1, 0x96, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x96, 1, 3); + gameSys.insertSequence(0x99, 1, 0x99, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(0x99, 1, 4); + } + + if (gameSys.getAnimationStatus(5) == 2) { + switch (_vm->_toyUfoActionStatus) { + case 2: + _vm->_sceneDone = true; + break; + default: + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, + _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + ++_vm->_toyUfoId; + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 5); + break; + } + _vm->_toyUfoActionStatus = -1; + } +} + +/*****************************************************************************/ + +Scene46::Scene46(GnapEngine *vm) : Scene(vm) { + _currSackGuySequenceId = -1; + _nextItchyGuySequenceId = -1; + _nextSackGuySequenceId = -1; + _currItchyGuySequenceId = -1; +} + +int Scene46::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + gameSys.setAnimation(0, 0, 2); + gameSys.setAnimation(0, 0, 3); + gameSys.setAnimation(0, 0, 4); + return 0x4E; +} + +void Scene46::updateHotspots() { + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_DISABLED); + _vm->setHotspot(kHS46UfoExitLeft, 0, 0, 10, 599, SF_EXIT_L_CURSOR); + _vm->setHotspot(kHS46UfoExitRight, 790, 0, 799, 599, SF_EXIT_R_CURSOR); + _vm->setDeviceHotspot(kHS46UfoDevice, -1, 534, -1, 599); + _vm->_hotspotsCount = 4; + } else { + _vm->setHotspot(kHS46Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS46ExitUfoParty, 150, 580, 650, 600, SF_EXIT_D_CURSOR | SF_WALKABLE, 5, 9); + _vm->setHotspot(kHS46ExitKissinBooth, 0, 100, 10, 599, SF_EXIT_L_CURSOR, 0, 8); + _vm->setHotspot(kHS46ExitDisco, 790, 100, 799, 599, SF_EXIT_R_CURSOR, 10, 8); + _vm->setHotspot(kHS46SackGuy, 180, 370, 235, 490, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 3, 8); + _vm->setHotspot(kHS46ItchyGuy, 535, 210, 650, 480, SF_PLAT_CURSOR | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR, 6, 8); + _vm->setHotspot(kHS46WalkArea1, 0, 0, 800, 485); + _vm->setDeviceHotspot(kHS46Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 8; + } +} + +void Scene46::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + PlayerPlat& plat = *_vm->_plat; + + _vm->queueInsertDeviceIcon(); + gameSys.insertSequence(0x4D, 0, 0, 0, kSeqLoop, 0, 0, 0); + + _currSackGuySequenceId = 0x4B; + _nextSackGuySequenceId = -1; + gameSys.setAnimation(0x4B, 1, 3); + gameSys.insertSequence(_currSackGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + _currItchyGuySequenceId = 0x47; + _nextItchyGuySequenceId = -1; + gameSys.setAnimation(0x47, 1, 4); + gameSys.insertSequence(_currItchyGuySequenceId, 1, 0, 0, kSeqNone, 0, 0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoId = 0; + _vm->_toyUfoActionStatus = -1; + _vm->_toyUfoSequenceId = _vm->toyUfoGetSequenceId(); + _vm->_toyUfoNextSequenceId = _vm->_toyUfoSequenceId; + if (_vm->_prevSceneNum == 44) + _vm->_toyUfoX = 30; + else + _vm->_toyUfoX = 770; + gameSys.setAnimation(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 2); + gameSys.insertSequence(_vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, 0, 0, kSeqNone, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->endSceneInit(); + } else if (_vm->_prevSceneNum == 44) { + gnap.initPos(-1, 8, kDirUpRight); + plat.initPos(-1, 8, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(1, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(2, 8), -1, 0x107B9, 1); + } else if (_vm->_prevSceneNum == 45) { + gnap.initPos(11, 8, kDirUpRight); + plat.initPos(12, 8, kDirUpLeft); + _vm->endSceneInit(); + gnap.walkTo(Common::Point(8, 8), -1, 0x107BA, 1); + plat.walkTo(Common::Point(9, 8), -1, 0x107D2, 1); + } else { + gnap.initPos(5, 11, kDirUpRight); + plat.initPos(6, 11, kDirUpLeft); + _vm->endSceneInit(); + plat.walkTo(Common::Point(5, 8), -1, 0x107C2, 1); + gnap.walkTo(Common::Point(6, 8), -1, 0x107BA, 1); + } + + _vm->_timers[4] = _vm->getRandom(50) + 80; + _vm->_timers[5] = _vm->getRandom(50) + 80; + + while (!_vm->_sceneDone) { + if (!_vm->isSoundPlaying(0x1094B)) + _vm->playSound(0x1094B, true); + + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + switch (_vm->_sceneClickedHotspot) { + case kHS46UfoExitLeft: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 3; + _vm->_newSceneNum = 44; + _vm->toyUfoFlyTo(-35, -1, -35, 799, 0, 300, 2); + } + break; + + case kHS46UfoExitRight: + if (_vm->_toyUfoActionStatus < 0) { + _vm->_isLeavingScene = true; + _vm->_toyUfoActionStatus = 3; + _vm->_newSceneNum = 45; + _vm->toyUfoFlyTo(835, -1, 0, 835, 0, 300, 2); + } + break; + + case kHS46UfoDevice: + _vm->runMenu(); + updateHotspots(); + break; + } + } else { + switch (_vm->_sceneClickedHotspot) { + case kHS46Device: + _vm->runMenu(); + updateHotspots(); + break; + + case kHS46Platypus: + if (gnap._actionStatus < 0) { + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playImpossible(plat._pos); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(plat._pos); + break; + case GRAB_CURSOR: + gnap.kissPlatypus(0); + break; + case TALK_CURSOR: + gnap.playBrainPulsating(plat._pos); + plat.playSequence(plat.getSequenceId()); + break; + case PLAT_CURSOR: + gnap.playImpossible(plat._pos); + break; + } + } + } + break; + + case kHS46SackGuy: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46SackGuy], 2, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46SackGuy].x + 1, 0)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpLeft; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS46SackGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = 2; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS46ItchyGuy: + if (_vm->_grabCursorSpriteIndex >= 0) { + gnap.playShowCurrItem(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 7, 0); + } else { + switch (_vm->_verbCursor) { + case LOOK_CURSOR: + gnap.playMoan1(Common::Point(_vm->_hotspotsWalkPos[kHS46ItchyGuy].x - 1, 0)); + break; + case TALK_CURSOR: + gnap._idleFacing = kDirUpRight; + gnap.walkTo(_vm->_hotspotsWalkPos[kHS46ItchyGuy], 0, gnap.getSequenceId(kGSBrainPulsating, Common::Point(0, 0)) | 0x10000, 1); + gnap._actionStatus = 1; + break; + case GRAB_CURSOR: + case PLAT_CURSOR: + gnap.playImpossible(); + break; + } + } + break; + + case kHS46ExitUfoParty: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(gnap._pos.x, _vm->_hotspotsWalkPos[kHS46ExitUfoParty].y), 0, 0x107AE, 1); + gnap._actionStatus = 0; + _vm->_newSceneNum = 40; + break; + + case kHS46ExitKissinBooth: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, gnap._pos.y), 0, 0x107AF, 1); + gnap._actionStatus = 0; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitKissinBooth].x, plat._pos.y), -1, 0x107CF, 1); + _vm->_newSceneNum = 44; + break; + + case kHS46ExitDisco: + _vm->_isLeavingScene = true; + gnap.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, gnap._pos.y), 0, 0x107AB, 1); + gnap._actionStatus = 0; + plat.walkTo(Common::Point(_vm->_hotspotsWalkPos[kHS46ExitDisco].x, plat._pos.y), -1, 0x107CD, 1); + _vm->_newSceneNum = 45; + break; + + case kHS46WalkArea1: + if (gnap._actionStatus < 0) + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + break; + } + } + + if (_vm->_mouseClickState._left && gnap._actionStatus < 0) { + _vm->_mouseClickState._left = false; + if (_vm->isFlag(kGFGnapControlsToyUFO)) { + _vm->_toyUfoActionStatus = 4; + _vm->toyUfoFlyTo(-1, -1, 0, 799, 0, 300, 2); + } else { + gnap.walkTo(Common::Point(-1, -1), -1, -1, 1); + } + } + + updateAnimations(); + _vm->toyUfoCheckTimer(); + + if (!_vm->_isLeavingScene) { + if (plat._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + plat.updateIdleSequence(); + if (gnap._actionStatus < 0 && !_vm->isFlag(kGFGnapControlsToyUFO)) + gnap.updateIdleSequence(); + if (!_vm->_timers[4]) { + _vm->_timers[4] = _vm->getRandom(50) + 80; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextItchyGuySequenceId == -1) { + if (_vm->getRandom(2) != 0) + _nextItchyGuySequenceId = 0x49; + else + _nextItchyGuySequenceId = 0x48; + } + } + if (!_vm->_timers[5]) { + _vm->_timers[5] = _vm->getRandom(50) + 80; + if (gnap._actionStatus < 0 && plat._actionStatus < 0 && _nextSackGuySequenceId == -1) + _nextSackGuySequenceId = 0x4C; + } + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + + _vm->gameUpdateTick(); + } +} + +void Scene46::updateAnimations() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (gameSys.getAnimationStatus(0) == 2) { + gameSys.setAnimation(0, 0, 0); + switch (gnap._actionStatus) { + case 0: + _vm->_sceneDone = true; + break; + case 1: + _nextItchyGuySequenceId = 0x46; + break; + case 2: + _nextSackGuySequenceId = 0x4A; + break; + } + gnap._actionStatus = -1; + } + + if (gameSys.getAnimationStatus(3) == 2 && _nextSackGuySequenceId != -1) { + gameSys.insertSequence(_nextSackGuySequenceId, 1, _currSackGuySequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextSackGuySequenceId, 1, 3); + _currSackGuySequenceId = _nextSackGuySequenceId; + _nextSackGuySequenceId = -1; + _vm->_timers[5] = _vm->getRandom(50) + 80; + } + + if (gameSys.getAnimationStatus(4) == 2 && _nextItchyGuySequenceId != -1) { + gameSys.insertSequence(_nextItchyGuySequenceId, 1, _currItchyGuySequenceId, 1, kSeqSyncWait, 0, 0, 0); + gameSys.setAnimation(_nextItchyGuySequenceId, 1, 4); + _currItchyGuySequenceId = _nextItchyGuySequenceId; + _nextItchyGuySequenceId = -1; + _vm->_timers[4] = _vm->getRandom(50) + 80; + } + + if (gameSys.getAnimationStatus(2) == 2) { + switch (_vm->_toyUfoActionStatus) { + case 3: + _vm->_sceneDone = true; + break; + default: + _vm->_toyUfoNextSequenceId = _vm->toyUfoGetSequenceId(); + gameSys.insertSequence(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId + 1, + _vm->_toyUfoSequenceId | 0x10000, _vm->_toyUfoId, + kSeqSyncWait, 0, _vm->_toyUfoX - 274, _vm->_toyUfoY - 128); + _vm->_toyUfoSequenceId = _vm->_toyUfoNextSequenceId; + ++_vm->_toyUfoId; + gameSys.setAnimation(_vm->_toyUfoNextSequenceId | 0x10000, _vm->_toyUfoId, 2); + break; + } + _vm->_toyUfoActionStatus = -1; + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/group4.h b/engines/gnap/scenes/group4.h new file mode 100644 index 0000000000..afcd62e9e7 --- /dev/null +++ b/engines/gnap/scenes/group4.h @@ -0,0 +1,298 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUP4_H +#define GNAP_GROUP4_H + +#include "gnap/debugger.h" + +namespace Gnap { + +enum { + kHS40Platypus = 0, + kHS40ExitCave = 1, + kHS40ExitToyStand = 2, + kHS40ExitBBQ = 3, + kHS40ExitUfo = 4, + kHS40ExitKissinBooth = 5, + kHS40ExitDancefloor = 6, + kHS40ExitShoe = 7, + kHS40Device = 8 +}; + +enum { + kHS41Platypus = 0, + kHS41ExitCave = 1, + kHS41Exit = 2, + kHS41ExitBBQ = 3, + kHS41ToyVendor = 4, + kHS41Kid = 5, + kHS41ToyUfo = 6, + kHS41Device = 7, + kHS41WalkArea1 = 8 +}; + +enum { + kHS41UfoExitLeft = 1, + kHS41UfoExitRight = 2, + kHS41UfoDevice = 3, + kHS41UfoWalkArea1 = 4 +}; + +enum { + kHS42Platypus = 0, + kHS42ExitUfoParty = 1, + kHS42ExitToyStand = 2, + kHS42ExitUfo = 3, + kHS42BBQVendor = 4, + kHS42ChickenLeg = 5, + kHS42Device = 6, + kHS42WalkArea1 = 7, + kHS42WalkArea2 = 8 +}; + +enum { + kHS42UfoExitLeft = 1, + kHS42UfoExitRight = 2, + kHS42UfoHotSauce = 3, + kHS42UfoDevice = 4 +}; + +enum { + kHS43Platypus = 0, + kHS43Device = 1, + kHS43ExitUfoParty = 2, + kHS43ExitBBQ = 3, + kHS43ExitKissinBooth = 4, + kHS43TwoHeadedGuy = 5, + kHS43Key = 6, + kHS43Ufo = 7, + kHS43WalkArea1 = 8, + kHS43WalkArea2 = 9 +}; + +enum { + kHS43UfoExitLeft = 1, + kHS43UfoExitRight = 2, + kHS43UfoKey = 3, + kHS43UfoBucket = 4, + kHS43UfoDevice = 5 +}; + +enum { + kHS44Platypus = 0, + kHS44ExitUfoParty = 1, + kHS44ExitUfo = 2, + kHS44ExitShow = 3, + kHS44KissingLady = 4, + kHS44Spring = 5, + kHS44SpringGuy = 6, + kHS44Device = 7, + kHS44WalkArea1 = 8, + kHS44WalkArea2 = 9 +}; + +enum { + kHS44UfoExitLeft = 1, + kHS44UfoExitRight = 2, + kHS44UfoDevice = 3 +}; + +enum { + kHS45Platypus = 0, + kHS45ExitUfoParty = 1, + kHS45ExitShoe = 2, + kHS45ExitRight = 3, + kHS45ExitDiscoBall = 4, + kHS45DiscoBall = 5, + kHS45Device = 6, + kHS45WalkArea1 = 7 +}; + +enum { + kHS45UfoExitLeft = 1, + kHS45UfoExitRight = 2, + kHS45UfoDevice = 3 +}; + +enum { + kHS46Platypus = 0, + kHS46ExitUfoParty = 1, + kHS46ExitKissinBooth = 2, + kHS46ExitDisco = 3, + kHS46SackGuy = 4, + kHS46ItchyGuy = 5, + kHS46Device = 6, + kHS46WalkArea1 = 7 +}; + +enum { + kHS46UfoExitLeft = 1, + kHS46UfoExitRight = 2, + kHS46UfoDevice = 3 +}; + +enum { + kAS41LeaveScene = 0, + kAS41UseQuarterWithToyVendor = 1, + kAS41TalkToyVendor = 2, + kAS41UseGumWithToyUfo = 3, + kAS41UseChickenBucketWithKid = 4, + kAS41GrabKid = 5, + kAS41GiveBackToyUfo = 6, + kAS41ToyUfoLeaveScene = 7, + kAS41ToyUfoRefresh = 8, + kAS41UfoGumAttached = 9 +}; + +enum { + kAS42LeaveScene = 0, + kAS42TalkBBQVendor = 1, + kAS42UseQuarterWithBBQVendor = 2, + kAS42UseQuarterWithBBQVendorDone = 3, + kAS42GrabChickenLeg = 4, + kAS42ToyUfoLeaveScene = 5, + kAS42ToyUfoRefresh = 6, + kAS42ToyUfoPickUpHotSauce = 7 +}; + +/*****************************************************************************/ + +class GnapEngine; +class CutScene; + +class Scene40: public Scene { +public: + Scene40(GnapEngine *vm); + virtual ~Scene40() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; +}; + +class Scene41: public Scene { +public: + Scene41(GnapEngine *vm); + virtual ~Scene41() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currKidSequenceId; + int _nextKidSequenceId; + int _currToyVendorSequenceId; + int _nextToyVendorSequenceId; +}; + +class Scene42: public Scene { +public: + Scene42(GnapEngine *vm); + virtual ~Scene42() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currBBQVendorSequenceId; + int _nextBBQVendorSequenceId; +}; + +class Scene43: public Scene { +public: + Scene43(GnapEngine *vm); + virtual ~Scene43() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currTwoHeadedGuySequenceId; + int _nextTwoHeadedGuySequenceId; +}; + +class Scene44: public Scene { +public: + Scene44(GnapEngine *vm); + virtual ~Scene44() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _nextSpringGuySequenceId; + int _nextKissingLadySequenceId; + int _currSpringGuySequenceId; + int _currKissingLadySequenceId; +}; + +class Scene45: public Scene { +public: + Scene45(GnapEngine *vm); + virtual ~Scene45() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currDancerSequenceId; +}; + +class Scene46: public Scene { +public: + Scene46(GnapEngine *vm); + virtual ~Scene46() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations(); + virtual void updateAnimationsCb() {}; + +private: + int _currSackGuySequenceId; + int _nextItchyGuySequenceId; + int _nextSackGuySequenceId; + int _currItchyGuySequenceId; +}; + +} // End of namespace Gnap + +#endif // GNAP_GROUP4_H diff --git a/engines/gnap/scenes/group5.cpp b/engines/gnap/scenes/group5.cpp new file mode 100644 index 0000000000..46f4c51e5d --- /dev/null +++ b/engines/gnap/scenes/group5.cpp @@ -0,0 +1,381 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/group5.h" + +namespace Gnap { + +Scene53::Scene53(GnapEngine *vm) : Scene(vm) { + _isGnapPhoning = false; + _currHandSequenceId = -1; + _callsMadeCtr = 0; + _callsRndUsed = 0; +} + +int Scene53::init() { + GameSys& gameSys = *_vm->_gameSys; + + gameSys.setAnimation(0, 0, 0); + gameSys.setAnimation(0, 0, 1); + return 0x75; +} + +void Scene53::updateHotspots() { + _vm->setHotspot(kHS53Platypus, 0, 0, 0, 0, SF_WALKABLE | SF_TALK_CURSOR | SF_GRAB_CURSOR | SF_LOOK_CURSOR); + _vm->setHotspot(kHS53PhoneKey1, 336, 238, 361, 270, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey2, 376, 243, 405, 274, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey3, 415, 248, 441, 276, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey4, 329, 276, 358, 303, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey5, 378, 282, 408, 311, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey6, 417, 286, 446, 319, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey7, 332, 311, 361, 342, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey8, 376, 318, 407, 349, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey9, 417, 320, 447, 353, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKey0, 377, 352, 405, 384, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKeySharp, 419, 358, 450, 394, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneKeyStar, 328, 346, 359, 379, SF_GRAB_CURSOR); + _vm->setHotspot(kHS53PhoneExit, 150, 585, 650, 600, SF_EXIT_D_CURSOR); + + _vm->setDeviceHotspot(kHS53Device, -1, -1, -1, -1); + _vm->_hotspotsCount = 15; +} + +int Scene53::pressPhoneNumberButton(int phoneNumber, int buttonNum) { + static const int kGnapHandSequenceIds[13] = { + 0x00, + 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x4F + }; + + static const int kPlatypusHandSequenceIds[13] = { + 0x00, + 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5A, 0x5C, 0x5D, 0x5B + }; + + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + if (_isGnapPhoning) { + gameSys.setAnimation(kGnapHandSequenceIds[buttonNum], 40, 6); + gameSys.insertSequence(kGnapHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currHandSequenceId = kGnapHandSequenceIds[buttonNum]; + } else { + gameSys.setAnimation(kPlatypusHandSequenceIds[buttonNum], 40, 6); + gameSys.insertSequence(kPlatypusHandSequenceIds[buttonNum], 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currHandSequenceId = kPlatypusHandSequenceIds[buttonNum]; + } + + gnap._actionStatus = 6; + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + gnap._actionStatus = -1; + + if (buttonNum < 11) + phoneNumber = buttonNum % 10 + 10 * phoneNumber; + + return phoneNumber; +} + +int Scene53::getRandomCallIndex() { + int index, tries = 0; + if (_callsRndUsed == 0x7FFF) + _callsRndUsed = 0; + do { + index = _vm->getRandom(16); + if (++tries == 300) + _callsRndUsed = 0; + } while (_callsRndUsed & (1 << index)); + _callsRndUsed |= (1 << index); + return index; +} + +void Scene53::runRandomCall() { + static const int kCallSequenceIds[15] = { + 0x60, 0x61, 0x62, 0x63, 0x64, + 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6A, 0x6B, 0x6C, 0x6D, 0x71 + }; + + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + ++_callsMadeCtr; + if (_callsMadeCtr <= 10) { + int index; + + do { + index = getRandomCallIndex(); + } while (!_isGnapPhoning && (index == 0 || index == 3 || index == 4 || index == 11)); + gameSys.setAnimation(kCallSequenceIds[index], 1, 6); + gameSys.insertSequence(kCallSequenceIds[index], 1, 0, 0, kSeqNone, 16, 0, 0); + } else { + gameSys.setAnimation(0x74, 1, 6); + gameSys.insertSequence(0x74, 1, 0, 0, kSeqNone, 16, 0, 0); + _callsMadeCtr = 0; + } + + gnap._actionStatus = 1; + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + gnap._actionStatus = -1; +} + +void Scene53::runChitChatLine() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + bool flag = false; + int sequenceId = -1; + + gameSys.setAnimation(0x6E, 1, 6); + gameSys.insertSequence(0x6E, 1, 0, 0, kSeqNone, 16, 0, 0); + + gnap._actionStatus = 1; + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + gnap._actionStatus = -1; + + if (_vm->isFlag(kGFSpringTaken)) { + gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currHandSequenceId = 0x45; + } else { + gameSys.insertSequence(0x45, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + _currHandSequenceId = 0x5E; + } + + _vm->_hotspots[kHS53Device]._flags = SF_DISABLED; + + while (!flag) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case 2: + sequenceId = 0x6F; + flag = 1; + break; + case 3: + sequenceId = 0x70; + flag = 1; + break; + case 4: + sequenceId = 0x71; + flag = 1; + break; + case 14: + sequenceId = -1; + flag = 1; + _vm->_isLeavingScene = true; + _vm->_sceneDone = true; + gnap._actionStatus = 0; + _vm->_newSceneNum = 17; + break; + case 5: + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1); + break; + } + + if (flag && sequenceId != -1) { + _vm->stopSound(0xA0); + pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1); + gnap._actionStatus = 1; + gameSys.setAnimation(sequenceId, 1, 6); + gameSys.insertSequence(sequenceId, 1, 0, 0, kSeqNone, 16, 0, 0); + gnap._actionStatus = 1; + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + gnap._actionStatus = -1; + gameSys.setAnimation(0x72, 1, 6); + gameSys.insertSequence(0x72, 1, 0, 0, kSeqNone, 16, 0, 0); + gnap._actionStatus = 1; + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + gnap._actionStatus = -1; + } + } + + updateHotspots(); + + gnap._actionStatus = 1; + + if (_vm->isFlag(kGFSpringTaken)) { + gameSys.setAnimation(0x73, 40, 6); + gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + _currHandSequenceId = 0x73; + gnap._actionStatus = -1; + } +} + +void Scene53::run() { + GameSys& gameSys = *_vm->_gameSys; + PlayerGnap& gnap = *_vm->_gnap; + + int phoneNumber = 0; + int phoneNumberLen = 0; + + _vm->queueInsertDeviceIcon(); + + if (_vm->isFlag(kGFSpringTaken)) { + _currHandSequenceId = 0x45; + _isGnapPhoning = true; + } else { + _currHandSequenceId = 0x5E; + _isGnapPhoning = false; + } + + gameSys.insertSequence(_currHandSequenceId, 40, 0, 0, kSeqNone, 0, 0, 0); + _vm->endSceneInit(); + _vm->setVerbCursor(GRAB_CURSOR); + _vm->playSound(0xA0, true); + + while (!_vm->_sceneDone) { + _vm->updateMouseCursor(); + _vm->updateCursorByHotspot(); + + _vm->testWalk(0, 0, -1, -1, -1, -1); + + _vm->_sceneClickedHotspot = _vm->getClickedHotspotId(); + _vm->updateGrabCursorSprite(0, 0); + + switch (_vm->_sceneClickedHotspot) { + case kHS53Device: + if (gnap._actionStatus < 0) { + _vm->runMenu(); + updateHotspots(); + } + break; + case kHS53PhoneKey1: + case kHS53PhoneKey2: + case kHS53PhoneKey3: + case kHS53PhoneKey4: + case kHS53PhoneKey5: + case kHS53PhoneKey6: + case kHS53PhoneKey7: + case kHS53PhoneKey8: + case kHS53PhoneKey9: + case kHS53PhoneKey0: + _vm->stopSound(0xA0); + ++phoneNumberLen; + phoneNumber = pressPhoneNumberButton(phoneNumber, _vm->_sceneClickedHotspot - 1); + debugC(kDebugBasic, "phoneNumber: %d", phoneNumber); + if (phoneNumberLen == 7) { + gnap._actionStatus = 1; + if (_vm->isFlag(kGFSpringTaken)) { + gameSys.setAnimation(0x73, 40, 6); + gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + _currHandSequenceId = 0x73; + gnap._actionStatus = -1; + } + if (phoneNumber == 7284141) { + runChitChatLine(); + phoneNumber = 0; + phoneNumberLen = 0; + _vm->_sceneDone = true; + _vm->_newSceneNum = 17; + } else if (phoneNumber != 5556789 || _vm->isFlag(kGFPictureTaken)) { + runRandomCall(); + phoneNumber = 0; + phoneNumberLen = 0; + _vm->_sceneDone = true; + _vm->_newSceneNum = 17; + } else { + phoneNumber = 0; + phoneNumberLen = 0; + _vm->_sceneDone = true; + _vm->_newSceneNum = 17; + if (_isGnapPhoning) + _vm->setFlag(kGFUnk25); + else + _vm->setFlag(kGFPlatypusTalkingToAssistant); + } + } + break; + case kHS53PhoneKeySharp: + case kHS53PhoneKeyStar: + pressPhoneNumberButton(0, _vm->_sceneClickedHotspot - 1); + break; + case kHS53PhoneExit: + if (gnap._actionStatus < 0) { + gnap._actionStatus = 1; + if (_vm->isFlag(kGFSpringTaken)) { + gameSys.setAnimation(0x73, 40, 6); + gameSys.insertSequence(0x73, 40, _currHandSequenceId, 40, kSeqSyncWait, 0, 0, 0); + while (gameSys.getAnimationStatus(6) != 2 && !_vm->_gameDone) { + _vm->updateMouseCursor(); + _vm->gameUpdateTick(); + } + _currHandSequenceId = 0x73; + gnap._actionStatus = -1; + } + _vm->_isLeavingScene = true; + _vm->_sceneDone = true; + gnap._actionStatus = 0; + _vm->_newSceneNum = 17; + } + break; + } + + _vm->checkGameKeys(); + + if (_vm->isKeyStatus1(Common::KEYCODE_BACKSPACE)) { + _vm->clearKeyStatus1(Common::KEYCODE_BACKSPACE); + _vm->runMenu(); + updateHotspots(); + } + _vm->gameUpdateTick(); + } +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/group5.h b/engines/gnap/scenes/group5.h new file mode 100644 index 0000000000..dd238ec65c --- /dev/null +++ b/engines/gnap/scenes/group5.h @@ -0,0 +1,77 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUP5_H +#define GNAP_GROUP5_H + +#include "gnap/debugger.h" +#include "gnap/scenes/scenecore.h" + +namespace Gnap { + +enum { + kHS53Platypus = 0, + kHS53Device = 1, + kHS53PhoneKey1 = 2, + kHS53PhoneKey2 = 3, + kHS53PhoneKey3 = 4, + kHS53PhoneKey4 = 5, + kHS53PhoneKey5 = 6, + kHS53PhoneKey6 = 7, + kHS53PhoneKey7 = 8, + kHS53PhoneKey8 = 9, + kHS53PhoneKey9 = 10, + kHS53PhoneKey0 = 11, + kHS53PhoneKeySharp = 12, + kHS53PhoneKeyStar = 13, + kHS53PhoneExit = 14 +}; + +/*****************************************************************************/ + +class GnapEngine; + +class Scene53: public Scene { +public: + Scene53(GnapEngine *vm); + virtual ~Scene53() {} + + virtual int init(); + virtual void updateHotspots(); + virtual void run(); + virtual void updateAnimations() {}; + virtual void updateAnimationsCb() {}; + +private: + bool _isGnapPhoning; + int _currHandSequenceId; + int _callsMadeCtr; + uint _callsRndUsed; + + int pressPhoneNumberButton(int phoneNumber, int buttonNum); + int getRandomCallIndex(); + void runRandomCall(); + void runChitChatLine(); +}; + +} // End of namespace Gnap +#endif // GNAP_GROUP5_H diff --git a/engines/gnap/scenes/groupcs.cpp b/engines/gnap/scenes/groupcs.cpp new file mode 100644 index 0000000000..c096eae27c --- /dev/null +++ b/engines/gnap/scenes/groupcs.cpp @@ -0,0 +1,430 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/groupcs.h" + + +namespace Gnap { + +Scene16::Scene16(GnapEngine *vm) : CutScene(vm) {} + +int Scene16::init() { + _sequenceIdArr[0] = 0x1F2; + _sequenceIdArr[1] = 0x201; + _sequenceIdArr[2] = 0x1FC; + _sequenceIdArr[3] = 0x1F4; + _sequenceIdArr[4] = 0x1FB; + _sequenceIdArr[5] = 0x1F0; + _sequenceIdArr[6] = 0x1FD; + _sequenceIdArr[7] = 0x1FE; + _sequenceIdArr[8] = 0x1F7; + _sequenceIdArr[9] = 0x1F9; + _sequenceIdArr[10] = 0x1F8; + _sequenceIdArr[11] = 0x1F1; + _sequenceIdArr[12] = 0x202; + _sequenceIdArr[13] = 0x1F6; + _sequenceIdArr[14] = 0x1F3; + _sequenceIdArr[15] = 0x1FA; + _sequenceIdArr[16] = 0x1FF; + _sequenceIdArr[17] = 0x200; + _sequenceIdArr[18] = 0x203; + _sequenceIdArr[19] = 0x206; + _sequenceIdArr[20] = 0x207; + _sequenceIdArr[21] = 0x204; + _sequenceIdArr[22] = 0x205; + _resourceIdArr[0] = 0x1C; + _resourceIdArr[1] = 2; + _resourceIdArr[2] = 0x1B; + _resourceIdArr[3] = 0; + _resourceIdArr[4] = 0x167; + _resourceIdArr[5] = 1; + _resourceIdArr[6] = 0x15B; + _resourceIdArr[7] = 0x15A; + _resourceIdArr[8] = 0x170; + _resourceIdArr[9] = 0x1EB; + _resourceIdArr[10] = 0x1EC; + _resourceIdArr[11] = 0x1BE; + _resourceIdArr[12] = 0x1BF; + _sequenceCountArr[0] = 4; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 1; + _sequenceCountArr[3] = 6; + _sequenceCountArr[4] = 1; + _sequenceCountArr[5] = 3; + _sequenceCountArr[6] = 1; + _sequenceCountArr[7] = 1; + _sequenceCountArr[8] = 1; + _sequenceCountArr[9] = 1; + _sequenceCountArr[10] = 1; + _sequenceCountArr[11] = 1; + _sequenceCountArr[12] = 1; + _itemsCount = 13; + + return -1; +} + +/*****************************************************************************/ + +Scene471::Scene471(GnapEngine *vm) : CutScene(vm) {} + +int Scene471::init() { + _sequenceIdArr[0] = 0x301; + _sequenceIdArr[1] = 0x305; + _sequenceIdArr[2] = 0x302; + _sequenceIdArr[3] = 0x304; + _sequenceIdArr[4] = 0x300; + _resourceIdArr[0] = 3; + _resourceIdArr[1] = 0; + _resourceIdArr[2] = 1; + _resourceIdArr[3] = 0; + _resourceIdArr[4] = 2; + _sequenceCountArr[0] = 1; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 1; + _sequenceCountArr[3] = 1; + _sequenceCountArr[4] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _canSkip[3] = false; + _canSkip[4] = false; + _itemsCount = 5; + + return -1; +} + +Scene472::Scene472(GnapEngine *vm) : CutScene(vm) {} + +int Scene472::init() { + _sequenceIdArr[0] = 0x306; + _sequenceIdArr[1] = 0x309; + _sequenceIdArr[2] = 0x307; + _sequenceIdArr[3] = 0x308; + _sequenceIdArr[4] = 0x30A; + _resourceIdArr[0] = 0x8E; + _resourceIdArr[1] = 0x90; + _resourceIdArr[2] = 0x8F; + _resourceIdArr[3] = 0x91; + _sequenceCountArr[0] = 2; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 1; + _sequenceCountArr[3] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _canSkip[3] = false; + _itemsCount = 4; + + return -1; +} + +Scene473::Scene473(GnapEngine *vm) : CutScene(vm) {} + +int Scene473::init() { + _sequenceIdArr[0] = 0x320; + _sequenceIdArr[1] = 0x321; + _resourceIdArr[0] = 0x142; + _resourceIdArr[1] = 0x143; + _sequenceCountArr[0] = 1; + _sequenceCountArr[1] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _itemsCount = 2; + + return -1; +} + +Scene474::Scene474(GnapEngine *vm) : CutScene(vm) {} + +int Scene474::init() { + _sequenceIdArr[0] = 0x30C; + _sequenceIdArr[1] = 0x30D; + _sequenceIdArr[2] = 0x30B; + _resourceIdArr[0] = 0x142; + _resourceIdArr[1] = 0x141; + _resourceIdArr[2] = 0x177; + _sequenceCountArr[0] = 1; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _itemsCount = 3; + + return -1; +} + +Scene475::Scene475(GnapEngine *vm) : CutScene(vm) {} + +int Scene475::init() { + _sequenceIdArr[0] = 0x30E; + _sequenceIdArr[1] = 0x30F; + _sequenceIdArr[2] = 0x310; + _sequenceIdArr[3] = 0x311; + _resourceIdArr[0] = 0x206; + _resourceIdArr[1] = 0x207; + _sequenceCountArr[0] = 3; + _sequenceCountArr[1] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _itemsCount = 2; + + return -1; +} + +Scene476::Scene476(GnapEngine *vm) : CutScene(vm) {} + +int Scene476::init() { + _sequenceIdArr[0] = 0x31E; + _sequenceIdArr[1] = 0x31F; + _resourceIdArr[0] = 0x2FA; + _sequenceCountArr[0] = 2; + _canSkip[0] = false; + _itemsCount = 1; + + return -1; +} + +Scene477::Scene477(GnapEngine *vm) : CutScene(vm) {} + +int Scene477::init() { + int v0, v4, v2, v3; + + _sequenceIdArr[0] = 0x316; + _sequenceIdArr[1] = 0x31A; + _sequenceIdArr[2] = 0x314; + _sequenceIdArr[3] = 0x31B; + int v1 = 4; + if (!_vm->isFlag(kGFTwigTaken)) { + _sequenceIdArr[4] = 0x31C; + v1 = 5; + } + if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) + _sequenceIdArr[v1++] = 0x31D; + v4 = v1; + _sequenceIdArr[v1] = 0x319; + v0 = v1 + 1; + v3 = v0; + _sequenceIdArr[v0++] = 0x317; + _sequenceIdArr[v0++] = 0x312; + _sequenceIdArr[v0] = 0x31A; + v2 = v0 + 1; + if (!_vm->isFlag(kGFTwigTaken)) + _sequenceIdArr[v2++] = 0x31C; + if (!_vm->isFlag(kGFPlatypusTalkingToAssistant)) + _sequenceIdArr[v2++] = 0x31D; + _sequenceIdArr[v2] = 0x313; + _sequenceIdArr[v2 + 1] = 0x315; + _resourceIdArr[0] = 0x2B8; + _resourceIdArr[1] = 0x20C; + _resourceIdArr[2] = 0x2B8; + _resourceIdArr[3] = 0x20B; + _resourceIdArr[4] = 0x20B; + _sequenceCountArr[0] = v4; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = v2 - v3; + _sequenceCountArr[3] = 1; + _sequenceCountArr[4] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _canSkip[3] = false; + _canSkip[4] = false; + _itemsCount = 5; + + return -1; +} + +/*****************************************************************************/ + +Scene48::Scene48(GnapEngine *vm) : CutScene(vm) {} + +int Scene48::init() { + _sequenceIdArr[0] = 390; + _sequenceIdArr[1] = 391; + _sequenceIdArr[2] = 392; + _sequenceIdArr[3] = 393; + _sequenceIdArr[4] = 394; + _sequenceIdArr[5] = 395; + _sequenceIdArr[6] = 396; + _sequenceIdArr[7] = 397; + _sequenceIdArr[8] = 398; + _sequenceIdArr[9] = 399; + _sequenceIdArr[10] = 400; + _sequenceIdArr[11] = 401; + _sequenceIdArr[12] = 402; + _resourceIdArr[0] = 238; + _resourceIdArr[1] = 42; + _resourceIdArr[2] = 2; + _resourceIdArr[3] = 37; + _resourceIdArr[4] = 35; + _resourceIdArr[5] = 38; + _resourceIdArr[6] = 39; + _resourceIdArr[7] = 40; + _resourceIdArr[8] = 41; + _resourceIdArr[9] = 36; + _resourceIdArr[10] = 41; + _resourceIdArr[11] = 388; + _resourceIdArr[12] = 387; + _sequenceCountArr[0] = 1; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 1; + _sequenceCountArr[3] = 1; + _sequenceCountArr[4] = 1; + _sequenceCountArr[5] = 1; + _sequenceCountArr[6] = 1; + _sequenceCountArr[7] = 1; + _sequenceCountArr[8] = 1; + _sequenceCountArr[9] = 1; + _sequenceCountArr[10] = 1; + _sequenceCountArr[11] = 1; + _sequenceCountArr[12] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _canSkip[3] = false; + _canSkip[4] = false; + _canSkip[5] = false; + _canSkip[6] = false; + _canSkip[7] = false; + _canSkip[8] = false; + _canSkip[9] = false; + _canSkip[10] = false; + _canSkip[11] = false; + _canSkip[12] = false; + _itemsCount = 13; + + return -1; +} + +/*****************************************************************************/ + +Scene541::Scene541(GnapEngine *vm) : CutScene(vm) {} + +int Scene541::init() { + _sequenceIdArr[0] = 0x1BE; + _sequenceIdArr[1] = 0x1BF; + _sequenceIdArr[2] = 0x1BA; + _sequenceIdArr[3] = 0x1BB; + _sequenceIdArr[4] = 0x1BD; + _sequenceIdArr[5] = 0x1BC; + _resourceIdArr[0] = 0x3C; + _resourceIdArr[1] = 0x43; + _resourceIdArr[2] = 0x44; + if (_vm->isFlag(kGFPictureTaken)) + _resourceIdArr[3] = 0x47; + else + _resourceIdArr[3] = 0x46; + _resourceIdArr[4] = 0x45; + _sequenceCountArr[0] = 1; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 1; + _sequenceCountArr[3] = 2; + _sequenceCountArr[4] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _canSkip[3] = false; + _canSkip[4] = false; + _itemsCount = 5; + + return -1; +} + +Scene542::Scene542(GnapEngine *vm) : CutScene(vm) {} + +int Scene542::init() { + _sequenceIdArr[0] = 0x1C9; + _sequenceIdArr[1] = 0x1C7; + _sequenceIdArr[2] = 0x1CC; + _sequenceIdArr[3] = 0x1C8; + _sequenceIdArr[4] = 0x1CB; + _sequenceIdArr[5] = 0x1C0; + _sequenceIdArr[6] = 0x1CA; + _sequenceIdArr[7] = 0x1CE; + _sequenceIdArr[8] = 0x1CD; + _sequenceIdArr[9] = 0x1C1; + _sequenceIdArr[10] = 0x1C2; + _sequenceIdArr[11] = 0x1C3; + _sequenceIdArr[12] = 0x1C4; + _sequenceIdArr[13] = 0x1C6; + _sequenceIdArr[14] = 0x1C5; + _sequenceIdArr[15] = 0x1D0; + _sequenceIdArr[16] = 0x1D0; + _sequenceIdArr[17] = 0x1D0; + _resourceIdArr[0] = 0xD5; + _resourceIdArr[1] = 0x14C; + _resourceIdArr[2] = 0xD5; + _resourceIdArr[3] = 0xBF; + _resourceIdArr[4] = 0xD6; + _resourceIdArr[5] = 0x154; + _resourceIdArr[6] = 0x155; + _resourceIdArr[7] = 0xB9; + _resourceIdArr[8] = 0xBA; + _resourceIdArr[9] = 0x17B; + _resourceIdArr[10] = 0x17A; + _resourceIdArr[11] = 0x17C; + _resourceIdArr[12] = 0x17A; + _resourceIdArr[13] = 0x1B7; + _resourceIdArr[14] = 0x1B8; + _resourceIdArr[15] = 0x1B9; + _sequenceCountArr[0] = 2; + _sequenceCountArr[1] = 1; + _sequenceCountArr[2] = 2; + _sequenceCountArr[3] = 1; + _sequenceCountArr[4] = 1; + _sequenceCountArr[5] = 1; + _sequenceCountArr[6] = 1; + _sequenceCountArr[7] = 1; + _sequenceCountArr[8] = 1; + _sequenceCountArr[9] = 1; + _sequenceCountArr[10] = 1; + _sequenceCountArr[11] = 1; + _sequenceCountArr[12] = 1; + _sequenceCountArr[13] = 1; + _sequenceCountArr[14] = 1; + _sequenceCountArr[15] = 1; + _canSkip[0] = false; + _canSkip[1] = false; + _canSkip[2] = false; + _canSkip[3] = false; + _canSkip[4] = false; + _canSkip[5] = false; + _canSkip[6] = false; + _canSkip[7] = false; + _canSkip[8] = false; + _canSkip[9] = false; + _canSkip[10] = false; + _canSkip[11] = false; + _canSkip[12] = false; + _canSkip[13] = true; + _canSkip[14] = true; + _canSkip[15] = false; + _itemsCount = 16; + + return -1; +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/groupcs.h b/engines/gnap/scenes/groupcs.h new file mode 100644 index 0000000000..58033564ce --- /dev/null +++ b/engines/gnap/scenes/groupcs.h @@ -0,0 +1,122 @@ +/* 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. + * + */ + +#ifndef GNAP_GROUPCS_H +#define GNAP_GROUPCS_H + +#include "gnap/debugger.h" + +namespace Gnap { + +class GnapEngine; +class CutScene; + +class Scene16: public CutScene { +public: + Scene16(GnapEngine *vm); + virtual ~Scene16() {} + + virtual int init(); +}; + +class Scene471: public CutScene { +public: + Scene471(GnapEngine *vm); + virtual ~Scene471() {} + + virtual int init(); +}; + +class Scene472: public CutScene { +public: + Scene472(GnapEngine *vm); + virtual ~Scene472() {} + + virtual int init(); +}; + +class Scene473: public CutScene { +public: + Scene473(GnapEngine *vm); + virtual ~Scene473() {} + + virtual int init(); +}; + +class Scene474: public CutScene { +public: + Scene474(GnapEngine *vm); + virtual ~Scene474() {} + + virtual int init(); +}; + +class Scene475: public CutScene { +public: + Scene475(GnapEngine *vm); + virtual ~Scene475() {} + + virtual int init(); +}; + +class Scene476: public CutScene { +public: + Scene476(GnapEngine *vm); + virtual ~Scene476() {} + + virtual int init(); +}; + +class Scene477: public CutScene { +public: + Scene477(GnapEngine *vm); + virtual ~Scene477() {} + + virtual int init(); +}; + +class Scene48: public CutScene { +public: + Scene48(GnapEngine *vm); + virtual ~Scene48() {} + + virtual int init(); +}; + +class Scene541: public CutScene { +public: + Scene541(GnapEngine *vm); + virtual ~Scene541() {} + + virtual int init(); +}; + +class Scene542: public CutScene { +public: + Scene542(GnapEngine *vm); + virtual ~Scene542() {} + + virtual int init(); +}; +} // End of namespace Gnap + +#endif // GNAP_GROUPCS_H diff --git a/engines/gnap/scenes/intro.cpp b/engines/gnap/scenes/intro.cpp new file mode 100644 index 0000000000..b4ba2f5201 --- /dev/null +++ b/engines/gnap/scenes/intro.cpp @@ -0,0 +1,182 @@ +/* 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. + * + */ + +#include "video/avi_decoder.h" + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" +#include "gnap/scenes/intro.h" + +namespace Gnap { + +SceneIntro::SceneIntro(GnapEngine *vm) : Scene(vm) { +} + +int SceneIntro::init() { + return 0x37C; +} + +void SceneIntro::run() { + const int animIdArr[] = { + 0x356, 0x357, 0x358, 0x35A, 0x35F, + 0x360, 0x361, 0x362, 0x363, 0x364, + 0x365, 0x368, 0x369, 0x36B, 0x378, + 0x36C, 0x36D, 0x36E, 0x36F, 0x370, + 0x371, 0x372, 0x373, 0x374, 0x375, + 0x376, 0x377, 0x378, 0x379, 0x37A, + 0x37B, 0}; + + const int backgroundIdArr[] = { + 0x354, 0x355, 0, 1, 3, + 4, 5, 6, 7, 8, + 7, 9, 0xA, 0xB, 0xC, + 0xD, 0xE, 0xF, 0x10, 0x11, + 0x12, 0x13, 0x17, 0x14, 0x19, + 0x1A, 0x14, 0x15, 0x16, 0x14, + 0x19, 0}; + + GameSys& gameSys = *_vm->_gameSys; + int index = 0; + bool skip = false; + + _vm->hideCursor(); + _vm->_dat->open(1, "musop_n.dat"); + + Video::VideoDecoder *videoDecoder = new Video::AVIDecoder(); + if (!videoDecoder->loadFile("hoffman.avi")) { + delete videoDecoder; + warning("Unable to open video 'hoffman.avi' - Skipping intro"); + return; + } + videoDecoder->start(); + + int vidPosX = (800 - videoDecoder->getWidth()) / 2; + int vidPosY = (600 - videoDecoder->getHeight()) / 2; + bool skipVideo = false; + + _vm->screenEffect(1, 255, 255, 255); + + while (!_vm->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { + if (videoDecoder->needsUpdate()) { + const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); + if (frame) { + if (frame->format.bytesPerPixel == 1) { + _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, vidPosX, vidPosY, frame->w, frame->h); + } else if (frame->format.bytesPerPixel != 4) { + Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat()); + _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h); + frame1->free(); + delete frame1; + } else { + // The intro AVI is played upside down, it's the only video played in the English version + for (uint16 y = 0; y < frame->h / 2; y++) { + uint32 *ptrFrom = (uint32 *)frame->getBasePtr(0, y); + uint32 *ptrTo = (uint32 *)frame->getBasePtr(0, frame->h - y - 1); + for (uint16 x = 0; x < frame->w; x++) { + uint32 t = *ptrFrom; + *ptrFrom = *ptrTo; + *ptrTo = t; + ptrFrom++; + ptrTo++; + } + } + + Graphics::Surface *frame1 = frame->convertTo(_vm->_system->getScreenFormat()); + _vm->_system->copyRectToScreen(frame1->getPixels(), frame1->pitch, vidPosX, vidPosY, frame1->w, frame1->h); + frame1->free(); + delete frame1; + } + _vm->_system->updateScreen(); + } + } + + Common::Event event; + while (g_system->getEventManager()->pollEvent(event)) { + if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || + event.type == Common::EVENT_LBUTTONUP) + skipVideo = true; + } + + _vm->_system->delayMillis(10); + } + + delete videoDecoder; + + gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]); + gameSys.insertSequence(0x356, 2, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(0x356, 2, 0); + + while (!_vm->_sceneDone) { + _vm->gameUpdateTick(); + + if (gameSys.getAnimationStatus(0) == 2 || skip ) { + skip = false; + gameSys.requestClear2(false); + gameSys.requestClear1(); + if ( index == 11 || index == 1 ) + _vm->screenEffect(0, 0, 0, 0); + + gameSys.setAnimation(0, 0, 0); + if (++index >= 31) + _vm->_sceneDone = true; + else { + gameSys.insertSequence(animIdArr[index], 2, 0, 0, kSeqNone, 0, 0, 0); + if (index == 2) { + _vm->playSound(0x10000, false); + gameSys.insertSequence(0x359, 2, 0, 0, 0, 0, 0, 0); + } else if (index == 3) + gameSys.insertSequence(0x35B, 2, 0, 0, kSeqNone, 0, 0, 0); + else if (index == 12) + gameSys.insertSequence(0x36A, 2, 0, 0, kSeqNone, 0, 0, 0); + + gameSys.drawSpriteToBackground(0, 0, backgroundIdArr[index]); + gameSys.setAnimation(animIdArr[index], 2, 0); + + if (index == 11) + _vm->stopSound(0x10000); + } + } + + if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) { + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_RETURN); + if (index == 0) { + skip = true; + _vm->stopSound(0x3CF); + } else if (index == 1) + skip = true; + else + _vm->_sceneDone = true; + } + } + + _vm->stopSound(0x10000); + + _vm->_newSceneNum = 1; + _vm->_newCursorValue = 1; + + _vm->_dat->open(1, "stock_n.dat"); +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/intro.h b/engines/gnap/scenes/intro.h new file mode 100644 index 0000000000..15aedfc4fc --- /dev/null +++ b/engines/gnap/scenes/intro.h @@ -0,0 +1,47 @@ +/* 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. + * + */ + +#ifndef GNAP_INTRO_H +#define GNAP_INTRO_H + +#include "gnap/debugger.h" +#include "gnap/scenes/scenecore.h" + +namespace Gnap { + +class GnapEngine; + +class SceneIntro: public Scene { +public: + SceneIntro(GnapEngine *vm); + virtual ~SceneIntro() {} + + virtual int init(); + virtual void updateHotspots() {} + virtual void run(); + virtual void updateAnimations() {} + virtual void updateAnimationsCb() {} +}; + +} // End of namespace Gnap + +#endif // GNAP_INTRO_H diff --git a/engines/gnap/scenes/scenecore.cpp b/engines/gnap/scenes/scenecore.cpp new file mode 100644 index 0000000000..5e941f4975 --- /dev/null +++ b/engines/gnap/scenes/scenecore.cpp @@ -0,0 +1,725 @@ +/* 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. + * + */ + +#include "gnap/gnap.h" +#include "gnap/gamesys.h" +#include "gnap/resource.h" + +#include "gnap/scenes/scenecore.h" + +#include "gnap/scenes/arcade.h" +#include "gnap/scenes/groupcs.h" +#include "gnap/scenes/group0.h" +#include "gnap/scenes/group1.h" +#include "gnap/scenes/group2.h" +#include "gnap/scenes/group3.h" +#include "gnap/scenes/group4.h" +#include "gnap/scenes/group5.h" +#include "gnap/scenes/intro.h" + +namespace Gnap { + +int GnapEngine::initSceneLogic() { + int backgroundId = -1; + + switch (_currentSceneNum) { + case 0: + _scene = new SceneIntro(this); + backgroundId = _scene->init(); + _gameSys->setScaleValues(0, 500, 1, 1000); + break; + case 1: + _scene = new Scene01(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 2: + _scene = new Scene02(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 3: + _scene = new Scene03(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 4: + _scene = new Scene04(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 5: + _scene = new Scene05(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 6: + _scene = new Scene06(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 7: + _scene = new Scene07(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 8: + _scene = new Scene08(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 9: + _scene = new Scene09(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 10: + _scene = new Scene10(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 11: + _scene = new Scene11(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 12: + _scene = new Scene12(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 13: + _scene = new Scene13(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 14: + _scene = new Scene14(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + break; + case 15: + _scene = new Scene15(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + break; + case 16: + case 47: + case 48: + case 54: + backgroundId = -1; + _gameSys->setScaleValues(0, 500, 1, 1000); + break; + case 17: + _scene = new Scene17(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 18: + _scene = new Scene18(this); + backgroundId = _scene->init(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + _scene->updateHotspots(); + break; + case 19: + _scene = new Scene19(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 20: + _scene = new Scene20(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 21: + _scene = new Scene21(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 22: + _scene = new Scene22(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 23: + _scene = new Scene23(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 24: + _scene = new Scene24(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 136, 11, 10); + break; + case 25: + _scene = new Scene25(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 26: + _scene = new Scene26(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 27: + _scene = new Scene27(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 28: + _scene = new Scene28(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 29: + _scene = new Scene29(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 30: + _scene = new Scene30(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 31: + _scene = new Scene31(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 32: + _scene = new Scene32(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 33: + _scene = new Scene33(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 34: + _scene = new Scene03(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 35: + _scene = new Scene05(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 36: + _scene = new Scene06(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 37: + _scene = new Scene04(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 38: + _scene = new Scene38(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 39: + _scene = new Scene39(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 40: + _scene = new Scene40(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 41: + _scene = new Scene41(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 42: + _scene = new Scene42(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 43: + _scene = new Scene43(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 44: + _scene = new Scene44(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 45: + _scene = new Scene45(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 46: + _scene = new Scene46(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 49: + _scene = new Scene49(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 50: + _scene = new Scene50(this); + backgroundId = _scene->init(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 51: + _scene = new Scene51(this); + backgroundId = _scene->init(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 52: + _scene = new Scene52(this); + backgroundId = _scene->init(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + case 53: + _scene = new Scene53(this); + backgroundId = _scene->init(); + _scene->updateHotspots(); + _gameSys->setScaleValues(0, 500, 1, 1000); + initSceneGrid(21, 146, 11, 10); + break; + } + + return backgroundId; +} + +void GnapEngine::runSceneLogic() { + switch (_currentSceneNum) { + case 0: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 8; + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 4; + break; + case 7: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 8; + break; + case 8: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 9; + break; + case 9: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 10; + break; + case 10: + case 12: + case 13: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 11; + break; + case 11: + case 15: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 12; + break; + case 14: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 13; + break; + case 16: + _scene = new Scene16(this); + _scene->init(); + _newSceneNum = 17; + _newCursorValue = 3; + _scene->run(); + delete _scene; + break; + case 17: + case 18: + case 21: + case 22: + case 23: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 20; + break; + case 19: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 19; + break; + case 20: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 22; + break; + case 32: + case 33: + case 34: + case 35: + case 36: + case 37: + case 38: + case 39: + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 37; + break; + case 47: + if (_prevSceneNum == 49) { + _scene = new Scene471(this); + _scene->init(); + _newSceneNum = 7; + _newCursorValue = 2; + } else if (_prevSceneNum == 13) { + _scene = new Scene472(this); + _scene->init(); + _newSceneNum = 11; + } else if (!isFlag(kGFPlatypusDisguised) && _prevSceneNum == 2) {//CHECKME + if (isFlag(kGFUnk25)) { + _scene = new Scene473(this); + _scene->init(); + _newSceneNum = 2; + } else { + _scene = new Scene474(this); + _scene->init(); + _newSceneNum = 49; + } + } else if (_prevSceneNum == 21) { + _scene = new Scene475(this); + _scene->init(); + _newSceneNum = 21; + setFlag(kGFTwigTaken); + setFlag(kGFKeysTaken); + } else if (_prevSceneNum == 30) { + _scene = new Scene476(this); + _scene->init(); + _newSceneNum = 26; + } else if (isFlag(kGFPlatypusDisguised) && _cursorValue == 1) { + _scene = new Scene477(this); + _scene->init(); + _newSceneNum = 4; + } + _scene->run(); + delete _scene; + break; + case 48: + _scene = new Scene48(this); + _scene->init(); + _newSceneNum = 33; + _newCursorValue = 4; + _scene->run(); + delete _scene; + break; + case 49: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 47; + break; + case 50: + _scene->run(); + delete _scene; + _newSceneNum = _prevSceneNum; + break; + case 51: + _scene->run(); + delete _scene; + break; + case 52: + _scene->run(); + delete _scene; + _newSceneNum = _prevSceneNum; + break; + case 53: + _scene->run(); + delete _scene; + if (_newSceneNum == 55) + _newSceneNum = 53; + break; + case 54: + if (_prevSceneNum == 45) { + _scene = new Scene541(this); + _scene->init(); + _newSceneNum = 43; + _scene->run(); + delete _scene; + } else { + _scene = new Scene542(this); + _scene->init(); + _scene->run(); + delete _scene; + _gameDone = true; + } + break; + } +} + +void Scene::playRandomSound(int timerIndex) { + if (!_vm->_timers[timerIndex]) { + _vm->_timers[timerIndex] = _vm->getRandom(40) + 50; + switch (_vm->getRandom(4)) { + case 0: + _vm->playSound(0x1091B, false); + break; + case 1: + _vm->playSound(0x10921, false); + break; + case 2: + _vm->playSound(0x10927, false); + break; + case 3: + _vm->playSound(0x1091D, false); + break; + } + } +} + +bool Scene::clearKeyStatus() { + if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE)) { + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_UP); + _vm->clearKeyStatus1(Common::KEYCODE_RIGHT); + _vm->clearKeyStatus1(Common::KEYCODE_LEFT); + _vm->clearKeyStatus1(Common::KEYCODE_p); + return true; + } + + if (_vm->isKeyStatus1(Common::KEYCODE_p)) { + _vm->clearKeyStatus1(Common::KEYCODE_p); + _vm->pauseGame(); + _vm->updatePause(); + } + + return false; +} + +void CutScene::run() { + GameSys& gameSys = *_vm->_gameSys; + + int itemIndex = 0; + int soundId = -1; + int volume = 100; + int duration = 0; + bool skip = false; + + if (_vm->_prevSceneNum == 2) { + soundId = 0x36B; + duration = MAX(1, 300 / _vm->getSequenceTotalDuration(_sequenceIdArr[_itemsCount - 1])); + _vm->_timers[0] = 0; + } + + if (soundId != -1) + _vm->playSound(soundId, false); + + _vm->hideCursor(); + + gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[0]); + + for (int j = 0; j < _sequenceCountArr[0]; ++j) + gameSys.insertSequence(_sequenceIdArr[j], j + 2, 0, 0, kSeqNone, 0, 0, 0); + gameSys.setAnimation(_sequenceIdArr[0], 2, 0); + + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_RETURN); + + _vm->_mouseClickState._left = false; + + int firstSequenceIndex = 0; + while (!_vm->_sceneDone) { + _vm->gameUpdateTick(); + + if (gameSys.getAnimationStatus(0) == 2 || skip) { + skip = false; + gameSys.requestClear2(false); + gameSys.requestClear1(); + gameSys.setAnimation(0, 0, 0); + firstSequenceIndex += _sequenceCountArr[itemIndex++]; + if (itemIndex >= _itemsCount) { + _vm->_sceneDone = true; + } else { + for (int m = 0; m < _sequenceCountArr[itemIndex]; ++m) + gameSys.insertSequence(_sequenceIdArr[firstSequenceIndex + m], m + 2, 0, 0, kSeqNone, 0, 0, 0); + gameSys.drawSpriteToBackground(0, 0, _resourceIdArr[itemIndex]); + gameSys.setAnimation(_sequenceIdArr[firstSequenceIndex], 2, 0); + } + } + + if (_vm->isKeyStatus1(Common::KEYCODE_ESCAPE) || _vm->isKeyStatus1(Common::KEYCODE_SPACE) || _vm->isKeyStatus1(Common::KEYCODE_RETURN)) { + _vm->clearKeyStatus1(Common::KEYCODE_ESCAPE); + _vm->clearKeyStatus1(Common::KEYCODE_SPACE); + _vm->clearKeyStatus1(Common::KEYCODE_RETURN); + if (_canSkip[itemIndex]) + skip = true; + else + _vm->_sceneDone = true; + } + + if (!_vm->_timers[0] && itemIndex == _itemsCount - 1) { + _vm->_timers[0] = 2; + volume = MAX(1, volume - duration); + _vm->setSoundVolume(soundId, volume); + } + } + + if (soundId != -1) + _vm->stopSound(soundId); +} + +} // End of namespace Gnap diff --git a/engines/gnap/scenes/scenecore.h b/engines/gnap/scenes/scenecore.h new file mode 100644 index 0000000000..5bfc80d185 --- /dev/null +++ b/engines/gnap/scenes/scenecore.h @@ -0,0 +1,70 @@ +/* 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. + * + */ + +#ifndef GNAP_SCENECORE_H +#define GNAP_SCENECORE_H + +#include "gnap/debugger.h" + +namespace Gnap { + +class GnapEngine; + +class Scene { +public: + Scene(GnapEngine *vm) : _vm(vm) {}; + virtual ~Scene() {}; + + void playRandomSound(int timerIndex); + bool clearKeyStatus(); + + virtual int init() = 0; + virtual void updateHotspots() = 0; + virtual void run() = 0; + virtual void updateAnimations() = 0; + virtual void updateAnimationsCb() = 0; + +protected: + GnapEngine *_vm; +}; + +class CutScene : public Scene { +public: + CutScene(GnapEngine *vm) : Scene(vm) {}; + virtual ~CutScene() {}; + + virtual int init() = 0; + void updateHotspots() {} + void run(); + void updateAnimations() {} + void updateAnimationsCb() {} + +protected: + int _itemsCount; + int _resourceIdArr[16]; + int _sequenceCountArr[16]; + int _sequenceIdArr[50]; + bool _canSkip[16]; +}; +} // End of namespace Gnap + +#endif // GNAP_SCENECORE_H diff --git a/engines/gnap/sound.cpp b/engines/gnap/sound.cpp new file mode 100644 index 0000000000..75cfb5555c --- /dev/null +++ b/engines/gnap/sound.cpp @@ -0,0 +1,96 @@ +/* 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. + * + */ + +#include "gnap/sound.h" +#include "audio/audiostream.h" +#include "audio/decoders/wave.h" + +namespace Gnap { + +SoundMan::SoundMan(GnapEngine *vm) + : _vm(vm) { +} + +SoundMan::~SoundMan() { +} + +void SoundMan::playSound(int resourceId, bool looping) { + SoundItem soundItem; + soundItem._resourceId = resourceId; + + SoundResource *soundResource = _vm->_soundCache->get(resourceId); + Common::MemoryReadStream *stream = new Common::MemoryReadStream(soundResource->_data, soundResource->_size, DisposeAfterUse::NO); + Audio::AudioStream *audioStream = Audio::makeLoopingAudioStream(Audio::makeWAVStream(stream, DisposeAfterUse::YES), looping ? 0 : 1); + + _vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &soundItem._handle, audioStream); + + _items.push_back(soundItem); + +} + +void SoundMan::stopSound(int resourceId) { + const int index = find(resourceId); + if (index >= 0) { + _vm->_soundCache->release(_items[index]._resourceId); + _vm->_mixer->stopHandle(_items[index]._handle); + _items.remove_at(index); + } +} + +void SoundMan::setSoundVolume(int resourceId, int volume) { + if (resourceId == -1 || volume < 0 || volume > 100) + return; + + const int index = find(resourceId); + int realVol = volume * 2.55; + _vm->_mixer->setChannelVolume(_items[index]._handle, realVol); +} + +bool SoundMan::isSoundPlaying(int resourceId) { + const int index = find(resourceId); + return index >= 0 && _vm->_mixer->isSoundHandleActive(_items[index]._handle); +} + +void SoundMan::stopAll() { + for (int index = 0; index < (int)_items.size(); ++index) { + _vm->_soundCache->release(_items[index]._resourceId); + _vm->_mixer->stopHandle(_items[index]._handle); + } +} + +void SoundMan::update() { + for (int index = 0; index < (int)_items.size(); ++index) + if (!_vm->_mixer->isSoundHandleActive(_items[index]._handle)) { + _vm->_soundCache->release(_items[index]._resourceId); + _items.remove_at(index); + --index; + } +} + +int SoundMan::find(int resourceId) { + for (int index = 0; index < (int)_items.size(); ++index) + if (_items[index]._resourceId == resourceId) + return index; + return -1; +} + +} // End of namespace Gnap diff --git a/engines/gnap/sound.h b/engines/gnap/sound.h new file mode 100644 index 0000000000..de3981245d --- /dev/null +++ b/engines/gnap/sound.h @@ -0,0 +1,57 @@ +/* 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. + * + */ + +#ifndef GNAP_SOUND_H +#define GNAP_SOUND_H + +#include "gnap/gnap.h" +#include "gnap/resource.h" +#include "audio/mixer.h" +#include "common/array.h" + +namespace Gnap { + +struct SoundItem { + int _resourceId; + Audio::SoundHandle _handle; +}; + +class SoundMan { +public: + SoundMan(GnapEngine *vm); + ~SoundMan(); + void playSound(int resourceId, bool looping); + void stopSound(int resourceId); + void setSoundVolume(int resourceId, int volume); + bool isSoundPlaying(int resourceId); + void stopAll(); + void update(); +protected: + GnapEngine *_vm; + Common::Array<SoundItem> _items; + + int find(int resourceId); +}; + +} // End of namespace Gnap + +#endif // GNAP_SOUND_H |