diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/bbvs/bbvs.cpp | 879 | ||||
-rw-r--r-- | engines/bbvs/bbvs.h | 7 | ||||
-rw-r--r-- | engines/bbvs/logic.cpp | 265 | ||||
-rw-r--r-- | engines/bbvs/module.mk | 3 | ||||
-rw-r--r-- | engines/bbvs/scene.cpp | 227 | ||||
-rw-r--r-- | engines/bbvs/walk.cpp | 466 |
6 files changed, 968 insertions, 879 deletions
diff --git a/engines/bbvs/bbvs.cpp b/engines/bbvs/bbvs.cpp index d7e6606d04..3da9e8b3ce 100644 --- a/engines/bbvs/bbvs.cpp +++ b/engines/bbvs/bbvs.cpp @@ -66,41 +66,11 @@ static const BBRect kVerbRects[6] = { { 13, -33, 19, 27}, {-10, 8, 19, 27}, {-11, -49, 19, 27} }; -static const int8 kWalkTurnTbl[] = { - 7, 9, 4, 8, 6, 10, 5, 11 -}; - -static const int8 kWalkAnimTbl[32] = { - 3, 0, 0, 0, 2, 1, 1, 1, - 15, 12, 14, 13, 0, 0, 0, 0, - 7, 9, 4, 8, 6, 10, 5, 11, - 3, 0, 2, 1, 15, 12, 14, 13 -}; - -static const int8 kTurnInfo[8][8] = { - { 0, 1, 1, 1, 1, -1, -1, -1}, - {-1, 0, 1, 1, 1, 1, -1, -1}, - {-1, -1, 0, 1, 1, 1, 1, -1}, - {-1, -1, -1, 0, 1, 1, 1, 1}, - { 1, -1, -1, -1, 0, 1, 1, 1}, - { 1, 1, -1, -1, -1, 0, 1, 1}, - { 1, 1, 1, -1, -1, -1, 0, 1}, - { 1, 1, 1, 1, -1, -1, -1, 0} -}; - static const byte kTurnTbl[] = { 2, 6, 4, 0, 2, 6, 4, 0, 3, 1, 5, 7, 0, 0, 0, 0 }; -static const int kAfterVideoSceneNum[] = { - 0, 43, 23, 12, 4, 44, 2, - 16, 4, 4, 4, 44, 12, 44 -}; - -const int kMainMenu = 44; -const int kCredits = 45; - bool WalkArea::contains(const Common::Point &pt) const { return Common::Rect(x, y, x + width, y + height).contains(pt); } @@ -312,243 +282,6 @@ void BbvsEngine::updateGame() { } -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); @@ -564,198 +297,6 @@ void BbvsEngine::updateBackgroundSounds() { } } -void BbvsEngine::loadScene(int sceneNum) { - debug(0, "BbvsEngine::loadScene() sceneNum: %d", sceneNum); - - Common::String sprFilename = Common::String::format("vnm/vspr%04d.vnm", sceneNum); - Common::String gamFilename = Common::String::format("vnm/game%04d.vnm", sceneNum); - - _screen->clear(); - - _spriteModule->load(sprFilename.c_str()); - _gameModule->load(gamFilename.c_str()); - - Palette palette = _spriteModule->getPalette(); - _screen->setPalette(palette); - - // Preload sounds - for (uint i = 0; i < _gameModule->getPreloadSoundsCount(); ++i) { - Common::String filename = Common::String::format("snd/snd%05d.aif", _gameModule->getPreloadSound(i)); - _sound->loadSound(filename); - } - - if (sceneNum >= kMainMenu) { - DrawList drawList; - drawList.add(_gameModule->getBgSpriteIndex(0), 0, 0, 0); - _screen->drawDrawList(drawList, _spriteModule); - drawScreen(); - } - -} - -void BbvsEngine::initScene(bool sounds) { - - stopSpeech(); - stopSounds(); - _sound->unloadSounds(); - - _gameState = kGSScene; - _prevSceneNum = _currSceneNum; - _sceneVisited[_currSceneNum] = 1; - _mouseCursorSpriteIndex = 0; - _verbPos.x = -1; - _verbPos.y = -1; - _activeItemType = kITEmpty; - _activeItemIndex = 0; - _cameraPos.x = 0; - _cameraPos.y = 0; - _newCameraPos.x = 0; - _newCameraPos.y = 0; - _inventoryButtonIndex = -1; - _currTalkObjectIndex = -1; - _currCameraNum = 0; - _walkMousePos.x = -1; - _walkMousePos.y = -1; - _currAction = 0; - _currActionCommandIndex = -1; - _currActionCommandTimeStamp = 0; - _dialogSlotCount = 0; - _buttheadObject = 0; - _beavisObject = 0; - - memset(_backgroundSoundsActive, 0, sizeof(_backgroundSoundsActive)); - - memset(_sceneObjects, 0, sizeof(_sceneObjects)); - for (int i = 0; i < kSceneObjectsCount; ++i) { - _sceneObjects[i].walkDestPt.x = -1; - _sceneObjects[i].walkDestPt.y = -1; - } - - memset(_dialogItemStatus, 0, sizeof(_dialogItemStatus)); - - _sceneObjectActions.clear(); - - loadScene(_newSceneNum); - _currSceneNum = _newSceneNum; - _newSceneNum = 0; - - for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) - _sceneObjects[i].sceneObjectDef = _gameModule->getSceneObjectDef(i); - - for (int i = 0; i < _gameModule->getSceneObjectInitsCount(); ++i) { - SceneObjectInit *soInit = _gameModule->getSceneObjectInit(i); - if (evalCondition(soInit->conditions)) { - SceneObject *sceneObject = &_sceneObjects[soInit->sceneObjectIndex]; - sceneObject->anim = _gameModule->getAnimation(soInit->animIndex); - sceneObject->animIndex = soInit->animIndex; - sceneObject->frameIndex = sceneObject->anim->frameCount - 1; - sceneObject->frameTicks = 1; - sceneObject->x = soInit->x << 16; - sceneObject->y = soInit->y << 16; - } - } - - if (_gameModule->getButtheadObjectIndex() >= 0) { - _buttheadObject = &_sceneObjects[_gameModule->getButtheadObjectIndex()]; - // Search for the Beavis object - for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) - if (!strcmp(_sceneObjects[i].sceneObjectDef->name, "Beavis")) { - _beavisObject = &_sceneObjects[i]; - break; - } - } - - updateSceneObjectsTurnValue(); - - updateWalkableRects(); - - _currCameraNum = 0; - if (_buttheadObject) { - int minDistance = 0xFFFFFF; - for (int cameraNum = 0; cameraNum < 4; ++cameraNum) { - CameraInit *cameraInit = _gameModule->getCameraInit(cameraNum); - int curDistance = ABS(cameraInit->cameraPos.x - (int)(_buttheadObject->x >> 16) + 160); - if (curDistance < minDistance) { - minDistance = curDistance; - _currCameraNum = cameraNum; - } - } - } - - _cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos; - _newCameraPos = _cameraPos; - - _walkAreaActions.clear(); - for (int i = 0; i < _gameModule->getActionsCount(); ++i) { - Action *action = _gameModule->getAction(i); - for (int j = 0; j < 8; ++j) - if (action->conditions.conditions[j].cond == kCondIsButtheadAtBgObject) - _walkAreaActions.push_back(action); - } - - _mouseCursorSpriteIndex = 0; - - _activeItemIndex = 0; - _activeItemType = kITEmpty; - - for (int i = 0; i < _gameModule->getActionsCount(); ++i) { - Action *action = _gameModule->getAction(i); - if (evalCondition(action->conditions)) { - _gameState = kGSWait; - _currAction = action; - for (uint j = 0; j < action->actionCommands.size(); ++j) { - ActionCommand *actionCommand = &action->actionCommands[j]; - if (actionCommand->cmd == kActionCmdSetCameraPos) { - _currCameraNum = actionCommand->param; - _cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos; - _newCameraPos = _cameraPos; - break; - } - } - break; - } - } - - if (sounds) - updateBackgroundSounds(); - -} - -bool BbvsEngine::changeScene() { - - writeContinueSavegame(); - - if (_newSceneNum >= 27 && _newSceneNum <= 30) { - // Run minigames - stopSpeech(); - stopSounds(); - _sceneVisited[_currSceneNum] = 1; - if (runMinigame(_newSceneNum - 27)) { - SWAP(_currSceneNum, _newSceneNum); - } - } else if (_newSceneNum >= 31 && _newSceneNum <= 43) { - // Play video - stopSpeech(); - stopSounds(); - _sceneVisited[_currSceneNum] = 1; - _playVideoNumber = _newSceneNum - 30; - _currSceneNum = _newSceneNum; - _newSceneNum = kAfterVideoSceneNum[_playVideoNumber]; - } else if (_newSceneNum >= 100 && _currSceneNum == kCredits) { - // Play secret video - stopSounds(); - _playVideoNumber = _newSceneNum; - _currSceneNum = 49; - _newSceneNum = kCredits; - } else { - // Normal scene - initScene(true); - } - - return true; - -} - bool BbvsEngine::update(int mouseX, int mouseY, uint mouseButtons, Common::KeyCode keyCode) { if (_bootSaveSlot >= 0) { @@ -1676,426 +1217,6 @@ void BbvsEngine::updateCommon() { } -void BbvsEngine::startWalkObject(SceneObject *sceneObject) { - const int kMaxDistance = 0xFFFFFF; - - if (_buttheadObject != sceneObject && _beavisObject != sceneObject) - return; - - initWalkAreas(sceneObject); - _sourceWalkAreaPt.x = sceneObject->x >> 16; - _sourceWalkAreaPt.y = sceneObject->y >> 16; - - _sourceWalkArea = getWalkAreaAtPos(_sourceWalkAreaPt); - if (!_sourceWalkArea) - return; - - _destWalkAreaPt = sceneObject->walkDestPt; - - _destWalkArea = getWalkAreaAtPos(_destWalkAreaPt); - if (!_destWalkArea) - return; - - if (_sourceWalkArea != _destWalkArea) { - _currWalkDistance = kMaxDistance; - walkFindPath(_sourceWalkArea, 0); - _destWalkAreaPt = _currWalkDistance == kMaxDistance ? _sourceWalkAreaPt : _finalWalkPt; - } - - walkObject(sceneObject, _destWalkAreaPt, sceneObject->sceneObjectDef->walkSpeed); - -} - -void BbvsEngine::updateWalkObject(SceneObject *sceneObject) { - int animIndex; - - if (sceneObject->walkCount > 0 && (sceneObject->xIncr != 0 || sceneObject->yIncr != 0)) { - if (ABS(sceneObject->xIncr) <= ABS(sceneObject->yIncr)) - sceneObject->turnValue = sceneObject->yIncr >= 0 ? 0 : 4; - else - sceneObject->turnValue = sceneObject->xIncr >= 0 ? 6 : 2; - animIndex = sceneObject->sceneObjectDef->animIndices[kWalkAnimTbl[sceneObject->turnValue]]; - sceneObject->turnCount = 0; - sceneObject->turnTicks = 0; - } else { - animIndex = sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[sceneObject->turnValue]]; - } - - Animation *anim = 0; - if (animIndex > 0) - anim = _gameModule->getAnimation(animIndex); - - if (sceneObject->anim != anim) { - if (anim) { - sceneObject->anim = anim; - sceneObject->animIndex = animIndex; - sceneObject->frameTicks = 1; - sceneObject->frameIndex = anim->frameCount - 1; - } else { - sceneObject->anim = 0; - sceneObject->animIndex = 0; - sceneObject->frameTicks = 0; - sceneObject->frameIndex = 0; - } - } - -} - -void BbvsEngine::walkObject(SceneObject *sceneObject, const Common::Point &destPt, int walkSpeed) { - int deltaX = destPt.x - (sceneObject->x >> 16); - int deltaY = destPt.y - (sceneObject->y >> 16); - float distance = sqrt((double)(deltaX * deltaX + deltaY * deltaY)); - // NOTE The original doesn't have this check but without it the whole pathfinding breaks - if (distance > 0.0) { - sceneObject->walkCount = distance / ((((float)ABS(deltaX) / distance) + 1.0) * ((float)walkSpeed / 120)); - sceneObject->xIncr = ((float)deltaX / sceneObject->walkCount) * 65536.0; - sceneObject->yIncr = ((float)deltaY / sceneObject->walkCount) * 65536.0; - sceneObject->x = (sceneObject->x & 0xFFFF0000) | 0x8000; - sceneObject->y = (sceneObject->y & 0xFFFF0000) | 0x8000; - } else - sceneObject->walkCount = 0; -} - -void BbvsEngine::turnObject(SceneObject *sceneObject) { - if (sceneObject->turnTicks > 0) { - --sceneObject->turnTicks; - } else { - int turnDir = kTurnInfo[sceneObject->turnValue][sceneObject->turnCount & 0x7F]; - if (turnDir) { - sceneObject->turnValue = (sceneObject->turnValue + turnDir) & 7; - int turnAnimIndex = sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[sceneObject->turnValue]]; - if (turnAnimIndex) { - Animation *anim = _gameModule->getAnimation(turnAnimIndex); - if (anim) { - sceneObject->anim = anim; - sceneObject->animIndex = turnAnimIndex; - sceneObject->turnTicks = 4; - sceneObject->frameTicks = 1; - sceneObject->frameIndex = anim->frameCount - 1; - } - } - } else { - sceneObject->turnCount = 0; - } - } -} - -int BbvsEngine::rectSubtract(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect *outRects) { - int count = 0; - Common::Rect workRect = rect1.findIntersectingRect(rect2); - if (!workRect.isEmpty()) { - count = 0; - outRects[count] = Common::Rect(rect2.width(), workRect.top - rect2.top); - if (!outRects[count].isEmpty()) { - outRects[count].translate(rect2.left, rect2.top); - ++count; - } - outRects[count] = Common::Rect(workRect.left - rect2.left, workRect.height()); - if (!outRects[count].isEmpty()) { - outRects[count].translate(rect2.left, workRect.top); - ++count; - } - outRects[count] = Common::Rect(rect2.right - workRect.right, workRect.height()); - if (!outRects[count].isEmpty()) { - outRects[count].translate(workRect.right, workRect.top); - ++count; - } - outRects[count] = Common::Rect(rect2.width(), rect2.bottom - workRect.bottom); - if (!outRects[count].isEmpty()) { - outRects[count].translate(rect2.left, workRect.bottom); - ++count; - } - } else { - outRects[0] = rect2; - count = 1; - } - return count; -} - -WalkInfo *BbvsEngine::addWalkInfo(int16 x, int16 y, int delta, int direction, int16 midPtX, int16 midPtY, int walkAreaIndex) { - WalkInfo *walkInfo = &_walkInfos[_walkInfosCount++]; - walkInfo->walkAreaIndex = walkAreaIndex; - walkInfo->direction = direction; - walkInfo->x = x; - walkInfo->y = y; - walkInfo->delta = delta; - walkInfo->midPt.x = midPtX; - walkInfo->midPt.y = midPtY; - return walkInfo; -} - -void BbvsEngine::initWalkAreas(SceneObject *sceneObject) { - int16 objX = sceneObject->x >> 16; - int16 objY = sceneObject->y >> 16; - Common::Rect rect; - bool doRect = false; - Common::Rect *workWalkableRects; - - if (_buttheadObject == sceneObject && _beavisObject->anim) { - rect = _beavisObject->anim->frameRects2[_beavisObject->frameIndex]; - rect.translate(_beavisObject->x >> 16, 1 + (_beavisObject->y >> 16)); - doRect = !rect.isEmpty(); - } else if (_buttheadObject->anim) { - rect = _buttheadObject->anim->frameRects2[_buttheadObject->frameIndex]; - rect.translate(_buttheadObject->x >> 16, 1 + (_buttheadObject->y >> 16)); - doRect = !rect.isEmpty(); - } - - workWalkableRects = _walkableRects; - - _walkAreasCount = _walkableRectsCount; - - if (doRect && !rect.contains(objX, objY)) { - _walkAreasCount = 0; - for (int i = 0; i < _walkableRectsCount; ++i) - _walkAreasCount += rectSubtract(rect, _walkableRects[i], &_tempWalkableRects1[_walkAreasCount]); - workWalkableRects = _tempWalkableRects1; - } - - for (int i = 0; i < _walkAreasCount; ++i) { - _walkAreas[i].x = workWalkableRects[i].left; - _walkAreas[i].y = workWalkableRects[i].top; - _walkAreas[i].width = workWalkableRects[i].width(); - _walkAreas[i].height = workWalkableRects[i].height(); - _walkAreas[i].checked = false; - _walkAreas[i].linksCount = 0; - } - - _walkInfosCount = 0; - - // Find connections between the walkRects - - for (int i = 0; i < _walkAreasCount; ++i) { - WalkArea *walkArea1 = &_walkAreas[i]; - int xIter = walkArea1->x + walkArea1->width; - int yIter = walkArea1->y + walkArea1->height; - - for (int j = 0; j < _walkAreasCount; ++j) { - WalkArea *walkArea2 = &_walkAreas[j]; - - if (i == j) - continue; - - if (walkArea2->y == yIter) { - int wa1x = MAX(walkArea1->x, walkArea2->x); - int wa2x = MIN(walkArea2->x + walkArea2->width, xIter); - if (wa2x > wa1x) { - debug(5, "WalkArea %d connected to %d by Y", i, j); - WalkInfo *walkInfo1 = addWalkInfo(wa1x, yIter - 1, wa2x - wa1x, 0, wa1x + (wa2x - wa1x) / 2, yIter - 1, i); - WalkInfo *walkInfo2 = addWalkInfo(wa1x, yIter, wa2x - wa1x, 0, wa1x + (wa2x - wa1x) / 2, yIter, j); - walkArea1->linksD1[walkArea1->linksCount] = walkInfo1; - walkArea1->linksD2[walkArea1->linksCount] = walkInfo2; - walkArea1->links[walkArea1->linksCount++] = walkArea2; - walkArea2->linksD1[walkArea2->linksCount] = walkInfo2; - walkArea2->linksD2[walkArea2->linksCount] = walkInfo1; - walkArea2->links[walkArea2->linksCount++] = walkArea1; - } - } - - if (walkArea2->x == xIter) { - int wa1y = MAX(walkArea1->y, walkArea2->y); - int wa2y = MIN(walkArea2->y + walkArea2->height, yIter); - if (wa2y > wa1y) { - debug(5, "WalkArea %d connected to %d by X", i, j); - WalkInfo *walkInfo1 = addWalkInfo(xIter - 1, wa1y, wa2y - wa1y, 1, xIter - 1, wa1y + (wa2y - wa1y) / 2, i); - WalkInfo *walkInfo2 = addWalkInfo(xIter, wa1y, wa2y - wa1y, 1, xIter, wa1y + (wa2y - wa1y) / 2, j); - walkArea1->linksD1[walkArea1->linksCount] = walkInfo1; - walkArea1->linksD2[walkArea1->linksCount] = walkInfo2; - walkArea1->links[walkArea1->linksCount++] = walkArea2; - walkArea2->linksD1[walkArea2->linksCount] = walkInfo2; - walkArea2->linksD2[walkArea2->linksCount] = walkInfo1; - walkArea2->links[walkArea2->linksCount++] = walkArea1; - } - } - - } - - } - -} - -WalkArea *BbvsEngine::getWalkAreaAtPos(const Common::Point &pt) { - for (int i = 0; i < _walkAreasCount; ++i) { - WalkArea *walkArea = &_walkAreas[i]; - if (walkArea->contains(pt)) - return walkArea; - } - return 0; -} - -bool BbvsEngine::canButtheadWalkToDest(const Common::Point &destPt) { - Common::Point srcPt; - - _walkReachedDestArea = false; - initWalkAreas(_buttheadObject); - srcPt.x = _buttheadObject->x >> 16; - srcPt.y = _buttheadObject->y >> 16; - _sourceWalkArea = getWalkAreaAtPos(srcPt); - if (_sourceWalkArea) { - _destWalkArea = getWalkAreaAtPos(destPt); - if (_destWalkArea) - canWalkToDest(_sourceWalkArea, 0); - } - return _walkReachedDestArea; -} - -void BbvsEngine::canWalkToDest(WalkArea *walkArea, int infoCount) { - - if (_destWalkArea == walkArea) { - _walkReachedDestArea = true; - return; - } - - if (_gameModule->getFieldC() <= 320 || infoCount <= 20) { - walkArea->checked = true; - for (int linkIndex = 0; linkIndex < walkArea->linksCount; ++linkIndex) { - if (!walkArea->links[linkIndex]->checked) { - canWalkToDest(walkArea->links[linkIndex], infoCount + 2); - if (_walkReachedDestArea) - break; - } - } - walkArea->checked = false; - } - -} - -bool BbvsEngine::walkTestLineWalkable(const Common::Point &sourcePt, const Common::Point &destPt, WalkInfo *walkInfo) { - const float ptDeltaX = destPt.x - sourcePt.x; - const float ptDeltaY = destPt.y - sourcePt.y; - const float wDeltaX = walkInfo->x - sourcePt.x; - const float wDeltaY = walkInfo->y - sourcePt.y; - if (destPt.x == sourcePt.x) - return true; - if (walkInfo->direction) { - const float nDeltaY = wDeltaX * ptDeltaY / ptDeltaX + (float)sourcePt.y - (float)walkInfo->y; - return (nDeltaY >= 0.0) && (nDeltaY < (float)walkInfo->delta); - } else { - const float nDeltaX = wDeltaY / ptDeltaX * ptDeltaY + (float)sourcePt.x - (float)walkInfo->x; - return (nDeltaX >= 0.0) && (nDeltaX < (float)walkInfo->delta); - } - return false; -} - -void BbvsEngine::walkFindPath(WalkArea *sourceWalkArea, int infoCount) { - if (_destWalkArea == sourceWalkArea) { - walkFoundPath(infoCount); - } else if (_gameModule->getFieldC() <= 320 || infoCount <= 20) { - sourceWalkArea->checked = true; - for (int linkIndex = 0; linkIndex < sourceWalkArea->linksCount; ++linkIndex) { - if (!sourceWalkArea->links[linkIndex]->checked) { - _walkInfoPtrs[infoCount + 0] = sourceWalkArea->linksD1[linkIndex]; - _walkInfoPtrs[infoCount + 1] = sourceWalkArea->linksD2[linkIndex]; - walkFindPath(sourceWalkArea->links[linkIndex], infoCount + 2); - } - } - sourceWalkArea->checked = false; - } -} - -int BbvsEngine::calcDistance(const Common::Point &pt1, const Common::Point &pt2) { - return (int)sqrt((double)(pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y)); -} - -void BbvsEngine::walkFoundPath(int count) { - debug(5, "BbvsEngine::walkFoundPath(%d)", count); - - Common::Point midPt = _sourceWalkAreaPt; - int totalMidPtDistance = 0; - - if (count > 0) { - Common::Point lastMidPt; - int halfCount = (count + 1) >> 1; - for (int i = 0; i < halfCount; ++i) { - lastMidPt = midPt; - midPt = _walkInfoPtrs[i * 2]->midPt; - totalMidPtDistance += calcDistance(midPt, lastMidPt); - } - } - - int distance = calcDistance(midPt, _destWalkAreaPt) + totalMidPtDistance; - - debug(5, "BbvsEngine::walkFoundPath() distance: %d; _currWalkDistance: %d", distance, _currWalkDistance); - - if (distance >= _currWalkDistance) - return; - - debug(5, "BbvsEngine::walkFoundPath() distance smaller"); - - _currWalkDistance = distance; - - Common::Point destPt = _destWalkAreaPt, newDestPt; - - while (1) { - - int index = 0; - if (count > 0) { - do { - if (!walkTestLineWalkable(_sourceWalkAreaPt, destPt, _walkInfoPtrs[index])) - break; - ++index; - } while (index < count); - } - - if (index == count) - break; - - WalkInfo *walkInfo = _walkInfoPtrs[--count]; - destPt.x = walkInfo->x; - destPt.y = walkInfo->y; - - if (walkInfo->direction) { - newDestPt.x = walkInfo->x; - newDestPt.y = walkInfo->y + walkInfo->delta - 1; - } else { - newDestPt.x = walkInfo->x + walkInfo->delta - 1; - newDestPt.y = walkInfo->y; - } - - if ((newDestPt.x - _destWalkAreaPt.x) * (newDestPt.x - _destWalkAreaPt.x) + - (newDestPt.y - _destWalkAreaPt.y) * (newDestPt.y - _destWalkAreaPt.y) < - (destPt.x - _destWalkAreaPt.x) * (destPt.x - _destWalkAreaPt.x) + - (destPt.y - _destWalkAreaPt.y) * (destPt.y - _destWalkAreaPt.y)) - destPt = newDestPt; - - } - - debug(5, "BbvsEngine::walkFoundPath() destPt: (%d, %d)", destPt.x, destPt.y); - - _finalWalkPt = destPt; - - debug(5, "BbvsEngine::walkFoundPath() OK"); - -} - -void BbvsEngine::updateWalkableRects() { - // Go through all walkable rects and subtract all scene object rects - Common::Rect *rectsList1 = _tempWalkableRects1; - Common::Rect *rectsList2 = _gameModule->getWalkRects(); - _walkableRectsCount = _gameModule->getWalkRectsCount(); - for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) { - SceneObject *sceneObject = &_sceneObjects[i]; - Animation *anim = sceneObject->anim; - if (anim && _buttheadObject != sceneObject && _beavisObject != sceneObject) { - Common::Rect rect = sceneObject->anim->frameRects2[sceneObject->frameIndex]; - rect.translate(sceneObject->x >> 16, sceneObject->y >> 16); - int count = _walkableRectsCount; - _walkableRectsCount = 0; - for (int j = 0; j < count; ++j) - _walkableRectsCount += rectSubtract(rect, rectsList2[j], &rectsList1[_walkableRectsCount]); - if (rectsList1 == _tempWalkableRects1) { - rectsList1 = _tempWalkableRects2; - rectsList2 = _tempWalkableRects1; - } else { - rectsList1 = _tempWalkableRects1; - rectsList2 = _tempWalkableRects2; - } - } - } - for (int i = 0; i < _walkableRectsCount; ++i) - _walkableRects[i] = rectsList2[i]; -} - void BbvsEngine::updateSceneObjectsTurnValue() { for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) { SceneObject *sceneObject = &_sceneObjects[i]; diff --git a/engines/bbvs/bbvs.h b/engines/bbvs/bbvs.h index b429c315f7..8136184e0b 100644 --- a/engines/bbvs/bbvs.h +++ b/engines/bbvs/bbvs.h @@ -206,6 +206,13 @@ const int kDialogItemStatusCount = 50; const int kGameVarsCount = 2000; const int kSceneVisitedCount = 64; +const int kMainMenu = 44; +const int kCredits = 45; + +static const int8 kWalkTurnTbl[] = { + 7, 9, 4, 8, 6, 10, 5, 11 +}; + class BbvsEngine : public Engine { protected: Common::Error run(); diff --git a/engines/bbvs/logic.cpp b/engines/bbvs/logic.cpp new file mode 100644 index 0000000000..06792e2df1 --- /dev/null +++ b/engines/bbvs/logic.cpp @@ -0,0 +1,265 @@ +/* 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" + +namespace Bbvs { + +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; + } + } +} + +} // End of namespace Bbvs diff --git a/engines/bbvs/module.mk b/engines/bbvs/module.mk index eb6dc86332..90c62d0acb 100644 --- a/engines/bbvs/module.mk +++ b/engines/bbvs/module.mk @@ -6,10 +6,13 @@ MODULE_OBJS := \ dialogs.o \ gamemodule.o \ graphics.o \ + logic.o \ saveload.o \ + scene.o \ sound.o \ spritemodule.o \ videoplayer.o \ + walk.o \ minigames/bbairguitar.o \ minigames/bbairguitar_anims.o \ minigames/bbant.o \ diff --git a/engines/bbvs/scene.cpp b/engines/bbvs/scene.cpp new file mode 100644 index 0000000000..0d86eb4dbc --- /dev/null +++ b/engines/bbvs/scene.cpp @@ -0,0 +1,227 @@ +/* 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 "bbvs/graphics.h" +#include "bbvs/sound.h" + +namespace Bbvs { + +static const int kAfterVideoSceneNum[] = { + 0, 43, 23, 12, 4, 44, 2, + 16, 4, 4, 4, 44, 12, 44 +}; + +void BbvsEngine::loadScene(int sceneNum) { + debug(0, "BbvsEngine::loadScene() sceneNum: %d", sceneNum); + + Common::String sprFilename = Common::String::format("vnm/vspr%04d.vnm", sceneNum); + Common::String gamFilename = Common::String::format("vnm/game%04d.vnm", sceneNum); + + _screen->clear(); + + _spriteModule->load(sprFilename.c_str()); + _gameModule->load(gamFilename.c_str()); + + Palette palette = _spriteModule->getPalette(); + _screen->setPalette(palette); + + // Preload sounds + for (uint i = 0; i < _gameModule->getPreloadSoundsCount(); ++i) { + Common::String filename = Common::String::format("snd/snd%05d.aif", _gameModule->getPreloadSound(i)); + _sound->loadSound(filename); + } + + if (sceneNum >= kMainMenu) { + DrawList drawList; + drawList.add(_gameModule->getBgSpriteIndex(0), 0, 0, 0); + _screen->drawDrawList(drawList, _spriteModule); + drawScreen(); + } + +} + +void BbvsEngine::initScene(bool sounds) { + + stopSpeech(); + stopSounds(); + _sound->unloadSounds(); + + _gameState = kGSScene; + _prevSceneNum = _currSceneNum; + _sceneVisited[_currSceneNum] = 1; + _mouseCursorSpriteIndex = 0; + _verbPos.x = -1; + _verbPos.y = -1; + _activeItemType = kITEmpty; + _activeItemIndex = 0; + _cameraPos.x = 0; + _cameraPos.y = 0; + _newCameraPos.x = 0; + _newCameraPos.y = 0; + _inventoryButtonIndex = -1; + _currTalkObjectIndex = -1; + _currCameraNum = 0; + _walkMousePos.x = -1; + _walkMousePos.y = -1; + _currAction = 0; + _currActionCommandIndex = -1; + _currActionCommandTimeStamp = 0; + _dialogSlotCount = 0; + _buttheadObject = 0; + _beavisObject = 0; + + memset(_backgroundSoundsActive, 0, sizeof(_backgroundSoundsActive)); + + memset(_sceneObjects, 0, sizeof(_sceneObjects)); + for (int i = 0; i < kSceneObjectsCount; ++i) { + _sceneObjects[i].walkDestPt.x = -1; + _sceneObjects[i].walkDestPt.y = -1; + } + + memset(_dialogItemStatus, 0, sizeof(_dialogItemStatus)); + + _sceneObjectActions.clear(); + + loadScene(_newSceneNum); + _currSceneNum = _newSceneNum; + _newSceneNum = 0; + + for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) + _sceneObjects[i].sceneObjectDef = _gameModule->getSceneObjectDef(i); + + for (int i = 0; i < _gameModule->getSceneObjectInitsCount(); ++i) { + SceneObjectInit *soInit = _gameModule->getSceneObjectInit(i); + if (evalCondition(soInit->conditions)) { + SceneObject *sceneObject = &_sceneObjects[soInit->sceneObjectIndex]; + sceneObject->anim = _gameModule->getAnimation(soInit->animIndex); + sceneObject->animIndex = soInit->animIndex; + sceneObject->frameIndex = sceneObject->anim->frameCount - 1; + sceneObject->frameTicks = 1; + sceneObject->x = soInit->x << 16; + sceneObject->y = soInit->y << 16; + } + } + + if (_gameModule->getButtheadObjectIndex() >= 0) { + _buttheadObject = &_sceneObjects[_gameModule->getButtheadObjectIndex()]; + // Search for the Beavis object + for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) + if (!strcmp(_sceneObjects[i].sceneObjectDef->name, "Beavis")) { + _beavisObject = &_sceneObjects[i]; + break; + } + } + + updateSceneObjectsTurnValue(); + + updateWalkableRects(); + + _currCameraNum = 0; + if (_buttheadObject) { + int minDistance = 0xFFFFFF; + for (int cameraNum = 0; cameraNum < 4; ++cameraNum) { + CameraInit *cameraInit = _gameModule->getCameraInit(cameraNum); + int curDistance = ABS(cameraInit->cameraPos.x - (int)(_buttheadObject->x >> 16) + 160); + if (curDistance < minDistance) { + minDistance = curDistance; + _currCameraNum = cameraNum; + } + } + } + + _cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos; + _newCameraPos = _cameraPos; + + _walkAreaActions.clear(); + for (int i = 0; i < _gameModule->getActionsCount(); ++i) { + Action *action = _gameModule->getAction(i); + for (int j = 0; j < 8; ++j) + if (action->conditions.conditions[j].cond == kCondIsButtheadAtBgObject) + _walkAreaActions.push_back(action); + } + + _mouseCursorSpriteIndex = 0; + + _activeItemIndex = 0; + _activeItemType = kITEmpty; + + for (int i = 0; i < _gameModule->getActionsCount(); ++i) { + Action *action = _gameModule->getAction(i); + if (evalCondition(action->conditions)) { + _gameState = kGSWait; + _currAction = action; + for (uint j = 0; j < action->actionCommands.size(); ++j) { + ActionCommand *actionCommand = &action->actionCommands[j]; + if (actionCommand->cmd == kActionCmdSetCameraPos) { + _currCameraNum = actionCommand->param; + _cameraPos = _gameModule->getCameraInit(_currCameraNum)->cameraPos; + _newCameraPos = _cameraPos; + break; + } + } + break; + } + } + + if (sounds) + updateBackgroundSounds(); + +} + +bool BbvsEngine::changeScene() { + + writeContinueSavegame(); + + if (_newSceneNum >= 27 && _newSceneNum <= 30) { + // Run minigames + stopSpeech(); + stopSounds(); + _sceneVisited[_currSceneNum] = 1; + if (runMinigame(_newSceneNum - 27)) { + SWAP(_currSceneNum, _newSceneNum); + } + } else if (_newSceneNum >= 31 && _newSceneNum <= 43) { + // Play video + stopSpeech(); + stopSounds(); + _sceneVisited[_currSceneNum] = 1; + _playVideoNumber = _newSceneNum - 30; + _currSceneNum = _newSceneNum; + _newSceneNum = kAfterVideoSceneNum[_playVideoNumber]; + } else if (_newSceneNum >= 100 && _currSceneNum == kCredits) { + // Play secret video + stopSounds(); + _playVideoNumber = _newSceneNum; + _currSceneNum = 49; + _newSceneNum = kCredits; + } else { + // Normal scene + initScene(true); + } + + return true; + +} + +} // End of namespace Bbvs diff --git a/engines/bbvs/walk.cpp b/engines/bbvs/walk.cpp new file mode 100644 index 0000000000..cabe402a46 --- /dev/null +++ b/engines/bbvs/walk.cpp @@ -0,0 +1,466 @@ +/* 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" + +namespace Bbvs { + +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 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 +}; + +void BbvsEngine::startWalkObject(SceneObject *sceneObject) { + const int kMaxDistance = 0xFFFFFF; + + if (_buttheadObject != sceneObject && _beavisObject != sceneObject) + return; + + initWalkAreas(sceneObject); + _sourceWalkAreaPt.x = sceneObject->x >> 16; + _sourceWalkAreaPt.y = sceneObject->y >> 16; + + _sourceWalkArea = getWalkAreaAtPos(_sourceWalkAreaPt); + if (!_sourceWalkArea) + return; + + _destWalkAreaPt = sceneObject->walkDestPt; + + _destWalkArea = getWalkAreaAtPos(_destWalkAreaPt); + if (!_destWalkArea) + return; + + if (_sourceWalkArea != _destWalkArea) { + _currWalkDistance = kMaxDistance; + walkFindPath(_sourceWalkArea, 0); + _destWalkAreaPt = _currWalkDistance == kMaxDistance ? _sourceWalkAreaPt : _finalWalkPt; + } + + walkObject(sceneObject, _destWalkAreaPt, sceneObject->sceneObjectDef->walkSpeed); + +} + +void BbvsEngine::updateWalkObject(SceneObject *sceneObject) { + int animIndex; + + if (sceneObject->walkCount > 0 && (sceneObject->xIncr != 0 || sceneObject->yIncr != 0)) { + if (ABS(sceneObject->xIncr) <= ABS(sceneObject->yIncr)) + sceneObject->turnValue = sceneObject->yIncr >= 0 ? 0 : 4; + else + sceneObject->turnValue = sceneObject->xIncr >= 0 ? 6 : 2; + animIndex = sceneObject->sceneObjectDef->animIndices[kWalkAnimTbl[sceneObject->turnValue]]; + sceneObject->turnCount = 0; + sceneObject->turnTicks = 0; + } else { + animIndex = sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[sceneObject->turnValue]]; + } + + Animation *anim = 0; + if (animIndex > 0) + anim = _gameModule->getAnimation(animIndex); + + if (sceneObject->anim != anim) { + if (anim) { + sceneObject->anim = anim; + sceneObject->animIndex = animIndex; + sceneObject->frameTicks = 1; + sceneObject->frameIndex = anim->frameCount - 1; + } else { + sceneObject->anim = 0; + sceneObject->animIndex = 0; + sceneObject->frameTicks = 0; + sceneObject->frameIndex = 0; + } + } + +} + +void BbvsEngine::walkObject(SceneObject *sceneObject, const Common::Point &destPt, int walkSpeed) { + int deltaX = destPt.x - (sceneObject->x >> 16); + int deltaY = destPt.y - (sceneObject->y >> 16); + float distance = sqrt((double)(deltaX * deltaX + deltaY * deltaY)); + // NOTE The original doesn't have this check but without it the whole pathfinding breaks + if (distance > 0.0) { + sceneObject->walkCount = distance / ((((float)ABS(deltaX) / distance) + 1.0) * ((float)walkSpeed / 120)); + sceneObject->xIncr = ((float)deltaX / sceneObject->walkCount) * 65536.0; + sceneObject->yIncr = ((float)deltaY / sceneObject->walkCount) * 65536.0; + sceneObject->x = (sceneObject->x & 0xFFFF0000) | 0x8000; + sceneObject->y = (sceneObject->y & 0xFFFF0000) | 0x8000; + } else + sceneObject->walkCount = 0; +} + +void BbvsEngine::turnObject(SceneObject *sceneObject) { + if (sceneObject->turnTicks > 0) { + --sceneObject->turnTicks; + } else { + int turnDir = kTurnInfo[sceneObject->turnValue][sceneObject->turnCount & 0x7F]; + if (turnDir) { + sceneObject->turnValue = (sceneObject->turnValue + turnDir) & 7; + int turnAnimIndex = sceneObject->sceneObjectDef->animIndices[kWalkTurnTbl[sceneObject->turnValue]]; + if (turnAnimIndex) { + Animation *anim = _gameModule->getAnimation(turnAnimIndex); + if (anim) { + sceneObject->anim = anim; + sceneObject->animIndex = turnAnimIndex; + sceneObject->turnTicks = 4; + sceneObject->frameTicks = 1; + sceneObject->frameIndex = anim->frameCount - 1; + } + } + } else { + sceneObject->turnCount = 0; + } + } +} + +int BbvsEngine::rectSubtract(const Common::Rect &rect1, const Common::Rect &rect2, Common::Rect *outRects) { + int count = 0; + Common::Rect workRect = rect1.findIntersectingRect(rect2); + if (!workRect.isEmpty()) { + count = 0; + outRects[count] = Common::Rect(rect2.width(), workRect.top - rect2.top); + if (!outRects[count].isEmpty()) { + outRects[count].translate(rect2.left, rect2.top); + ++count; + } + outRects[count] = Common::Rect(workRect.left - rect2.left, workRect.height()); + if (!outRects[count].isEmpty()) { + outRects[count].translate(rect2.left, workRect.top); + ++count; + } + outRects[count] = Common::Rect(rect2.right - workRect.right, workRect.height()); + if (!outRects[count].isEmpty()) { + outRects[count].translate(workRect.right, workRect.top); + ++count; + } + outRects[count] = Common::Rect(rect2.width(), rect2.bottom - workRect.bottom); + if (!outRects[count].isEmpty()) { + outRects[count].translate(rect2.left, workRect.bottom); + ++count; + } + } else { + outRects[0] = rect2; + count = 1; + } + return count; +} + +WalkInfo *BbvsEngine::addWalkInfo(int16 x, int16 y, int delta, int direction, int16 midPtX, int16 midPtY, int walkAreaIndex) { + WalkInfo *walkInfo = &_walkInfos[_walkInfosCount++]; + walkInfo->walkAreaIndex = walkAreaIndex; + walkInfo->direction = direction; + walkInfo->x = x; + walkInfo->y = y; + walkInfo->delta = delta; + walkInfo->midPt.x = midPtX; + walkInfo->midPt.y = midPtY; + return walkInfo; +} + +void BbvsEngine::initWalkAreas(SceneObject *sceneObject) { + int16 objX = sceneObject->x >> 16; + int16 objY = sceneObject->y >> 16; + Common::Rect rect; + bool doRect = false; + Common::Rect *workWalkableRects; + + if (_buttheadObject == sceneObject && _beavisObject->anim) { + rect = _beavisObject->anim->frameRects2[_beavisObject->frameIndex]; + rect.translate(_beavisObject->x >> 16, 1 + (_beavisObject->y >> 16)); + doRect = !rect.isEmpty(); + } else if (_buttheadObject->anim) { + rect = _buttheadObject->anim->frameRects2[_buttheadObject->frameIndex]; + rect.translate(_buttheadObject->x >> 16, 1 + (_buttheadObject->y >> 16)); + doRect = !rect.isEmpty(); + } + + workWalkableRects = _walkableRects; + + _walkAreasCount = _walkableRectsCount; + + if (doRect && !rect.contains(objX, objY)) { + _walkAreasCount = 0; + for (int i = 0; i < _walkableRectsCount; ++i) + _walkAreasCount += rectSubtract(rect, _walkableRects[i], &_tempWalkableRects1[_walkAreasCount]); + workWalkableRects = _tempWalkableRects1; + } + + for (int i = 0; i < _walkAreasCount; ++i) { + _walkAreas[i].x = workWalkableRects[i].left; + _walkAreas[i].y = workWalkableRects[i].top; + _walkAreas[i].width = workWalkableRects[i].width(); + _walkAreas[i].height = workWalkableRects[i].height(); + _walkAreas[i].checked = false; + _walkAreas[i].linksCount = 0; + } + + _walkInfosCount = 0; + + // Find connections between the walkRects + + for (int i = 0; i < _walkAreasCount; ++i) { + WalkArea *walkArea1 = &_walkAreas[i]; + int xIter = walkArea1->x + walkArea1->width; + int yIter = walkArea1->y + walkArea1->height; + + for (int j = 0; j < _walkAreasCount; ++j) { + WalkArea *walkArea2 = &_walkAreas[j]; + + if (i == j) + continue; + + if (walkArea2->y == yIter) { + int wa1x = MAX(walkArea1->x, walkArea2->x); + int wa2x = MIN(walkArea2->x + walkArea2->width, xIter); + if (wa2x > wa1x) { + debug(5, "WalkArea %d connected to %d by Y", i, j); + WalkInfo *walkInfo1 = addWalkInfo(wa1x, yIter - 1, wa2x - wa1x, 0, wa1x + (wa2x - wa1x) / 2, yIter - 1, i); + WalkInfo *walkInfo2 = addWalkInfo(wa1x, yIter, wa2x - wa1x, 0, wa1x + (wa2x - wa1x) / 2, yIter, j); + walkArea1->linksD1[walkArea1->linksCount] = walkInfo1; + walkArea1->linksD2[walkArea1->linksCount] = walkInfo2; + walkArea1->links[walkArea1->linksCount++] = walkArea2; + walkArea2->linksD1[walkArea2->linksCount] = walkInfo2; + walkArea2->linksD2[walkArea2->linksCount] = walkInfo1; + walkArea2->links[walkArea2->linksCount++] = walkArea1; + } + } + + if (walkArea2->x == xIter) { + int wa1y = MAX(walkArea1->y, walkArea2->y); + int wa2y = MIN(walkArea2->y + walkArea2->height, yIter); + if (wa2y > wa1y) { + debug(5, "WalkArea %d connected to %d by X", i, j); + WalkInfo *walkInfo1 = addWalkInfo(xIter - 1, wa1y, wa2y - wa1y, 1, xIter - 1, wa1y + (wa2y - wa1y) / 2, i); + WalkInfo *walkInfo2 = addWalkInfo(xIter, wa1y, wa2y - wa1y, 1, xIter, wa1y + (wa2y - wa1y) / 2, j); + walkArea1->linksD1[walkArea1->linksCount] = walkInfo1; + walkArea1->linksD2[walkArea1->linksCount] = walkInfo2; + walkArea1->links[walkArea1->linksCount++] = walkArea2; + walkArea2->linksD1[walkArea2->linksCount] = walkInfo2; + walkArea2->linksD2[walkArea2->linksCount] = walkInfo1; + walkArea2->links[walkArea2->linksCount++] = walkArea1; + } + } + + } + + } + +} + +WalkArea *BbvsEngine::getWalkAreaAtPos(const Common::Point &pt) { + for (int i = 0; i < _walkAreasCount; ++i) { + WalkArea *walkArea = &_walkAreas[i]; + if (walkArea->contains(pt)) + return walkArea; + } + return 0; +} + +bool BbvsEngine::canButtheadWalkToDest(const Common::Point &destPt) { + Common::Point srcPt; + + _walkReachedDestArea = false; + initWalkAreas(_buttheadObject); + srcPt.x = _buttheadObject->x >> 16; + srcPt.y = _buttheadObject->y >> 16; + _sourceWalkArea = getWalkAreaAtPos(srcPt); + if (_sourceWalkArea) { + _destWalkArea = getWalkAreaAtPos(destPt); + if (_destWalkArea) + canWalkToDest(_sourceWalkArea, 0); + } + return _walkReachedDestArea; +} + +void BbvsEngine::canWalkToDest(WalkArea *walkArea, int infoCount) { + + if (_destWalkArea == walkArea) { + _walkReachedDestArea = true; + return; + } + + if (_gameModule->getFieldC() <= 320 || infoCount <= 20) { + walkArea->checked = true; + for (int linkIndex = 0; linkIndex < walkArea->linksCount; ++linkIndex) { + if (!walkArea->links[linkIndex]->checked) { + canWalkToDest(walkArea->links[linkIndex], infoCount + 2); + if (_walkReachedDestArea) + break; + } + } + walkArea->checked = false; + } + +} + +bool BbvsEngine::walkTestLineWalkable(const Common::Point &sourcePt, const Common::Point &destPt, WalkInfo *walkInfo) { + const float ptDeltaX = destPt.x - sourcePt.x; + const float ptDeltaY = destPt.y - sourcePt.y; + const float wDeltaX = walkInfo->x - sourcePt.x; + const float wDeltaY = walkInfo->y - sourcePt.y; + if (destPt.x == sourcePt.x) + return true; + if (walkInfo->direction) { + const float nDeltaY = wDeltaX * ptDeltaY / ptDeltaX + (float)sourcePt.y - (float)walkInfo->y; + return (nDeltaY >= 0.0) && (nDeltaY < (float)walkInfo->delta); + } else { + const float nDeltaX = wDeltaY / ptDeltaX * ptDeltaY + (float)sourcePt.x - (float)walkInfo->x; + return (nDeltaX >= 0.0) && (nDeltaX < (float)walkInfo->delta); + } + return false; +} + +void BbvsEngine::walkFindPath(WalkArea *sourceWalkArea, int infoCount) { + if (_destWalkArea == sourceWalkArea) { + walkFoundPath(infoCount); + } else if (_gameModule->getFieldC() <= 320 || infoCount <= 20) { + sourceWalkArea->checked = true; + for (int linkIndex = 0; linkIndex < sourceWalkArea->linksCount; ++linkIndex) { + if (!sourceWalkArea->links[linkIndex]->checked) { + _walkInfoPtrs[infoCount + 0] = sourceWalkArea->linksD1[linkIndex]; + _walkInfoPtrs[infoCount + 1] = sourceWalkArea->linksD2[linkIndex]; + walkFindPath(sourceWalkArea->links[linkIndex], infoCount + 2); + } + } + sourceWalkArea->checked = false; + } +} + +int BbvsEngine::calcDistance(const Common::Point &pt1, const Common::Point &pt2) { + return (int)sqrt((double)(pt1.x - pt2.x) * (pt1.x - pt2.x) + (pt1.y - pt2.y) * (pt1.y - pt2.y)); +} + +void BbvsEngine::walkFoundPath(int count) { + debug(5, "BbvsEngine::walkFoundPath(%d)", count); + + Common::Point midPt = _sourceWalkAreaPt; + int totalMidPtDistance = 0; + + if (count > 0) { + Common::Point lastMidPt; + int halfCount = (count + 1) >> 1; + for (int i = 0; i < halfCount; ++i) { + lastMidPt = midPt; + midPt = _walkInfoPtrs[i * 2]->midPt; + totalMidPtDistance += calcDistance(midPt, lastMidPt); + } + } + + int distance = calcDistance(midPt, _destWalkAreaPt) + totalMidPtDistance; + + debug(5, "BbvsEngine::walkFoundPath() distance: %d; _currWalkDistance: %d", distance, _currWalkDistance); + + if (distance >= _currWalkDistance) + return; + + debug(5, "BbvsEngine::walkFoundPath() distance smaller"); + + _currWalkDistance = distance; + + Common::Point destPt = _destWalkAreaPt, newDestPt; + + while (1) { + + int index = 0; + if (count > 0) { + do { + if (!walkTestLineWalkable(_sourceWalkAreaPt, destPt, _walkInfoPtrs[index])) + break; + ++index; + } while (index < count); + } + + if (index == count) + break; + + WalkInfo *walkInfo = _walkInfoPtrs[--count]; + destPt.x = walkInfo->x; + destPt.y = walkInfo->y; + + if (walkInfo->direction) { + newDestPt.x = walkInfo->x; + newDestPt.y = walkInfo->y + walkInfo->delta - 1; + } else { + newDestPt.x = walkInfo->x + walkInfo->delta - 1; + newDestPt.y = walkInfo->y; + } + + if ((newDestPt.x - _destWalkAreaPt.x) * (newDestPt.x - _destWalkAreaPt.x) + + (newDestPt.y - _destWalkAreaPt.y) * (newDestPt.y - _destWalkAreaPt.y) < + (destPt.x - _destWalkAreaPt.x) * (destPt.x - _destWalkAreaPt.x) + + (destPt.y - _destWalkAreaPt.y) * (destPt.y - _destWalkAreaPt.y)) + destPt = newDestPt; + + } + + debug(5, "BbvsEngine::walkFoundPath() destPt: (%d, %d)", destPt.x, destPt.y); + + _finalWalkPt = destPt; + + debug(5, "BbvsEngine::walkFoundPath() OK"); + +} + +void BbvsEngine::updateWalkableRects() { + // Go through all walkable rects and subtract all scene object rects + Common::Rect *rectsList1 = _tempWalkableRects1; + Common::Rect *rectsList2 = _gameModule->getWalkRects(); + _walkableRectsCount = _gameModule->getWalkRectsCount(); + for (int i = 0; i < _gameModule->getSceneObjectDefsCount(); ++i) { + SceneObject *sceneObject = &_sceneObjects[i]; + Animation *anim = sceneObject->anim; + if (anim && _buttheadObject != sceneObject && _beavisObject != sceneObject) { + Common::Rect rect = sceneObject->anim->frameRects2[sceneObject->frameIndex]; + rect.translate(sceneObject->x >> 16, sceneObject->y >> 16); + int count = _walkableRectsCount; + _walkableRectsCount = 0; + for (int j = 0; j < count; ++j) + _walkableRectsCount += rectSubtract(rect, rectsList2[j], &rectsList1[_walkableRectsCount]); + if (rectsList1 == _tempWalkableRects1) { + rectsList1 = _tempWalkableRects2; + rectsList2 = _tempWalkableRects1; + } else { + rectsList1 = _tempWalkableRects1; + rectsList2 = _tempWalkableRects2; + } + } + } + for (int i = 0; i < _walkableRectsCount; ++i) + _walkableRects[i] = rectsList2[i]; +} + +} // End of namespace Bbvs |