diff options
34 files changed, 12020 insertions, 0 deletions
diff --git a/engines/bbvs/bbvs.cpp b/engines/bbvs/bbvs.cpp new file mode 100644 index 0000000000..2b0a4a5d51 --- /dev/null +++ b/engines/bbvs/bbvs.cpp @@ -0,0 +1,2196 @@ +/* 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/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 + 0, 43, 23, 12, 4, 44, 2, + 16, 4, 4, 4, 44, 12, 32 +}; + +const int kMainMenu = 44; + +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(); + + _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; + + //_newSceneNum = 23; // Class room + _newSceneNum = kMainMenu; // Main menu (TODO Buttons etc.) + //_newSceneNum = 25;// Tank and crash + //_newSceneNum = 7; + //_newSceneNum = 12; + + 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(); + if (_playVideoNumber > 0) { + playVideo(_playVideoNumber); + _playVideoNumber = 0; + } + } + + writeContinueSavegame(); + + freeSnapshot(); + + delete _sound; + delete _spriteModule; + delete _gameModule; + delete _screen; + + debug(0, "run() done"); + + 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: + _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(); + } + +} + +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("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 == 45) { + // Play secret video + stopSounds(); + _playVideoNumber = _newSceneNum; + _currSceneNum = 49; + _newSceneNum = 45; + } 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 ((sceneObject->x >> 16) != soAction->walkDest.x || (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(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; + } + } +} + +bool BbvsEngine::rectIntersection(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect &outRect) { + outRect.left = MAX(rect1.left, rect2.left); + outRect.top = MAX(rect1.top, rect2.top); + outRect.right = MIN(rect1.right, rect2.right); + outRect.bottom = MIN(rect1.bottom, rect2.bottom); + return !outRect.isEmpty(); +} + +int BbvsEngine::rectSubtract(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect *outRects) { + int count = 0; + Common::Rect workRect; + if (rectIntersection(rect1, rect2, workRect)) { + 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; + + // TODO This needs some cleanup but seems to work + + 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::makeLoopingAudioStream(Audio::makeAIFFStream(fd, DisposeAfterUse::YES), 1); + _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("BbvsEngine::runMinigame() minigameNum: %d", minigameNum); + + int callFlags = 0; + + if (_currSceneNum != kMainMenu) + callFlags = 1; + + _sound->unloadSounds(); + + Minigame *minigame = 0; + + switch (minigameNum) { + case 0: + minigame = new MinigameBbloogie(this); + break; + case 1: + minigame = new MinigameBbTennis(this); + break; + case 2: + minigame = new MinigameBbAnt(this); + break; + case 3: + minigame = new MinigameBbAirGuitar(this); + break; + default: + error("Incorrect minigame number %d", minigameNum); + break; + } + + int minigameResult = minigame->run(callFlags); + + delete minigame; + + // Check if the prinicpal was hit with a megaloogie in the loogie minigame + if (minigameNum == 0 && minigameResult == 1) + _gameVars[42] = 1; + + //DEBUG Fake it :) + if (minigameNum == 0) + _gameVars[42] = 1; + + return true; +} + +void BbvsEngine::runMainMenu() { + MainMenu *mainMenu = new MainMenu(this); + mainMenu->runModal(); + delete mainMenu; +} + +} // End of namespace Bbvs diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h new file mode 100644 index 0000000000..eaeb529fb8 --- /dev/null +++ b/engines/bbvs/bbvs.h @@ -0,0 +1,412 @@ +/* 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_H +#define 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 { + int 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); +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; + + 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); + + bool rectIntersection(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect &outRect); + 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(); + + // 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_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..698380dfc1 --- /dev/null +++ b/engines/bbvs/detection.cpp @@ -0,0 +1,161 @@ +/* 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", "Bbvs" }, + { 0, 0 } +}; + +namespace Bbvs { + +static const ADGameDescription gameDescriptions[] = { + { + "bbvs", "", + { + {"game0001.vnm", 0, "637e5411751c7065bc385dd73d224561", 64004}, + AD_LISTEND + }, + 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..9ecc33aaab --- /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..abc5086a7d --- /dev/null +++ b/engines/bbvs/gamemodule.cpp @@ -0,0 +1,630 @@ +/* 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 { + +#define DEBUG_DUMP + +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(); + +#ifdef DEBUG_DUMP + for (int i = 0; i < _bgSpriteCount; ++i) { + debug(0, "BgSprite(%d) %04X %d", i, _bgSpriteIndices[i], _bgSpritePriorities[i]); + } +#endif + +} + +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); + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < 4; ++i) { + CameraInit &cameraInit = _cameraInits[i]; + debug(0, "CameraInit(%d) (%d, %d)", i, cameraInit.cameraPos.x, cameraInit.cameraPos.y); + debugN(0, "CameraInit(%d) ", i); + for (int j = 0; j < 8; ++j) + debugN(0, "%d ", cameraInit.cameraLinks[j]); + debug(0, "."); + for (int j = 0; j < 8; ++j) + debug(0, "CameraInit(%d) (%d, %d, %d, %d)", i, cameraInit.rects[j].left, + cameraInit.rects[j].top, cameraInit.rects[j].right, cameraInit.rects[j].bottom); + } +#endif + +} + +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); + +#ifdef DEBUG_DUMP +#endif + +} + +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(); + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < _sceneExitsCount; ++i) { + debug(0, "SceneExit(%d) (%d, %d, %d, %d) %d", i, _sceneExits[i].rect.left, _sceneExits[i].rect.top, + _sceneExits[i].rect.right, _sceneExits[i].rect.bottom, _sceneExits[i].newModuleNum); + } +#endif + +} + +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); + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < _bgObjectsCount; ++i) { + debug(0, "BgObject(%d) [%s] (%d, %d, %d, %d)", i, _bgObjects[i].name, _bgObjects[i].rect.left, + _bgObjects[i].rect.top, _bgObjects[i].rect.right, _bgObjects[i].rect.bottom); + } +#endif + +} + +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); + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < _animationsCount; ++i) { + Animation &anim = _animations[i]; + debug(0, "Animation(%d) frameCount: %d", i, anim.frameCount); + for (int j = 0; j < anim.frameCount; ++j) { + debug(0, "Frame %d: %04X %d (%d, %d, %d, %d) (%d, %d, %d, %d) ", + j, anim.frameSpriteIndices[j], anim.frameTicks[j], + anim.frameRects1[j].left, anim.frameRects1[j].top, anim.frameRects1[j].right, + anim.frameRects1[j].bottom, anim.frameRects2[j].left, anim.frameRects2[j].top, + anim.frameRects2[j].right, anim.frameRects2[j].bottom); + } + } +#endif + +} + +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(); + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < _sceneObjectDefsCount; ++i) { + debugN(0, "SceneObjectDef(%d) [%s] %d ", i, _sceneObjectDefs[i].name, _sceneObjectDefs[i].walkSpeed); + for (int j = 0; j < 16; ++j) + debugN(0, " %d", _sceneObjectDefs[i].animIndices[j]); + debug(0, "."); + } +#endif + +} + +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(); + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < _sceneObjectInitsCount; ++i) { + debug(0, "SceneObjectInit(%d) %d %d (%d, %d)", i, _sceneObjectInits[i].sceneObjectIndex, + _sceneObjectInits[i].animIndex, _sceneObjectInits[i].x, _sceneObjectInits[i].y); + for (int j = 0; j < 8; ++j) + debug(0, " condition(%d) %d %d %d", j, _sceneObjectInits[i].conditions.conditions[j].cond, + _sceneObjectInits[i].conditions.conditions[j].value1, _sceneObjectInits[i].conditions.conditions[j].value2); + } +#endif + +} + +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); + } + } + +#ifdef DEBUG_DUMP + for (int i = 0; i < _actionsCount; ++i) { + debug(0, "Action(%d)", i); + for (int j = 0; j < 8; ++j) + debug(0, " condition(%d) %d %d %d", j, _actions[i].conditions.conditions[j].cond, + _actions[i].conditions.conditions[j].value1, _actions[i].conditions.conditions[j].value2); + for (int j = 0; j < 8; ++j) + debug(0, " result(%d) %d %d %d", j, _actions[i].results.actionResults[j].kind, + _actions[i].results.actionResults[j].value1, _actions[i].results.actionResults[j].value2); + for (uint j = 0; j < _actions[i].actionCommands.size(); ++j) { + ActionCommand &actionCommand = _actions[i].actionCommands[j]; + debug(0, " entry(%d) cmd: %d sceneObjectIndex: %d timeStamp: %d walkDest: (%d, %d) param: %d", j, actionCommand.cmd, actionCommand.sceneObjectIndex, + actionCommand.timeStamp, actionCommand.walkDest.x, actionCommand.walkDest.y, + actionCommand.param); + } + } +#endif + +} + +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(); + +#ifdef DEBUG_DUMP +#endif + +} + +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(); + +#ifdef DEBUG_DUMP +#endif + +} + +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 + } + +#ifdef DEBUG_DUMP +#endif + +} + +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(); + } + +#ifdef DEBUG_DUMP +#endif + +} + +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(); + } + +#ifdef DEBUG_DUMP + debug("_sceneSoundsCount: %d", _sceneSoundsCount); + for (int i = 0; i < _sceneSoundsCount; ++i) { + debug("sound(%d) soundNum: %d", i, _sceneSounds[i].soundNum); + } +#endif + +} + +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(); + +#ifdef DEBUG_DUMP + debug("_preloadSoundsCount: %d", _preloadSoundsCount); + for (uint i = 0; i < _preloadSoundsCount; ++i) { + debug("preloadSound(%d) soundNum: %d", i, _preloadSounds[i]); + } +#endif + +} + +} // End of namespace Bbvs diff --git a/engines/bbvs/gamemodule.h b/engines/bbvs/gamemodule.h new file mode 100644 index 0000000000..ffd2488c21 --- /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_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..277cf453cb --- /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_H diff --git a/engines/bbvs/minigames/bbairguitar.cpp b/engines/bbvs/minigames/bbairguitar.cpp new file mode 100644 index 0000000000..f81bb498fd --- /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 *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 *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(uint flags) { + + memset(_objects, 0, sizeof(_objects)); + + _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 = false; + if (flags & 1) + _fromMainGame = true; + + _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(); + } + + // Unload sounds + _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(); + +} + +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 PostMessageA(hWndParent, WM_COMMAND, 0x9C6Du, 0); + 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 PostMessageA(hWndParent, WM_COMMAND, 0x9C6Eu, 0); + 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..70ba5800ce --- /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(uint flags); +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_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..24dbd45b81 --- /dev/null +++ b/engines/bbvs/minigames/bbant.cpp @@ -0,0 +1,1340 @@ +/* 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 { + +struct Point { + int x, y; +}; + +static const Point kPosIncrTbl1[] = { + {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, + { 0, 1}, { 1, 1}, { 1, 0}, { 1, -1} +}; + +static const Point 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 *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; + const int kMaxBugsCount = 1;//DEBUG + + --_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; + } + +debug(0, "updateStatus1 #2"); + if ((mouseButtons & kRightButtonClicked) && (_stompCount > 0|| _hasLastStompObj) && !_objects[2].status) { + if (_hasLastStompObj) + removeStompObj(_lastStompObj); + --_stompCount; + _objects[2].status = 1; + } + +debug(0, "updateStatus1 #3"); + 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); + } + +debug(0, "updateStatus1 #4"); + if (_skullBugCtr > 0) { + if (--_skullBugCtr == 0) { + _skullBugCtr = _vm->getRandom(150) + 500; + insertRandomBugObj(5); + } + } + + if (_stompCounter2 > 0) + --_stompCounter2; + +debug(0, "updateStatus1 #5"); + if (_totalBugsCount < kMaxBugsCount && _vm->getRandom(_stompCounter2) == 0) { + int testTbl[4]; + int maxKindCount = 0, objKind = 0; + + _stompCounter2 = _stompCounter1; + +debug(0, "updateStatus1 #6"); + for (int i = 0; i < 4; ++i) + testTbl[i] = _vm->getRandom(_bugsChanceByKind[i] - _bugsCountByKind[i]); + +debug(0, "updateStatus1 #7"); + for (int i = 0; i < 4; ++i) { + if (testTbl[i] >= maxKindCount) { + maxKindCount = testTbl[i]; + objKind = i + 1; + } + } + +debug(0, "updateStatus1 #8"); + if (objKind) + insertRandomBugObj(objKind); + + } + +debug(0, "updateStatus1 #9"); + updateObjs(mouseButtons); +debug(0, "updateStatus1 #10"); + updateFootObj(2); + + if (--_countdown10 == 0) { + _countdown10 = 140; + if (_stompCounter1 > 20) + --_stompCounter1; + } + +debug(0, "updateStatus1 #XXX"); + 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); + debug("obj->anim(130): %d", obj->anim->frameIndices[0]); + 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 **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 **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 **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 **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 **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 **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 **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 **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; + debug("bug %d has candy %d", i, candyObjIndex); + 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)) { + debug("yes"); + 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(uint flags) { + + memset(_objects, 0, sizeof(_objects)); + + _numbersAnim = getAnimation(167); + + _backgroundSpriteIndex = 303; + _titleScreenSpriteIndex = 304; + + _fromMainGame = false; + if (flags & 1) + _fromMainGame = true; + + _hiScore = 0; + _gameState = 0; + _gameResult = 0; + _gameDone = false; + initObjects(); + initVars(); + + _spriteModule = new SpriteModule(); + _spriteModule->load("bbant/bbant.000"); + + Palette palette = _spriteModule->getPalette(); + _vm->_screen->setPalette(palette); + + // Load sounds + loadSounds(); + + _gameTicks = 0; + playSound(12, true); + + while (!_vm->shouldQuit() &&!_gameDone) { + _vm->updateEvents(); + update(); + } + + // Unload sounds + _vm->_sound->unloadSounds(); + + 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(); + +} + +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; + } + + 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; + } + + 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()); + } +} + +void MinigameBbAnt::playSound(uint index, bool loop) { + if (index > 0) + _vm->_sound->playSound(index - 1, loop); +} + +void MinigameBbAnt::stopSound(uint index) { + if (index > 0) + _vm->_sound->stopSound(index - 1); +} + +bool MinigameBbAnt::isSoundPlaying(uint index) { + return index > 0 && _vm->_sound->isSoundPlaying(index - 1); +} + +bool MinigameBbAnt::isAnySoundPlaying(const uint *indices, uint count) { + for (uint i = 0; i < count; ++i) + if (isSoundPlaying(indices[i])) + return true; + return false; +} + +} // End of namespace Bbvs diff --git a/engines/bbvs/minigames/bbant.h b/engines/bbvs/minigames/bbant.h new file mode 100644 index 0000000000..b9919ee14b --- /dev/null +++ b/engines/bbvs/minigames/bbant.h @@ -0,0 +1,177 @@ +/* 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(uint flags); +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 **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(); + void playSound(uint index, bool loop = false); + void stopSound(uint index); + bool isSoundPlaying(uint index); + bool isAnySoundPlaying(const uint *indices, uint count); + +}; + +} // End of namespace Bbvs + +#endif // BBVS_H diff --git a/engines/bbvs/minigames/bbant_anims.cpp b/engines/bbvs/minigames/bbant_anims.cpp new file mode 100644 index 0000000000..9527b7aa4e --- /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 *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 **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 **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..4098eb2d94 --- /dev/null +++ b/engines/bbvs/minigames/bbloogie.cpp @@ -0,0 +1,1361 @@ +/* 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 *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 = kGSMainGame; + if (!_fromMainGame) + _gameState = 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(uint flags) { + + memset(_objects, 0, sizeof(_objects)); + + _numbersAnim = getAnimation(9); + + _backgroundSpriteIndex = 210; + _titleScreenSpriteIndex = 211; + + _fromMainGame = false; + if (flags & 1) + _fromMainGame = true; + + _hiScore = 0; + if (!_fromMainGame) { + // TODO Load LoogieHiScore + } + + _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); + + // Load sounds + loadSounds(); + + playSound(32, true); + + while (!_vm->shouldQuit() &&!_gameDone) { + _vm->updateEvents(); + update(); + } + + // Unload sounds + _vm->_sound->unloadSounds(); + + if (!_fromMainGame) { + // TODO Save LoogieHiScore + } + + 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(); + +} + +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..b05536b001 --- /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(uint flags); +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_H diff --git a/engines/bbvs/minigames/bbloogie_anims.cpp b/engines/bbvs/minigames/bbloogie_anims.cpp new file mode 100644 index 0000000000..61a2e48eb7 --- /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..87ea355a10 --- /dev/null +++ b/engines/bbvs/minigames/bbtennis.cpp @@ -0,0 +1,1278 @@ +/* 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 *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(uint flags) { + + memset(_objects, 0, sizeof(_objects)); + + _numbersAnim = getAnimation(20); + + _backgroundSpriteIndex = 272; + _titleScreenSpriteIndex = 273; + + _fromMainGame = false; + if (flags & 1) + _fromMainGame = true; + + _hiScore = 0; + if (!_fromMainGame) { + // TODO Load HiScore + } + + _gameState = 0; + _gameResult = 0; + _gameDone = false; + initObjects(); + initVars(); + + _spriteModule = new SpriteModule(); + _spriteModule->load("bbtennis/bbtennis.000"); + + Palette palette = _spriteModule->getPalette(); + _vm->_screen->setPalette(palette); + + // Load sounds + loadSounds(); + + _gameTicks = 0; + playSound(29, true); + + while (!_vm->shouldQuit() &&!_gameDone) { + _vm->updateEvents(); + update(); + } + + // Unload sounds + _vm->_sound->unloadSounds(); + + if (!_fromMainGame) { + // TODO Save 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(); + +} + +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..63617c968c --- /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(uint flags); +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_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..299836ab00 --- /dev/null +++ b/engines/bbvs/minigames/minigame.cpp @@ -0,0 +1,74 @@ +/* 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" + +namespace Bbvs { + +Minigame::Minigame(BbvsEngine *vm) + : _vm(vm), _spriteModule(0) { +} + +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; +} + +} // End of namespace Bbvs diff --git a/engines/bbvs/minigames/minigame.h b/engines/bbvs/minigames/minigame.h new file mode 100644 index 0000000000..09630ae228 --- /dev/null +++ b/engines/bbvs/minigames/minigame.h @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef 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 { + +struct ObjAnimation { + int frameCount; + const int *frameIndices; + const int16 *frameTicks; + const BBRect *frameRects; +}; + +class Minigame { +public: + Minigame(BbvsEngine *vm); + virtual ~Minigame(); + virtual int run(uint flags) = 0; +public: + BbvsEngine *_vm; + SpriteModule *_spriteModule; + + int _gameState; + int _gameTicks; + int _gameResult; + bool _gameDone; + bool _fromMainGame; + + 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); + +}; + +} // End of namespace Bbvs + +#endif // BBVS_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..6714cd0ea1 --- /dev/null +++ b/engines/bbvs/saveload.cpp @@ -0,0 +1,287 @@ +/* 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; +#if 0 + debug("obj(%d) [%s]:", i, obj->sceneObjectDef->name); + debug("\tx: %d; y: %d; animIndex: %d", obj->x, obj->y, obj->animIndex); + debug("\tframeIndex: %d; frameTicks: %d", obj->frameIndex, obj->frameTicks); + debug("\twalkCount: %d; xIncr: %d; yIncr: %d", obj->walkCount, obj->xIncr, obj->yIncr); + debug("\tturnValue: %d; turnValue: %d; turnTicks: %d", obj->turnValue, obj->turnCount, obj->turnTicks); + debug("\twalkDestPt.x: %d; walkDestPt.y: %d", obj->walkDestPt.x, obj->walkDestPt.y); +#endif + } + + 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..24f14fc70f --- /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_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..13469f7543 --- /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_H diff --git a/engines/bbvs/videoplayer.cpp b/engines/bbvs/videoplayer.cpp new file mode 100644 index 0000000000..2da4cd0b6a --- /dev/null +++ b/engines/bbvs/videoplayer.cpp @@ -0,0 +1,83 @@ +/* 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) { + debug("BbvsEngine::playVideo() videoNum: %d", videoNum); + Common::String videoFilename; + + if (videoNum >= 100) + videoFilename = Common::String::format("snd/snd%05d.avi", videoNum + 1400); + else + videoFilename = Common::String::format("vid/video%03d.avi", videoNum - 1); + + debug("BbvsEngine::playVideo() videoFilename: %s", videoFilename.c_str()); + + // Set the correct video mode + Common::List<Graphics::PixelFormat> formats; + // RGB565 16bit + Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + formats.push_back(pixelFormat); + initGraphics(320, 240, false, formats); + if (_system->getScreenFormat().bytesPerPixel != pixelFormat.bytesPerPixel) + error("Could not switch screen format for the video"); + + 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 diff --git a/engines/configure.engines b/engines/configure.engines index 20e5a56ef1..13611a5037 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -53,3 +53,4 @@ add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit" add_engine tsage "TsAGE" yes add_engine tucker "Bud Tucker in Double Trouble" yes add_engine wintermute "Wintermute" no "" "" "jpeg png zlib vorbis 16bit" +add_engine bbvs "Beavis and Butthead in Virtual Stupidity" no diff --git a/engines/engines.mk b/engines/engines.mk index 5b3eeea61c..89f4862bc7 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -26,6 +26,11 @@ DEFINES += -DENABLE_AGOS2 endif endif +ifdef ENABLE_BBVS +DEFINES += -DENABLE_BBVS=$(ENABLE_BBVS) +MODULES += engines/bbvs +endif + ifdef ENABLE_CGE DEFINES += -DENABLE_CGE=$(ENABLE_CGE) MODULES += engines/cge diff --git a/engines/plugins_table.h b/engines/plugins_table.h index ee7713bb76..801f152760 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -8,6 +8,9 @@ LINK_PLUGIN(AGI) #if PLUGIN_ENABLED_STATIC(AGOS) LINK_PLUGIN(AGOS) #endif +#if PLUGIN_ENABLED_STATIC(BBVS) +LINK_PLUGIN(BBVS) +#endif #if PLUGIN_ENABLED_STATIC(CGE) LINK_PLUGIN(CGE) #endif |