aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorEugene Sandulenko2014-02-21 21:14:29 +0200
committerEugene Sandulenko2014-02-21 21:14:29 +0200
commitc2e9f38d79a577e54c5baefbcf9601c00e145e98 (patch)
treef01748074197caab1f22ce8776e503c7f790723f /engines
parent8cd0d40cefa1cc9e377deb86f04103c143afdfae (diff)
parent608485729b52e401865c7f189af2aa2e39021597 (diff)
downloadscummvm-rg350-c2e9f38d79a577e54c5baefbcf9601c00e145e98.tar.gz
scummvm-rg350-c2e9f38d79a577e54c5baefbcf9601c00e145e98.tar.bz2
scummvm-rg350-c2e9f38d79a577e54c5baefbcf9601c00e145e98.zip
Merge pull request #435 from johndoe123/bbvs
BBVS: New engine: Beavis and Butthead In Virtual Stupidity
Diffstat (limited to 'engines')
-rw-r--r--engines/bbvs/bbvs.cpp2237
-rw-r--r--engines/bbvs/bbvs.h415
-rw-r--r--engines/bbvs/configure.engine3
-rw-r--r--engines/bbvs/detection.cpp162
-rw-r--r--engines/bbvs/dialogs.cpp182
-rw-r--r--engines/bbvs/dialogs.h81
-rw-r--r--engines/bbvs/gamemodule.cpp500
-rw-r--r--engines/bbvs/gamemodule.h251
-rw-r--r--engines/bbvs/graphics.cpp141
-rw-r--r--engines/bbvs/graphics.h61
-rw-r--r--engines/bbvs/minigames/bbairguitar.cpp1198
-rw-r--r--engines/bbvs/minigames/bbairguitar.h148
-rw-r--r--engines/bbvs/minigames/bbairguitar_anims.cpp186
-rw-r--r--engines/bbvs/minigames/bbant.cpp1317
-rw-r--r--engines/bbvs/minigames/bbant.h173
-rw-r--r--engines/bbvs/minigames/bbant_anims.cpp757
-rw-r--r--engines/bbvs/minigames/bbloogie.cpp1355
-rw-r--r--engines/bbvs/minigames/bbloogie.h141
-rw-r--r--engines/bbvs/minigames/bbloogie_anims.cpp138
-rw-r--r--engines/bbvs/minigames/bbtennis.cpp1274
-rw-r--r--engines/bbvs/minigames/bbtennis.h134
-rw-r--r--engines/bbvs/minigames/bbtennis_anims.cpp142
-rw-r--r--engines/bbvs/minigames/minigame.cpp104
-rw-r--r--engines/bbvs/minigames/minigame.h82
-rw-r--r--engines/bbvs/module.mk29
-rw-r--r--engines/bbvs/saveload.cpp279
-rw-r--r--engines/bbvs/sound.cpp107
-rw-r--r--engines/bbvs/sound.h63
-rw-r--r--engines/bbvs/spritemodule.cpp112
-rw-r--r--engines/bbvs/spritemodule.h68
-rw-r--r--engines/bbvs/videoplayer.cpp78
31 files changed, 11918 insertions, 0 deletions
diff --git a/engines/bbvs/bbvs.cpp b/engines/bbvs/bbvs.cpp
new file mode 100644
index 0000000000..eefeea0d68
--- /dev/null
+++ b/engines/bbvs/bbvs.cpp
@@ -0,0 +1,2237 @@
+/* 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 "bbvs/bbvs.h"
+#include "bbvs/dialogs.h"
+#include "bbvs/gamemodule.h"
+#include "bbvs/graphics.h"
+#include "bbvs/sound.h"
+#include "bbvs/spritemodule.h"
+#include "bbvs/minigames/minigame.h"
+#include "bbvs/minigames/bbairguitar.h"
+#include "bbvs/minigames/bbant.h"
+#include "bbvs/minigames/bbloogie.h"
+#include "bbvs/minigames/bbtennis.h"
+#include "bbvs/minigames/minigame.h"
+
+#include "audio/audiostream.h"
+#include "common/config-manager.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/fs.h"
+#include "common/timer.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/font.h"
+#include "graphics/fontman.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+namespace Bbvs {
+
+static const BBPoint kInventorySlotPositions[] = {
+ { 66, 191}, { 94, 217}, {192, 217}, {159, 213}, {228, 49},
+ {137, 49}, {168, 165}, {101, 55}, {177, 46}, {165, 165},
+ {202, 74}, {141, 53}, {164, 164}, {165, 78}, {167, 71},
+ {142, 188}, {171, 100}, {250, 216}, {200, 72}, {200, 72},
+ {101, 82}, { 67, 93}, {133, 87}, {123, 220}, {199, 129},
+ {188, 192}, {102, 82}, {188, 192}, { 99, 170}, { 68, 126},
+ {159, 130}, {102, 116}, {207, 157}, {130, 141}, {236, 100},
+ {102, 197}, {141, 186}, {200, 102}, {221, 220}, {222, 188},
+ {135, 93}, {134, 145}, { 96, 224}, {128, 224}, {160, 224},
+ {192, 224}, {224, 224}, {240, 224}, {256, 224}, { 0, 0}
+};
+
+static const BBRect kVerbRects[6] = {
+ {-32, -2, 19, 27}, {-33, -33, 19, 27}, { 12, -2, 19, 27},
+ { 13, -33, 19, 27}, {-10, 8, 19, 27}, {-11, -49, 19, 27}
+};
+
+static const int8 kWalkTurnTbl[] = {
+ 7, 9, 4, 8, 6, 10, 5, 11
+};
+
+static const int8 kWalkAnimTbl[32] = {
+ 3, 0, 0, 0, 2, 1, 1, 1,
+ 15, 12, 14, 13, 0, 0, 0, 0,
+ 7, 9, 4, 8, 6, 10, 5, 11,
+ 3, 0, 2, 1, 15, 12, 14, 13
+};
+
+static const int8 kTurnInfo[8][8] = {
+ { 0, 1, 1, 1, 1, -1, -1, -1},
+ {-1, 0, 1, 1, 1, 1, -1, -1},
+ {-1, -1, 0, 1, 1, 1, 1, -1},
+ {-1, -1, -1, 0, 1, 1, 1, 1},
+ { 1, -1, -1, -1, 0, 1, 1, 1},
+ { 1, 1, -1, -1, -1, 0, 1, 1},
+ { 1, 1, 1, -1, -1, -1, 0, 1},
+ { 1, 1, 1, 1, -1, -1, -1, 0}
+};
+
+static const byte kTurnTbl[] = {
+ 2, 6, 4, 0, 2, 6, 4, 0,
+ 3, 1, 5, 7, 0, 0, 0, 0
+};
+
+static const int kAfterVideoSceneNum[] = {
+ 0, 43, 23, 12, 4, 44, 2,
+ 16, 4, 4, 4, 44, 12, 44
+};
+
+const int kMainMenu = 44;
+const int kCredits = 45;
+
+bool WalkArea::contains(const Common::Point &pt) const {
+ return Common::Rect(x, y, x + width, y + height).contains(pt);
+}
+
+BbvsEngine::BbvsEngine(OSystem *syst, const ADGameDescription *gd) :
+ Engine(syst), _gameDescription(gd) {
+
+ _random = new Common::RandomSource("bbvs");
+
+ Engine::syncSoundSettings();
+
+}
+
+BbvsEngine::~BbvsEngine() {
+
+ delete _random;
+
+}
+
+void BbvsEngine::newGame() {
+ _currInventoryItem = -1;
+ _newSceneNum = 32;
+}
+
+void BbvsEngine::continueGameFromQuickSave() {
+ _bootSaveSlot = 0;
+}
+
+void BbvsEngine::setNewSceneNum(int newSceneNum) {
+ _newSceneNum = newSceneNum;
+}
+
+Common::Error BbvsEngine::run() {
+
+ _isSaveAllowed = false;
+ _hasSnapshot = false;
+
+ initGraphics(320, 240, false);
+
+ _screen = new Screen(_system);
+ _gameModule = new GameModule();
+ _spriteModule = new SpriteModule();
+ _sound = new SoundMan();
+
+ allocSnapshot();
+ memset(_easterEggInput, 0, sizeof(_easterEggInput));
+
+ _gameTicks = 0;
+ _playVideoNumber = 0;
+ _bootSaveSlot = -1;
+
+ memset(_inventoryItemStatus, 0, sizeof(_inventoryItemStatus));
+ memset(_gameVars, 0, sizeof(_gameVars));
+ memset(_sceneVisited, 0, sizeof(_sceneVisited));
+
+ _mouseX = 160;
+ _mouseY = 120;
+ _mouseButtons = 0;
+
+ _currVerbNum = kVerbLook;
+ _currInventoryItem = -1;
+ _currTalkObjectIndex = -1;
+ _currSceneNum = 0;
+ _newSceneNum = 31;
+
+ if (ConfMan.hasKey("save_slot"))
+ _bootSaveSlot = ConfMan.getInt("save_slot");
+
+ while (!shouldQuit()) {
+ updateEvents();
+ if (_currSceneNum < kMainMenu || _newSceneNum > 0 || _bootSaveSlot >= 0)
+ updateGame();
+ else if (_currSceneNum == kMainMenu)
+ runMainMenu();
+ else if (_currSceneNum == kCredits &&
+ (_mouseButtons & kAnyButtonClicked)) {
+ _mouseButtons &= ~kAnyButtonClicked;
+ _newSceneNum = kMainMenu;
+ }
+ if (_playVideoNumber > 0) {
+ playVideo(_playVideoNumber);
+ _playVideoNumber = 0;
+ }
+ }
+
+ writeContinueSavegame();
+
+ freeSnapshot();
+
+ delete _sound;
+ delete _spriteModule;
+ delete _gameModule;
+ delete _screen;
+
+ return Common::kNoError;
+}
+
+bool BbvsEngine::hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+void BbvsEngine::updateEvents() {
+ Common::Event event;
+
+ while (_eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ _keyCode = event.kbd.keycode;
+ break;
+ case Common::EVENT_KEYUP:
+ checkEasterEgg(event.kbd.ascii);
+ _keyCode = Common::KEYCODE_INVALID;
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ break;
+ case Common::EVENT_LBUTTONDOWN:
+ _mouseButtons |= kLeftButtonClicked;
+ _mouseButtons |= kLeftButtonDown;
+ break;
+ case Common::EVENT_LBUTTONUP:
+ _mouseButtons &= ~kLeftButtonDown;
+ break;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButtons |= kRightButtonClicked;
+ _mouseButtons |= kRightButtonDown;
+ break;
+ case Common::EVENT_RBUTTONUP:
+ _mouseButtons &= ~kRightButtonDown;
+ break;
+ case Common::EVENT_QUIT:
+ quitGame();
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int BbvsEngine::getRandom(int max) {
+ return max == 0 ? 0 : _random->getRandomNumber(max - 1);
+}
+
+void BbvsEngine::drawDebugInfo() {
+#if 0
+ Graphics::Surface *s = _screen->_surface;
+ const Graphics::Font *font = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont);
+ for (int i = 0; i < _walkAreasCount; ++i) {
+ WalkArea *walkArea = &_walkAreas[i];
+ Common::Rect r(walkArea->x, walkArea->y, walkArea->x + walkArea->width, walkArea->y + walkArea->height);
+ s->frameRect(r, 255);
+ Common::String text = Common::String::format("%d", i);
+ font->drawString(s, text, r.left + 1, r.top + 1, 100, 11);
+ }
+#endif
+}
+
+void BbvsEngine::drawScreen() {
+ drawDebugInfo();
+ _screen->copyToScreen();
+}
+
+void BbvsEngine::updateGame() {
+ int currTicks, inputTicks;
+
+ if (_gameTicks > 0) {
+ currTicks = _system->getMillis();
+ inputTicks = (currTicks - _gameTicks) / 17;
+ _gameTicks = currTicks - (currTicks - _gameTicks) % 17;
+ } else {
+ inputTicks = 1;
+ _gameTicks = _system->getMillis();
+ }
+
+ if (inputTicks > 20) {
+ inputTicks = 20;
+ _gameTicks = _system->getMillis();
+ }
+
+ if (inputTicks == 0)
+ return;
+
+ if (_mouseX >= 320 || _mouseY >= 240) {
+ _mouseY = -1;
+ _mouseX = -1;
+ }
+
+ bool done;
+
+ do {
+ done = !update(_mouseX, _mouseY, _mouseButtons, _keyCode);
+ _mouseButtons &= ~kLeftButtonClicked;
+ _mouseButtons &= ~kRightButtonClicked;
+ _keyCode = Common::KEYCODE_INVALID;
+ } while (--inputTicks && _playVideoNumber == 0 && _gameTicks > 0 && !done);
+
+ if (!done && _playVideoNumber == 0 && _gameTicks > 0) {
+ DrawList drawList;
+ buildDrawList(drawList);
+ _screen->drawDrawList(drawList, _spriteModule);
+ drawScreen();
+ }
+
+ _system->delayMillis(10);
+
+}
+
+bool BbvsEngine::evalCondition(Conditions &conditions) {
+ bool result = true;
+ for (int i = 0; i < 8 && result; ++i) {
+ const Condition &condition = conditions.conditions[i];
+ switch (condition.cond) {
+ case kCondSceneObjectVerb:
+ result = _activeItemType == KITSceneObject &&
+ condition.value1 == _currVerbNum &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondBgObjectVerb:
+ result = _activeItemType == kITBgObject &&
+ condition.value1 == _currVerbNum &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondSceneObjectInventory:
+ result = _activeItemType == KITSceneObject &&
+ _currVerbNum == kVerbInvItem &&
+ condition.value1 == _currInventoryItem &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondBgObjectInventory:
+ result = _activeItemType == kITBgObject &&
+ _currVerbNum == kVerbInvItem &&
+ condition.value1 == _currInventoryItem &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondHasInventoryItem:
+ result = _inventoryItemStatus[condition.value1] != 0;
+ break;
+ case kCondHasNotInventoryItem:
+ result = _inventoryItemStatus[condition.value1] == 0;
+ break;
+ case kCondIsGameVar:
+ result = _gameVars[condition.value2] != 0;
+ break;
+ case kCondIsNotGameVar:
+ result = _gameVars[condition.value2] == 0;
+ break;
+ case kCondIsPrevSceneNum:
+ result = condition.value2 == _prevSceneNum;
+ break;
+ case kCondIsCurrTalkObject:
+ result = condition.value2 == _currTalkObjectIndex;
+ break;
+ case kCondIsDialogItem:
+ result = _activeItemType == kITDialog &&
+ condition.value1 == _activeItemIndex;
+ break;
+ case kCondIsCameraNum:
+ result = condition.value1 == _currCameraNum;
+ break;
+ case kCondIsNotPrevSceneNum:
+ result = condition.value2 != _prevSceneNum;
+ break;
+ case kCondIsButtheadAtBgObject:
+ result = _buttheadObject &&
+ _gameModule->getBgObject(condition.value2)->rect.contains(_buttheadObject->x >> 16, _buttheadObject->y >> 16);
+ break;
+ case kCondIsNotSceneVisited:
+ result = _sceneVisited[_currSceneNum] == 0;
+ break;
+ case kCondIsSceneVisited:
+ result = _sceneVisited[_currSceneNum] != 0;
+ break;
+ case kCondUnused:
+ case kCondDialogItem0:
+ case kCondIsCameraNumTransition:
+ result = false;
+ break;
+ }
+ }
+ return result;
+}
+
+bool BbvsEngine::evalCameraCondition(Conditions &conditions, int value) {
+ bool result = true;
+ for (int i = 0; i < 8 && result; ++i) {
+ const Condition &condition = conditions.conditions[i];
+ switch (condition.cond) {
+ case kCondHasInventoryItem:
+ result = _inventoryItemStatus[condition.value1] != 0;
+ break;
+ case kCondHasNotInventoryItem:
+ result = _inventoryItemStatus[condition.value1] == 0;
+ break;
+ case kCondIsGameVar:
+ result = _gameVars[condition.value2] != 0;
+ break;
+ case kCondIsNotGameVar:
+ result = _gameVars[condition.value2] == 0;
+ break;
+ case kCondIsPrevSceneNum:
+ result = condition.value2 == _prevSceneNum;
+ break;
+ case kCondIsNotPrevSceneNum:
+ result = condition.value2 != _prevSceneNum;
+ break;
+ case kCondIsNotSceneVisited:
+ result = _sceneVisited[_currSceneNum] == 0;
+ break;
+ case kCondIsSceneVisited:
+ result = _sceneVisited[_currSceneNum] != 0;
+ break;
+ case kCondIsCameraNumTransition:
+ result = condition.value1 == _currCameraNum &&
+ condition.value2 == value;
+ break;
+ case kCondUnused:
+ case kCondSceneObjectVerb:
+ case kCondBgObjectVerb:
+ case kCondSceneObjectInventory:
+ case kCondBgObjectInventory:
+ case kCondIsCurrTalkObject:
+ case kCondIsDialogItem:
+ case kCondIsCameraNum:
+ case kCondDialogItem0:
+ case kCondIsButtheadAtBgObject:
+ result = false;
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+int BbvsEngine::evalDialogCondition(Conditions &conditions) {
+ int result = -1;
+ bool success = false;
+ for (int i = 0; i < 8; ++i) {
+ const Condition &condition = conditions.conditions[i];
+ switch (condition.cond) {
+ case kCondSceneObjectVerb:
+ success = _activeItemType == KITSceneObject &&
+ condition.value1 == _currVerbNum &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondBgObjectVerb:
+ success = _activeItemType == kITBgObject &&
+ condition.value1 == _currVerbNum &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondSceneObjectInventory:
+ success = _activeItemType == KITSceneObject &&
+ _currVerbNum == kVerbInvItem &&
+ condition.value1 == _currInventoryItem &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondBgObjectInventory:
+ success = _activeItemType == kITBgObject &&
+ _currVerbNum == kVerbInvItem &&
+ condition.value1 == _currInventoryItem &&
+ condition.value2 == _activeItemIndex;
+ break;
+ case kCondHasInventoryItem:
+ success = _inventoryItemStatus[condition.value1] != 0;
+ break;
+ case kCondHasNotInventoryItem:
+ success = _inventoryItemStatus[condition.value1] == 0;
+ break;
+ case kCondIsGameVar:
+ success = _gameVars[condition.value2] != 0;
+ break;
+ case kCondIsNotGameVar:
+ success = _gameVars[condition.value2] == 0;
+ break;
+ case kCondIsPrevSceneNum:
+ success = condition.value2 == _prevSceneNum;
+ break;
+ case kCondIsCurrTalkObject:
+ success = condition.value2 == _currTalkObjectIndex;
+ break;
+ case kCondIsDialogItem:
+ result = condition.value1;
+ break;
+ case kCondIsCameraNum:
+ success = condition.value1 == _currCameraNum;
+ break;
+ case kCondIsNotPrevSceneNum:
+ success = condition.value2 != _prevSceneNum;
+ break;
+ case kCondIsButtheadAtBgObject:
+ success = _buttheadObject &&
+ _gameModule->getBgObject(condition.value2)->rect.contains(_buttheadObject->x >> 16, _buttheadObject->y >> 16);
+ break;
+ case kCondIsNotSceneVisited:
+ success = _sceneVisited[_currSceneNum] == 0;
+ break;
+ case kCondIsSceneVisited:
+ success = _sceneVisited[_currSceneNum] != 0;
+ break;
+ case kCondDialogItem0:
+ return 0;
+ case kCondUnused:
+ case kCondIsCameraNumTransition:
+ success = false;
+ break;
+ }
+ if (!success)
+ return -1;
+ }
+ return result;
+}
+
+void BbvsEngine::evalActionResults(ActionResults &results) {
+ for (int i = 0; i < 8; ++i) {
+ const ActionResult &result = results.actionResults[i];
+ switch (result.kind) {
+ case kActResAddInventoryItem:
+ _inventoryItemStatus[result.value1] = 1;
+ _currVerbNum = kVerbInvItem;
+ _currInventoryItem = result.value1;
+ break;
+ case kActResRemoveInventoryItem:
+ _inventoryItemStatus[result.value1] = 0;
+ if (result.value1 == _currInventoryItem)
+ _currInventoryItem = -1;
+ if (_currVerbNum == kVerbInvItem)
+ _currVerbNum = kVerbLook;
+ break;
+ case kActResSetGameVar:
+ _gameVars[result.value2] = 1;
+ break;
+ case kActResUnsetGameVar:
+ _gameVars[result.value2] = 0;
+ break;
+ case kActResStartDialog:
+ _gameState = kGSDialog;
+ break;
+ case kActResChangeScene:
+ _newSceneNum = result.value2;
+ break;
+ }
+ }
+}
+
+void BbvsEngine::updateBackgroundSounds() {
+ for (int i = 0; i < _gameModule->getSceneSoundsCount(); ++i) {
+ SceneSound *sceneSound = _gameModule->getSceneSound(i);
+ bool isActive = evalCondition(sceneSound->conditions);
+ debug(5, "bgSound(%d) isActive: %d; soundNum: %d", i, isActive, sceneSound->soundNum);
+ if (isActive && !_backgroundSoundsActive[i]) {
+ playSound(sceneSound->soundNum, true);
+ _backgroundSoundsActive[i] = 1;
+ } else if (!isActive && _backgroundSoundsActive[i]) {
+ stopSound(sceneSound->soundNum);
+ _backgroundSoundsActive[i] = 0;
+ }
+ }
+}
+
+void BbvsEngine::loadScene(int sceneNum) {
+ debug(0, "BbvsEngine::loadScene() sceneNum: %d", sceneNum);
+
+ Common::String sprFilename = Common::String::format("vnm/vspr%04d.vnm", sceneNum);
+ Common::String gamFilename = Common::String::format("vnm/game%04d.vnm", sceneNum);
+
+ _screen->clear();
+
+ _spriteModule->load(sprFilename.c_str());
+ _gameModule->load(gamFilename.c_str());
+
+ Palette palette = _spriteModule->getPalette();
+ _screen->setPalette(palette);
+
+ // Preload sounds
+ for (uint i = 0; i < _gameModule->getPreloadSoundsCount(); ++i) {
+ Common::String filename = Common::String::format("snd/snd%05d.aif", _gameModule->getPreloadSound(i));
+ _sound->loadSound(filename);
+ }
+
+ if (sceneNum >= kMainMenu) {
+ DrawList drawList;
+ drawList.add(_gameModule->getBgSpriteIndex(0), 0, 0, 0);
+ _screen->drawDrawList(drawList, _spriteModule);
+ drawScreen();
+ }
+
+}
+
+void BbvsEngine::initScene(bool sounds) {
+
+ stopSpeech();
+ stopSounds();
+ _sound->unloadSounds();
+
+ _gameState = kGSScene;
+ _prevSceneNum = _currSceneNum;
+ _sceneVisited[_currSceneNum] = 1;
+ _mouseCursorSpriteIndex = 0;
+ _verbPos.x = -1;
+ _verbPos.y = -1;
+ _activeItemType = kITEmpty;
+ _activeItemIndex = 0;
+ _cameraPos.x = 0;
+ _cameraPos.y = 0;
+ _newCameraPos.x = 0;
+ _newCameraPos.y = 0;
+ _inventoryButtonIndex = -1;
+ _currTalkObjectIndex = -1;
+ _currCameraNum = 0;
+ _walkMousePos.x = -1;
+ _walkMousePos.y = -1;
+ _currAction = 0;
+ _currActionCommandIndex = -1;
+ _currActionCommandTimeStamp = 0;
+ _dialogSlotCount = 0;
+ _buttheadObject = 0;
+ _beavisObject = 0;
+
+ memset(_backgroundSoundsActive, 0, sizeof(_backgroundSoundsActive));
+
+ memset(_sceneObjects, 0, sizeof(_sceneObjects));
+ for (int i = 0; i < kSceneObjectsCount; ++i) {
+ _sceneObjects[i].walkDestPt.x = -1;
+ _sceneObjects[i].walkDestPt.y = -1;
+ }
+
+ memset(_dialogItemStatus, 0, sizeof(_dialogItemStatus));
+
+ _sceneObjectActions.clear();
+
+ loadScene(_newSceneNum);
+ _currSceneNum = _newSceneNum;
+ _newSceneNum = 0;
+
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i)
+ _sceneObjects[i].sceneObjectDef = _gameModule->getSceneObjectDef(i);
+
+ for (int i = 0; i < _gameModule->getSceneObjectInitsCount(); ++i) {
+ SceneObjectInit *soInit = _gameModule->getSceneObjectInit(i);
+ if (evalCondition(soInit->conditions)) {
+ SceneObject *sceneObject = &_sceneObjects[soInit->sceneObjectIndex];
+ sceneObject->anim = _gameModule->getAnimation(soInit->animIndex);
+ sceneObject->animIndex = soInit->animIndex;
+ sceneObject->frameIndex = sceneObject->anim->frameCount - 1;
+ sceneObject->frameTicks = 1;
+ sceneObject->x = soInit->x << 16;
+ sceneObject->y = soInit->y << 16;
+ }
+ }
+
+ if (_gameModule->getButtheadObjectIndex() >= 0) {
+ _buttheadObject = &_sceneObjects[_gameModule->getButtheadObjectIndex()];
+ // Search for the Beavis object
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i)
+ if (!strcmp(_sceneObjects[i].sceneObjectDef->name, "Beavis")) {
+ _beavisObject = &_sceneObjects[i];
+ break;
+ }
+ }
+
+ updateSceneObjectsTurnValue();
+
+ updateWalkableRects();
+
+ _currCameraNum = 0;
+ if (_buttheadObject) {
+ int minDistance = 0xFFFFFF;
+ for (int cameraNum = 0; cameraNum < 4; ++cameraNum) {
+ CameraInit *cameraInit = _gameModule->getCameraInit(cameraNum);
+ int curDistance = ABS(cameraInit->cameraPos.x - (int)(_buttheadObject->x >> 16) + 160);
+ if (curDistance < minDistance) {
+ minDistance = curDistance;
+ _currCameraNum = cameraNum;
+ }
+ }
+ }
+
+ _cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos;
+ _newCameraPos = _cameraPos;
+
+ _walkAreaActions.clear();
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ for (int j = 0; j < 8; ++j)
+ if (action->conditions.conditions[j].cond == kCondIsButtheadAtBgObject)
+ _walkAreaActions.push_back(action);
+ }
+
+ _mouseCursorSpriteIndex = 0;
+
+ _activeItemIndex = 0;
+ _activeItemType = kITEmpty;
+
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ if (evalCondition(action->conditions)) {
+ _gameState = kGSWait;
+ _currAction = action;
+ for (uint j = 0; j < action->actionCommands.size(); ++j) {
+ ActionCommand *actionCommand = &action->actionCommands[j];
+ if (actionCommand->cmd == kActionCmdSetCameraPos) {
+ _currCameraNum = actionCommand->param;
+ _cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos;
+ _newCameraPos = _cameraPos;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if (sounds)
+ updateBackgroundSounds();
+
+}
+
+bool BbvsEngine::changeScene() {
+
+ writeContinueSavegame();
+
+ if (_newSceneNum >= 27 && _newSceneNum <= 30) {
+ // Run minigames
+ stopSpeech();
+ stopSounds();
+ _sceneVisited[_currSceneNum] = 1;
+ if (runMinigame(_newSceneNum - 27)) {
+ SWAP(_currSceneNum, _newSceneNum);
+ }
+ } else if (_newSceneNum >= 31 && _newSceneNum <= 43) {
+ // Play video
+ stopSpeech();
+ stopSounds();
+ _sceneVisited[_currSceneNum] = 1;
+ _playVideoNumber = _newSceneNum - 30;
+ _currSceneNum = _newSceneNum;
+ _newSceneNum = kAfterVideoSceneNum[_playVideoNumber];
+ } else if (_newSceneNum >= 100 && _currSceneNum == kCredits) {
+ // Play secret video
+ stopSounds();
+ _playVideoNumber = _newSceneNum;
+ _currSceneNum = 49;
+ _newSceneNum = kCredits;
+ } else {
+ // Normal scene
+ initScene(true);
+ }
+
+ return true;
+
+}
+
+bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCode keyCode) {
+
+ if (_bootSaveSlot >= 0) {
+ loadGameState(_bootSaveSlot);
+ _gameTicks = 0;
+ _bootSaveSlot = -1;
+ return false;
+ }
+
+ if (_newSceneNum != 0) {
+ _gameTicks = 0;
+ return changeScene();
+ }
+
+ _mousePos.x = mouseX + _cameraPos.x;
+ _mousePos.y = mouseY + _cameraPos.y;
+
+ switch (_gameState) {
+
+ case kGSScene:
+ _isSaveAllowed = true;
+ saveSnapshot();
+ if (mouseButtons & kRightButtonDown) {
+ _verbPos = _mousePos;
+ if (_mousePos.x - _cameraPos.x < 33)
+ _verbPos.x = _cameraPos.x + 33;
+ if (_verbPos.x - _cameraPos.x > 287)
+ _verbPos.x = _cameraPos.x + 287;
+ if (_verbPos.y - _cameraPos.y < 51)
+ _verbPos.y = _cameraPos.y + 51;
+ if (_verbPos.y - _cameraPos.y > 208)
+ _verbPos.y = _cameraPos.y + 208;
+ _gameState = kGSVerbs;
+ } else {
+ switch (keyCode) {
+ case Common::KEYCODE_SPACE:
+ case Common::KEYCODE_i:
+ _inventoryButtonIndex = -1;
+ _gameState = kGSInventory;
+ return true;
+ case Common::KEYCODE_l:
+ _currVerbNum = kVerbLook;
+ break;
+ case Common::KEYCODE_t:
+ _currVerbNum = kVerbTalk;
+ break;
+ case Common::KEYCODE_u:
+ _currVerbNum = kVerbUse;
+ break;
+ case Common::KEYCODE_w:
+ _currVerbNum = kVerbWalk;
+ break;
+ default:
+ break;
+ }
+ updateScene(mouseButtons & kLeftButtonClicked);
+ updateCommon();
+ }
+ break;
+
+ case kGSInventory:
+ _isSaveAllowed = true;
+ saveSnapshot();
+ if (mouseButtons & kRightButtonClicked)
+ _currVerbNum = kVerbUse;
+ switch (keyCode) {
+ case Common::KEYCODE_SPACE:
+ case Common::KEYCODE_i:
+ _gameState = kGSScene;
+ stopSpeech();
+ return true;
+ case Common::KEYCODE_l:
+ _currVerbNum = kVerbLook;
+ break;
+ case Common::KEYCODE_u:
+ _currVerbNum = kVerbUse;
+ break;
+ default:
+ break;
+ }
+ updateInventory(mouseButtons & kLeftButtonClicked);
+ break;
+
+ case kGSVerbs:
+ _isSaveAllowed = false;
+ updateVerbs();
+ if (!(mouseButtons & kRightButtonDown)) {
+ if (_currVerbNum == kVerbShowInv) {
+ _inventoryButtonIndex = -1;
+ _gameState = kGSInventory;
+ } else {
+ _gameState = kGSScene;
+ }
+ }
+ break;
+
+ case kGSWait:
+ case kGSWaitDialog:
+ _isSaveAllowed = false;
+ _activeItemType = kITEmpty;
+ _activeItemIndex = 0;
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(9);
+ if (keyCode == Common::KEYCODE_ESCAPE)
+ skipCurrAction();
+ else
+ updateCommon();
+ break;
+
+ case kGSDialog:
+ _isSaveAllowed = true;
+ saveSnapshot();
+ updateDialog(mouseButtons & kLeftButtonClicked);
+ updateCommon();
+ break;
+
+ }
+
+ return true;
+}
+
+void BbvsEngine::buildDrawList(DrawList &drawList) {
+
+ if (_gameState == kGSInventory) {
+
+ // Inventory background
+ drawList.add(_gameModule->getGuiSpriteIndex(15), 0, 0, 0);
+
+ // Inventory button
+ if (_inventoryButtonIndex == 0)
+ drawList.add(_gameModule->getGuiSpriteIndex(18 + 0), 97, 13, 1);
+ else if (_inventoryButtonIndex == 1)
+ drawList.add(_gameModule->getGuiSpriteIndex(18 + 1), 135, 15, 1);
+ else if (_inventoryButtonIndex == 2)
+ drawList.add(_gameModule->getGuiSpriteIndex(18 + 2), 202, 13, 1);
+
+ // Inventory items
+ int currItem = -1;
+ if (_currVerbNum == kVerbInvItem)
+ currItem = _currInventoryItem;
+ for (int i = 0; i < 50; ++i)
+ if (_inventoryItemStatus[i] && currItem != i)
+ drawList.add(_gameModule->getInventoryItemSpriteIndex(i * 2), kInventorySlotPositions[i].x, kInventorySlotPositions[i].y, 1);
+
+ } else {
+
+ // Scene objects
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *sceneObject = &_sceneObjects[i];
+ Animation *anim = sceneObject->anim;
+ if (anim) {
+ drawList.add(anim->frameSpriteIndices[sceneObject->frameIndex],
+ (sceneObject->x >> 16) - _cameraPos.x, (sceneObject->y >> 16) - _cameraPos.y,
+ sceneObject->y >> 16);
+ }
+ }
+
+ // Background objects
+ for (int i = 0; i < _gameModule->getBgSpritesCount(); ++i)
+ drawList.add(_gameModule->getBgSpriteIndex(i), -_cameraPos.x, -_cameraPos.y, _gameModule->getBgSpritePriority(i));
+
+ if (_gameState == kGSVerbs) {
+ // Verbs icon background
+ for (int i = 0; i < 6; ++i) {
+ if (i != 4) {
+ int index = (i == _activeItemIndex) ? 17 : 16;
+ drawList.add(_gameModule->getGuiSpriteIndex(index), _verbPos.x + kVerbRects[i].x - _cameraPos.x,
+ _verbPos.y + kVerbRects[i].y - _cameraPos.y, 499);
+ }
+ }
+ // Verbs background
+ drawList.add(_gameModule->getGuiSpriteIndex(13), _verbPos.x - _cameraPos.x,
+ _verbPos.y - _cameraPos.y, 500);
+ // Selected inventory item
+ if (_currInventoryItem >= 0) {
+ drawList.add(_gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem), _verbPos.x - _cameraPos.x,
+ _verbPos.y - _cameraPos.y + 27, 500);
+ }
+ }
+
+ if (_gameState == kGSDialog) {
+ // Dialog background
+ drawList.add(_gameModule->getGuiSpriteIndex(14), 0, 0, 500);
+ // Dialog icons
+ int iconX = 16;
+ for (int i = 0; i < 50; ++i)
+ if (_dialogItemStatus[i]) {
+ drawList.add(_gameModule->getDialogItemSpriteIndex(i), iconX, 36, 501);
+ iconX += 32;
+ }
+ }
+
+ }
+
+ // Mouse cursor
+ if (_mouseCursorSpriteIndex > 0 && _mousePos.x >= 0)
+ drawList.add(_mouseCursorSpriteIndex, _mousePos.x - _cameraPos.x, _mousePos.y - _cameraPos.y, 1000);
+
+}
+
+void BbvsEngine::updateVerbs() {
+
+ _activeItemIndex = 99;
+
+ if (_mousePos.x < 0) {
+ _mouseCursorSpriteIndex = 0;
+ return;
+ }
+
+ for (int i = 0; i < 6; ++i) {
+ const BBRect &verbRect = kVerbRects[i];
+ const int16 x = _verbPos.x + verbRect.x;
+ const int16 y = _verbPos.y + verbRect.y;
+ if (Common::Rect(x, y, x + verbRect.width, y + verbRect.height).contains(_mousePos)) {
+ if (i != kVerbInvItem || _currInventoryItem >= 0) {
+ _currVerbNum = i;
+ _activeItemIndex = i;
+ }
+ break;
+ }
+ }
+
+ switch (_currVerbNum) {
+ case kVerbLook:
+ case kVerbUse:
+ case kVerbTalk:
+ case kVerbWalk:
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(2 * _currVerbNum);
+ break;
+ case kVerbInvItem:
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem);
+ break;
+ case kVerbShowInv:
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(8);
+ break;
+ }
+
+}
+
+void BbvsEngine::updateDialog(bool clicked) {
+
+ if (_mousePos.x < 0) {
+ _mouseCursorSpriteIndex = 0;
+ _activeItemType = 0;
+ return;
+ }
+
+ if (_mousePos.y > 32) {
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(10);
+ _activeItemIndex = 0;
+ _activeItemType = kITEmpty;
+ if (clicked)
+ _gameState = kGSScene;
+ return;
+ }
+
+ int slotX = (_mousePos.x - _cameraPos.x) / 32;
+
+ if (slotX >= _dialogSlotCount) {
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(4);
+ _activeItemType = kITEmpty;
+ _activeItemIndex = 0;
+ return;
+ }
+
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(5);
+ _activeItemType = kITDialog;
+
+ // Find the selected dialog item index
+ for (int i = 0; i < 50 && slotX >= 0; ++i) {
+ if (_dialogItemStatus[i]) {
+ --slotX;
+ _activeItemIndex = i;
+ }
+ }
+
+ // Select the dialog item action if it was clicked
+ if (clicked) {
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ if (evalCondition(action->conditions)) {
+ _mouseCursorSpriteIndex = 0;
+ _gameState = kGSWaitDialog;
+ _currAction = action;
+ break;
+ }
+ }
+ }
+
+}
+
+void BbvsEngine::updateInventory(bool clicked) {
+
+ Common::Rect kInvButtonRects[3] = {
+ Common::Rect(97, 13, 97 + 20, 13 + 26),
+ Common::Rect(135, 15, 135 + 46, 15 + 25),
+ Common::Rect(202, 13, 202 + 20, 13 + 26)};
+
+ if (_mousePos.x < 0) {
+ _mouseCursorSpriteIndex = 0;
+ _activeItemType = 0;
+ return;
+ }
+
+ if (_currVerbNum != kVerbLook && _currVerbNum != kVerbUse && _currVerbNum != kVerbInvItem)
+ _currVerbNum = kVerbUse;
+
+ const int16 mx = _mousePos.x - _cameraPos.x;
+ const int16 my = _mousePos.y - _cameraPos.y;
+
+ // Check inventory exit left/right edge of screen
+ if (mx < 40 || mx > 280) {
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(10);
+ _activeItemIndex = 0;
+ _activeItemType = kITEmpty;
+ if (clicked) {
+ _gameState = kGSScene;
+ stopSpeech();
+ }
+ return;
+ }
+
+ // Check hovered/clicked inventory button
+ _inventoryButtonIndex = -1;
+ if (kInvButtonRects[0].contains(mx, my)) {
+ _inventoryButtonIndex = 0;
+ if (clicked)
+ _currVerbNum = kVerbLook;
+ } else if (kInvButtonRects[2].contains(mx, my)) {
+ _inventoryButtonIndex = 2;
+ if (clicked)
+ _currVerbNum = kVerbUse;
+ } else if (kInvButtonRects[1].contains(mx, my)) {
+ _inventoryButtonIndex = 1;
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(10);
+ _activeItemIndex = 0;
+ _activeItemType = kITEmpty;
+ if (clicked) {
+ _gameState = kGSScene;
+ stopSpeech();
+ }
+ return;
+ }
+
+ // Find hovered/clicked inventory item
+
+ int currItem = -1;
+
+ if (_currVerbNum == kVerbInvItem)
+ currItem = _currInventoryItem;
+
+ _activeItemType = kITEmpty;
+
+ for (int i = 0; i < 50; ++i) {
+ if (_inventoryItemStatus[i] && i != currItem) {
+ InventoryItemInfo *info = _gameModule->getInventoryItemInfo(i);
+ const int16 sx = kInventorySlotPositions[i].x + info->xOffs;
+ const int16 sy = kInventorySlotPositions[i].y + info->yOffs;
+ if (Common::Rect(sx, sy, sx + info->width, sy + info->height).contains(mx, my)) {
+ _activeItemType = kITInvItem;
+ _activeItemIndex = i;
+ break;
+ }
+ }
+ }
+
+ // Update mouse cursor and select inventory item if clicked
+
+ if (_activeItemType == kITInvItem) {
+ if (clicked) {
+ if (_currVerbNum == kVerbLook) {
+ stopSpeech();
+ playSpeech(_activeItemIndex + 10000);
+ } else if (_currVerbNum == kVerbUse) {
+ _currInventoryItem = _activeItemIndex;
+ _currVerbNum = kVerbInvItem;
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(2 * _activeItemIndex);
+ } else if (_currVerbNum == kVerbInvItem) {
+ if ((_currInventoryItem == 22 && _activeItemIndex == 39) ||
+ (_currInventoryItem == 39 && _activeItemIndex == 22)) {
+ _inventoryItemStatus[22] = 0;
+ _inventoryItemStatus[39] = 0;
+ _inventoryItemStatus[40] = 1;
+ _currVerbNum = kVerbInvItem;
+ _currInventoryItem = 40;
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(40);
+ }
+ if ((_currInventoryItem == 25 && _activeItemIndex == 26) ||
+ (_currInventoryItem == 26 && _activeItemIndex == 25)) {
+ _inventoryItemStatus[26] = 0;
+ _inventoryItemStatus[25] = 0;
+ _inventoryItemStatus[27] = 1;
+ _currVerbNum = kVerbInvItem;
+ _currInventoryItem = 27;
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(27);
+ }
+ }
+ } else {
+ if (_currVerbNum == kVerbLook)
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(1);
+ else if (_currVerbNum == kVerbUse)
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(3);
+ else if (_currVerbNum == kVerbInvItem)
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem + 1);
+ }
+ } else {
+ if (_currVerbNum >= kVerbInvItem)
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem);
+ else
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(2 * _currVerbNum);
+ }
+
+}
+
+void BbvsEngine::updateScene(bool clicked) {
+
+ if (_mousePos.x < 0) {
+ _mouseCursorSpriteIndex = 0;
+ _activeItemType = kITNone;
+ return;
+ }
+
+ int lastPriority = 0;
+
+ _activeItemType = kITEmpty;
+
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *sceneObject = &_sceneObjects[i];
+ if (sceneObject->anim) {
+ Common::Rect frameRect = sceneObject->anim->frameRects1[sceneObject->frameIndex];
+ const int objY = sceneObject->y >> 16;
+ frameRect.translate(sceneObject->x >> 16, objY);
+ if (lastPriority <= objY && frameRect.width() > 0 && frameRect.contains(_mousePos)) {
+ lastPriority = objY;
+ _activeItemIndex = i;
+ _activeItemType = KITSceneObject;
+ }
+ }
+ }
+
+ for (int i = 0; i < _gameModule->getBgObjectsCount(); ++i) {
+ BgObject *bgObject = _gameModule->getBgObject(i);
+ if (lastPriority <= bgObject->rect.bottom && bgObject->rect.contains(_mousePos)) {
+ lastPriority = bgObject->rect.bottom;
+ _activeItemIndex = i;
+ _activeItemType = kITBgObject;
+ }
+ }
+
+ if (_currVerbNum >= kVerbInvItem)
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem);
+ else
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(2 * _currVerbNum);
+
+ bool checkMore = true;
+
+ if (_activeItemType == KITSceneObject || _activeItemType == kITBgObject) {
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ if (evalCondition(action->conditions)) {
+ checkMore = false;
+ if (clicked) {
+ _mouseCursorSpriteIndex = 0;
+ _gameState = kGSWait;
+ _currAction = action;
+ if (_currVerbNum == kVerbTalk)
+ _currTalkObjectIndex = _activeItemIndex;
+ if (_buttheadObject) {
+ _buttheadObject->walkDestPt.x = -1;
+ _buttheadObject->walkCount = 0;
+ }
+ } else {
+ if (_currVerbNum >= kVerbInvItem)
+ _mouseCursorSpriteIndex = _gameModule->getInventoryItemSpriteIndex(2 * _currInventoryItem + 1);
+ else
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(2 * _currVerbNum + 1);
+ }
+ break;
+ }
+ }
+ }
+
+ // Test scroll arrow left
+ if (checkMore && _buttheadObject && _buttheadObject->anim && _mousePos.x - _cameraPos.x < 16 && _currCameraNum > 0) {
+ --_currCameraNum;
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ if (evalCameraCondition(action->conditions, _currCameraNum + 1)) {
+ checkMore = false;
+ if (clicked) {
+ _mouseCursorSpriteIndex = 0;
+ _gameState = kGSWait;
+ _currAction = action;
+ _buttheadObject->walkDestPt.x = -1;
+ _buttheadObject->walkCount = 0;
+ } else {
+ _activeItemType = kITScroll;
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(12);
+ }
+ break;
+ }
+ }
+ ++_currCameraNum;
+ }
+
+ // Test scroll arrow right
+ if (checkMore && _buttheadObject && _buttheadObject->anim && _mousePos.x - _cameraPos.x >= 304 && _currCameraNum < 4) {
+ ++_currCameraNum;
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ if (evalCameraCondition(action->conditions, _currCameraNum - 1)) {
+ checkMore = false;
+ if (clicked) {
+ _mouseCursorSpriteIndex = 0;
+ _gameState = kGSWait;
+ _currAction = action;
+ _buttheadObject->walkDestPt.x = -1;
+ _buttheadObject->walkCount = 0;
+ } else {
+ _activeItemType = kITScroll;
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(11);
+ }
+ break;
+ }
+ }
+ --_currCameraNum;
+ }
+
+ if (checkMore && _buttheadObject && _buttheadObject->anim) {
+ _walkMousePos = _mousePos;
+
+ while (1) {
+ int foundIndex = -1;
+
+ for (int i = 0; i < _walkableRectsCount; ++i)
+ if (_walkableRects[i].contains(_walkMousePos)) {
+ foundIndex = i;
+ break;
+ }
+
+ if (foundIndex >= 0) {
+ if (_walkMousePos.y != _mousePos.y)
+ _walkMousePos.y = _walkableRects[foundIndex].top;
+ break;
+ } else {
+ _walkMousePos.y += 4;
+ if (_walkMousePos.y >= 240)
+ break;
+ }
+
+ }
+
+ if (_beavisObject->anim) {
+ Common::Rect frameRect = _beavisObject->anim->frameRects2[_beavisObject->frameIndex];
+ frameRect.translate(_beavisObject->x >> 16, (_beavisObject->y >> 16) + 1);
+ if (!frameRect.isEmpty() && frameRect.contains(_walkMousePos))
+ _walkMousePos.y = frameRect.bottom;
+ }
+
+ if (_walkMousePos.y < 240 && canButtheadWalkToDest(_walkMousePos)) {
+ if (clicked) {
+ _buttheadObject->walkDestPt = _walkMousePos;
+ _buttheadObject->walkCount = 0;
+ }
+ for (int i = 0; i < _gameModule->getSceneExitsCount(); ++i) {
+ SceneExit *sceneExit = _gameModule->getSceneExit(i);
+ if (sceneExit->rect.contains(_walkMousePos.x, _walkMousePos.y)) {
+ _activeItemIndex = i;
+ _activeItemType = kITSceneExit;
+ _mouseCursorSpriteIndex = _gameModule->getGuiSpriteIndex(10);
+ }
+ }
+ } else {
+ _walkMousePos.x = -1;
+ _walkMousePos.y = -1;
+ }
+
+ }
+
+}
+
+bool BbvsEngine::performActionCommand(ActionCommand *actionCommand) {
+ debug(5, "BbvsEngine::performActionCommand() cmd: %d", actionCommand->cmd);
+
+ switch (actionCommand->cmd) {
+
+ case kActionCmdStop:
+ stopSpeech();
+ return false;
+
+ case kActionCmdWalkObject:
+ {
+ SceneObject *sceneObject = &_sceneObjects[actionCommand->sceneObjectIndex];
+ debug(5, "[%s] walks from (%d, %d) to (%d, %d)", sceneObject->sceneObjectDef->name,
+ sceneObject->x >> 16, sceneObject->y >> 16, actionCommand->walkDest.x, actionCommand->walkDest.y);
+ walkObject(sceneObject, actionCommand->walkDest, actionCommand->param);
+ }
+ return true;
+
+ case kActionCmdMoveObject:
+ {
+ SceneObject *sceneObject = &_sceneObjects[actionCommand->sceneObjectIndex];
+ sceneObject->x = actionCommand->walkDest.x << 16;
+ sceneObject->y = actionCommand->walkDest.y << 16;
+ sceneObject->xIncr = 0;
+ sceneObject->yIncr = 0;
+ sceneObject->walkCount = 0;
+ }
+ return true;
+
+ case kActionCmdAnimObject:
+ {
+ SceneObject *sceneObject = &_sceneObjects[actionCommand->sceneObjectIndex];
+ if (actionCommand->param == 0) {
+ sceneObject->anim = 0;
+ sceneObject->animIndex = 0;
+ sceneObject->frameTicks = 0;
+ sceneObject->frameIndex = 0;
+ } else if (actionCommand->timeStamp != 0 || sceneObject->anim != _gameModule->getAnimation(actionCommand->param)) {
+ sceneObject->animIndex = actionCommand->param;
+ sceneObject->anim = _gameModule->getAnimation(actionCommand->param);
+ sceneObject->frameIndex = sceneObject->anim->frameCount - 1;
+ sceneObject->frameTicks = 1;
+ }
+ }
+ return true;
+
+ case kActionCmdSetCameraPos:
+ _currCameraNum = actionCommand->param;
+ _newCameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos;
+ updateBackgroundSounds();
+ return true;
+
+ case kActionCmdPlaySpeech:
+ playSpeech(actionCommand->param);
+ return true;
+
+ case kActionCmdPlaySound:
+ playSound(actionCommand->param);
+ return true;
+
+ case kActionCmdStartBackgroundSound:
+ {
+ const uint soundIndex = _gameModule->getSceneSoundIndex(actionCommand->param);
+ if (!_backgroundSoundsActive[soundIndex]) {
+ _backgroundSoundsActive[soundIndex] = 1;
+ playSound(actionCommand->param, true);
+ }
+ }
+ return true;
+
+ case kActionCmdStopBackgroundSound:
+ {
+ const uint soundIndex = _gameModule->getSceneSoundIndex(actionCommand->param);
+ _backgroundSoundsActive[soundIndex] = 0;
+ stopSound(actionCommand->param);
+ }
+ return true;
+
+ default:
+ return true;
+
+ }
+
+}
+
+bool BbvsEngine::processCurrAction() {
+ bool actionsFinished = false;
+
+ if (_sceneObjectActions.size() == 0) {
+
+ for (uint i = 0; i < _currAction->actionCommands.size(); ++i) {
+ ActionCommand *actionCommand = &_currAction->actionCommands[i];
+ if (actionCommand->timeStamp != 0)
+ break;
+
+ if (actionCommand->cmd == kActionCmdMoveObject || actionCommand->cmd == kActionCmdAnimObject) {
+ SceneObjectAction *sceneObjectAction = 0;
+ // See if there's already an entry for the SceneObject
+ for (uint j = 0; j < _sceneObjectActions.size(); ++j)
+ if (_sceneObjectActions[j].sceneObjectIndex == actionCommand->sceneObjectIndex) {
+ sceneObjectAction = &_sceneObjectActions[j];
+ break;
+ }
+ // If not, add one
+ if (!sceneObjectAction) {
+ SceneObjectAction newSceneObjectAction;
+ newSceneObjectAction.sceneObjectIndex = actionCommand->sceneObjectIndex;
+ _sceneObjectActions.push_back(newSceneObjectAction);
+ sceneObjectAction = &_sceneObjectActions.back();
+ }
+ if (actionCommand->cmd == kActionCmdMoveObject) {
+ sceneObjectAction->walkDest = actionCommand->walkDest;
+ } else {
+ sceneObjectAction->animationIndex = actionCommand->param;
+ }
+ }
+
+ if (actionCommand->cmd == kActionCmdSetCameraPos) {
+ _currCameraNum = actionCommand->param;
+ _newCameraPos = _gameModule->getCameraInit(actionCommand->param)->cameraPos;
+ }
+
+ }
+
+ // Delete entries for SceneObjects without anim
+ for (uint i = 0; i < _sceneObjectActions.size();) {
+ if (!_sceneObjects[_sceneObjectActions[i].sceneObjectIndex].anim)
+ _sceneObjectActions.remove_at(i);
+ else
+ ++i;
+ }
+
+ // Prepare affected scene objects
+ for (uint i = 0; i < _sceneObjectActions.size(); ++i) {
+ _sceneObjects[_sceneObjectActions[i].sceneObjectIndex].walkCount = 0;
+ _sceneObjects[_sceneObjectActions[i].sceneObjectIndex].turnCount = 0;
+ }
+
+ }
+
+ actionsFinished = true;
+
+ // Update SceneObject actions (walk and turn)
+ for (uint i = 0; i < _sceneObjectActions.size(); ++i) {
+ SceneObjectAction *soAction = &_sceneObjectActions[i];
+ SceneObject *sceneObject = &_sceneObjects[soAction->sceneObjectIndex];
+ if (sceneObject->walkDestPt.x != -1) {
+ debug(5, "waiting for walk to finish");
+ actionsFinished = false;
+ } else if ((int16)(sceneObject->x >> 16) != soAction->walkDest.x || (int16)(sceneObject->y >> 16) != soAction->walkDest.y) {
+ debug(5, "starting to walk");
+ sceneObject->walkDestPt = soAction->walkDest;
+ actionsFinished = false;
+ } else if (sceneObject->walkCount == 0 && sceneObject->turnCount == 0) {
+ debug(5, "not walking");
+ for (int turnCount = 0; turnCount < 8; ++turnCount)
+ if (sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[turnCount]] == soAction->animationIndex && sceneObject->turnValue != turnCount) {
+ sceneObject->turnCount = turnCount | 0x80;
+ break;
+ }
+ }
+ if (sceneObject->turnCount)
+ actionsFinished = false;
+ }
+
+ if (actionsFinished)
+ _sceneObjectActions.clear();
+
+ return actionsFinished;
+}
+
+void BbvsEngine::skipCurrAction() {
+ ActionCommands &actionCommands = _currAction->actionCommands;
+ while (_currAction && _newSceneNum == 0)
+ updateCommon();
+ for (uint i = 0; i < actionCommands.size(); ++i)
+ if (actionCommands[i].cmd == kActionCmdPlaySound)
+ stopSound(actionCommands[i].param);
+ _system->delayMillis(250);
+ _gameTicks = 0;
+}
+
+void BbvsEngine::updateCommon() {
+
+ if (_currAction) {
+
+ bool doActionCommands = true;
+
+ if (_currActionCommandTimeStamp == 0) {
+ doActionCommands = processCurrAction();
+ _currActionCommandIndex = 0;
+ }
+
+ if (doActionCommands) {
+
+ ActionCommand *actionCommand = &_currAction->actionCommands[_currActionCommandIndex];
+
+ while (actionCommand->timeStamp == _currActionCommandTimeStamp &&
+ _currActionCommandIndex < (int)_currAction->actionCommands.size()) {
+ if (!performActionCommand(actionCommand)) {
+ _gameState = kGSScene;
+ evalActionResults(_currAction->results);
+ if (_gameState == kGSDialog)
+ updateDialogConditions();
+ _currAction = 0;
+ _currActionCommandTimeStamp = 0;
+ _currActionCommandIndex = -1;
+ updateSceneObjectsTurnValue();
+ updateWalkableRects();
+ break;
+ }
+ actionCommand = &_currAction->actionCommands[++_currActionCommandIndex];
+ }
+
+ if (_currAction) {
+ ++_currActionCommandTimeStamp;
+ } else {
+ _activeItemIndex = 0;
+ _mouseCursorSpriteIndex = 0;
+ _activeItemType = kITEmpty;
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ if (evalCondition(action->conditions)) {
+ _gameState = kGSWait;
+ _currAction = action;
+ }
+ }
+ }
+
+ }
+
+ }
+
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *sceneObject = &_sceneObjects[i];
+
+ if (sceneObject->walkDestPt.x != -1) {
+ if (sceneObject->walkCount == 0) {
+ debug(5, "[%s] needs to walk", sceneObject->sceneObjectDef->name);
+ startWalkObject(sceneObject);
+ if (sceneObject->walkCount == 0) {
+ debug(5, "no walk possible");
+ sceneObject->walkDestPt.x = -1;
+ sceneObject->walkDestPt.y = -1;
+ sceneObject->xIncr = 0;
+ sceneObject->yIncr = 0;
+ }
+ }
+ updateWalkObject(sceneObject);
+ }
+
+ if (sceneObject->walkCount > 0 && sceneObject->turnCount == 0) {
+ debug(5, "walk step, xIncr: %d, yIncr: %d", sceneObject->xIncr, sceneObject->yIncr);
+ sceneObject->x += sceneObject->xIncr;
+ sceneObject->y += sceneObject->yIncr;
+ --sceneObject->walkCount;
+ } else if (sceneObject->turnCount != 0) {
+ debug(5, "need turn, turnCount: %d", sceneObject->turnCount);
+ turnObject(sceneObject);
+ }
+
+ if (sceneObject == _buttheadObject && sceneObject->walkDestPt.x != -1) {
+ for (uint j = 0; j < _walkAreaActions.size(); ++j) {
+ if (_walkAreaActions[j] != _currAction && evalCondition(_walkAreaActions[j]->conditions)) {
+ _sceneObjectActions.clear();
+ _gameState = kGSWait;
+ _currAction = _walkAreaActions[j];
+ _currActionCommandTimeStamp = 0;
+ _currActionCommandIndex = -1;
+ for (int k = 0; k < _gameModule->getSceneObjectDefsCount(); ++k) {
+ SceneObject *sceneObject2 = &_sceneObjects[k];
+ sceneObject2->walkDestPt.x = -1;
+ sceneObject2->walkDestPt.y = -1;
+ sceneObject2->walkCount = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ if (sceneObject->anim && --sceneObject->frameTicks == 0) {
+ if (++sceneObject->frameIndex >= sceneObject->anim->frameCount)
+ sceneObject->frameIndex = 0;
+ sceneObject->frameTicks = sceneObject->anim->frameTicks[sceneObject->frameIndex];
+ }
+
+ }
+
+ if (!_currAction && _buttheadObject) {
+ int16 buttheadX = _buttheadObject->x >> 16;
+ int16 buttheadY = _buttheadObject->y >> 16;
+ CameraInit *cameraInit = _gameModule->getCameraInit(_currCameraNum);
+ for (int i = 0; i < 8; ++i) {
+ if (cameraInit->rects[i].contains(buttheadX, buttheadY)) {
+ int newCameraNum = cameraInit->cameraLinks[i];
+ if (_currCameraNum != newCameraNum) {
+ int prevCameraNum = _currCameraNum;
+ _currCameraNum = newCameraNum;
+ _newCameraPos = _gameModule->getCameraInit(newCameraNum)->cameraPos;
+ for (int j = 0; j < _gameModule->getActionsCount(); ++j) {
+ Action *action = _gameModule->getAction(j);
+ if (evalCameraCondition(action->conditions, prevCameraNum)) {
+ _gameState = kGSWait;
+ _currAction = action;
+ _mouseCursorSpriteIndex = 0;
+ _buttheadObject->walkDestPt.x = -1;
+ _buttheadObject->walkCount = 0;
+ break;
+ }
+ }
+ updateBackgroundSounds();
+ }
+ }
+ }
+ }
+
+ if (_cameraPos.x < _newCameraPos.x)
+ ++_cameraPos.x;
+ if (_cameraPos.x > _newCameraPos.x)
+ --_cameraPos.x;
+ if (_cameraPos.y < _newCameraPos.y)
+ ++_cameraPos.y;
+ if (_cameraPos.y > _newCameraPos.y)
+ --_cameraPos.y;
+
+ // Check if Butthead is inside a scene exit
+ if (_newSceneNum == 0 && !_currAction && _buttheadObject) {
+ int16 buttheadX = _buttheadObject->x >> 16;
+ int16 buttheadY = _buttheadObject->y >> 16;
+ for (int i = 0; i < _gameModule->getSceneExitsCount(); ++i) {
+ SceneExit *sceneExit = _gameModule->getSceneExit(i);
+ if (sceneExit->rect.contains(buttheadX, buttheadY)) {
+ _newSceneNum = sceneExit->newModuleNum;
+ break;
+ }
+ }
+ }
+
+}
+
+void BbvsEngine::startWalkObject(SceneObject *sceneObject) {
+ const int kMaxDistance = 0xFFFFFF;
+
+ if (_buttheadObject != sceneObject && _beavisObject != sceneObject)
+ return;
+
+ initWalkAreas(sceneObject);
+ _sourceWalkAreaPt.x = sceneObject->x >> 16;
+ _sourceWalkAreaPt.y = sceneObject->y >> 16;
+
+ _sourceWalkArea = getWalkAreaAtPos(_sourceWalkAreaPt);
+ if (!_sourceWalkArea)
+ return;
+
+ _destWalkAreaPt = sceneObject->walkDestPt;
+
+ _destWalkArea = getWalkAreaAtPos(_destWalkAreaPt);
+ if (!_destWalkArea)
+ return;
+
+ if (_sourceWalkArea != _destWalkArea) {
+ _currWalkDistance = kMaxDistance;
+ walkFindPath(_sourceWalkArea, 0);
+ _destWalkAreaPt = _currWalkDistance == kMaxDistance ? _sourceWalkAreaPt : _finalWalkPt;
+ }
+
+ walkObject(sceneObject, _destWalkAreaPt, sceneObject->sceneObjectDef->walkSpeed);
+
+}
+
+void BbvsEngine::updateWalkObject(SceneObject *sceneObject) {
+ int animIndex;
+
+ if (sceneObject->walkCount > 0 && (sceneObject->xIncr != 0 || sceneObject->yIncr != 0)) {
+ if (ABS(sceneObject->xIncr) <= ABS(sceneObject->yIncr))
+ sceneObject->turnValue = sceneObject->yIncr >= 0 ? 0 : 4;
+ else
+ sceneObject->turnValue = sceneObject->xIncr >= 0 ? 6 : 2;
+ animIndex = sceneObject->sceneObjectDef->animIndices[kWalkAnimTbl[sceneObject->turnValue]];
+ sceneObject->turnCount = 0;
+ sceneObject->turnTicks = 0;
+ } else {
+ animIndex = sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[sceneObject->turnValue]];
+ }
+
+ Animation *anim = 0;
+ if (animIndex > 0)
+ anim = _gameModule->getAnimation(animIndex);
+
+ if (sceneObject->anim != anim) {
+ if (anim) {
+ sceneObject->anim = anim;
+ sceneObject->animIndex = animIndex;
+ sceneObject->frameTicks = 1;
+ sceneObject->frameIndex = anim->frameCount - 1;
+ } else {
+ sceneObject->anim = 0;
+ sceneObject->animIndex = 0;
+ sceneObject->frameTicks = 0;
+ sceneObject->frameIndex = 0;
+ }
+ }
+
+}
+
+void BbvsEngine::walkObject(SceneObject *sceneObject, const Common::Point &destPt, int walkSpeed) {
+ int deltaX = destPt.x - (sceneObject->x >> 16);
+ int deltaY = destPt.y - (sceneObject->y >> 16);
+ float distance = sqrt((double)(deltaX * deltaX + deltaY * deltaY));
+ // NOTE The original doesn't have this check but without it the whole pathfinding breaks
+ if (distance > 0.0) {
+ sceneObject->walkCount = distance / ((((float)ABS(deltaX) / distance) + 1.0) * ((float)walkSpeed / 120));
+ sceneObject->xIncr = ((float)deltaX / sceneObject->walkCount) * 65536.0;
+ sceneObject->yIncr = ((float)deltaY / sceneObject->walkCount) * 65536.0;
+ sceneObject->x = (sceneObject->x & 0xFFFF0000) | 0x8000;
+ sceneObject->y = (sceneObject->y & 0xFFFF0000) | 0x8000;
+ } else
+ sceneObject->walkCount = 0;
+}
+
+void BbvsEngine::turnObject(SceneObject *sceneObject) {
+ if (sceneObject->turnTicks > 0) {
+ --sceneObject->turnTicks;
+ } else {
+ int turnDir = kTurnInfo[sceneObject->turnValue][sceneObject->turnCount & 0x7F];
+ if (turnDir) {
+ sceneObject->turnValue = (sceneObject->turnValue + turnDir) & 7;
+ int turnAnimIndex = sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[sceneObject->turnValue]];
+ if (turnAnimIndex) {
+ Animation *anim = _gameModule->getAnimation(turnAnimIndex);
+ if (anim) {
+ sceneObject->anim = anim;
+ sceneObject->animIndex = turnAnimIndex;
+ sceneObject->turnTicks = 4;
+ sceneObject->frameTicks = 1;
+ sceneObject->frameIndex = anim->frameCount - 1;
+ }
+ }
+ } else {
+ sceneObject->turnCount = 0;
+ }
+ }
+}
+
+int BbvsEngine::rectSubtract(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect *outRects) {
+ int count = 0;
+ Common::Rect workRect = rect1.findIntersectingRect(rect2);
+ if (!workRect.isEmpty()) {
+ count = 0;
+ outRects[count] = Common::Rect(rect2.width(), workRect.top - rect2.top);
+ if (!outRects[count].isEmpty()) {
+ outRects[count].translate(rect2.left, rect2.top);
+ ++count;
+ }
+ outRects[count] = Common::Rect(workRect.left - rect2.left, workRect.height());
+ if (!outRects[count].isEmpty()) {
+ outRects[count].translate(rect2.left, workRect.top);
+ ++count;
+ }
+ outRects[count] = Common::Rect(rect2.right - workRect.right, workRect.height());
+ if (!outRects[count].isEmpty()) {
+ outRects[count].translate(workRect.right, workRect.top);
+ ++count;
+ }
+ outRects[count] = Common::Rect(rect2.width(), rect2.bottom - workRect.bottom);
+ if (!outRects[count].isEmpty()) {
+ outRects[count].translate(rect2.left, workRect.bottom);
+ ++count;
+ }
+ } else {
+ outRects[0] = rect2;
+ count = 1;
+ }
+ return count;
+}
+
+WalkInfo *BbvsEngine::addWalkInfo(int16 x, int16 y, int delta, int direction, int16 midPtX, int16 midPtY, int walkAreaIndex) {
+ WalkInfo *walkInfo = &_walkInfos[_walkInfosCount++];
+ walkInfo->walkAreaIndex = walkAreaIndex;
+ walkInfo->direction = direction;
+ walkInfo->x = x;
+ walkInfo->y = y;
+ walkInfo->delta = delta;
+ walkInfo->midPt.x = midPtX;
+ walkInfo->midPt.y = midPtY;
+ return walkInfo;
+}
+
+void BbvsEngine::initWalkAreas(SceneObject *sceneObject) {
+ int16 objX = sceneObject->x >> 16;
+ int16 objY = sceneObject->y >> 16;
+ Common::Rect rect;
+ bool doRect = false;
+ Common::Rect *workWalkableRects;
+
+ if (_buttheadObject == sceneObject && _beavisObject->anim) {
+ rect = _beavisObject->anim->frameRects2[_beavisObject->frameIndex];
+ rect.translate(_beavisObject->x >> 16, 1 + (_beavisObject->y >> 16));
+ doRect = !rect.isEmpty();
+ } else if (_buttheadObject->anim) {
+ rect = _buttheadObject->anim->frameRects2[_buttheadObject->frameIndex];
+ rect.translate(_buttheadObject->x >> 16, 1 + (_buttheadObject->y >> 16));
+ doRect = !rect.isEmpty();
+ }
+
+ workWalkableRects = _walkableRects;
+
+ _walkAreasCount = _walkableRectsCount;
+
+ if (doRect && !rect.contains(objX, objY)) {
+ _walkAreasCount = 0;
+ for (int i = 0; i < _walkableRectsCount; ++i)
+ _walkAreasCount += rectSubtract(rect, _walkableRects[i], &_tempWalkableRects1[_walkAreasCount]);
+ workWalkableRects = _tempWalkableRects1;
+ }
+
+ for (int i = 0; i < _walkAreasCount; ++i) {
+ _walkAreas[i].x = workWalkableRects[i].left;
+ _walkAreas[i].y = workWalkableRects[i].top;
+ _walkAreas[i].width = workWalkableRects[i].width();
+ _walkAreas[i].height = workWalkableRects[i].height();
+ _walkAreas[i].checked = false;
+ _walkAreas[i].linksCount = 0;
+ }
+
+ _walkInfosCount = 0;
+
+ // Find connections between the walkRects
+
+ for (int i = 0; i < _walkAreasCount; ++i) {
+ WalkArea *walkArea1 = &_walkAreas[i];
+ int xIter = walkArea1->x + walkArea1->width;
+ int yIter = walkArea1->y + walkArea1->height;
+
+ for (int j = 0; j < _walkAreasCount; ++j) {
+ WalkArea *walkArea2 = &_walkAreas[j];
+
+ if (i == j)
+ continue;
+
+ if (walkArea2->y == yIter) {
+ int wa1x = MAX(walkArea1->x, walkArea2->x);
+ int wa2x = MIN(walkArea2->x + walkArea2->width, xIter);
+ if (wa2x > wa1x) {
+ debug(5, "WalkArea %d connected to %d by Y", i, j);
+ WalkInfo *walkInfo1 = addWalkInfo(wa1x, yIter - 1, wa2x - wa1x, 0, wa1x + (wa2x - wa1x) / 2, yIter - 1, i);
+ WalkInfo *walkInfo2 = addWalkInfo(wa1x, yIter, wa2x - wa1x, 0, wa1x + (wa2x - wa1x) / 2, yIter, j);
+ walkArea1->linksD1[walkArea1->linksCount] = walkInfo1;
+ walkArea1->linksD2[walkArea1->linksCount] = walkInfo2;
+ walkArea1->links[walkArea1->linksCount++] = walkArea2;
+ walkArea2->linksD1[walkArea2->linksCount] = walkInfo2;
+ walkArea2->linksD2[walkArea2->linksCount] = walkInfo1;
+ walkArea2->links[walkArea2->linksCount++] = walkArea1;
+ }
+ }
+
+ if (walkArea2->x == xIter) {
+ int wa1y = MAX(walkArea1->y, walkArea2->y);
+ int wa2y = MIN(walkArea2->y + walkArea2->height, yIter);
+ if (wa2y > wa1y) {
+ debug(5, "WalkArea %d connected to %d by X", i, j);
+ WalkInfo *walkInfo1 = addWalkInfo(xIter - 1, wa1y, wa2y - wa1y, 1, xIter - 1, wa1y + (wa2y - wa1y) / 2, i);
+ WalkInfo *walkInfo2 = addWalkInfo(xIter, wa1y, wa2y - wa1y, 1, xIter, wa1y + (wa2y - wa1y) / 2, j);
+ walkArea1->linksD1[walkArea1->linksCount] = walkInfo1;
+ walkArea1->linksD2[walkArea1->linksCount] = walkInfo2;
+ walkArea1->links[walkArea1->linksCount++] = walkArea2;
+ walkArea2->linksD1[walkArea2->linksCount] = walkInfo2;
+ walkArea2->linksD2[walkArea2->linksCount] = walkInfo1;
+ walkArea2->links[walkArea2->linksCount++] = walkArea1;
+ }
+ }
+
+ }
+
+ }
+
+}
+
+WalkArea *BbvsEngine::getWalkAreaAtPos(const Common::Point &pt) {
+ for (int i = 0; i < _walkAreasCount; ++i) {
+ WalkArea *walkArea = &_walkAreas[i];
+ if (walkArea->contains(pt))
+ return walkArea;
+ }
+ return 0;
+}
+
+bool BbvsEngine::canButtheadWalkToDest(const Common::Point &destPt) {
+ Common::Point srcPt;
+
+ _walkReachedDestArea = false;
+ initWalkAreas(_buttheadObject);
+ srcPt.x = _buttheadObject->x >> 16;
+ srcPt.y = _buttheadObject->y >> 16;
+ _sourceWalkArea = getWalkAreaAtPos(srcPt);
+ if (_sourceWalkArea) {
+ _destWalkArea = getWalkAreaAtPos(destPt);
+ if (_destWalkArea)
+ canWalkToDest(_sourceWalkArea, 0);
+ }
+ return _walkReachedDestArea;
+}
+
+void BbvsEngine::canWalkToDest(WalkArea *walkArea, int infoCount) {
+
+ if (_destWalkArea == walkArea) {
+ _walkReachedDestArea = true;
+ return;
+ }
+
+ if (_gameModule->getFieldC() <= 320 || infoCount <= 20) {
+ walkArea->checked = true;
+ for (int linkIndex = 0; linkIndex < walkArea->linksCount; ++linkIndex) {
+ if (!walkArea->links[linkIndex]->checked) {
+ canWalkToDest(walkArea->links[linkIndex], infoCount + 2);
+ if (_walkReachedDestArea)
+ break;
+ }
+ }
+ walkArea->checked = false;
+ }
+
+}
+
+bool BbvsEngine::walkTestLineWalkable(const Common::Point &sourcePt, const Common::Point &destPt, WalkInfo *walkInfo) {
+ const float ptDeltaX = destPt.x - sourcePt.x;
+ const float ptDeltaY = destPt.y - sourcePt.y;
+ const float wDeltaX = walkInfo->x - sourcePt.x;
+ const float wDeltaY = walkInfo->y - sourcePt.y;
+ if (destPt.x == sourcePt.x)
+ return true;
+ if (walkInfo->direction) {
+ const float nDeltaY = wDeltaX * ptDeltaY / ptDeltaX + (float)sourcePt.y - (float)walkInfo->y;
+ return (nDeltaY >= 0.0) && (nDeltaY < (float)walkInfo->delta);
+ } else {
+ const float nDeltaX = wDeltaY / ptDeltaX * ptDeltaY + (float)sourcePt.x - (float)walkInfo->x;
+ return (nDeltaX >= 0.0) && (nDeltaX < (float)walkInfo->delta);
+ }
+ return false;
+}
+
+void BbvsEngine::walkFindPath(WalkArea *sourceWalkArea, int infoCount) {
+ if (_destWalkArea == sourceWalkArea) {
+ walkFoundPath(infoCount);
+ } else if (_gameModule->getFieldC() <= 320 || infoCount <= 20) {
+ sourceWalkArea->checked = true;
+ for (int linkIndex = 0; linkIndex < sourceWalkArea->linksCount; ++linkIndex) {
+ if (!sourceWalkArea->links[linkIndex]->checked) {
+ _walkInfoPtrs[infoCount + 0] = sourceWalkArea->linksD1[linkIndex];
+ _walkInfoPtrs[infoCount + 1] = sourceWalkArea->linksD2[linkIndex];
+ walkFindPath(sourceWalkArea->links[linkIndex], infoCount + 2);
+ }
+ }
+ sourceWalkArea->checked = false;
+ }
+}
+
+int BbvsEngine::calcDistance(const Common::Point &pt1, const Common::Point &pt2) {
+ return sqrt((pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y));
+}
+
+void BbvsEngine::walkFoundPath(int count) {
+ debug(5, "BbvsEngine::walkFoundPath(%d)", count);
+
+ Common::Point midPt = _sourceWalkAreaPt;
+ int totalMidPtDistance = 0;
+
+ if (count > 0) {
+ Common::Point lastMidPt;
+ int halfCount = (count + 1) >> 1;
+ for (int i = 0; i < halfCount; ++i) {
+ lastMidPt = midPt;
+ midPt = _walkInfoPtrs[i * 2]->midPt;
+ totalMidPtDistance += calcDistance(midPt, lastMidPt);
+ }
+ }
+
+ int distance = calcDistance(midPt, _destWalkAreaPt) + totalMidPtDistance;
+
+ debug(5, "BbvsEngine::walkFoundPath() distance: %d; _currWalkDistance: %d", distance, _currWalkDistance);
+
+ if (distance >= _currWalkDistance)
+ return;
+
+ debug(5, "BbvsEngine::walkFoundPath() distance smaller");
+
+ _currWalkDistance = distance;
+
+ Common::Point destPt = _destWalkAreaPt, newDestPt;
+
+ while (1) {
+
+ int index = 0;
+ if (count > 0) {
+ do {
+ if (!walkTestLineWalkable(_sourceWalkAreaPt, destPt, _walkInfoPtrs[index]))
+ break;
+ ++index;
+ } while (index < count);
+ }
+
+ if (index == count)
+ break;
+
+ WalkInfo *walkInfo = _walkInfoPtrs[--count];
+ destPt.x = walkInfo->x;
+ destPt.y = walkInfo->y;
+
+ if (walkInfo->direction) {
+ newDestPt.x = walkInfo->x;
+ newDestPt.y = walkInfo->y + walkInfo->delta - 1;
+ } else {
+ newDestPt.x = walkInfo->x + walkInfo->delta - 1;
+ newDestPt.y = walkInfo->y;
+ }
+
+ if ((newDestPt.x - _destWalkAreaPt.x) * (newDestPt.x - _destWalkAreaPt.x) +
+ (newDestPt.y - _destWalkAreaPt.y) * (newDestPt.y - _destWalkAreaPt.y) <
+ (destPt.x - _destWalkAreaPt.x) * (destPt.x - _destWalkAreaPt.x) +
+ (destPt.y - _destWalkAreaPt.y) * (destPt.y - _destWalkAreaPt.y))
+ destPt = newDestPt;
+
+ }
+
+ debug(5, "BbvsEngine::walkFoundPath() destPt: (%d, %d)", destPt.x, destPt.y);
+
+ _finalWalkPt = destPt;
+
+ debug(5, "BbvsEngine::walkFoundPath() OK");
+
+}
+
+void BbvsEngine::updateWalkableRects() {
+ // Go through all walkable rects and subtract all scene object rects
+ Common::Rect *rectsList1 = _tempWalkableRects1;
+ Common::Rect *rectsList2 = _gameModule->getWalkRects();
+ _walkableRectsCount = _gameModule->getWalkRectsCount();
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *sceneObject = &_sceneObjects[i];
+ Animation *anim = sceneObject->anim;
+ if (anim && _buttheadObject != sceneObject && _beavisObject != sceneObject) {
+ Common::Rect rect = sceneObject->anim->frameRects2[sceneObject->frameIndex];
+ rect.translate(sceneObject->x >> 16, sceneObject->y >> 16);
+ int count = _walkableRectsCount;
+ _walkableRectsCount = 0;
+ for (int j = 0; j < count; ++j)
+ _walkableRectsCount += rectSubtract(rect, rectsList2[j], &rectsList1[_walkableRectsCount]);
+ if (rectsList1 == _tempWalkableRects1) {
+ rectsList1 = _tempWalkableRects2;
+ rectsList2 = _tempWalkableRects1;
+ } else {
+ rectsList1 = _tempWalkableRects1;
+ rectsList2 = _tempWalkableRects2;
+ }
+ }
+ }
+ for (int i = 0; i < _walkableRectsCount; ++i)
+ _walkableRects[i] = rectsList2[i];
+}
+
+void BbvsEngine::updateSceneObjectsTurnValue() {
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *sceneObject = &_sceneObjects[i];
+ sceneObject->turnValue = 0;
+ for (int j = 0; j < 12; ++j) {
+ if (sceneObject->sceneObjectDef->animIndices[j] == sceneObject->animIndex) {
+ sceneObject->turnValue = kTurnTbl[j];
+ break;
+ }
+ }
+ }
+}
+
+void BbvsEngine::updateDialogConditions() {
+ _dialogSlotCount = 0;
+ memset(_dialogItemStatus, 0, sizeof(_dialogItemStatus));
+ for (int i = 0; i < _gameModule->getActionsCount(); ++i) {
+ Action *action = _gameModule->getAction(i);
+ int slotIndex = evalDialogCondition(action->conditions);
+ if (slotIndex >= 0) {
+ _dialogItemStatus[slotIndex] = 1;
+ ++_dialogSlotCount;
+ }
+ }
+}
+
+void BbvsEngine::playSpeech(int soundNum) {
+ debug(5, "playSpeech(%0d)", soundNum);
+ Common::String sndFilename = Common::String::format("snd/snd%05d.aif", soundNum);
+ Common::File *fd = new Common::File();
+ fd->open(sndFilename);
+ Audio::AudioStream *audioStream = Audio::makeAIFFStream(fd, DisposeAfterUse::YES);
+ _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechSoundHandle, audioStream);
+
+}
+
+void BbvsEngine::stopSpeech() {
+ _mixer->stopHandle(_speechSoundHandle);
+}
+
+void BbvsEngine::playSound(uint soundNum, bool loop) {
+ debug(5, "playSound(%0d)", soundNum);
+ for (uint i = 0; i < _gameModule->getPreloadSoundsCount(); ++i)
+ if (_gameModule->getPreloadSound(i) == soundNum) {
+ _sound->playSound(i, loop);
+ break;
+ }
+}
+
+void BbvsEngine::stopSound(uint soundNum) {
+ for (uint i = 0; i < _gameModule->getPreloadSoundsCount(); ++i)
+ if (_gameModule->getPreloadSound(i) == soundNum) {
+ _sound->stopSound(i);
+ break;
+ }
+}
+
+void BbvsEngine::stopSounds() {
+ _sound->stopAllSounds();
+}
+
+bool BbvsEngine::runMinigame(int minigameNum) {
+ debug(0, "BbvsEngine::runMinigame() minigameNum: %d", minigameNum);
+
+ bool fromMainGame = _currSceneNum != kMainMenu;
+
+ _sound->unloadSounds();
+
+ Minigame *minigame = 0;
+
+ switch (minigameNum) {
+ case kMinigameBbLoogie:
+ minigame = new MinigameBbLoogie(this);
+ break;
+ case kMinigameBbTennis:
+ minigame = new MinigameBbTennis(this);
+ break;
+ case kMinigameBbAnt:
+ minigame = new MinigameBbAnt(this);
+ break;
+ case kMinigameBbAirGuitar:
+ minigame = new MinigameBbAirGuitar(this);
+ break;
+ default:
+ error("Incorrect minigame number %d", minigameNum);
+ break;
+ }
+
+ int minigameResult = minigame->run(fromMainGame);
+
+ delete minigame;
+
+ // Check if the prinicpal was hit with a megaloogie in the loogie minigame
+ if (minigameNum == 0 && minigameResult == 1)
+ _gameVars[42] = 1;
+
+#if 0
+ //DEBUG Fake it :)
+ if (minigameNum == 0)
+ _gameVars[42] = 1;
+#endif
+
+ return true;
+}
+
+void BbvsEngine::runMainMenu() {
+ MainMenu *mainMenu = new MainMenu(this);
+ mainMenu->runModal();
+ delete mainMenu;
+}
+
+void BbvsEngine::checkEasterEgg(char key) {
+
+ static const char * const kEasterEggStrings[] = {
+ "BOIDUTS",
+ "YNNIF",
+ "SKCUS",
+ "NAMTAH"
+ };
+
+ static const int kEasterEggLengths[] = {
+ 7, 5, 5, 6
+ };
+
+ if (_currSceneNum == kCredits) {
+ memcpy(&_easterEggInput[1], &_easterEggInput[0], 6);
+ _easterEggInput[0] = key;
+ for (int i = 0; i < ARRAYSIZE(kEasterEggStrings); ++i) {
+ if (!scumm_strnicmp(kEasterEggStrings[i], _easterEggInput, kEasterEggLengths[i])) {
+ _easterEggInput[0] = 0;
+ _newSceneNum = 100 + i;
+ break;
+ }
+ }
+ }
+
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h
new file mode 100644
index 0000000000..b429c315f7
--- /dev/null
+++ b/engines/bbvs/bbvs.h
@@ -0,0 +1,415 @@
+/* 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 BBVS_BBVS_H
+#define BBVS_BBVS_H
+
+#include "audio/mixer.h"
+#include "audio/decoders/aiff.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 "common/winexe.h"
+#include "common/winexe_pe.h"
+#include "engines/engine.h"
+
+struct ADGameDescription;
+
+namespace Bbvs {
+
+class ActionCommands;
+struct Action;
+class GameModule;
+struct Condition;
+struct Conditions;
+struct ActionResult;
+struct ActionResults;
+struct ActionCommand;
+struct CameraInit;
+struct SceneObjectDef;
+struct SceneObjectInit;
+struct SceneExit;
+struct Animation;
+struct SceneSound;
+class DrawList;
+class SpriteModule;
+class Screen;
+class SoundMan;
+
+#define BBVS_SAVEGAME_VERSION 0
+
+enum {
+ kVerbLook = 0,
+ kVerbUse = 1,
+ kVerbTalk = 2,
+ kVerbWalk = 3,
+ kVerbInvItem = 4,
+ kVerbShowInv = 5
+};
+
+enum {
+ kITNone = 0,
+ kITEmpty = 1,
+ KITSceneObject = 2,
+ kITBgObject = 3,
+ kITDialog = 4,
+ kITScroll = 5,
+ kITSceneExit = 6,
+ kITInvItem = 7
+};
+
+enum {
+ kGSScene = 0,
+ kGSInventory = 1,
+ kGSVerbs = 2,
+ kGSWait = 3,
+ kGSDialog = 4,
+ kGSWaitDialog = 5
+};
+
+enum {
+ kActionCmdStop = 0,
+ kActionCmdWalkObject = 3,
+ kActionCmdMoveObject = 4,
+ kActionCmdAnimObject = 5,
+ kActionCmdSetCameraPos = 7,
+ kActionCmdPlaySpeech = 8,
+ kActionCmdPlaySound = 10,
+ kActionCmdStartBackgroundSound = 11,
+ kActionCmdStopBackgroundSound = 12
+};
+
+enum {
+ kCondUnused = 1,
+ kCondSceneObjectVerb = 2,
+ kCondBgObjectVerb = 3,
+ kCondSceneObjectInventory = 4,
+ kCondBgObjectInventory = 5,
+ kCondHasInventoryItem = 6,
+ kCondHasNotInventoryItem = 7,
+ kCondIsGameVar = 8,
+ kCondIsNotGameVar = 9,
+ kCondIsPrevSceneNum = 10,
+ kCondIsCurrTalkObject = 11,
+ kCondIsDialogItem = 12,
+ kCondIsCameraNum = 13,
+ kCondIsNotPrevSceneNum = 14,
+ kCondDialogItem0 = 15,
+ kCondIsButtheadAtBgObject = 16,
+ kCondIsNotSceneVisited = 17,
+ kCondIsSceneVisited = 18,
+ kCondIsCameraNumTransition = 19
+};
+
+enum {
+ kActResAddInventoryItem = 1,
+ kActResRemoveInventoryItem = 2,
+ kActResSetGameVar = 3,
+ kActResUnsetGameVar = 4,
+ kActResStartDialog = 5,
+ kActResChangeScene = 6
+};
+
+enum {
+ kLeftButtonClicked = 1,
+ kRightButtonClicked = 2,
+ kLeftButtonDown = 4,
+ kRightButtonDown = 8,
+ kAnyButtonClicked = kLeftButtonClicked | kRightButtonClicked,
+ kAnyButtonDown = kLeftButtonDown | kRightButtonDown
+};
+
+struct BBPoint {
+ int16 x, y;
+};
+
+struct BBRect {
+ int16 x, y, width, height;
+};
+
+struct BBPolygon {
+ const BBPoint *points;
+ int pointsCount;
+};
+
+struct Rect {
+ int16 left, top, right, bottom;
+};
+
+struct SceneObject {
+ uint32 x, y;
+ SceneObjectDef *sceneObjectDef;
+ Animation *anim;
+ int animIndex;
+ int frameIndex;
+ int frameTicks;
+ int walkCount;
+ int xIncr, yIncr;
+ int turnValue, turnCount, turnTicks;
+ Common::Point walkDestPt;
+ SceneObject() : sceneObjectDef(0), anim(0) {
+ }
+};
+
+struct SceneObjectAction {
+ int sceneObjectIndex;
+ int animationIndex;
+ Common::Point walkDest;
+};
+
+struct WalkInfo {
+ int16 x, y;
+ int delta;
+ int direction;
+ Common::Point midPt;
+ int walkAreaIndex;
+};
+
+struct WalkArea {
+ int16 x, y, width, height;
+ bool checked;
+ int linksCount;
+ WalkArea *links[16];
+ WalkInfo *linksD1[32];
+ WalkInfo *linksD2[32];
+ bool contains(const Common::Point &pt) const;
+};
+
+const int kSceneObjectsCount = 64;
+const int kSceneSoundsCount = 8;
+const int kInventoryItemStatusCount = 50;
+const int kDialogItemStatusCount = 50;
+const int kGameVarsCount = 2000;
+const int kSceneVisitedCount = 64;
+
+class BbvsEngine : public Engine {
+protected:
+ Common::Error run();
+ virtual bool hasFeature(EngineFeature f) const;
+public:
+ BbvsEngine(OSystem *syst, const ADGameDescription *gd);
+ ~BbvsEngine();
+ void newGame();
+ void continueGameFromQuickSave();
+ void setNewSceneNum(int newSceneNum);
+ const Common::String getTargetName() { return _targetName; }
+private:
+ const ADGameDescription *_gameDescription;
+ Graphics::PixelFormat _pixelFormat;
+public:
+ Common::RandomSource *_random;
+
+ GameModule *_gameModule;
+ SpriteModule *_spriteModule;
+ SoundMan *_sound;
+
+ Screen *_screen;
+
+ int _bootSaveSlot;
+
+ int _mouseX, _mouseY;
+ uint _mouseButtons;
+ Common::KeyCode _keyCode;
+
+ int _mouseCursorSpriteIndex;
+
+ int _gameState;
+ int _gameTicks;
+
+ Common::Point _mousePos;
+ Common::Point _verbPos;
+ Common::Point _walkMousePos;
+
+ int _activeItemType;
+ int _activeItemIndex;
+ int _currTalkObjectIndex;
+
+ Common::Point _cameraPos, _newCameraPos;
+
+ int _newSceneNum, _prevSceneNum, _currSceneNum;
+ int _playVideoNumber;
+
+ int _dialogSlotCount;
+ byte _dialogItemStatus[kDialogItemStatusCount];
+
+ byte _gameVars[kGameVarsCount];
+ byte _sceneVisited[kSceneVisitedCount];
+
+ int _currVerbNum;
+
+ int _currInventoryItem;
+ byte _inventoryItemStatus[kInventoryItemStatusCount];
+ int _inventoryButtonIndex;
+
+ Action *_currAction;
+ uint32 _currActionCommandTimeStamp;
+ int _currActionCommandIndex;
+
+ Common::Array<Action*> _walkAreaActions;
+
+ SceneObject _sceneObjects[kSceneObjectsCount];
+ Common::Array<SceneObjectAction> _sceneObjectActions;
+
+ SceneObject *_buttheadObject, *_beavisObject;
+ int _currCameraNum;
+
+ byte _backgroundSoundsActive[kSceneSoundsCount];
+ Audio::SoundHandle _speechSoundHandle;
+
+ int _walkAreasCount;
+ WalkArea _walkAreas[80];
+ int _walkInfosCount;
+ WalkInfo _walkInfos[256];
+ int _walkableRectsCount;
+ Common::Rect _walkableRects[256];
+ Common::Rect _tempWalkableRects1[256];
+ Common::Rect _tempWalkableRects2[256];
+ WalkInfo *_walkInfoPtrs[256];
+
+ WalkArea *_sourceWalkArea, *_destWalkArea;
+ Common::Point _sourceWalkAreaPt, _destWalkAreaPt, _finalWalkPt;
+ int _currWalkDistance;
+ bool _walkReachedDestArea;
+
+ bool _hasSnapshot;
+ uint32 _snapshotSize;
+ byte *_snapshot;
+ Common::SeekableMemoryWriteStream *_snapshotStream;
+
+ char _easterEggInput[7];
+
+ void updateEvents();
+ int getRandom(int max);
+
+ void drawDebugInfo();
+ void drawScreen();
+
+ void updateGame();
+
+ bool evalCondition(Conditions &conditions);
+ bool evalCameraCondition(Conditions &conditions, int value);
+ int evalDialogCondition(Conditions &conditions);
+ void evalActionResults(ActionResults &results);
+
+ void updateBackgroundSounds();
+
+ void loadScene(int sceneNum);
+ void initScene(bool sounds);
+ bool changeScene();
+ bool update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCode keyCode);
+
+ void buildDrawList(DrawList &drawList);
+
+ void updateVerbs();
+ void updateDialog(bool clicked);
+ void updateInventory(bool clicked);
+ void updateScene(bool clicked);
+
+ bool performActionCommand(ActionCommand *actionCommand);
+ bool processCurrAction();
+ void skipCurrAction();
+
+ void updateCommon();
+
+ void updateWalkableRects();
+ void startWalkObject(SceneObject *sceneObject);
+ void updateWalkObject(SceneObject *sceneObject);
+ void walkObject(SceneObject *sceneObject, const Common::Point &destPt, int walkSpeed);
+ void turnObject(SceneObject *sceneObject);
+
+ int rectSubtract(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect *outRects);
+
+ WalkInfo *addWalkInfo(int16 x, int16 y, int delta, int direction, int16 midPtX, int16 midPtY, int walkAreaIndex);
+ void initWalkAreas(SceneObject *sceneObject);
+ WalkArea *getWalkAreaAtPos(const Common::Point &pt);
+ bool canButtheadWalkToDest(const Common::Point &destPt);
+ void canWalkToDest(WalkArea *walkArea, int infoCount);
+ bool walkTestLineWalkable(const Common::Point &sourcePt, const Common::Point &destPt, WalkInfo *walkInfo);
+ void walkFindPath(WalkArea *sourceWalkArea, int infoCount);
+ int calcDistance(const Common::Point &pt1, const Common::Point &pt2);
+ void walkFoundPath(int count);
+
+ void updateSceneObjectsTurnValue();
+ void updateDialogConditions();
+
+ void playSpeech(int soundNum);
+ void stopSpeech();
+
+ void playSound(uint soundNum, bool loop = false);
+ void stopSound(uint soundNum);
+ void stopSounds();
+
+ bool runMinigame(int minigameNum);
+ void playVideo(int videoNum);
+
+ void runMainMenu();
+ void checkEasterEgg(char key);
+
+ // Savegame API
+
+ enum kReadSaveHeaderError {
+ kRSHENoError = 0,
+ kRSHEInvalidType = 1,
+ kRSHEInvalidVersion = 2,
+ kRSHEIoError = 3
+ };
+
+ struct SaveHeader {
+ Common::String description;
+ uint32 version;
+ byte gameID;
+ uint32 flags;
+ uint32 saveDate;
+ uint32 saveTime;
+ uint32 playTime;
+ Graphics::Surface *thumbnail;
+ };
+
+ bool _isSaveAllowed;
+
+ bool canLoadGameStateCurrently() { return _isSaveAllowed; }
+ bool canSaveGameStateCurrently() { return _isSaveAllowed; }
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameState(int slot, const Common::String &description);
+ void savegame(const char *filename, const char *description);
+ void loadgame(const char *filename);
+ const char *getSavegameFilename(int num);
+ bool existsSavegame(int num);
+ static Common::String getSavegameFilename(const Common::String &target, int num);
+ static kReadSaveHeaderError readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header);
+
+ void allocSnapshot();
+ void freeSnapshot();
+ void saveSnapshot();
+
+ void writeContinueSavegame();
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_BBVS_H
diff --git a/engines/bbvs/configure.engine b/engines/bbvs/configure.engine
new file mode 100644
index 0000000000..c1dc1ef924
--- /dev/null
+++ b/engines/bbvs/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 bbvs "Beavis and Butthead in Virtual Stupidity" no
diff --git a/engines/bbvs/detection.cpp b/engines/bbvs/detection.cpp
new file mode 100644
index 0000000000..98565c8e78
--- /dev/null
+++ b/engines/bbvs/detection.cpp
@@ -0,0 +1,162 @@
+/* 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 "bbvs/bbvs.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 bbvsGames[] = {
+ { "bbvs", "Beavis and Butthead in Virtual Stupidity" },
+ { 0, 0 }
+};
+
+namespace Bbvs {
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "bbvs",
+ 0,
+ AD_ENTRY1s("game0001.vnm", "637e5411751c7065bc385dd73d224561", 64004),
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ ADGF_NO_FLAGS,
+ GUIO0()
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Bbvs
+
+static const char * const directoryGlobs[] = {
+ "vnm",
+ 0
+};
+
+class BbvsMetaEngine : public AdvancedMetaEngine {
+public:
+ BbvsMetaEngine() : AdvancedMetaEngine(Bbvs::gameDescriptions, sizeof(ADGameDescription), bbvsGames) {
+ _singleid = "bbvs";
+ _maxScanDepth = 3;
+ _directoryGlobs = directoryGlobs;
+ }
+
+ virtual const char *getName() const {
+ return "MTV's Beavis and Butt-Head in Virtual Stupidity";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "(C) 1995 Viacom New Media";
+ }
+
+ 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 BbvsMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+void BbvsMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+int BbvsMetaEngine::getMaximumSaveSlot() const {
+ return 999;
+}
+
+SaveStateList BbvsMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Bbvs::BbvsEngine::SaveHeader header;
+ Common::String pattern = target;
+ pattern += ".???";
+ Common::StringArray filenames;
+ filenames = saveFileMan->listSavefiles(pattern.c_str());
+ Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ int slotNum = atoi(file->c_str() + file->size() - 3);
+ if (slotNum >= 0 && slotNum <= 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str());
+ if (in) {
+ if (Bbvs::BbvsEngine::readSaveHeader(in, false, header) == Bbvs::BbvsEngine::kRSHENoError) {
+ saveList.push_back(SaveStateDescriptor(slotNum, header.description));
+ }
+ delete in;
+ }
+ }
+ }
+ return saveList;
+}
+
+SaveStateDescriptor BbvsMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String filename = Bbvs::BbvsEngine::getSavegameFilename(target, slot);
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str());
+ if (in) {
+ Bbvs::BbvsEngine::SaveHeader header;
+ Bbvs::BbvsEngine::kReadSaveHeaderError error;
+ error = Bbvs::BbvsEngine::readSaveHeader(in, true, header);
+ delete in;
+ if (error == Bbvs::BbvsEngine::kRSHENoError) {
+ SaveStateDescriptor desc(slot, header.description);
+ // Slot 0 is used for the "Continue" save
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+ desc.setThumbnail(header.thumbnail);
+ desc.setSaveDate(header.saveDate & 0xFFFF, (header.saveDate >> 16) & 0xFF, (header.saveDate >> 24) & 0xFF);
+ desc.setSaveTime((header.saveTime >> 16) & 0xFF, (header.saveTime >> 8) & 0xFF);
+ desc.setPlayTime(header.playTime * 1000);
+ return desc;
+ }
+ }
+ return SaveStateDescriptor();
+}
+
+bool BbvsMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Bbvs::BbvsEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(BBVS)
+ REGISTER_PLUGIN_DYNAMIC(BBVS, PLUGIN_TYPE_ENGINE, BbvsMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(BBVS, PLUGIN_TYPE_ENGINE, BbvsMetaEngine);
+#endif
diff --git a/engines/bbvs/dialogs.cpp b/engines/bbvs/dialogs.cpp
new file mode 100644
index 0000000000..5247a58ec8
--- /dev/null
+++ b/engines/bbvs/dialogs.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 "bbvs/dialogs.h"
+#include "common/events.h"
+#include "gui/gui-manager.h"
+#include "gui/ThemeEval.h"
+
+namespace Bbvs {
+
+struct MenuButton {
+ const char *label;
+ uint32 cmd;
+};
+
+static const MenuButton kMenuButtons[] = {
+ // Main menu
+ {"New Game", kCmdNewGame},
+ {"Continue", kCmdContinue},
+ {"Options", kCmdOptions},
+ {"Mini Games", kCmdMiniGames},
+ {"Quit", kCmdQuit},
+ // Options
+ {"Uninstall", kCmdUninstall},
+ {"Credits", kCmdCredits},
+ {"Opening", kCmdOpening},
+ {"Chicks 'n' Stuff", kCmdChicksNStuff},
+ {"Back ..", kCmdBack},
+ // Minigames
+ {"Hock-A-Loogie", kCmdHockALoogie},
+ {"Bug Justice", kCmdBugJustice},
+ {"Court Chaos", kCmdCourtChaos},
+ {"Air Guitar", kCmdAirGuitar},
+ {"Back ..", kCmdBack}
+};
+
+MainMenu::MainMenu(BbvsEngine *vm) : Dialog(0, 0, 1, 1), _vm(vm) {
+ init();
+}
+
+MainMenu::~MainMenu() {
+}
+
+void MainMenu::init() {
+ _buttons[0] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
+ _buttons[1] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
+ _buttons[2] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
+ _buttons[3] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
+ _buttons[4] = new GUI::ButtonWidget(this, 0, 0, 1, 1, "", 0, 0);
+ gotoMenuScreen(kMainMenuScr);
+}
+
+void MainMenu::reflowLayout() {
+ const int screenW = g_system->getOverlayWidth();
+ const int screenH = g_system->getOverlayHeight();
+
+ const int buttonWidth = screenW * 70 / 320;
+ const int buttonHeight = screenH * 14 / 240;
+ const int buttonPadding = screenW * 3 / 320;
+
+ _w = 2 * buttonWidth + buttonPadding;
+ _h = 3 * buttonHeight + 3 * buttonPadding;
+ _x = (screenW - _w) / 2;
+ _y = screenH - _h;
+
+ int x = 0, y = 0;
+
+ x = 0;
+ y = 0;
+ _buttons[0]->resize(x, y, buttonWidth, buttonHeight);
+ x += buttonWidth + buttonPadding;
+ _buttons[1]->resize(x, y, buttonWidth, buttonHeight);
+
+ x = 0;
+ y += buttonHeight + buttonPadding;
+ _buttons[2]->resize(x, y, buttonWidth, buttonHeight);
+ x += buttonWidth + buttonPadding;
+ _buttons[3]->resize(x, y, buttonWidth, buttonHeight);
+
+ x = (_w - buttonWidth) / 2; // Center the last button
+ y += buttonHeight + buttonPadding;
+ _buttons[4]->resize(x, y, buttonWidth, buttonHeight);
+
+ GUI::Dialog::reflowLayout();
+
+}
+
+void MainMenu::handleCommand(GUI::CommandSender *sender, uint32 command, uint32 data) {
+ switch (command) {
+ // Main menu
+ case kCmdNewGame:
+ close();
+ _vm->newGame();
+ break;
+ case kCmdContinue:
+ close();
+ _vm->continueGameFromQuickSave();
+ break;
+ case kCmdOptions:
+ gotoMenuScreen(kOptionsMenuScr);
+ break;
+ case kCmdMiniGames:
+ gotoMenuScreen(kMiniGamesMenuScr);
+ break;
+ case kCmdQuit:
+ close();
+ _vm->quitGame();
+ break;
+ // Options menu
+ case kCmdUninstall:
+ break;
+ case kCmdCredits:
+ gotoScene(45);
+ break;
+ case kCmdOpening:
+ gotoScene(43);
+ break;
+ case kCmdChicksNStuff:
+ gotoScene(41);
+ break;
+ // Minigames menu
+ case kCmdHockALoogie:
+ gotoScene(27);
+ break;
+ case kCmdBugJustice:
+ gotoScene(29);
+ break;
+ case kCmdCourtChaos:
+ gotoScene(28);
+ break;
+ case kCmdAirGuitar:
+ gotoScene(30);
+ break;
+ case kCmdBack:
+ gotoMenuScreen(kMainMenuScr);
+ break;
+ default:
+ Dialog::handleCommand(sender, command, data);
+ }
+}
+
+void MainMenu::gotoMenuScreen(int screen) {
+ for (int i = 0; i < 5; ++i) {
+ const MenuButton *btn = &kMenuButtons[screen * 5 + i];
+ _buttons[i]->setLabel(btn->label);
+ _buttons[i]->setCmd(btn->cmd);
+ _buttons[i]->setEnabled(btn->cmd != 0);
+ }
+ // Enable the "Continue" button if a savegame at slot 0 exists
+ if (screen == kMainMenuScr)
+ _buttons[1]->setEnabled(canContinue());
+}
+
+bool MainMenu::canContinue() {
+ return _vm->existsSavegame(0);
+}
+
+void MainMenu::gotoScene(int sceneNum) {
+ close();
+ _vm->setNewSceneNum(sceneNum);
+}
+
+} // End of namespace Hugo
diff --git a/engines/bbvs/dialogs.h b/engines/bbvs/dialogs.h
new file mode 100644
index 0000000000..2dce2a110b
--- /dev/null
+++ b/engines/bbvs/dialogs.h
@@ -0,0 +1,81 @@
+/* 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 BBVS_DIALOGS_H
+#define BBVS_DIALOGS_H
+
+#include "bbvs/bbvs.h"
+#include "gui/dialog.h"
+#include "gui/widgets/edittext.h"
+
+namespace Bbvs {
+
+enum {
+ // Main menu
+ kCmdNewGame = 'NEWG',
+ kCmdContinue = 'CONT',
+ kCmdOptions = 'OPTN',
+ kCmdMiniGames = 'MINI',
+ kCmdQuit = 'QUIT',
+ // Options
+ kCmdUninstall = 0,
+ kCmdCredits = 'CRED',
+ kCmdOpening = 'OPEN',
+ kCmdChicksNStuff = 'CHIC',
+ // Minigames
+ kCmdHockALoogie = 'HOCK',
+ kCmdBugJustice = 'BUGJ',
+ kCmdCourtChaos = 'CORT',
+ kCmdAirGuitar = 'AIRG',
+ kCmdBack = 'BACK'
+};
+
+enum {
+ kMainMenuScr = 0,
+ kOptionsMenuScr = 1,
+ kMiniGamesMenuScr = 2
+};
+
+class MainMenu : public GUI::Dialog {
+public:
+ MainMenu(BbvsEngine *vm);
+ ~MainMenu();
+
+ void reflowLayout();
+ void handleCommand(GUI::CommandSender *sender, uint32 command, uint32 data);
+
+protected:
+ BbvsEngine *_vm;
+
+ void init();
+
+ GUI::ButtonWidget *_buttons[5];
+
+ void gotoMenuScreen(int index);
+ bool canContinue();
+ void gotoScene(int sceneNum);
+
+};
+
+}
+
+#endif // BBVS_DIALOGS_H
diff --git a/engines/bbvs/gamemodule.cpp b/engines/bbvs/gamemodule.cpp
new file mode 100644
index 0000000000..d6343084ab
--- /dev/null
+++ b/engines/bbvs/gamemodule.cpp
@@ -0,0 +1,500 @@
+/* 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 "bbvs/gamemodule.h"
+#include "engines/util.h"
+
+namespace Bbvs {
+
+GameModule::GameModule()
+ : _bgSpriteCount(0), _bgSpriteIndices(0), _bgSpritePriorities(0), _walkRectsCount(0),
+ _walkRects(0), _sceneExitsCount(0), _sceneExits(0), _bgObjectsCount(0), _bgObjects(0),
+ _animationsCount(0), _animations(0), _sceneObjectDefsCount(0), _sceneObjectDefs(0),
+ _sceneObjectInitsCount(0), _sceneObjectInits(0), _actionsCount(0), _actions(0),
+ _sceneSoundsCount(0), _sceneSounds(0), _preloadSoundsCount(0), _preloadSounds(0) {
+}
+
+GameModule::~GameModule() {
+ unload();
+}
+
+void GameModule::load(const char *filename) {
+ debug(0, "GameModule::load()");
+
+ unload();
+
+ Common::File fd;
+
+ if (!fd.open(filename))
+ error("GameModule::load() Could not open %s", filename);
+
+ loadBgSprites(fd);
+ loadCameraInits(fd);
+ loadWalkRects(fd);
+ loadSceneExits(fd);
+ loadBgObjects(fd);
+ loadAnimations(fd);
+ loadSceneObjectDefs(fd);
+ loadSceneObjectInits(fd);
+ loadActions(fd);
+ loadGuiSpriteIndices(fd);
+ loadInventoryItemSpriteIndices(fd);
+ loadInventoryItemInfos(fd);
+ loadDialogItemSpriteIndices(fd);
+ loadSceneSounds(fd);
+ loadPreloadSounds(fd);
+
+ fd.seek(0xC);
+ _fieldC = fd.readUint32LE();
+
+ fd.seek(0x1A8);
+ _buttheadObjectIndex = fd.readUint32LE();
+
+ fd.close();
+
+ debug(0, "GameModule::load() OK");
+}
+
+int GameModule::getFieldC() {
+ return _fieldC;
+}
+
+int GameModule::getButtheadObjectIndex() {
+ return _buttheadObjectIndex;
+}
+
+int GameModule::getGuiSpriteIndex(int index) {
+ assert(index < kGuiSpriteCount);
+ return _guiSpriteIndices[index];
+}
+
+int GameModule::getInventoryItemSpriteIndex(int index) {
+ assert(index < kInventoryItemSpriteCount);
+ return _inventoryItemSpriteIndices[index];
+}
+
+int GameModule::getDialogItemSpriteIndex(int index) {
+ assert(index < kDialogItemSpriteCount);
+ return _dialogItemSpriteIndices[index];
+}
+
+int GameModule::getActionsCount() {
+ return _actionsCount;
+}
+
+Action *GameModule::getAction(int index) {
+ assert(index < _actionsCount);
+ return &_actions[index];
+}
+
+InventoryItemInfo *GameModule::getInventoryItemInfo(int index) {
+ assert(index < kInventoryItemCount);
+ return &_inventoryItemInfos[index];
+}
+
+CameraInit *GameModule::getCameraInit(int cameraNum) {
+ assert(cameraNum < kCameraInitsCount);
+ return &_cameraInits[cameraNum];
+}
+
+int GameModule::getSceneExitsCount() {
+ return _sceneExitsCount;
+}
+
+SceneExit *GameModule::getSceneExit(int index) {
+ assert(index < _sceneExitsCount);
+ return &_sceneExits[index];
+}
+
+int GameModule::getWalkRectsCount() {
+ return _walkRectsCount;
+}
+
+Common::Rect *GameModule::getWalkRects() {
+ return _walkRects;
+}
+
+int GameModule::getSceneObjectDefsCount() {
+ return _sceneObjectDefsCount;
+}
+
+SceneObjectDef *GameModule::getSceneObjectDef(int index) {
+ assert(index < _sceneObjectDefsCount);
+ return &_sceneObjectDefs[index];
+}
+
+int GameModule::getSceneObjectInitsCount() {
+ return _sceneObjectInitsCount;
+}
+
+SceneObjectInit *GameModule::getSceneObjectInit(int index) {
+ assert(index < _sceneObjectInitsCount);
+ return &_sceneObjectInits[index];
+}
+
+int GameModule::getBgObjectsCount() {
+ return _bgObjectsCount;
+}
+
+BgObject *GameModule::getBgObject(int index) {
+ assert(index < _bgObjectsCount);
+ return &_bgObjects[index];
+}
+
+int GameModule::getBgSpritesCount() {
+ return _bgSpriteCount;
+}
+
+int GameModule::getBgSpriteIndex(int index) {
+ assert(index < _bgSpriteCount);
+ return _bgSpriteIndices[index];
+}
+
+int GameModule::getBgSpritePriority(int index) {
+ assert(index < _bgSpriteCount);
+ return _bgSpritePriorities[index];
+}
+
+int GameModule::getSceneSoundsCount() {
+ return _sceneSoundsCount;
+}
+
+SceneSound *GameModule::getSceneSound(int index) {
+ assert(index < _sceneSoundsCount);
+ return &_sceneSounds[index];
+}
+
+uint GameModule::getSceneSoundIndex(uint soundNum) {
+ for (int i = 0; i < getSceneSoundsCount(); ++i)
+ if (getSceneSound(i)->soundNum == soundNum)
+ return i;
+ return 0;
+}
+
+uint GameModule::getPreloadSoundsCount() {
+ return _preloadSoundsCount;
+}
+
+uint GameModule::getPreloadSound(uint index) {
+ assert(index < _preloadSoundsCount);
+ return _preloadSounds[index];
+}
+
+Animation *GameModule::getAnimation(int index) {
+ assert(index < _animationsCount);
+ return &_animations[index];
+}
+
+Common::Point GameModule::readPoint(Common::SeekableReadStream &s) {
+ Common::Point p;
+ p.x = s.readUint16LE();
+ p.y = s.readUint16LE();
+ return p;
+}
+
+Common::Rect GameModule::readRect(Common::SeekableReadStream &s) {
+ Common::Rect r;
+ r.left = s.readUint16LE();
+ r.top = s.readUint16LE();
+ r.setWidth(s.readUint16LE());
+ r.setHeight(s.readUint16LE());
+ return r;
+}
+
+Conditions GameModule::readConditions(Common::SeekableReadStream &s) {
+ Conditions c;
+ for (int i = 0; i < 8; ++i) {
+ c.conditions[i].cond = s.readByte();
+ c.conditions[i].value1 = s.readByte();
+ c.conditions[i].value2 = s.readUint16LE();
+ }
+ return c;
+}
+
+void GameModule::unload() {
+ delete[] _bgSpriteIndices;
+ delete[] _bgSpritePriorities;
+ delete[] _walkRects;
+ delete[] _sceneExits;
+ delete[] _bgObjects;
+ delete[] _animations;
+ delete[] _sceneObjectDefs;
+ delete[] _sceneObjectInits;
+ delete[] _actions;
+ delete[] _sceneSounds;
+ delete[] _preloadSounds;
+ _bgSpriteIndices = 0;
+ _bgSpritePriorities = 0;
+ _walkRects = 0;
+ _sceneExits = 0;
+ _bgObjects = 0;
+ _animations = 0;
+ _sceneObjectDefs = 0;
+ _sceneObjectInits = 0;
+ _actions = 0;
+ _sceneSounds = 0;
+ _preloadSounds = 0;
+}
+
+void GameModule::loadBgSprites(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadBgSprites()");
+
+ s.seek(0x14);
+ _bgSpriteCount = s.readUint32LE();
+ uint32 bgSpriteIndicesOffs = s.readUint32LE();
+ uint32 bgSpritePrioritiesOffs = s.readUint32LE();
+ _bgSpriteIndices = new int[_bgSpriteCount];
+ _bgSpritePriorities = new int16[_bgSpriteCount];
+ s.seek(bgSpriteIndicesOffs);
+ for (int i = 0; i < _bgSpriteCount; ++i)
+ _bgSpriteIndices[i] = s.readUint32LE();
+ s.seek(bgSpritePrioritiesOffs);
+ for (int i = 0; i < _bgSpriteCount; ++i)
+ _bgSpritePriorities[i] = s.readUint16LE();
+
+}
+
+void GameModule::loadCameraInits(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadCameraInits()");
+
+ s.seek(0x20);
+ for (int i = 0; i < kCameraInitsCount; ++i) {
+ CameraInit &cameraInit = _cameraInits[i];
+ cameraInit.cameraPos = readPoint(s);
+ for (int j = 0; j < 8; ++j)
+ cameraInit.cameraLinks[j] = s.readByte();
+ for (int j = 0; j < 8; ++j)
+ cameraInit.rects[j] = readRect(s);
+ }
+}
+
+void GameModule::loadWalkRects(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadWalkRects()");
+
+ s.seek(0x150);
+ _walkRectsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _walkRects = new Common::Rect[_walkRectsCount];
+ s.seek(offs);
+ for (int i = 0; i < _walkRectsCount; ++i)
+ _walkRects[i] = readRect(s);
+}
+
+void GameModule::loadSceneExits(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadSceneExits()");
+
+ s.seek(0x158);
+ _sceneExitsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _sceneExits = new SceneExit[_sceneExitsCount];
+ s.seek(offs);
+ for (int i = 0; i < _sceneExitsCount; ++i) {
+ _sceneExits[i].rect = readRect(s);
+ _sceneExits[i].newModuleNum = s.readUint32LE();
+ }
+}
+
+void GameModule::loadBgObjects(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadBgObjects()");
+
+ s.seek(0x160);
+ _bgObjectsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _bgObjects = new BgObject[_bgObjectsCount];
+ s.seek(offs);
+ for (int i = 0; i < _bgObjectsCount; ++i) {
+ s.read(_bgObjects[i].name, 20);
+ _bgObjects[i].rect = readRect(s);
+ }
+}
+
+void GameModule::loadAnimations(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadAnimations()");
+
+ s.seek(0x168);
+ _animationsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _animations = new Animation[_animationsCount];
+ for (int i = 0; i < _animationsCount; ++i) {
+ Animation &anim = _animations[i];
+ s.seek(offs + i * 20);
+ anim.frameCount = s.readUint32LE();
+ uint32 frameSpriteIndicesOffs = s.readUint32LE();
+ uint32 frameTicksOffs = s.readUint32LE();
+ uint32 frameRects1Offs = s.readUint32LE();
+ uint32 frameRects2Offs = s.readUint32LE();
+ anim.frameSpriteIndices = new int[anim.frameCount];
+ s.seek(frameSpriteIndicesOffs);
+ for (int j = 0; j < anim.frameCount; ++j)
+ anim.frameSpriteIndices[j] = s.readUint32LE();
+ anim.frameTicks = new int16[anim.frameCount];
+ s.seek(frameTicksOffs);
+ for (int j = 0; j < anim.frameCount; ++j)
+ anim.frameTicks[j] = s.readUint16LE();
+ anim.frameRects1 = new Common::Rect[anim.frameCount];
+ s.seek(frameRects1Offs);
+ for (int j = 0; j < anim.frameCount; ++j)
+ anim.frameRects1[j] = readRect(s);
+ anim.frameRects2 = new Common::Rect[anim.frameCount];
+ s.seek(frameRects2Offs);
+ for (int j = 0; j < anim.frameCount; ++j)
+ anim.frameRects2[j] = readRect(s);
+ }
+}
+
+void GameModule::loadSceneObjectDefs(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadSceneObjectDefs()");
+
+ s.seek(0x170);
+ _sceneObjectDefsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _sceneObjectDefs = new SceneObjectDef[_sceneObjectDefsCount];
+ s.seek(offs);
+ for (int i = 0; i < _sceneObjectDefsCount; ++i) {
+ s.read(_sceneObjectDefs[i].name, 20);
+ _sceneObjectDefs[i].walkSpeed = s.readUint32LE();
+ for (int j = 0; j < 16; ++j)
+ _sceneObjectDefs[i].animIndices[j] = s.readUint32LE();
+ }
+}
+
+void GameModule::loadSceneObjectInits(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadSceneObjectInits()");
+
+ s.seek(0x178);
+ _sceneObjectInitsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _sceneObjectInits = new SceneObjectInit[_sceneObjectInitsCount];
+ s.seek(offs);
+ for (int i = 0; i < _sceneObjectInitsCount; ++i) {
+ _sceneObjectInits[i].conditions = readConditions(s);
+ _sceneObjectInits[i].sceneObjectIndex = s.readUint32LE();
+ _sceneObjectInits[i].animIndex = s.readUint32LE();
+ _sceneObjectInits[i].x = s.readUint16LE();
+ _sceneObjectInits[i].y = s.readUint16LE();
+ }
+}
+
+void GameModule::loadActions(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadActions()");
+
+ s.seek(0x180);
+ _actionsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _actions = new Action[_actionsCount];
+ for (int i = 0; i < _actionsCount; ++i) {
+ s.seek(offs + i * 72);
+ debug(0, "Action(%d) offs: %08X", i, offs + i * 72);
+ _actions[i].conditions = readConditions(s);
+ for (int j = 0; j < 8; ++j) {
+ _actions[i].results.actionResults[j].kind = s.readByte();
+ _actions[i].results.actionResults[j].value1 = s.readByte();
+ _actions[i].results.actionResults[j].value2 = s.readUint16LE();
+ }
+ const int actionListCount = s.readUint32LE();
+ const uint32 actionListOffs = s.readUint32LE();
+ s.seek(actionListOffs);
+ for (int j = 0; j < actionListCount; ++j) {
+ ActionCommand actionCommand;
+ actionCommand.cmd = s.readUint16LE();
+ actionCommand.sceneObjectIndex = s.readUint16LE();
+ actionCommand.timeStamp = s.readUint32LE();
+ actionCommand.walkDest = readPoint(s);
+ actionCommand.param = s.readUint32LE();
+ _actions[i].actionCommands.push_back(actionCommand);
+ }
+ }
+}
+
+void GameModule::loadGuiSpriteIndices(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadGuiSpriteIndices()");
+
+ s.seek(0x188);
+ uint32 offs = s.readUint32LE();
+ s.seek(offs);
+ for (int i = 0; i < kGuiSpriteCount; ++i)
+ _guiSpriteIndices[i] = s.readUint32LE();
+}
+
+void GameModule::loadInventoryItemSpriteIndices(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadInventoryItemSpriteIndices()");
+
+ s.seek(0x18C);
+ uint32 offs = s.readUint32LE();
+ s.seek(offs);
+ for (int i = 0; i < kInventoryItemSpriteCount; ++i)
+ _inventoryItemSpriteIndices[i] = s.readUint32LE();
+}
+
+void GameModule::loadInventoryItemInfos(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadInventoryItemInfos()");
+
+ s.seek(0x190);
+ uint32 offs = s.readUint32LE();
+ s.seek(offs);
+ for (int i = 0; i < kInventoryItemCount; ++i) {
+ _inventoryItemInfos[i].xOffs = s.readUint16LE();
+ _inventoryItemInfos[i].yOffs = s.readUint16LE();
+ _inventoryItemInfos[i].width = s.readUint16LE();
+ _inventoryItemInfos[i].height = s.readUint16LE();
+ s.skip(8); // Unused
+ }
+}
+
+void GameModule::loadDialogItemSpriteIndices(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadDialogItemSpriteIndices()");
+
+ s.seek(0x194);
+ uint32 offs = s.readUint32LE();
+ s.seek(offs);
+ for (int i = 0; i < kDialogItemSpriteCount; ++i) {
+ _dialogItemSpriteIndices[i] = s.readUint32LE();
+ }
+}
+
+void GameModule::loadSceneSounds(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadSceneSounds()");
+
+ s.seek(0x1A0);
+ _sceneSoundsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _sceneSounds = new SceneSound[_sceneSoundsCount];
+ s.seek(offs);
+ for (int i = 0; i < _sceneSoundsCount; ++i) {
+ _sceneSounds[i].conditions = readConditions(s);
+ _sceneSounds[i].soundNum = s.readUint32LE();
+ }
+}
+
+void GameModule::loadPreloadSounds(Common::SeekableReadStream &s) {
+ debug(0, "GameModule::loadPreloadSounds()");
+
+ s.seek(0x198);
+ _preloadSoundsCount = s.readUint32LE();
+ uint32 offs = s.readUint32LE();
+ _preloadSounds = new uint[_preloadSoundsCount];
+ s.seek(offs);
+ for (uint i = 0; i < _preloadSoundsCount; ++i)
+ _preloadSounds[i] = s.readUint32LE();
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/gamemodule.h b/engines/bbvs/gamemodule.h
new file mode 100644
index 0000000000..4d4f5b90a1
--- /dev/null
+++ b/engines/bbvs/gamemodule.h
@@ -0,0 +1,251 @@
+/* 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 BBVS_GAMEMODULE_H
+#define BBVS_GAMEMODULE_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/rect.h"
+#include "common/str.h"
+
+namespace Bbvs {
+
+const int kInventoryItemCount = 42;
+const int kInventoryItemSpriteCount = 2 * kInventoryItemCount;
+const int kDialogItemSpriteCount = 26;
+const int kGuiSpriteCount = 21;
+const int kCameraInitsCount = 4;
+
+struct Condition {
+ byte cond;
+ byte value1;
+ int16 value2;
+};
+
+struct Conditions {
+ Condition conditions[8];
+};
+
+struct ActionResult {
+ byte kind;
+ byte value1;
+ int16 value2;
+};
+
+struct ActionResults {
+ ActionResult actionResults[8];
+};
+
+struct ActionCommand {
+ uint16 cmd;
+ int16 sceneObjectIndex;
+ uint32 timeStamp;
+ Common::Point walkDest;
+ int32 param;
+};
+
+class ActionCommands : public Common::Array<ActionCommand> {
+};
+
+struct Action {
+ Conditions conditions;
+ ActionResults results;
+ ActionCommands actionCommands;
+};
+
+struct InventoryItemInfo {
+ int16 xOffs, yOffs;
+ int16 width, height;
+};
+
+struct CameraInit {
+ Common::Point cameraPos;
+ byte cameraLinks[8];
+ Common::Rect rects[8];
+};
+
+struct SceneObjectDef {
+ char name[20];
+ int animIndices[16];
+ int walkSpeed;
+};
+
+struct SceneObjectInit {
+ Conditions conditions;
+ int sceneObjectIndex;
+ int animIndex;
+ int x, y;
+};
+
+struct BgObject {
+ char name[20];
+ Common::Rect rect;
+};
+
+struct Animation {
+ int frameCount;
+ int *frameSpriteIndices;
+ int16 *frameTicks;
+ Common::Rect *frameRects1;
+ Common::Rect *frameRects2;
+ Animation()
+ : frameCount(0), frameSpriteIndices(0), frameTicks(0), frameRects1(0), frameRects2(0) {
+ }
+ ~Animation() {
+ delete[] frameSpriteIndices;
+ delete[] frameTicks;
+ delete[] frameRects1;
+ delete[] frameRects2;
+ }
+};
+
+struct SceneExit {
+ Common::Rect rect;
+ int newModuleNum;
+};
+
+struct SceneSound {
+ Conditions conditions;
+ uint soundNum;
+};
+
+class GameModule {
+public:
+ GameModule();
+ ~GameModule();
+
+ void load(const char *filename);
+
+ int getFieldC();
+ int getButtheadObjectIndex();
+
+ int getGuiSpriteIndex(int index);
+ int getInventoryItemSpriteIndex(int index);
+ int getDialogItemSpriteIndex(int index);
+
+ int getActionsCount();
+ Action *getAction(int index);
+
+ InventoryItemInfo *getInventoryItemInfo(int index);
+
+ CameraInit *getCameraInit(int cameraNum);
+
+ int getSceneExitsCount();
+ SceneExit *getSceneExit(int index);
+
+ int getWalkRectsCount();
+ Common::Rect *getWalkRects();
+
+ int getSceneObjectDefsCount();
+ SceneObjectDef *getSceneObjectDef(int index);
+
+ int getSceneObjectInitsCount();
+ SceneObjectInit *getSceneObjectInit(int index);
+
+ int getBgObjectsCount();
+ BgObject *getBgObject(int index);
+
+ int getBgSpritesCount();
+ int getBgSpriteIndex(int index);
+ int getBgSpritePriority(int index);
+
+ int getSceneSoundsCount();
+ SceneSound *getSceneSound(int index);
+ uint getSceneSoundIndex(uint soundNum);
+
+ uint getPreloadSoundsCount();
+ uint getPreloadSound(uint index);
+
+ Animation *getAnimation(int index);
+
+protected:
+
+ int _bgSpriteCount;
+ int *_bgSpriteIndices;
+ int16 *_bgSpritePriorities;
+
+ CameraInit _cameraInits[kCameraInitsCount];
+
+ int _walkRectsCount;
+ Common::Rect *_walkRects;
+
+ int _sceneExitsCount;
+ SceneExit *_sceneExits;
+
+ int _bgObjectsCount;
+ BgObject *_bgObjects;
+
+ int _animationsCount;
+ Animation *_animations;
+
+ int _sceneObjectDefsCount;
+ SceneObjectDef *_sceneObjectDefs;
+
+ int _sceneObjectInitsCount;
+ SceneObjectInit *_sceneObjectInits;
+
+ int _actionsCount;
+ Action *_actions;
+
+ int _sceneSoundsCount;
+ SceneSound *_sceneSounds;
+
+ uint _preloadSoundsCount;
+ uint *_preloadSounds;
+
+ int _guiSpriteIndices[kGuiSpriteCount];
+ int _inventoryItemSpriteIndices[kInventoryItemSpriteCount];
+ InventoryItemInfo _inventoryItemInfos[kInventoryItemCount];
+ int _dialogItemSpriteIndices[kDialogItemSpriteCount];
+
+ int _fieldC;
+ int _buttheadObjectIndex;
+
+ Common::Point readPoint(Common::SeekableReadStream &s);
+ Common::Rect readRect(Common::SeekableReadStream &s);
+ Conditions readConditions(Common::SeekableReadStream &s);
+
+ void unload();
+
+ void loadBgSprites(Common::SeekableReadStream &s);
+ void loadCameraInits(Common::SeekableReadStream &s);
+ void loadWalkRects(Common::SeekableReadStream &s);
+ void loadSceneExits(Common::SeekableReadStream &s);
+ void loadBgObjects(Common::SeekableReadStream &s);
+ void loadAnimations(Common::SeekableReadStream &s);
+ void loadSceneObjectDefs(Common::SeekableReadStream &s);
+ void loadSceneObjectInits(Common::SeekableReadStream &s);
+ void loadActions(Common::SeekableReadStream &s);
+ void loadGuiSpriteIndices(Common::SeekableReadStream &s);
+ void loadInventoryItemSpriteIndices(Common::SeekableReadStream &s);
+ void loadInventoryItemInfos(Common::SeekableReadStream &s);
+ void loadDialogItemSpriteIndices(Common::SeekableReadStream &s);
+ void loadSceneSounds(Common::SeekableReadStream &s);
+ void loadPreloadSounds(Common::SeekableReadStream &s);
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_GAMEMODULE_H
diff --git a/engines/bbvs/graphics.cpp b/engines/bbvs/graphics.cpp
new file mode 100644
index 0000000000..810d910abf
--- /dev/null
+++ b/engines/bbvs/graphics.cpp
@@ -0,0 +1,141 @@
+/* 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 "bbvs/graphics.h"
+
+namespace Bbvs {
+
+void DrawList::add(int index, int x, int y, int priority) {
+ debug(5, "DrawList::add() %d (%d, %d) %d", index, x, y, priority);
+ DrawListEntry drawListEntry;
+ drawListEntry.index = index;
+ drawListEntry.x = x;
+ drawListEntry.y = y;
+ drawListEntry.priority = priority;
+ // Insert the sprite at the correct position
+ uint insertIndex = 0;
+ while (insertIndex < size() && (*this)[insertIndex].priority <= priority)
+ ++insertIndex;
+ insert_at(insertIndex, drawListEntry);
+}
+
+Screen::Screen(OSystem *system) : _system(system) {
+ _surface = new Graphics::Surface();
+ _surface->create(320, 240, Graphics::PixelFormat::createFormatCLUT8());
+}
+
+Screen::~Screen() {
+ _surface->free();
+ delete _surface;
+}
+
+void Screen::setPalette(Palette &palette) {
+ byte pal[768];
+ memset(pal, 0, 768);
+ memcpy(&pal[palette.start * 3], palette.data, palette.count * 3);
+ _system->getPaletteManager()->setPalette(pal, 0, 256);
+}
+
+void Screen::copyToScreen() {
+ _system->copyRectToScreen((const byte*)_surface->getBasePtr(0, 0), _surface->pitch, 0, 0, 320, 240);
+ _system->updateScreen();
+}
+
+void Screen::clear() {
+ _surface->fillRect(Common::Rect(0, 0, 320, 240), 0);
+}
+
+void Screen::drawDrawList(DrawList &drawList, SpriteModule *spriteModule) {
+ for (uint i = 0; i < drawList.size(); ++i) {
+ debug(1, "index: %d; x: %d; y: %d; priority: %d", drawList[i].index, drawList[i].x, drawList[i].y, drawList[i].priority);
+ Sprite sprite = spriteModule->getSprite(drawList[i].index);
+ drawSprite(sprite, drawList[i].x, drawList[i].y);
+ }
+}
+
+void Screen::drawSprite(Sprite &sprite, int x, int y) {
+ debug(5, "Screen::drawSprite()");
+
+ int destX, destY, width, height, skipX = 0, skipY = 0;
+
+ destX = sprite.xOffs + x;
+ destY = sprite.yOffs + y;
+
+ if (destX >= _surface->w || destY >= _surface->h)
+ return;
+
+ height = sprite.height;
+ if (destY < 0) {
+ height += destY;
+ if (height <= 0)
+ return;
+ skipY = -destY;
+ destY = 0;
+ }
+ if (destY + height > _surface->h)
+ height = _surface->h - destY;
+
+ width = sprite.width;
+ if (destX < 0) {
+ width += destX;
+ if (width <= 0)
+ return;
+ skipX = -destX;
+ destX = 0;
+ }
+ if (destX + width >= _surface->w)
+ width = _surface->w - destX;
+
+ debug(0, "drawSprite() (%d, %d, %d, %d); skipX: %d; skipY: %d; %d", destX, destY, width, height, skipX, skipY, sprite.type);
+
+ if (sprite.type == 1) {
+ for (int yc = 0; yc < height; ++yc) {
+ byte *source = sprite.getRow(skipY + yc);
+ byte *dest = (byte*)_surface->getBasePtr(destX, destY + yc);
+ int currWidth = -skipX;
+ while (currWidth < width) {
+ int8 op = *source++;
+ if (op < 0) {
+ currWidth += (-op);
+ } else {
+ while (op >= 0 && currWidth < width) {
+ if (currWidth >= 0)
+ dest[currWidth] = *source;
+ ++source;
+ ++currWidth;
+ --op;
+ }
+ }
+ }
+ }
+ } else {
+ for (int yc = 0; yc < height; ++yc) {
+ byte *source = sprite.getRow(skipY + yc) + skipX;
+ byte *dest = (byte*)_surface->getBasePtr(destX, destY + yc);
+ memcpy(dest, source, width);
+ }
+ }
+
+ debug(5, "Screen::drawSprite() OK");
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/graphics.h b/engines/bbvs/graphics.h
new file mode 100644
index 0000000000..acb8eb953a
--- /dev/null
+++ b/engines/bbvs/graphics.h
@@ -0,0 +1,61 @@
+/* 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 BBVS_GRAPHICS_H
+#define BBVS_GRAPHICS_H
+
+#include "bbvs/spritemodule.h"
+#include "common/array.h"
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+namespace Bbvs {
+
+struct DrawListEntry {
+ int index;
+ int x, y;
+ int priority;
+};
+
+class DrawList : public Common::Array<DrawListEntry> {
+public:
+ void add(int index, int x, int y, int priority);
+};
+
+class Screen {
+public:
+ Screen(OSystem *system);
+ ~Screen();
+ void setPalette(Palette &palette);
+ void copyToScreen();
+ void drawDrawList(DrawList &drawList, SpriteModule *spriteModule);
+ void drawSprite(Sprite &sprite, int x, int y);
+ void clear();
+//protected:
+ OSystem *_system;
+ Graphics::Surface *_surface;
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_GRAPHICS_H
diff --git a/engines/bbvs/minigames/bbairguitar.cpp b/engines/bbvs/minigames/bbairguitar.cpp
new file mode 100644
index 0000000000..2c97bcd6bc
--- /dev/null
+++ b/engines/bbvs/minigames/bbairguitar.cpp
@@ -0,0 +1,1198 @@
+/* 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 "bbvs/minigames/bbairguitar.h"
+
+namespace Bbvs {
+
+static const char * const kNoteSoundFilenames[] = {
+ "a.aif", "a#.aif", "b.aif", "c.aif", "c#.aif",
+ "d.aif", "d#.aif", "e.aif", "f.aif", "f#.aif",
+ "g.aif", "g#.aif", "a_oct.aif"
+};
+
+static const uint kNoteSoundFilenamesCount = ARRAYSIZE(kNoteSoundFilenames);
+
+static const char * const kPatchDirectories[] = {
+ "rock", "burp", "fart"
+};
+
+static const uint kPatchDirectoriesCount = ARRAYSIZE(kPatchDirectories);
+
+static const BBPoint kPianoKeyArea1[] = {{29, 192}, {38, 192}, {38, 222}, {41, 222}, {41, 239}, {29, 239}};
+static const BBPoint kPianoKeyArea2[] = {{38, 192}, {43, 192}, {43, 222}, {38, 222}};
+static const BBPoint kPianoKeyArea3[] = {{43, 192}, {49, 192}, {49, 222}, {52, 222}, {52, 239}, {41, 239}, {41, 222}, {43, 222}};
+static const BBPoint kPianoKeyArea4[] = {{49, 192}, {54, 192}, {54, 222}, {49, 222}};
+static const BBPoint kPianoKeyArea5[] = {{54, 192}, {63, 192}, {63, 239}, {52, 239}, {52, 222}, {54, 222}};
+static const BBPoint kPianoKeyArea6[] = {{63, 192}, {71, 192}, {71, 222}, {74, 222}, {74, 239}, {63, 239}};
+static const BBPoint kPianoKeyArea7[] = {{71, 192}, {76, 192}, {76, 222}, {71, 222}};
+static const BBPoint kPianoKeyArea8[] = {{76, 192}, {82, 192}, {82, 222}, {85, 222}, {85, 239}, {74, 239}, {74, 222}, {76, 222}};
+static const BBPoint kPianoKeyArea9[] = {{82, 192}, {87, 192}, {87, 222}, {82, 222}};
+static const BBPoint kPianoKeyArea10[] = {{87, 192}, {94, 192}, {94, 222}, {96, 222}, {96, 239}, {85, 239}, {85, 222}, {87, 222}};
+static const BBPoint kPianoKeyArea11[] = {{94, 192}, {99, 192}, {99, 222}, {94, 222}};
+static const BBPoint kPianoKeyArea12[] = {{99, 192}, {107, 192}, {107, 239}, {96, 239}, {96, 222}, {99, 222}};
+static const BBPoint kPianoKeyArea13[] = {{107, 192}, {118, 192}, {118, 239}, {107, 239}};
+
+static const BBPolygon kPianoKeyAreas[] = {
+ {kPianoKeyArea1, ARRAYSIZE(kPianoKeyArea1)},
+ {kPianoKeyArea2, ARRAYSIZE(kPianoKeyArea2)},
+ {kPianoKeyArea3, ARRAYSIZE(kPianoKeyArea3)},
+ {kPianoKeyArea4, ARRAYSIZE(kPianoKeyArea4)},
+ {kPianoKeyArea5, ARRAYSIZE(kPianoKeyArea5)},
+ {kPianoKeyArea6, ARRAYSIZE(kPianoKeyArea6)},
+ {kPianoKeyArea7, ARRAYSIZE(kPianoKeyArea7)},
+ {kPianoKeyArea8, ARRAYSIZE(kPianoKeyArea8)},
+ {kPianoKeyArea9, ARRAYSIZE(kPianoKeyArea9)},
+ {kPianoKeyArea10, ARRAYSIZE(kPianoKeyArea10)},
+ {kPianoKeyArea11, ARRAYSIZE(kPianoKeyArea11)},
+ {kPianoKeyArea12, ARRAYSIZE(kPianoKeyArea12)},
+ {kPianoKeyArea13, ARRAYSIZE(kPianoKeyArea13)},
+};
+
+static const BBPoint kObjPoints[] = {
+ {161, 189}, {269, 189}, {161, 208}, {279, 208}, {172, 208},
+ {141, 224}, {257, 191}, {257, 199}, {148, 223}, {124, 224},
+ { 29, 192}, {182, 220}, {245, 220}, {269, 220}, {161, 220},
+ {203, 220}, {224, 220}, {123, 189}, {123, 199}, {123, 209},
+ {134, 224}, { 29, 185}, {124, 224}, {226, 127}, {226, 127},
+ {209, 141}, {244, 141}, {226, 127}, { 99, 107}, { 99, 107},
+ { 76, 137}, {118, 136}, { 99, 107}, {195, 104}, {100, 78}
+};
+
+static const MinigameBbAirGuitar::PianoKeyInfo kPianoKeyInfos[] = {
+ { 30, 192, 0},
+ { 38, 192, 5},
+ { 41, 192, 1},
+ { 49, 192, 5},
+ { 52, 192, 2},
+ { 63, 192, 3},
+ { 71, 192, 5},
+ { 74, 192, 1},
+ { 82, 192, 5},
+ { 85, 192, 1},
+ { 94, 192, 5},
+ { 96, 192, 2},
+ {107, 192, 4}
+};
+
+static const Rect kRect2 = {29, 189, 290, 239};
+static const Rect kPianoRect = {29, 192, 118, 239};
+
+static const Rect kPlayerButtonRects[] = {
+ {123, 189, 145, 199},
+ {123, 199, 145, 209},
+ {123, 209, 145, 220},
+ {148, 223, 156, 236},
+ {161, 189, 182, 205},
+ {161, 208, 171, 218},
+ {161, 220, 182, 231},
+ {182, 220, 203, 231},
+ {203, 220, 224, 231},
+ {224, 220, 245, 231},
+ {245, 220, 266, 231},
+ {269, 220, 290, 231},
+ {269, 189, 290, 205},
+ {279, 208, 290, 218}
+};
+
+static const BBPoint kPointsTbl1[] = {
+ {196, 191}, {202, 191}, {207, 191}, {212, 191}, {217, 191},
+ {223, 191}, {228, 191}, {233, 191}, {238, 191}, {244, 191},
+ {249, 191}
+};
+
+static const BBPoint kPointsTbl2[] = {
+ {196, 199}, {202, 199}, {207, 199}, {212, 199}, {217, 199},
+ {223, 199}, {228, 199}, {233, 199}, {238, 199}, {244, 199},
+ {249, 199}
+};
+
+static const struct { int frameIndex; byte flag; } kNoteFrameTbl[13] = {
+ {2, 0}, {2, 1}, {3, 0}, {3, 1}, {4, 0},
+ {5, 0}, {5, 1}, {6, 0}, {6, 1}, {0, 0},
+ {0, 1}, {1, 0}, {2, 0}
+};
+
+const int kTrackBarMinX = 172;
+const int kTrackBarMaxX = 272;
+
+bool MinigameBbAirGuitar::ptInRect(const Rect *r, int x, int y) {
+ return r && Common::Rect(r->left, r->top, r->right, r->bottom).contains(x, y);
+}
+
+bool MinigameBbAirGuitar::ptInPoly(const BBPolygon *poly, int x, int y) {
+ if (!poly)
+ return false;
+ const BBPoint *points = poly->points;
+ int pointsCount = poly->pointsCount;
+ bool result = false;
+ if (pointsCount > 0)
+ for (int i = 0, j = pointsCount - 1; i < pointsCount; j = i++)
+ if (((points[i].y > y) != (points[j].y > y)) &&
+ (x < (points[j].x - points[i].x) * (y - points[i].y) /
+ (points[j].y - points[i].y) + points[i].x))
+ result = !result;
+ return result;
+}
+
+void MinigameBbAirGuitar::buildDrawList(DrawList &drawList) {
+ switch (_gameState) {
+ case 0:
+ buildDrawList0(drawList);
+ break;
+ case 1:
+ buildDrawList1(drawList);
+ break;
+ }
+}
+
+void MinigameBbAirGuitar::buildDrawList0(DrawList &drawList) {
+
+ drawList.add(_objects[0].anim->frameIndices[0], _objects[0].x, _objects[0].y, 2000);
+
+ for (int i = 1; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
+ }
+
+ if (_titleScreenSpriteIndex> 0)
+ drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
+
+}
+
+void MinigameBbAirGuitar::buildDrawList1(DrawList &drawList) {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 255 - i);
+ }
+
+ if (_movingTrackBar) {
+ _trackBarX = _trackBarMouseX;
+ } else if (_totalTrackLength > 0) {
+ _trackBarX = 100 * _currTrackPos / _totalTrackLength + kTrackBarMinX;
+ } else {
+ _trackBarX = kTrackBarMinX;
+ }
+
+ if (_trackBarX > kTrackBarMaxX)
+ _trackBarX = kTrackBarMaxX;
+
+ _trackBarThumbRect.top = 208;
+ _trackBarThumbRect.bottom = 218;
+ _trackBarThumbRect.left = _trackBarX;
+ _trackBarThumbRect.right = _trackBarX + 6;
+
+ drawList.add(_objects[5].anim->frameIndices[0], _trackBarX, 208, 100);
+
+ if (_playerMode != 0) {
+ for (int i = 36; i < _vuMeterLeft2 + 36; ++i) {
+ int frameIndex = 0;
+ if (i >= 45)
+ frameIndex = 3;
+ else if (i >= 43)
+ frameIndex = 2;
+ else if (i >= 41)
+ frameIndex = 1;
+ drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl1[i - 36].x, kPointsTbl1[i - 36].y, 254);
+ }
+ for (int i = 47; i < _vuMeterRight2 + 47; ++i) {
+ int frameIndex = 0;
+ if (i >= 56)
+ frameIndex = 3;
+ else if (i >= 54)
+ frameIndex = 2;
+ else if (i >= 52)
+ frameIndex = 1;
+ drawList.add(_objects[i].anim->frameIndices[frameIndex], kPointsTbl2[i - 47].x, kPointsTbl2[i - 47].y, 254);
+ }
+ }
+
+ if (_backgroundSpriteIndex > 0)
+ drawList.add(_backgroundSpriteIndex, 0, 0, 0);
+
+}
+
+void MinigameBbAirGuitar::drawSprites() {
+ DrawList drawList;
+ buildDrawList(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+void MinigameBbAirGuitar::initObjs() {
+ for (int i = 0; i < kMaxObjectsCount; ++i)
+ _objects[i].kind = 0;
+}
+
+MinigameBbAirGuitar::Obj *MinigameBbAirGuitar::getFreeObject() {
+ for (int i = 0; i < kMaxObjectsCount; ++i)
+ if (_objects[i].kind == 0)
+ return &_objects[i];
+ return 0;
+}
+
+void MinigameBbAirGuitar::initObjects() {
+ switch (_gameState) {
+ case 0:
+ initObjects0();
+ break;
+ case 1:
+ initObjects1();
+ break;
+ }
+}
+
+void MinigameBbAirGuitar::initObjects0() {
+ _objects[0].anim = getAnimation(0);
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = getAnimation(0)->frameTicks[0];
+ _objects[0].x = 160;
+ _objects[0].y = 120;
+ _objects[0].kind = 1;
+ _objects[1].anim = getAnimation(37);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = getAnimation(37)->frameTicks[0];
+ _objects[1].x = 40;
+ _objects[1].y = 240;
+ _objects[1].kind = 2;
+ _objects[2].anim = getAnimation(36);
+ _objects[2].frameIndex = 0;
+ _objects[2].ticks = getAnimation(36)->frameTicks[0];
+ _objects[2].x = 280;
+ _objects[2].y = 240;
+ _objects[2].kind = 2;
+
+}
+
+void MinigameBbAirGuitar::initObjects1() {
+
+ for (int i = 0; i < 60; ++i)
+ _objects[i].kind = 0;
+
+ _objects[0].kind = 0;
+ _objects[0].kind = 1;
+ _objects[0].anim = getAnimation(0);
+ _objects[0].ticks = getAnimation(0)->frameTicks[0];
+ _objects[1].anim = getAnimation(1);
+ _objects[1].ticks = getAnimation(1)->frameTicks[0];
+ _objects[2].anim = getAnimation(2);
+ _objects[2].ticks = getAnimation(2)->frameTicks[0];
+ _objects[3].anim = getAnimation(3);
+ _objects[3].ticks = getAnimation(3)->frameTicks[0];
+ _objects[4].anim = getAnimation(4);
+ _objects[4].ticks = getAnimation(4)->frameTicks[0];
+ _objects[5].anim = getAnimation(5);
+ _objects[5].ticks = getAnimation(5)->frameTicks[0];
+ _objects[6].anim = getAnimation(6);
+ _objects[6].ticks = getAnimation(6)->frameTicks[0];
+ _objects[7].anim = getAnimation(8);
+ _objects[7].ticks = getAnimation(8)->frameTicks[0];
+ _objects[8].anim = getAnimation(9);
+ _objects[8].ticks = getAnimation(9)->frameTicks[0];
+ _objects[9].anim = getAnimation(10);
+ _objects[9].ticks = getAnimation(10)->frameTicks[0];
+ _objects[10].anim = getAnimation(11);
+ _objects[10].ticks = getAnimation(11)->frameTicks[0];
+ _objects[11].anim = getAnimation(12);
+ _objects[11].ticks = getAnimation(12)->frameTicks[0];
+ _objects[12].anim = getAnimation(13);
+ _objects[12].ticks = getAnimation(13)->frameTicks[0];
+ _objects[13].anim = getAnimation(14);
+ _objects[13].ticks = getAnimation(14)->frameTicks[0];
+ _objects[14].anim = getAnimation(15);
+ _objects[14].ticks = getAnimation(15)->frameTicks[0];
+ _objects[15].anim = getAnimation(16);
+ _objects[15].ticks = getAnimation(16)->frameTicks[0];
+ _objects[16].anim = getAnimation(17);
+ _objects[16].ticks = getAnimation(17)->frameTicks[0];
+ _objects[17].anim = getAnimation(18);
+ _objects[17].ticks = getAnimation(18)->frameTicks[0];
+ _objects[18].anim = getAnimation(19);
+ _objects[18].ticks = getAnimation(19)->frameTicks[0];
+ _objects[19].anim = getAnimation(20);
+ _objects[19].ticks = getAnimation(20)->frameTicks[0];
+ _objects[20].anim = getAnimation(21);
+ _objects[20].ticks = getAnimation(21)->frameTicks[0];
+ _objects[21].anim = getAnimation(11);
+ _objects[21].ticks = getAnimation(11)->frameTicks[0];
+ _objects[22].anim = getAnimation(22);
+ _objects[22].ticks = getAnimation(22)->frameTicks[0];
+ _objects[23].anim = getAnimation(23);
+ _objects[23].ticks = getAnimation(23)->frameTicks[0];
+ _objects[24].anim = getAnimation(24);
+ _objects[24].ticks = getAnimation(24)->frameTicks[0];
+ _objects[25].anim = getAnimation(25);
+ _objects[25].ticks = getAnimation(25)->frameTicks[0];
+ _objects[26].anim = getAnimation(26);
+ _objects[26].ticks = getAnimation(26)->frameTicks[0];
+ _objects[27].anim = getAnimation(27);
+ _objects[27].ticks = getAnimation(27)->frameTicks[0];
+ _objects[28].anim = getAnimation(28);
+ _objects[28].ticks = getAnimation(28)->frameTicks[0];
+ _objects[29].anim = getAnimation(29);
+ _objects[29].ticks = getAnimation(29)->frameTicks[0];
+ _objects[30].anim = getAnimation(30);
+ _objects[30].ticks = getAnimation(30)->frameTicks[0];
+ _objects[31].anim = getAnimation(31);
+ _objects[31].ticks = getAnimation(31)->frameTicks[0];
+ _objects[32].anim = getAnimation(32);
+ _objects[32].ticks = getAnimation(32)->frameTicks[0];
+ _objects[33].anim = getAnimation(33);
+ _objects[33].ticks = getAnimation(33)->frameTicks[0];
+ _objects[34].anim = getAnimation(34);
+ _objects[34].ticks = getAnimation(34)->frameTicks[0];
+ _objects[35].anim = getAnimation(35);
+ _objects[35].ticks = getAnimation(35)->frameTicks[0];
+
+ for (int i = 36; i <= 57; ++i) {
+ _objects[i].anim = getAnimation(7);
+ _objects[i].ticks = getAnimation(7)->frameTicks[0];
+ }
+
+ for (int i = 1; i <= 35; ++i) {
+ _objects[i].x = kObjPoints[i - 1].x;
+ _objects[i].y = kObjPoints[i - 1].y;
+ }
+
+ _objects[22].kind = 1;
+ _objects[6].kind = 1;
+ _objects[26].kind = 1;
+ _objects[26].frameIndex = 3;
+ _objects[27].kind = 1;
+ _objects[27].frameIndex = 3;
+ _objects[31].kind = 1;
+ _objects[31].frameIndex = 3;
+ _objects[32].kind = 1;
+ _objects[32].frameIndex = 3;
+ _objects[28].kind = 1;
+ _objects[33].kind = 1;
+ _objects[34].kind = 1;
+ _objects[35].kind = 1;
+
+ _track[0].noteNum = -1;
+ stop();
+ changePatch(0);
+
+}
+
+bool MinigameBbAirGuitar::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
+ switch (_gameState) {
+ case 0:
+ return updateStatus0(mouseX, mouseY, mouseButtons);
+ case 1:
+ return updateStatus1(mouseX, mouseY, mouseButtons);
+ }
+ return false;
+}
+
+bool MinigameBbAirGuitar::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
+
+ if (mouseButtons & kAnyButtonDown) {
+ stopSound(1);
+ _rockTunePlaying = false;
+ _gameState = 1;
+ initObjects();
+ _gameTicks = 0;
+ } else {
+
+ if (!_rockTunePlaying) {
+ _rockTunePlaying = true;
+ playSound(1, true);
+ }
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ for (int i = 1; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind && --obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex >= obj->anim->frameCount)
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+ }
+
+ }
+
+ return true;
+}
+
+bool MinigameBbAirGuitar::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
+
+ int currTicks = _vm->_system->getMillis();
+
+ if (_playerMode == 1 && _track[_trackIndex].ticks <= currTicks - _noteStartTime) {
+ noteOff(_track[_trackIndex].noteNum);
+ if (_trackIndex < _trackCount && _track[++_trackIndex].noteNum != -1)
+ noteOn(_track[_trackIndex].noteNum);
+ else
+ stop();
+ }
+
+ if (_vuMeterLeft1 - 2 <= _vuMeterLeft2) {
+ if (_vuMeterLeft1 + 1 >= _vuMeterLeft2) {
+ int incr = MIN(_vm->getRandom(4), 2) - 1;
+ if (incr < 0 && _vuMeterLeft2 == 0)
+ incr = -incr;
+ if (incr > 0 && _vuMeterLeft2 == 11)
+ incr = -incr;
+ _vuMeterLeft2 += incr;
+ } else {
+ --_vuMeterLeft2;
+ }
+ } else {
+ ++_vuMeterLeft2;
+ }
+
+ if (_vuMeterRight1 - 2 <= _vuMeterRight2) {
+ if (_vuMeterRight1 + 1 >= _vuMeterRight2) {
+ int incr = MIN(_vm->getRandom(4), 2) - 1;
+ if (incr < 0 && _vuMeterRight2 == 0)
+ incr = -incr;
+ if (incr > 0 && _vuMeterRight2 == 11)
+ incr = -incr;
+ _vuMeterRight2 += incr;
+ } else {
+ --_vuMeterRight2;
+ }
+ } else {
+ ++_vuMeterRight2;
+ }
+
+ if (_resetAnims && _vm->_system->getMillis() - _noteStartTime >= 1000)
+ resetObjs();
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ _trackBarMouseX = CLIP(mouseX, kTrackBarMinX, kTrackBarMaxX);
+
+ bool checkClick = false;
+
+ if (mouseButtons & kAnyButtonClicked) {
+ checkClick = true;
+ } else if (!(mouseButtons & kAnyButtonDown)) {
+ afterButtonReleased();
+ } else if (!_movingTrackBar && ((_currButtonNum >= 14 && ptInPoly(_currPianoKeyArea, mouseX, mouseY)) || ptInRect(_currPlayerButtonRect, mouseX, mouseY))) {
+ if (_currButtonNum == 5 && _trackIndex > 0) {
+ --_trackIndex;
+ calcTotalTicks2();
+ } else if (_currButtonNum == 13 && _trackIndex < _trackCount) {
+ ++_trackIndex;
+ calcTotalTicks2();
+ }
+ } else if (!_movingTrackBar)
+ checkClick = true;
+
+ if (checkClick) {
+
+ afterButtonReleased();
+ _objects[0].frameIndex = 1;
+
+ if (ptInRect(&kRect2, mouseX, mouseY)) {
+
+ if (_playerMode != 1 && ptInRect(&kPianoRect, mouseX, mouseY)) {
+ for (int i = 0; i <= 12; ++i) {
+ if (ptInPoly(&kPianoKeyAreas[i], mouseX, mouseY)) {
+ _currButtonNum = i + 14;
+ _currPianoKeyArea = &kPianoKeyAreas[i];
+ _objects[11].kind = 1;
+ _objects[11].x = kPianoKeyInfos[i].x;
+ _objects[11].y = kPianoKeyInfos[i].y;
+ _objects[11].frameIndex = kPianoKeyInfos[i].frameIndex;
+ noteOn(i);
+ break;
+ }
+ }
+ } else if (_playerMode != 1 && ptInRect(&_trackBarThumbRect, mouseX, mouseY)) {
+ _movingTrackBar = true;
+ } else {
+
+ int playerButtonNum = -1;
+ for (int i = 0; i < 14; ++i) {
+ if (ptInRect(&kPlayerButtonRects[i], mouseX, mouseY)) {
+ playerButtonNum = i;
+ break;
+ }
+ }
+
+ if (playerButtonNum >= 0) {
+ _currButtonNum = playerButtonNum;
+ _currPlayerButtonRect = &kPlayerButtonRects[playerButtonNum];
+
+ switch (playerButtonNum) {
+
+ case 0:
+ if (_playerMode == 0) {
+ changePatch(0);
+ _currFrameIndex = &_objects[18 + 0].frameIndex;
+ *_currFrameIndex = 0;
+ }
+ break;
+
+ case 1:
+ if (_playerMode == 0) {
+ changePatch(1);
+ _currFrameIndex = &_objects[18 + 1].frameIndex;
+ *_currFrameIndex = 0;
+ }
+ break;
+
+ case 2:
+ if (_playerMode == 0) {
+ changePatch(2);
+ _currFrameIndex = &_objects[18 + 2].frameIndex;
+ *_currFrameIndex = 0;
+ }
+ break;
+
+ case 3:
+ _btn3KindToggle = !_btn3KindToggle;
+ _objects[9].kind = _btn3KindToggle ? 0 : 1;
+ _objects[22].frameIndex = _btn3KindToggle ? 0 : 1;
+ break;
+
+ case 4:
+ if (_playerMode == 0) {
+ _objects[1].kind = 1;
+ _currFrameIndex = &_objects[1].frameIndex;
+ _objects[1].frameIndex = 0;
+ }
+ break;
+
+ case 5:
+ if (_playerMode == 0) {
+ if (_trackIndex > 0)
+ --_trackIndex;
+ _objects[3].kind = 1;
+ calcTotalTicks2();
+ }
+ break;
+
+ case 6:
+ stop();
+ _currFrameIndex = &_objects[15].frameIndex;
+ _objects[15].frameIndex = 0;
+ break;
+
+ case 7:
+ if (_playerMode == 0) {
+ play();
+ _currFrameIndex = &_objects[12].frameIndex;
+ _objects[12].frameIndex = 0;
+ }
+ break;
+
+ case 8:
+ if (_playerMode == 0) {
+ _trackIndex = 0;
+ _objects[16].kind = 1;
+ calcTotalTicks2();
+ }
+ break;
+
+ case 9:
+ if (_playerMode == 0) {
+ _trackIndex = _trackCount;
+ _objects[17].kind = 1;
+ calcTotalTicks2();
+ }
+ break;
+
+ case 10:
+ if (_playerMode == 0) {
+ record();
+ _currFrameIndex = &_objects[13].frameIndex;
+ _objects[13].frameIndex = 0;
+ }
+ break;
+
+ case 11:
+ if (_playerMode == 0) {
+ setPlayerMode3();
+ _currFrameIndex = &_objects[14].frameIndex;
+ _objects[14].frameIndex = 0;
+ }
+ break;
+
+ case 12:
+ if (_playerMode == 0) {
+ _objects[2].kind = 1;
+ _currFrameIndex = &_objects[2].frameIndex;
+ _objects[2].frameIndex = 0;
+ }
+ break;
+
+ case 13:
+ if (_playerMode == 0) {
+ if (_trackIndex < _trackCount)
+ ++_trackIndex;
+ _objects[4].kind = 1;
+ calcTotalTicks2();
+ }
+ break;
+
+ }
+ }
+ }
+ }
+ }
+
+ if (_playerMode != 0) {
+ _currTrackPos = currTicks + _actionStartTrackPos - _actionStartTime;
+ if (_currTrackPos > _actionTrackPos && _playerMode != 1) {
+ if (_currTrackPos >= 15000) {
+ _currTrackPos = 15000;
+ _actionTrackPos = 15000;
+ stop();
+ } else {
+ _actionTrackPos = currTicks + _actionStartTrackPos - _actionStartTime;
+ }
+ }
+ }
+
+ if (_buttonClickTicks + 1000 < currTicks)
+ _buttonClickTicks = currTicks;
+
+ int newKind = _buttonClickTicks + 500 < currTicks ? 1 : 0;
+
+ switch (_playerMode) {
+
+ case 1:
+ if (_currButtonNum == 7) {
+ _objects[12].kind = 1;
+ _objects[12].frameIndex = 0;
+ } else {
+ _objects[12].kind = newKind;
+ _objects[12].frameIndex = 1;
+ }
+ break;
+
+ case 2:
+ if (_currButtonNum == 10) {
+ _objects[13].kind = 1;
+ _objects[13].frameIndex = 0;
+ } else {
+ _objects[13].kind = newKind;
+ _objects[13].frameIndex = 1;
+ }
+ break;
+
+ case 3:
+ if (_currButtonNum == 11) {
+ _objects[14].kind = 1;
+ _objects[14].frameIndex = 0;
+ } else {
+ _objects[14].kind = newKind;
+ _objects[14].frameIndex = 1;
+ }
+ break;
+
+ }
+
+ updateObjs();
+
+ return true;
+}
+
+void MinigameBbAirGuitar::updateObjs() {
+ for (int i = 24; i <= 33; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind && --obj->ticks == 0) {
+ if (obj->frameIndex + 1 >= obj->anim->frameCount) {
+ obj->ticks = -1;
+ } else {
+ ++obj->frameIndex;
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+ }
+ }
+}
+
+int MinigameBbAirGuitar::run(bool fromMainGame) {
+
+ memset(_objects, 0, sizeof(_objects));
+
+ _modified = false;
+ _currPatchNum = -1;
+ _btn3KindToggle = 0;
+ _currButtonNum = 27;
+ _actionStartTime = 0;
+ _currFrameIndex = 0;
+ _currPlayerButtonRect = 0;
+ _currPianoKeyArea = 0;
+ _trackCount = 0;
+ _trackIndex = 0;
+ _totalTrackLength = 0;
+ _actionTrackPos = 0;
+ _noteStartTime = 0;
+ _actionStartTrackPos = 0;
+ _trackBarX = kTrackBarMinX;
+ _currTrackPos = 0;
+ _currNoteNum = -2;
+ _resetAnims = false;
+ _vuMeterLeft2 = 0;
+ _vuMeterRight2 = 0;
+ _vuMeterLeft1 = 0;
+ _vuMeterRight1 = 0;
+ _rockTunePlaying = false;
+
+ _backgroundSpriteIndex = 97;
+ _titleScreenSpriteIndex = 98;
+
+ _fromMainGame = fromMainGame;
+
+ _gameState = 0;
+ _gameTicks = 0;
+ _gameResult = 0;
+ _gameDone = false;
+ initObjects();
+
+ _spriteModule = new SpriteModule();
+ _spriteModule->load("bbairg/bbairg.000");
+
+ Palette palette = _spriteModule->getPalette();
+ _vm->_screen->setPalette(palette);
+
+ loadSounds();
+
+ while (!_vm->shouldQuit() &&!_gameDone) {
+ _vm->updateEvents();
+ update();
+ }
+
+ _vm->_sound->unloadSounds();
+
+ delete _spriteModule;
+
+ return _gameResult;
+}
+
+void MinigameBbAirGuitar::update() {
+
+ int currTicks, inputTicks;
+
+ if (_gameTicks > 0) {
+ currTicks = _vm->_system->getMillis();
+ inputTicks = 3 * (currTicks - _gameTicks) / 50;
+ _gameTicks = currTicks - (currTicks - _gameTicks - 50 * inputTicks / 3);
+ } else {
+ inputTicks = 1;
+ _gameTicks = _vm->_system->getMillis();
+ }
+
+ if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
+ _gameDone = true;
+ return;
+ }
+
+ if (inputTicks == 0)
+ return;
+
+ bool done;
+
+ do {
+ done = !updateStatus(_vm->_mouseX, _vm->_mouseY, _vm->_mouseButtons);
+ _vm->_mouseButtons &= ~kLeftButtonClicked;
+ _vm->_mouseButtons &= ~kRightButtonClicked;
+ _vm->_keyCode = Common::KEYCODE_INVALID;
+ } while (--inputTicks && _gameTicks > 0 && !done);
+
+ drawSprites();
+
+ _vm->_system->delayMillis(10);
+
+}
+
+void MinigameBbAirGuitar::play() {
+ if (_track[_trackIndex].noteNum != -1) {
+ _playerMode = 1;
+ _objects[7].kind = 1;
+ _objects[8].kind = 0;
+ _objects[15].kind = 0;
+ _actionStartTime = _vm->_system->getMillis();
+ _actionStartTrackPos = _currTrackPos;
+ noteOn(_track[_trackIndex].noteNum);
+ }
+}
+
+
+void MinigameBbAirGuitar::record() {
+ _playerMode = 2;
+ _objects[7].kind = 1;
+ _objects[8].kind = 0;
+ _objects[15].kind = 0;
+ _totalTrackLength = 15000;
+ _actionStartTime = _vm->_system->getMillis();
+ _actionStartTrackPos = _currTrackPos;
+ _noteStartTime = _vm->_system->getMillis();
+ _actionTrackPos = _currTrackPos;
+ _trackCount = _trackIndex;
+ _vuMeterRight1 = 0;
+ _vuMeterRight2 = 0;
+ _vuMeterLeft1 = 0;
+ _vuMeterLeft2 = 0;
+ _modified = true;
+ _track[_trackIndex].noteNum = -2;
+}
+
+void MinigameBbAirGuitar::setPlayerMode3() {
+ _playerMode = 3;
+ _objects[7].kind = 1;
+ _objects[8].kind = 0;
+ _objects[15].kind = 0;
+ _totalTrackLength = 15000;
+ _actionStartTime = _vm->_system->getMillis();
+ _actionStartTrackPos = _currTrackPos;
+ _noteStartTime = _vm->_system->getMillis();
+ _actionTrackPos = _currTrackPos;
+ _trackCount = _trackIndex;
+ _vuMeterRight1 = 0;
+ _vuMeterRight2 = 0;
+ _vuMeterLeft1 = 0;
+ _vuMeterLeft2 = 0;
+ _modified = true;
+ _track[_trackIndex].noteNum = -2;
+}
+
+void MinigameBbAirGuitar::stop() {
+ noteOff(_currNoteNum);
+ if (_playerMode == 2 || _playerMode == 3) {
+ _totalTrackLength = _actionTrackPos;
+ _track[_trackCount].noteNum = -1;
+ }
+ _playerMode = 0;
+ _objects[7].kind = 0;
+ _objects[8].kind = 1;
+ _objects[15].kind = 1;
+ _objects[15].frameIndex = 1;
+ _objects[12].kind = 0;
+ _objects[13].kind = 0;
+ _objects[14].kind = 0;
+ resetObjs();
+}
+
+void MinigameBbAirGuitar::changePatch(int patchNum) {
+
+ resetObjs();
+
+ if (patchNum == -1 || patchNum != _currPatchNum)
+ _currPatchNum = -1;
+
+ _objects[20].kind = 0;
+ _objects[19].kind = _objects[20].kind;
+ _objects[18].kind = _objects[19].kind;
+ _objects[patchNum + 18].kind = 1;
+ _objects[patchNum + 18].frameIndex = 1;
+ _objects[6].frameIndex = patchNum;
+ _currPatchNum = patchNum;
+}
+
+void MinigameBbAirGuitar::afterButtonReleased() {
+ if (_movingTrackBar) {
+ _movingTrackBar = false;
+ _currTrackPos = _totalTrackLength * (_trackBarX - kTrackBarMinX) / 100;
+ calcTotalTicks1();
+ } else {
+ switch (_currButtonNum) {
+ case 0:
+ case 1:
+ case 2:
+ *_currFrameIndex = 1;
+ break;
+ case 4:
+ *_currFrameIndex = 1;
+ // TODO Run load dialog
+ break;
+ case 5:
+ _objects[3].kind = 0;
+ break;
+ case 6:
+ *_currFrameIndex = 1;
+ break;
+ case 7:
+ *_currFrameIndex = 1;
+ break;
+ case 8:
+ _objects[16].kind = 0;
+ break;
+ case 9:
+ _objects[17].kind = 0;
+ break;
+ case 10:
+ *_currFrameIndex = 1;
+ break;
+ case 11:
+ *_currFrameIndex = 1;
+ break;
+ case 12:
+ *_currFrameIndex = 1;
+ // TODO Run save dialog
+ break;
+ case 13:
+ _objects[4].kind = 0;
+ break;
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ noteOff(_currButtonNum - 14);
+ break;
+ }
+ }
+
+ _objects->frameIndex = 0;
+ _currPlayerButtonRect = 0;
+ _currPianoKeyArea = 0;
+ _currButtonNum = 27;
+}
+
+void MinigameBbAirGuitar::calcTotalTicks2() {
+ _currTrackPos = 0;
+ for (int i = 0; i < _trackIndex; ++i)
+ _currTrackPos += _track[i].ticks;
+}
+
+void MinigameBbAirGuitar::calcTotalTicks1() {
+ int totalTicks = 0;
+ // TODO Try to clean this up
+ _trackIndex = 0;
+ if (_track[0].ticks <= _currTrackPos) {
+ do {
+ totalTicks += _track[_trackIndex].ticks;
+ if (_trackIndex >= _trackCount)
+ break;
+ ++_trackIndex;
+ } while (totalTicks + _track[_trackIndex].ticks <= _currTrackPos);
+ }
+ _currTrackPos = totalTicks;
+}
+
+void MinigameBbAirGuitar::noteOn(int noteNum) {
+
+ if (_currNoteNum != -2) {
+ if (noteNum == _currNoteNum)
+ return;
+ noteOff(_currNoteNum);
+ }
+
+ if (noteNum == -2) {
+ _vuMeterRight1 = 0;
+ _vuMeterRight2 = 0;
+ _vuMeterLeft1 = 0;
+ _vuMeterLeft2 = 0;
+ } else {
+ playNote(noteNum);
+ _vuMeterRight1 = 10;
+ _vuMeterRight2 = 10;
+ _vuMeterLeft1 = 10;
+ _vuMeterLeft2 = 10;
+ if (_btn3KindToggle) {
+ _objects[23].kind = 1;
+ _objects[23].frameIndex = noteNum;
+ } else {
+ _objects[10].kind = 1;
+ _objects[10].frameIndex = kNoteFrameTbl[noteNum].frameIndex;
+ if (kNoteFrameTbl[noteNum].flag) {
+ _objects[21].kind = 1;
+ _objects[21].frameIndex = 7;
+ }
+ }
+ }
+
+ _currNoteNum = noteNum;
+
+ if (_playerMode == 2 || _playerMode == 3) {
+ _ticksDelta = _vm->_system->getMillis() - _noteStartTime;
+ _track[_trackCount].ticks = _ticksDelta;
+ if (_trackCount < kMaxTracks)
+ ++_trackCount;
+ _track[_trackCount].noteNum = noteNum;
+ }
+
+ _noteStartTime = _vm->_system->getMillis();
+
+ if (noteNum != -2) {
+ _resetAnims = false;
+ if (_currPatchNum == 0) {
+ _objects[25].kind = 1;
+ _objects[28].kind = 0;
+ _objects[25].frameIndex = 0;
+ _objects[25].ticks = getAnimation(25)->frameTicks[0];
+ _objects[26].frameIndex = 0;
+ _objects[26].ticks = getAnimation(26)->frameTicks[0];
+ _objects[27].frameIndex = 0;
+ _objects[27].ticks = getAnimation(27)->frameTicks[0];
+ _objects[30].kind = 1;
+ _objects[33].kind = 0;
+ _objects[30].frameIndex = 0;
+ _objects[30].ticks = getAnimation(30)->frameTicks[0];
+ _objects[31].frameIndex = 0;
+ _objects[31].ticks = getAnimation(31)->frameTicks[0];
+ _objects[32].frameIndex = 0;
+ _objects[32].ticks = getAnimation(32)->frameTicks[0];
+ } else if (_currPatchNum == 1) {
+ _objects[29].kind = 1;
+ _objects[33].kind = 0;
+ _objects[29].frameIndex = 0;
+ _objects[29].ticks = getAnimation(29)->frameTicks[0];
+ _objects[31].frameIndex = 0;
+ _objects[31].ticks = getAnimation(31)->frameTicks[0];
+ _objects[32].frameIndex = 0;
+ _objects[32].ticks = getAnimation(32)->frameTicks[0];
+ } else if (_currPatchNum == 2) {
+ _objects[24].kind = 1;
+ _objects[28].kind = 0;
+ _objects[24].frameIndex = 0;
+ _objects[24].ticks = getAnimation(24)->frameTicks[0];
+ _objects[26].frameIndex = 0;
+ _objects[26].ticks = getAnimation(26)->frameTicks[0];
+ _objects[27].frameIndex = 0;
+ _objects[27].ticks = getAnimation(27)->frameTicks[0];
+ }
+ }
+
+}
+
+void MinigameBbAirGuitar::noteOff(int noteNum) {
+
+ if (_currNoteNum != noteNum)
+ return;
+
+ if (noteNum != -2)
+ stopNote(noteNum);
+
+ _objects[21].kind = 0;
+ _objects[23].kind = _objects[21].kind;
+ _objects[10].kind = _objects[23].kind;
+
+ _vuMeterRight1 = 0;
+ _vuMeterRight2 = 0;
+ _vuMeterLeft1 = 0;
+ _vuMeterLeft2 = 0;
+
+ _currNoteNum = -2;
+
+ _objects[11].kind = 0;
+
+ _ticksDelta = _vm->_system->getMillis() - _noteStartTime;
+
+ if (_playerMode == 2 || _playerMode == 3) {
+ if (_actionTrackPos + _ticksDelta > 15000)
+ _ticksDelta = 15000 - _actionTrackPos;
+ _track[_trackCount].ticks = _ticksDelta;
+ if (_trackCount < 2048)
+ ++_trackCount;
+ _track[_trackCount].noteNum = -2;
+ _noteStartTime = _vm->_system->getMillis();
+ }
+
+ if (noteNum != -2) {
+ if (_playerMode == 0) {
+ _resetAnims = true;
+ _noteStartTime = _vm->_system->getMillis();
+ }
+ if (_currPatchNum == 0) {
+ _objects[25].frameIndex = 3;
+ _objects[25].ticks = -1;
+ _objects[26].frameIndex = 3;
+ _objects[26].ticks = -1;
+ _objects[27].frameIndex = 3;
+ _objects[27].ticks = -1;
+ _objects[30].frameIndex = 3;
+ _objects[30].ticks = -1;
+ _objects[31].frameIndex = 3;
+ _objects[31].ticks = -1;
+ _objects[32].frameIndex = 3;
+ _objects[32].ticks = -1;
+ } else if (_currPatchNum == 1) {
+ _objects[29].frameIndex = 3;
+ _objects[29].ticks = -1;
+ _objects[31].frameIndex = 3;
+ _objects[31].ticks = -1;
+ _objects[32].frameIndex = 3;
+ _objects[32].ticks = -1;
+ } else if (_currPatchNum == 2) {
+ _objects[24].frameIndex = 2;
+ _objects[24].ticks = -1;
+ _objects[26].frameIndex = 3;
+ _objects[26].ticks = -1;
+ _objects[27].frameIndex = 3;
+ _objects[27].ticks = -1;
+ }
+ }
+
+}
+
+void MinigameBbAirGuitar::resetObjs() {
+ _resetAnims = false;
+ _objects[25].kind = 0;
+ _objects[24].kind = 0;
+ _objects[28].kind = 1;
+ _objects[26].frameIndex = 0;
+ _objects[26].ticks = -1;
+ _objects[27].frameIndex = 0;
+ _objects[27].ticks = -1;
+ _objects[30].kind = 0;
+ _objects[29].kind = 0;
+ _objects[33].kind = 1;
+ _objects[31].frameIndex = 0;
+ _objects[31].ticks = -1;
+ _objects[32].frameIndex = 0;
+ _objects[32].ticks = -1;
+}
+
+void MinigameBbAirGuitar::loadSounds() {
+ _vm->_sound->loadSound("bbairg/audio/rocktune.aif");
+ for (uint i = 0; i < kPatchDirectoriesCount; ++i) {
+ const char *patchDirectory = kPatchDirectories[i];
+ for (uint j = 0; j < kNoteSoundFilenamesCount; ++j) {
+ Common::String filename = Common::String::format("bbairg/audio/%s/%s", patchDirectory, kNoteSoundFilenames[j]);
+ _vm->_sound->loadSound(filename.c_str());
+ }
+ }
+}
+
+void MinigameBbAirGuitar::playNote(int noteNum) {
+ if (noteNum >= 0 && _currPatchNum >= 0)
+ playSound(2 + _currPatchNum * kNoteSoundFilenamesCount + noteNum);
+}
+
+void MinigameBbAirGuitar::stopNote(int noteNum) {
+ if (noteNum >= 0 && _currPatchNum >= 0)
+ stopSound(2 + _currPatchNum * kNoteSoundFilenamesCount + noteNum);
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbairguitar.h b/engines/bbvs/minigames/bbairguitar.h
new file mode 100644
index 0000000000..eba301632d
--- /dev/null
+++ b/engines/bbvs/minigames/bbairguitar.h
@@ -0,0 +1,148 @@
+/* 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 BBVS_MINIGAMES_BBAIRGUITAR_H
+#define BBVS_MINIGAMES_BBAIRGUITAR_H
+
+#include "bbvs/minigames/minigame.h"
+
+namespace Bbvs {
+
+class MinigameBbAirGuitar : public Minigame {
+public:
+ MinigameBbAirGuitar(BbvsEngine *vm) : Minigame(vm) {};
+ int run(bool fromMainGame);
+public:
+
+ struct Obj {
+ int kind;
+ int x, y;
+ int xIncr, yIncr;
+ const ObjAnimation *anim;
+ int frameIndex;
+ int ticks;
+ int status;
+ int16 frameIndexAdd;
+ int16 unk2;
+ };
+
+ enum {
+ kMaxObjectsCount = 256,
+ kMaxTracks = 2049
+ };
+
+ struct PianoKeyInfo {
+ int x, y;
+ int frameIndex;
+ };
+
+ struct TrackEvt {
+ int8 noteNum;
+ int16 ticks;
+ };
+
+ Obj _objects[kMaxObjectsCount];
+
+ int _playerMode;
+
+ bool _modified;
+
+ TrackEvt _track[kMaxTracks];
+ int _trackIndex, _trackCount;
+
+ int _noteStartTime;
+
+ int _vuMeterLeft1, _vuMeterLeft2;
+ int _vuMeterRight1, _vuMeterRight2;
+
+ bool _resetAnims;
+ bool _rockTunePlaying;
+
+ int _currButtonNum;
+ int _buttonClickTicks;
+
+ int *_currFrameIndex;
+ int _btn3KindToggle;
+
+ const BBPolygon *_currPianoKeyArea;
+ const Rect *_currPlayerButtonRect;
+
+ bool _movingTrackBar;
+ int _trackBarMouseX;
+ int _trackBarX;
+ Rect _trackBarThumbRect;
+
+ int _currTrackPos, _totalTrackLength;
+ int _ticksDelta;
+
+ int _actionStartTrackPos, _actionTrackPos;
+ int _actionStartTime;
+
+ int _currNoteNum;
+ int _currPatchNum;
+
+ const ObjAnimation *getAnimation(int animIndex);
+ bool ptInRect(const Rect *r, int x, int y);
+ bool ptInPoly(const BBPolygon *poly, int x, int y);
+
+ void buildDrawList(DrawList &drawList);
+ void buildDrawList0(DrawList &drawList);
+ void buildDrawList1(DrawList &drawList);
+
+ void drawSprites();
+
+ void initObjs();
+ Obj *getFreeObject();
+
+ void initObjects();
+ void initObjects0();
+ void initObjects1();
+
+ bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
+
+ void updateObjs();
+
+ void update();
+
+ void play();
+ void record();
+ void setPlayerMode3();
+ void stop();
+ void changePatch(int patchNum);
+ void afterButtonReleased();
+ void calcTotalTicks2();
+ void calcTotalTicks1();
+ void noteOn(int noteNum);
+ void noteOff(int noteNum);
+ void resetObjs();
+
+ void loadSounds();
+ void playNote(int noteNum);
+ void stopNote(int noteNum);
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_MINIGAMES_BBAIRGUITAR_H
diff --git a/engines/bbvs/minigames/bbairguitar_anims.cpp b/engines/bbvs/minigames/bbairguitar_anims.cpp
new file mode 100644
index 0000000000..4f87eb5c78
--- /dev/null
+++ b/engines/bbvs/minigames/bbairguitar_anims.cpp
@@ -0,0 +1,186 @@
+/* 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 "bbvs/minigames/bbairguitar.h"
+
+namespace Bbvs {
+
+static const int kAnim0FrameIndices[] = {0, 1};
+static const int16 kAnim0FrameTicks[] = {6, 6};
+static const BBRect kAnim0FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim1FrameIndices[] = {2, 3};
+static const int16 kAnim1FrameTicks[] = {6, 6};
+static const BBRect kAnim1FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim2FrameIndices[] = {4, 5};
+static const int16 kAnim2FrameTicks[] = {6, 6};
+static const BBRect kAnim2FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim3FrameIndices[] = {6};
+static const int16 kAnim3FrameTicks[] = {6};
+static const BBRect kAnim3FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim4FrameIndices[] = {7};
+static const int16 kAnim4FrameTicks[] = {6};
+static const BBRect kAnim4FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim5FrameIndices[] = {8};
+static const int16 kAnim5FrameTicks[] = {6};
+static const BBRect kAnim5FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim6FrameIndices[] = {9, 10, 11};
+static const int16 kAnim6FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim6FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim7FrameIndices[] = {12, 13, 14, 15};
+static const int16 kAnim7FrameTicks[] = {10, 10, 10, 10};
+static const BBRect kAnim7FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim8FrameIndices[] = {16};
+static const int16 kAnim8FrameTicks[] = {10};
+static const BBRect kAnim8FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim9FrameIndices[] = {17};
+static const int16 kAnim9FrameTicks[] = {10};
+static const BBRect kAnim9FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim10FrameIndices[] = {18};
+static const int16 kAnim10FrameTicks[] = {6};
+static const BBRect kAnim10FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim11FrameIndices[] = {19, 20, 21, 22, 23, 24, 25, 26, 27};
+static const int16 kAnim11FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim11FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim12FrameIndices[] = {28, 29, 30, 31, 32, 33};
+static const int16 kAnim12FrameTicks[] = {10, 10, 10, 10, 10, 10};
+static const BBRect kAnim12FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim13FrameIndices[] = {34, 35};
+static const int16 kAnim13FrameTicks[] = {6, 6};
+static const BBRect kAnim13FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim14FrameIndices[] = {36, 37};
+static const int16 kAnim14FrameTicks[] = {6, 6};
+static const BBRect kAnim14FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim15FrameIndices[] = {38, 39};
+static const int16 kAnim15FrameTicks[] = {6, 6};
+static const BBRect kAnim15FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim16FrameIndices[] = {40, 41};
+static const int16 kAnim16FrameTicks[] = {6, 6};
+static const BBRect kAnim16FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim17FrameIndices[] = {42};
+static const int16 kAnim17FrameTicks[] = {6};
+static const BBRect kAnim17FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim18FrameIndices[] = {43};
+static const int16 kAnim18FrameTicks[] = {6};
+static const BBRect kAnim18FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim19FrameIndices[] = {44, 45};
+static const int16 kAnim19FrameTicks[] = {6, 6};
+static const BBRect kAnim19FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim20FrameIndices[] = {46, 47};
+static const int16 kAnim20FrameTicks[] = {6, 6};
+static const BBRect kAnim20FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim21FrameIndices[] = {48, 49};
+static const int16 kAnim21FrameTicks[] = {6, 6};
+static const BBRect kAnim21FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim22FrameIndices[] = {50, 51};
+static const int16 kAnim22FrameTicks[] = {10, 10};
+static const BBRect kAnim22FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim23FrameIndices[] = {52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64};
+static const int16 kAnim23FrameTicks[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8};
+static const BBRect kAnim23FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim24FrameIndices[] = {65, 66, 67};
+static const int16 kAnim24FrameTicks[] = {11, 16, 6};
+static const BBRect kAnim24FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim25FrameIndices[] = {68, 67, 69, 67};
+static const int16 kAnim25FrameTicks[] = {6, 6, 11, 6};
+static const BBRect kAnim25FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim26FrameIndices[] = {70, 71, 72, 71};
+static const int16 kAnim26FrameTicks[] = {6, 6, 6, 6};
+static const BBRect kAnim26FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim27FrameIndices[] = {73, 74, 75, 74};
+static const int16 kAnim27FrameTicks[] = {6, 6, 6, 6};
+static const BBRect kAnim27FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim28FrameIndices[] = {76};
+static const int16 kAnim28FrameTicks[] = {6};
+static const BBRect kAnim28FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim29FrameIndices[] = {77, 78, 79, 78};
+static const int16 kAnim29FrameTicks[] = {6, 6, 18, 6};
+static const BBRect kAnim29FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim30FrameIndices[] = {77, 80, 81, 80};
+static const int16 kAnim30FrameTicks[] = {6, 6, 10, 6};
+static const BBRect kAnim30FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim31FrameIndices[] = {82, 83, 84, 83};
+static const int16 kAnim31FrameTicks[] = {6, 6, 6, 6};
+static const BBRect kAnim31FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim32FrameIndices[] = {85, 86, 87, 86};
+static const int16 kAnim32FrameTicks[] = {6, 6, 6, 6};
+static const BBRect kAnim32FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim33FrameIndices[] = {88};
+static const int16 kAnim33FrameTicks[] = {6};
+static const BBRect kAnim33FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim34FrameIndices[] = {89};
+static const int16 kAnim34FrameTicks[] = {6};
+static const BBRect kAnim34FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim35FrameIndices[] = {90};
+static const int16 kAnim35FrameTicks[] = {6};
+static const BBRect kAnim35FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim36FrameIndices[] = {91, 92, 93, 91, 93, 91, 92, 93, 92, 91, 92, 93, 91, 93, 91, 92, 93, 92};
+static const int16 kAnim36FrameTicks[] = {10, 6, 8, 6, 6, 8, 6, 6, 6, 10, 6, 8, 6, 6, 8, 6, 6, 6};
+static const BBRect kAnim36FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim37FrameIndices[] = {94, 95, 96, 94, 96, 94, 95, 96, 95, 94, 95, 96, 94, 96, 94, 95, 96, 95};
+static const int16 kAnim37FrameTicks[] = {10, 6, 8, 6, 6, 8, 6, 6, 6, 10, 6, 8, 6, 6, 8, 6, 6, 6};
+static const BBRect kAnim37FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const ObjAnimation kAnimations[] = {
+ {2, kAnim0FrameIndices, kAnim0FrameTicks, kAnim0FrameRects},
+ {2, kAnim1FrameIndices, kAnim1FrameTicks, kAnim1FrameRects},
+ {2, kAnim2FrameIndices, kAnim2FrameTicks, kAnim2FrameRects},
+ {1, kAnim3FrameIndices, kAnim3FrameTicks, kAnim3FrameRects},
+ {1, kAnim4FrameIndices, kAnim4FrameTicks, kAnim4FrameRects},
+ {1, kAnim5FrameIndices, kAnim5FrameTicks, kAnim5FrameRects},
+ {3, kAnim6FrameIndices, kAnim6FrameTicks, kAnim6FrameRects},
+ {4, kAnim7FrameIndices, kAnim7FrameTicks, kAnim7FrameRects},
+ {1, kAnim8FrameIndices, kAnim8FrameTicks, kAnim8FrameRects},
+ {1, kAnim9FrameIndices, kAnim9FrameTicks, kAnim9FrameRects},
+ {1, kAnim10FrameIndices, kAnim10FrameTicks, kAnim10FrameRects},
+ {9, kAnim11FrameIndices, kAnim11FrameTicks, kAnim11FrameRects},
+ {6, kAnim12FrameIndices, kAnim12FrameTicks, kAnim12FrameRects},
+ {2, kAnim13FrameIndices, kAnim13FrameTicks, kAnim13FrameRects},
+ {2, kAnim14FrameIndices, kAnim14FrameTicks, kAnim14FrameRects},
+ {2, kAnim15FrameIndices, kAnim15FrameTicks, kAnim15FrameRects},
+ {2, kAnim16FrameIndices, kAnim16FrameTicks, kAnim16FrameRects},
+ {1, kAnim17FrameIndices, kAnim17FrameTicks, kAnim17FrameRects},
+ {1, kAnim18FrameIndices, kAnim18FrameTicks, kAnim18FrameRects},
+ {2, kAnim19FrameIndices, kAnim19FrameTicks, kAnim19FrameRects},
+ {2, kAnim20FrameIndices, kAnim20FrameTicks, kAnim20FrameRects},
+ {2, kAnim21FrameIndices, kAnim21FrameTicks, kAnim21FrameRects},
+ {2, kAnim22FrameIndices, kAnim22FrameTicks, kAnim22FrameRects},
+ {13, kAnim23FrameIndices, kAnim23FrameTicks, kAnim23FrameRects},
+ {3, kAnim24FrameIndices, kAnim24FrameTicks, kAnim24FrameRects},
+ {4, kAnim25FrameIndices, kAnim25FrameTicks, kAnim25FrameRects},
+ {4, kAnim26FrameIndices, kAnim26FrameTicks, kAnim26FrameRects},
+ {4, kAnim27FrameIndices, kAnim27FrameTicks, kAnim27FrameRects},
+ {1, kAnim28FrameIndices, kAnim28FrameTicks, kAnim28FrameRects},
+ {4, kAnim29FrameIndices, kAnim29FrameTicks, kAnim29FrameRects},
+ {4, kAnim30FrameIndices, kAnim30FrameTicks, kAnim30FrameRects},
+ {4, kAnim31FrameIndices, kAnim31FrameTicks, kAnim31FrameRects},
+ {4, kAnim32FrameIndices, kAnim32FrameTicks, kAnim32FrameRects},
+ {1, kAnim33FrameIndices, kAnim33FrameTicks, kAnim33FrameRects},
+ {1, kAnim34FrameIndices, kAnim34FrameTicks, kAnim34FrameRects},
+ {1, kAnim35FrameIndices, kAnim35FrameTicks, kAnim35FrameRects},
+ {18, kAnim36FrameIndices, kAnim36FrameTicks, kAnim36FrameRects},
+ {18, kAnim37FrameIndices, kAnim37FrameTicks, kAnim37FrameRects}
+};
+
+const ObjAnimation *MinigameBbAirGuitar::getAnimation(int animIndex) {
+ return &kAnimations[animIndex];
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbant.cpp b/engines/bbvs/minigames/bbant.cpp
new file mode 100644
index 0000000000..abecf22aff
--- /dev/null
+++ b/engines/bbvs/minigames/bbant.cpp
@@ -0,0 +1,1317 @@
+/* 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 "bbvs/minigames/bbant.h"
+
+namespace Bbvs {
+
+static const BBPoint kPosIncrTbl1[] = {
+ {0, -1}, {-1, -1}, {-1, 0}, {-1, 1},
+ { 0, 1}, { 1, 1}, { 1, 0}, { 1, -1}
+};
+
+static const BBPoint kPosIncrTbl2[] = {
+ {0, -2}, {-2, -2}, {-2, 0}, {-2, 2},
+ { 0, 2}, { 2, 2}, { 2, 0}, { 2, -2}
+};
+
+static const int kScoreTbl[] = {
+ 0, 1, 1, 3, 2, 4
+};
+
+static const char * const kSoundFilenames[] = {
+ "ant1.aif", "ant2.aif", "ant3.aif", "ant4.aif", "ant5.aif",
+ "ant6.aif", "ant7.aif", "ant8.aif", "ant9.aif", "ant10.aif",
+ "ant11.aif", "antmus1.aif", "fryant.aif", "stomp.aif", "bing.aif",
+ "bvyell.aif"
+};
+
+static const uint kSoundFilenamesCount = ARRAYSIZE(kSoundFilenames);
+
+static const uint kSoundTbl1[] = {
+ 2, 3, 4, 6
+};
+
+static const uint kSoundTbl2[] = {
+ 5, 7, 11
+};
+
+static const uint kSoundTbl3[] = {
+ 8, 10, 11
+};
+
+static const uint kSoundTbl4[] = {
+ 2, 3, 4, 6, 8, 10, 11, 5, 7, 16
+};
+
+void MinigameBbAnt::buildDrawList0(DrawList &drawList) {
+
+ if (_titleScreenSpriteIndex)
+ drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->priority);
+ }
+
+}
+
+void MinigameBbAnt::buildDrawList1(DrawList &drawList) {
+
+ if (_backgroundSpriteIndex)
+ drawList.add(_backgroundSpriteIndex, _stompX, _stompY, 0);
+
+ for (int i = 1; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind) {
+ drawList.add(obj->anim->frameIndices[obj->frameIndex],
+ _stompX + (obj->x >> 16), _stompY + (obj->y >> 16),
+ obj->priority);
+ }
+ }
+
+ drawList.add(getAnimation(164)->frameIndices[0], 5, 2, 2000);
+ drawNumber(drawList, _score, 68, 16);
+ drawList.add(getAnimation(166)->frameIndices[0], 230, 2, 2000);
+ drawNumber(drawList, _levelTimeLeft, 280, 16);
+
+ for (int i = 0; i < _stompCount; ++i)
+ drawList.add(getAnimation(130)->frameIndices[0], 20 + i * 30, 230, 2000);
+
+}
+
+void MinigameBbAnt::buildDrawList2(DrawList &drawList) {
+ buildDrawList1(drawList);
+ drawList.add(getAnimation(168)->frameIndices[0], 40, 100, 2000);
+ drawNumber(drawList, _counter1, 190, 112);
+ drawNumber(drawList, _countdown5, 258, 112);
+ drawList.add(getAnimation(169)->frameIndices[0], 120, 120, 2000);
+ drawNumber(drawList, _counter4, 192, 132);
+}
+
+void MinigameBbAnt::buildDrawList3(DrawList &drawList) {
+ buildDrawList1(drawList);
+ drawList.add(getAnimation(163)->frameIndices[0], 120, 70, 2000);
+ drawList.add(getAnimation(165)->frameIndices[0], 95, 95, 2000);
+ drawNumber(drawList, _hiScore, 208, 107);
+}
+
+void MinigameBbAnt::drawMagnifyingGlass(DrawList &drawList) {
+ scale2x(_objects[0].x - 28, _objects[0].y - 27);
+ drawList.clear();
+ drawList.add(_objects[0].anim->frameIndices[0], _objects[0].x, _objects[0].y, _objects[0].priority);
+ drawList.add(_objects[0].anim->frameIndices[1], _objects[0].x, _objects[0].y, _objects[0].priority);
+ drawList.add(_objects[0].anim->frameIndices[2], _objects[0].x, _objects[0].y, _objects[0].priority);
+}
+
+void MinigameBbAnt::drawSprites() {
+ switch (_gameState) {
+ case 0:
+ drawSprites0();
+ break;
+ case 1:
+ drawSprites1();
+ break;
+ case 2:
+ drawSprites2();
+ break;
+ case 3:
+ drawSprites3();
+ break;
+ }
+}
+
+void MinigameBbAnt::drawSprites0() {
+ DrawList drawList;
+ buildDrawList0(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+void MinigameBbAnt::drawSprites1() {
+ DrawList drawList;
+ buildDrawList1(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ drawMagnifyingGlass(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+void MinigameBbAnt::drawSprites2() {
+ DrawList drawList;
+ buildDrawList2(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ drawMagnifyingGlass(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+void MinigameBbAnt::drawSprites3() {
+ DrawList drawList;
+ buildDrawList3(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+MinigameBbAnt::Obj *MinigameBbAnt::getFreeObject() {
+ for (int i = 12; i < kMaxObjectsCount; ++i)
+ if (_objects[i].kind == 0)
+ return &_objects[i];
+ return 0;
+}
+
+void MinigameBbAnt::initObjects() {
+ switch (_gameState) {
+ case 0:
+ initObjects0();
+ break;
+ case 1:
+ initObjects1();
+ break;
+ case 2:
+ case 3:
+ // Nothing
+ break;
+ }
+}
+
+void MinigameBbAnt::initObjects0() {
+ _objects[0].anim = getAnimation(172);
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = getAnimation(172)->frameTicks[0];
+ _objects[0].x = 160;
+ _objects[0].y = 120;
+ _objects[0].priority = 2000;
+ _objects[0].kind = 1;
+ _objects[1].anim = getAnimation(170);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = getAnimation(170)->frameTicks[0];
+ _objects[1].x = 40;
+ _objects[1].y = 240;
+ _objects[1].priority = 100;
+ _objects[1].kind = 2;
+ _objects[2].anim = getAnimation(171);
+ _objects[2].frameIndex = 0;
+ _objects[2].ticks = getAnimation(171)->frameTicks[0];
+ _objects[2].x = 280;
+ _objects[2].y = 240;
+ _objects[2].priority = 100;
+ _objects[2].kind = 2;
+}
+
+void MinigameBbAnt::initObjects1() {
+ _objects[0].kind = 0;
+ _objects[0].x = 160;
+ _objects[0].y = 120;
+ _objects[0].xIncr = 0;
+ _objects[0].yIncr = 0;
+ _objects[0].anim = getAnimation(159);
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = _objects[0].anim->frameTicks[0];
+ _objects[0].priority = 1000;
+ _objects[1].kind = 8;
+ _objects[1].x = 0x1E0000;
+ _objects[1].y = 0x280000;
+ _objects[1].xIncr = 0;
+ _objects[1].yIncr = 0;
+ _objects[1].anim = getAnimation(160);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = _objects[0].anim->frameTicks[0];
+ _objects[1].priority = 900;
+ _objects[1].smokeCtr = 0;
+ _objects[1].hasSmoke = false;
+ _objects[1].status = 0;
+ _objects[2].kind = 8;
+ _objects[2].x = 0x280000;
+ _objects[2].y = 0x4B0000;
+ _objects[2].xIncr = 0;
+ _objects[2].yIncr = 0;
+ _objects[2].anim = getAnimation(161);
+ _objects[2].frameIndex = 0;
+ _objects[2].ticks = _objects[0].anim->frameTicks[0];
+ _objects[2].priority = 900;
+ _objects[2].smokeCtr = 0;
+ _objects[2].hasSmoke = false;
+ _objects[2].status = 0;
+ for (int i = 3; i < 12; ++i) {
+ const ObjInit *objInit = getObjInit(i - 3);
+ _objects[i].kind = 6;
+ _objects[i].x = objInit->x << 16;
+ _objects[i].y = objInit->y << 16;
+ _objects[i].xIncr = 0;
+ _objects[i].yIncr = 0;
+ _objects[i].anim = objInit->anim1;
+ _objects[i].frameIndex = 0;
+ _objects[i].ticks = _objects[0].anim->frameTicks[0];
+ _objects[i].priority = 600;
+ _objects[i].status = 9;
+ _objects[i].damageCtr = 0;
+
+ }
+}
+
+void MinigameBbAnt::initVars() {
+ switch (_gameState) {
+ case 0:
+ // Nothing
+ break;
+ case 1:
+ initVars1();
+ break;
+ case 2:
+ initVars2();
+ break;
+ case 3:
+ initVars3();
+ break;
+ }
+}
+
+void MinigameBbAnt::initVars1() {
+ _stompX = 0;
+ _stompY = 0;
+ _stompDelay1 = 0;
+ _stompCount = 1;
+ _stompCounter1 = 80;
+ _stompCounter2 = 80;
+ _totalBugsCount = 0;
+ _hasLastStompObj = false;
+ _counter1 = 9;
+ _countdown10 = 140;
+ _score = 0;
+ _counter4 = 1;
+ _gameTicks = 0;
+ _skullBugCtr = 500;
+ _levelTimeDelay = 58;
+ _levelTimeLeft = 30;
+ _bugsChanceByKind[0] = 0;
+ _bugsChanceByKind[1] = 20;
+ _bugsChanceByKind[2] = 20;
+ _bugsChanceByKind[3] = 5;
+ _bugsChanceByKind[4] = 7;
+ _bugsCountByKind[0] = 0;
+ _bugsCountByKind[1] = 0;
+ _bugsCountByKind[2] = 0;
+ _bugsCountByKind[3] = 0;
+ _bugsCountByKind[4] = 0;
+ _bugsCountByKind[5] = 0;
+}
+
+void MinigameBbAnt::initVars2() {
+ _countdown4 = 0;
+ _countdown3 = 0;
+ _levelTimeDelay = 58;
+ _countdown6 = 60;
+ _countdown5 = 50 * _counter1;
+}
+
+void MinigameBbAnt::initVars3() {
+ if (_score > _hiScore)
+ _hiScore = _score;
+ playSound(9);
+}
+
+bool MinigameBbAnt::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
+ switch (_gameState) {
+ case 0:
+ return updateStatus0(mouseX, mouseY, mouseButtons);
+ case 1:
+ return updateStatus1(mouseX, mouseY, mouseButtons);
+ case 2:
+ return updateStatus2(mouseX, mouseY, mouseButtons);
+ case 3:
+ return updateStatus3(mouseX, mouseY, mouseButtons);
+ }
+ return false;
+}
+
+bool MinigameBbAnt::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ if (_objects[0].x >= 320)
+ _objects[0].x = 320 - 1;
+ if (_objects[0].y >= 240)
+ _objects[0].y = 240 - 1;
+ if (_objects[0].x < 0)
+ _objects[0].x = 0;
+ if (_objects[0].y < 0)
+ _objects[0].y = 0;
+
+ if ((mouseButtons & kLeftButtonDown) || (mouseButtons & kRightButtonDown)) {
+ _gameState = 1;
+ initObjects();
+ initVars();
+ _gameTicks = 0;
+ playSound(1);
+ } else {
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind == 2) {
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex >= obj->anim->frameCount)
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool MinigameBbAnt::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
+ const int kMaxBugsCount = 52;
+
+ --_levelTimeDelay;
+ if (!_levelTimeDelay) {
+ _levelTimeDelay = 58;
+ --_levelTimeLeft;
+ }
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ if (_objects[0].x >= 320)
+ _objects[0].x = 320 - 1;
+ if (_objects[0].y >= 240)
+ _objects[0].y = 240 - 1;
+ if (_objects[0].x < 0)
+ _objects[0].x = 0;
+ if (_objects[0].y < 0)
+ _objects[0].y = 0;
+
+ if (!_levelTimeLeft) {
+ _gameState = 2;
+ initVars();
+ initObjects();
+ _gameTicks = 0;
+ return true;
+ }
+
+ if (_counter1 == 0) {
+ _gameState = 3;
+ initVars();
+ initObjects();
+ _gameTicks = 0;
+ return true;
+ }
+
+ if ((mouseButtons & kRightButtonClicked) && (_stompCount > 0|| _hasLastStompObj) && !_objects[2].status) {
+ if (_hasLastStompObj)
+ removeStompObj(_lastStompObj);
+ --_stompCount;
+ _objects[2].status = 1;
+ }
+
+ if ((mouseButtons & kLeftButtonClicked) && _objects[2].status == 0 && isMagGlassAtBeavisLeg(2)) {
+ if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
+ playSound(16);
+ insertSmokeObj(_objects[0].x << 16, _objects[0].y << 16);
+ }
+
+ if (_skullBugCtr > 0) {
+ if (--_skullBugCtr == 0) {
+ _skullBugCtr = _vm->getRandom(150) + 500;
+ insertRandomBugObj(5);
+ }
+ }
+
+ if (_stompCounter2 > 0)
+ --_stompCounter2;
+
+ if (_totalBugsCount < kMaxBugsCount && _vm->getRandom(_stompCounter2) == 0) {
+ int testTbl[4];
+ int maxKindCount = 0, objKind = 0;
+
+ _stompCounter2 = _stompCounter1;
+
+ for (int i = 0; i < 4; ++i)
+ testTbl[i] = _vm->getRandom(_bugsChanceByKind[i] - _bugsCountByKind[i]);
+
+ for (int i = 0; i < 4; ++i) {
+ if (testTbl[i] >= maxKindCount) {
+ maxKindCount = testTbl[i];
+ objKind = i + 1;
+ }
+ }
+
+ if (objKind)
+ insertRandomBugObj(objKind);
+
+ }
+
+ updateObjs(mouseButtons);
+ updateFootObj(2);
+
+ if (--_countdown10 == 0) {
+ _countdown10 = 140;
+ if (_stompCounter1 > 20)
+ --_stompCounter1;
+ }
+
+ return true;
+}
+
+bool MinigameBbAnt::updateStatus2(int mouseX, int mouseY, uint mouseButtons) {
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ if (_objects[0].x >= 320)
+ _objects[0].x = 320 - 1;
+ if (_objects[0].y >= 240)
+ _objects[0].y = 240 - 1;
+ if (_objects[0].x < 0)
+ _objects[0].x = 0;
+ if (_objects[0].y < 0)
+ _objects[0].y = 0;
+
+ if (_countdown6 > 0) {
+ if (--_countdown6 == 0) {
+ _countdown4 = 150;
+ playSound(15, true);
+ }
+ } else if (_countdown4 > 0) {
+ if (--_countdown4 == 0) {
+ _countdown3 = 150;
+ } else if (_countdown5 > 0) {
+ ++_countdown4;
+ ++_score;
+ if (--_countdown5 == 0) {
+ stopSound(15);
+ _bugsChanceByKind[5] = 10;
+ _countdown7 = 40;
+ _countdown4 = 10 * (13 - _counter1);
+ return true;
+ }
+ } else {
+ if (--_countdown7 == 0) {
+ bool flag1 = false;
+ _countdown7 = _bugsChanceByKind[5];
+ for (int i = 3; i < 12 && !flag1; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->status == 13) {
+ const ObjInit *objInit = getObjInit(i - 3);
+ obj->x = objInit->x << 16;
+ obj->y = objInit->y << 16;
+ obj->anim = objInit->anim3;
+ obj->frameIndex = 0;
+ obj->ticks = _objects[0].anim->frameTicks[0];
+ obj->status = 9;
+ obj->damageCtr = 0;
+ obj->priority = 600;
+ ++_counter1;
+ playSound(15);
+ flag1 = true;
+ }
+ }
+ }
+ }
+ } else if (_countdown3 > 0) {
+ if ((mouseButtons & kLeftButtonDown) || (mouseButtons & kRightButtonDown) || (--_countdown3 == 0)) {
+ _levelTimeDelay = 58;
+ _levelTimeLeft = 30;
+ _gameState = 1;
+ _gameTicks = 0;
+ ++_counter4;
+ }
+ }
+
+ return true;
+}
+
+bool MinigameBbAnt::updateStatus3(int mouseX, int mouseY, uint mouseButtons) {
+ if (!isSoundPlaying(9) && _fromMainGame) {
+ _vm->_system->delayMillis(1000);
+ _gameDone = true;
+ }
+ return true;
+}
+
+void MinigameBbAnt::getRandomBugObjValues(int &x, int &y, int &animIndexIncr, int &field30) {
+ field30 = _vm->getRandom(4);
+ switch (field30) {
+ case 0:
+ y = -5;
+ x = _vm->getRandom(190) + 120;
+ animIndexIncr = 4;
+ break;
+ case 1:
+ x = 325;
+ y = _vm->getRandom(220) + 10;
+ animIndexIncr = 2;
+ break;
+ case 2:
+ y = 245;
+ x = _vm->getRandom(300) + 10;
+ animIndexIncr = 0;
+ break;
+ case 3:
+ x = -5;
+ y = _vm->getRandom(190) + 120;
+ animIndexIncr = 6;
+ break;
+ }
+}
+
+void MinigameBbAnt::insertBugSmokeObj(int x, int y, int bugObjIndex) {
+ Obj *obj = getFreeObject();
+ if (obj) {
+ Obj *bugObj = &_objects[bugObjIndex];
+ bugObj->hasSmoke = true;
+ obj->kind = 7;
+ obj->x = x;
+ obj->y = y;
+ obj->priority = 950;
+ if (bugObj->status >= 4 && (bugObj->status <= 6 || bugObj->status == 8)) {
+ obj->xIncr = 0;
+ obj->yIncr = (-1 << 16);
+ } else {
+ obj->xIncr = bugObj->xIncr / 8;
+ obj->yIncr = bugObj->yIncr / 8;
+ }
+ obj->anim = getAnimation(158);
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ }
+}
+
+void MinigameBbAnt::insertSmokeObj(int x, int y) {
+ Obj *obj = getFreeObject();
+ if (obj) {
+ obj->kind = 7;
+ obj->x = x;
+ obj->y = y;
+ obj->priority = 950;
+ obj->xIncr = 0x2000;
+ obj->yIncr = -0xC000;
+ obj->anim = getAnimation(158);
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ }
+}
+
+void MinigameBbAnt::resetObj(int objIndex) {
+ _objects[objIndex].kind = 0;
+}
+
+void MinigameBbAnt::insertStompObj(int x, int y) {
+ Obj *obj = getFreeObject();
+ if (obj) {
+ obj->kind = 9;
+ obj->x = x;
+ obj->y = y;
+ obj->priority = 2000;
+ obj->xIncr = (0x1E0000 * _stompCount - x + 0x140000) / 15;
+ obj->yIncr = (0xE60000 - y) / 15;
+ obj->anim = getAnimation(130);
+ obj->frameIndex = 0;
+ obj->ticks = 15;
+ _lastStompObj = obj;
+ _hasLastStompObj = true;
+ }
+}
+
+void MinigameBbAnt::removeStompObj(Obj *obj) {
+ ++_stompCount;
+ _hasLastStompObj = false;
+ obj->kind = 0;
+}
+
+void MinigameBbAnt::insertBugObj(int kind, int animIndexIncr, int always0, int x, int y, int field30, int always1) {
+ Obj *obj = getFreeObject();
+ if (obj) {
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(kind);
+ obj->field30 = field30;
+ obj->animIndexIncr = animIndexIncr;
+ obj->kind = kind;
+ obj->x = x << 16;
+ obj->y = y << 16;
+ obj->priority = 610;
+ obj->xIncr = kPosIncrTbl1[0].x << 16;
+ obj->yIncr = kPosIncrTbl1[0].y << 16;
+ obj->anim = objKindAnimTable[0];
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ obj->animIndex = 0;
+ obj->status = 1;
+ obj->damageCtr = 0;
+ obj->hasSmoke = false;
+ obj->flag = 0;
+ ++_bugsCountByKind[kind];
+ ++_totalBugsCount;
+ }
+}
+
+void MinigameBbAnt::removeBugObj(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+ --_totalBugsCount;
+ --_bugsCountByKind[obj->kind];
+ obj->hasSmoke = false;
+ obj->kind = 0;
+}
+
+void MinigameBbAnt::updateBugObjAnim(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->field30) {
+ case 0:
+ obj->animIndexIncr = 4;
+ break;
+ case 1:
+ obj->animIndexIncr = 2;
+ break;
+ case 2:
+ obj->animIndexIncr = 0;
+ break;
+ case 3:
+ obj->animIndexIncr = 6;
+ break;
+ }
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
+ obj->xIncr = kPosIncrTbl1[obj->animIndexIncr].x << 16;
+ obj->yIncr = kPosIncrTbl1[obj->animIndexIncr].y << 16;
+ obj->anim = objKindAnimTable[obj->animIndexIncr];
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+}
+
+void MinigameBbAnt::updateObjAnim2(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->animIndexIncr += _vm->getRandom(3) - 1;
+ if (obj->animIndexIncr < 0)
+ obj->animIndexIncr = 7;
+ if (obj->animIndexIncr > 7)
+ obj->animIndexIncr = 0;
+ obj->animIndexIncr += 4;
+ if (obj->animIndexIncr >= 8)
+ obj->animIndexIncr %= 8;
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
+ obj->xIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].x << 16;
+ obj->yIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].y << 16;
+ obj->anim = objKindAnimTable[obj->animIndex + obj->animIndexIncr];
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+}
+
+void MinigameBbAnt::insertRandomBugObj(int kind) {
+ int x, y, animIndexIncr, field30;
+ getRandomBugObjValues(x, y, animIndexIncr, field30);
+ insertBugObj(kind, animIndexIncr, 0, x, y, field30, 1);
+}
+
+bool MinigameBbAnt::isBugOutOfScreen(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ return
+ obj->x < (-10 << 16) || obj->x > (330 << 16) ||
+ obj->y < (-10 << 16) || obj->y > (250 << 16);
+}
+
+void MinigameBbAnt::updateObjAnim3(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->animIndexIncr += _vm->getRandom(3) - 1;
+ if (obj->animIndexIncr < 0)
+ obj->animIndexIncr = 7;
+ if (obj->animIndexIncr > 7)
+ obj->animIndexIncr = 0;
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
+ obj->xIncr = kPosIncrTbl1[obj->animIndexIncr].x << 16;
+ obj->yIncr = kPosIncrTbl1[obj->animIndexIncr].y << 16;
+ obj->anim = objKindAnimTable[obj->animIndexIncr];
+}
+
+void MinigameBbAnt::updateBugObj1(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+ bool flag1 = false;
+ bool flag2 = false;
+
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->anim->frameCount == obj->frameIndex) {
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ flag1 = true;
+ } else {
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ flag2 = true;
+ }
+ }
+
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+
+ if (obj->status != 7) {
+ if (obj->damageCtr <= 5) {
+ obj->hasSmoke = false;
+ } else if (!obj->hasSmoke) {
+ obj->smokeCtr = 6;
+ insertBugSmokeObj(obj->x, obj->y, objIndex);
+ } else if (obj->damageCtr > 200 && obj->status != 4 && obj->status != 6) {
+ _score += kScoreTbl[obj->kind];
+ if (obj->status == 3) {
+ _objects[obj->otherObjIndex].status = 9;
+ _objects[obj->otherObjIndex].priority = 600;
+ if (_vm->getRandom(3) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
+ playSound(kSoundTbl3[_vm->getRandom(3)]);
+ } else {
+ if (_vm->getRandom(3) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
+ playSound(kSoundTbl2[_vm->getRandom(3)]);
+ }
+ flag1 = false;
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
+ obj->hasSmoke = false;
+ obj->status = 4;
+ obj->xIncr = 0;
+ obj->yIncr = 0;
+ obj->anim = objKindAnimTable[16];
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ obj->priority = 605;
+ if (obj->kind == 5) {
+ // Skull Beetle
+ if (_stompCount < 10)
+ insertStompObj(obj->x, obj->y);
+ obj->kind = 4;
+ obj->anim = getObjAnim(70);
+ obj->ticks = obj->anim->frameTicks[0];
+ }
+ } else if (--obj->smokeCtr == 0) {
+ obj->smokeCtr = 6;
+ insertBugSmokeObj(obj->x, obj->y, objIndex);
+ }
+ }
+
+ switch (obj->status) {
+
+ case 1:
+ if (isBugOutOfScreen(objIndex))
+ removeBugObj(objIndex);
+ else if (flag1 && !obj->flag)
+ updateObjAnim3(objIndex);
+ break;
+
+ case 3:
+ // Bug carries candy
+ _objects[obj->otherObjIndex].x = obj->x;
+ _objects[obj->otherObjIndex].y = obj->y;
+ if (isBugOutOfScreen(objIndex)) {
+ _objects[obj->otherObjIndex].status = 13;
+ _objects[obj->otherObjIndex].x = (500 << 16);
+ _objects[obj->otherObjIndex].y = (500 << 16);
+ removeBugObj(objIndex);
+ --_counter1;
+ }
+ break;
+
+ case 4:
+ if (flag1) {
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
+ obj->status = 6;
+ obj->xIncr = 0;
+ obj->yIncr = 0;
+ obj->anim = objKindAnimTable[17];
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ }
+ break;
+
+ case 6:
+ if (flag1) {
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(obj->kind);
+ obj->status = 7;
+ obj->xIncr = kPosIncrTbl2[obj->animIndexIncr].x << 16;
+ obj->yIncr = kPosIncrTbl2[obj->animIndexIncr].y << 16;
+ obj->anim = objKindAnimTable[obj->animIndexIncr + 8];
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[0];
+ obj->animIndex = 8;
+ obj->priority = 610;
+ }
+ break;
+
+ case 7:
+ if (isBugOutOfScreen(objIndex))
+ removeBugObj(objIndex);
+ break;
+
+ case 8:
+ if (--obj->counter != 0) {
+ if (flag2 && obj->frameIndex == 13) {
+ obj->frameIndex = 4;
+ obj->ticks = obj->anim->frameTicks[4];
+ }
+ } else {
+ obj->status = obj->status2;
+ obj->anim = obj->anim2;
+ obj->frameIndex = obj->frameIndex2;
+ obj->ticks = obj->ticks2;
+ obj->xIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].x << 16;
+ obj->yIncr = kPosIncrTbl1[obj->animIndex + obj->animIndexIncr].y << 16;
+ obj->priority = 610;
+ }
+ break;
+
+ }
+
+}
+
+void MinigameBbAnt::updateObjKind2(int objIndex) {
+ updateBugObj1(objIndex);
+}
+
+void MinigameBbAnt::updateObjKind3(int objIndex) {
+ updateBugObj1(objIndex);
+}
+
+void MinigameBbAnt::updateObjKind4(int objIndex) {
+ updateBugObj1(objIndex);
+}
+
+void MinigameBbAnt::updateObjKind5(int objIndex) {
+ ++_skullBugCtr;
+ updateBugObj1(objIndex);
+}
+
+void MinigameBbAnt::updateStompObj(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+ if (--obj->ticks == 0)
+ removeStompObj(obj);
+}
+
+void MinigameBbAnt::updateSmokeObj(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->anim->frameCount == obj->frameIndex)
+ resetObj(objIndex);
+ else
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+}
+
+void MinigameBbAnt::updateFootObj(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->status) {
+
+ case 1:
+ obj->xIncr = -0x8000;
+ obj->yIncr = (-4 << 16);
+ obj->status = 2;
+ _stompCounter1 += 5;
+ _stompCounter2 = 100;
+ break;
+
+ case 2:
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+ obj->yIncr += 0x2000;
+ if (obj->y < (20 << 16)) {
+ obj->xIncr = 0x8000;
+ obj->yIncr = (7 << 16);
+ obj->status = 3;
+ }
+ break;
+
+ case 3:
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+ obj->yIncr += 0x2000;
+ if (obj->y >= 0x4B0000) {
+ obj->x = (40 << 16);
+ obj->y = (75 << 16);
+ obj->status = 4;
+ _stompDelay1 = 6;
+ _stompY = 0;
+ playSound(14);
+ }
+ break;
+
+ case 4:
+ if (--_stompDelay1 == 0) {
+ _gameTicks = 0;
+ if (_stompDelay1 % 2)
+ _stompY = _stompY < 1 ? -8 : 0;
+ } else {
+ obj->status = 0;
+ _stompX = 0;
+ _stompY = 0;
+ // Stun all bugs
+ for (int i = 12; i < kMaxObjectsCount; ++i) {
+ Obj *bugObj = &_objects[i];
+ if (bugObj->kind >= 1 && bugObj->kind <= 5) {
+ bugObj->counter = _vm->getRandom(200) + 360;
+ const ObjAnimation * const *objKindAnimTable = getObjKindAnimTable(bugObj->kind);
+ if (bugObj->status == 8) {
+ bugObj->hasSmoke = false;
+ bugObj->xIncr = 0;
+ bugObj->yIncr = 0;
+ bugObj->status2 = 7;
+ bugObj->anim2 = objKindAnimTable[bugObj->animIndexIncr + 8];
+ bugObj->frameIndex2 = 0;
+ bugObj->ticks2 = obj->anim->frameTicks[0];
+ bugObj->anim = objKindAnimTable[17];
+ bugObj->frameIndex = 0;
+ bugObj->ticks = _vm->getRandom(4) + obj->anim->frameTicks[0];
+ bugObj->animIndex = 8;
+ } else {
+ if (bugObj->status == 3) {
+ bugObj->priority = 610;
+ _objects[bugObj->otherObjIndex].status = 9;
+ _objects[bugObj->otherObjIndex].priority = 600;
+ }
+ bugObj->hasSmoke = false;
+ bugObj->xIncr = 0;
+ bugObj->yIncr = 0;
+ bugObj->status2 = 1;
+ bugObj->anim2 = bugObj->anim;
+ bugObj->frameIndex2 = bugObj->frameIndex;
+ bugObj->ticks2 = bugObj->ticks;
+ bugObj->anim = objKindAnimTable[17];
+ bugObj->frameIndex = 0;
+ bugObj->ticks = _vm->getRandom(4) + obj->anim->frameTicks[0];
+ }
+ bugObj->status = 8;
+ bugObj->priority = 605;
+ }
+ }
+ }
+ break;
+
+ }
+
+}
+
+bool MinigameBbAnt::isBugAtCandy(int objIndex, int &candyObjIndex) {
+ Obj *obj = &_objects[objIndex];
+ bool result = false;
+
+ if (obj->kind >= 1 && obj->kind <= 4) {
+ const BBRect &frameRect1 = obj->anim->frameRects[obj->frameIndex];
+ const int obj1X1 = frameRect1.x + (obj->x >> 16);
+ const int obj1Y1 = frameRect1.y + (obj->y >> 16);
+ const int obj1X2 = obj1X1 + frameRect1.width;
+ const int obj1Y2 = obj1Y1 + frameRect1.height;
+ for (int i = 3; i < 12 && !result; ++i) {
+ Obj *obj2 = &_objects[i];
+ const BBRect &frameRect2 = obj->anim->frameRects[obj2->frameIndex]; // sic
+ const int obj2X1 = (obj2->x >> 16) + frameRect2.x;
+ const int obj2Y1 = (obj2->y >> 16) + frameRect2.y;
+ const int obj2X2 = obj2X1 + frameRect2.width;
+ const int obj2Y2 = obj2Y1 + frameRect2.height;
+ if (obj2->status == 9 && obj1X1 <= obj2X2 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1) {
+ result = true;
+ candyObjIndex = i;
+ }
+ }
+ }
+ return result;
+}
+
+bool MinigameBbAnt::isMagGlassAtBug(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+ Obj *obj0 = &_objects[0];
+ bool result = false;
+
+ if (obj->kind >= 1 && obj->kind <= 5) {
+ const BBRect &frameRect1 = obj0->anim->frameRects[0];
+ const int obj1X1 = obj0->x + frameRect1.x;
+ const int obj1Y1 = obj0->y + frameRect1.y;
+ const int obj1X2 = obj1X1 + frameRect1.width;
+ const int obj1Y2 = obj1Y1 + frameRect1.height;
+ const BBRect &frameRect2 = obj->anim->frameRects[obj->frameIndex];
+ const int obj2X1 = (obj->x >> 16) + frameRect2.x;
+ const int obj2Y1 = (obj->y >> 16) + frameRect2.y;
+ const int obj2X2 = obj2X1 + frameRect2.width;
+ const int obj2Y2 = obj2Y1 + frameRect2.height;
+ if (obj2X2 >= obj1X1 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1)
+ result = true;
+ }
+ return result;
+}
+
+bool MinigameBbAnt::isMagGlassAtBeavisLeg(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+ Obj *magGlassObj = &_objects[0];
+ bool result = false;
+
+ const BBRect &frameRect1 = magGlassObj->anim->frameRects[0];
+ const int obj1X1 = magGlassObj->x + frameRect1.x;
+ const int obj1Y1 = magGlassObj->y + frameRect1.y;
+ const int obj1X2 = obj1X1 + frameRect1.width;
+ const int obj1Y2 = obj1Y1 + frameRect1.height;
+ const BBRect &frameRect2 = obj->anim->frameRects[obj->frameIndex];
+ const int obj2X1 = (obj->x >> 16) + frameRect2.x;
+ const int obj2Y1 = (obj->y >> 16) + frameRect2.y;
+ const int obj2X2 = obj2X1 + frameRect2.width;
+ const int obj2Y2 = obj2Y1 + frameRect2.height;
+ if (obj2X2 >= obj1X1 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1)
+ result = true;
+ return result;
+}
+
+bool MinigameBbAnt::testObj5(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+ bool result = false;
+ if (obj->kind >= 1 && obj->kind <= 5) {
+ const int x = obj->x >> 16;
+ const int y = obj->y >> 16;
+ if (x < 0 || x >= 110 || y < 0 || y >= 110) {
+ obj->flag = 0;
+ } else if (!obj->flag) {
+ obj->flag = 1;
+ result = true;
+ }
+ }
+ return result;
+}
+
+void MinigameBbAnt::updateObjs(uint mouseButtons) {
+
+ for (int i = 12; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+
+ if (obj->kind) {
+
+ if ((mouseButtons & kLeftButtonClicked) && isMagGlassAtBug(i))
+ obj->damageCtr += 100;
+
+ if (obj->status == 1) {
+ int candyObjIndex;
+ if (isBugAtCandy(i, candyObjIndex)) {
+ obj->status = 3;
+ obj->otherObjIndex = candyObjIndex;
+ _objects[candyObjIndex].otherObjIndex = i;
+ _objects[candyObjIndex].status = 10;
+ _objects[candyObjIndex].priority = 620;
+ _objects[candyObjIndex].status = 11;
+ _objects[candyObjIndex].anim = getObjInit(candyObjIndex - 3)->anim3;
+ updateBugObjAnim(i);
+ if (_vm->getRandom(3) == 1 && !isAnySoundPlaying(kSoundTbl4, 10))
+ playSound(kSoundTbl1[_vm->getRandom(4)]);
+ }
+ }
+
+ if (testObj5(i)) {
+ updateObjAnim2(i);
+ }
+
+ if (obj->damageCtr) {
+ --obj->damageCtr;
+ if (!isSoundPlaying(13))
+ playSound(13);
+ }
+
+ switch (obj->kind) {
+ case 1:
+ updateBugObj1(i);
+ break;
+ case 2:
+ updateObjKind2(i);
+ break;
+ case 3:
+ updateObjKind3(i);
+ break;
+ case 4:
+ updateObjKind4(i);
+ break;
+ case 5:
+ updateObjKind5(i);
+ break;
+ case 7:
+ updateSmokeObj(i);
+ break;
+ case 9:
+ updateStompObj(i);
+ break;
+ }
+
+ }
+
+ }
+
+}
+
+int MinigameBbAnt::run(bool fromMainGame) {
+
+ memset(_objects, 0, sizeof(_objects));
+
+ _numbersAnim = getAnimation(167);
+
+ _backgroundSpriteIndex = 303;
+ _titleScreenSpriteIndex = 304;
+
+ _fromMainGame = fromMainGame;
+
+ _hiScore = 0;
+ if (!_fromMainGame)
+ _hiScore = loadHiscore(kMinigameBbAnt);
+
+ _gameState = 0;
+ _gameResult = 0;
+ _gameDone = false;
+ initObjects();
+ initVars();
+
+ _spriteModule = new SpriteModule();
+ _spriteModule->load("bbant/bbant.000");
+
+ Palette palette = _spriteModule->getPalette();
+ _vm->_screen->setPalette(palette);
+
+ loadSounds();
+
+ _gameTicks = 0;
+ playSound(12, true);
+
+ while (!_vm->shouldQuit() &&!_gameDone) {
+ _vm->updateEvents();
+ update();
+ }
+
+ _vm->_sound->unloadSounds();
+
+ if (!_fromMainGame)
+ saveHiscore(kMinigameBbAnt, _hiScore);
+
+ delete _spriteModule;
+
+ return _gameResult;
+}
+
+void MinigameBbAnt::update() {
+
+ int currTicks, inputTicks;
+
+ if (_gameTicks > 0) {
+ currTicks = _vm->_system->getMillis();
+ inputTicks = 3 * (currTicks - _gameTicks) / 50;
+ _gameTicks = currTicks - (currTicks - _gameTicks - 50 * inputTicks / 3);
+ } else {
+ inputTicks = 1;
+ _gameTicks = _vm->_system->getMillis();
+ }
+
+ if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
+ _gameDone = true;
+ return;
+ }
+
+ if (inputTicks == 0)
+ return;
+
+ bool done;
+
+ do {
+ done = !updateStatus(_vm->_mouseX, _vm->_mouseY, _vm->_mouseButtons);
+ _vm->_mouseButtons &= ~kLeftButtonClicked;
+ _vm->_mouseButtons &= ~kRightButtonClicked;
+ _vm->_keyCode = Common::KEYCODE_INVALID;
+ } while (--inputTicks && _gameTicks > 0 && !done);
+
+ drawSprites();
+
+ _vm->_system->delayMillis(10);
+
+}
+
+void MinigameBbAnt::scale2x(int x, int y) {
+ Graphics::Surface *surface = _vm->_screen->_surface;
+
+ int srcX = x + 14, srcY = y + 14;
+ int srcW = kScaleDim, srcH = kScaleDim;
+
+ if (srcX < 0) {
+ srcW += srcX;
+ srcX = 0;
+ }
+
+ if (srcY < 0) {
+ srcH += srcY;
+ srcY = 0;
+ }
+
+ if (srcX + srcW >= 320)
+ srcW = 320 - srcX - 1;
+
+ if (srcY + srcH >= 240)
+ srcH = 240 - srcY - 1;
+
+ for (int yc = 0; yc < srcH; ++yc) {
+ byte *src = (byte*)surface->getBasePtr(srcX, srcY + yc);
+ memcpy(&_scaleBuf[yc * kScaleDim], src, srcW);
+ }
+
+ int dstX = x, dstY = y;
+ int dstW = 2 * kScaleDim, dstH = 2 * kScaleDim;
+
+ if (dstX < 0) {
+ dstW += dstX;
+ dstX = 0;
+ }
+
+ if (dstY < 0) {
+ dstH += dstY;
+ dstY = 0;
+ }
+
+ if (dstX + dstW >= 320)
+ dstW = 320 - dstX - 1;
+
+ if (dstY + dstH >= 240)
+ dstH = 240 - dstY - 1;
+
+ int w = MIN(srcW * 2, dstW), h = MIN(srcH * 2, dstH);
+
+ for (int yc = 0; yc < h; ++yc) {
+ byte *src = _scaleBuf + kScaleDim * (yc / 2);
+ byte *dst = (byte*)surface->getBasePtr(dstX, dstY + yc);
+ for (int xc = 0; xc < w; ++xc)
+ dst[xc] = src[xc / 2];
+ }
+
+}
+
+void MinigameBbAnt::loadSounds() {
+ for (uint i = 0; i < kSoundFilenamesCount; ++i) {
+ Common::String filename = Common::String::format("bbant/%s", kSoundFilenames[i]);
+ _vm->_sound->loadSound(filename.c_str());
+ }
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbant.h b/engines/bbvs/minigames/bbant.h
new file mode 100644
index 0000000000..b9ead3a87b
--- /dev/null
+++ b/engines/bbvs/minigames/bbant.h
@@ -0,0 +1,173 @@
+/* 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 BBVS_MINIGAMES_BBANT_H
+#define BBVS_MINIGAMES_BBANT_H
+
+#include "bbvs/minigames/minigame.h"
+
+namespace Bbvs {
+
+class MinigameBbAnt : public Minigame {
+public:
+ MinigameBbAnt(BbvsEngine *vm) : Minigame(vm) {};
+ int run(bool fromMainGame);
+public:
+
+ struct Obj {
+ int kind;
+ int x, y, priority;
+ int xIncr, yIncr;
+ const ObjAnimation *anim;
+ int frameIndex;
+ int ticks;
+ int otherObjIndex;
+ int animIndex;
+ int animIndexIncr;
+ int status;
+ int field30;
+ int damageCtr;
+ int smokeCtr;
+ int counter;
+ int hasSmoke;
+ const ObjAnimation *anim2;
+ int frameIndex2;
+ int ticks2;
+ int status2;
+ int flag;
+ };
+
+ enum {
+ kMaxObjectsCount = 256,
+ kScaleDim = 28
+ };
+
+ struct ObjInit {
+ const ObjAnimation *anim1;
+ const ObjAnimation *anim2;
+ const ObjAnimation *anim3;
+ int x, y;
+ };
+
+ Obj _objects[kMaxObjectsCount];
+
+ int _score, _hiScore;
+
+ int _totalBugsCount;
+ int _bugsChanceByKind[6], _bugsCountByKind[6];
+ int _skullBugCtr;
+
+ int _stompX, _stompY;
+ int _stompDelay1;
+ int _stompCounter1;
+ int _stompCounter2;
+
+ int _stompCount;
+ int _hasLastStompObj;
+ Obj *_lastStompObj;
+
+ int _counter1;
+ int _countdown10;
+ int _counter4;
+ int _levelTimeDelay;
+ int _levelTimeLeft;
+
+ int _countdown4;
+ int _countdown3;
+ int _countdown6;
+ int _countdown5;
+ int _countdown7;
+
+ byte _scaleBuf[kScaleDim * kScaleDim];
+
+ const ObjAnimation *getAnimation(int animIndex);
+ const ObjInit *getObjInit(int index);
+ const ObjAnimation * const *getObjKindAnimTable(int kind);
+ const ObjAnimation *getObjAnim(int index);
+
+ void buildDrawList0(DrawList &drawList);
+ void buildDrawList1(DrawList &drawList);
+ void buildDrawList2(DrawList &drawList);
+ void buildDrawList3(DrawList &drawList);
+ void drawMagnifyingGlass(DrawList &drawList);
+
+ void drawSprites();
+ void drawSprites0();
+ void drawSprites1();
+ void drawSprites2();
+ void drawSprites3();
+
+ Obj *getFreeObject();
+
+ void initObjects();
+ void initObjects0();
+ void initObjects1();
+
+ void initVars();
+ void initVars1();
+ void initVars2();
+ void initVars3();
+
+ bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus2(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus3(int mouseX, int mouseY, uint mouseButtons);
+
+ void getRandomBugObjValues(int &x, int &y, int &animIndexIncr, int &field30);
+ void insertBugSmokeObj(int x, int y, int bugObjIndex);
+ void insertSmokeObj(int x, int y);
+ void resetObj(int objIndex);
+ void insertStompObj(int x, int y);
+ void removeStompObj(Obj *obj);
+ void insertBugObj(int kind, int animIndexIncr, int always0, int x, int y, int field30, int always1);
+ void removeBugObj(int objIndex);
+ void updateBugObjAnim(int objIndex);
+ void updateObjAnim2(int objIndex);
+ void insertRandomBugObj(int kind);
+ bool isBugOutOfScreen(int objIndex);
+ void updateObjAnim3(int objIndex);
+ void updateBugObj1(int objIndex);
+ void updateObjKind2(int objIndex);
+ void updateObjKind3(int objIndex);
+ void updateObjKind4(int objIndex);
+ void updateObjKind5(int objIndex);
+ void updateStompObj(int objIndex);
+ void updateSmokeObj(int objIndex);
+ void updateFootObj(int objIndex);
+ bool isBugAtCandy(int objIndex, int &candyObjIndex);
+ bool isMagGlassAtBug(int objIndex);
+ bool isMagGlassAtBeavisLeg(int objIndex);
+ bool testObj5(int objIndex);
+ void updateObjs(uint mouseButtons);
+
+ void update();
+
+ void scale2x(int x, int y);
+
+ void loadSounds();
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_MINIGAMES_BBANT_H
diff --git a/engines/bbvs/minigames/bbant_anims.cpp b/engines/bbvs/minigames/bbant_anims.cpp
new file mode 100644
index 0000000000..c9223adca1
--- /dev/null
+++ b/engines/bbvs/minigames/bbant_anims.cpp
@@ -0,0 +1,757 @@
+/* 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 "bbvs/minigames/bbant.h"
+
+namespace Bbvs {
+
+static const int kAnim0FrameIndices[] = {0, 1, 2};
+static const int16 kAnim0FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim0FrameRects[] = {{-3, -8, 6, 14}, {-3, -8, 6, 13}, {-3, -7, 6, 12}};
+static const int kAnim1FrameIndices[] = {3, 4, 5};
+static const int16 kAnim1FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim1FrameRects[] = {{-5, -6, 13, 9}, {-5, -6, 13, 10}, {-5, -6, 13, 10}};
+static const int kAnim2FrameIndices[] = {6, 7, 8};
+static const int16 kAnim2FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim2FrameRects[] = {{-6, -6, 17, 7}, {-6, -6, 15, 6}, {-7, -6, 17, 6}};
+static const int kAnim3FrameIndices[] = {9, 10, 11};
+static const int16 kAnim3FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim3FrameRects[] = {{-5, -7, 13, 8}, {-5, -7, 12, 7}, {-5, -7, 12, 9}};
+static const int kAnim4FrameIndices[] = {12, 13, 14};
+static const int16 kAnim4FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim4FrameRects[] = {{-3, -9, 7, 11}, {-3, -9, 7, 11}, {-3, -9, 7, 11}};
+static const int kAnim5FrameIndices[] = {15, 16, 17};
+static const int16 kAnim5FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim5FrameRects[] = {{-7, -8, 13, 9}, {-7, -7, 13, 8}, {-7, -7, 13, 8}};
+static const int kAnim6FrameIndices[] = {18, 19, 20};
+static const int16 kAnim6FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim6FrameRects[] = {{-10, -6, 17, 7}, {-11, -6, 18, 7}, {-11, -6, 18, 6}};
+static const int kAnim7FrameIndices[] = {21, 22, 23};
+static const int16 kAnim7FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim7FrameRects[] = {{-7, -6, 13, 8}, {-7, -7, 12, 9}, {-7, -7, 13, 9}};
+static const int kAnim8FrameIndices[] = {24};
+static const int16 kAnim8FrameTicks[] = {8};
+static const BBRect kAnim8FrameRects[] = {{-3, -9, 6, 12}};
+static const int kAnim9FrameIndices[] = {25};
+static const int16 kAnim9FrameTicks[] = {8};
+static const BBRect kAnim9FrameRects[] = {{-5, -6, 12, 7}};
+static const int kAnim10FrameIndices[] = {26};
+static const int16 kAnim10FrameTicks[] = {8};
+static const BBRect kAnim10FrameRects[] = {{-4, -6, 13, 6}};
+static const int kAnim11FrameIndices[] = {27};
+static const int16 kAnim11FrameTicks[] = {8};
+static const BBRect kAnim11FrameRects[] = {{-5, -7, 11, 8}};
+static const int kAnim12FrameIndices[] = {28};
+static const int16 kAnim12FrameTicks[] = {8};
+static const BBRect kAnim12FrameRects[] = {{-2, -10, 5, 12}};
+static const int kAnim13FrameIndices[] = {29};
+static const int16 kAnim13FrameTicks[] = {8};
+static const BBRect kAnim13FrameRects[] = {{-6, -8, 13, 9}};
+static const int kAnim14FrameIndices[] = {30};
+static const int16 kAnim14FrameTicks[] = {8};
+static const BBRect kAnim14FrameRects[] = {{-8, -6, 13, 6}};
+static const int kAnim15FrameIndices[] = {31};
+static const int16 kAnim15FrameTicks[] = {8};
+static const BBRect kAnim15FrameRects[] = {{-7, -7, 12, 8}};
+static const int kAnim16FrameIndices[] = {0, 1, 2};
+static const int16 kAnim16FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim16FrameRects[] = {{-3, -8, 6, 14}, {-3, -8, 6, 13}, {-3, -7, 6, 12}};
+static const int kAnim17FrameIndices[] = {3, 4, 5};
+static const int16 kAnim17FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim17FrameRects[] = {{-5, -6, 13, 9}, {-5, -6, 13, 10}, {-5, -6, 13, 10}};
+static const int kAnim18FrameIndices[] = {6, 7, 8};
+static const int16 kAnim18FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim18FrameRects[] = {{-6, -6, 17, 7}, {-6, -6, 15, 6}, {-7, -6, 17, 6}};
+static const int kAnim19FrameIndices[] = {9, 10, 11};
+static const int16 kAnim19FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim19FrameRects[] = {{-5, -7, 13, 8}, {-5, -7, 12, 7}, {-5, -7, 12, 9}};
+static const int kAnim20FrameIndices[] = {12, 13, 14};
+static const int16 kAnim20FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim20FrameRects[] = {{-3, -9, 7, 11}, {-3, -9, 7, 11}, {-3, -9, 7, 11}};
+static const int kAnim21FrameIndices[] = {15, 16, 17};
+static const int16 kAnim21FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim21FrameRects[] = {{-7, -8, 13, 9}, {-7, -7, 13, 8}, {-7, -7, 13, 8}};
+static const int kAnim22FrameIndices[] = {18, 19, 20};
+static const int16 kAnim22FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim22FrameRects[] = {{-10, -6, 17, 7}, {-11, -6, 18, 7}, {-11, -6, 18, 6}};
+static const int kAnim23FrameIndices[] = {21, 22, 23};
+static const int16 kAnim23FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim23FrameRects[] = {{-7, -6, 13, 8}, {-7, -7, 12, 9}, {-7, -7, 13, 9}};
+static const int kAnim24FrameIndices[] = {32, 33, 34, 35, 36, 37, 36, 37, 36, 37, 36, 37, 36, 38};
+static const int16 kAnim24FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim24FrameRects[] = {{-3, -14, 12, 10}, {-2, -21, 11, 11}, {0, -23, 8, 14}, {-6, -15, 13, 11}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 5}};
+static const int kAnim25FrameIndices[] = {39, 40, 41, 42, 43, 44, 43, 44, 43, 44, 43, 44, 43, 45};
+static const int16 kAnim25FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim25FrameRects[] = {{-9, -14, 13, 10}, {-8, -22, 12, 12}, {-8, -24, 8, 15}, {-7, -15, 13, 10}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}};
+static const int kAnim26FrameIndices[] = {46, 47, 48};
+static const int16 kAnim26FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim26FrameRects[] = {{-3, -8, 6, 14}, {-3, -8, 6, 13}, {-3, -7, 6, 12}};
+static const int kAnim27FrameIndices[] = {49, 50, 51};
+static const int16 kAnim27FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim27FrameRects[] = {{-5, -6, 13, 9}, {-5, -6, 13, 10}, {-5, -6, 13, 10}};
+static const int kAnim28FrameIndices[] = {52, 53, 54};
+static const int16 kAnim28FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim28FrameRects[] = {{-6, -6, 17, 7}, {-6, -6, 15, 6}, {-7, -6, 17, 6}};
+static const int kAnim29FrameIndices[] = {55, 56, 57};
+static const int16 kAnim29FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim29FrameRects[] = {{-5, -7, 13, 8}, {-5, -7, 12, 7}, {-5, -7, 12, 9}};
+static const int kAnim30FrameIndices[] = {58, 59, 60};
+static const int16 kAnim30FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim30FrameRects[] = {{-3, -9, 7, 11}, {-3, -9, 7, 11}, {-3, -9, 7, 11}};
+static const int kAnim31FrameIndices[] = {61, 62, 63};
+static const int16 kAnim31FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim31FrameRects[] = {{-7, -8, 13, 9}, {-7, -7, 13, 8}, {-7, -7, 13, 8}};
+static const int kAnim32FrameIndices[] = {64, 65, 66};
+static const int16 kAnim32FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim32FrameRects[] = {{-10, -6, 17, 7}, {-11, -6, 18, 7}, {-11, -6, 18, 6}};
+static const int kAnim33FrameIndices[] = {67, 68, 69};
+static const int16 kAnim33FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim33FrameRects[] = {{-7, -6, 13, 8}, {-7, -7, 12, 9}, {-7, -7, 13, 9}};
+static const int kAnim34FrameIndices[] = {70};
+static const int16 kAnim34FrameTicks[] = {8};
+static const BBRect kAnim34FrameRects[] = {{-3, -9, 6, 12}};
+static const int kAnim35FrameIndices[] = {71};
+static const int16 kAnim35FrameTicks[] = {8};
+static const BBRect kAnim35FrameRects[] = {{-5, -6, 12, 7}};
+static const int kAnim36FrameIndices[] = {72};
+static const int16 kAnim36FrameTicks[] = {8};
+static const BBRect kAnim36FrameRects[] = {{-4, -6, 13, 6}};
+static const int kAnim37FrameIndices[] = {73};
+static const int16 kAnim37FrameTicks[] = {8};
+static const BBRect kAnim37FrameRects[] = {{-5, -7, 11, 8}};
+static const int kAnim38FrameIndices[] = {74};
+static const int16 kAnim38FrameTicks[] = {8};
+static const BBRect kAnim38FrameRects[] = {{-2, -10, 5, 12}};
+static const int kAnim39FrameIndices[] = {75};
+static const int16 kAnim39FrameTicks[] = {8};
+static const BBRect kAnim39FrameRects[] = {{-6, -8, 13, 9}};
+static const int kAnim40FrameIndices[] = {76};
+static const int16 kAnim40FrameTicks[] = {8};
+static const BBRect kAnim40FrameRects[] = {{-8, -6, 13, 6}};
+static const int kAnim41FrameIndices[] = {77};
+static const int16 kAnim41FrameTicks[] = {8};
+static const BBRect kAnim41FrameRects[] = {{-7, -7, 12, 8}};
+static const int kAnim42FrameIndices[] = {46, 47, 48};
+static const int16 kAnim42FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim42FrameRects[] = {{-3, -8, 6, 14}, {-3, -8, 6, 13}, {-3, -7, 6, 12}};
+static const int kAnim43FrameIndices[] = {49, 50, 51};
+static const int16 kAnim43FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim43FrameRects[] = {{-5, -6, 13, 9}, {-5, -6, 13, 10}, {-5, -6, 13, 10}};
+static const int kAnim44FrameIndices[] = {52, 53, 54};
+static const int16 kAnim44FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim44FrameRects[] = {{-6, -6, 17, 7}, {-6, -6, 15, 6}, {-7, -6, 17, 6}};
+static const int kAnim45FrameIndices[] = {55, 56, 57};
+static const int16 kAnim45FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim45FrameRects[] = {{-5, -7, 13, 8}, {-5, -7, 12, 7}, {-5, -7, 12, 9}};
+static const int kAnim46FrameIndices[] = {58, 59, 60};
+static const int16 kAnim46FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim46FrameRects[] = {{-3, -9, 7, 11}, {-3, -9, 7, 11}, {-3, -9, 7, 11}};
+static const int kAnim47FrameIndices[] = {61, 62, 63};
+static const int16 kAnim47FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim47FrameRects[] = {{-7, -8, 13, 9}, {-7, -7, 13, 8}, {-7, -7, 13, 8}};
+static const int kAnim48FrameIndices[] = {64, 65, 66};
+static const int16 kAnim48FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim48FrameRects[] = {{-10, -6, 17, 7}, {-11, -6, 18, 7}, {-11, -6, 18, 6}};
+static const int kAnim49FrameIndices[] = {67, 68, 69};
+static const int16 kAnim49FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim49FrameRects[] = {{-7, -6, 13, 8}, {-7, -7, 12, 9}, {-7, -7, 13, 9}};
+static const int kAnim50FrameIndices[] = {78, 79, 80, 81, 82, 83, 82, 83, 82, 83, 82, 83, 82, 84};
+static const int16 kAnim50FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim50FrameRects[] = {{-3, -14, 12, 10}, {-2, -21, 11, 11}, {0, -23, 8, 14}, {-6, -15, 13, 11}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 6}, {-8, -4, 15, 5}, {-9, -4, 16, 5}};
+static const int kAnim51FrameIndices[] = {85, 86, 87, 88, 89, 90, 89, 90, 89, 90, 89, 90, 89, 91};
+static const int16 kAnim51FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim51FrameRects[] = {{-9, -14, 13, 10}, {-8, -22, 12, 12}, {-8, -24, 8, 15}, {-7, -15, 13, 10}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}, {-6, -4, 15, 7}, {-7, -4, 16, 6}};
+static const int kAnim52FrameIndices[] = {92, 93, 94};
+static const int16 kAnim52FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim52FrameRects[] = {{-6, -14, 13, 24}, {-7, -13, 14, 23}, {-6, -13, 12, 22}};
+static const int kAnim53FrameIndices[] = {95, 96, 97};
+static const int16 kAnim53FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim53FrameRects[] = {{-4, -12, 19, 17}, {-3, -12, 18, 18}, {-2, -12, 17, 18}};
+static const int kAnim54FrameIndices[] = {98, 99, 100};
+static const int16 kAnim54FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim54FrameRects[] = {{-6, -16, 23, 14}, {-6, -15, 24, 13}, {-7, -15, 25, 14}};
+static const int kAnim55FrameIndices[] = {101, 102, 103};
+static const int16 kAnim55FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim55FrameRects[] = {{-4, -22, 16, 20}, {-3, -23, 14, 22}, {-4, -23, 14, 22}};
+static const int kAnim56FrameIndices[] = {104, 105, 106};
+static const int16 kAnim56FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim56FrameRects[] = {{-5, -24, 11, 23}, {-5, -25, 11, 25}, {-5, -25, 11, 26}};
+static const int kAnim57FrameIndices[] = {107, 108, 109};
+static const int16 kAnim57FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim57FrameRects[] = {{-10, -23, 15, 21}, {-11, -22, 16, 20}, {-11, -23, 17, 21}};
+static const int kAnim58FrameIndices[] = {110, 111, 112};
+static const int16 kAnim58FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim58FrameRects[] = {{-17, -15, 25, 15}, {-17, -15, 25, 14}, {-17, -15, 25, 14}};
+static const int kAnim59FrameIndices[] = {113, 114, 115};
+static const int16 kAnim59FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim59FrameRects[] = {{-14, -12, 20, 17}, {-14, -13, 19, 18}, {-14, -13, 19, 18}};
+static const int kAnim60FrameIndices[] = {116};
+static const int16 kAnim60FrameTicks[] = {6};
+static const BBRect kAnim60FrameRects[] = {{-6, -12, 12, 23}};
+static const int kAnim61FrameIndices[] = {117};
+static const int16 kAnim61FrameTicks[] = {6};
+static const BBRect kAnim61FrameRects[] = {{-5, -11, 20, 19}};
+static const int kAnim62FrameIndices[] = {118};
+static const int16 kAnim62FrameTicks[] = {6};
+static const BBRect kAnim62FrameRects[] = {{-8, -14, 27, 15}};
+static const int kAnim63FrameIndices[] = {119};
+static const int16 kAnim63FrameTicks[] = {6};
+static const BBRect kAnim63FrameRects[] = {{-4, -22, 17, 20}};
+static const int kAnim64FrameIndices[] = {120};
+static const int16 kAnim64FrameTicks[] = {6};
+static const BBRect kAnim64FrameRects[] = {{-6, -25, 13, 25}};
+static const int kAnim65FrameIndices[] = {121};
+static const int16 kAnim65FrameTicks[] = {6};
+static const BBRect kAnim65FrameRects[] = {{-11, -23, 17, 23}};
+static const int kAnim66FrameIndices[] = {122};
+static const int16 kAnim66FrameTicks[] = {6};
+static const BBRect kAnim66FrameRects[] = {{-18, -13, 29, 13}};
+static const int kAnim67FrameIndices[] = {123};
+static const int16 kAnim67FrameTicks[] = {6};
+static const BBRect kAnim67FrameRects[] = {{-14, -12, 21, 19}};
+static const int kAnim68FrameIndices[] = {92, 93, 94};
+static const int16 kAnim68FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim68FrameRects[] = {{-6, -14, 13, 24}, {-7, -13, 14, 23}, {-6, -13, 12, 22}};
+static const int kAnim69FrameIndices[] = {95, 96, 97};
+static const int16 kAnim69FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim69FrameRects[] = {{-4, -12, 19, 17}, {-3, -12, 18, 18}, {-2, -12, 17, 18}};
+static const int kAnim70FrameIndices[] = {98, 99, 100};
+static const int16 kAnim70FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim70FrameRects[] = {{-6, -16, 23, 14}, {-6, -15, 24, 13}, {-7, -15, 25, 14}};
+static const int kAnim71FrameIndices[] = {101, 102, 103};
+static const int16 kAnim71FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim71FrameRects[] = {{-4, -22, 16, 20}, {-3, -23, 14, 22}, {-4, -23, 14, 22}};
+static const int kAnim72FrameIndices[] = {104, 105, 106};
+static const int16 kAnim72FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim72FrameRects[] = {{-5, -24, 11, 23}, {-5, -25, 11, 25}, {-5, -25, 11, 26}};
+static const int kAnim73FrameIndices[] = {107, 108, 109};
+static const int16 kAnim73FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim73FrameRects[] = {{-10, -23, 15, 21}, {-11, -22, 16, 20}, {-11, -23, 17, 21}};
+static const int kAnim74FrameIndices[] = {110, 111, 112};
+static const int16 kAnim74FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim74FrameRects[] = {{-17, -15, 25, 15}, {-17, -15, 25, 14}, {-17, -15, 25, 14}};
+static const int kAnim75FrameIndices[] = {113, 114, 115};
+static const int16 kAnim75FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim75FrameRects[] = {{-14, -12, 20, 17}, {-14, -13, 19, 18}, {-14, -13, 19, 18}};
+static const int kAnim76FrameIndices[] = {124, 125, 126, 127, 128, 129, 128, 129, 128, 129, 128, 129, 128, 130};
+static const int16 kAnim76FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim76FrameRects[] = {{-14, -23, 23, 18}, {-12, -32, 18, 23}, {-16, -29, 18, 22}, {-17, -17, 23, 17}, {-17, -10, 26, 14}, {-17, -12, 25, 15}, {-17, -10, 26, 14}, {-17, -12, 25, 15}, {-17, -10, 26, 14}, {-17, -12, 25, 15}, {-17, -10, 26, 14}, {-17, -12, 25, 15}, {-17, -10, 26, 14}, {-18, -13, 28, 14}};
+static const int kAnim77FrameIndices[] = {131, 132, 133, 134, 135, 136, 135, 136, 135, 136, 135, 136, 135, 137};
+static const int16 kAnim77FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim77FrameRects[] = {{-6, -24, 21, 19}, {-5, -33, 19, 24}, {-1, -29, 18, 22}, {-5, -17, 22, 17}, {-6, -10, 23, 14}, {-7, -10, 26, 13}, {-6, -10, 23, 14}, {-7, -10, 26, 13}, {-6, -10, 23, 14}, {-7, -10, 26, 13}, {-6, -10, 23, 14}, {-7, -10, 26, 13}, {-6, -10, 23, 14}, {-7, -12, 26, 14}};
+static const int kAnim78FrameIndices[] = {138, 139, 140};
+static const int16 kAnim78FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim78FrameRects[] = {{-3, -17, 7, 20}, {-3, -16, 7, 19}, {-3, -16, 7, 19}};
+static const int kAnim79FrameIndices[] = {141, 142, 143};
+static const int16 kAnim79FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim79FrameRects[] = {{-6, -14, 13, 15}, {-7, -13, 14, 14}, {-6, -13, 13, 14}};
+static const int kAnim80FrameIndices[] = {144, 145, 146};
+static const int16 kAnim80FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim80FrameRects[] = {{-10, -10, 20, 9}, {-9, -9, 19, 8}, {-9, -9, 19, 8}};
+static const int kAnim81FrameIndices[] = {147, 148, 149};
+static const int16 kAnim81FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim81FrameRects[] = {{-7, -11, 16, 10}, {-7, -11, 16, 10}, {-7, -11, 16, 10}};
+static const int kAnim82FrameIndices[] = {150, 151, 152};
+static const int16 kAnim82FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim82FrameRects[] = {{-3, -13, 7, 16}, {-3, -13, 7, 16}, {-3, -12, 7, 15}};
+static const int kAnim83FrameIndices[] = {153, 154, 155};
+static const int16 kAnim83FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim83FrameRects[] = {{-8, -11, 18, 10}, {-7, -11, 16, 11}, {-7, -10, 17, 9}};
+static const int kAnim84FrameIndices[] = {156, 157, 158};
+static const int16 kAnim84FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim84FrameRects[] = {{-8, -9, 20, 7}, {-9, -9, 21, 8}, {-9, -9, 21, 8}};
+static const int kAnim85FrameIndices[] = {159, 160, 161};
+static const int16 kAnim85FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim85FrameRects[] = {{-6, -14, 15, 15}, {-5, -13, 12, 14}, {-6, -13, 14, 14}};
+static const int kAnim86FrameIndices[] = {162};
+static const int16 kAnim86FrameTicks[] = {6};
+static const BBRect kAnim86FrameRects[] = {{-3, -15, 8, 18}};
+static const int kAnim87FrameIndices[] = {163};
+static const int16 kAnim87FrameTicks[] = {6};
+static const BBRect kAnim87FrameRects[] = {{-7, -13, 14, 14}};
+static const int kAnim88FrameIndices[] = {164};
+static const int16 kAnim88FrameTicks[] = {6};
+static const BBRect kAnim88FrameRects[] = {{-11, -9, 21, 8}};
+static const int kAnim89FrameIndices[] = {165};
+static const int16 kAnim89FrameTicks[] = {6};
+static const BBRect kAnim89FrameRects[] = {{-9, -11, 18, 11}};
+static const int kAnim90FrameIndices[] = {166};
+static const int16 kAnim90FrameTicks[] = {6};
+static const BBRect kAnim90FrameRects[] = {{-3, -12, 7, 15}};
+static const int kAnim91FrameIndices[] = {167};
+static const int16 kAnim91FrameTicks[] = {6};
+static const BBRect kAnim91FrameRects[] = {{-8, -11, 17, 12}};
+static const int kAnim92FrameIndices[] = {168};
+static const int16 kAnim92FrameTicks[] = {6};
+static const BBRect kAnim92FrameRects[] = {{-9, -10, 21, 9}};
+static const int kAnim93FrameIndices[] = {169};
+static const int16 kAnim93FrameTicks[] = {6};
+static const BBRect kAnim93FrameRects[] = {{-6, -14, 14, 15}};
+static const int kAnim94FrameIndices[] = {138, 139, 140};
+static const int16 kAnim94FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim94FrameRects[] = {{-3, -17, 7, 20}, {-3, -16, 7, 19}, {-3, -16, 7, 19}};
+static const int kAnim95FrameIndices[] = {141, 142, 143};
+static const int16 kAnim95FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim95FrameRects[] = {{-6, -14, 13, 15}, {-7, -13, 14, 14}, {-6, -13, 13, 14}};
+static const int kAnim96FrameIndices[] = {144, 145, 146};
+static const int16 kAnim96FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim96FrameRects[] = {{-10, -10, 20, 9}, {-9, -9, 19, 8}, {-9, -9, 19, 8}};
+static const int kAnim97FrameIndices[] = {147, 148, 149};
+static const int16 kAnim97FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim97FrameRects[] = {{-7, -11, 16, 10}, {-7, -11, 16, 10}, {-7, -11, 16, 10}};
+static const int kAnim98FrameIndices[] = {150, 151, 152};
+static const int16 kAnim98FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim98FrameRects[] = {{-3, -13, 7, 16}, {-3, -13, 7, 16}, {-3, -12, 7, 15}};
+static const int kAnim99FrameIndices[] = {153, 154, 155};
+static const int16 kAnim99FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim99FrameRects[] = {{-8, -11, 18, 10}, {-7, -11, 16, 11}, {-7, -10, 17, 9}};
+static const int kAnim100FrameIndices[] = {156, 157, 158};
+static const int16 kAnim100FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim100FrameRects[] = {{-8, -9, 20, 7}, {-9, -9, 21, 8}, {-9, -9, 21, 8}};
+static const int kAnim101FrameIndices[] = {159, 160, 161};
+static const int16 kAnim101FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim101FrameRects[] = {{-6, -14, 15, 15}, {-5, -13, 12, 14}, {-6, -13, 14, 14}};
+static const int kAnim102FrameIndices[] = {170, 171, 172, 173, 174, 175, 174, 175, 174, 175, 174, 175, 174, 176};
+static const int16 kAnim102FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim102FrameRects[] = {{-7, -18, 15, 14}, {-6, -24, 11, 18}, {-6, -24, 9, 17}, {-5, -14, 16, 11}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}};
+static const int kAnim103FrameIndices[] = {177, 178, 179, 180, 181, 182, 181, 182, 181, 182, 181, 182, 181, 183};
+static const int16 kAnim103FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim103FrameRects[] = {{-9, -18, 16, 15}, {-6, -24, 12, 18}, {-6, -24, 13, 16}, {-12, -15, 17, 13}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -6, 21, 6}};
+static const int kAnim104FrameIndices[] = {184, 185, 186};
+static const int16 kAnim104FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim104FrameRects[] = {{-3, -17, 7, 20}, {-3, -16, 7, 19}, {-3, -16, 7, 19}};
+static const int kAnim105FrameIndices[] = {187, 188, 189};
+static const int16 kAnim105FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim105FrameRects[] = {{-6, -14, 13, 15}, {-7, -13, 14, 14}, {-6, -13, 13, 14}};
+static const int kAnim106FrameIndices[] = {190, 191, 192};
+static const int16 kAnim106FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim106FrameRects[] = {{-10, -10, 20, 9}, {-9, -9, 19, 8}, {-9, -9, 19, 8}};
+static const int kAnim107FrameIndices[] = {193, 194, 195};
+static const int16 kAnim107FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim107FrameRects[] = {{-7, -11, 16, 10}, {-7, -11, 16, 10}, {-7, -11, 16, 10}};
+static const int kAnim108FrameIndices[] = {196, 197, 198};
+static const int16 kAnim108FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim108FrameRects[] = {{-3, -13, 7, 16}, {-3, -13, 7, 16}, {-3, -12, 7, 15}};
+static const int kAnim109FrameIndices[] = {199, 200, 201};
+static const int16 kAnim109FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim109FrameRects[] = {{-8, -11, 18, 10}, {-7, -11, 16, 11}, {-7, -10, 17, 9}};
+static const int kAnim110FrameIndices[] = {202, 203, 204};
+static const int16 kAnim110FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim110FrameRects[] = {{-8, -9, 20, 7}, {-9, -9, 21, 8}, {-9, -9, 21, 8}};
+static const int kAnim111FrameIndices[] = {205, 206, 207};
+static const int16 kAnim111FrameTicks[] = {10, 8, 8};
+static const BBRect kAnim111FrameRects[] = {{-6, -14, 15, 15}, {-5, -13, 12, 14}, {-6, -13, 14, 14}};
+static const int kAnim112FrameIndices[] = {208};
+static const int16 kAnim112FrameTicks[] = {6};
+static const BBRect kAnim112FrameRects[] = {{-3, -15, 8, 18}};
+static const int kAnim113FrameIndices[] = {209};
+static const int16 kAnim113FrameTicks[] = {6};
+static const BBRect kAnim113FrameRects[] = {{-7, -13, 14, 14}};
+static const int kAnim114FrameIndices[] = {210};
+static const int16 kAnim114FrameTicks[] = {6};
+static const BBRect kAnim114FrameRects[] = {{-11, -9, 21, 8}};
+static const int kAnim115FrameIndices[] = {211};
+static const int16 kAnim115FrameTicks[] = {6};
+static const BBRect kAnim115FrameRects[] = {{-9, -11, 18, 11}};
+static const int kAnim116FrameIndices[] = {212};
+static const int16 kAnim116FrameTicks[] = {6};
+static const BBRect kAnim116FrameRects[] = {{-3, -12, 7, 15}};
+static const int kAnim117FrameIndices[] = {213};
+static const int16 kAnim117FrameTicks[] = {6};
+static const BBRect kAnim117FrameRects[] = {{-8, -11, 17, 12}};
+static const int kAnim118FrameIndices[] = {214};
+static const int16 kAnim118FrameTicks[] = {6};
+static const BBRect kAnim118FrameRects[] = {{-9, -10, 21, 9}};
+static const int kAnim119FrameIndices[] = {215};
+static const int16 kAnim119FrameTicks[] = {6};
+static const BBRect kAnim119FrameRects[] = {{-6, -14, 14, 15}};
+static const int kAnim120FrameIndices[] = {184, 185, 186};
+static const int16 kAnim120FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim120FrameRects[] = {{-3, -17, 7, 20}, {-3, -16, 7, 19}, {-3, -16, 7, 19}};
+static const int kAnim121FrameIndices[] = {187, 188, 189};
+static const int16 kAnim121FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim121FrameRects[] = {{-6, -14, 13, 15}, {-7, -13, 14, 14}, {-6, -13, 13, 14}};
+static const int kAnim122FrameIndices[] = {190, 191, 192};
+static const int16 kAnim122FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim122FrameRects[] = {{-10, -10, 20, 9}, {-9, -9, 19, 8}, {-9, -9, 19, 8}};
+static const int kAnim123FrameIndices[] = {193, 194, 195};
+static const int16 kAnim123FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim123FrameRects[] = {{-7, -11, 16, 10}, {-7, -11, 16, 10}, {-7, -11, 16, 10}};
+static const int kAnim124FrameIndices[] = {196, 197, 198};
+static const int16 kAnim124FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim124FrameRects[] = {{-3, -13, 7, 16}, {-3, -13, 7, 16}, {-3, -12, 7, 15}};
+static const int kAnim125FrameIndices[] = {199, 200, 201};
+static const int16 kAnim125FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim125FrameRects[] = {{-8, -11, 18, 10}, {-7, -11, 16, 11}, {-7, -10, 17, 9}};
+static const int kAnim126FrameIndices[] = {202, 203, 204};
+static const int16 kAnim126FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim126FrameRects[] = {{-8, -9, 20, 7}, {-9, -9, 21, 8}, {-9, -9, 21, 8}};
+static const int kAnim127FrameIndices[] = {205, 206, 207};
+static const int16 kAnim127FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim127FrameRects[] = {{-6, -14, 15, 15}, {-5, -13, 12, 14}, {-6, -13, 14, 14}};
+static const int kAnim128FrameIndices[] = {216, 217, 218, 219, 220, 221, 220, 221, 220, 221, 220, 221, 220, 222};
+static const int16 kAnim128FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim128FrameRects[] = {{-7, -18, 15, 14}, {-6, -24, 11, 18}, {-6, -24, 9, 17}, {-5, -14, 16, 11}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}, {-7, -6, 18, 7}, {-8, -7, 19, 8}};
+static const int kAnim129FrameIndices[] = {223, 224, 225, 226, 227, 228, 227, 228, 227, 228, 227, 228, 227, 229};
+static const int16 kAnim129FrameTicks[] = {6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim129FrameRects[] = {{-9, -18, 16, 15}, {-6, -24, 12, 18}, {-6, -24, 13, 16}, {-12, -15, 17, 13}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -7, 21, 9}, {-10, -7, 19, 8}, {-11, -6, 21, 6}};
+static const int kAnim130FrameIndices[] = {230};
+static const int16 kAnim130FrameTicks[] = {6};
+static const BBRect kAnim130FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim131FrameIndices[] = {231};
+static const int16 kAnim131FrameTicks[] = {6};
+static const BBRect kAnim131FrameRects[] = {{-8, -9, 16, 12}};
+static const int kAnim132FrameIndices[] = {231, 232, 233};
+static const int16 kAnim132FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim132FrameRects[] = {{-8, -9, 16, 12}, {-8, -11, 16, 12}, {-8, -13, 16, 12}};
+static const int kAnim133FrameIndices[] = {233};
+static const int16 kAnim133FrameTicks[] = {6};
+static const BBRect kAnim133FrameRects[] = {{-8, -13, 16, 12}};
+static const int kAnim134FrameIndices[] = {234};
+static const int16 kAnim134FrameTicks[] = {6};
+static const BBRect kAnim134FrameRects[] = {{-7, -6, 14, 10}};
+static const int kAnim135FrameIndices[] = {234, 235, 236};
+static const int16 kAnim135FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim135FrameRects[] = {{-7, -6, 14, 10}, {-7, -9, 14, 9}, {-7, -12, 14, 9}};
+static const int kAnim136FrameIndices[] = {236};
+static const int16 kAnim136FrameTicks[] = {6};
+static const BBRect kAnim136FrameRects[] = {{-7, -12, 14, 9}};
+static const int kAnim137FrameIndices[] = {237};
+static const int16 kAnim137FrameTicks[] = {6};
+static const BBRect kAnim137FrameRects[] = {{-7, -8, 16, 13}};
+static const int kAnim138FrameIndices[] = {237, 238, 239};
+static const int16 kAnim138FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim138FrameRects[] = {{-7, -8, 16, 13}, {-7, -11, 16, 12}, {-7, -14, 16, 13}};
+static const int kAnim139FrameIndices[] = {239};
+static const int16 kAnim139FrameTicks[] = {6};
+static const BBRect kAnim139FrameRects[] = {{-7, -14, 16, 13}};
+static const int kAnim140FrameIndices[] = {240};
+static const int16 kAnim140FrameTicks[] = {6};
+static const BBRect kAnim140FrameRects[] = {{-4, -4, 11, 7}};
+static const int kAnim141FrameIndices[] = {240, 241, 242};
+static const int16 kAnim141FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim141FrameRects[] = {{-4, -4, 11, 7}, {-5, -7, 12, 7}, {-5, -10, 12, 7}};
+static const int kAnim142FrameIndices[] = {242};
+static const int16 kAnim142FrameTicks[] = {6};
+static const BBRect kAnim142FrameRects[] = {{-5, -10, 12, 7}};
+static const int kAnim143FrameIndices[] = {243};
+static const int16 kAnim143FrameTicks[] = {6};
+static const BBRect kAnim143FrameRects[] = {{-5, -4, 12, 7}};
+static const int kAnim144FrameIndices[] = {243, 244, 245};
+static const int16 kAnim144FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim144FrameRects[] = {{-5, -4, 12, 7}, {-5, -7, 12, 7}, {-5, -10, 11, 7}};
+static const int kAnim145FrameIndices[] = {245};
+static const int16 kAnim145FrameTicks[] = {6};
+static const BBRect kAnim145FrameRects[] = {{-5, -10, 11, 7}};
+static const int kAnim146FrameIndices[] = {246};
+static const int16 kAnim146FrameTicks[] = {6};
+static const BBRect kAnim146FrameRects[] = {{-9, -11, 19, 15}};
+static const int kAnim147FrameIndices[] = {246, 247, 248};
+static const int16 kAnim147FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim147FrameRects[] = {{-9, -11, 19, 15}, {-9, -13, 19, 14}, {-9, -17, 19, 15}};
+static const int kAnim148FrameIndices[] = {248};
+static const int16 kAnim148FrameTicks[] = {6};
+static const BBRect kAnim148FrameRects[] = {{-9, -17, 19, 15}};
+static const int kAnim149FrameIndices[] = {249};
+static const int16 kAnim149FrameTicks[] = {6};
+static const BBRect kAnim149FrameRects[] = {{-9, -12, 22, 17}};
+static const int kAnim150FrameIndices[] = {249, 250, 251};
+static const int16 kAnim150FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim150FrameRects[] = {{-9, -12, 22, 17}, {-9, -15, 22, 17}, {-9, -18, 22, 17}};
+static const int kAnim151FrameIndices[] = {251};
+static const int16 kAnim151FrameTicks[] = {6};
+static const BBRect kAnim151FrameRects[] = {{-9, -18, 22, 17}};
+static const int kAnim152FrameIndices[] = {252};
+static const int16 kAnim152FrameTicks[] = {6};
+static const BBRect kAnim152FrameRects[] = {{-8, -5, 18, 9}};
+static const int kAnim153FrameIndices[] = {252, 253, 254};
+static const int16 kAnim153FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim153FrameRects[] = {{-8, -5, 18, 9}, {-7, -9, 17, 9}, {-8, -11, 19, 9}};
+static const int kAnim154FrameIndices[] = {254};
+static const int16 kAnim154FrameTicks[] = {6};
+static const BBRect kAnim154FrameRects[] = {{-8, -11, 19, 9}};
+static const int kAnim155FrameIndices[] = {255};
+static const int16 kAnim155FrameTicks[] = {6};
+static const BBRect kAnim155FrameRects[] = {{-8, -9, 18, 13}};
+static const int kAnim156FrameIndices[] = {255, 256, 257};
+static const int16 kAnim156FrameTicks[] = {6, 6, 6};
+static const BBRect kAnim156FrameRects[] = {{-8, -9, 18, 13}, {-8, -12, 18, 13}, {-7, -15, 17, 13}};
+static const int kAnim157FrameIndices[] = {257};
+static const int16 kAnim157FrameTicks[] = {6};
+static const BBRect kAnim157FrameRects[] = {{-7, -15, 17, 13}};
+static const int kAnim158FrameIndices[] = {258, 259, 260, 261, 262, 263};
+static const int16 kAnim158FrameTicks[] = {6, 8, 8, 8, 6, 6};
+static const BBRect kAnim158FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim159FrameIndices[] = {264, 265, 266};
+static const int16 kAnim159FrameTicks[] = {1, 1, 1};
+static const BBRect kAnim159FrameRects[] = {{-9, -8, 18, 16}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim160FrameIndices[] = {267};
+static const int16 kAnim160FrameTicks[] = {6};
+static const BBRect kAnim160FrameRects[] = {{-25, -83, 43, 54}};
+static const int kAnim161FrameIndices[] = {268};
+static const int16 kAnim161FrameTicks[] = {6};
+static const BBRect kAnim161FrameRects[] = {{-33, -93, 41, 60}};
+static const int kAnim162FrameIndices[] = {269};
+static const int16 kAnim162FrameTicks[] = {1};
+static const BBRect kAnim162FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim163FrameIndices[] = {270};
+static const int16 kAnim163FrameTicks[] = {5};
+static const BBRect kAnim163FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim164FrameIndices[] = {271};
+static const int16 kAnim164FrameTicks[] = {1};
+static const BBRect kAnim164FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim165FrameIndices[] = {272};
+static const int16 kAnim165FrameTicks[] = {1};
+static const BBRect kAnim165FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim166FrameIndices[] = {273};
+static const int16 kAnim166FrameTicks[] = {2};
+static const BBRect kAnim166FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim167FrameIndices[] = {274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286};
+static const int16 kAnim167FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim167FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim168FrameIndices[] = {287};
+static const int16 kAnim168FrameTicks[] = {1};
+static const BBRect kAnim168FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim169FrameIndices[] = {288};
+static const int16 kAnim169FrameTicks[] = {6};
+static const BBRect kAnim169FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim170FrameIndices[] = {289, 290, 291, 292, 293, 294};
+static const int16 kAnim170FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim170FrameRects[] = {{-22, -91, 45, 93}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}};
+static const int kAnim171FrameIndices[] = {295, 296, 297, 298, 299, 300};
+static const int16 kAnim171FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim171FrameRects[] = {{-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}};
+static const int kAnim172FrameIndices[] = {301, 302};
+static const int16 kAnim172FrameTicks[] = {6, 6};
+static const BBRect kAnim172FrameRects[] = {{-9, -9, 17, 15}, {-11, -10, 19, 16}};
+static const ObjAnimation kAnimations[] = {
+ {3, kAnim0FrameIndices, kAnim0FrameTicks, kAnim0FrameRects},
+ {3, kAnim1FrameIndices, kAnim1FrameTicks, kAnim1FrameRects},
+ {3, kAnim2FrameIndices, kAnim2FrameTicks, kAnim2FrameRects},
+ {3, kAnim3FrameIndices, kAnim3FrameTicks, kAnim3FrameRects},
+ {3, kAnim4FrameIndices, kAnim4FrameTicks, kAnim4FrameRects},
+ {3, kAnim5FrameIndices, kAnim5FrameTicks, kAnim5FrameRects},
+ {3, kAnim6FrameIndices, kAnim6FrameTicks, kAnim6FrameRects},
+ {3, kAnim7FrameIndices, kAnim7FrameTicks, kAnim7FrameRects},
+ {1, kAnim8FrameIndices, kAnim8FrameTicks, kAnim8FrameRects},
+ {1, kAnim9FrameIndices, kAnim9FrameTicks, kAnim9FrameRects},
+ {1, kAnim10FrameIndices, kAnim10FrameTicks, kAnim10FrameRects},
+ {1, kAnim11FrameIndices, kAnim11FrameTicks, kAnim11FrameRects},
+ {1, kAnim12FrameIndices, kAnim12FrameTicks, kAnim12FrameRects},
+ {1, kAnim13FrameIndices, kAnim13FrameTicks, kAnim13FrameRects},
+ {1, kAnim14FrameIndices, kAnim14FrameTicks, kAnim14FrameRects},
+ {1, kAnim15FrameIndices, kAnim15FrameTicks, kAnim15FrameRects},
+ {3, kAnim16FrameIndices, kAnim16FrameTicks, kAnim16FrameRects},
+ {3, kAnim17FrameIndices, kAnim17FrameTicks, kAnim17FrameRects},
+ {3, kAnim18FrameIndices, kAnim18FrameTicks, kAnim18FrameRects},
+ {3, kAnim19FrameIndices, kAnim19FrameTicks, kAnim19FrameRects},
+ {3, kAnim20FrameIndices, kAnim20FrameTicks, kAnim20FrameRects},
+ {3, kAnim21FrameIndices, kAnim21FrameTicks, kAnim21FrameRects},
+ {3, kAnim22FrameIndices, kAnim22FrameTicks, kAnim22FrameRects},
+ {3, kAnim23FrameIndices, kAnim23FrameTicks, kAnim23FrameRects},
+ {14, kAnim24FrameIndices, kAnim24FrameTicks, kAnim24FrameRects},
+ {14, kAnim25FrameIndices, kAnim25FrameTicks, kAnim25FrameRects},
+ {3, kAnim26FrameIndices, kAnim26FrameTicks, kAnim26FrameRects},
+ {3, kAnim27FrameIndices, kAnim27FrameTicks, kAnim27FrameRects},
+ {3, kAnim28FrameIndices, kAnim28FrameTicks, kAnim28FrameRects},
+ {3, kAnim29FrameIndices, kAnim29FrameTicks, kAnim29FrameRects},
+ {3, kAnim30FrameIndices, kAnim30FrameTicks, kAnim30FrameRects},
+ {3, kAnim31FrameIndices, kAnim31FrameTicks, kAnim31FrameRects},
+ {3, kAnim32FrameIndices, kAnim32FrameTicks, kAnim32FrameRects},
+ {3, kAnim33FrameIndices, kAnim33FrameTicks, kAnim33FrameRects},
+ {1, kAnim34FrameIndices, kAnim34FrameTicks, kAnim34FrameRects},
+ {1, kAnim35FrameIndices, kAnim35FrameTicks, kAnim35FrameRects},
+ {1, kAnim36FrameIndices, kAnim36FrameTicks, kAnim36FrameRects},
+ {1, kAnim37FrameIndices, kAnim37FrameTicks, kAnim37FrameRects},
+ {1, kAnim38FrameIndices, kAnim38FrameTicks, kAnim38FrameRects},
+ {1, kAnim39FrameIndices, kAnim39FrameTicks, kAnim39FrameRects},
+ {1, kAnim40FrameIndices, kAnim40FrameTicks, kAnim40FrameRects},
+ {1, kAnim41FrameIndices, kAnim41FrameTicks, kAnim41FrameRects},
+ {3, kAnim42FrameIndices, kAnim42FrameTicks, kAnim42FrameRects},
+ {3, kAnim43FrameIndices, kAnim43FrameTicks, kAnim43FrameRects},
+ {3, kAnim44FrameIndices, kAnim44FrameTicks, kAnim44FrameRects},
+ {3, kAnim45FrameIndices, kAnim45FrameTicks, kAnim45FrameRects},
+ {3, kAnim46FrameIndices, kAnim46FrameTicks, kAnim46FrameRects},
+ {3, kAnim47FrameIndices, kAnim47FrameTicks, kAnim47FrameRects},
+ {3, kAnim48FrameIndices, kAnim48FrameTicks, kAnim48FrameRects},
+ {3, kAnim49FrameIndices, kAnim49FrameTicks, kAnim49FrameRects},
+ {14, kAnim50FrameIndices, kAnim50FrameTicks, kAnim50FrameRects},
+ {14, kAnim51FrameIndices, kAnim51FrameTicks, kAnim51FrameRects},
+ {3, kAnim52FrameIndices, kAnim52FrameTicks, kAnim52FrameRects},
+ {3, kAnim53FrameIndices, kAnim53FrameTicks, kAnim53FrameRects},
+ {3, kAnim54FrameIndices, kAnim54FrameTicks, kAnim54FrameRects},
+ {3, kAnim55FrameIndices, kAnim55FrameTicks, kAnim55FrameRects},
+ {3, kAnim56FrameIndices, kAnim56FrameTicks, kAnim56FrameRects},
+ {3, kAnim57FrameIndices, kAnim57FrameTicks, kAnim57FrameRects},
+ {3, kAnim58FrameIndices, kAnim58FrameTicks, kAnim58FrameRects},
+ {3, kAnim59FrameIndices, kAnim59FrameTicks, kAnim59FrameRects},
+ {1, kAnim60FrameIndices, kAnim60FrameTicks, kAnim60FrameRects},
+ {1, kAnim61FrameIndices, kAnim61FrameTicks, kAnim61FrameRects},
+ {1, kAnim62FrameIndices, kAnim62FrameTicks, kAnim62FrameRects},
+ {1, kAnim63FrameIndices, kAnim63FrameTicks, kAnim63FrameRects},
+ {1, kAnim64FrameIndices, kAnim64FrameTicks, kAnim64FrameRects},
+ {1, kAnim65FrameIndices, kAnim65FrameTicks, kAnim65FrameRects},
+ {1, kAnim66FrameIndices, kAnim66FrameTicks, kAnim66FrameRects},
+ {1, kAnim67FrameIndices, kAnim67FrameTicks, kAnim67FrameRects},
+ {3, kAnim68FrameIndices, kAnim68FrameTicks, kAnim68FrameRects},
+ {3, kAnim69FrameIndices, kAnim69FrameTicks, kAnim69FrameRects},
+ {3, kAnim70FrameIndices, kAnim70FrameTicks, kAnim70FrameRects},
+ {3, kAnim71FrameIndices, kAnim71FrameTicks, kAnim71FrameRects},
+ {3, kAnim72FrameIndices, kAnim72FrameTicks, kAnim72FrameRects},
+ {3, kAnim73FrameIndices, kAnim73FrameTicks, kAnim73FrameRects},
+ {3, kAnim74FrameIndices, kAnim74FrameTicks, kAnim74FrameRects},
+ {3, kAnim75FrameIndices, kAnim75FrameTicks, kAnim75FrameRects},
+ {14, kAnim76FrameIndices, kAnim76FrameTicks, kAnim76FrameRects},
+ {14, kAnim77FrameIndices, kAnim77FrameTicks, kAnim77FrameRects},
+ {3, kAnim78FrameIndices, kAnim78FrameTicks, kAnim78FrameRects},
+ {3, kAnim79FrameIndices, kAnim79FrameTicks, kAnim79FrameRects},
+ {3, kAnim80FrameIndices, kAnim80FrameTicks, kAnim80FrameRects},
+ {3, kAnim81FrameIndices, kAnim81FrameTicks, kAnim81FrameRects},
+ {3, kAnim82FrameIndices, kAnim82FrameTicks, kAnim82FrameRects},
+ {3, kAnim83FrameIndices, kAnim83FrameTicks, kAnim83FrameRects},
+ {3, kAnim84FrameIndices, kAnim84FrameTicks, kAnim84FrameRects},
+ {3, kAnim85FrameIndices, kAnim85FrameTicks, kAnim85FrameRects},
+ {1, kAnim86FrameIndices, kAnim86FrameTicks, kAnim86FrameRects},
+ {1, kAnim87FrameIndices, kAnim87FrameTicks, kAnim87FrameRects},
+ {1, kAnim88FrameIndices, kAnim88FrameTicks, kAnim88FrameRects},
+ {1, kAnim89FrameIndices, kAnim89FrameTicks, kAnim89FrameRects},
+ {1, kAnim90FrameIndices, kAnim90FrameTicks, kAnim90FrameRects},
+ {1, kAnim91FrameIndices, kAnim91FrameTicks, kAnim91FrameRects},
+ {1, kAnim92FrameIndices, kAnim92FrameTicks, kAnim92FrameRects},
+ {1, kAnim93FrameIndices, kAnim93FrameTicks, kAnim93FrameRects},
+ {3, kAnim94FrameIndices, kAnim94FrameTicks, kAnim94FrameRects},
+ {3, kAnim95FrameIndices, kAnim95FrameTicks, kAnim95FrameRects},
+ {3, kAnim96FrameIndices, kAnim96FrameTicks, kAnim96FrameRects},
+ {3, kAnim97FrameIndices, kAnim97FrameTicks, kAnim97FrameRects},
+ {3, kAnim98FrameIndices, kAnim98FrameTicks, kAnim98FrameRects},
+ {3, kAnim99FrameIndices, kAnim99FrameTicks, kAnim99FrameRects},
+ {3, kAnim100FrameIndices, kAnim100FrameTicks, kAnim100FrameRects},
+ {3, kAnim101FrameIndices, kAnim101FrameTicks, kAnim101FrameRects},
+ {14, kAnim102FrameIndices, kAnim102FrameTicks, kAnim102FrameRects},
+ {14, kAnim103FrameIndices, kAnim103FrameTicks, kAnim103FrameRects},
+ {3, kAnim104FrameIndices, kAnim104FrameTicks, kAnim104FrameRects},
+ {3, kAnim105FrameIndices, kAnim105FrameTicks, kAnim105FrameRects},
+ {3, kAnim106FrameIndices, kAnim106FrameTicks, kAnim106FrameRects},
+ {3, kAnim107FrameIndices, kAnim107FrameTicks, kAnim107FrameRects},
+ {3, kAnim108FrameIndices, kAnim108FrameTicks, kAnim108FrameRects},
+ {3, kAnim109FrameIndices, kAnim109FrameTicks, kAnim109FrameRects},
+ {3, kAnim110FrameIndices, kAnim110FrameTicks, kAnim110FrameRects},
+ {3, kAnim111FrameIndices, kAnim111FrameTicks, kAnim111FrameRects},
+ {1, kAnim112FrameIndices, kAnim112FrameTicks, kAnim112FrameRects},
+ {1, kAnim113FrameIndices, kAnim113FrameTicks, kAnim113FrameRects},
+ {1, kAnim114FrameIndices, kAnim114FrameTicks, kAnim114FrameRects},
+ {1, kAnim115FrameIndices, kAnim115FrameTicks, kAnim115FrameRects},
+ {1, kAnim116FrameIndices, kAnim116FrameTicks, kAnim116FrameRects},
+ {1, kAnim117FrameIndices, kAnim117FrameTicks, kAnim117FrameRects},
+ {1, kAnim118FrameIndices, kAnim118FrameTicks, kAnim118FrameRects},
+ {1, kAnim119FrameIndices, kAnim119FrameTicks, kAnim119FrameRects},
+ {3, kAnim120FrameIndices, kAnim120FrameTicks, kAnim120FrameRects},
+ {3, kAnim121FrameIndices, kAnim121FrameTicks, kAnim121FrameRects},
+ {3, kAnim122FrameIndices, kAnim122FrameTicks, kAnim122FrameRects},
+ {3, kAnim123FrameIndices, kAnim123FrameTicks, kAnim123FrameRects},
+ {3, kAnim124FrameIndices, kAnim124FrameTicks, kAnim124FrameRects},
+ {3, kAnim125FrameIndices, kAnim125FrameTicks, kAnim125FrameRects},
+ {3, kAnim126FrameIndices, kAnim126FrameTicks, kAnim126FrameRects},
+ {3, kAnim127FrameIndices, kAnim127FrameTicks, kAnim127FrameRects},
+ {14, kAnim128FrameIndices, kAnim128FrameTicks, kAnim128FrameRects},
+ {14, kAnim129FrameIndices, kAnim129FrameTicks, kAnim129FrameRects},
+ {1, kAnim130FrameIndices, kAnim130FrameTicks, kAnim130FrameRects},
+ {1, kAnim131FrameIndices, kAnim131FrameTicks, kAnim131FrameRects},
+ {3, kAnim132FrameIndices, kAnim132FrameTicks, kAnim132FrameRects},
+ {1, kAnim133FrameIndices, kAnim133FrameTicks, kAnim133FrameRects},
+ {1, kAnim134FrameIndices, kAnim134FrameTicks, kAnim134FrameRects},
+ {3, kAnim135FrameIndices, kAnim135FrameTicks, kAnim135FrameRects},
+ {1, kAnim136FrameIndices, kAnim136FrameTicks, kAnim136FrameRects},
+ {1, kAnim137FrameIndices, kAnim137FrameTicks, kAnim137FrameRects},
+ {3, kAnim138FrameIndices, kAnim138FrameTicks, kAnim138FrameRects},
+ {1, kAnim139FrameIndices, kAnim139FrameTicks, kAnim139FrameRects},
+ {1, kAnim140FrameIndices, kAnim140FrameTicks, kAnim140FrameRects},
+ {3, kAnim141FrameIndices, kAnim141FrameTicks, kAnim141FrameRects},
+ {1, kAnim142FrameIndices, kAnim142FrameTicks, kAnim142FrameRects},
+ {1, kAnim143FrameIndices, kAnim143FrameTicks, kAnim143FrameRects},
+ {3, kAnim144FrameIndices, kAnim144FrameTicks, kAnim144FrameRects},
+ {1, kAnim145FrameIndices, kAnim145FrameTicks, kAnim145FrameRects},
+ {1, kAnim146FrameIndices, kAnim146FrameTicks, kAnim146FrameRects},
+ {3, kAnim147FrameIndices, kAnim147FrameTicks, kAnim147FrameRects},
+ {1, kAnim148FrameIndices, kAnim148FrameTicks, kAnim148FrameRects},
+ {1, kAnim149FrameIndices, kAnim149FrameTicks, kAnim149FrameRects},
+ {3, kAnim150FrameIndices, kAnim150FrameTicks, kAnim150FrameRects},
+ {1, kAnim151FrameIndices, kAnim151FrameTicks, kAnim151FrameRects},
+ {1, kAnim152FrameIndices, kAnim152FrameTicks, kAnim152FrameRects},
+ {3, kAnim153FrameIndices, kAnim153FrameTicks, kAnim153FrameRects},
+ {1, kAnim154FrameIndices, kAnim154FrameTicks, kAnim154FrameRects},
+ {1, kAnim155FrameIndices, kAnim155FrameTicks, kAnim155FrameRects},
+ {3, kAnim156FrameIndices, kAnim156FrameTicks, kAnim156FrameRects},
+ {1, kAnim157FrameIndices, kAnim157FrameTicks, kAnim157FrameRects},
+ {6, kAnim158FrameIndices, kAnim158FrameTicks, kAnim158FrameRects},
+ {3, kAnim159FrameIndices, kAnim159FrameTicks, kAnim159FrameRects},
+ {1, kAnim160FrameIndices, kAnim160FrameTicks, kAnim160FrameRects},
+ {1, kAnim161FrameIndices, kAnim161FrameTicks, kAnim161FrameRects},
+ {1, kAnim162FrameIndices, kAnim162FrameTicks, kAnim162FrameRects},
+ {1, kAnim163FrameIndices, kAnim163FrameTicks, kAnim163FrameRects},
+ {1, kAnim164FrameIndices, kAnim164FrameTicks, kAnim164FrameRects},
+ {1, kAnim165FrameIndices, kAnim165FrameTicks, kAnim165FrameRects},
+ {1, kAnim166FrameIndices, kAnim166FrameTicks, kAnim166FrameRects},
+ {13, kAnim167FrameIndices, kAnim167FrameTicks, kAnim167FrameRects},
+ {1, kAnim168FrameIndices, kAnim168FrameTicks, kAnim168FrameRects},
+ {1, kAnim169FrameIndices, kAnim169FrameTicks, kAnim169FrameRects},
+ {6, kAnim170FrameIndices, kAnim170FrameTicks, kAnim170FrameRects},
+ {6, kAnim171FrameIndices, kAnim171FrameTicks, kAnim171FrameRects},
+ {2, kAnim172FrameIndices, kAnim172FrameTicks, kAnim172FrameRects}
+};
+
+static const MinigameBbAnt::ObjInit kObjInits[] = {
+ {&kAnimations[131], &kAnimations[132], &kAnimations[133], 160, 120},
+ {&kAnimations[134], &kAnimations[135], &kAnimations[136], 155, 130},
+ {&kAnimations[137], &kAnimations[138], &kAnimations[139], 150, 100},
+ {&kAnimations[140], &kAnimations[141], &kAnimations[142], 195, 150},
+ {&kAnimations[143], &kAnimations[144], &kAnimations[145], 120, 110},
+ {&kAnimations[146], &kAnimations[147], &kAnimations[148], 170, 170},
+ {&kAnimations[149], &kAnimations[150], &kAnimations[151], 175, 95},
+ {&kAnimations[152], &kAnimations[153], &kAnimations[154], 145, 165},
+ {&kAnimations[155], &kAnimations[156], &kAnimations[157], 110, 175}
+};
+static const ObjAnimation * const kAnimationsTbl[] = {&kAnimations[0], &kAnimations[1], &kAnimations[2], &kAnimations[3], &kAnimations[4], &kAnimations[5], &kAnimations[6], &kAnimations[7], &kAnimations[16], &kAnimations[17], &kAnimations[18], &kAnimations[19], &kAnimations[20], &kAnimations[21], &kAnimations[22], &kAnimations[23], &kAnimations[24], &kAnimations[25], &kAnimations[26], &kAnimations[27], &kAnimations[28], &kAnimations[29], &kAnimations[30], &kAnimations[31], &kAnimations[32], &kAnimations[33], &kAnimations[42], &kAnimations[43], &kAnimations[44], &kAnimations[45], &kAnimations[46], &kAnimations[47], &kAnimations[48], &kAnimations[49], &kAnimations[50], &kAnimations[51], &kAnimations[52], &kAnimations[53], &kAnimations[54], &kAnimations[55], &kAnimations[56], &kAnimations[57], &kAnimations[58], &kAnimations[59], &kAnimations[68], &kAnimations[69], &kAnimations[70], &kAnimations[71], &kAnimations[72], &kAnimations[73], &kAnimations[74], &kAnimations[75], &kAnimations[76], &kAnimations[77], &kAnimations[78], &kAnimations[79], &kAnimations[80], &kAnimations[81], &kAnimations[82], &kAnimations[83], &kAnimations[84], &kAnimations[85], &kAnimations[94], &kAnimations[95], &kAnimations[96], &kAnimations[97], &kAnimations[98], &kAnimations[99], &kAnimations[100], &kAnimations[101], &kAnimations[102], &kAnimations[103], &kAnimations[104], &kAnimations[105], &kAnimations[106], &kAnimations[107], &kAnimations[108], &kAnimations[109], &kAnimations[110], &kAnimations[111], &kAnimations[120], &kAnimations[121], &kAnimations[122], &kAnimations[123], &kAnimations[124], &kAnimations[125], &kAnimations[126], &kAnimations[127], &kAnimations[128], &kAnimations[129]};
+
+static const ObjAnimation * const * const kObjKindAnimTables[] = {
+ 0, &kAnimationsTbl[0],
+ &kAnimationsTbl[18], &kAnimationsTbl[36],
+ &kAnimationsTbl[54], &kAnimationsTbl[72]
+};
+
+const ObjAnimation *MinigameBbAnt::getAnimation(int animIndex) {
+ return &kAnimations[animIndex];
+}
+
+const MinigameBbAnt::ObjInit *MinigameBbAnt::getObjInit(int index) {
+ return &kObjInits[index];
+}
+
+const ObjAnimation * const *MinigameBbAnt::getObjKindAnimTable(int kind) {
+ return kObjKindAnimTables[kind];
+}
+
+const ObjAnimation *MinigameBbAnt::getObjAnim(int index) {
+ return kAnimationsTbl[index];
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbloogie.cpp b/engines/bbvs/minigames/bbloogie.cpp
new file mode 100644
index 0000000000..df7fec3123
--- /dev/null
+++ b/engines/bbvs/minigames/bbloogie.cpp
@@ -0,0 +1,1355 @@
+/* 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 "bbvs/minigames/bbloogie.h"
+
+namespace Bbvs {
+
+static const int kLoogieOffY[16] = {
+ 0, 1, 1, 2, 2, 3, 3, 4,
+ 4, 5, 5, 6, 6, 7, 7, 0
+};
+
+static const int kSquirrelOffX[] = {
+ -43, -43, -38, -33, -33, -27, -23, -23,
+ -23, -23, -23, -23, -18, -14, -8, -4,
+ 2, 8, 12, 18, 20, 20, 26, 31,
+ 37, 37, 37, 37, 37, 37, 37, 32,
+ 29, 26, 21, 14, 10, 6, 6, 6,
+ 6, 6, 6, 6, 0, -6, -15, -20,
+ -27, -37, -41, -41, -41, -41
+};
+
+static const int kPlaneOffX[] = {
+ 0, -1, -1, -1, 0, 1, 1, 1
+};
+
+static const int kPlaneOffY[] = {
+ -1, -1, 0, 1, 1, 1, 0, -1
+};
+
+static const int kLevelScores[] = {
+ 20, 50, 90, 140, 200, 270, 350, 440, 540, 10000
+};
+
+static const int kLevelTimes[] = {
+ 120, 110, 100, 90, 80, 70, 60, 50, 40, 30
+};
+
+static const uint kBeavisSounds1[] = {
+ 14, 15, 19, 20, 22, 23, 24, 26
+};
+
+static const uint kButtheadSounds1[] = {
+ 16, 14, 15, 22, 23
+};
+
+static const uint kBeavisSounds2[] = {
+ 9, 3, 4, 5, 7, 14, 15, 19, 20, 22, 23, 24, 26
+};
+
+static const uint kButtheadSounds2[] = {
+ 9, 3, 4, 5, 7, 16, 14, 15, 22, 23
+};
+
+static const uint kPrincipalSounds[] = {
+ 3, 4, 5, 7
+};
+
+static const char * const kSoundFilenames[] = {
+ "loog1.aif", "loog2.aif", "loog3.aif", "loog4.aif", "loog5.aif",
+ "loog6.aif", "loog7.aif", "loog8.aif", "loog9.aif", "loog10.aif",
+ "loog11.aif", "loog12.aif", "loog13.aif", "loog14.aif", "loog15.aif",
+ "loog16.aif", "loog17.aif", "loog18.aif", "loog19.aif", "loog20.aif",
+ "loog21.aif", "loog22.aif", "loog23.aif", "loog24.aif", "loog25.aif",
+ "loog26.aif", "loog27.aif", "meghoker.aif", "spit1.aif", "megaloog.aif",
+ "megaspit.aif", "gamemuse.aif", "bing.aif", "carhit.aif", "bikehit.aif",
+ "squirhit.aif", "planehit.aif", "bing2.aif"
+};
+
+static const uint kSoundFilenamesCount = ARRAYSIZE(kSoundFilenames);
+
+void MinigameBbLoogie::buildDrawList(DrawList &drawList) {
+ switch (_gameState) {
+ case kGSTitleScreen:
+ buildDrawList0(drawList);
+ break;
+ case kGSMainGame:
+ buildDrawList1(drawList);
+ break;
+ case kGSStandaloneGame:
+ buildDrawList2(drawList);
+ break;
+ case kGSScoreCountUp:
+ buildDrawList3(drawList);
+ break;
+ }
+}
+
+void MinigameBbLoogie::buildDrawList0(DrawList &drawList) {
+ drawList.add(_objects[0].anim->frameIndices[_objects[0].frameIndex], _objects[0].x, _objects[0].y, 2000);
+ for (int i = 1; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind != 0)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
+ }
+ if (_titleScreenSpriteIndex)
+ drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
+}
+
+void MinigameBbLoogie::buildDrawList1(DrawList &drawList) {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ switch (obj->kind) {
+ case 0:
+ // Empty object
+ break;
+ case 2:
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 400);
+ break;
+ case 3:
+ drawList.add(obj->anim->frameIndices[obj->frameIndex + obj->frameIndexAdd], obj->x, obj->y, 1000);
+ break;
+ case 7:
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 390);
+ break;
+ case 8:
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 1000);
+ break;
+ default:
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
+ break;
+ }
+ }
+
+ if (_backgroundSpriteIndex)
+ drawList.add(_backgroundSpriteIndex, 0, 0, 0);
+
+ if (_fromMainGame) {
+ drawList.add(getAnimation(8)->frameIndices[0], 8, 2, 2000);
+ drawNumber(drawList, _numberOfHits, 56, 16);
+ } else {
+ drawList.add(getAnimation(10)->frameIndices[0], 230, 2, 2000);
+ drawNumber(drawList, _levelTimeLeft, 280, 16);
+ drawList.add(getAnimation(15)->frameIndices[0], 5, 2, 2000);
+ int numberX2 = drawNumber(drawList, _currScore, 68, 16);
+ drawList.add(getAnimation(9)->frameIndices[10], numberX2, 16, 2000);
+ drawNumber(drawList, _dispLevelScore, numberX2 + 10, 16);
+ }
+
+ for (int i = 0; i < _megaLoogieCount; ++i)
+ drawList.add(getAnimation(19)->frameIndices[0], 20 + i * 25, 236, 2000);
+
+}
+
+void MinigameBbLoogie::buildDrawList2(DrawList &drawList) {
+
+ buildDrawList1(drawList);
+
+ if (_level > 0 && (_bonusDisplayDelay1 > 0 || _bonusDisplayDelay2 > 0)) {
+ drawList.add(getAnimation(12)->frameIndices[0], 100, 80, 2000);
+ drawNumber(drawList, _timeBonusCtr, 212, 94);
+ }
+
+ if (_bonusDisplayDelay3 > 0) {
+ drawList.add(getAnimation(14)->frameIndices[0], 65, 80, 2000);
+ int numberX2 = drawNumber(drawList, _nextLevelScore, 170, 92);
+ drawList.add(getAnimation(11)->frameIndices[0], numberX2, 80, 2000);
+ }
+
+}
+
+void MinigameBbLoogie::buildDrawList3(DrawList &drawList) {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind == 2)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, 400);
+ else
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
+ }
+
+ if (_backgroundSpriteIndex)
+ drawList.add(_backgroundSpriteIndex, 0, 0, 0);
+
+ drawList.add(getAnimation(10)->frameIndices[0], 230, 2, 2000);
+
+ drawNumber(drawList, _levelTimeLeft, 280, 16);
+
+ drawList.add(getAnimation(15)->frameIndices[0], 5, 2, 2000);
+
+ int numberX2 = drawNumber(drawList, _currScore, 68, 16);
+ drawList.add(getAnimation(9)->frameIndices[10], numberX2, 16, 2000);
+ drawNumber(drawList, _dispLevelScore, numberX2 + 10, 16);
+
+ drawList.add(getAnimation(20)->frameIndices[0], 120, 70, 2000);
+ drawList.add(getAnimation(13)->frameIndices[0], 95, 95, 2000);
+
+ drawNumber(drawList, _hiScore, 210, 109);
+
+}
+
+void MinigameBbLoogie::drawSprites() {
+ DrawList drawList;
+ buildDrawList(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+void MinigameBbLoogie::initObjs() {
+ for (int i = 0; i < kMaxObjectsCount; ++i)
+ _objects[i].kind = 0;
+}
+
+MinigameBbLoogie::Obj *MinigameBbLoogie::getFreeObject() {
+ for (int i = 0; i < kMaxObjectsCount; ++i)
+ if (_objects[i].kind == 0)
+ return &_objects[i];
+ return 0;
+}
+
+MinigameBbLoogie::Obj *MinigameBbLoogie::findLoogieObj(int startObjIndex) {
+ for (int i = startObjIndex; i < kMaxObjectsCount; ++i)
+ if (_objects[i].kind == 3)
+ return &_objects[i];
+ return 0;
+}
+
+bool MinigameBbLoogie::isHit(Obj *obj1, Obj *obj2) {
+ const BBRect &frameRect1 = obj1->anim->frameRects[obj1->frameIndex];
+ const BBRect &frameRect2 = obj2->anim->frameRects[obj2->frameIndex];
+ const int obj1X1 = obj1->x + frameRect1.x;
+ const int obj1Y1 = obj1->y + frameRect1.y;
+ const int obj1X2 = obj1X1 + frameRect1.width;
+ const int obj1Y2 = obj1Y1 + frameRect1.height;
+ const int obj2X1 = obj2->x + frameRect2.x;
+ const int obj2Y1 = obj2->y + frameRect2.y;
+ const int obj2X2 = obj2X1 + frameRect2.width;
+ const int obj2Y2 = obj2Y1 + frameRect2.height;
+ return obj1X1 <= obj2X2 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1;
+}
+
+bool MinigameBbLoogie::isCursorAtObj(int objIndex) {
+ return isHit(&_objects[0], &_objects[objIndex]);
+}
+
+void MinigameBbLoogie::initObjects() {
+ switch (_gameState) {
+ case kGSTitleScreen:
+ initObjects0();
+ break;
+ case kGSMainGame:
+ initObjects1();
+ break;
+ case kGSStandaloneGame:
+ // Nothing
+ break;
+ case kGSScoreCountUp:
+ initObjects3();
+ break;
+ }
+}
+
+void MinigameBbLoogie::initObjects0() {
+ initObjs();
+ _objects[0].anim = getAnimation(25);
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = getAnimation(25)->frameTicks[0];
+ _objects[0].x = 160;
+ _objects[0].y = 120;
+ _objects[0].kind = 1;
+ _objects[1].anim = getAnimation(21);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = getAnimation(21)->frameTicks[0];
+ _objects[1].x = 40;
+ _objects[1].y = 240;
+ _objects[1].kind = 1;
+ _objects[2].anim = getAnimation(23);
+ _objects[2].frameIndex = 0;
+ _objects[2].ticks = getAnimation(23)->frameTicks[0];
+ _objects[2].x = 280;
+ _objects[2].y = 240;
+ _objects[2].kind = 1;
+ _objects[3].anim = getAnimation(22);
+ _objects[3].frameIndex = 0;
+ _objects[3].ticks = getAnimation(22)->frameTicks[0];
+ _objects[3].x = 40;
+ _objects[3].y = 240;
+ _objects[3].kind = 0;
+ _objects[4].anim = getAnimation(24);
+ _objects[4].frameIndex = 0;
+ _objects[4].ticks = getAnimation(24)->frameTicks[0];
+ _objects[4].x = 280;
+ _objects[4].y = 240;
+ _objects[4].kind = 0;
+}
+
+void MinigameBbLoogie::initObjects1() {
+ initObjs();
+ _objects[0].anim = _playerAnim;
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = _playerAnim->frameTicks[0];
+ _objects[0].status = 0;
+ _objects[0].x = 160;
+ _objects[0].y = 240;
+ _objects[0].kind = 1;
+ _objects[1].anim = getAnimation(4);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = getAnimation(4)->frameTicks[0];
+ _objects[1].x = 248;
+ _objects[1].y = 24;
+ _objects[1].kind = 2;
+}
+
+void MinigameBbLoogie::initObjects3() {
+ initObjs();
+ _objects[0].anim = _playerAnim;
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = _playerAnim->frameTicks[0];
+ _objects[0].status = 0;
+ _objects[0].kind = 1;
+ _objects[1].anim = getAnimation(4);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = getAnimation(4)->frameTicks[0];
+ _objects[1].x = 248;
+ _objects[1].y = 24;
+ _objects[1].kind = 2;
+}
+
+void MinigameBbLoogie::initVars() {
+ switch (_gameState) {
+ case kGSTitleScreen:
+ initVars0();
+ break;
+ case kGSMainGame:
+ initVars1();
+ break;
+ case kGSStandaloneGame:
+ initVars2();
+ break;
+ case kGSScoreCountUp:
+ initVars3();
+ break;
+ }
+}
+
+void MinigameBbLoogie::initVars0() {
+ _carDelay = 120;
+ _bikeDelay = 250;
+ _squirrelDelay = 40;
+ _paperPlaneDelay = 400; // Uninitialized in the original
+ _principalDelay = 1750;
+ _levelTimeDelay = 58;
+ _principalAngry = false;
+ _squirrelDirection = false;
+ _numberOfHits = 0;
+ _megaLoogieCount = 0;
+ _level = 0;
+ _levelTimeLeft = 0;
+ _currScore = 0;
+ _dispLevelScore = 0;
+}
+
+void MinigameBbLoogie::initVars1() {
+ _carDelay = 120;
+ _bikeDelay = 250;
+ _squirrelDelay = 40;
+ _paperPlaneDelay = 400; // Uninitialized in the original
+ _principalDelay = 1750;
+ _squirrelDirection = false;
+ _numberOfHits = 0;
+ _megaLoogieCount = 0;
+}
+
+void MinigameBbLoogie::initVars2() {
+ _timeBonusCtr = _levelTimeLeft;
+ _levelTimeDelay = 58;
+ _bonusDisplayDelay1 = 60;
+ _levelTimeLeft = kLevelTimes[_level];
+ _nextLevelScore = kLevelScores[_level] + _currScore;
+ _bonusDisplayDelay2 = 0;
+ _bonusDisplayDelay3 = 0;
+}
+
+void MinigameBbLoogie::initVars3() {
+ if (_currScore > _hiScore)
+ _hiScore = _currScore;
+ if (_playerKind) {
+ playSound(11);
+ } else {
+ playSound(21);
+ }
+}
+
+bool MinigameBbLoogie::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
+ switch (_gameState) {
+ case kGSTitleScreen:
+ return updateStatus0(mouseX, mouseY, mouseButtons);
+ case kGSMainGame:
+ return updateStatus1(mouseX, mouseY, mouseButtons);
+ case kGSStandaloneGame:
+ return updateStatus2(mouseX, mouseY, mouseButtons);
+ case kGSScoreCountUp:
+ return updateStatus3(mouseX, mouseY, mouseButtons);
+ }
+ return false;
+}
+
+bool MinigameBbLoogie::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ if (_objects[1].kind != 0 && isCursorAtObj(1)) {
+ _objects[0].frameIndex = 1;
+ _objects[1].kind = 0;
+ _objects[3].kind = 11;
+ _objects[3].frameIndex = 0;
+ _objects[3].ticks = _objects[3].anim->frameTicks[0];
+ } else if (!isCursorAtObj(3)) {
+ if (_objects[4].kind == 0)
+ _objects[0].frameIndex = 0;
+ _objects[3].kind = 0;
+ _objects[1].kind = 1;
+ }
+
+ if (_objects[2].kind && isCursorAtObj(2)) {
+ _objects[0].frameIndex = 1;
+ _objects[2].kind = 0;
+ _objects[4].kind = 11;
+ _objects[4].frameIndex = 0;
+ _objects[4].ticks = _objects[4].anim->frameTicks[0];
+ } else if (!isCursorAtObj(4)) {
+ if (_objects[3].kind == 0)
+ _objects[0].frameIndex = 0;
+ _objects[4].kind = 0;
+ _objects[2].kind = 1;
+ }
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind == 11) {
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex >= obj->anim->frameCount)
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+ }
+ }
+
+ if ((mouseButtons & kLeftButtonDown) &&
+ (_objects[3].kind != 0 || _objects[4].kind != 0)) {
+ if (_objects[4].kind != 0) {
+ // Beavis
+ _playerKind = 0;
+ _playerAnim = getAnimation(0);
+ _playerSounds1 = kBeavisSounds1;
+ _playerSounds1Count = 8;
+ _playerSounds2 = kBeavisSounds2;
+ _playerSounds2Count = 13;
+ playSound(15);
+ while (isSoundPlaying(15)) { }
+ } else {
+ // Butt-head
+ _playerKind = 1;
+ _playerAnim = getAnimation(1);
+ _playerSounds1 = kButtheadSounds1;
+ _playerSounds1Count = 5;
+ _playerSounds2 = kButtheadSounds2;
+ _playerSounds2Count = 10;
+ playSound(23);
+ while (isSoundPlaying(23)) { }
+ }
+ _gameState = _fromMainGame ? kGSMainGame : kGSStandaloneGame;
+ initObjects1();
+ initObjects();
+ initVars();
+ _gameTicks = 0;
+ }
+
+ return true;
+}
+
+bool MinigameBbLoogie::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
+
+ if (--_levelTimeDelay == 0) {
+ _levelTimeDelay = 58;
+ --_levelTimeLeft;
+ }
+
+ if (!_fromMainGame && _levelTimeLeft == 0) {
+ _gameState = kGSScoreCountUp;
+ initObjects();
+ initVars();
+ } else if (_fromMainGame || _currScore < _nextLevelScore) {
+ _objects->x = CLIP(mouseX, 0, 319);
+ _objects->y = 240;
+ if (!_principalAngry &&
+ ((mouseButtons & kLeftButtonDown) || ((mouseButtons & kRightButtonDown) && _megaLoogieCount)) &&
+ _objects[0].status == 0 && mouseX != 32512 && mouseY != 32512) {
+ _objects[0].ticks = _playerAnim->frameTicks[13];
+ _objects[0].frameIndex = 14;
+ _objects[0].status = 1;
+ _objects[0].unk2 = 0;
+ Obj *newObj = getFreeObject();
+ newObj->anim = getAnimation(17);
+ newObj->frameIndex = 0;
+ newObj->ticks = 1;
+ newObj->x = 0;
+ newObj->y = 140;
+ newObj->kind = 8;
+ if (mouseButtons & kLeftButtonDown) {
+ _doubleScore = 0;
+ playSound(28);
+ } else {
+ _doubleScore = 17;
+ playSound(30);
+ }
+ }
+ updateObjs(mouseButtons);
+ } else {
+ _gameState = kGSStandaloneGame;
+ ++_level;
+ initObjects();
+ initVars();
+ }
+ return true;
+}
+
+bool MinigameBbLoogie::updateStatus2(int mouseX, int mouseY, uint mouseButtons) {
+
+ _objects[0].x = mouseX;
+
+ if (_bonusDisplayDelay1 > 0) {
+ if (--_bonusDisplayDelay1 == 0) {
+ _bonusDisplayDelay2 = 60;
+ if (_timeBonusCtr)
+ playSound(33, true);
+ }
+ } else if (_bonusDisplayDelay2 > 0) {
+ if (--_bonusDisplayDelay2 == 0) {
+ _bonusDisplayDelay3 = 150;
+ playSound(38);
+ } else if (_timeBonusCtr > 0) {
+ ++_bonusDisplayDelay2;
+ ++_levelTimeLeft;
+ if (--_timeBonusCtr == 0)
+ stopSound(33);
+ }
+ } else if (_bonusDisplayDelay3 > 0) {
+ if ((mouseButtons & kAnyButtonDown) || (--_bonusDisplayDelay3 == 0)) {
+ _dispLevelScore = _nextLevelScore;
+ _gameState = kGSMainGame;
+ _gameTicks = 0;
+ }
+ }
+ return true;
+}
+
+bool MinigameBbLoogie::updateStatus3(int mouseX, int mouseY, uint mouseButtons) {
+
+ _objects[0].x = mouseX;
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind == 2) {
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex >= obj->anim->frameCount)
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+ }
+ }
+
+ return true;
+}
+
+void MinigameBbLoogie::updateObjs(uint mouseButtons) {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ switch (obj->kind) {
+ case 1:
+ updatePlayer(i, mouseButtons);
+ break;
+ case 2:
+ updateObjKind2(i);
+ break;
+ case 3:
+ updateLoogie(i);
+ break;
+ case 4:
+ updateCar(i);
+ break;
+ case 5:
+ updateBike(i);
+ break;
+ case 6:
+ updateSquirrel(i);
+ break;
+ case 7:
+ updatePaperPlane(i);
+ break;
+ case 8:
+ updateIndicator(i);
+ break;
+ case 9:
+ updatePrincipal(i);
+ break;
+ }
+ }
+
+ if (--_carDelay == 0) {
+ // Car
+ Obj *obj = getFreeObject();
+ obj->anim = getAnimation(2);
+ obj->kind = 4;
+ obj->frameIndex = 0;
+ obj->x = 379;
+ obj->y = 22;
+ obj->xIncr = -2;
+ obj->yIncr = 0;
+ _carDelay = _vm->getRandom(256) + 800;
+ }
+
+ if (--_bikeDelay == 0) {
+ // Bike
+ Obj *obj = getFreeObject();
+ obj->kind = 5;
+ obj->anim = getAnimation(3);
+ obj->frameIndex = 0;
+ obj->x = 360;
+ obj->y = _vm->getRandom(32) + 82;
+ obj->xIncr = -1;
+ obj->yIncr = 0;
+ _bikeDelay = _vm->getRandom(512) + 500;
+ }
+
+ if (--_squirrelDelay == 0) {
+ // Squirrel
+ Obj *obj = getFreeObject();
+ obj->kind = 6;
+ obj->anim = getAnimation(7);
+ obj->frameIndex = !_squirrelDirection ? 0 : 29;
+ obj->x = 160;
+ obj->y = 36;
+ obj->xIncr = 0;
+ obj->yIncr = 0;
+ _squirrelDirection = !_squirrelDirection;
+ if (_vm->getRandom(5) == 1 && !isAnySoundPlaying(_playerSounds2, _playerSounds2Count))
+ playSound(9);
+ _squirrelDelay = _vm->getRandom(512) + 300;
+ }
+
+ if (--_paperPlaneDelay == 0) {
+ // Paper plane
+ Obj *obj = getFreeObject();
+ obj->kind = 7;
+ obj->anim = getAnimation(16);
+ obj->frameIndex = 0;
+ obj->x = 86;
+ obj->y = 187;
+ obj->xIncr = 0;
+ obj->yIncr = -1;
+ switch (_vm->getRandom(3)) {
+ case 1:
+ obj->frameIndex = 1;
+ obj->xIncr = -1;
+ break;
+ case 2:
+ obj->frameIndex = 7;
+ obj->xIncr = 1;
+ break;
+ }
+ _paperPlaneDelay = 400;
+ }
+
+ if (_principalDelay >= 0 && --_principalDelay == 0) {
+ // Principal
+ Obj *obj = getFreeObject();
+ obj->kind = 9;
+ obj->anim = getAnimation(18);
+ obj->frameIndex = 11;
+ obj->x = -20;
+ obj->y = 130;
+ obj->xIncr = 1;
+ obj->yIncr = 0;
+ obj->status = 0;
+ obj->frameIndexAdd = 0;
+ obj->unk2 = _vm->getRandom(256) + 100;
+ _principalCtr = 0;
+ _principalFirstFrameIndex = 11;
+ _principalLastFrameIndex = 16;
+ }
+
+}
+
+void MinigameBbLoogie::updatePlayer(int objIndex, uint mouseButtons) {
+
+ Obj *obj = &_objects[0];
+
+ switch (obj->status) {
+
+ case 1:
+ if (obj->ticks-- == 0) {
+ if (obj->frameIndex != 15) {
+ ++obj->frameIndex;
+ obj->ticks = _playerAnim->frameTicks[obj->frameIndex];
+ }
+ }
+ if ((((mouseButtons & kLeftButtonDown) && _doubleScore == 0) ||
+ ((mouseButtons & kRightButtonDown) && _doubleScore == 17))
+ && obj->unk2 != 61) {
+ ++obj->unk2;
+ } else {
+ obj->status = 2;
+ obj->frameIndex = 16;
+ obj->ticks = _playerAnim->frameTicks[16];
+ if (obj->unk2 >= 30) {
+ obj->status = 3;
+ obj->frameIndex = 21;
+ obj->ticks = _playerAnim->frameTicks[21];
+ }
+ if (obj->unk2 < 30) {
+ Obj *newObj = getFreeObject();
+ newObj->kind = 3;
+ newObj->anim = getAnimation(5);
+ newObj->frameIndex = 0;
+ newObj->ticks = getAnimation(5)->frameTicks[0];
+ newObj->x = obj->x;
+ newObj->y = 172;
+ newObj->unk2 = obj->unk2;
+ newObj->frameIndexAdd = _doubleScore;
+ if (_doubleScore)
+ --_megaLoogieCount;
+ }
+ if (_doubleScore) {
+ stopSound(30);
+ playSound(31);
+ } else {
+ stopSound(28);
+ playSound(29);
+ }
+ }
+ break;
+
+ case 2:
+ if (obj->ticks-- == 0) {
+ if (obj->frameIndex == 17) {
+ obj->frameIndex = 0;
+ obj->status = 0;
+ } else {
+ ++obj->frameIndex;
+ obj->ticks = _playerAnim->frameTicks[obj->frameIndex];
+ }
+ }
+ break;
+
+ case 3:
+ if (obj->ticks-- == 0) {
+ if (obj->frameIndex == 23) {
+ obj->frameIndex = 0;
+ obj->status = 0;
+ } else {
+ ++obj->frameIndex;
+ obj->ticks = _playerAnim->frameTicks[obj->frameIndex];
+ if (obj->frameIndex == 22) {
+ Obj *newObj = getFreeObject();
+ newObj->kind = 3;
+ newObj->anim = getAnimation(5);
+ newObj->frameIndex = 0;
+ newObj->ticks = getAnimation(5)->frameTicks[0];
+ newObj->x = obj->x;
+ newObj->y = 154;
+ newObj->unk2 = obj->unk2;
+ newObj->frameIndexAdd = _doubleScore;
+ if (_doubleScore)
+ --_megaLoogieCount;
+ }
+ }
+ }
+ break;
+
+ }
+
+}
+
+void MinigameBbLoogie::updateObjKind2(int objIndex) {
+
+ Obj *obj = &_objects[objIndex];
+
+ if (obj->ticks-- == 0) {
+ obj->ticks = getAnimation(4)->frameTicks[0];
+ if (obj->frameIndex > 7)
+ obj->frameIndex = 1;
+ if (obj->frameIndex++ >= 7)
+ obj->frameIndex = 0;
+ }
+
+}
+
+void MinigameBbLoogie::updateLoogie(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ if (obj->unk2 > 0) {
+ obj->y -= kLoogieOffY[obj->unk2 / 8];
+ --obj->unk2;
+ }
+
+ if (obj->ticks-- == 0) {
+ obj->ticks = getAnimation(5)->frameTicks[0];
+ ++obj->frameIndex;
+ if (obj->frameIndex >= 17) {
+ obj->kind = 0;
+ obj->anim = getAnimation(6);
+ obj->frameIndex = 0;
+ }
+ }
+
+}
+
+void MinigameBbLoogie::updateCar(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->x += obj->xIncr;
+
+ if (obj->ticks-- == 0) {
+ if (obj->frameIndex++ == 3 || obj->frameIndex == 6)
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(2)->frameTicks[obj->frameIndex];
+ }
+
+ if (obj->x <= -60) {
+ obj->kind = 0;
+ obj->anim = getAnimation(6);
+ obj->frameIndex = 0;
+ } else if (!_principalAngry && obj->frameIndex <= 3) {
+ int loogieObjIndex = 0;
+ Obj *loogieObj = findLoogieObj(loogieObjIndex++);
+ while (loogieObj) {
+ if (loogieObj->frameIndex >= 8 && loogieObj->frameIndex <= 10 && isHit(obj, loogieObj)) {
+ incNumberOfHits();
+ incScore(7);
+ loogieObj->frameIndex = 13;
+ loogieObj->ticks = getAnimation(5)->frameTicks[12];
+ obj->frameIndex = 4;
+ obj->ticks = getAnimation(2)->frameTicks[4];
+ playSound(34);
+ playRndSound();
+ }
+ loogieObj = findLoogieObj(loogieObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbLoogie::updateBike(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->x += obj->xIncr;
+
+ if (obj->ticks-- == 0) {
+ if (obj->frameIndex++ == 3 || obj->frameIndex == 7)
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(3)->frameTicks[obj->frameIndex];
+ }
+
+ if (obj->x == -40) {
+ obj->kind = 0;
+ obj->anim = getAnimation(6);
+ obj->frameIndex = 0;
+ } else if (!_principalAngry && obj->frameIndex <= 3) {
+ int loogieObjIndex = 0;
+ Obj *loogieObj = findLoogieObj(loogieObjIndex++);
+ while (loogieObj) {
+ if (loogieObj->frameIndex >= 7 && loogieObj->frameIndex <= 11 && isHit(obj, loogieObj)) {
+ incNumberOfHits();
+ incScore(2);
+ loogieObj->frameIndex = 13;
+ loogieObj->ticks = getAnimation(5)->frameTicks[12];
+ obj->frameIndex = 4;
+ obj->ticks = getAnimation(3)->frameTicks[4];
+ playSound(35);
+ playRndSound();
+ }
+ loogieObj = findLoogieObj(loogieObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbLoogie::updateSquirrel(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ if (obj->ticks-- == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 29 || obj->frameIndex == 54 ||
+ obj->frameIndex == 58 || obj->frameIndex == 62) {
+ obj->kind = 0;
+ obj->anim = getAnimation(6);
+ obj->frameIndex = 0;
+ }
+ obj->ticks = getAnimation(7)->frameTicks[obj->frameIndex];
+ }
+
+ if (!_principalAngry && obj->frameIndex <= 53) {
+ int loogieObjIndex = 0;
+ Obj *loogieObj = findLoogieObj(loogieObjIndex++);
+ while (loogieObj) {
+ if (loogieObj->frameIndex >= 7 && loogieObj->frameIndex <= 9 && isHit(obj, loogieObj)) {
+ incNumberOfHits();
+ incScore(10);
+ loogieObj->frameIndex = 13;
+ loogieObj->ticks = getAnimation(5)->frameTicks[12];
+ obj->x += kSquirrelOffX[obj->frameIndex];
+ obj->frameIndex = obj->frameIndex < 29 ? 54 : 58;
+ obj->ticks = getAnimation(7)->frameTicks[obj->frameIndex];
+ playSound(36);
+ playRndSound();
+ }
+ loogieObj = findLoogieObj(loogieObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbLoogie::updatePaperPlane(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+
+ if (obj->x == -16 || obj->x == 336 || obj->y == -16) {
+ obj->kind = 0;
+ obj->anim = getAnimation(6);
+ obj->frameIndex = 0;
+ }
+
+ if (!_principalAngry && obj->frameIndex <= 53) {
+ int loogieObjIndex = 0;
+ Obj *loogieObj = findLoogieObj(loogieObjIndex++);
+ while (loogieObj) {
+ if (loogieObj->frameIndex >= 4 && loogieObj->frameIndex <= 7 && isHit(obj, loogieObj)) {
+ incNumberOfHits();
+ incScore(5);
+ loogieObj->frameIndex = 13;
+ loogieObj->ticks = getAnimation(5)->frameTicks[12];
+ obj->frameIndex = (obj->frameIndex + 1) % 8;
+ obj->xIncr = kPlaneOffX[obj->frameIndex];
+ obj->yIncr = kPlaneOffY[obj->frameIndex];
+ playSound(37);
+ playRndSound();
+ }
+ loogieObj = findLoogieObj(loogieObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbLoogie::updateIndicator(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+ Obj *loogieObj = &_objects[0];
+
+ if (obj->ticks-- == 0) {
+ obj->frameIndex = (obj->frameIndex + 1) % 2;
+ obj->ticks = getAnimation(17)->frameTicks[0];
+ }
+
+ if (loogieObj->status != 0) {
+ int unk2mod = loogieObj->unk2 / 8;
+ int unk2div = loogieObj->unk2 / 8 * 8;
+ int v6 = 0;
+ if (unk2div >= 8) {
+ int v7 = 1;
+ if (unk2div != 8) {
+ do {
+ v6 += 8 * kLoogieOffY[v7++];
+ } while (v7 != unk2mod);
+ }
+ }
+ int yOfs = (loogieObj->unk2 % 8 + 1) * kLoogieOffY[loogieObj->unk2 / 8] + v6;
+ if (loogieObj->unk2 >= 30)
+ yOfs += 18;
+ obj->y = 140 - yOfs;
+ } else {
+ obj->kind = 0;
+ obj->anim = getAnimation(6);
+ }
+
+}
+
+void MinigameBbLoogie::updatePrincipal(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->status) {
+
+ case 0:
+ if (obj->unk2--) {
+ if (obj->ticks-- == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == _principalLastFrameIndex)
+ obj->frameIndex = _principalFirstFrameIndex;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ ++_principalCtr;
+ if (_principalCtr % 2 != 0) {
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+ if (obj->xIncr > 0 && obj->x == 340) {
+ obj->xIncr = -1;
+ _principalLastFrameIndex = 34;
+ _principalFirstFrameIndex = 29;
+ obj->frameIndex = 29;
+ obj->status = 2;
+ obj->ticks = _vm->getRandom(256) + 60;
+ }
+ if (obj->xIncr < 0 && obj->x == -20) {
+ obj->xIncr = 1;
+ _principalLastFrameIndex = 16;
+ _principalFirstFrameIndex = 11;
+ obj->frameIndex = 11;
+ obj->status = 2;
+ obj->ticks = _vm->getRandom(256) + 60;
+ }
+ }
+ } else {
+ obj->unk2 = _vm->getRandom(64) + 20;
+ ++obj->status;
+ if (_vm->getRandom(2) == 1) {
+ obj->frameIndex = _principalFirstFrameIndex < 11 ? 17 : 26;
+ _principalFirstFrameIndex = 19;
+ } else {
+ obj->frameIndex = _principalFirstFrameIndex < 11 ? 8 : 35;
+ _principalFirstFrameIndex = 1;
+ }
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ break;
+
+ case 1:
+ if (obj->unk2--) {
+ if (obj->ticks-- == 0)
+ obj->frameIndex = _principalFirstFrameIndex;
+ } else {
+ obj->unk2 = _vm->getRandom(256) + 100;
+ ++obj->status;
+ if (_vm->getRandom(2) == 1) {
+ _principalLastFrameIndex = 16;
+ _principalFirstFrameIndex = 11;
+ obj->frameIndex = obj->frameIndex < 1 ? 8 : 17;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ obj->xIncr = 1;
+ } else {
+ _principalLastFrameIndex = 34;
+ _principalFirstFrameIndex = 29;
+ obj->frameIndex = obj->frameIndex < 1 ? 35 : 26;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ obj->xIncr = -1;
+ }
+ }
+ break;
+
+ case 2:
+ if (obj->ticks-- == 0) {
+ obj->status = 0;
+ obj->frameIndex = _principalFirstFrameIndex;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ break;
+
+ case 3:
+ if (obj->ticks-- == 0) {
+ obj->status = _prevPrincipalStatus;
+ obj->frameIndex = _principalFirstFrameIndex;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ break;
+
+ case 4:
+ if (obj->ticks-- == 0) {
+ switch (obj->frameIndex) {
+ case 8:
+ obj->frameIndex = 36;
+ break;
+ case 26:
+ obj->frameIndex = 28;
+ break;
+ case 28:
+ obj->frameIndex = 35;
+ break;
+ case 35:
+ ++obj->frameIndex;
+ break;
+ case 36:
+ obj->status = 5;
+ ++obj->frameIndex;
+ break;
+ }
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ break;
+
+ case 5:
+ if (obj->ticks-- == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 48)
+ obj->frameIndex = 36;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ if (!isSoundPlaying(1)) {
+ _gameResult = 1;
+ if (_fromMainGame) {
+ _principalAngry = true;
+ if (obj->x <= 140 || obj->x >= 165) {
+ obj->status = 6;
+ if (obj->x >= 160) {
+ _principalLastFrameIndex = 34;
+ _principalFirstFrameIndex = 29;
+ obj->frameIndex = 29;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ obj->xIncr = -1;
+ } else {
+ _principalLastFrameIndex = 16;
+ _principalFirstFrameIndex = 11;
+ obj->frameIndex = 11;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ obj->xIncr = 1;
+ }
+ } else {
+ obj->status = 7;
+ _principalFirstFrameIndex = 2;
+ _principalLastFrameIndex = 7;
+ obj->frameIndex = 2;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ obj->xIncr = 0;
+ obj->yIncr = 1;
+ }
+ } else {
+ obj->status = _prevPrincipalStatus;
+ obj->frameIndex = _principalFirstFrameIndex;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ }
+ break;
+
+ case 6:
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+ if (obj->ticks-- == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == _principalLastFrameIndex)
+ obj->frameIndex = _principalFirstFrameIndex;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ if (obj->x > 145 && obj->x < 160) {
+ obj->status = 7;
+ _principalFirstFrameIndex = 2;
+ _principalLastFrameIndex = 7;
+ obj->frameIndex = 2;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ obj->xIncr = 0;
+ obj->yIncr = 1;
+ }
+ break;
+
+ case 7:
+ obj->x += obj->xIncr;
+ obj->y += obj->yIncr;
+ if (obj->ticks-- == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == _principalLastFrameIndex)
+ obj->frameIndex = _principalFirstFrameIndex;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ }
+ if (obj->y > 175) {
+ // Angry principal enters school, end the minigame
+ _gameDone = true;
+ }
+ break;
+
+ }
+
+ if (!_principalAngry) {
+ int loogieObjIndex = 0;
+ Obj *loogieObj = findLoogieObj(loogieObjIndex++);
+ while (loogieObj) {
+ if (loogieObj->frameIndex >= 7 && loogieObj->frameIndex <= 12 && isHit(obj, loogieObj)) {
+ incNumberOfHits();
+ incScore(1);
+ loogieObj->frameIndex = 13;
+ loogieObj->ticks = getAnimation(5)->frameTicks[12];
+ if (obj->status != 3 && obj->status != 4 && obj->status != 5) {
+ _prevPrincipalStatus = obj->status;
+ obj->status = 3;
+ if (_principalFirstFrameIndex == 1 || _principalFirstFrameIndex == 19)
+ obj->frameIndex = _principalFirstFrameIndex - 1;
+ else
+ obj->frameIndex = _principalFirstFrameIndex - 2;
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ if (loogieObj->frameIndexAdd > 0) {
+ obj->status = 4;
+ switch (obj->frameIndex) {
+ case 0:
+ obj->frameIndex = 36;
+ break;
+ case 9:
+ obj->frameIndex = 8;
+ break;
+ case 27:
+ obj->frameIndex = 35;
+ break;
+ case 18:
+ obj->frameIndex = 26;
+ break;
+ }
+ obj->ticks = getAnimation(18)->frameTicks[obj->frameIndex];
+ playSound(1);
+ } else {
+ if (!isAnySoundPlaying(_playerSounds2, _playerSounds2Count))
+ playSound(kPrincipalSounds[_vm->getRandom(4)]);
+ playRndSound();
+ }
+ }
+ }
+ loogieObj = findLoogieObj(loogieObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbLoogie::incNumberOfHits() {
+ ++_numberOfHits;
+ if (_numberOfHits == 1000)
+ _numberOfHits = 0;
+ if (_numberOfHits % 10 == 0) {
+ ++_megaLoogieCount;
+ if (_megaLoogieCount > 11)
+ _megaLoogieCount = 11;
+ }
+}
+
+void MinigameBbLoogie::incScore(int incrAmount) {
+ if (_doubleScore)
+ _currScore += 2 * incrAmount;
+ else
+ _currScore += incrAmount;
+}
+
+void MinigameBbLoogie::playRndSound() {
+ if (!isAnySoundPlaying(_playerSounds2, _playerSounds2Count))
+ playSound(_playerSounds1[_vm->getRandom(_playerSounds1Count)]);
+}
+
+int MinigameBbLoogie::run(bool fromMainGame) {
+
+ memset(_objects, 0, sizeof(_objects));
+
+ _numbersAnim = getAnimation(9);
+
+ _backgroundSpriteIndex = 210;
+ _titleScreenSpriteIndex = 211;
+
+ _fromMainGame = fromMainGame;
+
+ _hiScore = 0;
+ if (!_fromMainGame)
+ _hiScore = loadHiscore(kMinigameBbLoogie);
+
+ _gameState = kGSTitleScreen;
+ _gameTicks = 0;
+ _gameResult = 0;
+ _gameDone = false;
+ initObjects();
+ initVars();
+
+ _spriteModule = new SpriteModule();
+ _spriteModule->load("bbloogie/bbloogie.000");
+
+ Palette palette = _spriteModule->getPalette();
+ _vm->_screen->setPalette(palette);
+
+ loadSounds();
+
+ playSound(32, true);
+
+ while (!_vm->shouldQuit() &&!_gameDone) {
+ _vm->updateEvents();
+ update();
+ }
+
+ _vm->_sound->unloadSounds();
+
+ if (!_fromMainGame)
+ saveHiscore(kMinigameBbLoogie, _hiScore);
+
+ delete _spriteModule;
+
+ return _gameResult;
+}
+
+void MinigameBbLoogie::update() {
+
+ int currTicks, inputTicks;
+
+ if (_gameTicks > 0) {
+ currTicks = _vm->_system->getMillis();
+ inputTicks = (currTicks - _gameTicks) / 17;
+ _gameTicks = currTicks - (currTicks - _gameTicks) % 17;
+ } else {
+ inputTicks = 1;
+ _gameTicks = _vm->_system->getMillis();
+ }
+
+ if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
+ _gameDone = true;
+ return;
+ }
+
+ if (inputTicks == 0)
+ return;
+
+ bool done;
+
+ do {
+ done = !updateStatus(_vm->_mouseX, _vm->_mouseY, _vm->_mouseButtons);
+ _vm->_mouseButtons &= ~kLeftButtonClicked;
+ _vm->_mouseButtons &= ~kRightButtonClicked;
+ _vm->_keyCode = Common::KEYCODE_INVALID;
+ } while (--inputTicks && _gameTicks > 0 && !done);
+
+ drawSprites();
+
+ _vm->_system->delayMillis(10);
+
+}
+
+void MinigameBbLoogie::loadSounds() {
+ for (uint i = 0; i < kSoundFilenamesCount; ++i) {
+ Common::String filename = Common::String::format("bbloogie/%s", kSoundFilenames[i]);
+ _vm->_sound->loadSound(filename.c_str());
+ }
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbloogie.h b/engines/bbvs/minigames/bbloogie.h
new file mode 100644
index 0000000000..6c4ece3269
--- /dev/null
+++ b/engines/bbvs/minigames/bbloogie.h
@@ -0,0 +1,141 @@
+/* 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 BBVS_MINIGAMES_BBLOOGIE_H
+#define BBVS_MINIGAMES_BBLOOGIE_H
+
+#include "bbvs/minigames/minigame.h"
+
+namespace Bbvs {
+
+class MinigameBbLoogie : public Minigame {
+public:
+ MinigameBbLoogie(BbvsEngine *vm) : Minigame(vm) {};
+ int run(bool fromMainGame);
+public:
+
+ struct Obj {
+ int kind;
+ int x, y;
+ int xIncr, yIncr;
+ const ObjAnimation *anim;
+ int frameIndex;
+ int ticks;
+ int status;
+ int16 frameIndexAdd;
+ int16 unk2;
+ };
+
+ enum {
+ kMaxObjectsCount = 256
+ };
+
+ enum {
+ kGSTitleScreen = 0, // Title screen
+ kGSMainGame = 1, // Game when called as part of the main game
+ kGSStandaloneGame = 2, // Game when called as standalone game
+ kGSScoreCountUp = 3 // Score countup and next level text
+ };
+
+ Obj _objects[kMaxObjectsCount];
+
+ int _playerKind;
+ const ObjAnimation *_playerAnim;
+ const uint *_playerSounds1, *_playerSounds2;
+ uint _playerSounds1Count, _playerSounds2Count;
+
+ int _level, _levelTimeLeft, _levelTimeDelay;
+ int _numberOfHits, _currScore, _hiScore;
+ int _doubleScore, _megaLoogieCount;
+
+ int _dispLevelScore, _nextLevelScore;
+
+ int _timeBonusCtr, _bonusDisplayDelay1, _bonusDisplayDelay2, _bonusDisplayDelay3;
+
+ int _carDelay;
+ int _bikeDelay;
+ int _squirrelDelay;
+ bool _squirrelDirection;
+ int _paperPlaneDelay;
+ int _principalDelay;
+
+ int _prevPrincipalStatus;
+ int _principalCtr, _principalFirstFrameIndex, _principalLastFrameIndex;
+ bool _principalAngry;
+
+ const ObjAnimation *getAnimation(int animIndex);
+
+ void buildDrawList(DrawList &drawList);
+ void buildDrawList0(DrawList &drawList);
+ void buildDrawList1(DrawList &drawList);
+ void buildDrawList2(DrawList &drawList);
+ void buildDrawList3(DrawList &drawList);
+
+ void drawSprites();
+
+ void initObjs();
+ Obj *getFreeObject();
+ Obj *findLoogieObj(int startObjIndex);
+ bool isHit(Obj *obj1, Obj *obj2);
+ bool isCursorAtObj(int objIndex);
+
+ void initObjects();
+ void initObjects0();
+ void initObjects1();
+ void initObjects3();
+
+ void initVars();
+ void initVars0();
+ void initVars1();
+ void initVars2();
+ void initVars3();
+
+ bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus2(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus3(int mouseX, int mouseY, uint mouseButtons);
+
+ void updateObjs(uint mouseButtons);
+ void updatePlayer(int objIndex, uint mouseButtons);
+ void updateObjKind2(int objIndex);
+ void updateLoogie(int objIndex);
+ void updateCar(int objIndex);
+ void updateBike(int objIndex);
+ void updateSquirrel(int objIndex);
+ void updatePaperPlane(int objIndex);
+ void updateIndicator(int objIndex);
+ void updatePrincipal(int objIndex);
+
+ void incNumberOfHits();
+ void incScore(int incrAmount);
+ void playRndSound();
+
+ void update();
+
+ void loadSounds();
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_MINIGAMES_BBLOOGIE_H
diff --git a/engines/bbvs/minigames/bbloogie_anims.cpp b/engines/bbvs/minigames/bbloogie_anims.cpp
new file mode 100644
index 0000000000..a82be8a279
--- /dev/null
+++ b/engines/bbvs/minigames/bbloogie_anims.cpp
@@ -0,0 +1,138 @@
+/* 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 "bbvs/minigames/bbloogie.h"
+
+namespace Bbvs {
+
+static const int kAnim0FrameIndices[] = {0, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 0, 5, 6, 7, 0, 0, 5, 6, 7, 8, 0, 4, 3, 2, 1, 4, 3, 2, 1, 4, 3, 2, 1, 0};
+static const int16 kAnim0FrameTicks[] = {22, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 20, 8, 8, 10, 10, 10, 8, 22, 6, 12, 20, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 22};
+static const BBRect kAnim0FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim1FrameIndices[] = {9, 10, 11, 12, 13, 10, 11, 12, 13, 10, 11, 12, 13, 9, 14, 15, 16, 9, 9, 14, 15, 16, 17, 9, 13, 12, 11, 10, 13, 12, 11, 10, 13, 12, 11, 10, 9};
+static const int16 kAnim1FrameTicks[] = {22, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 20, 8, 8, 10, 10, 10, 8, 22, 6, 12, 20, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 22};
+static const BBRect kAnim1FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim2FrameIndices[] = {18, 19, 20, 18, 21, 22};
+static const int16 kAnim2FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim2FrameRects[] = {{-45, -43, 86, 38}, {-45, -43, 86, 38}, {-45, -43, 86, 38}, {-45, -43, 86, 38}, {-45, -43, 86, 38}, {-45, -43, 86, 38}};
+static const int kAnim3FrameIndices[] = {23, 24, 25, 26, 27, 28, 27};
+static const int16 kAnim3FrameTicks[] = {6, 6, 6, 6, 6, 7, 6};
+static const BBRect kAnim3FrameRects[] = {{-24, -17, 48, 14}, {-24, -17, 48, 14}, {-24, -17, 48, 14}, {-24, -17, 48, 14}, {-24, -17, 48, 14}, {-24, -17, 48, 14}, {-24, -17, 48, 14}};
+static const int kAnim4FrameIndices[] = {29, 30, 31, 32, 33, 34, 35, 36};
+static const int16 kAnim4FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim4FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim5FrameIndices[] = {37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70};
+static const int16 kAnim5FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim5FrameRects[] = {{-1, -11, 4, 11}, {-2, -15, 6, 8}, {-3, -24, 8, 8}, {-3, -31, 7, 9}, {-3, -33, 8, 8}, {-3, -34, 8, 10}, {-2, -34, 7, 8}, {-1, -34, 6, 7}, {-1, -34, 5, 6}, {-1, -34, 4, 4}, {0, -34, 3, 4}, {-1, -34, 4, 3}, {0, -34, 3, 4}, {0, -33, 3, 3}, {-1, -35, 5, 5}, {-3, -37, 9, 9}, {-4, -39, 12, 13}, {-3, -11, 7, 8}, {-3, -15, 8, 9}, {-5, -24, 11, 13}, {-4, -31, 10, 13}, {-5, -34, 11, 13}, {-5, -34, 11, 11}, {-4, -34, 9, 10}, {-4, -34, 9, 9}, {-3, -34, 7, 8}, {-2, -34, 6, 7}, {-2, -34, 5, 6}, {-2, -34, 4, 5}, {-7, -38, 13, 13}, {-10, -44, 22, 22}, {-13, -47, 27, 27}, {-17, -49, 32, 30}, {-17, -50, 34, 33}};
+static const int kAnim6FrameIndices[] = {71};
+static const int16 kAnim6FrameTicks[] = {1};
+static const BBRect kAnim6FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim7FrameIndices[] = {72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 80, 79, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 110, 109, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129};
+static const int16 kAnim7FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 30, 6, 20, 6, 30, 6, 6, 6, 6, 6, 6, 6, 6, 6, 30, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 30, 6, 20, 6, 30, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim7FrameRects[] = {{-46, -6, 7, 6}, {-46, -12, 11, 12}, {-47, -15, 17, 15}, {-46, -14, 20, 12}, {-47, -10, 24, 10}, {-41, -11, 22, 11}, {-33, -10, 15, 10}, {-32, -10, 14, 10}, {-32, -9, 13, 9}, {-32, -9, 13, 9}, {-32, -9, 13, 9}, {-32, -10, 13, 10}, {-34, -11, 24, 11}, {-30, -12, 25, 9}, {-24, -10, 24, 10}, {-18, -11, 22, 11}, {-14, -11, 24, 10}, {-9, -12, 25, 9}, {-3, -10, 24, 10}, {4, -11, 22, 11}, {11, -10, 15, 10}, {12, -10, 13, 10}, {10, -11, 24, 11}, {15, -12, 25, 9}, {22, -16, 22, 16}, {34, -16, 9, 16}, {35, -12, 9, 12}, {38, -6, 6, 6}, {38, -6, 4, 4}, {36, -6, 7, 6}, {31, -12, 12, 12}, {27, -15, 17, 15}, {24, -12, 20, 12}, {19, -11, 22, 11}, {13, -11, 24, 11}, {7, -11, 25, 9}, {4, -10, 24, 10}, {1, -11, 22, 11}, {1, -10, 15, 10}, {2, -10, 13, 10}, {2, -10, 13, 10}, {2, -9, 13, 9}, {2, -10, 13, 10}, {2, -10, 13, 10}, {-7, -11, 24, 11}, {-14, -11, 25, 9}, {-21, -10, 24, 11}, {-27, -11, 23, 11}, {-34, -12, 24, 11}, {-44, -18, 22, 16}, {-44, -16, 9, 16}, {-46, -12, 9, 12}, {-45, -6, 7, 6}, {-45, -4, 6, 5}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim8FrameIndices[] = {130};
+static const int16 kAnim8FrameTicks[] = {6};
+static const BBRect kAnim8FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim9FrameIndices[] = {131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141};
+static const int16 kAnim9FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim9FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim10FrameIndices[] = {142};
+static const int16 kAnim10FrameTicks[] = {2};
+static const BBRect kAnim10FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim11FrameIndices[] = {143};
+static const int16 kAnim11FrameTicks[] = {1};
+static const BBRect kAnim11FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim12FrameIndices[] = {144};
+static const int16 kAnim12FrameTicks[] = {1};
+static const BBRect kAnim12FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim13FrameIndices[] = {145};
+static const int16 kAnim13FrameTicks[] = {1};
+static const BBRect kAnim13FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim14FrameIndices[] = {146};
+static const int16 kAnim14FrameTicks[] = {1};
+static const BBRect kAnim14FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim15FrameIndices[] = {147};
+static const int16 kAnim15FrameTicks[] = {1};
+static const BBRect kAnim15FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim16FrameIndices[] = {148, 149, 150, 151, 152, 153, 154, 155};
+static const int16 kAnim16FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim16FrameRects[] = {{-5, -5, 9, 9}, {-6, -5, 11, 11}, {-6, -4, 9, 9}, {-5, -5, 10, 10}, {-5, -3, 9, 9}, {-6, -5, 10, 10}, {-4, -4, 9, 9}, {-6, -4, 10, 10}};
+static const int kAnim17FrameIndices[] = {156, 157};
+static const int16 kAnim17FrameTicks[] = {6, 6};
+static const BBRect kAnim17FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim18FrameIndices[] = {158, 159, 160, 161, 160, 162, 163, 162, 164, 165, 166, 167, 168, 167, 169, 170, 169, 171, 172, 173, 174, 175, 174, 176, 177, 176, 178, 179, 180, 181, 182, 181, 183, 184, 183, 185, 186, 187, 188, 189, 190, 188, 189, 191, 188, 190, 189, 187, 186};
+static const int16 kAnim18FrameTicks[] = {10, 20, 8, 8, 8, 8, 8, 8, 6, 10, 20, 8, 8, 8, 8, 8, 8, 6, 10, 20, 8, 8, 8, 8, 8, 8, 6, 10, 20, 8, 8, 8, 8, 8, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim18FrameRects[] = {{-13, -16, 26, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-10, -19, 18, 20}, {-8, -20, 15, 23}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-10, -18, 19, 20}, {-12, -17, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-12, -16, 24, 16}, {-10, -18, 20, 19}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-8, -20, 16, 22}, {-9, -19, 18, 20}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}, {-12, -17, 24, 17}};
+static const int kAnim19FrameIndices[] = {192};
+static const int16 kAnim19FrameTicks[] = {8};
+static const BBRect kAnim19FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim20FrameIndices[] = {193};
+static const int16 kAnim20FrameTicks[] = {5};
+static const BBRect kAnim20FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim21FrameIndices[] = {194};
+static const int16 kAnim21FrameTicks[] = {6};
+static const BBRect kAnim21FrameRects[] = {{-7, -80, 17, 81}};
+static const int kAnim22FrameIndices[] = {195, 196, 197, 198, 199, 200};
+static const int16 kAnim22FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim22FrameRects[] = {{-22, -91, 45, 93}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}};
+static const int kAnim23FrameIndices[] = {201};
+static const int16 kAnim23FrameTicks[] = {6};
+static const BBRect kAnim23FrameRects[] = {{-12, -75, 21, 75}};
+static const int kAnim24FrameIndices[] = {202, 203, 204, 205, 206, 207};
+static const int16 kAnim24FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim24FrameRects[] = {{-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}};
+static const int kAnim25FrameIndices[] = {208, 209};
+static const int16 kAnim25FrameTicks[] = {6, 6};
+static const BBRect kAnim25FrameRects[] = {{-9, -9, 17, 15}, {-11, -10, 19, 16}};
+static const ObjAnimation kAnimations[] = {
+ {37, kAnim0FrameIndices, kAnim0FrameTicks, kAnim0FrameRects},
+ {37, kAnim1FrameIndices, kAnim1FrameTicks, kAnim1FrameRects},
+ {6, kAnim2FrameIndices, kAnim2FrameTicks, kAnim2FrameRects},
+ {7, kAnim3FrameIndices, kAnim3FrameTicks, kAnim3FrameRects},
+ {8, kAnim4FrameIndices, kAnim4FrameTicks, kAnim4FrameRects},
+ {34, kAnim5FrameIndices, kAnim5FrameTicks, kAnim5FrameRects},
+ {1, kAnim6FrameIndices, kAnim6FrameTicks, kAnim6FrameRects},
+ {62, kAnim7FrameIndices, kAnim7FrameTicks, kAnim7FrameRects},
+ {1, kAnim8FrameIndices, kAnim8FrameTicks, kAnim8FrameRects},
+ {11, kAnim9FrameIndices, kAnim9FrameTicks, kAnim9FrameRects},
+ {1, kAnim10FrameIndices, kAnim10FrameTicks, kAnim10FrameRects},
+ {1, kAnim11FrameIndices, kAnim11FrameTicks, kAnim11FrameRects},
+ {1, kAnim12FrameIndices, kAnim12FrameTicks, kAnim12FrameRects},
+ {1, kAnim13FrameIndices, kAnim13FrameTicks, kAnim13FrameRects},
+ {1, kAnim14FrameIndices, kAnim14FrameTicks, kAnim14FrameRects},
+ {1, kAnim15FrameIndices, kAnim15FrameTicks, kAnim15FrameRects},
+ {8, kAnim16FrameIndices, kAnim16FrameTicks, kAnim16FrameRects},
+ {2, kAnim17FrameIndices, kAnim17FrameTicks, kAnim17FrameRects},
+ {49, kAnim18FrameIndices, kAnim18FrameTicks, kAnim18FrameRects},
+ {1, kAnim19FrameIndices, kAnim19FrameTicks, kAnim19FrameRects},
+ {1, kAnim20FrameIndices, kAnim20FrameTicks, kAnim20FrameRects},
+ {1, kAnim21FrameIndices, kAnim21FrameTicks, kAnim21FrameRects},
+ {6, kAnim22FrameIndices, kAnim22FrameTicks, kAnim22FrameRects},
+ {1, kAnim23FrameIndices, kAnim23FrameTicks, kAnim23FrameRects},
+ {6, kAnim24FrameIndices, kAnim24FrameTicks, kAnim24FrameRects},
+ {2, kAnim25FrameIndices, kAnim25FrameTicks, kAnim25FrameRects}
+};
+
+const ObjAnimation *MinigameBbLoogie::getAnimation(int animIndex) {
+ return &kAnimations[animIndex];
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbtennis.cpp b/engines/bbvs/minigames/bbtennis.cpp
new file mode 100644
index 0000000000..aa9e2c2ae2
--- /dev/null
+++ b/engines/bbvs/minigames/bbtennis.cpp
@@ -0,0 +1,1274 @@
+/* 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 "bbvs/sound.h"
+#include "bbvs/minigames/bbtennis.h"
+
+namespace Bbvs {
+
+static const int kLeftPlayerOffX[] = {
+ -44, -44, -44, -44, -39, -39, -34,
+ -26, -26, -14, -6, -6, -6, -6
+};
+
+static const int kLeftPlayerOffY[] = {
+ -31, -31, -31, -31, -23, -23, -21,
+ -18, -18, -14, -11, -11, -11, -11
+};
+
+static const char * const kSoundFilenames[] = {
+ "tenis9.aif", "tenis10.aif", "tenis11.aif", "tenis12.aif", "tenis13.aif",
+ "tenis14.aif", "tenis15.aif", "tenis16.aif", "tenis17.aif", "tenis18.aif",
+ "tenis19.aif", "tenis20.aif", "tenis21.aif", "1ahh.aif", "1dammit.aif",
+ "1getawy.aif", "1getthem.aif", "1owww.aif", "1pardon.aif", "1rcktbll.aif",
+ "1yourout.aif", "2hey.aif", "2inhere.aif", "2stoptht.aif", "2theyare.aif",
+ "3oh.aif", "3ow.aif", "3upunks.aif", "tenismus.aif", "canon1.aif",
+ "canon2.aif"
+};
+
+static const uint kSoundFilenamesCount = ARRAYSIZE(kSoundFilenames);
+
+static const int kLeftNetPlayAnims[] = {
+ 13, 15, 17
+};
+
+static const int kRightNetPlayAnims[] = {
+ 14, 16, 18
+};
+
+static const uint kYuppieHitSounds[] = {
+ 14, 15, 18, 22, 26, 27
+};
+
+static const uint kYuppieEnteringCourtSounds[] = {
+ 19, 20
+};
+
+static const uint kYuppieChargeSounds[] = {
+ 16, 17, 23, 24, 28, 0
+};
+
+static const uint kAllSounds[] = {
+ 3, 4, 7, 9, 19, 20, 16, 17, 23, 24, 28
+};
+
+void MinigameBbTennis::buildDrawList(DrawList &drawList) {
+ switch (_gameState) {
+ case 0:
+ buildDrawList0(drawList);
+ break;
+ case 1:
+ buildDrawList1(drawList);
+ break;
+ case 2:
+ buildDrawList2(drawList);
+ break;
+ }
+}
+
+void MinigameBbTennis::buildDrawList0(DrawList &drawList) {
+
+ drawList.add(_objects[0].anim->frameIndices[_objects[0].frameIndex], _objects[0].x, _objects[0].y, 2000);
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
+ }
+
+ if (_titleScreenSpriteIndex > 0)
+ drawList.add(_titleScreenSpriteIndex, 0, 0, 0);
+
+}
+
+void MinigameBbTennis::buildDrawList1(DrawList &drawList) {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+
+ if (obj->kind) {
+ int index = obj->anim->frameIndices[obj->frameIndex];
+ int x = obj->x;
+ int y = obj->y;
+ int priority = obj->y + 16;
+
+ switch (obj->kind) {
+
+ case 1:
+ priority = 3000;
+ break;
+
+ case 2:
+ priority = 550;
+ if (obj->frameIndex == 0)
+ drawList.add(obj->anim->frameIndices[8], obj->x, obj->y, 550);
+ break;
+
+ case 6:
+ if (obj->frameIndex == 31) {
+ y = 640;
+ index = obj->anim->frameIndices[26];
+ }
+ if (obj->status == 4) {
+ --obj->blinkCtr;
+ if (obj->blinkCtr % 2)
+ y = 600;
+ if (obj->blinkCtr == 0)
+ obj->kind = 0;
+ }
+ break;
+
+ case 7:
+ priority = 540;
+ if (obj->frameIndex == 0)
+ drawList.add(obj->anim->frameIndices[8], obj->x, obj->y, 550);
+ break;
+
+ case 4:
+ if (obj->status == 8) {
+ --obj->blinkCtr;
+ if (obj->blinkCtr % 2)
+ y = 600;
+ if (obj->blinkCtr == 0)
+ obj->kind = 0;
+ }
+ break;
+
+ }
+
+ drawList.add(index, x, y, priority);
+
+ }
+ }
+
+ if (_rapidFireBallsCount > 0) {
+ drawList.add(getAnimation(19)->frameIndices[0], 24, 208, 990);
+ drawList.add(getAnimation(20)->frameIndices[_rapidFireBallsCount / 10 % 10], 19, 198, 2000);
+ drawList.add(getAnimation(20)->frameIndices[_rapidFireBallsCount % 10], 29, 198, 2000);
+
+ }
+
+ if (_backgroundSpriteIndex > 0)
+ drawList.add(_backgroundSpriteIndex, 0, 0, 0);
+
+ drawList.add(getAnimation(8)->frameIndices[0], 9, 53, 500);
+ drawList.add(getAnimation(9)->frameIndices[0], 256, 52, 500);
+ drawList.add(getAnimation(10)->frameIndices[0], 60, 162, 500);
+ drawList.add(getAnimation(21)->frameIndices[0], 36, 18, 2000);
+
+ drawNumber(drawList, _score, 70, 18);
+
+ for (int i = 0; i < _numHearts; ++i)
+ drawList.add(getAnimation(7)->frameIndices[0], 20 + i * 20, 236, 990);
+
+}
+
+void MinigameBbTennis::buildDrawList2(DrawList &drawList) {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind)
+ drawList.add(obj->anim->frameIndices[obj->frameIndex], obj->x, obj->y, obj->y + 16);
+ }
+
+ if (_backgroundSpriteIndex > 0)
+ drawList.add(_backgroundSpriteIndex, 0, 0, 0);
+
+ drawList.add(getAnimation(21)->frameIndices[0], 36, 18, 2000);
+
+ drawNumber(drawList, _score, 70, 18);
+
+ drawList.add(getAnimation(22)->frameIndices[0], 120, 70, 2000);
+ drawList.add(getAnimation(23)->frameIndices[0], 95, 95, 2000);
+
+ drawNumber(drawList, _hiScore, 210, 109);
+
+}
+
+void MinigameBbTennis::drawSprites() {
+ DrawList drawList;
+ buildDrawList(drawList);
+ _vm->_screen->drawDrawList(drawList, _spriteModule);
+ _vm->_screen->copyToScreen();
+}
+
+void MinigameBbTennis::initObjs() {
+ for (int i = 0; i < kMaxObjectsCount; ++i)
+ _objects[i].kind = 0;
+}
+
+MinigameBbTennis::Obj *MinigameBbTennis::getFreeObject() {
+ for (int i = 0; i < kMaxObjectsCount; ++i)
+ if (_objects[i].kind == 0)
+ return &_objects[i];
+ return 0;
+}
+
+MinigameBbTennis::Obj *MinigameBbTennis::findTennisBall(int startObjIndex) {
+ for (int i = startObjIndex; i < kMaxObjectsCount; ++i)
+ if (_objects[i].kind == 2)
+ return &_objects[i];
+ return 0;
+}
+
+bool MinigameBbTennis::isHit(Obj *obj1, Obj *obj2) {
+ const BBRect &frameRect1 = obj1->anim->frameRects[obj1->frameIndex];
+ const BBRect &frameRect2 = obj2->anim->frameRects[obj2->frameIndex];
+ const int obj1X1 = obj1->x + frameRect1.x;
+ const int obj1Y1 = obj1->y + frameRect1.y;
+ const int obj1X2 = obj1X1 + frameRect1.width;
+ const int obj1Y2 = obj1Y1 + frameRect1.height;
+ const int obj2X1 = obj2->x + frameRect2.x;
+ const int obj2Y1 = obj2->y + frameRect2.y;
+ const int obj2X2 = obj2X1 + frameRect2.width;
+ const int obj2Y2 = obj2Y1 + frameRect2.height;
+ return obj1X1 <= obj2X2 && obj1X2 >= obj2X1 && obj1Y1 <= obj2Y2 && obj1Y2 >= obj2Y1;
+}
+
+void MinigameBbTennis::initObjects() {
+ switch (_gameState) {
+ case 0:
+ initObjects0();
+ break;
+ case 1:
+ initObjects1();
+ break;
+ case 2:
+ initObjects2();
+ break;
+ }
+}
+
+void MinigameBbTennis::initObjects0() {
+ _objects[0].anim = getAnimation(24);
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = getAnimation(24)->frameTicks[0];
+ _objects[0].x = 160;
+ _objects[0].y = 100;
+ _objects[0].kind = 1;
+ _objects[1].anim = getAnimation(25);
+ _objects[1].frameIndex = 0;
+ _objects[1].ticks = getAnimation(25)->frameTicks[0];
+ _objects[1].x = 40;
+ _objects[1].y = 240;
+ _objects[1].kind = 2;
+ _objects[2].anim = getAnimation(26);
+ _objects[2].frameIndex = 0;
+ _objects[2].ticks = getAnimation(26)->frameTicks[0];
+ _objects[2].x = 280;
+ _objects[2].y = 240;
+ _objects[2].kind = 2;
+}
+
+void MinigameBbTennis::initObjects1() {
+ _objects[0].anim = getAnimation(5);
+ _objects[0].frameIndex = 0;
+ _objects[0].ticks = getAnimation(5)->frameTicks[0];
+ _objects[0].status = 0;
+ _objects[0].x = 160;
+ _objects[0].y = 100;
+ _objects[0].kind = 1;
+ for (int i = 1; i < kMaxObjectsCount; ++i)
+ _objects[i].kind = 0;
+}
+
+void MinigameBbTennis::initObjects2() {
+ // Nothing
+}
+
+void MinigameBbTennis::initVars() {
+ switch (_gameState) {
+ case 0:
+ initVars0();
+ break;
+ case 1:
+ initVars1();
+ break;
+ case 2:
+ initVars2();
+ break;
+ }
+}
+
+void MinigameBbTennis::initVars0() {
+ // Nothing
+}
+
+void MinigameBbTennis::initVars1() {
+ _numHearts = 15;
+ _allHeartsGone = false;
+ _squirrelDelay = 500;
+ _tennisPlayerDelay = 300;
+ _throwerDelay = 400;
+ _netPlayerDelay = 340;
+ _playerDecrease = 0;
+ _delayDecreaseTimer = 0;
+ _numBalls = 0;
+ _newBallTimer = 1;
+ _initBallTimer = 10;
+ _maxBalls = 5;
+ _rapidFireBallsCount = 0;
+ _score = 0;
+ _hitMissRatio = 0;
+ _playedThisIsTheCoolest = false;
+ _startSoundPlayed = false;
+ _endSoundPlaying = false;
+ stopSound(12);
+}
+
+void MinigameBbTennis::initVars2() {
+ if (_score > _hiScore)
+ _hiScore = _score;
+}
+
+bool MinigameBbTennis::updateStatus(int mouseX, int mouseY, uint mouseButtons) {
+ switch (_gameState) {
+ case 0:
+ return updateStatus0(mouseX, mouseY, mouseButtons);
+ case 1:
+ return updateStatus1(mouseX, mouseY, mouseButtons);
+ case 2:
+ return updateStatus2(mouseX, mouseY, mouseButtons);
+ }
+ return false;
+}
+
+bool MinigameBbTennis::updateStatus0(int mouseX, int mouseY, uint mouseButtons) {
+
+ if ((mouseButtons & kLeftButtonDown) || (mouseButtons & kRightButtonDown)) {
+ _gameState = 1;
+ initObjects();
+ initVars();
+ _gameTicks = 0;
+ return true;
+ }
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ if (obj->kind == 2) {
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex >= obj->anim->frameCount)
+ obj->frameIndex = 0;
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+ }
+ }
+
+ return true;
+}
+
+bool MinigameBbTennis::updateStatus1(int mouseX, int mouseY, uint mouseButtons) {
+
+ _objects[0].x = mouseX;
+ _objects[0].y = mouseY;
+
+ if (_allHeartsGone) {
+ _gameState = 2;
+ initObjects();
+ initVars();
+ _gameTicks = 0;
+ return true;
+ }
+
+ if (!_startSoundPlayed) {
+ playSound(12);
+ _startSoundPlayed = true;
+ }
+
+ if (((mouseButtons & kLeftButtonClicked) || (_rapidFireBallsCount > 0 && (mouseButtons & kLeftButtonDown))) &&
+ _newBallTimer == 0 && _numBalls < _maxBalls) {
+ // Insert a ball
+ Obj *obj = getFreeObject();
+ obj->anim = getAnimation(6);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(6)->frameTicks[0];
+ obj->x = 160;
+ obj->y = 240;
+ obj->kind = 2;
+ obj->targetX = mouseX;
+ obj->targetY = mouseY;
+ obj->ballStep = 12;
+ obj->ballStepCtr = 0;
+ obj->fltX = 160.0;
+ obj->fltY = 240.0;
+ obj->fltStepX = ((160 - mouseX) * 0.75) / 12.0;
+ obj->fltStepY = ((240 - mouseY) * 0.75) / 12.0;
+ _newBallTimer = _initBallTimer;
+ ++_numBalls;
+ playSound(31);
+ if (_rapidFireBallsCount > 0 && --_rapidFireBallsCount == 0) {
+ _initBallTimer = 10;
+ _maxBalls = 5;
+ }
+ }
+
+ if (_newBallTimer > 0)
+ --_newBallTimer;
+
+ if (++_delayDecreaseTimer == 30) {
+ _delayDecreaseTimer = 0;
+ if (_playerDecrease < 199)
+ ++_playerDecrease;
+ }
+
+ updateObjs();
+
+ if (!_playedThisIsTheCoolest && _score > 3 && _vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 11)) {
+ _playedThisIsTheCoolest = true;
+ playSound(9);
+ }
+
+ return true;
+}
+
+bool MinigameBbTennis::updateStatus2(int mouseX, int mouseY, uint mouseButtons) {
+ if (_endSoundPlaying) {
+ if (!isSoundPlaying(21) && _fromMainGame) {
+ //_vm->delayMillis(1000);
+ _gameDone = true;
+ }
+ } else {
+ playSound(21);
+ _endSoundPlaying = true;
+ }
+ return true;
+}
+
+void MinigameBbTennis::updateObjs() {
+
+ for (int i = 0; i < kMaxObjectsCount; ++i) {
+ Obj *obj = &_objects[i];
+ switch (obj->kind) {
+ case 2:
+ updateTennisBall(i);
+ break;
+ case 3:
+ updateSquirrel(i);
+ break;
+ case 4:
+ updateTennisPlayer(i);
+ break;
+ case 5:
+ updateThrower(i);
+ break;
+ case 6:
+ updateNetPlayer(i);
+ break;
+ case 7:
+ updateEnemyTennisBall(i);
+ break;
+ }
+ }
+
+ if (_rapidFireBallsCount == 0) {
+ --_squirrelDelay;
+ if (--_squirrelDelay == 0) {
+ Obj *obj = getFreeObject();
+ obj->kind = 3;
+ obj->x = 100;
+ obj->y = 69;
+ obj->anim = getAnimation(1);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(1)->frameTicks[0];
+ obj->status = 0;
+ obj->blinkCtr = _vm->getRandom(128) + 10;
+ _squirrelDelay = _vm->getRandom(512) + 1000;
+ }
+ }
+
+ if (--_tennisPlayerDelay == 0) {
+ Obj *obj = getFreeObject();
+ obj->kind = 4;
+ obj->y = 146;
+ obj->anim = getAnimation(11);
+ obj->ticks = getAnimation(11)->frameTicks[0];
+ if (_vm->getRandom(2) == 1) {
+ obj->x = 40;
+ obj->frameIndex = 0;
+ obj->status = 0;
+ } else {
+ obj->x = _vm->getRandom(2) == 1 ? 40 : 274;
+ obj->frameIndex = 16;
+ obj->status = 4;
+ }
+ obj->blinkCtr = _vm->getRandom(64) + 60;
+ _tennisPlayerDelay = _vm->getRandom(128) + 400 - _playerDecrease;
+ if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 0x11))
+ playSound(kYuppieEnteringCourtSounds[_vm->getRandom(2)]);
+ }
+
+ if (--_throwerDelay == 0) {
+ Obj *obj = getFreeObject();
+ obj->kind = 5;
+ obj->x = 50;
+ obj->y = 62;
+ obj->anim = getAnimation(12);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(12)->frameTicks[0];
+ obj->status = 0;
+ _throwerDelay = _vm->getRandom(128) + 200 - _playerDecrease;
+ if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 11))
+ playSound(kYuppieChargeSounds[_vm->getRandom(2)]);
+ }
+
+ if (--_netPlayerDelay == 0) {
+ Obj *obj = getFreeObject();
+ obj->kind = 6;
+ obj->y = 176;
+ if (_vm->getRandom(2) == 1) {
+ obj->x = 110;
+ obj->netPlayDirection = 1;
+ obj->anim = getAnimation(kLeftNetPlayAnims[_vm->getRandom(3)]);
+ } else {
+ obj->x = 216;
+ obj->netPlayDirection = 0;
+ obj->anim = getAnimation(kRightNetPlayAnims[_vm->getRandom(3)]);
+ }
+ obj->frameIndex = 1;
+ obj->ticks = obj->anim->frameTicks[1];
+ obj->status = 0;
+ obj->blinkCtr = 1;
+ _netPlayerDelay = _vm->getRandom(128) + 250 - _playerDecrease;
+ if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 11))
+ playSound(kYuppieChargeSounds[_vm->getRandom(2)]);
+ }
+
+}
+
+void MinigameBbTennis::updateTennisBall(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 7) {
+ obj->kind = 0;
+ --_numBalls;
+ if (_hitMissRatio > 0) {
+ if (--_hitMissRatio == 0 && _vm->getRandom(8) == 1 && !isAnySoundPlaying(kAllSounds, 11))
+ playSound(3);
+ } else {
+ if (_vm->getRandom(10) == 1 && !isAnySoundPlaying(kAllSounds, 11))
+ playSound(3);
+ }
+ return;
+ }
+ obj->ticks = getAnimation(6)->frameTicks[obj->frameIndex];
+ }
+
+ if (--obj->ballStep == 0) {
+ obj->ballStep = 12;
+ ++obj->ballStepCtr;
+ if (obj->ballStepCtr == 1) {
+ obj->fltStepX = ((obj->fltX - (float)obj->targetX) * 0.75) / 12.0;
+ obj->fltStepY = ((obj->fltY - (float)obj->targetY) * 0.75) / 12.0;
+ } else if (obj->ballStepCtr == 2) {
+ obj->fltStepX = (obj->fltX - (float)obj->targetX) / 12.0;
+ obj->fltStepY = (obj->fltY - (float)obj->targetY) / 12.0;
+ } else {
+ obj->fltStepX = 0.0;
+ obj->fltStepY = 0.0;
+ }
+ }
+
+ obj->fltX = obj->fltX - obj->fltStepX;
+ obj->x = obj->fltX;
+ obj->fltY = obj->fltY - obj->fltStepY;
+ obj->y = obj->fltY;
+
+}
+
+void MinigameBbTennis::updateSquirrel(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->status) {
+
+ case 0:
+ --obj->ticks;
+ if (--obj->ticks == 0) {
+ if (++obj->frameIndex == 4) {
+ obj->anim = getAnimation(0);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(0)->frameTicks[0];
+ obj->y += 2;
+ ++obj->status;
+ } else {
+ obj->ticks = getAnimation(1)->frameTicks[obj->frameIndex];
+ ++_squirrelDelay;
+ }
+ } else {
+ ++_squirrelDelay;
+ }
+ break;
+
+ case 1:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 4)
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(0)->frameTicks[obj->frameIndex];
+ }
+ ++obj->x;
+ if (obj->x < 230) {
+ if (--obj->blinkCtr <= 0) {
+ obj->anim = getAnimation(4);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(4)->frameTicks[obj->frameIndex];
+ obj->status = 3;
+ }
+ ++_squirrelDelay;
+ } else {
+ obj->anim = getAnimation(2);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(2)->frameTicks[0];
+ obj->y -= 2;
+ ++obj->status;
+ }
+ break;
+
+ case 2:
+ if (--obj->ticks == 0) {
+ if (++obj->frameIndex == 4) {
+ obj->kind = 0;
+ } else {
+ obj->ticks = getAnimation(2)->frameTicks[0];
+ ++_squirrelDelay;
+ }
+ } else {
+ ++_squirrelDelay;
+ }
+ break;
+
+ case 3:
+ if (--obj->ticks) {
+ if (++obj->frameIndex == 2) {
+ obj->anim = getAnimation(0);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(0)->frameTicks[0];
+ obj->status = 1;
+ obj->blinkCtr = _vm->getRandom(128) + 10;
+ } else {
+ obj->ticks = getAnimation(4)->frameTicks[obj->frameIndex];
+ ++_squirrelDelay;
+ }
+ } else {
+ ++_squirrelDelay;
+ }
+ break;
+
+ case 4:
+ if (--obj->ticks == 0) {
+ if (++obj->frameIndex == 5) {
+ obj->kind = 0;
+ } else {
+ obj->ticks = getAnimation(3)->frameTicks[obj->frameIndex];
+ ++_squirrelDelay;
+ }
+ } else {
+ ++_squirrelDelay;
+ }
+ break;
+
+ }
+
+ if (obj->status != 4) {
+ int tennisBallObjIndex = 0;
+ Obj *tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ while (tennisBallObj) {
+ if (tennisBallObj->frameIndex >= 6 && isHit(obj, tennisBallObj)) {
+ hitSomething();
+ tennisBallObj->kind = 0;
+ --_numBalls;
+ obj->status = 4;
+ obj->anim = getAnimation(3);
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(3)->frameTicks[0];
+ _rapidFireBallsCount = 50;
+ _maxBalls = 10;
+ _initBallTimer = 6;
+ if (!isAnySoundPlaying(kAllSounds, 11))
+ playSound(4);
+ break;
+ }
+ tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbTennis::updateTennisPlayer(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->status) {
+
+ case 0:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 6)
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(11)->frameTicks[0];
+ }
+ ++obj->x;
+ if (obj->x == 280)
+ obj->kind = 0;
+ --obj->blinkCtr;
+ if (obj->blinkCtr <= 0) {
+ obj->frameIndex = 6;
+ obj->ticks = getAnimation(11)->frameTicks[6];
+ ++obj->status;
+ }
+ ++_tennisPlayerDelay;
+ break;
+
+ case 1:
+ if (--obj->ticks == 0) {
+ if (++obj->frameIndex == 9) {
+ if (obj->x < 210) {
+ obj->frameIndex = 9;
+ obj->status = 2;
+ } else {
+ obj->frameIndex = 15;
+ obj->status = 3;
+ }
+ obj->blinkCtr = _vm->getRandom(64) + 40;
+ }
+ obj->ticks = getAnimation(11)->frameTicks[obj->frameIndex];
+ }
+ if ((obj->ticks % 2) && obj->frameIndex != 8) {
+ ++obj->x;
+ if (obj->x == 280)
+ obj->kind = 0;
+ }
+ ++_tennisPlayerDelay;
+ break;
+
+ case 2:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 15)
+ ++obj->status;
+ obj->ticks = getAnimation(11)->frameTicks[obj->frameIndex];
+ if (obj->frameIndex == 13)
+ makeEnemyBall(obj->x, obj->y - 31, 4);
+ }
+ ++_tennisPlayerDelay;
+ break;
+
+ case 3:
+ if (--obj->ticks == 0) {
+ ++obj->status;
+ obj->frameIndex = 16;
+ obj->ticks = getAnimation(11)->frameTicks[16];
+ }
+ if (obj->ticks % 2) {
+ --obj->x;
+ if (obj->x <= 40)
+ obj->kind = 0;
+ } else
+ ++_tennisPlayerDelay;
+ break;
+
+ case 4:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 22)
+ obj->frameIndex = 16;
+ obj->ticks = getAnimation(11)->frameTicks[obj->frameIndex];
+ }
+ --obj->x;
+ if (obj->x > 40) {
+ if (--obj->blinkCtr <= 0) {
+ ++obj->status;
+ obj->frameIndex = 22;
+ obj->ticks = getAnimation(11)->frameTicks[22];
+ }
+ ++_tennisPlayerDelay;
+ } else {
+ obj->kind = 0;
+ }
+ break;
+
+ case 5:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 25) {
+ if (obj->x <= 70) {
+ obj->frameIndex = 33;
+ obj->status = 7;
+ } else {
+ obj->frameIndex = 25;
+ obj->status = 6;
+ }
+ obj->blinkCtr = _vm->getRandom(64) + 40;
+ }
+ obj->ticks = getAnimation(11)->frameTicks[obj->frameIndex];
+ }
+ if ((obj->ticks % 2) && obj->frameIndex != 24) {
+ --obj->x;
+ if (obj->x <= 40)
+ obj->kind = 0;
+ } else
+ ++_tennisPlayerDelay;
+ break;
+
+ case 6:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 33)
+ ++obj->status;
+ obj->ticks = getAnimation(11)->frameTicks[obj->frameIndex];
+ if (obj->frameIndex == 31)
+ makeEnemyBall(obj->x + 8, obj->y - 49, 4);
+ }
+ ++_tennisPlayerDelay;
+ break;
+
+ case 7:
+ if (--obj->ticks == 0) {
+ obj->frameIndex = 0;
+ obj->ticks = getAnimation(11)->frameTicks[0];
+ obj->status = 0;
+ }
+ if (obj->ticks % 2) {
+ ++obj->x;
+ if (obj->x == 280)
+ obj->kind = 0;
+ }
+ ++_tennisPlayerDelay;
+ break;
+
+ case 8:
+ break;
+
+ }
+
+ if (obj->status != 8) {
+ int tennisBallObjIndex = 0;
+ Obj *tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ while (tennisBallObj) {
+ if (tennisBallObj->frameIndex >= 6 && isHit(obj, tennisBallObj)) {
+ hitSomething();
+ tennisBallObj->kind = 0;
+ --_numBalls;
+ obj->status = 8;
+ obj->blinkCtr = 20;
+ playSound(kYuppieHitSounds[_vm->getRandom(6)]);
+ break;
+ }
+ tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbTennis::updateThrower(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->status) {
+
+ case 0:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 4)
+ ++obj->status;
+ obj->ticks = getAnimation(12)->frameTicks[obj->frameIndex];
+ }
+ ++_throwerDelay;
+ break;
+
+ case 1:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 8)
+ ++obj->status;
+ obj->ticks = getAnimation(12)->frameTicks[obj->frameIndex];
+ if (obj->frameIndex == 7)
+ makeEnemyBall(obj->x - 10, obj->y - 10, 3);
+ }
+ ++_throwerDelay;
+ break;
+
+ case 2:
+ --obj->ticks;
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 12) {
+ obj->kind = 0;
+ } else {
+ obj->ticks = getAnimation(12)->frameTicks[obj->frameIndex];
+ ++_throwerDelay;
+ }
+ } else {
+ ++_throwerDelay;
+ }
+ break;
+
+ case 3:
+ --obj->ticks;
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 14) {
+ obj->kind = 0;
+ } else {
+ obj->ticks = getAnimation(12)->frameTicks[obj->frameIndex];
+ ++_throwerDelay;
+ }
+ } else {
+ ++_throwerDelay;
+ }
+ break;
+
+ }
+
+ if (obj->status != 3) {
+ int tennisBallObjIndex = 0;
+ Obj *tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ while (tennisBallObj) {
+ if (tennisBallObj->frameIndex >= 5 && tennisBallObj->frameIndex <= 7 && isHit(obj, tennisBallObj)) {
+ hitSomething();
+ tennisBallObj->kind = 0;
+ --_numBalls;
+ obj->status = 3;
+ obj->frameIndex = 12;
+ obj->ticks = getAnimation(12)->frameTicks[12];
+ playSound(kYuppieHitSounds[_vm->getRandom(6)]);
+ break;
+ }
+ tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbTennis::updateNetPlayer(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ switch (obj->status) {
+
+ case 0:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 15) {
+ obj->blinkCtr = _vm->getRandom(32) + 10;
+ ++obj->status;
+ obj->frameIndex = 31;
+ } else {
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ ++_netPlayerDelay;
+ }
+ } else {
+ ++_netPlayerDelay;
+ }
+ break;
+
+ case 1:
+ if (--obj->blinkCtr <= 0) {
+ ++obj->status;
+ obj->frameIndex = 15;
+ obj->ticks = obj->anim->frameTicks[15];
+ obj->x = _vm->getRandom(128) + 100;
+ }
+ ++_netPlayerDelay;
+ break;
+
+ case 2:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 24) {
+ ++obj->status;
+ obj->frameIndex = 28;
+ }
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ if (obj->frameIndex == 23)
+ makeEnemyBall(obj->x - 8, obj->y - 40, 3);
+ }
+ ++_netPlayerDelay;
+ break;
+
+ case 3:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 31) {
+ obj->status = 1;
+ obj->frameIndex = 31;
+ obj->blinkCtr = _vm->getRandom(32) + 10;
+ } else {
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ ++_netPlayerDelay;
+ }
+ } else {
+ ++_netPlayerDelay;
+ }
+ break;
+
+ case 5:
+ if (--obj->ticks == 0) {
+ ++obj->frameIndex;
+ if (obj->frameIndex == 27)
+ obj->kind = 0;
+ obj->ticks = obj->anim->frameTicks[obj->frameIndex];
+ }
+ break;
+
+ case 4:
+ break;
+
+ }
+
+ if (obj->status < 4 && obj->frameIndex != 31) {
+ int tennisBallObjIndex = 0;
+ Obj *tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ while (tennisBallObj) {
+ if (obj->status == 0 && tennisBallObj->frameIndex >= 3 && tennisBallObj->frameIndex <= 6 &&
+ isHit(obj, tennisBallObj)) {
+ hitSomething();
+ tennisBallObj->kind = 0;
+ --_numBalls;
+ if (obj->netPlayDirection) {
+ obj->x += kLeftPlayerOffX[obj->frameIndex] + 10;
+ obj->y += kLeftPlayerOffY[obj->frameIndex] + 10;
+ } else {
+ obj->x -= kLeftPlayerOffX[obj->frameIndex] + 12;
+ obj->y += kLeftPlayerOffY[obj->frameIndex] + 10;
+ }
+ obj->status = 4;
+ obj->frameIndex = 0;
+ obj->blinkCtr = 20;
+ playSound(kYuppieHitSounds[_vm->getRandom(6)]);
+ break;
+ } else if (obj->status > 1 && obj->status < 4 && tennisBallObj->frameIndex >= 3 && tennisBallObj->frameIndex <= 4 &&
+ isHit(obj, tennisBallObj)) {
+ hitSomething();
+ tennisBallObj->kind = 0;
+ --_numBalls;
+ obj->status = 5;
+ obj->frameIndex = 24;
+ obj->ticks = obj->anim->frameTicks[24];
+ playSound(kYuppieHitSounds[_vm->getRandom(6)]);
+ break;
+ }
+ tennisBallObj = findTennisBall(tennisBallObjIndex++);
+ }
+ }
+
+}
+
+void MinigameBbTennis::updateEnemyTennisBall(int objIndex) {
+ Obj *obj = &_objects[objIndex];
+
+ if (--obj->ticks == 0) {
+ --obj->frameIndex;
+ obj->ticks = getAnimation(6)->frameTicks[obj->frameIndex];
+ }
+
+ if (--obj->ballStep == 0) {
+ obj->ballStep = 12;
+ --obj->ballStepCtr;
+ if (obj->ballStepCtr == 1) {
+ obj->fltStepX = (obj->fltX - (float)obj->targetX) / 12.0;
+ obj->fltStepY = (obj->fltY - (float)obj->targetY) / 12.0;
+ } else if (obj->ballStepCtr == 2) {
+ obj->fltStepX = ((obj->fltX - (float)obj->targetX) * 0.18) / 12.0;
+ obj->fltStepY = ((obj->fltY - (float)obj->targetY) * 0.18) / 12.0;
+ } else {
+ obj->kind = 0;
+ if (_numHearts > 0 && --_numHearts == 0)
+ _allHeartsGone = true;
+ }
+ }
+
+ obj->fltX = obj->fltX - obj->fltStepX;
+ obj->x = obj->fltX;
+ obj->fltY = obj->fltY - obj->fltStepY;
+ obj->y = obj->fltY;
+
+}
+
+void MinigameBbTennis::makeEnemyBall(int x, int y, int frameIndex) {
+ Obj *obj = getFreeObject();
+
+ obj->kind = 7;
+ obj->x = x;
+ obj->y = y;
+ obj->anim = getAnimation(6);
+ obj->frameIndex = frameIndex;
+ obj->ticks = getAnimation(6)->frameTicks[frameIndex];
+ obj->targetX = 160;
+ obj->targetY = 180;
+ obj->fltX = (float)x;
+ obj->fltY = (float)y;
+
+ switch (frameIndex) {
+
+ case 6:
+ obj->ballStep = 18;
+ obj->ballStepCtr = 3;
+ obj->fltStepX = 0.0;
+ obj->fltStepY = 0.0;
+ break;
+
+ case 5:
+ obj->ballStep = 12;
+ obj->ballStepCtr = 3;
+ obj->fltStepX = ((float)(x - 160) * 0.07) / 12.0;
+ obj->fltStepY = ((float)(y - 180) * 0.07) / 12.0;
+ break;
+
+ case 4:
+ obj->ballStep = 6;
+ obj->ballStepCtr = 3;
+ obj->fltStepX = ((float)(x - 160) * 0.07) / 6.0;
+ obj->fltStepY = ((float)(y - 180) * 0.07) / 6.0;
+ break;
+
+ case 3:
+ obj->ballStep = 12;
+ obj->ballStepCtr = 2;
+ obj->fltStepX = ((float)(x - 160) * 0.18) / 12.0;
+ obj->fltStepY = ((float)(y - 180) * 0.18) / 12.0;
+ break;
+
+ case 2:
+ obj->ballStep = 6;
+ obj->ballStepCtr = 2;
+ obj->fltStepX = ((float)(x - 160) * 0.18) / 6.0;
+ obj->fltStepY = ((float)(y - 180) * 0.18) / 6.0;
+ break;
+
+ case 1:
+ obj->ballStep = 12;
+ obj->ballStepCtr = 1;
+ obj->fltStepX = (float)((x - 160) / 12);
+ obj->fltStepY = (float)((y - 180) / 12);
+ break;
+
+ case 0:
+ obj->ballStep = 6;
+ obj->ballStepCtr = 1;
+ obj->fltStepX = (float)((x - 160) / 6);
+ obj->fltStepY = (float)((y - 180) / 6);
+ break;
+
+ }
+
+}
+
+void MinigameBbTennis::hitSomething() {
+ if (_hitMissRatio < 15)
+ _hitMissRatio += 3;
+ ++_score;
+}
+
+int MinigameBbTennis::run(bool fromMainGame) {
+
+ memset(_objects, 0, sizeof(_objects));
+
+ _numbersAnim = getAnimation(20);
+
+ _backgroundSpriteIndex = 272;
+ _titleScreenSpriteIndex = 273;
+
+ _fromMainGame = fromMainGame;
+
+ _hiScore = 0;
+ if (!_fromMainGame)
+ _hiScore = loadHiscore(kMinigameBbTennis);
+
+ _gameState = 0;
+ _gameResult = 0;
+ _gameDone = false;
+ initObjects();
+ initVars();
+
+ _spriteModule = new SpriteModule();
+ _spriteModule->load("bbtennis/bbtennis.000");
+
+ Palette palette = _spriteModule->getPalette();
+ _vm->_screen->setPalette(palette);
+
+ loadSounds();
+
+ _gameTicks = 0;
+ playSound(29, true);
+
+ while (!_vm->shouldQuit() &&!_gameDone) {
+ _vm->updateEvents();
+ update();
+ }
+
+ _vm->_sound->unloadSounds();
+
+ if (!_fromMainGame)
+ saveHiscore(kMinigameBbTennis, _hiScore);
+
+ delete _spriteModule;
+
+ return _gameResult;
+}
+
+void MinigameBbTennis::update() {
+
+ int currTicks, inputTicks;
+
+ if (_gameTicks > 0) {
+ currTicks = _vm->_system->getMillis();
+ inputTicks = 3 * (currTicks - _gameTicks) / 50;
+ _gameTicks = currTicks - (currTicks - _gameTicks - 50 * inputTicks / 3);
+ } else {
+ inputTicks = 1;
+ _gameTicks = _vm->_system->getMillis();
+ }
+
+ if (_vm->_keyCode == Common::KEYCODE_ESCAPE) {
+ _gameDone = true;
+ return;
+ }
+
+ if (inputTicks == 0)
+ return;
+
+ bool done;
+
+ do {
+ done = !updateStatus(_vm->_mouseX, _vm->_mouseY, _vm->_mouseButtons);
+ _vm->_mouseButtons &= ~kLeftButtonClicked;
+ _vm->_mouseButtons &= ~kRightButtonClicked;
+ _vm->_keyCode = Common::KEYCODE_INVALID;
+ } while (--inputTicks && _gameTicks > 0 && !done);
+
+ drawSprites();
+
+ _vm->_system->delayMillis(10);
+
+}
+
+void MinigameBbTennis::loadSounds() {
+ for (uint i = 0; i < kSoundFilenamesCount; ++i) {
+ Common::String filename = Common::String::format("bbtennis/%s", kSoundFilenames[i]);
+ _vm->_sound->loadSound(filename.c_str());
+ }
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/bbtennis.h b/engines/bbvs/minigames/bbtennis.h
new file mode 100644
index 0000000000..72ee719387
--- /dev/null
+++ b/engines/bbvs/minigames/bbtennis.h
@@ -0,0 +1,134 @@
+/* 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 BBVS_MINIGAMES_BBTENNIS_H
+#define BBVS_MINIGAMES_BBTENNIS_H
+
+#include "bbvs/minigames/minigame.h"
+
+namespace Bbvs {
+
+class MinigameBbTennis : public Minigame {
+public:
+ MinigameBbTennis(BbvsEngine *vm) : Minigame(vm) {};
+ int run(bool fromMainGame);
+public:
+
+ struct Obj {
+ int kind;
+ int x, y;
+ const ObjAnimation *anim;
+ int frameIndex;
+ int ticks;
+ int status;
+ int blinkCtr;
+ float fltStepX;
+ float fltStepY;
+ float fltX;
+ float fltY;
+ int targetX;
+ int targetY;
+ int ballStep;
+ int ballStepCtr;
+ int netPlayDirection;
+ };
+
+ enum {
+ kMaxObjectsCount = 256
+ };
+
+ enum {
+ kGSTitleScreen = 0, // Title screen
+ kGSMainGame = 1, // Game when called as part of the main game
+ kGSStandaloneGame = 2, // Game when called as standalone game
+ kGSScoreCountUp = 3 // Score countup and next level text
+ };
+
+ Obj _objects[kMaxObjectsCount];
+
+ int _numHearts;
+ int _squirrelDelay;
+ int _tennisPlayerDelay;
+ int _throwerDelay;
+ int _netPlayerDelay;
+ int _playerDecrease;
+ int _delayDecreaseTimer;
+ int _numBalls;
+ int _newBallTimer;
+ int _initBallTimer;
+ int _maxBalls;
+ int _rapidFireBallsCount;
+ int _score, _hiScore;
+ int _hitMissRatio;
+ bool _allHeartsGone;
+ bool _playedThisIsTheCoolest;
+ bool _startSoundPlayed;
+ bool _endSoundPlaying;
+
+ const ObjAnimation *getAnimation(int animIndex);
+
+ void buildDrawList(DrawList &drawList);
+ void buildDrawList0(DrawList &drawList);
+ void buildDrawList1(DrawList &drawList);
+ void buildDrawList2(DrawList &drawList);
+
+ void drawSprites();
+
+ void initObjs();
+ Obj *getFreeObject();
+ Obj *findTennisBall(int startObjIndex);
+ bool isHit(Obj *obj1, Obj *obj2);
+
+ void initObjects();
+ void initObjects0();
+ void initObjects1();
+ void initObjects2();
+
+ void initVars();
+ void initVars0();
+ void initVars1();
+ void initVars2();
+
+ bool updateStatus(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus0(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus1(int mouseX, int mouseY, uint mouseButtons);
+ bool updateStatus2(int mouseX, int mouseY, uint mouseButtons);
+
+ void updateObjs();
+ void updateTennisBall(int objIndex);
+ void updateSquirrel(int objIndex);
+ void updateTennisPlayer(int objIndex);
+ void updateThrower(int objIndex);
+ void updateNetPlayer(int objIndex);
+ void updateEnemyTennisBall(int objIndex);
+ void makeEnemyBall(int x, int y, int frameIndex);
+ void hitSomething();
+
+ void update();
+
+ void loadSounds();
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_MINIGAMES_BBTENNIS_H
diff --git a/engines/bbvs/minigames/bbtennis_anims.cpp b/engines/bbvs/minigames/bbtennis_anims.cpp
new file mode 100644
index 0000000000..7441c66749
--- /dev/null
+++ b/engines/bbvs/minigames/bbtennis_anims.cpp
@@ -0,0 +1,142 @@
+/* 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 "bbvs/minigames/bbtennis.h"
+
+namespace Bbvs {
+
+static const int kAnim0FrameIndices[] = {0, 1, 2, 3};
+static const int16 kAnim0FrameTicks[] = {6, 6, 6, 6};
+static const BBRect kAnim0FrameRects[] = {{-15, -11, 22, 10}, {-15, -12, 23, 10}, {-14, -11, 22, 8}, {-13, -11, 20, 10}};
+static const int kAnim1FrameIndices[] = {4, 5, 6, 7, 8, 3};
+static const int16 kAnim1FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim1FrameRects[] = {{-16, -3, 7, 6}, {-13, -8, 11, 10}, {-14, -12, 15, 12}, {-15, -10, 17, 10}, {-17, -10, 22, 9}, {-13, -12, 20, 12}};
+static const int kAnim2FrameIndices[] = {9, 10, 11, 12};
+static const int16 kAnim2FrameTicks[] = {6, 8, 8, 8};
+static const BBRect kAnim2FrameRects[] = {{-11, -14, 20, 14}, {-1, -14, 10, 15}, {3, -9, 6, 10}, {2, -5, 7, 6}};
+static const int kAnim3FrameIndices[] = {13, 14, 15, 16, 17};
+static const int16 kAnim3FrameTicks[] = {8, 8, 6, 6, 6};
+static const BBRect kAnim3FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim4FrameIndices[] = {18, 19};
+static const int16 kAnim4FrameTicks[] = {61, 22};
+static const BBRect kAnim4FrameRects[] = {{-8, -12, 14, 11}, {-8, -12, 14, 11}};
+static const int kAnim5FrameIndices[] = {20};
+static const int16 kAnim5FrameTicks[] = {6};
+static const BBRect kAnim5FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim6FrameIndices[] = {21, 22, 23, 24, 25, 26, 27, 28, 29};
+static const int16 kAnim6FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim6FrameRects[] = {{-59, -43, 114, 114}, {-24, -13, 44, 46}, {-12, -5, 24, 25}, {-8, -3, 15, 15}, {-5, -3, 8, 8}, {-3, -2, 5, 5}, {-1, -1, 3, 3}, {0, 0, 2, 2}, {-56, 25, 102, 50}};
+static const int kAnim7FrameIndices[] = {30};
+static const int16 kAnim7FrameTicks[] = {6};
+static const BBRect kAnim7FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim8FrameIndices[] = {31};
+static const int16 kAnim8FrameTicks[] = {6};
+static const BBRect kAnim8FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim9FrameIndices[] = {32};
+static const int16 kAnim9FrameTicks[] = {6};
+static const BBRect kAnim9FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim10FrameIndices[] = {33};
+static const int16 kAnim10FrameTicks[] = {6};
+static const BBRect kAnim10FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim11FrameIndices[] = {34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 58, 59, 60, 61, 62, 63, 64, 42, 65};
+static const int16 kAnim11FrameTicks[] = {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 6, 6, 6, 10, 10, 10, 10};
+static const BBRect kAnim11FrameRects[] = {{0, -50, 16, 47}, {1, -49, 16, 47}, {-1, -49, 17, 46}, {0, -47, 16, 45}, {2, -46, 15, 46}, {0, -48, 17, 45}, {2, -50, 14, 49}, {-2, -46, 17, 46}, {0, -57, 15, 57}, {-2, -56, 14, 56}, {-4, -56, 13, 56}, {-4, -56, 15, 56}, {5, -51, 14, 49}, {4, -52, 15, 52}, {-1, -57, 13, 57}, {0, -55, 14, 55}, {-5, -50, 17, 49}, {-9, -50, 17, 49}, {-9, -48, 16, 47}, {-6, -49, 14, 48}, {-8, -50, 17, 50}, {-10, -48, 19, 48}, {-2, -50, 14, 50}, {2, -47, 13, 48}, {-1, -57, 13, 57}, {4, -55, 12, 56}, {4, -58, 13, 59}, {5, -58, 12, 59}, {5, -57, 15, 58}, {1, -57, 14, 57}, {-7, -51, 15, 51}, {-5, -53, 16, 53}, {0, -57, 15, 57}, {1, -55, 14, 55}};
+static const int kAnim12FrameIndices[] = {66, 67, 68, 69, 70, 71, 72, 73, 69, 68, 67, 66, 74, 75};
+static const int16 kAnim12FrameTicks[] = {10, 10, 10, 20, 10, 10, 6, 10, 20, 10, 10, 10, 8, 6};
+static const BBRect kAnim12FrameRects[] = {{-5, -8, 12, 6}, {-12, -17, 24, 15}, {-12, -28, 24, 28}, {-10, -36, 20, 35}, {-9, -36, 18, 37}, {-11, -37, 17, 38}, {-6, -36, 16, 34}, {-5, -35, 20, 39}, {-10, -36, 20, 35}, {-12, -28, 24, 28}, {-12, -17, 24, 15}, {-5, -8, 12, 6}, {-15, -27, 23, 38}, {-19, -17, 15, 17}};
+static const int kAnim13FrameIndices[] = {76, 77, 78, 77, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 98, 102, 103, 90};
+static const int16 kAnim13FrameTicks[] = {16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 10, 10, 6, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim13FrameRects[] = {{-21, -61, 16, 52}, {-42, -76, 7, 14}, {-43, -75, 13, 24}, {-42, -76, 7, 14}, {-42, -75, 4, 42}, {-42, -76, 11, 57}, {-40, -74, 13, 55}, {-36, -74, 11, 55}, {-31, -72, 12, 56}, {-27, -71, 14, 57}, {-20, -69, 15, 55}, {-12, -65, 15, 51}, {-7, -57, 18, 44}, {-3, -43, 18, 29}, {4, -27, 20, 14}, {0, -28, 13, 14}, {0, -38, 14, 24}, {-1, -49, 19, 36}, {0, -61, 17, 47}, {-2, -63, 19, 49}, {-5, -64, 19, 50}, {-3, -62, 18, 48}, {0, -61, 19, 47}, {0, -61, 16, 47}, {-4, -48, 17, 34}, {-9, -37, 15, 23}, {-13, -26, 14, 12}, {0, -61, 16, 47}, {0, -50, 15, 36}, {0, -39, 13, 25}, {0, -28, 12, 14}};
+static const int kAnim14FrameIndices[] = {104, 105, 106, 105, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 126, 130, 131, 118};
+static const int16 kAnim14FrameTicks[] = {16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 10, 10, 6, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim14FrameRects[] = {{6, -61, 14, 52}, {35, -77, 7, 16}, {29, -76, 13, 24}, {35, -77, 7, 16}, {38, -76, 4, 43}, {32, -75, 10, 55}, {24, -74, 16, 54}, {22, -74, 14, 53}, {18, -72, 12, 55}, {12, -71, 15, 57}, {2, -69, 17, 55}, {-5, -65, 18, 51}, {-13, -57, 18, 43}, {-20, -43, 23, 29}, {-26, -30, 25, 16}, {-13, -28, 13, 14}, {-16, -38, 24, 24}, {-16, -49, 20, 35}, {-15, -61, 17, 47}, {-15, -63, 17, 49}, {-13, -64, 17, 51}, {-14, -62, 15, 48}, {-19, -61, 19, 47}, {-16, -61, 16, 48}, {-18, -48, 22, 34}, {-6, -37, 14, 23}, {0, -27, 12, 14}, {-16, -61, 16, 48}, {-16, -50, 19, 36}, {-14, -39, 15, 25}, {-12, -28, 12, 15}};
+static const int kAnim15FrameIndices[] = {132, 133, 134, 133, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 154, 158, 159, 146};
+static const int16 kAnim15FrameTicks[] = {16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 10, 10, 6, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim15FrameRects[] = {{-21, -61, 16, 52}, {-42, -76, 7, 14}, {-43, -75, 13, 24}, {-42, -76, 7, 14}, {-42, -75, 4, 42}, {-42, -76, 11, 57}, {-40, -74, 13, 55}, {-36, -74, 11, 55}, {-31, -72, 12, 56}, {-27, -71, 14, 57}, {-20, -69, 15, 55}, {-12, -65, 15, 51}, {-7, -57, 18, 44}, {-3, -43, 18, 29}, {4, -27, 20, 14}, {0, -28, 13, 14}, {0, -38, 14, 24}, {-1, -49, 19, 36}, {0, -61, 17, 47}, {-2, -63, 19, 49}, {-5, -64, 19, 50}, {-3, -62, 18, 48}, {0, -61, 19, 47}, {0, -61, 16, 47}, {-4, -48, 17, 34}, {-9, -37, 15, 23}, {-13, -26, 14, 12}, {0, -61, 16, 47}, {0, -50, 15, 36}, {0, -39, 13, 25}, {0, -28, 12, 14}};
+static const int kAnim16FrameIndices[] = {160, 161, 162, 161, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 182, 186, 187, 174};
+static const int16 kAnim16FrameTicks[] = {16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 10, 10, 6, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim16FrameRects[] = {{6, -61, 14, 52}, {35, -77, 7, 16}, {29, -76, 13, 24}, {35, -77, 7, 16}, {38, -76, 4, 43}, {32, -75, 10, 55}, {24, -74, 16, 54}, {22, -74, 14, 53}, {18, -72, 12, 55}, {12, -71, 15, 57}, {2, -69, 17, 55}, {-5, -65, 18, 51}, {-13, -57, 18, 43}, {-20, -43, 23, 29}, {-26, -30, 25, 16}, {-13, -28, 13, 14}, {-16, -38, 24, 24}, {-16, -49, 20, 35}, {-15, -61, 17, 47}, {-15, -63, 17, 49}, {-13, -64, 17, 51}, {-14, -62, 15, 48}, {-19, -61, 19, 47}, {-16, -61, 16, 48}, {-18, -48, 22, 34}, {-6, -37, 14, 23}, {0, -27, 12, 14}, {-16, -61, 16, 48}, {-16, -50, 19, 36}, {-14, -39, 15, 25}, {-12, -28, 12, 15}};
+static const int kAnim17FrameIndices[] = {188, 189, 190, 189, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 210, 214, 215, 202};
+static const int16 kAnim17FrameTicks[] = {16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 10, 10, 6, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim17FrameRects[] = {{-21, -61, 16, 52}, {-42, -76, 7, 14}, {-43, -75, 13, 24}, {-42, -76, 7, 14}, {-42, -75, 4, 42}, {-42, -76, 11, 57}, {-40, -74, 13, 55}, {-36, -74, 11, 55}, {-31, -72, 12, 56}, {-27, -71, 14, 57}, {-20, -69, 15, 55}, {-12, -65, 15, 51}, {-7, -57, 18, 44}, {-3, -43, 18, 29}, {4, -27, 20, 14}, {0, -28, 13, 14}, {0, -38, 14, 24}, {-1, -49, 19, 36}, {0, -61, 17, 47}, {-2, -63, 19, 49}, {-5, -64, 19, 50}, {-3, -62, 18, 48}, {0, -61, 19, 47}, {0, -61, 16, 47}, {-4, -48, 17, 34}, {-9, -37, 15, 23}, {-13, -26, 14, 12}, {0, -61, 16, 47}, {0, -50, 15, 36}, {0, -39, 13, 25}, {0, -28, 12, 14}};
+static const int kAnim18FrameIndices[] = {216, 217, 218, 217, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 238, 242, 243, 230};
+static const int16 kAnim18FrameTicks[] = {16, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 6, 10, 10, 6, 10, 10, 10, 10, 10, 10};
+static const BBRect kAnim18FrameRects[] = {{6, -61, 14, 52}, {35, -77, 7, 16}, {29, -76, 13, 24}, {35, -77, 7, 16}, {38, -76, 4, 43}, {32, -75, 10, 55}, {24, -74, 16, 54}, {22, -74, 14, 53}, {18, -72, 12, 55}, {12, -71, 15, 57}, {2, -69, 17, 55}, {-5, -65, 18, 51}, {-13, -57, 18, 43}, {-20, -43, 23, 29}, {-26, -30, 25, 16}, {-13, -28, 13, 14}, {-16, -38, 24, 24}, {-16, -49, 20, 35}, {-15, -61, 17, 47}, {-15, -63, 17, 49}, {-13, -64, 17, 51}, {-14, -62, 15, 48}, {-19, -61, 19, 47}, {-16, -61, 16, 48}, {-18, -48, 22, 34}, {-6, -37, 14, 23}, {0, -27, 12, 14}, {-16, -61, 16, 48}, {-16, -50, 19, 36}, {-14, -39, 15, 25}, {-12, -28, 12, 15}};
+static const int kAnim19FrameIndices[] = {244};
+static const int16 kAnim19FrameTicks[] = {6};
+static const BBRect kAnim19FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim20FrameIndices[] = {245, 246, 247, 248, 249, 250, 251, 252, 253, 254};
+static const int16 kAnim20FrameTicks[] = {6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
+static const BBRect kAnim20FrameRects[] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+static const int kAnim21FrameIndices[] = {255};
+static const int16 kAnim21FrameTicks[] = {1};
+static const BBRect kAnim21FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim22FrameIndices[] = {256};
+static const int16 kAnim22FrameTicks[] = {5};
+static const BBRect kAnim22FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim23FrameIndices[] = {257};
+static const int16 kAnim23FrameTicks[] = {1};
+static const BBRect kAnim23FrameRects[] = {{0, 0, 0, 0}};
+static const int kAnim24FrameIndices[] = {258, 259};
+static const int16 kAnim24FrameTicks[] = {6, 6};
+static const BBRect kAnim24FrameRects[] = {{-9, -9, 17, 15}, {-11, -10, 19, 16}};
+static const int kAnim25FrameIndices[] = {260, 261, 262, 263, 264, 265};
+static const int16 kAnim25FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim25FrameRects[] = {{-22, -91, 45, 93}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}, {-21, -92, 43, 95}};
+static const int kAnim26FrameIndices[] = {266, 267, 268, 269, 270, 271};
+static const int16 kAnim26FrameTicks[] = {6, 6, 6, 6, 6, 6};
+static const BBRect kAnim26FrameRects[] = {{-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}, {-21, -85, 38, 86}};
+static const ObjAnimation kAnimations[] = {
+ {4, kAnim0FrameIndices, kAnim0FrameTicks, kAnim0FrameRects},
+ {6, kAnim1FrameIndices, kAnim1FrameTicks, kAnim1FrameRects},
+ {4, kAnim2FrameIndices, kAnim2FrameTicks, kAnim2FrameRects},
+ {5, kAnim3FrameIndices, kAnim3FrameTicks, kAnim3FrameRects},
+ {2, kAnim4FrameIndices, kAnim4FrameTicks, kAnim4FrameRects},
+ {1, kAnim5FrameIndices, kAnim5FrameTicks, kAnim5FrameRects},
+ {9, kAnim6FrameIndices, kAnim6FrameTicks, kAnim6FrameRects},
+ {1, kAnim7FrameIndices, kAnim7FrameTicks, kAnim7FrameRects},
+ {1, kAnim8FrameIndices, kAnim8FrameTicks, kAnim8FrameRects},
+ {1, kAnim9FrameIndices, kAnim9FrameTicks, kAnim9FrameRects},
+ {1, kAnim10FrameIndices, kAnim10FrameTicks, kAnim10FrameRects},
+ {34, kAnim11FrameIndices, kAnim11FrameTicks, kAnim11FrameRects},
+ {14, kAnim12FrameIndices, kAnim12FrameTicks, kAnim12FrameRects},
+ {31, kAnim13FrameIndices, kAnim13FrameTicks, kAnim13FrameRects},
+ {31, kAnim14FrameIndices, kAnim14FrameTicks, kAnim14FrameRects},
+ {31, kAnim15FrameIndices, kAnim15FrameTicks, kAnim15FrameRects},
+ {31, kAnim16FrameIndices, kAnim16FrameTicks, kAnim16FrameRects},
+ {31, kAnim17FrameIndices, kAnim17FrameTicks, kAnim17FrameRects},
+ {31, kAnim18FrameIndices, kAnim18FrameTicks, kAnim18FrameRects},
+ {1, kAnim19FrameIndices, kAnim19FrameTicks, kAnim19FrameRects},
+ {10, kAnim20FrameIndices, kAnim20FrameTicks, kAnim20FrameRects},
+ {1, kAnim21FrameIndices, kAnim21FrameTicks, kAnim21FrameRects},
+ {1, kAnim22FrameIndices, kAnim22FrameTicks, kAnim22FrameRects},
+ {1, kAnim23FrameIndices, kAnim23FrameTicks, kAnim23FrameRects},
+ {2, kAnim24FrameIndices, kAnim24FrameTicks, kAnim24FrameRects},
+ {6, kAnim25FrameIndices, kAnim25FrameTicks, kAnim25FrameRects},
+ {6, kAnim26FrameIndices, kAnim26FrameTicks, kAnim26FrameRects}
+};
+
+const ObjAnimation *MinigameBbTennis::getAnimation(int animIndex) {
+ return &kAnimations[animIndex];
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/minigame.cpp b/engines/bbvs/minigames/minigame.cpp
new file mode 100644
index 0000000000..888040f87a
--- /dev/null
+++ b/engines/bbvs/minigames/minigame.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.
+ *
+ */
+
+#include "bbvs/minigames/minigame.h"
+#include "common/savefile.h"
+
+namespace Bbvs {
+
+Minigame::Minigame(BbvsEngine *vm)
+ : _vm(vm), _spriteModule(0) {
+
+ memset(_hiScoreTable, 0, sizeof(_hiScoreTable));
+}
+
+Minigame::~Minigame() {
+}
+
+int Minigame::drawNumber(DrawList &drawList, int number, int x, int y) {
+ int digits = 1, rightX = x;
+
+ for (int mag = 10; number / mag != 0; mag *= 10)
+ ++digits;
+
+ rightX = x + digits * 10;
+ x = rightX;
+
+ while (digits--) {
+ const int n = number % 10;
+ x -= 10;
+ drawList.add(_numbersAnim->frameIndices[n], x, y, 2000);
+ number /= 10;
+ }
+
+ return rightX;
+}
+
+void Minigame::playSound(uint index, bool loop) {
+ if (index > 0)
+ _vm->_sound->playSound(index - 1, loop);
+}
+
+void Minigame::stopSound(uint index) {
+ if (index > 0)
+ _vm->_sound->stopSound(index - 1);
+}
+
+bool Minigame::isSoundPlaying(uint index) {
+ return index > 0 && _vm->_sound->isSoundPlaying(index - 1);
+}
+
+bool Minigame::isAnySoundPlaying(const uint *indices, uint count) {
+ for (uint i = 0; i < count; ++i)
+ if (isSoundPlaying(indices[i]))
+ return true;
+ return false;
+}
+
+void Minigame::saveHiscore(int minigameNum, int score) {
+ Common::String filename = _vm->getTargetName() + "-highscore.dat";
+ Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(filename);
+ if (file) {
+ // Reserve a byte for future usage (rarely a bad idea, you never know...)
+ file->writeByte(0);
+ _hiScoreTable[minigameNum] = score;
+ for (int i = 0; i < kMinigameCount; ++i)
+ file->writeUint32LE(_hiScoreTable[i]);
+ delete file;
+ }
+}
+
+int Minigame::loadHiscore(int minigameNum) {
+ int score = 0;
+ Common::String filename = _vm->getTargetName() + "-highscore.dat";
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(filename);
+ if (file) {
+ file->readByte();
+ for (int i = 0; i < kMinigameCount; ++i)
+ _hiScoreTable[i] = file->readUint32LE();
+ delete file;
+ score = _hiScoreTable[minigameNum];
+ }
+ return score;
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/minigames/minigame.h b/engines/bbvs/minigames/minigame.h
new file mode 100644
index 0000000000..cc5a96e3c0
--- /dev/null
+++ b/engines/bbvs/minigames/minigame.h
@@ -0,0 +1,82 @@
+/* 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 BBVS_MINIGAMES_MINIGAME_H
+#define BBVS_MINIGAMES_MINIGAME_H
+
+#include "bbvs/bbvs.h"
+#include "bbvs/graphics.h"
+#include "bbvs/sound.h"
+#include "bbvs/spritemodule.h"
+
+namespace Bbvs {
+
+enum {
+ kMinigameBbLoogie = 0,
+ kMinigameBbTennis = 1,
+ kMinigameBbAnt = 2,
+ kMinigameBbAirGuitar = 3,
+ kMinigameCount
+};
+
+struct ObjAnimation {
+ int frameCount;
+ const int *frameIndices;
+ const int16 *frameTicks;
+ const BBRect *frameRects;
+};
+
+class Minigame {
+public:
+ Minigame(BbvsEngine *vm);
+ virtual ~Minigame();
+ virtual int run(bool fromMainGame) = 0;
+protected:
+ BbvsEngine *_vm;
+ SpriteModule *_spriteModule;
+
+ int _gameState;
+ int _gameTicks;
+ int _gameResult;
+ bool _gameDone;
+ bool _fromMainGame;
+ int _hiScoreTable[kMinigameCount];
+
+ int _backgroundSpriteIndex, _titleScreenSpriteIndex;
+
+ const ObjAnimation *_numbersAnim;
+
+ int drawNumber(DrawList &drawList, int number, int x, int y);
+
+ void playSound(uint index, bool loop = false);
+ void stopSound(uint index);
+ bool isSoundPlaying(uint index);
+ bool isAnySoundPlaying(const uint *indices, uint count);
+
+ void saveHiscore(int minigameNum, int score);
+ int loadHiscore(int minigameNum);
+
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_MINIGAMES_MINIGAME_H
diff --git a/engines/bbvs/module.mk b/engines/bbvs/module.mk
new file mode 100644
index 0000000000..eb6dc86332
--- /dev/null
+++ b/engines/bbvs/module.mk
@@ -0,0 +1,29 @@
+MODULE := engines/bbvs
+
+MODULE_OBJS := \
+ bbvs.o \
+ detection.o \
+ dialogs.o \
+ gamemodule.o \
+ graphics.o \
+ saveload.o \
+ sound.o \
+ spritemodule.o \
+ videoplayer.o \
+ minigames/bbairguitar.o \
+ minigames/bbairguitar_anims.o \
+ minigames/bbant.o \
+ minigames/bbant_anims.o \
+ minigames/bbloogie.o \
+ minigames/bbloogie_anims.o \
+ minigames/bbtennis.o \
+ minigames/bbtennis_anims.o \
+ minigames/minigame.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_BBVS), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/bbvs/saveload.cpp b/engines/bbvs/saveload.cpp
new file mode 100644
index 0000000000..3bb980053c
--- /dev/null
+++ b/engines/bbvs/saveload.cpp
@@ -0,0 +1,279 @@
+/* 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 "bbvs/bbvs.h"
+#include "bbvs/gamemodule.h"
+#include "common/savefile.h"
+#include "graphics/thumbnail.h"
+
+namespace Bbvs {
+
+BbvsEngine::kReadSaveHeaderError BbvsEngine::readSaveHeader(Common::SeekableReadStream *in, bool loadThumbnail, SaveHeader &header) {
+
+ header.version = in->readUint32LE();
+ if (header.version > BBVS_SAVEGAME_VERSION)
+ return kRSHEInvalidVersion;
+
+ byte descriptionLen = in->readByte();
+ header.description = "";
+ while (descriptionLen--)
+ header.description += (char)in->readByte();
+
+ if (loadThumbnail) {
+ header.thumbnail = Graphics::loadThumbnail(*in);
+ } else {
+ Graphics::skipThumbnail(*in);
+ }
+
+ // Not used yet, reserved for future usage
+ header.gameID = in->readByte();
+ header.flags = in->readUint32LE();
+
+ header.saveDate = in->readUint32LE();
+ header.saveTime = in->readUint32LE();
+ header.playTime = in->readUint32LE();
+
+ return ((in->eos() || in->err()) ? kRSHEIoError : kRSHENoError);
+}
+
+void BbvsEngine::savegame(const char *filename, const char *description) {
+
+ Common::OutSaveFile *out;
+ if (!(out = g_system->getSavefileManager()->openForSaving(filename))) {
+ warning("Can't create file '%s', game not saved", filename);
+ return;
+ }
+
+ TimeDate curTime;
+ g_system->getTimeAndDate(curTime);
+
+ // Header start
+ out->writeUint32LE(BBVS_SAVEGAME_VERSION);
+
+ byte descriptionLen = strlen(description);
+ out->writeByte(descriptionLen);
+ out->write(description, descriptionLen);
+
+ Graphics::saveThumbnail(*out);
+
+ // Not used yet, reserved for future usage
+ out->writeByte(0);
+ out->writeUint32LE(0);
+ uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF);
+ uint32 saveTime = ((curTime.tm_hour & 0xFF) << 16) | (((curTime.tm_min) & 0xFF) << 8) | ((curTime.tm_sec) & 0xFF);
+ uint32 playTime = g_engine->getTotalPlayTime() / 1000;
+ out->writeUint32LE(saveDate);
+ out->writeUint32LE(saveTime);
+ out->writeUint32LE(playTime);
+ // Header end
+
+ out->write(_snapshot, _snapshotStream->pos());
+
+ out->finalize();
+ delete out;
+}
+
+void BbvsEngine::loadgame(const char *filename) {
+ Common::InSaveFile *in;
+ if (!(in = g_system->getSavefileManager()->openForLoading(filename))) {
+ warning("Can't open file '%s', game not loaded", filename);
+ return;
+ }
+
+ SaveHeader header;
+
+ kReadSaveHeaderError errorCode = readSaveHeader(in, false, header);
+
+ if (errorCode != kRSHENoError) {
+ warning("Error loading savegame '%s'", filename);
+ delete in;
+ return;
+ }
+
+ g_engine->setTotalPlayTime(header.playTime * 1000);
+
+ memset(_sceneObjects, 0, sizeof(_sceneObjects));
+ for (int i = 0; i < kSceneObjectsCount; ++i) {
+ _sceneObjects[i].walkDestPt.x = -1;
+ _sceneObjects[i].walkDestPt.y = -1;
+ }
+
+ _currSceneNum = 0;
+ _newSceneNum = in->readUint32LE();
+
+ initScene(false);
+
+ _prevSceneNum = in->readUint32LE();
+ _gameState = in->readUint32LE();
+ _mouseCursorSpriteIndex = in->readUint32LE();
+ _mousePos.x = in->readUint16LE();
+ _mousePos.y = in->readUint16LE();
+ _currVerbNum = in->readUint32LE();
+ _activeItemType = in->readUint32LE();
+ _activeItemIndex = in->readUint32LE();
+ _verbPos.x = in->readUint16LE();
+ _verbPos.y = in->readUint16LE();
+ _inventoryButtonIndex = in->readUint32LE();
+ _currInventoryItem = in->readUint32LE();
+ _currTalkObjectIndex = in->readUint32LE();
+ _currCameraNum = in->readUint32LE();
+ _cameraPos.x = in->readUint16LE();
+ _cameraPos.y = in->readUint16LE();
+ _newCameraPos.x = in->readUint16LE();
+ _newCameraPos.y = in->readUint16LE();
+ _dialogSlotCount = in->readUint32LE();
+ _walkMousePos.x = in->readUint16LE();
+ _walkMousePos.y = in->readUint16LE();
+ in->read(_backgroundSoundsActive, kSceneSoundsCount);
+ in->read(_inventoryItemStatus, kInventoryItemStatusCount);
+ in->read(_dialogItemStatus, kDialogItemStatusCount);
+ in->read(_gameVars, kGameVarsCount);
+ in->read(_sceneVisited, kSceneVisitedCount);
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *obj = &_sceneObjects[i];
+ obj->x = in->readUint32LE();
+ obj->y = in->readUint32LE();
+ obj->animIndex = in->readUint32LE();
+ obj->frameIndex = in->readUint32LE();
+ obj->frameTicks = in->readUint32LE();
+ obj->walkCount = in->readUint32LE();
+ obj->xIncr = in->readUint32LE();
+ obj->yIncr = in->readUint32LE();
+ obj->turnValue = in->readUint32LE();
+ obj->turnCount = in->readUint32LE();
+ obj->turnTicks = in->readUint32LE();
+ obj->walkDestPt.x = in->readUint16LE();
+ obj->walkDestPt.y = in->readUint16LE();
+ obj->anim = obj->animIndex > 0 ? _gameModule->getAnimation(obj->animIndex) : 0;
+ }
+
+ updateWalkableRects();
+
+ // Restart scene background sounds
+ for (int i = 0; i < _gameModule->getSceneSoundsCount(); ++i) {
+ if (_backgroundSoundsActive[i]) {
+ SceneSound *sceneSound = _gameModule->getSceneSound(i);
+ playSound(sceneSound->soundNum, true);
+ }
+ }
+
+ _currAction = 0;
+ _currActionCommandIndex = -1;
+
+ delete in;
+
+}
+
+Common::Error BbvsEngine::loadGameState(int slot) {
+ const char *fileName = getSavegameFilename(slot);
+ loadgame(fileName);
+ return Common::kNoError;
+}
+
+Common::Error BbvsEngine::saveGameState(int slot, const Common::String &description) {
+ const char *fileName = getSavegameFilename(slot);
+ savegame(fileName, description.c_str());
+ return Common::kNoError;
+}
+
+const char *BbvsEngine::getSavegameFilename(int num) {
+ static Common::String filename;
+ filename = getSavegameFilename(_targetName, num);
+ return filename.c_str();
+}
+
+Common::String BbvsEngine::getSavegameFilename(const Common::String &target, int num) {
+ assert(num >= 0 && num <= 999);
+ return Common::String::format("%s.%03d", target.c_str(), num);
+}
+
+bool BbvsEngine::existsSavegame(int num) {
+ return _system->getSavefileManager()->listSavefiles(getSavegameFilename(_targetName, num)).size() != 0;
+}
+
+void BbvsEngine::allocSnapshot() {
+ _snapshotSize = 23072;
+ _snapshot = new byte[_snapshotSize];
+ _snapshotStream = new Common::SeekableMemoryWriteStream(_snapshot, _snapshotSize);
+}
+
+void BbvsEngine::freeSnapshot() {
+ delete _snapshotStream;
+ delete[] _snapshot;
+}
+
+void BbvsEngine::saveSnapshot() {
+ _hasSnapshot = true;
+ _snapshotStream->seek(0);
+ _snapshotStream->writeUint32LE(_currSceneNum);
+ _snapshotStream->writeUint32LE(_prevSceneNum);
+ _snapshotStream->writeUint32LE(_gameState);
+ _snapshotStream->writeUint32LE(_mouseCursorSpriteIndex);
+ _snapshotStream->writeUint16LE(_mousePos.x);
+ _snapshotStream->writeUint16LE(_mousePos.y);
+ _snapshotStream->writeUint32LE(_currVerbNum);
+ _snapshotStream->writeUint32LE(_activeItemType);
+ _snapshotStream->writeUint32LE(_activeItemIndex);
+ _snapshotStream->writeUint16LE(_verbPos.x);
+ _snapshotStream->writeUint16LE(_verbPos.y);
+ _snapshotStream->writeUint32LE(_inventoryButtonIndex);
+ _snapshotStream->writeUint32LE(_currInventoryItem);
+ _snapshotStream->writeUint32LE(_currTalkObjectIndex);
+ _snapshotStream->writeUint32LE(_currCameraNum);
+ _snapshotStream->writeUint16LE(_cameraPos.x);
+ _snapshotStream->writeUint16LE(_cameraPos.y);
+ _snapshotStream->writeUint16LE(_newCameraPos.x);
+ _snapshotStream->writeUint16LE(_newCameraPos.y);
+ _snapshotStream->writeUint32LE(_dialogSlotCount);
+ _snapshotStream->writeUint16LE(_walkMousePos.x);
+ _snapshotStream->writeUint16LE(_walkMousePos.y);
+ _snapshotStream->write(_backgroundSoundsActive, kSceneSoundsCount);
+ _snapshotStream->write(_inventoryItemStatus, kInventoryItemStatusCount);
+ _snapshotStream->write(_dialogItemStatus, kDialogItemStatusCount);
+ _snapshotStream->write(_gameVars, kGameVarsCount);
+ _snapshotStream->write(_sceneVisited, kSceneVisitedCount);
+ for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) {
+ SceneObject *obj = &_sceneObjects[i];
+ _snapshotStream->writeUint32LE(obj->x);
+ _snapshotStream->writeUint32LE(obj->y);
+ _snapshotStream->writeUint32LE(obj->animIndex);
+ _snapshotStream->writeUint32LE(obj->frameIndex);
+ _snapshotStream->writeUint32LE(obj->frameTicks);
+ _snapshotStream->writeUint32LE(obj->walkCount);
+ _snapshotStream->writeUint32LE(obj->xIncr);
+ _snapshotStream->writeUint32LE(obj->yIncr);
+ _snapshotStream->writeUint32LE(obj->turnValue);
+ _snapshotStream->writeUint32LE(obj->turnCount);
+ _snapshotStream->writeUint32LE(obj->turnTicks);
+ _snapshotStream->writeUint16LE(obj->walkDestPt.x);
+ _snapshotStream->writeUint16LE(obj->walkDestPt.y);
+ }
+}
+
+void BbvsEngine::writeContinueSavegame() {
+ if (_hasSnapshot) {
+ saveGameState(0, "Continue");
+ }
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/sound.cpp b/engines/bbvs/sound.cpp
new file mode 100644
index 0000000000..7f9c00ad48
--- /dev/null
+++ b/engines/bbvs/sound.cpp
@@ -0,0 +1,107 @@
+/* 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 "bbvs/sound.h"
+#include "audio/decoders/aiff.h"
+#include "common/debug.h"
+#include "common/file.h"
+#include "common/system.h"
+
+namespace Bbvs {
+
+Sound::Sound() : _stream(0) {
+}
+
+Sound::~Sound() {
+ stop();
+ delete _stream;
+}
+
+void Sound::load(const Common::String &filename) {
+ Common::File *fd = new Common::File();
+ if (!fd->open(filename)) {
+ delete fd;
+ error("SoundMan::loadSound() Could not load %s", filename.c_str());
+ }
+ _stream = Audio::makeAIFFStream(fd, DisposeAfterUse::YES);
+ _filename = filename;
+}
+
+void Sound::play(bool loop) {
+ debug(0, "Sound::play() [%s] loop:%d", _filename.c_str(), loop);
+ stop();
+ _stream->rewind();
+ Audio::AudioStream *audioStream = Audio::makeLoopingAudioStream(_stream, loop ? 0 : 1);
+ g_system->getMixer()->playStream(Audio::Mixer::kSFXSoundType, &_handle, audioStream,
+ -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+}
+
+void Sound::stop() {
+ g_system->getMixer()->stopHandle(_handle);
+}
+
+bool Sound::isPlaying() {
+ return g_system->getMixer()->isSoundHandleActive(_handle);
+}
+
+SoundMan::~SoundMan() {
+ stopAllSounds();
+ unloadSounds();
+}
+
+void SoundMan::loadSound(const Common::String &filename) {
+ Sound *sound = new Sound();
+ sound->load(filename);
+ _sounds.push_back(sound);
+}
+
+void SoundMan::playSound(uint index, bool loop) {
+ _sounds[index]->play(loop);
+}
+
+void SoundMan::stopSound(uint index) {
+ _sounds[index]->stop();
+}
+
+bool SoundMan::isSoundPlaying(uint index) {
+ return _sounds[index]->isPlaying();
+}
+
+bool SoundMan::isAnySoundPlaying(uint *indices, uint count) {
+ for (uint i = 0; i < count; ++i)
+ if (isSoundPlaying(indices[i]))
+ return true;
+ return false;
+}
+
+void SoundMan::unloadSounds() {
+ for (uint i = 0; i < _sounds.size(); ++i)
+ delete _sounds[i];
+ _sounds.clear();
+}
+
+void SoundMan::stopAllSounds() {
+ for (uint i = 0; i < _sounds.size(); ++i)
+ _sounds[i]->stop();
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/sound.h b/engines/bbvs/sound.h
new file mode 100644
index 0000000000..4e44c2b962
--- /dev/null
+++ b/engines/bbvs/sound.h
@@ -0,0 +1,63 @@
+/* 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 BBVS_SOUND_H
+#define BBVS_SOUND_H
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "common/array.h"
+
+namespace Bbvs {
+
+class Sound {
+public:
+ Sound();
+ ~Sound();
+ void load(const Common::String &filename);
+ void play(bool loop);
+ void stop();
+ bool isPlaying();
+protected:
+ Audio::SeekableAudioStream *_stream;
+ Audio::SoundHandle _handle;
+ // Keep the filename for debugging purposes
+ Common::String _filename;
+};
+
+class SoundMan {
+public:
+ ~SoundMan();
+ void loadSound(const Common::String &fileName);
+ void playSound(uint index, bool loop = false);
+ void stopSound(uint index);
+ bool isSoundPlaying(uint index);
+ bool isAnySoundPlaying(uint *indices, uint count);
+ void unloadSounds();
+ void stopAllSounds();
+protected:
+ Common::Array<Sound*> _sounds;
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_SOUND_H
diff --git a/engines/bbvs/spritemodule.cpp b/engines/bbvs/spritemodule.cpp
new file mode 100644
index 0000000000..8eae7f9a6a
--- /dev/null
+++ b/engines/bbvs/spritemodule.cpp
@@ -0,0 +1,112 @@
+/* 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 "bbvs/spritemodule.h"
+
+namespace Bbvs {
+
+byte *Sprite::getRow(int y) {
+ if (type == 1)
+ return data + READ_LE_UINT32((data + offset) + y * 4);
+ else
+ return data + offset + y * width;
+}
+
+SpriteModule::SpriteModule()
+ : _spritesCount(0), _paletteStart(0), _paletteCount(0), _spriteData(0) {
+}
+
+SpriteModule::~SpriteModule() {
+ unload();
+}
+
+void SpriteModule::load(const char *filename) {
+ unload();
+
+ Common::File fd;
+ if (!fd.open(filename))
+ error("SpriteModule::load() Could not open %s", filename);
+
+ fd.readUint32LE(); // Skip magic
+ fd.readUint32LE(); // Skip unused
+ fd.readUint32LE(); // Skip filesize
+
+ _paletteOffs = fd.readUint32LE();
+ fd.readUint32LE(); // Skip unused flagsTbl1Ofs
+ fd.readUint32LE(); // Skip unused flagsTbl2Ofs
+ _spriteTblOffs = fd.readUint32LE();
+ _paletteStart = fd.readUint32LE();
+ _paletteCount = fd.readUint32LE();
+ _spritesCount = fd.readUint32LE();
+
+ debug(0, "_paletteOffs: %08X", _paletteOffs);
+ debug(0, "_spriteTblOffs: %08X", _spriteTblOffs);
+ debug(0, "_paletteStart: %d", _paletteStart);
+ debug(0, "_paletteCount: %d", _paletteCount);
+ debug(0, "_spritesCount: %d", _spritesCount);
+
+ _spriteDataSize = fd.size();
+ _spriteData = new byte[_spriteDataSize];
+ fd.seek(0);
+ fd.read(_spriteData, _spriteDataSize);
+
+ // Convert palette
+ byte *palette = _spriteData + _paletteOffs;
+ for (int i = 0; i < _paletteCount; ++i) {
+ palette[i * 3 + 0] <<= 2;
+ palette[i * 3 + 1] <<= 2;
+ palette[i * 3 + 2] <<= 2;
+ }
+
+}
+
+Sprite SpriteModule::getSprite(int index) {
+ Sprite sprite;
+ uint32 spriteOffs = READ_LE_UINT32(_spriteData + _spriteTblOffs + index * 4);
+ byte *info = _spriteData + spriteOffs;
+ sprite.data = _spriteData;
+ sprite.offset = READ_LE_UINT32(info + 0);
+ sprite.type = READ_LE_UINT32(info + 4);
+ sprite.width = READ_LE_UINT32(info + 8);
+ sprite.height = READ_LE_UINT32(info + 12);
+ sprite.xOffs = READ_LE_UINT32(info + 16);
+ sprite.yOffs = READ_LE_UINT32(info + 20);
+ return sprite;
+}
+
+Palette SpriteModule::getPalette() {
+ Palette palette;
+ palette.data = _spriteData + _paletteOffs;
+ palette.start = _paletteStart;
+ palette.count = _paletteCount;
+ return palette;
+}
+
+void SpriteModule::unload() {
+ _spritesCount = 0;
+ _paletteStart = 0;
+ _paletteCount = 0;
+ delete[] _spriteData;
+ _spriteData = 0;
+}
+
+} // End of namespace Bbvs
diff --git a/engines/bbvs/spritemodule.h b/engines/bbvs/spritemodule.h
new file mode 100644
index 0000000000..c287815dec
--- /dev/null
+++ b/engines/bbvs/spritemodule.h
@@ -0,0 +1,68 @@
+/* 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 BBVS_SPRITEMODULE_H
+#define BBVS_SPRITEMODULE_H
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/memstream.h"
+#include "common/rect.h"
+#include "common/str.h"
+
+namespace Bbvs {
+
+struct Sprite {
+ int type;
+ int xOffs, yOffs;
+ int width, height;
+ byte *data;
+ uint32 offset;
+ byte *getRow(int y);
+};
+
+struct Palette {
+ byte *data;
+ int start, count;
+};
+
+class SpriteModule {
+public:
+ SpriteModule();
+ ~SpriteModule();
+ void load(const char *filename);
+ int getSpriteCount() { return _spritesCount; }
+ Sprite getSprite(int index);
+ Palette getPalette();
+protected:
+ byte *_spriteData;
+ int _spriteDataSize;
+ int _spritesCount;
+ uint32 _spriteTblOffs;
+ uint32 _paletteOffs;
+ int _paletteStart, _paletteCount;
+ void unload();
+};
+
+} // End of namespace Bbvs
+
+#endif // BBVS_SPRITEMODULE_H
diff --git a/engines/bbvs/videoplayer.cpp b/engines/bbvs/videoplayer.cpp
new file mode 100644
index 0000000000..85cc5ed544
--- /dev/null
+++ b/engines/bbvs/videoplayer.cpp
@@ -0,0 +1,78 @@
+/* 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 "bbvs/bbvs.h"
+#include "engines/util.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+#include "video/avi_decoder.h"
+
+namespace Bbvs {
+
+void BbvsEngine::playVideo(int videoNum) {
+ Common::String videoFilename;
+
+ if (videoNum >= 100)
+ videoFilename = Common::String::format("snd/snd%05d.aif", videoNum + 1400);
+ else
+ videoFilename = Common::String::format("vid/video%03d.avi", videoNum - 1);
+
+ // Set the correct video mode
+ initGraphics(320, 240, false, 0);
+ if (_system->getScreenFormat().bytesPerPixel == 1) {
+ warning("Couldn't switch to a RGB color video mode to play a video.");
+ return;
+ }
+
+ Video::VideoDecoder *videoDecoder = new Video::AVIDecoder();
+ videoDecoder->loadFile(videoFilename);
+
+ videoDecoder->start();
+
+ bool skipVideo = false;
+
+ while (!shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
+ if (videoDecoder->needsUpdate()) {
+ const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
+ if (frame) {
+ _system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h);
+ _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;
+ }
+
+ _system->delayMillis(10);
+ }
+
+ delete videoDecoder;
+
+ initGraphics(320, 240, false);
+
+}
+
+} // End of namespace Bbvs