From 5f4fc9a1dd5668ab9fa9706a8e86b2ec3ac808d1 Mon Sep 17 00:00:00 2001 From: johndoe123 Date: Fri, 27 Dec 2013 13:49:38 +0100 Subject: BBVS: Initial commit --- engines/bbvs/bbvs.cpp | 2196 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2196 insertions(+) create mode 100644 engines/bbvs/bbvs.cpp (limited to 'engines/bbvs/bbvs.cpp') 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 -- cgit v1.2.3