/* 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; _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; _platypusSequenceId = -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; _arcadeScreenBottom = 0; _shipsLeft = 0; _shipPosX = 0; _shipCannonPosX = 0; _shipCannonPosY = 0; _shipCannonFiring = false; _shipCannonFired = false; _shipCannonWidth = 0; _shipCannonHeight = 0; _shipCannonTopY = 0; _shipMidX = 0; _shipMidY = 0; _shipFlag = false; _alienSpeed = 0; _alienWidth = 0; _alienHeight = 0; _alienLeftX = 0; _alienTopY = 0; _alienRowDownCtr = 0; _alienWave = false; _alienSingle = false; _alienCounter = 0; _bottomAlienFlag = false; _aliensCount = 0; _nextUfoSequenceId = -1; _ufoSequenceId = -1; _liveAlienRows = 0; } 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; } } _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 delay = CLIP(_alienSpeed, 2, 10); _vm->_timers[0] = delay; } } 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; int arcadeScreenRight = 595 - _shipMidX; int 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