/* 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 3 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, see . * */ #include "backends/keymapper/keymapper.h" #include "common/config-manager.h" #include "common/savefile.h" #include "image/png.h" #include "tot/anims.h" #include "tot/debug.h" #include "tot/statics.h" #include "tot/tot.h" #include "tot/util.h" namespace Tot { void TotEngine::drawText(uint number) { readTextFile(); uint foo = 0; sayLine(number, 255, 0, foo, false); _verbFile.close(); } void TotEngine::displayLoading() { const char *msg = getFullScreenMessagesByCurrentLanguage()[58]; setRGBPalette(255, 63, 63, 63); littText(121, 72, msg, 0); _screen->update(); delay(kEnforcedTextAnimDelay); littText(120, 71, msg, 0); _screen->update(); delay(kEnforcedTextAnimDelay); littText(119, 72, msg, 0); _screen->update(); delay(kEnforcedTextAnimDelay); littText(120, 73, msg, 0); _screen->update(); delay(kEnforcedTextAnimDelay); littText(120, 72, msg, 255); _screen->update(); // enforce a delay for now so it's visible g_system->delayMillis(200); } void TotEngine::runaroundRed() { const uint devilTrajectory[91][2] = { {204, 47}, {204, 49}, {203, 51}, {203, 53}, {201, 55}, {199, 57}, {197, 59}, {195, 61}, {193, 63}, {192, 65}, {192, 67}, {192, 69}, {192, 71}, {192, 73}, {191, 75}, {191, 77}, {191, 79}, {191, 81}, {191, 83}, {191, 85}, {191, 87}, {192, 89}, {192, 91}, {192, 93}, {192, 95}, {193, 97}, {194, 99}, {195, 101}, {196, 103}, {197, 105}, {198, 107}, {199, 109}, {200, 111}, {201, 111}, {203, 111}, {205, 111}, {207, 111}, {209, 111}, {211, 111}, {213, 111}, {215, 110}, {217, 110}, {219, 110}, {221, 110}, {223, 110}, {225, 110}, {227, 110}, {229, 110}, {231, 110}, {232, 109}, {234, 108}, {236, 107}, {238, 106}, {240, 105}, {242, 104}, {244, 103}, {246, 102}, {248, 101}, {250, 100}, {252, 99}, {254, 98}, {256, 97}, {258, 96}, {260, 95}, {261, 93}, {262, 91}, {263, 89}, {264, 87}, {265, 85}, {266, 83}, {267, 81}, {268, 79}, {269, 77}, {270, 75}, {271, 73}, {272, 71}, {273, 69}, {274, 67}, {275, 65}, {276, 63}, {277, 61}, {278, 59}, {279, 57}, {280, 55}, {281, 53}, {282, 52}, {282, 52}, {282, 52}, {282, 52}, {282, 52}, {282, 52} }; bool exitLoop = false; loadDevil(); uint secTrajIndex = 0; uint secTrajLength = 82; _iframe2 = 0; _isSecondaryAnimationEnabled = true; do { _chrono->updateChrono(); if (_chrono->_gameTick) { if (secTrajIndex == secTrajLength) exitLoop = true; secTrajIndex += 1; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; _secondaryAnimation.posx = devilTrajectory[secTrajIndex][0] - 15; _secondaryAnimation.posy = devilTrajectory[secTrajIndex][1] - 42; if (secTrajIndex <= 8) { _secondaryAnimation.dir = 2; _secondaryAnimation.depth = 1; } else if (secTrajIndex <= 33) { _secondaryAnimation.dir = 2; _secondaryAnimation.depth = 14; } else if (secTrajIndex <= 63) { _secondaryAnimation.dir = 1; _secondaryAnimation.depth = 14; } else { _secondaryAnimation.dir = 0; _secondaryAnimation.depth = 3; } _chrono->_gameTickHalfSpeed = true; sprites(false); _chrono->_gameTick = false; _graphics->advancePaletteAnim(); _screen->update(); } } while (!exitLoop && !shouldQuit()); clearAnimation(); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); } void updateMovementGrids() { uint j1arm, j2arm; byte i1arm, i2arm; j1arm = (g_engine->_currentRoomData->secondaryAnimTrajectory[g_engine->_currentSecondaryTrajectoryIndex - 1].x / kXGridCount) + 1; j2arm = (g_engine->_currentRoomData->secondaryAnimTrajectory[g_engine->_currentSecondaryTrajectoryIndex - 1].y / kYGridCount) + 1; if ((g_engine->_oldposx != j1arm) || (g_engine->_oldposy != j2arm)) { for (i1arm = 0; i1arm < g_engine->_maxXGrid; i1arm++) for (i2arm = 0; i2arm < g_engine->_maxYGrid; i2arm++) { g_engine->_currentRoomData->walkAreasGrid[g_engine->_oldposx + i1arm][g_engine->_oldposy + i2arm] = g_engine->_movementGridForSecondaryAnim[i1arm][i2arm]; g_engine->_currentRoomData->mouseGrid[g_engine->_oldposx + i1arm][g_engine->_oldposy + i2arm] = g_engine->_mouseGridForSecondaryAnim[i1arm][i2arm]; } for (i1arm = 0; i1arm < g_engine->_maxXGrid; i1arm++) for (i2arm = 0; i2arm < g_engine->_maxYGrid; i2arm++) { g_engine->_movementGridForSecondaryAnim[i1arm][i2arm] = g_engine->_currentRoomData->walkAreasGrid[j1arm + i1arm][j2arm + i2arm]; if (g_engine->_maskGridSecondaryAnim[i1arm][i2arm] > 0) g_engine->_currentRoomData->walkAreasGrid[j1arm + i1arm][j2arm + i2arm] = g_engine->_maskGridSecondaryAnim[i1arm][i2arm]; g_engine->_mouseGridForSecondaryAnim[i1arm][i2arm] = g_engine->_currentRoomData->mouseGrid[j1arm + i1arm][j2arm + i2arm]; if (g_engine->_maskMouseSecondaryAnim[i1arm][i2arm] > 0) g_engine->_currentRoomData->mouseGrid[j1arm + i1arm][j2arm + i2arm] = g_engine->_maskMouseSecondaryAnim[i1arm][i2arm]; } g_engine->_oldposx = j1arm; g_engine->_oldposy = j2arm; g_engine->_oldGridX = 0; g_engine->_oldGridY = 0; } } void sprites(bool drawCharacter); static void assembleBackground() { uint posabs; // copies the entire clean background in backgroundCopy back into background g_engine->_graphics->restoreBackground(); posabs = 4 + g_engine->_dirtyMainSpriteY * 320 + g_engine->_dirtyMainSpriteX; uint16 w, h; w = READ_LE_UINT16(g_engine->_characterDirtyRect); h = READ_LE_UINT16(g_engine->_characterDirtyRect + 2); w++; h++; g_engine->_dirtyMainSpriteX2 = g_engine->_dirtyMainSpriteX + w; g_engine->_dirtyMainSpriteY2 = g_engine->_dirtyMainSpriteY + h; for (int j = 0; j < h; j++) { for (int i = 0; i < w; i++) { int pos = posabs + j * 320 + i; int destPos = 4 + (j * w + i); g_engine->_characterDirtyRect[destPos] = g_engine->_sceneBackground[pos]; } } } /** * calculates the overlapping area between the source image and the background, * then "blits" (copies) the pixels from the image to the overlapping area of the background, respecting transparency. */ static void assembleImage(const byte *img, uint imgPosX, uint imgPosY) { uint x, // starting point of the overlap y; uint incx, // width and height of the overlapping area incy; uint16 wImg = READ_LE_UINT16(img) + 1; uint16 hImg = READ_LE_UINT16(img + 2) + 1; uint16 wBg = READ_LE_UINT16(g_engine->_characterDirtyRect) + 1; uint16 hBg = READ_LE_UINT16(g_engine->_characterDirtyRect + 2) + 1; // This region calculates the overlapping area of (x, incx, y, incy) { if (imgPosX < g_engine->_dirtyMainSpriteX) x = g_engine->_dirtyMainSpriteX; else x = imgPosX; if (imgPosX + wImg < static_cast(g_engine->_dirtyMainSpriteX + wBg)) incx = imgPosX + wImg - x; else incx = g_engine->_dirtyMainSpriteX + wBg - x; if (imgPosY < g_engine->_dirtyMainSpriteY) y = g_engine->_dirtyMainSpriteY; else y = imgPosY; if (imgPosY + hImg < static_cast(g_engine->_dirtyMainSpriteY + hBg)) incy = imgPosY + hImg - y; else incy = g_engine->_dirtyMainSpriteY + hBg - y; } // end of region calculating overlapping area for (uint j = 0; j < incy; j++) { for (uint i = 0; i < incx; i++) { int bgOffset = 4 + ((y - g_engine->_dirtyMainSpriteY) + j) * wBg + i + (x - g_engine->_dirtyMainSpriteX); int imgOffset = 4 + (y - imgPosY + j) * wImg + i + (x - imgPosX); if (img[imgOffset] != 0) { g_engine->_characterDirtyRect[bgOffset] = img[imgOffset]; } } } } static void overlayLayers() { if (g_engine->_screenLayers[g_engine->_curDepth] != nullptr) { if ( (g_engine->_depthMap[g_engine->_curDepth].posx <= g_engine->_dirtyMainSpriteX2) && (g_engine->_depthMap[g_engine->_curDepth].posx2 > g_engine->_dirtyMainSpriteX) && (g_engine->_depthMap[g_engine->_curDepth].posy < g_engine->_dirtyMainSpriteY2) && (g_engine->_depthMap[g_engine->_curDepth].posy2 > g_engine->_dirtyMainSpriteY)) { assembleImage(g_engine->_screenLayers[g_engine->_curDepth], g_engine->_depthMap[g_engine->_curDepth].posx, g_engine->_depthMap[g_engine->_curDepth].posy); } } } void drawMainCharacter() { uint16 tempW; uint16 tempH; tempW = READ_LE_UINT16(g_engine->_curCharacterAnimationFrame); tempH = READ_LE_UINT16(g_engine->_curCharacterAnimationFrame + 2); tempW += 6; tempH += 6; if (g_engine->_dirtyMainSpriteY + tempH > 140) { tempH -= (g_engine->_dirtyMainSpriteY + tempH) - 140; } if (g_engine->_dirtyMainSpriteX + tempW > 320) { tempW -= (g_engine->_dirtyMainSpriteX + tempW) - 320; } g_engine->_characterDirtyRect = (byte *)malloc((tempW + 1) * (tempH + 1) + 4); WRITE_LE_UINT16(g_engine->_characterDirtyRect, tempW); WRITE_LE_UINT16(g_engine->_characterDirtyRect + 2, tempH); assembleBackground(); g_engine->_curDepth = 0; while (g_engine->_curDepth != kDepthLevelCount) { overlayLayers(); if (g_engine->_mainCharAnimation.depth == g_engine->_curDepth) assembleImage(g_engine->_curCharacterAnimationFrame, g_engine->_characterPosX, g_engine->_characterPosY); g_engine->_curDepth += 1; } g_engine->_graphics->putImg(g_engine->_dirtyMainSpriteX, g_engine->_dirtyMainSpriteY, g_engine->_characterDirtyRect); free(g_engine->_characterDirtyRect); } void TotEngine::sprites(bool drawMainCharachter) { // grabs the current frame from the walk cycle _curCharacterAnimationFrame = _mainCharAnimation.bitmap[_charFacingDirection][_iframe]; _dirtyMainSpriteX = _characterPosX - 3; _dirtyMainSpriteY = _characterPosY - 3; if (_isSecondaryAnimationEnabled) { if (_currentRoomData->secondaryTrajectoryLength > 1) { updateMovementGrids(); } if (_chrono->_gameTickHalfSpeed) { if (_isPeterCoughing && !_sound->isVocPlaying()) { _iframe2 = 0; } newSecondaryAnimationFrame(); Common::copy(_secondaryAnimation.bitmap[_secondaryAnimation.dir][_iframe2], _secondaryAnimation.bitmap[_secondaryAnimation.dir][_iframe2] + _secondaryAnimFrameSize, _curSecondaryAnimationFrame); } uint16 curCharFrameW = READ_LE_UINT16(_curCharacterAnimationFrame); uint16 curCharFrameH = READ_LE_UINT16(_curCharacterAnimationFrame + 2); uint16 secAnimW = READ_LE_UINT16(_curSecondaryAnimationFrame); uint16 secAnimH = READ_LE_UINT16(_curSecondaryAnimationFrame + 2); if ( ((_secondaryAnimation.posx < (_characterPosX + curCharFrameW) + 4) && ((_secondaryAnimation.posx + secAnimW + 1) > _dirtyMainSpriteX) && (_secondaryAnimation.posy < (_characterPosY + curCharFrameH + 4))) && ((_secondaryAnimation.posy + secAnimH + 1) > _dirtyMainSpriteY)) { // Character is in the area of the animation if (_secondaryAnimation.posx < _characterPosX) { _dirtyMainSpriteX = _secondaryAnimation.posx - 3; } if (_secondaryAnimation.posy < _characterPosY) { _dirtyMainSpriteY = _secondaryAnimation.posy - 3; } uint16 patchW = secAnimW + curCharFrameW + 6; uint16 patchH; if ((curCharFrameH + _characterPosY) > (_secondaryAnimation.posy + secAnimH)) { patchH = curCharFrameH + 6 + abs(_characterPosY - _secondaryAnimation.posy); } else { patchH = secAnimH + 6 + abs(_characterPosY - _secondaryAnimation.posy); } if (_dirtyMainSpriteY + patchH > 140) { patchH -= (_dirtyMainSpriteY + patchH) - 140 + 1; } if (_dirtyMainSpriteX + patchW > 320) { patchW -= (_dirtyMainSpriteX + patchW) - 320 + 1; } _characterDirtyRect = (byte *)malloc((patchW + 1) * (patchH + 1) + 4); WRITE_LE_UINT16(_characterDirtyRect, patchW); WRITE_LE_UINT16(_characterDirtyRect + 2, patchH); assembleBackground(); _curDepth = 0; while (_curDepth != kDepthLevelCount) { overlayLayers(); if (_secondaryAnimation.depth == _curDepth) assembleImage(_curSecondaryAnimationFrame, _secondaryAnimation.posx, _secondaryAnimation.posy); if (_mainCharAnimation.depth == _curDepth) assembleImage(_curCharacterAnimationFrame, _characterPosX, _characterPosY); _curDepth += 1; } _graphics->putImg(_dirtyMainSpriteX, _dirtyMainSpriteY, _characterDirtyRect); free(_characterDirtyRect); } else { // character and animation are in different parts of the screen if (drawMainCharachter) { drawMainCharacter(); } _dirtyMainSpriteX = _secondaryAnimation.posx - 3; _dirtyMainSpriteY = _secondaryAnimation.posy - 3; secAnimW = READ_LE_UINT16(_curSecondaryAnimationFrame) + 6; secAnimH = READ_LE_UINT16(_curSecondaryAnimationFrame + 2) + 6; if (_dirtyMainSpriteY + secAnimH > 140) { secAnimH -= (_dirtyMainSpriteY + secAnimH) - 140 + 1; } if (_dirtyMainSpriteX + secAnimW > 320) { secAnimW -= (_dirtyMainSpriteX + secAnimW) - 320 + 1; } _characterDirtyRect = (byte *)malloc((secAnimW + 1) * (secAnimH + 1) + 4); WRITE_LE_UINT16(_characterDirtyRect, secAnimW); WRITE_LE_UINT16(_characterDirtyRect + 2, secAnimH); assembleBackground(); _curDepth = 0; while (_curDepth != kDepthLevelCount) { overlayLayers(); if (_secondaryAnimation.depth == _curDepth) assembleImage(_curSecondaryAnimationFrame, _secondaryAnimation.posx, _secondaryAnimation.posy); _curDepth += 1; } _graphics->putImg(_dirtyMainSpriteX, _dirtyMainSpriteY, _characterDirtyRect); free(_characterDirtyRect); } } else if (drawMainCharachter) { drawMainCharacter(); } } void TotEngine::adjustKey() { _iframe = 0; calculateTrajectory(129, 13); _charFacingDirection = 0; do { _characterPosX = _trajectory[_currentTrajectoryIndex].x; _characterPosY = _trajectory[_currentTrajectoryIndex].y; _iframe++; _currentTrajectoryIndex += 1; emptyLoop(); _chrono->_gameTick = false; _graphics->advancePaletteAnim(); sprites(true); } while (_currentTrajectoryIndex != _trajectoryLength); _charFacingDirection = 3; emptyLoop(); _chrono->_gameTick = false; sprites(true); } void TotEngine::adjustKey2() { _iframe = 0; _charFacingDirection = 2; _trajectoryLength = 1; do { _characterPosX = _trajectory[_currentTrajectoryIndex].x; _characterPosY = _trajectory[_currentTrajectoryIndex].y; _iframe++; _currentTrajectoryIndex -= 1; emptyLoop(); _chrono->_gameTick = false; _graphics->advancePaletteAnim(); sprites(true); } while (_currentTrajectoryIndex != 0); emptyLoop(); _chrono->_gameTick = false; sprites(true); } void TotEngine::animatedSequence(uint numSequence) { Common::File animationFile; uint repIndex, animIndex; uint16 animFrameSize; uint animX, animY; int tmpCharacterPosX; byte secFrameCount; byte *animptr; switch (numSequence) { case 1: { tmpCharacterPosX = _characterPosX; _characterPosX = 3; if (!animationFile.open("POZO01.DAT")) { showError(277); } animX = 127; animY = 70; animFrameSize = animationFile.readUint16LE(); secFrameCount = animationFile.readByte(); animationFile.readByte(); animptr = (byte *)malloc(animFrameSize); for (uint loopIdx = 1; loopIdx <= 3; loopIdx++) { _sound->playVoc("POZO", 180395, 6034); animIndex = 0; do { emptyLoop(); _chrono->_gameTick = false; if (_chrono->_gameTickHalfSpeed) { if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; sprites(false); animationFile.read(animptr, animFrameSize); _graphics->putImg(animX, animY, animptr); animIndex += 1; } } while (animIndex != secFrameCount && !shouldQuit()); animationFile.seek(4); } free(animptr); animationFile.close(); _characterPosX = tmpCharacterPosX; } break; case 2: { if (!animationFile.open("POZOATR.DAT")) { showError(277); } animX = 127; tmpCharacterPosX = _characterPosX; _characterPosX = 3; animY = 70; animFrameSize = animationFile.readUint16LE(); secFrameCount = animationFile.readByte(); animationFile.readByte(); animptr = (byte *)malloc(animFrameSize); for (repIndex = 1; repIndex <= 3; repIndex++) { _sound->playVoc("POZO", 180395, 6034); animIndex = 0; do { emptyLoop(); _chrono->_gameTick = false; if (_chrono->_gameTickHalfSpeed) { if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; sprites(false); animationFile.read(animptr, animFrameSize); _graphics->putImg(animX, animY, animptr); animIndex += 1; } } while (animIndex != secFrameCount && !shouldQuit()); animationFile.seek(4); } _sound->stopVoc(); free(animptr); animationFile.close(); _characterPosX = tmpCharacterPosX; } break; case 3: { tmpCharacterPosX = _characterPosX; _characterPosX = 3; if (!animationFile.open("POZO02.DAT")) { showError(277); } animX = 127; animY = 70; animFrameSize = animationFile.readUint16LE(); secFrameCount = animationFile.readByte(); animationFile.readByte(); animptr = (byte *)malloc(animFrameSize); animIndex = 0; do { emptyLoop(); _chrono->_gameTick = false; if (_chrono->_gameTickHalfSpeed) { if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; sprites(false); animationFile.read(animptr, animFrameSize); _graphics->putImg(animX, animY, animptr); animIndex += 1; } } while (animIndex != secFrameCount && !shouldQuit()); free(animptr); animationFile.close(); _iframe = 0; _charFacingDirection = 2; emptyLoop(); _chrono->_gameTick = false; _characterPosX = tmpCharacterPosX; sprites(true); } break; case 4: { adjustKey(); if (!animationFile.open("TIOLLAVE.DAT")) { showError(277); } animX = 85; animY = 15; animFrameSize = animationFile.readUint16LE(); secFrameCount = animationFile.readByte(); animationFile.readByte(); animptr = (byte *)malloc(animFrameSize); for (animIndex = 1; animIndex <= 31; animIndex++) { animationFile.read(animptr, animFrameSize); emptyLoop(); _chrono->_gameTick = false; _graphics->advancePaletteAnim(); _graphics->putShape(animX, animY, animptr); } clearScreenLayer(_curObject->depth - 1); _graphics->restoreBackground(); animIndex = _mainCharAnimation.depth; _mainCharAnimation.depth = 30; clearScreenLayer(12); _screenLayers[12] = animptr; _depthMap[12].posx = animX; _depthMap[12].posy = animY; assembleScreen(); _graphics->drawScreen(_sceneBackground); // do not clear layer yet, needed for next frames _screenLayers[12] = nullptr; _mainCharAnimation.depth = animIndex; drawInventory(); for (animIndex = 32; animIndex <= secFrameCount; animIndex++) { animationFile.read(animptr, animFrameSize); emptyLoop(); _chrono->_gameTick = false; _graphics->advancePaletteAnim(); _graphics->putImg(animX, animY, animptr); if (shouldQuit()) { break; } } adjustKey2(); free(animptr); animationFile.close(); } break; case 5: { if (!animationFile.open("TIOSACO.DAT")) { showError(277); } animX = 204; animY = 44; animFrameSize = animationFile.readUint16LE(); secFrameCount = animationFile.readByte(); animationFile.readByte(); animptr = (byte *)malloc(animFrameSize); for (animIndex = 1; animIndex <= 8; animIndex++) { animationFile.read(animptr, animFrameSize); emptyLoop(); _chrono->_gameTick = false; _graphics->putShape(animX, animY, animptr); if (shouldQuit()) { break; } } animIndex = _mainCharAnimation.depth; _mainCharAnimation.depth = 30; clearScreenLayer(12); _screenLayers[12] = animptr; _depthMap[12].posx = animX; _depthMap[12].posy = animY; disableSecondAnimation(); _mainCharAnimation.depth = animIndex; _graphics->drawScreen(_sceneBackground); // do not clear layer yet, needed for next frames _screenLayers[12] = nullptr; for (animIndex = 9; animIndex <= secFrameCount; animIndex++) { animationFile.read(animptr, animFrameSize); emptyLoop(); _chrono->_gameTick = false; emptyLoop(); _chrono->_gameTick = false; _graphics->putShape(animX, animY, animptr); if (shouldQuit()) { break; } } free(animptr); animationFile.close(); _iframe = 0; _charFacingDirection = 2; emptyLoop(); _chrono->_gameTick = false; sprites(true); } break; case 6: { _currentRoomData->animationFlag = false; if (!animationFile.open("AZCCOG.DAT")) { showError(277); } animFrameSize = animationFile.readUint16LE(); secFrameCount = animationFile.readByte(); animationFile.readByte(); if (g_engine->_screenLayers[6]) { free(g_engine->_screenLayers[6]); } _screenLayers[6] = (byte *)malloc(animFrameSize); _depthMap[6].posx = _secondaryAnimation.posx + 5; _depthMap[6].posy = _secondaryAnimation.posy - 6; animIndex = 0; do { emptyLoop(); _chrono->_gameTick = false; _graphics->advancePaletteAnim(); if (_chrono->_gameTickHalfSpeed) { animationFile.read(_screenLayers[6], animFrameSize); Common::copy(_screenLayers[6], _screenLayers[6] + animFrameSize, _sceneBackground + 44900); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animIndex += 1; if (animIndex == 8) _sound->playVoc("PUFF", 191183, 18001); } } while (animIndex != secFrameCount && !shouldQuit()); animationFile.close(); _sound->stopVoc(); clearScreenLayer(6); _currentRoomData->animationFlag = true; } break; } } void TotEngine::loadScreenData(uint screenNumber) { _currentRoomNumber = screenNumber; _rooms->seek(screenNumber * kRoomRegSize, SEEK_SET); if (_currentRoomData) { delete _currentRoomData; } _currentRoomData = readScreenDataFile(_rooms); loadScreen(); for (int i = 0; i < 15; i++) { RoomBitmapRegister &bitmap = _currentRoomData->screenLayers[i]; if (bitmap.bitmapSize > 0) { loadScreenLayer(bitmap.coordx, bitmap.coordy, bitmap.bitmapSize, bitmap.bitmapPointer, bitmap.depth); } } if (_currentRoomData->animationFlag && _currentRoomData->code != 24) { loadAnimation(_currentRoomData->animationName); _iframe2 = 0; _currentSecondaryTrajectoryIndex = 1; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; if (_currentRoomData->animationName == "FUENTE01") _secondaryAnimation.depth = 0; else { updateSecondaryAnimationDepth(); } for (int i = 0; i < _maxXGrid; i++) for (int j = 0; j < _maxYGrid; j++) { if (_maskGridSecondaryAnim[i][j] > 0) _currentRoomData->walkAreasGrid[_oldposx + i][_oldposy + j] = _maskGridSecondaryAnim[i][j]; if (_maskMouseSecondaryAnim[i][j] > 0) _currentRoomData->mouseGrid[_oldposx + i][_oldposy + j] = _maskMouseSecondaryAnim[i][j]; } } else _currentRoomData->animationFlag = false; updateMainCharacterDepth(); assembleScreen(); g_engine->_graphics->_paletteAnimFrame = 0; } /** * Calculates a trajectory between the current position (xframe, yframe) * and the target position (finalx, finaly) using bresenham's algorithm */ void TotEngine::calculateTrajectory(uint finalX, uint finalY) { int deltaX = finalX - _characterPosX; int deltaY = finalY - _characterPosY; int incrXDiag = (deltaX >= 0) ? 1 : -1; int incrYDiag = (deltaY >= 0) ? 1 : -1; deltaX = abs(deltaX); deltaY = abs(deltaY); bool horizontalDominant = (deltaX >= deltaY); if (!horizontalDominant) { int tmp = deltaX; deltaX = deltaY; deltaY = tmp; } // step increments for straight moves int straightXIncrease = horizontalDominant ? incrXDiag : 0; int straightYIncrease = horizontalDominant ? 0 : incrYDiag; int straightAmount = 2 * deltaY; int slope = straightAmount - (2 * deltaX); int dec = straightAmount - deltaX; // decision variable // start at initial position uint x = _characterPosX, y = _characterPosY; int trajectorySteps = deltaX + 1; // number of steps _currentTrajectoryIndex = 0; _trajectoryLength = 0; _trajectory[_trajectoryLength].x = x; _trajectory[_trajectoryLength].y = y; _trajectoryLength++; while (--trajectorySteps) { if (dec >= 0) { x += incrXDiag; y += incrYDiag; dec += slope; } else { x += straightXIncrease; y += straightYIncrease; dec += straightAmount; } _trajectory[_trajectoryLength].x = x; _trajectory[_trajectoryLength].y = y; _trajectoryLength++; } // Ensure last value is also final position to account for overflow of the route _trajectory[_trajectoryLength].x = finalX; _trajectory[_trajectoryLength].y = finalY; _trajectory[_trajectoryLength + 1].x = finalX; _trajectory[_trajectoryLength + 1].y = finalY; } void TotEngine::lookAtObject(byte objectCode) { byte yaux; Common::String description; bool foobar = false; TextEntry textRef; Palette secPalette; _cpCounter2 = _cpCounter; _mouse->hide(); _graphics->copyPalette(g_engine->_graphics->_pal, secPalette); readObject(_inventory[objectCode].code); _graphics->getImg(0, 0, 319, 139, _sceneBackground); _graphics->partialFadeOut(234); bar(0, 0, 319, 139, 0); for (yaux = 1; yaux <= 12; yaux++) buttonBorder( 120 - (yaux * 5), // x1 80 - (yaux * 5), // y1 200 + (yaux * 5), // x2 70 + (yaux * 5), // y2 251, // color1 251, // color2 251, // color3 251, // color4 0 // color5 ); drawMenu(4); if (_curObject->used[0] != 9) { if (_curObject->beforeUseTextRef != 0) { readTextFile(); textRef = readTextRegister(_curObject->beforeUseTextRef); description = textRef.text; for (yaux = 0; yaux < textRef.text.size(); yaux++) description.setChar(_decryptionKey[yaux] ^ textRef.text[yaux], yaux); displayObjectDescription(description); _verbFile.close(); } else { description = _inventory[objectCode].objectName; displayObjectDescription(description); } } else { if (_curObject->afterUseTextRef != 0) { readTextFile(); textRef = readTextRegister(_curObject->afterUseTextRef); description = textRef.text; for (yaux = 0; yaux < textRef.text.size(); yaux++) description.setChar(_decryptionKey[yaux] ^ textRef.text[yaux], yaux); displayObjectDescription(description); _verbFile.close(); } else { description = _inventory[objectCode].objectName; displayObjectDescription(description); } } drawFlc(125, 70, _curObject->rotatingObjectAnimation, 60000, 9, 0, false, true, true, foobar); _graphics->sceneTransition(true, nullptr, 3); _graphics->partialFadeOut(234); assembleScreen(); _graphics->drawScreen(_sceneBackground); _graphics->copyPalette(secPalette, g_engine->_graphics->_pal); _graphics->partialFadeIn(234); _mouse->show(); } void TotEngine::useInventoryObjectWithInventoryObject(int16 objectCode1, int16 objectCode2) { byte invIndex, indobj1, indobj2; readObject(_sceneObjectsData, objectCode1, _curObject); if (_curObject->used[0] != 1 || _curObject->useWith != objectCode2) { drawText(getRandom(11) + 1022); return; } invIndex = 0; while (_inventory[invIndex].code != objectCode1) { invIndex += 1; } indobj1 = invIndex; invIndex = 0; while (_inventory[invIndex].code != objectCode2) { invIndex += 1; } indobj2 = invIndex; uint textRef = _curObject->useTextRef; if (_curObject->replaceWith == 0) { readObject(_sceneObjectsData, objectCode1, _curObject); _curObject->used[0] = 9; saveObject(_curObject, _sceneObjectsData); readObject(_sceneObjectsData, objectCode2, _curObject); _curObject->used[0] = 9; saveObject(_curObject, _sceneObjectsData); } else { readObject(_sceneObjectsData, _curObject->replaceWith, _curObject); _inventory[indobj1].bitmapIndex = _curObject->objectIconBitmap; _inventory[indobj1].code = _curObject->code; _inventory[indobj1].objectName = _curObject->name; for (indobj1 = indobj2; indobj1 < (kInventoryIconCount - 1); indobj1++) { _inventory[indobj1].bitmapIndex = _inventory[indobj1 + 1].bitmapIndex; _inventory[indobj1].code = _inventory[indobj1 + 1].code; _inventory[indobj1].objectName = _inventory[indobj1 + 1].objectName; } _mouse->hide(); drawInventory(); _mouse->show(); } if (textRef > 0) drawText(textRef); } void TotEngine::calculateRoute(byte zone1, byte zone2, bool extraCorrection, bool barredZone) { // Resets the entire route for (_trajectorySteps = 0; _trajectorySteps < 7; _trajectorySteps++) { _mainRoute[_trajectorySteps].x = 0; _mainRoute[_trajectorySteps].y = 0; } _trajectorySteps = 0; // Starts first element of route with current position _mainRoute[0].x = _characterPosX; _mainRoute[0].y = _characterPosY; Common::Point point; do { _trajectorySteps += 1; point = _currentRoomData->trajectories[zone1 - 1][zone2 - 1][_trajectorySteps - 1]; if (point.x < (kCharacterCorrectionX + 3)) _mainRoute[_trajectorySteps].x = 3; else _mainRoute[_trajectorySteps].x = point.x - kCharacterCorrectionX; if (point.y < (kCharacerCorrectionY + 3)) _mainRoute[_trajectorySteps].y = 3; else _mainRoute[_trajectorySteps].y = point.y - kCharacerCorrectionY; } while (point.y != 9999 && _trajectorySteps != 5); if (zone2 < 10) { if (point.y == 9999) { _mainRoute[_trajectorySteps].x = _xframe2 - kCharacterCorrectionX; _mainRoute[_trajectorySteps].y = _yframe2 - kCharacerCorrectionY; } else { _mainRoute[6].x = _xframe2 - kCharacterCorrectionX; _mainRoute[6].y = _yframe2 - kCharacerCorrectionY; _trajectorySteps = 6; } } else { if ((_mainRoute[_trajectorySteps].y + kCharacerCorrectionY) == 9999) { _trajectorySteps -= 1; } if (extraCorrection) { switch (_currentRoomData->code) { case 5: if (zone2 == 27) _trajectorySteps += 1; break; case 6: if (zone2 == 21) _trajectorySteps += 1; break; } } } if (extraCorrection && barredZone) { _trajectorySteps -= 1; } // Sets xframe2 now to be the number of steps in the route _xframe2 = _trajectorySteps; // Sets yframe2 to now be current step _yframe2 = 1; _trajectoryLength = 10; _currentTrajectoryIndex = 30; } void TotEngine::goToObject(byte zone1, byte zone2) { bool barredZone = false; _cpCounter2 = _cpCounter; for (int i = 0; i < 5; i++) { if (_currentRoomData->doors[i].doorcode == zone2) { barredZone = true; break; } } if (_currentRoomData->code == 21 && _currentRoomData->animationFlag) { if ((zone2 >= 1 && zone2 <= 5) || (zone2 >= 9 && zone2 <= 13) || (zone2 >= 18 && zone2 <= 21) || zone2 == 25) { _targetZone = 7; _mouse->mouseClickX = 232; _mouse->mouseClickY = 75; zone2 = 7; } if (zone2 == 24) { barredZone = false; _targetZone = 7; _mouse->mouseClickX = 232; _mouse->mouseClickY = 75; zone2 = 7; } } if (zone1 < 10) { _xframe2 = _mouse->mouseClickX + 7; _yframe2 = _mouse->mouseClickY + 7; _mouse->hide(); calculateRoute(zone1, zone2, true, barredZone); do { _chrono->updateChrono(); g_engine->_events->pollEvent(); advanceAnimations(barredZone, false); _screen->update(); g_system->delayMillis(10); } while (_xframe2 != 0); _iframe = 0; sprites(true); _mouse->show(); } } void TotEngine::updateSecondaryAnimationDepth() { uint animationPos = _secondaryAnimation.posy + _secondaryAnimHeight - 1; if (animationPos && animationPos <= 56) { _secondaryAnimation.depth = 0; } else if (animationPos >= 57 && animationPos <= 64) { _secondaryAnimation.depth = 1; } else if (animationPos >= 65 && animationPos <= 72) { _secondaryAnimation.depth = 2; } else if (animationPos >= 73 && animationPos <= 80) { _secondaryAnimation.depth = 3; } else if (animationPos >= 81 && animationPos <= 88) { _secondaryAnimation.depth = 4; } else if (animationPos >= 89 && animationPos <= 96) { _secondaryAnimation.depth = 5; } else if (animationPos >= 97 && animationPos <= 104) { _secondaryAnimation.depth = 6; } else if (animationPos >= 105 && animationPos <= 112) { _secondaryAnimation.depth = 7; } else if (animationPos >= 113 && animationPos <= 120) { _secondaryAnimation.depth = 8; } else if (animationPos >= 121 && animationPos <= 140) { _secondaryAnimation.depth = 9; } } void TotEngine::updateMainCharacterDepth() { if (_characterPosY && _characterPosY <= 7) { _mainCharAnimation.depth = 0; } else if (_characterPosY >= 8 && _characterPosY <= 17) { _mainCharAnimation.depth = 1; } else if (_characterPosY >= 18 && _characterPosY <= 25) { _mainCharAnimation.depth = 2; } else if (_characterPosY >= 26 && _characterPosY <= 33) { _mainCharAnimation.depth = 3; } else if (_characterPosY >= 34 && _characterPosY <= 41) { _mainCharAnimation.depth = 4; } else if (_characterPosY >= 42 && _characterPosY <= 49) { _mainCharAnimation.depth = 5; } else if (_characterPosY >= 50 && _characterPosY <= 57) { _mainCharAnimation.depth = 6; } else if (_characterPosY >= 58 && _characterPosY <= 65) { _mainCharAnimation.depth = 7; } else if (_characterPosY >= 66 && _characterPosY <= 73) { _mainCharAnimation.depth = 8; } else if (_characterPosY >= 74 && _characterPosY <= 139) { _mainCharAnimation.depth = 9; } } void TotEngine::advanceAnimations(bool barredZone, bool animateMouse) { if (_chrono->_gameTick) { if (_currentRoomData->animationFlag && _chrono->_gameTickHalfSpeed) { if (_isPeterCoughing && (getRandom(100) == 1) && !_sound->isVocPlaying() && _mintTopic[0] == false) { debug("Playing tos"); _sound->playVoc("TOS", 258006, 14044); } if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; switch (_currentRoomData->code) { case 23: _secondaryAnimation.depth = 0; break; case 24: _secondaryAnimation.depth = 14; break; default: updateSecondaryAnimationDepth(); } } // This means character needs to walk if (_xframe2 > 0) { if (_charFacingDirection == 1 || _charFacingDirection == 3) { _currentTrajectoryIndex += 1; } _currentTrajectoryIndex += 1; // yframe2, xframe2 now represent max steps and current step if (_yframe2 <= _xframe2) { if (_currentTrajectoryIndex > _trajectoryLength) { _element1 = _mainRoute[_yframe2].x - _mainRoute[_yframe2 - 1].x; _element2 = _mainRoute[_yframe2].y - _mainRoute[_yframe2 - 1].y; if ((abs(_element1) > 2) || (abs(_element2) > 2)) { if (abs(_element2) > (abs(_element1) + 5)) { if (_element2 < 0) _charFacingDirection = 0; else _charFacingDirection = 2; } else { if (_element1 > 0) _charFacingDirection = 1; else _charFacingDirection = 3; } } _yframe2 += 1; calculateTrajectory(_mainRoute[_yframe2 - 1].x, _mainRoute[_yframe2 - 1].y); } } else if (_currentTrajectoryIndex >= _trajectoryLength) { _xframe2 = 0; if (!_roomChange) { _element1 = (_mouse->mouseX + 7) - (_characterPosX + kCharacterCorrectionX); _element2 = (_mouse->mouseY + 7) - (_characterPosY + kCharacerCorrectionY); if (abs(_element2) > (abs(_element1) + 20)) { if (_element2 < 0) _charFacingDirection = 0; else _charFacingDirection = 2; } else { if (_element1 > 0) _charFacingDirection = 1; else _charFacingDirection = 3; } } } _iframe++; if (_iframe > kWalkFrameCount) _iframe = 0; } else { _iframe = 0; if (barredZone == false && !_roomChange) { _element1 = (_mouse->mouseX + 7) - (_characterPosX + kCharacterCorrectionX); _element2 = (_mouse->mouseY + 7) - (_characterPosY + kCharacerCorrectionY); if (abs(_element2) > (abs(_element1) + 20)) { if (_element2 < 0) _charFacingDirection = 0; else _charFacingDirection = 2; } else { if (_element1 > 0) _charFacingDirection = 1; else _charFacingDirection = 3; } } } _characterPosX = _trajectory[_currentTrajectoryIndex].x; _characterPosY = _trajectory[_currentTrajectoryIndex].y; updateMainCharacterDepth(); if (_isDrawingEnabled) { sprites(true); } _chrono->_gameTick = false; _graphics->advancePaletteAnim(); } } void TotEngine::actionLineText(const Common::String &actionLine) { euroText(160, 144, actionLine, 255, Graphics::kTextAlignCenter); } void TotEngine::animateGive(uint dir, uint height) { _charFacingDirection = dir; for (uint i = 0; i < 5; i++) { emptyLoop(); _chrono->_gameTick = false; // Must add 1 to i because the original game uses 1-based indices _iframe = 15 + 6 + 5 + height * 10 - (i + 1); _graphics->advancePaletteAnim(); sprites(true); } _iframe = 0; } // Lean over to pick void TotEngine::animatePickup1(uint dir, uint height) { _charFacingDirection = dir; for (uint i = 0; i < 5; i++) { emptyLoop(); _chrono->_gameTick = false; _iframe = 15 + height * 10 + (i + 1); _graphics->advancePaletteAnim(); sprites(true); _screen->update(); } } // Lean back after pick void TotEngine::animatePickup2(uint dir, uint height) { _charFacingDirection = dir; for (uint i = 0; i < 5; i++) { emptyLoop(); _chrono->_gameTick = false; _iframe = 15 + 5 + height * 10 + (i + 1); _graphics->advancePaletteAnim(); sprites(true); _screen->update(); } emptyLoop(); _chrono->_gameTick = false; sprites(true); _iframe = 0; } void TotEngine::animateOpen2(uint dir, uint height) { _charFacingDirection = dir; _cpCounter = _cpCounter2; for (uint i = 0; i < 5; i++) { emptyLoop(); _chrono->_gameTick = false; _iframe = 15 + 6 + height * 10 - (i + 1); _graphics->advancePaletteAnim(); sprites(true); } emptyLoop(); _chrono->_gameTick = false; sprites(true); _iframe = 0; } void TotEngine::animateBat() { const uint batTrajectory[91][2] = { {288, 40}, {289, 38}, {289, 36}, {289, 34}, {290, 32}, {290, 30}, {289, 31}, {288, 32}, {288, 34}, {286, 36}, {284, 38}, {282, 40}, {280, 42}, {278, 44}, {276, 46}, {274, 48}, {272, 50}, {270, 48}, {268, 46}, {266, 48}, {265, 50}, {264, 52}, {263, 54}, {263, 56}, {262, 58}, {261, 60}, {261, 62}, {261, 64}, {260, 66}, {260, 68}, {260, 70}, {260, 72}, {259, 74}, {259, 76}, {260, 78}, {262, 76}, {264, 74}, {266, 72}, {266, 74}, {266, 76}, {268, 78}, {270, 80}, {272, 82}, {274, 84}, {276, 86}, {278, 88}, {279, 90}, {280, 88}, {281, 86}, {282, 84}, {283, 82}, {283, 84}, {283, 86}, {283, 88}, {284, 90}, {284, 92}, {284, 94}, {284, 96}, {285, 98}, {285, 100}, {286, 98}, {288, 96}, {290, 94}, {290, 92}, {290, 90}, {289, 92}, {289, 94}, {289, 96}, {289, 98}, {289, 100}, {289, 102}, {288, 104}, {287, 106}, {287, 108}, {288, 110}, {288, 112}, {288, 114}, {289, 116}, {289, 114}, {289, 112}, {290, 110}, {290, 112}, {290, 114}, {289, 116}, {289, 118}, {289, 120}, {289, 122}, {289, 124}, {290, 122}, {290, 120}, {290, 118} }; byte curAnimIFrame = 0; uint currAnimWidth = 0, curAnimHeight = 0, curAnimIdx = 0, curAnimLength = 0, curAnimX = 0, curAnimY = 0, curAnimDepth = 0, curAnimDir = 0; bool loopBreak = false; if (_currentRoomData->animationFlag) { curAnimIFrame = _iframe2; curAnimX = _secondaryAnimation.posx; curAnimY = _secondaryAnimation.posy; currAnimWidth = _secondaryAnimWidth; curAnimHeight = _secondaryAnimHeight; curAnimDepth = _secondaryAnimation.depth; curAnimDir = _secondaryAnimation.dir; clearAnimation(); } loadBat(); _sound->stopVoc(); _sound->playVoc("MURCIEL", 160848, 4474); curAnimIdx = 0; curAnimLength = 87; _iframe2 = 0; _secondaryAnimation.depth = 14; do { _chrono->updateChrono(); if (_chrono->_gameTick) { if (curAnimIdx == curAnimLength) loopBreak = true; curAnimIdx += 1; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; _secondaryAnimation.posx = batTrajectory[curAnimIdx][0] - 20; _secondaryAnimation.posy = batTrajectory[curAnimIdx][1]; _secondaryAnimation.dir = 0; sprites(true); _chrono->_gameTick = false; if (curAnimIdx % 24 == 0) _sound->playVoc(); _graphics->advancePaletteAnim(); } _screen->update(); g_system->delayMillis(10); } while (!loopBreak && !shouldQuit()); _sound->stopVoc(); clearAnimation(); if (_currentRoomData->animationFlag) { _secondaryAnimWidth = currAnimWidth; _secondaryAnimHeight = curAnimHeight; setRoomTrajectories(_secondaryAnimHeight, _secondaryAnimWidth, RESTORE, false); loadAnimation(_currentRoomData->animationName); _iframe2 = curAnimIFrame; _secondaryAnimation.posx = curAnimX; _secondaryAnimation.posy = curAnimY; _secondaryAnimation.depth = curAnimDepth; _secondaryAnimation.dir = curAnimDir; } _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); } void TotEngine::updateVideo() { readBitmap(_curObject->dropOverlay, _screenLayers[_curObject->depth - 1], _curObject->dropOverlaySize, 319); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); } void TotEngine::nicheAnimation(byte nicheDir, int32 bitmap) { uint bitmapOffset = 0; int increment = 0; // Room with Red if (_currentRoomData->code == 24) { if (g_engine->_screenLayers[1]) { free(g_engine->_screenLayers[1]); } _screenLayers[1] = (byte *)malloc(3660); readBitmap(1382874, _screenLayers[1], 3652, 319); uint16 object1Width = READ_LE_UINT16(_screenLayers[1]); uint16 object1Height = READ_LE_UINT16(_screenLayers[1] + 2); _depthMap[1].posx = 211; _depthMap[1].posy = 16; _depthMap[1].posx2 = 211 + object1Width + 1; _depthMap[1].posy2 = 16 + object1Height + 1; } switch (nicheDir) { case 0: { bitmapOffset = 44904; increment = 1; Common::copy(_screenLayers[0], _screenLayers[0] + 892, _sceneBackground + 44900); readBitmap(bitmap, _screenLayers[0], 892, 319); Common::copy(_screenLayers[0] + 4, _screenLayers[0] + 4 + 888, _sceneBackground + 44900 + 892); } break; case 1: { // object slides to reveal empty stand bitmapOffset = 892 + 44900; increment = -1; // Reads the empty niche into a non-visible part of background readBitmap(bitmap, _sceneBackground + 44900, 892, 319); // Copies whatever is currently on the niche in a non-visible part of background contiguous with the above Common::copy(_screenLayers[0] + 4, _screenLayers[0] + 4 + 888, _sceneBackground + 44900 + 892); // We now have in consecutive pixels the empty stand and the object } break; } uint16 nicheWidth = READ_LE_UINT16(_screenLayers[0]); uint16 nicheHeight = READ_LE_UINT16(_screenLayers[0] + 2); // Set the height to double to animate 2 images of the same height moving up/down *(_sceneBackground + 44900 + 2) = (nicheHeight * 2) + 1; _graphics->restoreBackground(); for (uint i = 1; i <= nicheHeight; i++) { bitmapOffset = bitmapOffset + (increment * (nicheWidth + 1)); Common::copy(_sceneBackground + bitmapOffset, _sceneBackground + bitmapOffset + 888, _screenLayers[0] + 4); assembleScreen(); _graphics->drawScreen(_sceneBackground); _screen->update(); } readBitmap(bitmap, _screenLayers[0], 892, 319); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); if (_currentRoomData->code == 24) { clearScreenLayer(1); } } void TotEngine::pickupScreenObject() { byte inventoryIndex; uint screenObject; Common::Point p = _mouse->getClickCoordsWithinGrid(); uint correctedMouseX = p.x; uint correctedMouseY = p.y; screenObject = _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex; if (screenObject == 0) return; readObject(screenObject); goToObject( _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], _currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]); if (_curObject->pickupable) { _mouse->hide(); switch (_curObject->code) { case 521: { // Corridor lamp _currentRoomData->mouseGrid[10][11] = 19; _currentRoomData->mouseGrid[9][12] = 18; _currentRoomData->mouseGrid[10][12] = 18; } break; case 567: { // Pickup rubble if (_currentRoomData->animationFlag) { _mouse->show(); drawText(3226); return; } } break; case 590: // Ectoplasm _caves[1] = true; break; case 665: // Bird _caves[0] = true; break; case 676: case 688: { _caves[4] = true; _isVasePlaced = false; } break; } switch (_curObject->height) { case 0: { // Pick up above switch (_curObject->code) { case 590: { // Ectoplasm animatePickup1(3, 0); animatePickup2(3, 0); } break; default: { animatePickup1(_charFacingDirection, 0); clearScreenLayer(_curObject->depth - 1); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(_charFacingDirection, 0); } } } break; case 1: { // Waist level switch (_curObject->code) { case 218: // Necronomicon case 308: // Mistletoe case 517: // mints animatePickup1(0, 1); animatePickup2(0, 1); break; case 223: { // table cloths animatePickup1(0, 1); _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex = _curObject->replaceWith; updateVideo(); animatePickup2(0, 1); } break; case 402: { // Kitchen table animatePickup1(0, 1); updateVideo(); animatePickup2(0, 1); } break; case 479: { // Scissors animatePickup1(3, 1); animatePickup2(3, 1); } break; case 521: { // Puts plaster and key on the floor animatePickup1(0, 1); { RoomBitmapRegister &with = _currentRoomData->screenLayers[1]; with.bitmapPointer = 775611; with.bitmapSize = 36; with.coordx = 80; with.coordy = 56; with.depth = 2; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } { RoomBitmapRegister &with = _currentRoomData->screenLayers[2]; with.bitmapPointer = 730743; with.bitmapSize = 64; with.coordx = 76; with.coordy = 62; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } clearScreenLayer(_curObject->depth -1); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(0, 1); } break; case 562: { // niche switch (_currentRoomData->code) { case 20: { // First scene with niche if (_niche[0][_niche[0][3]] > 0) { // Possibly if (_niche[0][3] == 2 || _niche[0][_niche[0][3]] == 563) { readObject(_niche[0][_niche[0][3]]); _niche[0][_niche[0][3]] = 0; _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(4); animatePickup1(3, 1); readBitmap(1190768, _screenLayers[_curObject->depth - 1], 892, 319); _currentRoomData->screenLayers[1].bitmapPointer = 1190768; _currentRoomData->screenLayers[1].bitmapSize = 892; _currentRoomData->screenLayers[1].coordx = 66; _currentRoomData->screenLayers[1].coordy = 35; _currentRoomData->screenLayers[1].depth = 1; _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(3, 1); } else { readObject(_niche[0][_niche[0][3]]); _niche[0][_niche[0][3]] = 0; _niche[0][3] += 1; _niche[1][3] -= 1; _currentRoomData->screenObjectIndex[9]->objectName = " "; animatePickup1(3, 1); readBitmap(1190768, _screenLayers[_curObject->depth - 1], 892, 319); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(3, 1); _sound->playVoc("PLATAF", 375907, 14724); _currentRoomData->screenLayers[1].bitmapSize = 892; _currentRoomData->screenLayers[1].coordx = 66; _currentRoomData->screenLayers[1].coordy = 35; _currentRoomData->screenLayers[1].depth = 1; switch (_niche[0][_niche[0][3]]) { case 0: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(4); nicheAnimation(0, 1190768); _currentRoomData->screenLayers[1].bitmapPointer = 1190768; } break; case 561: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(5); nicheAnimation(0, 1182652); _currentRoomData->screenLayers[1].bitmapPointer = 1182652; } break; case 563: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(6); nicheAnimation(0, 1186044); _currentRoomData->screenLayers[1].bitmapPointer = 1186044; } break; case 615: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(7); nicheAnimation(0, 1181760); _currentRoomData->screenLayers[1].bitmapPointer = 1181760; } break; } updateAltScreen(24); } } else { _mouse->show(); drawText(1049 + getRandom(10)); _mouse->hide(); return; } } break; case 24: { // Second scene with niche if (_niche[1][_niche[1][3]] > 0 && _niche[1][3] != 1) { if (_niche[1][3] == 2) { readObject(_niche[1][2]); _niche[1][2] = 0; _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(4); animatePickup1(0, 1); readBitmap(1399610, _screenLayers[_curObject->depth - 1], 892, 319); _currentRoomData->screenLayers[0].bitmapPointer = 1399610; _currentRoomData->screenLayers[0].bitmapSize = 892; _currentRoomData->screenLayers[0].coordx = 217; _currentRoomData->screenLayers[0].coordy = 48; _currentRoomData->screenLayers[0].depth = 1; _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(0, 1); } else { readObject(_niche[1][_niche[1][3]]); _niche[1][_niche[1][3]] = 622; _niche[1][3] += 1; _niche[0][3] -= 1; _currentRoomData->screenObjectIndex[8]->objectName = " "; animatePickup1(0, 1); readBitmap(1399610, _screenLayers[0], 892, 319); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(0, 1); _sound->playVoc("PLATAF", 375907, 14724); _currentRoomData->screenLayers[0].bitmapSize = 892; _currentRoomData->screenLayers[0].coordx = 217; _currentRoomData->screenLayers[0].coordy = 48; _currentRoomData->screenLayers[0].depth = 1; switch (_niche[1][_niche[1][3]]) { case 0: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(4); nicheAnimation(0, 1399610); _currentRoomData->screenLayers[0].bitmapPointer = 1399610; } break; case 561: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(5); nicheAnimation(0, 1381982); _currentRoomData->screenLayers[0].bitmapPointer = 1381982; } break; case 615: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(7); nicheAnimation(0, 1381090); _currentRoomData->screenLayers[0].bitmapPointer = 1381090; } break; case 622: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(8); nicheAnimation(0, 1400502); _currentRoomData->screenLayers[0].bitmapPointer = 1400502; } break; case 623: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(9); nicheAnimation(0, 1398718); _currentRoomData->screenLayers[0].bitmapPointer = 1398718; } break; } updateAltScreen(20); } } else { _mouse->show(); drawText(1049 + getRandom(10)); _mouse->hide(); return; } } break; } } break; case 624: { // red devil animatePickup1(2, 1); { RoomBitmapRegister &with = _currentRoomData->screenLayers[3]; with.bitmapPointer = 0; with.bitmapSize = 0; with.coordx = 0; with.coordy = 0; with.depth = 0; } clearScreenLayer(3); disableSecondAnimation(); _graphics->drawScreen(_sceneBackground); animatePickup2(2, 1); _isRedDevilCaptured = true; _isTrapSet = false; } break; default: { animatePickup1(_charFacingDirection, 1); clearScreenLayer(_curObject->depth - 1); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(_charFacingDirection, 1); } } } break; case 2: { // Pick up feet level switch (_curObject->code) { case 216: { // chisel animatePickup1(0, 2); _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex = _curObject->replaceWith; updateVideo(); animatePickup2(0, 2); } break; case 295: { // candles animatePickup1(3, 2); _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex = _curObject->replaceWith; updateVideo(); animatePickup2(3, 2); } break; case 362: { // charcoal animatePickup1(0, 2); animatePickup2(0, 2); } break; case 598: { // mud animatePickup1(3, 2); animatePickup2(3, 2); } break; case 659: { // spider web, puts bird and ring on the floor animatePickup1(3, 2); clearScreenLayer(_curObject->depth - 1); { // bird RoomBitmapRegister &with = _currentRoomData->screenLayers[2]; with.bitmapPointer = 1545924; with.bitmapSize = 172; with.coordx = 38; with.coordy = 58; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } { // ring RoomBitmapRegister &with = _currentRoomData->screenLayers[1]; with.bitmapPointer = 1591272; with.bitmapSize = 92; with.coordx = 50; with.coordy = 58; with.depth = 3; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(3, 2); } break; default: { animatePickup1(_charFacingDirection, 2); clearScreenLayer(_curObject->depth - 1); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(_charFacingDirection, 2); } } } break; case 9: { // bat uint textRef = _curObject->pickTextRef; readObject(204); animatePickup1(0, 1); animateOpen2(0, 1); animateBat(); _mouse->show(); drawText(textRef); _currentRoomData->mouseGrid[34][8] = 24; _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); return; } break; } _mouse->show(); if (_curObject->code != 624) for (int j = _curObject->ygrid1; j <= _curObject->ygrid2; j++) for (int i = _curObject->xgrid1; i <= _curObject->xgrid2; i++) { _currentRoomData->walkAreasGrid[i][j] = _curObject->walkAreasPatch[i - _curObject->xgrid1][j - _curObject->ygrid1]; _currentRoomData->mouseGrid[i][j] = _curObject->mouseGridPatch[i - _curObject->xgrid1][j - _curObject->ygrid1]; } switch (_curObject->code) { case 216: { // chisel _currentRoomData->screenLayers[5].bitmapPointer = 517485; _currentRoomData->screenLayers[5].bitmapSize = 964; _currentRoomData->screenLayers[5].coordx = 223; _currentRoomData->screenLayers[5].coordy = 34; _currentRoomData->screenLayers[5].depth = 1; } break; case 218:; // necronomicon break; case 223: { // table cloth _currentRoomData->screenLayers[6].bitmapPointer = 436752; _currentRoomData->screenLayers[6].bitmapSize = 1372; _currentRoomData->screenLayers[6].coordx = 174; _currentRoomData->screenLayers[6].coordy = 32; _currentRoomData->screenLayers[6].depth = 1; } break; case 295: { // candles _currentRoomData->screenLayers[3].bitmapPointer = 1130756; _currentRoomData->screenLayers[3].bitmapSize = 1764; _currentRoomData->screenLayers[3].coordx = 100; _currentRoomData->screenLayers[3].coordy = 28; _currentRoomData->screenLayers[3].depth = 1; } break; case 308:; // mistletoe break; case 362:; // charcoal break; case 402: { _currentRoomData->screenLayers[5].bitmapPointer = 68130; _currentRoomData->screenLayers[5].bitmapSize = 2564; _currentRoomData->screenLayers[5].coordx = 148; _currentRoomData->screenLayers[5].coordy = 49; _currentRoomData->screenLayers[5].depth = 7; } break; case 479:; // scissors break; case 517:; // mints break; case 590:; // ectoplasm break; case 598:; // mud break; case 624:; // red devil break; default: { for (int i = 0; i < 15; i++) if (_currentRoomData->screenLayers[i].bitmapPointer == _curObject->bitmapPointer) { _currentRoomData->screenLayers[i].bitmapPointer = 0; _currentRoomData->screenLayers[i].bitmapSize = 0; _currentRoomData->screenLayers[i].coordx = 0; _currentRoomData->screenLayers[i].coordy = 0; _currentRoomData->screenLayers[i].depth = 0; } } } } else { if (_curObject->pickTextRef > 0) drawText(_curObject->pickTextRef); _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); return; } inventoryIndex = 0; while (_inventory[inventoryIndex].code != 0) { inventoryIndex += 1; } _inventory[inventoryIndex].bitmapIndex = _curObject->objectIconBitmap; _inventory[inventoryIndex].code = _curObject->code; _inventory[inventoryIndex].objectName = _curObject->name; _mouse->hide(); drawInventory(); _mouse->show(); if (_curObject->pickTextRef > 0) drawText(_curObject->pickTextRef); _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } void TotEngine::replaceBackpack(byte obj1, uint obj2) { readObject(obj2); _inventory[obj1].bitmapIndex = _curObject->objectIconBitmap; _inventory[obj1].code = obj2; _inventory[obj1].objectName = _curObject->name; _cpCounter = _cpCounter2; } void TotEngine::dropObjectInScreen(ScreenObject *replacementObject) { byte objIndex; if (replacementObject->bitmapSize > 0) { objIndex = 0; while (!(_currentRoomData->screenLayers[objIndex].bitmapSize == 0) || objIndex == 15) { objIndex++; } if (_currentRoomData->screenLayers[objIndex].bitmapSize == 0) { { RoomBitmapRegister &with = _currentRoomData->screenLayers[objIndex]; with.bitmapPointer = replacementObject->bitmapPointer; with.bitmapSize = replacementObject->bitmapSize; with.coordx = replacementObject->dropOverlayX; with.coordy = replacementObject->dropOverlayY; with.depth = replacementObject->depth; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } for (int j = replacementObject->ygrid1; j <= replacementObject->ygrid2; j++) for (int i = replacementObject->xgrid1; i <= replacementObject->xgrid2; i++) { _currentRoomData->walkAreasGrid[i][j] = replacementObject->walkAreasPatch[i - replacementObject->xgrid1][j - replacementObject->ygrid1]; _currentRoomData->mouseGrid[i][j] = replacementObject->mouseGridPatch[i - replacementObject->xgrid1][j - replacementObject->ygrid1]; } } else showError(264); } } void TotEngine::useScreenObject() { byte usedObjectIndex, listIndex, invIndex; bool verifyList, foobar; uint foo; Common::Point p = _mouse->getClickCoordsWithinGrid(); uint correctedMouseX = p.x; uint correctedMouseY = p.y; uint sceneObject = _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex; if (_inventoryObjectName != "") { //Use inv object with something on the scene usedObjectIndex = 0; while (_inventory[usedObjectIndex].objectName != _inventoryObjectName) { usedObjectIndex += 1; } readObject(_inventory[usedObjectIndex].code); goToObject( _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], _currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]); if (_curObject->useWith == sceneObject && sceneObject > 0 && _curObject->used[0] == 5) { switch (_curObject->useWith) { case 30: { // corn with rooster drawText(_curObject->useTextRef); _mouse->hide(); animateGive(1, 2); animatePickup2(1, 2); updateObject(_curObject->code); _currentRoomData->screenObjectIndex[27]->fileIndex = 201; do { _chrono->updateChrono(); if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; emptyLoop(); _chrono->_gameTick = false; emptyLoop2(); sprites(true); _screen->update(); } while (_currentSecondaryTrajectoryIndex != 4); for (listIndex = 0; listIndex < _maxXGrid; listIndex++) for (invIndex = 0; invIndex < _maxYGrid; invIndex++) { _currentRoomData->walkAreasGrid[_oldposx + listIndex][_oldposy + invIndex] = _movementGridForSecondaryAnim[listIndex][invIndex]; _currentRoomData->mouseGrid[_oldposx + listIndex][_oldposy + invIndex] = _mouseGridForSecondaryAnim[listIndex][invIndex]; } clearAnimation(); _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x + 8; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; _currentRoomData->animationName = "GALLOPIC"; _currentRoomData->secondaryAnimDirections[299] = 201; loadAnimation("GALLOPIC"); _currentRoomData->secondaryAnimDirections[0] = 0; _currentRoomData->secondaryAnimTrajectory[0].x = _secondaryAnimation.posx; _currentRoomData->secondaryAnimTrajectory[0].y = _secondaryAnimation.posy; _currentSecondaryTrajectoryIndex = 1; _currentRoomData->secondaryTrajectoryLength = 1; for (listIndex = 0; listIndex < _maxXGrid; listIndex++) for (invIndex = 0; invIndex < _maxYGrid; invIndex++) { if (_maskGridSecondaryAnim[listIndex][invIndex] > 0) _currentRoomData->walkAreasGrid[_oldposx + listIndex][_oldposy + invIndex] = _maskGridSecondaryAnim[listIndex][invIndex]; if (_maskMouseSecondaryAnim[listIndex][invIndex] > 0) _currentRoomData->mouseGrid[_oldposx + listIndex][_oldposy + invIndex] = _maskMouseSecondaryAnim[listIndex][invIndex]; } _mouse->show(); } break; case 153: { // oil with well drawText(_curObject->useTextRef); _mouse->hide(); _sound->playVoc("BLUP", 330921, 3858); animateGive(3, 1); animatePickup2(3, 1); _mouse->show(); updateObject(_curObject->code); _currentRoomData->screenObjectIndex[21]->fileIndex = 154; } break; case 157: { // giving something to john verifyList = false; debug("used object = %d", _inventory[usedObjectIndex].code); if (_obtainedList1) { for (listIndex = 0; listIndex < 5; listIndex++) { if (_inventory[usedObjectIndex].code == _firstList[listIndex]) verifyList = true; } if (verifyList) { int completedListItems = 0; for (listIndex = 0; listIndex < 5; listIndex++) { for (invIndex = 0; invIndex < kInventoryIconCount; invIndex++) { if (_inventory[invIndex].code == _firstList[listIndex]) { completedListItems += 1; break; } } } if (completedListItems == 5) { _obtainedList1 = false; _list1Complete = true; readTextFile(); sayLine(1018, 255, 0, foo, false); sayLine(foo, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); for (listIndex = 0; listIndex < 5; listIndex++) { invIndex = 0; while (_inventory[invIndex].code != _firstList[listIndex]) { invIndex += 1; } updateInventory(invIndex); } listIndex = 0; while (_inventory[listIndex].code != 149) { listIndex += 1; } updateInventory(listIndex); drawInventory(); _mouse->show(); } else { readTextFile(); sayLine(_curObject->useTextRef, 255, 0, foo, false); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _verbFile.close(); } } } verifyList = false; if (_obtainedList2) { for (listIndex = 0; listIndex < 5; listIndex++) if (_inventory[usedObjectIndex].code == _secondList[listIndex]) verifyList = true; if (verifyList) { int completedListItems = 0; for (listIndex = 0; listIndex < 5; listIndex++) { for (invIndex = 0; invIndex < kInventoryIconCount; invIndex++) { if (_inventory[invIndex].code == _secondList[listIndex]) { completedListItems += 1; break; } } } if (completedListItems == 5) { _obtainedList2 = false; _list2Complete = true; readTextFile(); sayLine(1020, 255, 0, foo, false); sayLine(foo, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); for (listIndex = 0; listIndex < 5; listIndex++) { invIndex = 0; while (_inventory[invIndex].code != _secondList[listIndex]) { invIndex += 1; } updateInventory(invIndex); } listIndex = 0; while (_inventory[listIndex].code != 150) { listIndex += 1; } updateInventory(listIndex); drawInventory(); _mouse->show(); } else { readTextFile(); sayLine(_curObject->useTextRef, 255, 0, foo, false); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _verbFile.close(); } } } } break; case 159: { switch (_curObject->code) { case 173: { readTextFile(); sayLine(1118, 255, 0, foo, false); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _verbFile.close(); } break; case 218: { readTextFile(); sayLine(687, 255, 0, foo, false); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); for (foo = 0; foo < kCharacterCount; foo++) _bookTopic[foo] = true; _firstTimeTopicB[0] = true; } break; } } break; case 160: { readTextFile(); sayLine(2466, 255, 0, foo, false); _mouse->hide(); animateGive(_charFacingDirection, 1); animateOpen2(_charFacingDirection, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); for (foo = 0; foo < kCharacterCount; foo++) { _mintTopic[foo] = true; _firstTimeTopicC[foo] = true; } } break; case 164: { switch (_curObject->code) { case 563: { _isPottersManualDelivered = true; if (_isPottersWheelDelivered && _isGreenDevilDelivered && _isMudDelivered) { readTextFile(); sayLine(2696, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animateOpen2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _caves[4] = true; sayLine(3247, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); replaceBackpack(usedObjectIndex, 676); drawInventory(); disableSecondAnimation(); { RoomBitmapRegister &with = _currentRoomData->screenLayers[0]; with.bitmapPointer = 1545820; with.bitmapSize = 104; with.coordx = 120; with.coordy = 55; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _currentRoomData->mouseGrid[15][12] = 7; _mouse->show(); } else { readTextFile(); sayLine(2696, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animateOpen2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); sayLine(3246, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); } } break; case 598: { _isMudDelivered = true; if (_isPottersWheelDelivered && _isGreenDevilDelivered && _isPottersManualDelivered) { readTextFile(); sayLine(2821, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animatePickup2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _caves[4] = true; sayLine(3247, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); replaceBackpack(usedObjectIndex, 676); drawInventory(); disableSecondAnimation(); { RoomBitmapRegister &with = _currentRoomData->screenLayers[0]; with.bitmapPointer = 1545820; with.bitmapSize = 104; with.coordx = 120; with.coordy = 55; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _currentRoomData->mouseGrid[15][12] = 7; _mouse->show(); } else { readTextFile(); sayLine(2821, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animateOpen2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); sayLine(3246, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); } } break; case 623: { _isPottersWheelDelivered = true; if (_isMudDelivered && _isGreenDevilDelivered && _isPottersManualDelivered) { readTextFile(); sayLine(2906, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animatePickup2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _caves[4] = true; sayLine(3247, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); replaceBackpack(usedObjectIndex, 676); drawInventory(); disableSecondAnimation(); { RoomBitmapRegister &with = _currentRoomData->screenLayers[0]; with.bitmapPointer = 1545820; with.bitmapSize = 104; with.coordx = 120; with.coordy = 55; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _currentRoomData->mouseGrid[15][12] = 7; _mouse->show(); } else { readTextFile(); sayLine(2906, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animateOpen2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); sayLine(3246, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); } } break; case 701: { _isGreenDevilDelivered = true; if (_isMudDelivered && _isPottersWheelDelivered && _isPottersManualDelivered) { readTextFile(); sayLine(3188, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animatePickup2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); _caves[4] = true; sayLine(3247, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); replaceBackpack(usedObjectIndex, 676); drawInventory(); disableSecondAnimation(); { RoomBitmapRegister &with = _currentRoomData->screenLayers[0]; with.bitmapPointer = 1545820; with.bitmapSize = 104; with.coordx = 120; with.coordy = 55; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _currentRoomData->mouseGrid[15][12] = 7; _mouse->show(); } else { readTextFile(); sayLine(3188, 255, 0, foo, false); _mouse->hide(); animateGive(0, 1); animateOpen2(0, 1); _mouse->show(); sayLine(foo, 253, 249, foo, true); sayLine(3246, 253, 249, foo, true); _verbFile.close(); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); } } break; } } break; case 165: { drawText(1098); _mouse->hide(); do { if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; emptyLoop(); _chrono->_gameTick = false; emptyLoop2(); sprites(true); } while (!(_currentSecondaryTrajectoryIndex == (_currentRoomData->secondaryTrajectoryLength / 2u))); animateGive(3, 2); updateInventory(usedObjectIndex); drawInventory(); animateOpen2(3, 2); animatedSequence(6); do { if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; emptyLoop(); _chrono->_gameTick = false; emptyLoop2(); sprites(true); } while (_currentSecondaryTrajectoryIndex != _currentRoomData->secondaryTrajectoryLength); disableSecondAnimation(); _graphics->drawScreen(_sceneBackground); _mouse->show(); } break; case 201: { drawText(_curObject->useTextRef); _sound->playVoc("GALLO", 94965, 46007); _mouse->hide(); animatedSequence(5); replaceBackpack(usedObjectIndex, 423); drawInventory(); _mouse->show(); _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 219: { drawText(_curObject->useTextRef); _mouse->hide(); _sound->playVoc("TAZA", 223698, 29066); animateGive(3, 2); do { _chrono->updateChrono(); if (_chrono->_gameTick) { _graphics->advancePaletteAnim(); _chrono->_gameTick = false; } _screen->update(); g_system->delayMillis(10); } while (_sound->isVocPlaying()); animateOpen2(3, 2); updateObject(_curObject->code); disableSecondAnimation(); _graphics->drawScreen(_sceneBackground); _mouse->show(); drawText(2652); _mouse->hide(); readObject(536); for (int i = 12; i <= 13; i++) for (int j = 7; j <= 14; j++) _currentRoomData->mouseGrid[i][j] = 14; for (int i = 8; i <= 12; i++) _currentRoomData->mouseGrid[14][i] = 14; _currentRoomData->mouseGrid[9][10] = 1; _currentRoomData->mouseGrid[10][10] = 1; for (int i = 0; i < 15; i++) if (_currentRoomData->screenLayers[i].bitmapPointer == _curObject->bitmapPointer) { _currentRoomData->screenLayers[i].bitmapPointer = 0; _currentRoomData->screenLayers[i].bitmapSize = 0; _currentRoomData->screenLayers[i].coordx = 0; _currentRoomData->screenLayers[i].coordy = 0; _currentRoomData->screenLayers[i].depth = 0; } usedObjectIndex = 0; while (_inventory[usedObjectIndex].code != 0) { usedObjectIndex += 1; } _inventory[usedObjectIndex].bitmapIndex = _curObject->objectIconBitmap; _inventory[usedObjectIndex].code = _curObject->code; _inventory[usedObjectIndex].objectName = _curObject->name; animatedSequence(4); _mouse->show(); _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 221: { drawText(_curObject->useTextRef); _curObject->used[0] = 9; usedObjectIndex = 0; while (_inventory[usedObjectIndex].code != 0) { usedObjectIndex += 1; } _sceneObjectsData->seek(_curObject->code); saveObjectsData(_curObject, _sceneObjectsData); readObject(_sceneObjectsData, 221, _curObject); _inventory[usedObjectIndex].bitmapIndex = _curObject->objectIconBitmap; _inventory[usedObjectIndex].code = _curObject->code; _inventory[usedObjectIndex].objectName = _curObject->name; _mouse->hide(); animatePickup1(2, 0); _sound->playVoc("TIJERAS", 252764, 5242); _sound->waitForSoundEnd(); animatePickup2(2, 0); drawInventory(); _mouse->show(); } break; case 227: { drawText(_curObject->useTextRef); _mouse->hide(); _sound->playVoc("ALACENA", 319112, 11809); animatePickup1(0, 2); _sound->waitForSoundEnd(); animateOpen2(0, 2); replaceBackpack(usedObjectIndex, 453); drawInventory(); _mouse->show(); updateObject(_inventory[usedObjectIndex].code); _isCupboardOpen = true; } break; case 274: { drawText(_curObject->useTextRef); _mouse->hide(); _sound->playVoc("CINCEL", 334779, 19490); animatePickup1(_charFacingDirection, 2); _sound->waitForSoundEnd(); animateOpen2(_charFacingDirection, 2); _mouse->show(); updateObject(_curObject->code); _isChestOpen = true; } break; case 416: { updateObject(_curObject->code); _mouse->hide(); _sound->playVoc("PUERTA", 186429, 4754); animatePickup1(0, 1); animateOpen2(0, 1); _sound->waitForSoundEnd(); _sound->loadVoc("GOTA", 140972, 1029); _mouse->show(); drawText(_curObject->useTextRef); _currentRoomData->doors[2].openclosed = 0; } break; case 446: { drawText(_curObject->useTextRef); _mouse->hide(); _sound->playVoc("TAZA", 223698, 29066); animateGive(0, 2); _sound->waitForSoundEnd(); animatePickup2(0, 2); replaceBackpack(usedObjectIndex, 204); drawInventory(); _mouse->show(); } break; case 507: { _mouse->hide(); animatePickup1(0, 1); _sound->playVoc("MAQUINA", 153470, 7378); animateOpen2(0, 1); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); _currentRoomData->mouseGrid[27][8] = 22; } break; case 549: { updateObject(_curObject->code); _mouse->hide(); _sound->playVoc("PUERTA", 186429, 4754); animatePickup1(1, 1); animateOpen2(1, 1); _mouse->show(); drawText(_curObject->useTextRef); _currentRoomData->doors[0].openclosed = 0; } break; case 562: { // put any object in the niches switch (_currentRoomData->code) { case 20: { if (_niche[0][_niche[0][3]] == 0) { if (_niche[0][3] == 0) { _niche[0][0] = _curObject->code; drawText(_curObject->useTextRef); _mouse->hide(); _currentRoomData->screenObjectIndex[9]->objectName = " "; animateGive(3, 1); switch (_niche[0][0]) { case 561: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(5); readBitmap(1182652, _screenLayers[0], 892, 319); _currentRoomData->screenLayers[1].bitmapPointer = 1182652; } break; case 615: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(7); readBitmap(1181760, _screenLayers[0], 892, 319); _currentRoomData->screenLayers[1].bitmapPointer = 1181760; } break; } _currentRoomData->screenLayers[1].bitmapSize = 892; _currentRoomData->screenLayers[1].coordx = 66; _currentRoomData->screenLayers[1].coordy = 35; _currentRoomData->screenLayers[1].depth = 1; _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(3, 1); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); } else { _niche[0][_niche[0][3]] = _curObject->code; _niche[1][3] += 1; _niche[0][3] -= 1; drawText(_curObject->useTextRef); _mouse->hide(); animateGive(3, 1); switch (_curObject->code) { case 561: readBitmap(1182652, _screenLayers[0], 892, 319); break; case 615: readBitmap(1181760, _screenLayers[0], 892, 319); break; } _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(3, 1); updateInventory(usedObjectIndex); drawInventory(); _currentRoomData->screenObjectIndex[9]->objectName = " "; _sound->playVoc("PLATAF", 375907, 14724); switch (_niche[0][_niche[0][3]]) { case 0: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(4); nicheAnimation(1, 1190768); _currentRoomData->screenLayers[1].bitmapPointer = 1190768; } break; case 561: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(5); nicheAnimation(1, 1182652); _currentRoomData->screenLayers[1].bitmapPointer = 1182652; } break; case 563: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(6); nicheAnimation(1, 1186044); _currentRoomData->screenLayers[1].bitmapPointer = 1186044; } break; case 615: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(7); nicheAnimation(1, 1181760); _currentRoomData->screenLayers[1].bitmapPointer = 1181760; } break; } _currentRoomData->screenLayers[1].bitmapSize = 892; _currentRoomData->screenLayers[1].coordx = 66; _currentRoomData->screenLayers[1].coordy = 35; _currentRoomData->screenLayers[1].depth = 1; _mouse->show(); updateAltScreen(24); } } else { drawText(getRandom(11) + 1022); } } break; case 24: { if (_niche[1][_niche[1][3]] == 0) { if (_niche[1][3] == 0) { _niche[1][0] = _curObject->code; drawText(_curObject->useTextRef); _mouse->hide(); _currentRoomData->screenObjectIndex[8]->objectName = " "; animateGive(0, 1); switch (_niche[1][0]) { case 561: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(5); readBitmap(1381982, _screenLayers[0], 892, 319); _currentRoomData->screenLayers[0].bitmapPointer = 1381982; } break; case 615: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(7); readBitmap(1381090, _screenLayers[0], 892, 319); _currentRoomData->screenLayers[0].bitmapPointer = 1381090; } break; } _currentRoomData->screenLayers[0].bitmapSize = 892; _currentRoomData->screenLayers[0].coordx = 217; _currentRoomData->screenLayers[0].coordy = 48; _currentRoomData->screenLayers[0].depth = 1; _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(0, 1); updateInventory(usedObjectIndex); drawInventory(); _mouse->show(); } else { _niche[1][_niche[1][3]] = _curObject->code; _niche[0][3] += 1; _niche[1][3] -= 1; drawText(_curObject->useTextRef); _mouse->hide(); animateGive(0, 1); switch (_curObject->code) { case 561: readBitmap(1381982, _screenLayers[_curObject->depth - 1], 892, 319); break; case 615: readBitmap(1381090, _screenLayers[_curObject->depth - 1], 892, 319); break; } _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(0, 1); updateInventory(usedObjectIndex); drawInventory(); _currentRoomData->screenObjectIndex[8]->objectName = " "; _sound->playVoc("PLATAF", 375907, 14724); switch (_niche[1][_niche[1][3]]) { case 0: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(4); nicheAnimation(1, 1399610); _currentRoomData->screenLayers[0].bitmapPointer = 1399610; } break; case 561: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(5); nicheAnimation(1, 1381982); _currentRoomData->screenLayers[0].bitmapPointer = 1381982; } break; case 615: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(7); nicheAnimation(1, 1381090); _currentRoomData->screenLayers[0].bitmapPointer = 1381090; } break; case 622: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(8); nicheAnimation(1, 1400502); _currentRoomData->screenLayers[0].bitmapPointer = 1400502; } break; case 623: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(9); nicheAnimation(1, 1398718); _currentRoomData->screenLayers[0].bitmapPointer = 1398718; } break; } _currentRoomData->screenLayers[0].bitmapSize = 892; _currentRoomData->screenLayers[0].coordx = 217; _currentRoomData->screenLayers[0].coordy = 48; _currentRoomData->screenLayers[0].depth = 1; _mouse->show(); updateAltScreen(20); } } else { drawText(getRandom(11) + 1022); } } break; } } break; case 583: { int32 offset = getOffsetsByCurrentLanguage()[20]; drawText(_curObject->useTextRef); _mouse->hide(); drawFlc(140, 34, offset, 0, 9, 24, false, false, true, foobar); _mouse->show(); updateObject(_curObject->code); _currentRoomData->screenObjectIndex[7]->fileIndex = 716; _currentRoomData->mouseGrid[19][9] = 14; _currentRoomData->mouseGrid[22][16] = 15; for (listIndex = 21; listIndex <= 22; listIndex++) for (invIndex = 17; invIndex <= 20; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 17; { RoomBitmapRegister &with = _currentRoomData->screenLayers[0]; with.bitmapPointer = 1243652; with.bitmapSize = 2718; with.coordx = 127; with.coordy = 36; with.depth = 6; } { RoomBitmapRegister &with = _currentRoomData->screenLayers[1]; with.bitmapPointer = 1240474; with.bitmapSize = 344; with.coordx = 168; with.coordy = 83; with.depth = 12; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } { RoomBitmapRegister &with = _currentRoomData->screenLayers[2]; with.bitmapPointer = 1240818; with.bitmapSize = 116; with.coordx = 177; with.coordy = 82; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } readBitmap(1243652, _screenLayers[5], 2718, 319); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); } break; case 594: { drawText(_curObject->useTextRef); _mouse->hide(); animateGive(3, 2); animatePickup2(3, 2); replaceBackpack(usedObjectIndex, 607); drawInventory(); _mouse->show(); } break; case 608: { drawText(_curObject->useTextRef); goToObject(_currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY], 26); _mouse->hide(); animateGive(2, 2); animateOpen2(2, 2); { RoomBitmapRegister &with = _currentRoomData->screenLayers[3]; with.bitmapPointer = 1546096; with.bitmapSize = 372; with.coordx = 208; with.coordy = 105; with.depth = 4; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); updateInventory(usedObjectIndex); drawInventory(); _isTrapSet = true; _mouse->show(); } break; case 632: { int32 offset = getOffsetsByCurrentLanguage()[21]; drawText(_curObject->useTextRef); _mouse->hide(); animateGive(_charFacingDirection, 1); // Show feather on pedestal loadScreenLayer(187, 70, 104, 1545820, 8); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); _screen->update(); animateOpen2(_charFacingDirection, 1); _mouse->show(); goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 14); _mouse->hide(); _sound->playVoc("PUFF", 191183, 18001); // Animate to scythe drawFlc(180, 60, offset, 0, 9, 0, false, false, true, foobar); // load Scythe _currentRoomData->screenLayers[2].bitmapPointer = 1545820; _currentRoomData->screenLayers[2].bitmapSize = 104; _currentRoomData->screenLayers[2].coordx = 277; _currentRoomData->screenLayers[2].coordy = 104; _currentRoomData->screenLayers[2].depth = 1; _depthMap[0].posy = 104; readBitmap(1545820, _screenLayers[0], 104, 319); _currentRoomData->screenLayers[4].bitmapPointer = 1447508; _currentRoomData->screenLayers[4].bitmapSize = 464; _currentRoomData->screenLayers[4].coordx = 186; _currentRoomData->screenLayers[4].coordy = 64; _currentRoomData->screenLayers[4].depth = 8; loadScreenLayer(186, 63, 464, 1447508, 8); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); _mouse->show(); goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 18); _mouse->hide(); animatePickup1(1, 1); replaceBackpack(usedObjectIndex, 638); _currentRoomData->screenLayers[4].bitmapPointer = 0; _currentRoomData->screenLayers[4].bitmapSize = 0; _currentRoomData->screenLayers[4].coordx = 0; _currentRoomData->screenLayers[4].coordy = 0; _currentRoomData->screenLayers[4].depth = 0; clearScreenLayer(7); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(1, 1); drawInventory(); _mouse->show(); for (listIndex = 35; listIndex <= 37; listIndex++) for (invIndex = 21; invIndex <= 25; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 11; _isScytheTaken = true; if (_isTridentTaken) _caves[3] = true; } break; case 633: { //Use ring! int32 offset = getOffsetsByCurrentLanguage()[22]; drawText(_curObject->useTextRef); _mouse->hide(); animateGive(3, 1); loadScreenLayer(86, 55, 92, 1591272, 8); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(3, 1); _mouse->show(); goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 10); _mouse->hide(); _sound->playVoc("PUFF", 191183, 18001); drawFlc(0, 47, offset, 0, 9, 0, false, false, true, foobar); _currentRoomData->screenLayers[3].bitmapPointer = 1591272; _currentRoomData->screenLayers[3].bitmapSize = 92; _currentRoomData->screenLayers[3].coordx = 18; _currentRoomData->screenLayers[3].coordy = 60; _currentRoomData->screenLayers[3].depth = 3; _depthMap[2].posx = 18; _depthMap[2].posy = 60; readBitmap(1591272, _screenLayers[2], 92, 319); _currentRoomData->screenLayers[4].bitmapPointer = 1746554; _currentRoomData->screenLayers[4].bitmapSize = 384; _currentRoomData->screenLayers[4].coordx = 82; _currentRoomData->screenLayers[4].coordy = 53; _currentRoomData->screenLayers[4].depth = 8; loadScreenLayer(82, 53, 384, 1746554, 8); assembleScreen(); _graphics->drawScreen(_sceneBackground); _mouse->show(); goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 15); _mouse->hide(); animatePickup1(3, 1); replaceBackpack(usedObjectIndex, 637); _currentRoomData->screenLayers[4].bitmapPointer = 0; _currentRoomData->screenLayers[4].bitmapSize = 0; _currentRoomData->screenLayers[4].coordx = 0; _currentRoomData->screenLayers[4].coordy = 0; _currentRoomData->screenLayers[4].depth = 0; clearScreenLayer(7); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animatePickup2(3, 1); drawInventory(); _mouse->show(); for (listIndex = 0; listIndex <= 2; listIndex++) for (invIndex = 10; invIndex <= 12; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 10; _isTridentTaken = true; if (_isScytheTaken) _caves[3] = true; } break; case 643: { // Urn with altar int32 offset = getOffsetsByCurrentLanguage()[23]; if (_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount] != 5) drawText(_curObject->useTextRef); _mouse->mouseClickX = 149 - 7; _mouse->mouseClickY = 126 - 7; goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 5); _mouse->hide(); updateInventory(usedObjectIndex); drawInventory(); drawFlc(133, 0, offset, 0, 9, 22, false, false, true, foobar); { RoomBitmapRegister &with = _currentRoomData->screenLayers[2]; with.bitmapPointer = 1744230; with.bitmapSize = 824; with.coordx = 147; with.coordy = 38; with.depth = 9; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } updateAltScreen(31); for (listIndex = 18; listIndex <= 20; listIndex++) for (invIndex = 8; invIndex <= 14; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 12; _isSealRemoved = true; _caves[1] = false; _caves[0] = false; _caves[4] = false; _mouse->show(); } break; case 657: { // sharpen scythe int32 offset = getOffsetsByCurrentLanguage()[24]; drawText(_curObject->useTextRef); _mouse->mouseClickX = 178 - 7; _mouse->mouseClickY = 71 - 7; goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 3); _mouse->hide(); _sound->playVoc("AFILAR", 0, 6433); drawFlc(160, 15, offset, 0, 9, 23, false, false, true, foobar); replaceBackpack(usedObjectIndex, 715); drawInventory(); _mouse->show(); } break; case 686: { drawText(_curObject->useTextRef); _isVasePlaced = true; _caves[4] = false; _mouse->hide(); animateGive(1, 1); updateInventory(usedObjectIndex); dropObjectInScreen(_curObject); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); drawInventory(); animateOpen2(1, 1); for (listIndex = 19; listIndex <= 21; listIndex++) for (invIndex = 10; invIndex <= 13; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 13; _mouse->show(); } break; case 689: { // rope int32 offset = getOffsetsByCurrentLanguage()[25]; drawText(_curObject->useTextRef); _mouse->mouseClickX = 124 - 7; _mouse->mouseClickY = 133 - 7; goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 9); _mouse->hide(); drawFlc(110, 79, offset, 0, 9, 0, false, false, true, foobar); replaceBackpack(usedObjectIndex, 701); drawInventory(); _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); _mouse->show(); for (listIndex = 18; listIndex <= 20; listIndex++) _currentRoomData->mouseGrid[listIndex][26] = 10; for (listIndex = 17; listIndex <= 21; listIndex++) _currentRoomData->mouseGrid[listIndex][27] = 10; } break; case 700: { // Trident int32 offset = getOffsetsByCurrentLanguage()[26]; drawText(_curObject->useTextRef); _mouse->mouseClickX = 224 - 7; _mouse->mouseClickY = 91 - 7; goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], 7); _mouse->hide(); drawFlc(208, 0, offset, 0, 9, 21, false, false, true, foobar); _currentRoomData->screenLayers[0].bitmapPointer = 0; _currentRoomData->screenLayers[0].bitmapSize = 0; _currentRoomData->screenLayers[0].coordx = 0; _currentRoomData->screenLayers[0].coordy = 0; _currentRoomData->screenLayers[0].depth = 0; clearScreenLayer(2); for (invIndex = 6; invIndex <= 9; invIndex++) _currentRoomData->mouseGrid[26][invIndex] = 3; for (invIndex = 3; invIndex <= 5; invIndex++) _currentRoomData->mouseGrid[27][invIndex] = 3; for (invIndex = 6; invIndex <= 10; invIndex++) _currentRoomData->mouseGrid[27][invIndex] = 4; for (invIndex = 11; invIndex <= 12; invIndex++) _currentRoomData->mouseGrid[27][invIndex] = 7; for (invIndex = 2; invIndex <= 10; invIndex++) _currentRoomData->mouseGrid[28][invIndex] = 4; for (invIndex = 11; invIndex <= 12; invIndex++) _currentRoomData->mouseGrid[28][invIndex] = 7; _currentRoomData->mouseGrid[28][13] = 4; for (invIndex = 1; invIndex <= 14; invIndex++) _currentRoomData->mouseGrid[29][invIndex] = 4; for (listIndex = 30; listIndex <= 32; listIndex++) for (invIndex = 0; invIndex <= 15; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 4; for (invIndex = 1; invIndex <= 14; invIndex++) _currentRoomData->mouseGrid[33][invIndex] = 4; for (invIndex = 2; invIndex <= 14; invIndex++) _currentRoomData->mouseGrid[34][invIndex] = 4; for (invIndex = 3; invIndex <= 8; invIndex++) _currentRoomData->mouseGrid[35][invIndex] = 4; for (invIndex = 9; invIndex <= 11; invIndex++) _currentRoomData->mouseGrid[35][invIndex] = 7; _currentRoomData->doors[1].openclosed = 1; _mouse->show(); updateObject(_curObject->code); } break; case 709: { // rock with mural int32 offset = getOffsetsByCurrentLanguage()[27]; if (_isSealRemoved) { drawText(_curObject->useTextRef); _mouse->hide(); animatePickup1(0, 1); _sound->playVoc("TIZA", 390631, 18774); { RoomBitmapRegister &with = _currentRoomData->screenLayers[1]; with.bitmapPointer = 1745054; with.bitmapSize = 1500; with.coordx = 39; with.coordy = 16; with.depth = 1; loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); _sound->waitForSoundEnd(); _sound->playVoc("PUFF", 191183, 18001); animateOpen2(0, 1); drawFlc(180, 50, offset, 0, 9, 22, false, false, true, foobar); _shouldQuitGame = true; } else drawText(getRandom(11) + 1022); } break; } } else { goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], _currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]); if (_curObject->code == 536 || _curObject->code == 220) drawText(getRandom(6) + 1033); else drawText(getRandom(11) + 1022); } } else { //use object with something on the scene if (sceneObject > 0) { readObject(sceneObject); goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], _currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]); switch (_curObject->used[0]) { case 0: { if (_curObject->useTextRef > 0) drawText(_curObject->useTextRef); } break; case 9: { if (_curObject->afterUseTextRef > 0) drawText(_curObject->afterUseTextRef); } break; case 100: { switch (_curObject->code) { case 153: { _mouse->hide(); animatedSequence(2); _mouse->show(); } break; case 154: { _curObject->used[0] = 9; if (_curObject->beforeUseTextRef > 0) drawText(_curObject->beforeUseTextRef); _mouse->hide(); animatedSequence(1); _mouse->show(); drawText(1425); _mouse->hide(); animatedSequence(3); _mouse->show(); updateObject(_curObject->code); readObject(152); usedObjectIndex = 0; while (_inventory[usedObjectIndex].code != 0) { usedObjectIndex += 1; } _inventory[usedObjectIndex].bitmapIndex = _curObject->objectIconBitmap; _inventory[usedObjectIndex].code = _curObject->code; _inventory[usedObjectIndex].objectName = _curObject->name; _mouse->hide(); drawInventory(); _mouse->show(); } break; case 169: { _mouse->hide(); animatePickup1(0, 1); animateOpen2(0, 1); _isTVOn = !(_isTVOn); if (_isTVOn) { _sound->playVoc("CLICK", 27742, 2458); _sound->waitForSoundEnd(); _currentRoomData->paletteAnimationFlag = true; _sound->autoPlayVoc("PARASITO", 355778, 20129); } else { _sound->stopVoc(); _sound->playVoc("CLICK", 27742, 2458); _currentRoomData->paletteAnimationFlag = false; for (int i = 195; i <= 200; i++) { g_engine->_graphics->_pal[i * 3 + 0] = 2 << 2; g_engine->_graphics->_pal[i * 3 + 1] = 2 << 2; g_engine->_graphics->_pal[i * 3 + 2] = 2 << 2; setRGBPalette(i, 2, 2, 2); } } _mouse->show(); } break; case 347: { drawText(_curObject->useTextRef); _sound->stopVoc(); _sound->playVoc("CLICK", 27742, 2458); _mouse->hide(); animatePickup1(0, 0); delay(100); animateOpen2(0, 0); _sound->stopVoc(); _sound->autoPlayVoc("CALDERA", 6433, 15386); _graphics->turnLightOn(); _mouse->show(); _currentRoomData->palettePointer = 1536; _currentRoomData->screenObjectIndex[1]->fileIndex = 424; _currentRoomData->doors[1].openclosed = 1; } break; case 359: { drawText(_curObject->useTextRef); _sound->stopVoc(); _sound->playVoc("CARBON", 21819, 5923); _mouse->hide(); animatePickup1(0, 0); delay(100); animateOpen2(0, 0); _mouse->show(); updateObject(_curObject->code); _currentRoomData->screenObjectIndex[16]->fileIndex = 362; _currentRoomData->screenObjectIndex[16]->objectName = getObjectName(2); _currentRoomData->screenObjectIndex[1]->fileIndex = 347; _currentRoomData->screenObjectIndex[1]->objectName = getObjectName(3); _sound->stopVoc(); _sound->autoPlayVoc("CALDERA", 6433, 15386); } break; case 682: { int32 offsetWithJar = getOffsetsByCurrentLanguage()[28]; int32 offsetNoJar = getOffsetsByCurrentLanguage()[29]; _mouse->hide(); _sound->playVoc("CLICK", 27742, 2458); animatePickup1(0, 1); _sound->waitForSoundEnd(); animateOpen2(0, 1); _sound->playVoc("FUEGO", 72598, 9789); if (_isVasePlaced) { drawFlc(108, 0, offsetWithJar, 0, 9, 0, false, false, true, foobar); { RoomBitmapRegister &with = _currentRoomData->screenLayers[0]; with.bitmapPointer = 1636796; with.bitmapSize = 628; with.coordx = 153; with.coordy = 48; with.depth = 1; } for (listIndex = 19; listIndex <= 21; listIndex++) for (invIndex = 10; invIndex <= 13; invIndex++) _currentRoomData->mouseGrid[listIndex][invIndex] = 12; } else drawFlc(108, 0, offsetNoJar, 0, 9, 0, false, false, true, foobar); _mouse->show(); } break; } if ((_curObject->beforeUseTextRef > 0) && (_curObject->code != 154)) drawText(_curObject->beforeUseTextRef); } break; default: drawText(1022 + getRandom(11)); } } } _oldGridX = 0; _oldGridY = 0; _actionCode = 0; checkMouseGrid(); } void TotEngine::openScreenObject() { byte xIndex, yIndex; bool shouldSpeak; //Whether the character should speak to reject the action or not Common::Point p = _mouse->getClickCoordsWithinGrid(); uint correctedMouseX = p.x; uint correctedMouseY = p.y; uint screenObject = _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex; if (screenObject == 0) return; readObject(screenObject); debug("Read screen object = %s, with code = %d, depth=%d", _curObject->name.c_str(), _curObject->code, _curObject->depth); goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], _currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]); if (_curObject->openable == false) { drawText(getRandom(9) + 1059); return; } else { shouldSpeak = false; switch (_curObject->code) { case 227: if (_isCupboardOpen == false) shouldSpeak = true; break; case 274: if (_isChestOpen == false) shouldSpeak = true; break; case 415: if (_currentRoomData->doors[2].openclosed == 2) shouldSpeak = true; else { _mouse->hide(); animatePickup1(0, 1); clearScreenLayer(_curObject->depth - 1); yIndex = 0; while (yIndex < 14 && _currentRoomData->screenLayers[yIndex].depth != _curObject->depth) { yIndex++; } _currentRoomData->screenLayers[yIndex].bitmapPointer = 0; _currentRoomData->screenLayers[yIndex].bitmapSize = 0; _currentRoomData->screenLayers[yIndex].coordx = 0; _currentRoomData->screenLayers[yIndex].coordy = 0; _currentRoomData->screenLayers[yIndex].depth = 0; _currentRoomData->doors[2].openclosed = 1; _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(0, 1); _mouse->show(); for (yIndex = 0; yIndex <= 12; yIndex++) for (xIndex = 33; xIndex <= 36; xIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 43; for (xIndex = 33; xIndex <= 35; xIndex++) _currentRoomData->mouseGrid[xIndex][13] = 43; _actionCode = 0; _oldGridX = 0; _oldGridY = 0; _oldTargetZone = 0; checkMouseGrid(); return; } break; case 548: if (_currentRoomData->doors[0].openclosed == 2) shouldSpeak = true; else { _mouse->hide(); animatePickup1(1, 1); clearScreenLayer(_curObject->depth - 1); yIndex = 0; while (_currentRoomData->screenLayers[yIndex].depth != _curObject->depth && yIndex != 14) { yIndex++; } _currentRoomData->screenLayers[yIndex].bitmapPointer = 0; _currentRoomData->screenLayers[yIndex].bitmapSize = 0; _currentRoomData->screenLayers[yIndex].coordx = 0; _currentRoomData->screenLayers[yIndex].coordy = 0; _currentRoomData->screenLayers[yIndex].depth = 0; _currentRoomData->doors[0].openclosed = 1; _graphics->restoreBackground(); assembleScreen(); _graphics->drawScreen(_sceneBackground); animateOpen2(1, 1); _mouse->show(); xIndex = 30; for (yIndex = 17; yIndex <= 18; yIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 8; xIndex += 1; for (yIndex = 4; yIndex <= 20; yIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 8; xIndex += 1; for (yIndex = 0; yIndex <= 20; yIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 8; xIndex += 1; for (yIndex = 0; yIndex <= 17; yIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 8; xIndex += 1; for (yIndex = 0; yIndex <= 12; yIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 8; for (xIndex = 35; xIndex <= 39; xIndex++) for (yIndex = 0; yIndex <= 10; yIndex++) _currentRoomData->mouseGrid[xIndex][yIndex] = 8; _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); return; } break; } if (shouldSpeak) { drawText(getRandom(9) + 1059); return; } _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex = _curObject->replaceWith; _mouse->hide(); switch (_curObject->height) { case 0: { animatePickup1(_charFacingDirection, 0); updateVideo(); animateOpen2(_charFacingDirection, 0); } break; case 1: { animatePickup1(_charFacingDirection, 1); updateVideo(); animateOpen2(_charFacingDirection, 1); } break; case 2: { animatePickup1(_charFacingDirection, 2); updateVideo(); animateOpen2(_charFacingDirection, 2); } break; } _mouse->show(); for (yIndex = _curObject->ygrid1; yIndex <= _curObject->ygrid2; yIndex++) for (xIndex = _curObject->xgrid1; xIndex <= _curObject->xgrid2; xIndex++) { _currentRoomData->walkAreasGrid[xIndex][yIndex] = _curObject->walkAreasPatch[xIndex - _curObject->xgrid1][yIndex - _curObject->ygrid1]; _currentRoomData->mouseGrid[xIndex][yIndex] = _curObject->mouseGridPatch[xIndex - _curObject->xgrid1][yIndex - _curObject->ygrid1]; } for (xIndex = 0; xIndex < 15; xIndex++) if (_currentRoomData->screenLayers[xIndex].bitmapPointer == _curObject->bitmapPointer) { _currentRoomData->screenLayers[xIndex].bitmapPointer = _curObject->dropOverlay; _currentRoomData->screenLayers[xIndex].bitmapSize = _curObject->dropOverlaySize; } _actionCode = 0; } _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } void TotEngine::closeScreenObject() { byte xIndex, yIndex; bool shouldSpeak; uint sceneObject; Common::Point p = _mouse->getClickCoordsWithinGrid(); uint correctedMouseX = p.x; uint correctedMouseY = p.y; sceneObject = _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex; if (sceneObject == 0) return; readObject(sceneObject); goToObject(_currentRoomData->walkAreasGrid[((_characterPosX + kCharacterCorrectionX) / kXGridCount)][((_characterPosY + kCharacerCorrectionY) / kYGridCount)], _currentRoomData->walkAreasGrid[correctedMouseX][correctedMouseY]); if (_curObject->closeable == false) { drawText((getRandom(10) + 1068)); return; } else { shouldSpeak = false; switch (_curObject->code) { case 224: case 226: if (_isCupboardOpen == false) shouldSpeak = true; break; case 275: case 277: if (_isChestOpen == false) shouldSpeak = true; break; } if (shouldSpeak) { drawText(getRandom(10) + 1068); return; } _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[correctedMouseX][correctedMouseY]]->fileIndex = _curObject->replaceWith; _mouse->hide(); switch (_curObject->height) { case 0: { animatePickup1(_charFacingDirection, 0); updateVideo(); animateOpen2(_charFacingDirection, 0); } break; case 1: { animatePickup1(_charFacingDirection, 1); updateVideo(); animateOpen2(_charFacingDirection, 1); } break; case 2: { animatePickup1(_charFacingDirection, 2); updateVideo(); animateOpen2(_charFacingDirection, 2); } break; } _mouse->show(); for (yIndex = _curObject->ygrid1; yIndex <= _curObject->ygrid2; yIndex++) for (xIndex = _curObject->xgrid1; xIndex <= _curObject->xgrid2; xIndex++) { _currentRoomData->walkAreasGrid[xIndex][yIndex] = _curObject->walkAreasPatch[xIndex - _curObject->xgrid1][yIndex - _curObject->ygrid1]; _currentRoomData->mouseGrid[xIndex][yIndex] = _curObject->mouseGridPatch[xIndex - _curObject->xgrid1][yIndex - _curObject->ygrid1]; } for (xIndex = 0; xIndex < 15; xIndex++) if (_currentRoomData->screenLayers[xIndex].bitmapPointer == _curObject->bitmapPointer) { _currentRoomData->screenLayers[xIndex].bitmapPointer = _curObject->dropOverlay; _currentRoomData->screenLayers[xIndex].bitmapSize = _curObject->dropOverlaySize; } _actionCode = 0; } _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } void TotEngine::action() { bar(0, 140, 319, 149, 0); Common::String actionLine; switch (_actionCode) { case 0: actionLine = getActionLineText(0); break; case 1: actionLine = getActionLineText(1); break; case 2: actionLine = getActionLineText(2); break; case 3: actionLine = getActionLineText(3); break; case 4: { actionLine = getActionLineText(4); _inventoryObjectName = ""; } break; case 5: actionLine = getActionLineText(5); break; case 6: actionLine = getActionLineText(6); break; } actionLineText(actionLine); } void TotEngine::handleAction(byte invPos) { bar(0, 140, 319, 149, 0); switch (_actionCode) { case 1: { _mouse->hide(); actionLineText(getActionLineText(1) + _inventory[invPos].objectName); _mouse->show(); drawText((getRandom(10) + 1039)); _actionCode = 0; if (_cpCounter > 130) showError(274); _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 2: { _mouse->hide(); actionLineText(getActionLineText(2) + _inventory[invPos].objectName); if (_cpCounter2 > 13) showError(274); _mouse->show(); drawText((getRandom(10) + 1049)); _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 3: { _mouse->hide(); actionLineText(getActionLineText(3) + _inventory[invPos].objectName); _mouse->show(); _actionCode = 0; lookAtObject(invPos); _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 4: if (_inventoryObjectName == "") { _mouse->hide(); actionLineText(getActionLineText(4) + _inventory[invPos].objectName + getActionLineText(7)); _mouse->show(); _inventoryObjectName = _inventory[invPos].objectName; _backpackObjectCode = _inventory[invPos].code; } else { _actionCode = 0; if (_cpCounter > 25) showError(274); useInventoryObjectWithInventoryObject(_backpackObjectCode, _inventory[invPos].code); _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 5: { _mouse->hide(); actionLineText(getActionLineText(5) + _inventory[invPos].objectName); _mouse->show(); drawText(getRandom(9) + 1059); _actionCode = 0; _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; case 6: { _mouse->hide(); actionLineText(getActionLineText(6) + _inventory[invPos].objectName); _mouse->show(); drawText(getRandom(10) + 1068); _actionCode = 0; if (_cpCounter2 > 35) showError(274); _oldGridX = 0; _oldGridY = 0; checkMouseGrid(); } break; } } void TotEngine::loadInventory() { Common::File objectFile; switch (_gamePart) { case 1: objectFile.open("OBJMOCH.DAT"); break; case 2: objectFile.open("OBJMOCH.TWO"); break; } if (!objectFile.isOpen()) { debug("Object file exists? %d, open? %d, gamepart? %d", objectFile.exists("OBJMOCH.DAT"), objectFile.isOpen(), _gamePart); showError(312); } for (int i = 0; i < kInventoryIconCount; i++) { _inventoryIconBitmaps[i] = (byte *)malloc(kInventoryIconSize); objectFile.read(_inventoryIconBitmaps[i], kInventoryIconSize); } if (_cpCounter > 65) showError(274); const char *emptyName = getHardcodedTextsByCurrentLanguage()[10]; for (int i = 0; i < kInventoryIconCount; i++) { _inventory[i].bitmapIndex = 34; _inventory[i].code = 0; _inventory[i].objectName = emptyName; } objectFile.close(); } void TotEngine::obtainName(Common::String &playerName) { uint16 namePromptBGSize; byte *namePromptBG; namePromptBGSize = imagesize(84, 34, 235, 80); namePromptBG = (byte *)malloc(namePromptBGSize); _graphics->getImg(84, 34, 235, 80, namePromptBG); drawMenu(8); _screen->update(); Common::String prompt; readAlphaGraph(prompt, 8, 125, 62, 252); playerName = prompt.c_str(); _graphics->putImg(84, 34, namePromptBG); _screen->update(); free(namePromptBG); } /** * Blits srcImage over dstImage on the zeroed pixels of dstImage */ static void blit(byte *srcImage, byte *dstImage) { // Near; uint16 w = READ_LE_UINT16(dstImage) + 1; uint16 h = READ_LE_UINT16(dstImage + 2) + 1; uint size = w * h; byte *dst = dstImage + 4; byte *src = srcImage + 4; for (uint i = 0; i < size; i++) { if (dst[i] == 0) { dst[i] = src[i]; } } } /** * Grabs the action area of the screen into a pointer */ static void getScreen(byte *bg) { byte *screenBuf = (byte *)g_engine->_screen->getPixels(); Common::copy(screenBuf, screenBuf + (22400 * 2), bg + 4); } void TotEngine::scrollRight(uint horizontalPos) { int characterPos = 25 + (320 - (_characterPosX + kCharacterCorrectionX * 2)); // We scroll 4 by 4 pixels so we divide by 4 to find out the number of necessary steps uint stepCount = (320 - horizontalPos) >> 2; byte *assembledCharacterFrame = (byte *)malloc(_mainCharFrameSize); // Number of bytes to move size_t numBytes = 44796; for (uint i = 0; i < stepCount; i++) { // move everything to the left memmove(_sceneBackground + 4, _sceneBackground + 8, numBytes); horizontalPos += 4; for (int k = 0; k < 140; k++) { for (int j = 0; j < 4; j++) { _sceneBackground[320 + k * 320 + j] = _backgroundCopy[horizontalPos + k * 320 + j]; } } if (characterPos > 0) { characterPos -= 2; if (characterPos > 0 && _iframe < 15) { _iframe++; } else _iframe = 0; _characterPosX -= 2; _curCharacterAnimationFrame = _mainCharAnimation.bitmap[1][_iframe]; // We need to copy the original frame as to not replace its black background for after // the scroll ends. Original code would copy from XMS memory. Common::copy(_curCharacterAnimationFrame, _curCharacterAnimationFrame + _mainCharFrameSize, assembledCharacterFrame); // puts the original captured background back in the background for next iteration _graphics->putImageArea(_characterPosX - 2, _characterPosY, _sceneBackground, _spriteBackground); uint16 pasoframeW = READ_LE_UINT16(assembledCharacterFrame); uint16 pasoframeH = READ_LE_UINT16(assembledCharacterFrame + 2); // Grabs current area surrounding character (which might contain parts of A and B) _graphics->getImageArea(_characterPosX, _characterPosY, _characterPosX + pasoframeW, _characterPosY + pasoframeH, _sceneBackground, _spriteBackground); // blits over the character sprite, only on black pixels blit(_spriteBackground, assembledCharacterFrame); // puts it back in the background (character + piece of background) _graphics->putImageArea(_characterPosX, _characterPosY, _sceneBackground, assembledCharacterFrame); } else _characterPosX -= 4; _screen->addDirtyRect(Common::Rect(0, 0, 320, 140)); _screen->update(); _graphics->drawScreen(_sceneBackground); } free(assembledCharacterFrame); } void TotEngine::scrollLeft(uint horizontalPos) { int characterPos = 25 + _characterPosX; horizontalPos = 320 - horizontalPos; // We scroll 4 by 4 pixels so we divide by 4 to find out the number of necessary steps uint stepCount = horizontalPos >> 2; byte *assembledCharacterFrame = (byte *)malloc(_mainCharFrameSize); size_t numBytes = 44796; for (int i = stepCount; i >= 1; i--) { for (int j = numBytes; j > 0; j--) { // move the previous background to the right _sceneBackground[j + 4] = _sceneBackground[j]; } horizontalPos -= 4; for (int k = 0; k < 140; k++) { for (int j = 0; j < 4; j++) { _sceneBackground[4 + k * 320 + j] = _backgroundCopy[4 + horizontalPos + k * 320 + j]; } } if (characterPos > 0) { characterPos -= 2; if (characterPos > 0 && _iframe < 15) _iframe++; else _iframe = 0; _characterPosX += 2; _curCharacterAnimationFrame = _mainCharAnimation.bitmap[3][_iframe]; Common::copy(_curCharacterAnimationFrame, _curCharacterAnimationFrame + _mainCharFrameSize, assembledCharacterFrame); _graphics->putImageArea(_characterPosX + 2, _characterPosY, _sceneBackground, _spriteBackground); uint16 pasoframeW = READ_LE_UINT16(assembledCharacterFrame); uint16 pasoframeH = READ_LE_UINT16(assembledCharacterFrame + 2); _graphics->getImageArea(_characterPosX, _characterPosY, _characterPosX + pasoframeW, _characterPosY + pasoframeH, _sceneBackground, _spriteBackground); blit(_spriteBackground, assembledCharacterFrame); _graphics->putImageArea(_characterPosX, _characterPosY, _sceneBackground, assembledCharacterFrame); } else _characterPosX += 4; _screen->addDirtyRect(Common::Rect(0, 0, 320, 140)); _screen->update(); _graphics->drawScreen(_sceneBackground); } free(assembledCharacterFrame); } /** * Scrolling happens between two screens. We grab the area surroudning the player from screen A, * then transition to screen B. */ void TotEngine::loadScrollData(uint roomCode, bool rightScroll, uint horizontalPos, int scrollCorrection) { _graphics->restoreBackground(); // background now contains background A, backgroundCopy contains background A uint characterFrameW = READ_LE_UINT16(_curCharacterAnimationFrame); uint characterFrameH = READ_LE_UINT16(_curCharacterAnimationFrame + 2); /* Copy the area with the player from previous scren*/ _spriteBackground = (byte *)malloc(4 + (characterFrameW + 8) * (characterFrameH + 8)); _graphics->getImageArea(_characterPosX, _characterPosY, _characterPosX + characterFrameW, _characterPosY + characterFrameH, _sceneBackground, _spriteBackground); // Start screen 2 _rooms->seek(roomCode * kRoomRegSize, SEEK_SET); if (_currentRoomData) { delete _currentRoomData; } _currentRoomData = readScreenDataFile(_rooms); loadScreen(); // Background now contains background B, backgroundCopy contains background B for (int i = 0; i < 15; i++) { { RoomBitmapRegister &with = _currentRoomData->screenLayers[i]; if (with.bitmapSize > 0) loadScreenLayer(with.coordx, with.coordy, with.bitmapSize, with.bitmapPointer, with.depth); } } // assembles the screen objects into background assembleScreen(true); // background contains background B + objects, backgroundCopy contains plain background B // Copies the contents of background into backgroundCopy Common::copy(_sceneBackground, _sceneBackground + 44804, _backgroundCopy); // background contains background B + objects, backgroundCopy contains background B + objects g_engine->_graphics->_paletteAnimFrame = 0; getScreen(_sceneBackground); // background now contains full background A again, backgroundCopy contains background B + objects _graphics->drawScreen(_sceneBackground); if (rightScroll) scrollRight(horizontalPos); else scrollLeft(horizontalPos); // After scroll is done, backgroundCopy will now contain the resulting background (background B + objects) Common::copy(_backgroundCopy, _backgroundCopy + 44804, _sceneBackground); _characterPosX += scrollCorrection; assembleScreen(); _graphics->drawScreen(_sceneBackground); free(_spriteBackground); loadScreen(); _trajectory[_currentTrajectoryIndex].x = _characterPosX; _trajectory[_currentTrajectoryIndex].y = _characterPosY; } void TotEngine::sayLine( uint textRef, byte textColor, byte shadowColor, uint &responseNumber, /** Whether the text being said is part of a conversation or just descriptions */ bool isWithinConversation) { TextEntry text; uint charCounter; byte insertName, lineBreakCount, width; byte characterFacingDir; uint talkAnimIndex, bgSize, posx, posy; byte *backgroundtextht; byte lineBreaks[15]; _mouse->hide(); switch (_currentRoomData->code) { case 2: { // Leisure room posx = 10; posy = 2; width = 28; } break; case 3: { // dining room posx = 130; posy = 2; width = 30; } break; case 8: // patch case 21: // p4 posx = 10; posy = 100; width = 50; break; case 10: { // well posx = 10; posy = 2; width = 40; } break; case 11: { // pond posx = 172; posy = 2; width = 26; } break; case 16: { // dorm. 1 posx = 140; posy = 2; width = 30; } break; case 17: { // dorm. 2 posx = 10; posy = 2; width = 30; } break; case 23: { // fountain posx = 10; posy = 2; width = 19; } break; case 25: { // catacombs posx = 10; posy = 2; width = 22; } break; case 28: { // storage room posx = 180; posy = 60; width = 24; } break; case 31: { // prison posx = 10; posy = 2; width = 25; } break; default: { // any other room posx = 10; posy = 2; width = 50; } } _verbFile.seek(textRef * kVerbRegSize); do { text = readTextRegister(); insertName = 0; for (uint i = 0; i < text.text.size(); i++) { text.text.setChar(_decryptionKey[i] ^ text.text[i], i); if (text.text[i] == '@') insertName = i; } if (insertName > 0) { text.text.deleteChar(insertName); text.text.insertString(_characterName, insertName); } if (text.text.size() < width) { bgSize = imagesize(posx - 1, posy - 1, posx + (text.text.size() * 8) + 2, posy + 13); backgroundtextht = (byte *)malloc(bgSize); _graphics->getImg(posx - 1, posy - 1, posx + (text.text.size() * 8) + 2, posy + 13, backgroundtextht); littText(posx - 1, posy, text.text, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx + 1, posy, text.text, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx, posy - 1, text.text, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx, posy + 1, text.text, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx, posy, text.text, textColor); _screen->update(); delay(kEnforcedTextAnimDelay); } else { charCounter = 0; lineBreakCount = 0; lineBreaks[0] = 0; // Breaks text lines on the last space when reaching the [anchoht] do { charCounter += width; lineBreakCount += 1; do { charCounter -= 1; } while (text.text[charCounter] != ' '); lineBreaks[lineBreakCount] = charCounter + 1; } while (((int)charCounter + 1) <= ((int)text.text.size() - (int)width)); lineBreakCount += 1; lineBreaks[lineBreakCount] = text.text.size(); // Grab patch of background behind where the text will be, to paste it back later bgSize = imagesize(posx - 1, posy - 1, posx + (width * 8) + 2, posy + lineBreakCount * 13); backgroundtextht = (byte *)malloc(bgSize); _graphics->getImg(posx - 1, posy - 1, posx + (width * 8) + 2, posy + lineBreakCount * 13, backgroundtextht); for (int i = 1; i <= lineBreakCount; i++) { Common::String lineString = Common::String(text.text.c_str() + lineBreaks[i - 1], text.text.c_str() + lineBreaks[i]); littText(posx + 1, posy + ((i - 1) * 11), lineString, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx - 1, posy + ((i - 1) * 11), lineString, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx, posy + ((i - 1) * 11) + 1, lineString, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx, posy + ((i - 1) * 11) - 1, lineString, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); littText(posx, posy + ((i - 1) * 11), lineString, textColor); _screen->update(); delay(kEnforcedTextAnimDelay); } } talkAnimIndex = 0; bool mouseClicked = false; // Plays talk cycle if needed do { _chrono->updateChrono(); g_engine->_events->pollEvent(); if (g_engine->_events->_leftMouseButton || g_engine->_events->_rightMouseButton) { mouseClicked = true; } if (_chrono->_gameTick) { _chrono->_gameTick = false; if (_chrono->_gameTickHalfSpeed) { if (isWithinConversation) { talkAnimIndex += 1; if (textColor == 255) { _iframe2 = 0; if (_iframe >= 15) _iframe = 0; else _iframe++; } else { _iframe = 0; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; } // Talk sprites are always put in facing direction 0 characterFacingDir = _charFacingDirection; _charFacingDirection = 0; sprites(true); _charFacingDirection = characterFacingDir; } else { if (_currentSecondaryTrajectoryIndex >= _currentRoomData->secondaryTrajectoryLength) _currentSecondaryTrajectoryIndex = 1; else _currentSecondaryTrajectoryIndex += 1; _secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x; _secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y; _secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1]; if (_iframe2 >= _secondaryAnimationFrameCount - 1) _iframe2 = 0; else _iframe2++; sprites(false); } } _graphics->advancePaletteAnim(); } _screen->update(); g_system->delayMillis(10); } while (talkAnimIndex <= (text.text.size() * 4) && !mouseClicked && !shouldQuit()); _graphics->putImg(posx - 1, posy - 1, backgroundtextht); free(backgroundtextht); g_system->delayMillis(10); } while (text.continued && !shouldQuit()); responseNumber = text.response; _mouse->show(); } void TotEngine::initScreenPointers() { _screenSize = 65520; _sceneBackground = (byte *)malloc(_screenSize); _backgroundCopy = (byte *)malloc(_screenSize); } void TotEngine::loadAnimationForDirection(Common::SeekableReadStream *stream, int direction) { uint size = _secondaryAnimFrameSize; for (int j = 0; j < _secondaryAnimationFrameCount; j++) { if (_secondaryAnimation.bitmap[direction][j]) { free(_secondaryAnimation.bitmap[direction][j]); } _secondaryAnimation.bitmap[direction][j] = (byte *)malloc(size); stream->read(_secondaryAnimation.bitmap[direction][j], size); Common::copy(_secondaryAnimation.bitmap[direction][j], _secondaryAnimation.bitmap[direction][j] + size, g_engine->_curSecondaryAnimationFrame); } } void TotEngine::loadAnimation(const Common::String &animationName) { Common::File animFile; if (animationName == "PETER") _isPeterCoughing = true; else _isPeterCoughing = false; _isSecondaryAnimationEnabled = true; if (!animFile.open(Common::Path(animationName + ".DAT"))) { showError(265); } _secondaryAnimFrameSize = animFile.readUint16LE(); _secondaryAnimationFrameCount = animFile.readByte(); _secondaryAnimDirCount = animFile.readByte(); newSecondaryAnimationFrame(); if (_secondaryAnimDirCount != 0) { _secondaryAnimationFrameCount = _secondaryAnimationFrameCount / 4; for (int i = 0; i < 4; i++) { loadAnimationForDirection(&animFile, i); } } else { loadAnimationForDirection(&animFile, 0); } animFile.close(); _secondaryAnimWidth = READ_LE_UINT16(_secondaryAnimation.bitmap[0][1]) + 1; _secondaryAnimHeight = READ_LE_UINT16(_secondaryAnimation.bitmap[0][1] + 2) + 1; setRoomTrajectories(_secondaryAnimHeight, _secondaryAnimWidth, SET_WITH_ANIM, false); readObject(_currentRoomData->secondaryAnimDirections[299]); _maxXGrid = (_curObject->xgrid2 - _curObject->xgrid1 + 1); _maxYGrid = (_curObject->ygrid2 - _curObject->ygrid1 + 1); _oldposx = _curObject->xgrid1 + 1; _oldposy = _curObject->ygrid1 + 1; for (int i = 0; i < 10; i++) for (int j = 0; j < 10; j++) { _maskGridSecondaryAnim[i][j] = 0; _maskMouseSecondaryAnim[i][j] = 0; _movementGridForSecondaryAnim[i][j] = 0; _mouseGridForSecondaryAnim[i][j] = 0; } for (int i = 0; i < _maxXGrid; i++) for (int j = 0; j < _maxYGrid; j++) { _maskGridSecondaryAnim[i][j] = _curObject->walkAreasPatch[i][j]; _maskMouseSecondaryAnim[i][j] = _curObject->mouseGridPatch[i][j]; _movementGridForSecondaryAnim[i][j] = _currentRoomData->walkAreasGrid[_oldposx + i][_oldposy + j]; _mouseGridForSecondaryAnim[i][j] = _currentRoomData->mouseGrid[_oldposx + i][_oldposy + j]; } _iframe2 = 0; } void TotEngine::updateAltScreen(byte otherScreenNumber) { uint i22; uint i11; if (_currentRoomData) { byte currentScreen = _currentRoomData->code; setRoomTrajectories(_secondaryAnimHeight, _secondaryAnimWidth, RESTORE); // Save current room saveRoomData(_currentRoomData, _rooms); // Load other screen _rooms->seek(otherScreenNumber * kRoomRegSize, SEEK_SET); delete _currentRoomData; _currentRoomData = readScreenDataFile(_rooms); switch (otherScreenNumber) { case 20: { switch (_niche[0][_niche[0][3]]) { case 0: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(4); _currentRoomData->screenLayers[1].bitmapPointer = 1190768; } break; case 561: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(5); _currentRoomData->screenLayers[1].bitmapPointer = 1182652; } break; case 563: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(6); _currentRoomData->screenLayers[1].bitmapPointer = 1186044; } break; case 615: { _currentRoomData->screenObjectIndex[9]->objectName = getObjectName(7); _currentRoomData->screenLayers[1].bitmapPointer = 1181760; } break; } _currentRoomData->screenLayers[1].bitmapSize = 892; _currentRoomData->screenLayers[1].coordx = 66; _currentRoomData->screenLayers[1].coordy = 35; _currentRoomData->screenLayers[1].depth = 1; } break; case 24: { switch (_niche[1][_niche[1][3]]) { case 0: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(4); _currentRoomData->screenLayers[0].bitmapPointer = 1399610; } break; case 561: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(5); _currentRoomData->screenLayers[0].bitmapPointer = 1381982; } break; case 615: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(7); _currentRoomData->screenLayers[0].bitmapPointer = 1381090; } break; case 622: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(8); _currentRoomData->screenLayers[0].bitmapPointer = 1400502; } break; case 623: { _currentRoomData->screenObjectIndex[8]->objectName = getObjectName(9); _currentRoomData->screenLayers[0].bitmapPointer = 1398718; } break; } _currentRoomData->screenLayers[0].bitmapSize = 892; _currentRoomData->screenLayers[0].coordx = 217; _currentRoomData->screenLayers[0].coordy = 48; _currentRoomData->screenLayers[0].depth = 1; } break; case 31: { for (i11 = 23; i11 <= 25; i11++) for (i22 = 4; i22 <= 9; i22++) _currentRoomData->mouseGrid[i11][i22] = 4; for (i11 = 23; i11 <= 25; i11++) for (i22 = 10; i22 <= 11; i22++) _currentRoomData->mouseGrid[i11][i22] = 3; _currentRoomData->screenLayers[0].bitmapSize = 0; _currentRoomData->screenLayers[0].bitmapPointer = 0; _currentRoomData->screenLayers[0].coordx = 0; _currentRoomData->screenLayers[0].coordy = 0; _currentRoomData->screenLayers[0].depth = 0; } break; } // Save other screen saveRoomData(_currentRoomData, _rooms); // Restore current room again _rooms->seek(currentScreen * kRoomRegSize, SEEK_SET); if (_currentRoomData) { delete _currentRoomData; } _currentRoomData = readScreenDataFile(_rooms); setRoomTrajectories(_secondaryAnimHeight, _secondaryAnimWidth, SET_WITH_ANIM); } } void TotEngine::loadTV() { Common::File fichct; if (!fichct.open("PALETAS.DAT")) { showError(310); } fichct.seek(_currentRoomData->palettePointer + 603); fichct.read(g_engine->_graphics->_palAnimSlice, 144); for (int i = 0; i <= 48; i++) { g_engine->_graphics->_palAnimSlice[i * 3 + 0] <<= 2; g_engine->_graphics->_palAnimSlice[i * 3 + 1] <<= 2; g_engine->_graphics->_palAnimSlice[i * 3 + 2] <<= 2; } fichct.close(); for (int ix = 195; ix <= 200; ix++) { g_engine->_graphics->_pal[ix * 3 + 0] = 2 << 2; g_engine->_graphics->_pal[ix * 3 + 1] = 2 << 2; g_engine->_graphics->_pal[ix * 3 + 2] = 2 << 2; setRGBPalette(ix, 2, 2, 2); } } void TotEngine::loadScreen() { Common::File paletteFile; Palette palcp; _screenSize = _currentRoomData->roomImageSize; readBitmap(_currentRoomData->roomImagePointer, _sceneBackground, _screenSize, 316); Common::copy(_sceneBackground, _sceneBackground + _screenSize, _backgroundCopy); switch (_gamePart) { case 1: { if (!paletteFile.open("PALETAS.DAT")) { showError(310); } paletteFile.seek(_currentRoomData->palettePointer); paletteFile.read(palcp, 603); if (_currentRoomData->paletteAnimationFlag) { paletteFile.read(g_engine->_graphics->_palAnimSlice, 144); for (int i = 0; i <= 48; i++) { g_engine->_graphics->_palAnimSlice[i * 3 + 0] <<= 2; g_engine->_graphics->_palAnimSlice[i * 3 + 1] <<= 2; g_engine->_graphics->_palAnimSlice[i * 3 + 2] <<= 2; } } paletteFile.close(); for (int i = 1; i <= 200; i++) { g_engine->_graphics->_pal[i * 3 + 0] = palcp[i * 3 + 0] << 2; g_engine->_graphics->_pal[i * 3 + 1] = palcp[i * 3 + 1] << 2; g_engine->_graphics->_pal[i * 3 + 2] = palcp[i * 3 + 2] << 2; } _graphics->setPalette(g_engine->_graphics->_pal, 0, 201); } break; case 2: { _graphics->loadPaletteFromFile("SEGUNDA"); _currentRoomData->paletteAnimationFlag = true; } break; } } void TotEngine::clearScreenLayers() { for (int i = 0; i < kNumScreenOverlays; i++) { clearScreenLayer(i); } } void TotEngine::clearAnimation() { if (_isSecondaryAnimationEnabled) { _isSecondaryAnimationEnabled = false; if (_curSecondaryAnimationFrame != nullptr) { free(_curSecondaryAnimationFrame); } _curSecondaryAnimationFrame = nullptr; for (int j = 0; j < _secondaryAnimDirCount; j++) { for (int i = 0; i < _secondaryAnimationFrameCount; i++) { if (_secondaryAnimation.bitmap[j][i] != nullptr) { free(_secondaryAnimation.bitmap[j][i]); } _secondaryAnimation.bitmap[j][i] = nullptr; } } } } void TotEngine::freeInventory() { for (int i = 0; i < kInventoryIconCount; i++) { free(_inventoryIconBitmaps[i]); } } void TotEngine::loadScreenLayerWithDepth(uint coordx, uint coordy, uint bitmapSize, int32 bitmapIndex, uint depth) { if (g_engine->_screenLayers[depth]) { free(g_engine->_screenLayers[depth]); } _screenLayers[depth] = (byte *)malloc(bitmapSize); readBitmap(bitmapIndex, _screenLayers[depth], bitmapSize, 319); uint16 w, h; w = READ_LE_UINT16(_screenLayers[depth]); h = READ_LE_UINT16(_screenLayers[depth] + 2); _depthMap[depth].posx = coordx; _depthMap[depth].posy = coordy; _depthMap[depth].posx2 = coordx + w + 1; _depthMap[depth].posy2 = coordy + h + 1; } void TotEngine::loadScreenLayer(uint coordx, uint coordy, uint bitmapSize, int32 bitmapIndex, uint depth) { loadScreenLayerWithDepth(coordx, coordy, bitmapSize, bitmapIndex, depth - 1); } void TotEngine::updateInventory(byte index) { for (int i = index; i < (kInventoryIconCount - 1); i++) { _inventory[i].bitmapIndex = _inventory[i + 1].bitmapIndex; _inventory[i].code = _inventory[i + 1].code; _inventory[i].objectName = _inventory[i + 1].objectName; } } void TotEngine::drawLookAtItem(RoomObjectListEntry obj) { _mouse->hide(); bar(0, 140, 319, 149, 0); actionLineText(getActionLineText(3) + obj.objectName); _mouse->show(); } void TotEngine::putIcon(uint iconPosX, uint iconPosY, uint iconNum) { // substract 1 to account for 1-based indices _graphics->putImg(iconPosX, iconPosY, _inventoryIconBitmaps[_inventory[iconNum].bitmapIndex - 1]); } void TotEngine::drawInventory() { putIcon(34, 169, _inventoryPosition); putIcon(77, 169, _inventoryPosition + 1); putIcon(120, 169, _inventoryPosition + 2); putIcon(163, 169, _inventoryPosition + 3); putIcon(206, 169, _inventoryPosition + 4); putIcon(249, 169, _inventoryPosition + 5); } void lightUpLeft() { line(10, 173, 29, 173, 255); line(10, 173, 10, 189, 255); line(30, 174, 30, 190, 249); line(30, 190, 11, 190, 249); } void turnOffLeft() { line(10, 173, 29, 173, 249); line(10, 173, 10, 189, 249); line(30, 174, 30, 190, 255); line(30, 190, 11, 190, 255); } void lightUpRight() { line(291, 173, 310, 173, 255); line(291, 173, 291, 189, 255); line(311, 174, 311, 190, 249); line(311, 190, 292, 190, 249); } void turnOffRight() { line(291, 173, 310, 173, 249); line(291, 173, 291, 189, 249); line(311, 174, 311, 190, 255); line(311, 190, 292, 190, 255); } void TotEngine::drawInventory(byte dir, byte max) { switch (dir) { case 0: if (_inventoryPosition > 0) { _inventoryPosition -= 1; drawInventory(); } break; case 1: if (_inventoryPosition < (max - 6)) { _inventoryPosition += 1; drawInventory(); } break; } _mouse->hide(); if (_inventoryPosition > 0) lightUpLeft(); else turnOffLeft(); if (_inventory[_inventoryPosition + 6].code > 0) lightUpRight(); else turnOffRight(); _mouse->show(); if (_cpCounter > 145) showError(274); } void TotEngine::drawInventoryMask() { buttonBorder(0, 140, 319, 149, 0, 0, 0, 0, 0); for (int i = 1; i <= 25; i++) buttonBorder(0, (175 - i), 319, (174 + i), 251, 251, 251, 251, 0); drawMenu(1); if (_inventoryPosition > 1) lightUpLeft(); else turnOffLeft(); if (_inventory[_inventoryPosition + 6].code > 0) lightUpRight(); else turnOffRight(); } byte *getArrow(uint x, uint y) { Common::File menuFile; if (!menuFile.open("MENUS.DAT")) { showError(258); } int32 menuOffset = isLanguageSpanish() ? menuOffsets_ES[0][0] : menuOffsets_EN[0][0]; uint w = 20; uint h = 18; uint size = 4 + w * h; byte *bitmap = (byte *)malloc(size); WRITE_LE_UINT16(bitmap, w - 1); WRITE_LE_UINT16(bitmap + 2, h - 1); menuFile.seek(menuOffset); uint originalW = menuFile.readUint16LE() + 1; for(uint i = 0; i < h; i++) { menuFile.seek(menuOffset + 4 + + (y + i) * originalW + x); menuFile.read(bitmap + 4 + i * w, w); } menuFile.close(); return bitmap; } void TotEngine::drawLeftArrow(uint x, uint y) { byte *bitmap = getArrow(10, 23); _graphics->putImg(x, y, bitmap); free(bitmap); } void TotEngine::drawRightArrow(uint x, uint y) { byte *bitmap = getArrow(291, 23); _graphics->putImg(x, y, bitmap); free(bitmap); } void TotEngine::drawMenu(byte menuNumber) { byte *bitmap; uint menuSize; byte xmenu = 0, ymenu = 0; int32 menuOffset; Common::File menuFile; if (!menuFile.open("MENUS.DAT")) { showError(258); } menuOffset = isLanguageSpanish() ? menuOffsets_ES[menuNumber - 1][0] : menuOffsets_EN[menuNumber - 1][0]; menuSize = isLanguageSpanish() ? menuOffsets_ES[menuNumber - 1][1] : menuOffsets_EN[menuNumber - 1][1]; switch (menuNumber) { case 1: { xmenu = 0; ymenu = 150; } break; case 2: case 3: case 6: xmenu = 50; ymenu = 10; break; case 4: { if (_cpCounter2 > 20) showError(274); xmenu = 50; ymenu = 10; } break; case 5: { if (_cpCounter > 23) showError(274); xmenu = 0; ymenu = 150; } break; case 7: { xmenu = 58; ymenu = 48; } break; case 8: { xmenu = 84; ymenu = 34; } break; } bitmap = (byte *)malloc(menuSize); menuFile.seek(menuOffset); menuFile.read(bitmap, menuSize); _graphics->putImg(xmenu, ymenu, bitmap); free(bitmap); menuFile.close(); } static void loadDiploma(Common::String &photoName, Common::String &key) { Palette auxPal; byte *screen; uint size; byte *stamp; Common::File dipFile; if (!dipFile.open("DIPLOMA.PAN")) { showError(318); } dipFile.read(auxPal, 768); screen = (byte *)malloc(64000); dipFile.read(screen, 64000); dipFile.close(); if (!dipFile.open(Common::Path("DIPLOMA/SELLO.BMP"))) showError(271); stamp = (byte *)malloc(2054); dipFile.read(stamp, 2054); dipFile.close(); g_engine->_graphics->drawFullScreen(screen); free(screen); if (dipFile.open(Common::Path("DIPLOMA/" + photoName + ".FOT"))) { size = dipFile.size() - 768; screen = (byte *)malloc(size); dipFile.read(g_engine->_graphics->_pal, 768); dipFile.read(screen, size); dipFile.close(); g_engine->_graphics->putShape(10, 20, screen); free(screen); } for (int i = 16; i <= 255; i++) { auxPal[i * 3 + 0] = g_engine->_graphics->_pal[i * 3 + 0]; auxPal[i * 3 + 1] = g_engine->_graphics->_pal[i * 3 + 1]; auxPal[i * 3 + 2] = g_engine->_graphics->_pal[i * 3 + 2]; } g_engine->_graphics->copyPalette(auxPal, g_engine->_graphics->_pal); g_engine->_graphics->fixPalette(g_engine->_graphics->_pal, 768); g_engine->_graphics->setPalette(g_engine->_graphics->_pal); g_engine->_screen->markAllDirty(); g_engine->_screen->update(); char *passArray = new char[10]; for (int i = 0; i < 10; i++) passArray[i] = (char)(getRandom(10) + 48); key.append(passArray, passArray + 10); const char *const *messages = getFullScreenMessagesByCurrentLanguage(); biosText(91, 16, messages[49] + key, 255); biosText(90, 15, messages[49] + key, 13); biosText(81, 61, messages[50], 0); biosText(61, 81, messages[51], 0); if(isLanguageSpanish()) { biosText(31, 101, messages[52] + g_engine->_characterName, 0); } else { biosText(31, 101, messages[52], 0); biosText(151, 101, g_engine->_characterName, 0); } biosText(31, 121, messages[53], 0); biosText(31, 141, messages[54], 0); biosText(31, 161, messages[55], 0); biosText(80, 60, messages[50], 15); biosText(60, 80, messages[51], 15); biosText(30, 100, messages[52], 15); biosText(150, 100, g_engine->_characterName, 13); biosText(30, 120, messages[53], 15); biosText(30, 140, messages[54], 15); biosText(30, 160, messages[55], 15); delay(1500); g_engine->_sound->playVoc("PORTAZO", 434988, 932); g_engine->_graphics->putShape(270, 159, stamp); delete[] passArray; free(stamp); } static void saveDiploma(Common::String &photoName, Common::String &key) { Common::String name; if (photoName != "") name = "tot-diploma-" + photoName + ".png"; else name = "tot-diploma-default.png"; Common::OutSaveFile *thumbnail = g_engine->getSaveFileManager()->openForSaving(name); Graphics::Surface *surface = g_system->lockScreen(); assert(surface); Image::writePNG(*thumbnail, *surface, g_engine->_graphics->getPalette()); g_system->unlockScreen(); thumbnail->finalize(); delete thumbnail; } void TotEngine::generateDiploma(Common::String &photoName) { Common::String key; _mouse->hide(); photoName.toUppercase(); _graphics->totalFadeOut(0); loadDiploma(photoName, key); do { _screen->update(); g_engine->_events->pollEvent(); g_system->delayMillis(10); } while (!g_engine->_events->_keyPressed && !shouldQuit()); saveDiploma(photoName, key); _mouse->show(); } void TotEngine::checkMouseGrid() { uint xGrid, yGrid; Common::String invObject; if (_cpCounter2 > 120) showError(274); if (_mouse->mouseY <= 131) { xGrid = _mouse->getMouseCoordsWithinGrid().x; yGrid = _mouse->getMouseCoordsWithinGrid().y; if (_currentRoomData->mouseGrid[xGrid][yGrid] != _currentRoomData->mouseGrid[_oldGridX][_oldGridY] || _oldInventoryObjectName != "") { bar(0, 140, 319, 149, 0); Common::String actionLine; switch (_actionCode) { case 0: actionLine = getActionLineText(0) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; case 1: actionLine = getActionLineText(1) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; case 2: actionLine = getActionLineText(2) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; case 3: actionLine = getActionLineText(3) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; case 4: if (_inventoryObjectName != "") actionLine = getActionLineText(4) + _inventoryObjectName + getActionLineText(7) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; else actionLine = getActionLineText(4) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; case 5: actionLine = getActionLineText(5) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; case 6: actionLine = getActionLineText(6) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; break; default: actionLine = getActionLineText(0) + _currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[xGrid][yGrid]]->objectName; } actionLineText(actionLine); _mouse->show(); _oldGridX = xGrid; _oldGridY = yGrid; } _oldActionCode = 253; _oldInventoryObjectName = ""; } else if (_mouse->mouseY <= 165) { if (_actionCode != _oldActionCode) { bar(0, 140, 319, 149, 0); Common::String actionLine; switch (_actionCode) { case 0: actionLine = getActionLineText(0); break; case 1: actionLine = getActionLineText(1); break; case 2: actionLine = getActionLineText(2); break; case 3: actionLine = getActionLineText(3); break; case 4: if (_inventoryObjectName != "") actionLine = getActionLineText(4) + _inventoryObjectName + getActionLineText(7); else actionLine = getActionLineText(4); break; case 5: actionLine = getActionLineText(5); break; case 6: actionLine = getActionLineText(6); break; } actionLineText(actionLine); _mouse->show(); _oldActionCode = _actionCode; _oldInventoryObjectName = ""; _oldGridX = 0; _oldGridY = 0; } } else if (_mouse->mouseY <= 199) { if (_mouse->mouseX >= 26 && _mouse->mouseX <= 65) { invObject = _inventory[_inventoryPosition].objectName; } else if (_mouse->mouseX >= 70 && _mouse->mouseX <= 108) { invObject = _inventory[_inventoryPosition + 1].objectName; } else if (_mouse->mouseX >= 113 && _mouse->mouseX <= 151) { invObject = _inventory[_inventoryPosition + 2].objectName; } else if (_mouse->mouseX >= 156 && _mouse->mouseX <= 194) { invObject = _inventory[_inventoryPosition + 3].objectName; } else if (_mouse->mouseX >= 199 && _mouse->mouseX <= 237) { invObject = _inventory[_inventoryPosition + 4].objectName; } else if (_mouse->mouseX >= 242 && _mouse->mouseX <= 280) { invObject = _inventory[_inventoryPosition + 5].objectName; } else { invObject = ' '; } if (invObject != _oldInventoryObjectName || _oldGridX != 0) { bar(0, 140, 319, 149, 0); Common::String actionLine; switch (_actionCode) { case 1: actionLine = getActionLineText(1) + invObject; break; case 2: actionLine = getActionLineText(2) + invObject; break; case 3: actionLine = getActionLineText(3) + invObject; break; case 4: if (_inventoryObjectName == "") actionLine = getActionLineText(4) + invObject; else actionLine = getActionLineText(4) + _inventoryObjectName + getActionLineText(7) + invObject; break; case 5: actionLine = getActionLineText(5) + invObject; break; case 6: actionLine = getActionLineText(6) + invObject; break; default: euroText(160, 144, invObject, 255, Graphics::kTextAlignCenter); } actionLineText(actionLine); _mouse->show(); _oldInventoryObjectName = invObject; } _oldActionCode = 255; _oldGridX = 0; _oldGridY = 0; } } void TotEngine::readAlphaGraph(Common::String &output, int length, int posx, int posy, byte barColor) { int pun = 1; bar(posx, posy - 2, posx + length * 8, posy + 8, barColor); biosText(posx, posy, "_", 0); Common::Event e; bool done = false; g_system->getEventManager()->getKeymapper()->setEnabled(false); while (!done && !shouldQuit()) { while (g_system->getEventManager()->pollEvent(e)) { if (e.type == Common::EVENT_KEYDOWN) { int keycode = e.kbd.keycode; int asciiCode = e.kbd.ascii; // ENTER key if (keycode == Common::KEYCODE_RETURN || keycode == Common::KEYCODE_KP_ENTER) { if (output.size() > 0) { done = true; continue; } } // Max 8 chars if (pun > length && asciiCode != 8) { _sound->beep(750, 60); bar((posx + (output.size()) * 8), (posy - 2), (posx + (output.size() + 1) * 8), (posy + 8), barColor); } else if (asciiCode == 8 && pun > 1) { // delete output = output.substr(0, output.size() - 1); bar(posx, (posy - 2), (posx + length * 8), (posy + 8), barColor); biosText(posx, posy, output.c_str(), 0); biosText((posx + (output.size()) * 8), posy, "_", 0); pun -= 1; } else if ( (asciiCode < 97 || asciiCode > 122) && (asciiCode < 65 || asciiCode > 90) && (asciiCode < 32 || asciiCode > 57) && (asciiCode < 164 || asciiCode > 165)) { _sound->beep(1200, 60); } else { pun += 1; output = output + (char)e.kbd.ascii; bar(posx, (posy - 2), (posx + length * 8), (posy + 8), barColor); biosText(posx, posy, output.c_str(), 0); biosText((posx + (output.size()) * 8), posy, "_", 0); } } } g_system->delayMillis(10); _screen->update(); } g_system->getEventManager()->getKeymapper()->setEnabled(true); } bool getEvent(Common::Event &e, Common::Event &firstEvent) { if (firstEvent.type != Common::EVENT_INVALID) { e = firstEvent; firstEvent.type = Common::EVENT_INVALID; return true; } return g_system->getEventManager()->pollEvent(e); } void TotEngine::readAlphaGraphSmall( Common::String &output, int length, int posx, int posy, byte barColor, byte textColor, Common::Event event) { int pun = 1; bool removeCaret = false; g_system->getEventManager()->getKeymapper()->setEnabled(false); output = ""; bar(posx, posy + 2, posx + length * 6, posy + 9, barColor); euroText(posx, posy, "-", textColor); Common::Event e; bool done = false; while (!done && !shouldQuit()) { while (getEvent(e, event)) { if (e.type == Common::EVENT_KEYDOWN) { int keycode = e.kbd.keycode; int asciiCode = e.kbd.ascii; // ENTER key if (keycode == Common::KEYCODE_RETURN || keycode == Common::KEYCODE_KP_ENTER) { if (output.size() > 0) { done = true; removeCaret = true; continue; } } if (pun > length && asciiCode != 8) { _sound->beep(750, 60); bar((posx + (output.size()) * 6), (posy + 2), (posx + (output.size() + 1) * 6), (posy + 10), barColor); } else if (asciiCode == 8 && pun > 1) { output = output.substr(0, output.size() - 1); bar(posx, (posy + 2), (posx + length * 6), (posy + 10), barColor); euroText(posx, posy, output, textColor); euroText(posx + _graphics->euroTextWidth(output), posy, "-", textColor); pun -= 1; removeCaret = true; } else if ( (asciiCode < 97 || asciiCode > 122) && (asciiCode < 65 || asciiCode > 90) && (asciiCode < 32 || asciiCode > 57) && (asciiCode < 164 || asciiCode > 165)) { _sound->beep(1200, 60); removeCaret = false; } else { pun += 1; output = output + (char)e.kbd.ascii; bar(posx, (posy + 2), (posx + length * 6), (posy + 9), barColor); euroText(posx, posy, output, textColor); euroText(posx + _graphics->euroTextWidth(output), posy, "-", textColor); removeCaret = true; } } } g_system->delayMillis(10); _screen->update(); } if (removeCaret) { bar(posx + _graphics->euroTextWidth(output), posy + 2, (posx + _graphics->euroTextWidth(output)) + 6, posy + 9, barColor); } g_system->getEventManager()->getKeymapper()->setEnabled(true); } void TotEngine::displayObjectDescription(const Common::String &textString) { uint xpos = 60; uint ypos = 15; byte maxWidth = 33; byte textColor = 255; byte shadowColor = 0; uint ihc; byte lineCounter; byte newLineMatrix[10]; if (textString.size() < maxWidth) { euroText((xpos + 1), (ypos + 1), textString, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); euroText(xpos, ypos, textString, textColor); _screen->update(); delay(kEnforcedTextAnimDelay); } else { ihc = 0; lineCounter = 0; newLineMatrix[0] = 0; do { ihc += maxWidth + 1; lineCounter += 1; do { ihc -= 1; } while (textString[ihc] != ' '); newLineMatrix[lineCounter] = ihc + 1; } while (ihc + 1 <= textString.size() - maxWidth); lineCounter += 1; newLineMatrix[lineCounter] = textString.size(); for (byte line = 1; line <= lineCounter; line++) { Common::String lineString = textString.substr(newLineMatrix[line - 1], newLineMatrix[line] - newLineMatrix[line - 1]); euroText((xpos + 1), (ypos + ((line - 1) * 11) + 1), lineString, shadowColor); _screen->update(); delay(kEnforcedTextAnimDelay); euroText(xpos, (ypos + ((line - 1) * 11)), lineString, textColor); _screen->update(); delay(kEnforcedTextAnimDelay); } } } void TotEngine::buttonBorder(uint x1, uint y1, uint x2, uint y2, byte color1, byte color2, byte color3, byte color4, byte color5) { bar(x1, y1, x2, y2, color4); line(x1, y1, x1, y2, color1); line(x1, y1, x2, y1, color1); line(x2, y1, x2, y2, color2); line(x2, y2, x1, y2, color2); putpixel(x2, y1, color3); putpixel(x1, y2, color3); _screen->addDirtyRect(Common::Rect(x1, y1, x2, y2)); _screen->update(); } static void buttonPress(uint xx1, uint yy1, uint xx2, uint yy2, bool pressed) { g_engine->_mouse->hide(); uint color = 0; if (pressed) color = 249; else color = 255; line(xx1, yy1, (xx2 - 1), yy1, color); line(xx1, yy1, xx1, (yy2 - 1), color); if (pressed) color = 255; else color = 249; line((xx1 + 1), yy2, xx2, yy2, color); line(xx2, (yy1 + 1), xx2, yy2, color); g_engine->_screen->addDirtyRect(Common::Rect(xx1, yy1, xx2, yy2)); g_engine->_screen->update(); g_engine->_mouse->show(); delay(100); } void TotEngine::copyProtection() { if (!ConfMan.getBool("copy_protection") || isDemo()) { return; } const char *message = isLanguageSpanish() ? hardcodedTexts_ES[12] : hardcodedTexts_EN[12]; int beepDelay = 100; int chunkSize = 4; uint inputPassword = 0; byte cursorPos = 0, attempts = 0; int32 diskPass = 0, protXor1 = 0, protXor2 = 0; Common::File protectionFile; if (!protectionFile.open("MCGA.DRV")) { showError(260); } Common::String inputString = " "; byte numRow = getRandom(95) + 1; byte numColumn = getRandom(38) + 1; protectionFile.seek(1 * chunkSize); protXor1 = protectionFile.readUint32LE(); protectionFile.seek((((numRow - 1) * 38) + numColumn + 1) * chunkSize); protXor2 = protectionFile.readUint32LE(); inputPassword = 0; diskPass = protectionFile.readUint32LE(); uint correctPassword = ((diskPass ^ protXor1) - protXor2); bool exitDialog = false; protectionFile.close(); uint oldMouseX = _mouse->mouseX; uint oldMouseY = _mouse->mouseY; uint oldMouseMaskIndex = _mouse->mouseMaskIndex; _mouse->hide(); uint bgSize = imagesize(50, 10, 270, 120); byte *bgPointer = (byte *)malloc(bgSize); _graphics->getImg(50, 10, 270, 120, bgPointer); _mouse->mouseX = 150; _mouse->mouseY = 60; _mouse->mouseMaskIndex = 1; _mouse->setMouseArea(Common::Rect(55, 13, 250, 105)); for (int i = 1; i <= 6; i++) buttonBorder((120 - (i * 10)), (80 - (i * 10)), (200 + (i * 10)), (60 + (i * 10)), 251, 251, 251, 251, 0); drawMenu(6); euroText(65, 15, Common::String::format(message, numRow, numColumn), 255); cursorPos = 0; attempts = 0; _mouse->warpMouse(1, _mouse->mouseX, _mouse->mouseY); _screen->markAllDirty(); _screen->update(); Common::Event e; do { bool mouseClicked = false; do { _chrono->updateChrono(); if (_chrono->_gameTick) { _mouse->animateMouseIfNeeded(); _chrono->_gameTick = false; } while (g_system->getEventManager()->pollEvent(e)) { if (isMouseEvent(e)) { _mouse->warpMouse(e.mouse); _mouse->mouseX = e.mouse.x; _mouse->mouseY = e.mouse.y; } if (e.type == Common::EVENT_LBUTTONUP) { _mouse->mouseClickX = e.mouse.x; _mouse->mouseClickY = e.mouse.y; mouseClicked = true; } } _screen->markAllDirty(); _screen->update(); g_system->delayMillis(10); } while (!mouseClicked && !shouldQuit()); int correctedMouseX = _mouse->mouseClickX + 7; int correctedMouseY = _mouse->mouseClickY + 7; if ((correctedMouseX > 59 && correctedMouseX < 180) && (correctedMouseY > 28 && correctedMouseY < 119)) { if (correctedMouseY <= 58) { if (correctedMouseX <= 89) { if (cursorPos < 50) { _sound->beep(200, beepDelay); buttonPress(60, 29, 89, 58, true); euroText(205 + cursorPos, 44, "0", 255); inputString = inputString + '0'; buttonPress(60, 29, 89, 58, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else if (correctedMouseX <= 119) { if (cursorPos < 50) { _sound->beep(250, beepDelay); buttonPress(90, 29, 119, 58, true); euroText((205 + cursorPos), 44, "1", 255); inputString = inputString + '1'; buttonPress(90, 29, 119, 58, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else if (correctedMouseX <= 149) { if (cursorPos < 50) { _sound->beep(300, beepDelay); buttonPress(120, 29, 149, 58, true); euroText((205 + cursorPos), 44, "2", 255); inputString = inputString + '2'; buttonPress(120, 29, 149, 58, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else { if (cursorPos < 50) { _sound->beep(350, beepDelay); buttonPress(150, 29, 179, 58, true); euroText((205 + cursorPos), 44, "3", 255); inputString = inputString + '3'; buttonPress(150, 29, 179, 58, false); cursorPos += 10; } else { _sound->beep(70, 250); } } } else if (correctedMouseY <= 88) { if (correctedMouseX <= 89) { if (cursorPos < 50) { _sound->beep(400, beepDelay); buttonPress(60, 59, 89, 88, true); euroText((205 + cursorPos), 44, "4", 255); inputString = inputString + '4'; buttonPress(60, 59, 89, 88, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else if (correctedMouseX <= 119) { if (cursorPos < 50) { _sound->beep(450, beepDelay); buttonPress(90, 59, 119, 88, true); euroText((205 + cursorPos), 44, "5", 255); inputString = inputString + '5'; buttonPress(90, 59, 119, 88, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else if (correctedMouseX <= 149) { if (cursorPos < 50) { _sound->beep(500, beepDelay); buttonPress(120, 59, 149, 88, true); euroText((205 + cursorPos), 44, "6", 255); inputString = inputString + '6'; buttonPress(120, 59, 149, 88, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else { if (cursorPos < 50) { _sound->beep(550, beepDelay); buttonPress(150, 59, 179, 88, true); euroText((205 + cursorPos), 44, "7", 255); inputString = inputString + '7'; buttonPress(150, 59, 179, 88, false); cursorPos += 10; } else { _sound->beep(70, 250); } } } else { if (correctedMouseX <= 89) { if (cursorPos < 50) { _sound->beep(600, beepDelay); buttonPress(60, 89, 89, 118, true); euroText((205 + cursorPos), 44, "8", 255); inputString = inputString + '8'; buttonPress(60, 89, 89, 118, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else if (correctedMouseX <= 119) { if (cursorPos < 50) { _sound->beep(650, beepDelay); buttonPress(90, 89, 119, 118, true); euroText((205 + cursorPos), 44, "9", 255); inputString = inputString + '9'; buttonPress(90, 89, 119, 118, false); cursorPos += 10; } else { _sound->beep(70, 250); } } else if (correctedMouseX <= 149) { if (cursorPos > 0) { _sound->beep(700, beepDelay); buttonPress(120, 89, 149, 118, true); cursorPos -= 10; euroText((205 + cursorPos), 44, "\xDB", 250); inputString = inputString.substr(0, inputString.size() - 1); buttonPress(120, 89, 149, 118, false); } else { _sound->beep(70, 250); } } else { if (cursorPos > 39) { _sound->beep(750, beepDelay); buttonPress(150, 89, 179, 118, true); inputPassword = atoi(inputString.c_str()); buttonPress(150, 89, 179, 118, false); if (attempts < 3) { if (inputPassword == correctPassword) exitDialog = true; else { attempts += 1; _sound->beep(60, 250); } } if (attempts >= 3) showError(259); } else { _sound->beep(70, 250); } } } } } while (!exitDialog && !shouldQuit()); _graphics->putImg(50, 10, bgPointer); _mouse->mouseX = oldMouseX; _mouse->mouseY = oldMouseY; _mouse->mouseMaskIndex = oldMouseMaskIndex; _mouse->warpMouse(_mouse->mouseMaskIndex, _mouse->mouseX, _mouse->mouseY); if (_cpCounter > 8) showError(274); free(bgPointer); _mouse->setMouseArea(Common::Rect(0, 0, 305, 185)); } void TotEngine::soundControls() { uint oldMouseX, oldMouseY, soundControlsSize, sliderSize, sliderBgSize, sfxVol, musicVol, xfade, oldxfade; byte ytext, oldMouseMask; bool exitSoundControls; exitSoundControls = false; oldMouseX = _mouse->mouseX; oldMouseY = _mouse->mouseY; oldMouseMask = _mouse->mouseMaskIndex; _mouse->hide(); soundControlsSize = imagesize(50, 10, 270, 120); // What was on the screen before blitting sound controls byte *soundControlsBackground = (byte *)malloc(soundControlsSize); _graphics->getImg(50, 10, 270, 120, soundControlsBackground); _mouse->mouseX = 150; _mouse->mouseY = 60; _mouse->mouseMaskIndex = 1; _mouse->setMouseArea(Common::Rect(55, 13, 250, 105)); for (ytext = 1; ytext <= 6; ytext++) buttonBorder(120 - (ytext * 10), 80 - (ytext * 10), 200 + (ytext * 10), 60 + (ytext * 10), 251, 251, 251, 251, 0); buttonBorder(86, 31, 94, 44, 0, 0, 0, 0, 0); line(90, 31, 90, 44, 255); sliderSize = imagesize(86, 31, 94, 44); byte *slider = (byte *)malloc(sliderSize); _graphics->getImg(86, 31, 94, 44, slider); drawMenu(3); sliderBgSize = imagesize(86, 31, 234, 44); byte *sliderBackground1 = (byte *)malloc(sliderBgSize); byte *sliderBackground2 = (byte *)malloc(sliderBgSize); _graphics->getImg(86, 31, 234, 44, sliderBackground1); _graphics->getImg(86, 76, 234, 89, sliderBackground2); sfxVol = MIN(256, ConfMan.getInt("sfx_volume")) * 140 / 256; musicVol = MIN(256, ConfMan.getInt("music_volume")) * 140 / 256; _graphics->putImg(sfxVol + 86, 31, slider); _graphics->putImg(musicVol + 86, 76, slider); _mouse->warpMouse(1, _mouse->mouseX, _mouse->mouseY); bool keyPressed = false; bool mouseClicked = false; do { _chrono->updateChrono(); do { _chrono->updateChrono(); _mouse->animateMouseIfNeeded(); g_engine->_events->pollEvent(true); if (g_engine->_events->_keyPressed) { keyPressed = true; } if (g_engine->_events->_leftMouseButton) { debug("Mouse clicked!"); mouseClicked = true; _mouse->mouseClickX = g_engine->_events->_mouseX; _mouse->mouseClickY = g_engine->_events->_mouseY; } _screen->update(); } while ((!keyPressed && !mouseClicked) && !shouldQuit()); _chrono->updateChrono(); _mouse->animateMouseIfNeeded(); if (keyPressed) { exitSoundControls = true; } if (mouseClicked) { if (_mouse->mouseClickY >= 22 && _mouse->mouseClickY <= 37) { _mouse->hide(); xfade = 86 + sfxVol; bool mouseReleased = false; do { oldxfade = xfade; g_engine->_events->pollEvent(true); if (g_engine->_events->_leftMouseButton == 0) { mouseReleased = true; } else { xfade = g_engine->_events->_mouseX; } if (xfade < 86) { xfade = 86; } else if (xfade > 226) { xfade = 226; } if (oldxfade != xfade) { _graphics->putImg(86, 31, sliderBackground1); _graphics->putImg(xfade, 31, slider); // This yields a volume between 0 and 140 sfxVol = xfade - 86; ConfMan.setInt("sfx_volume", sfxVol * 256 / 140); g_engine->syncSoundSettings(); } _screen->update(); } while (!mouseReleased); _mouse->show(); } else if (_mouse->mouseClickY >= 67 && _mouse->mouseClickY <= 82) { _mouse->hide(); xfade = 86 + musicVol; bool mouseReleased = false; do { oldxfade = xfade; g_engine->_events->pollEvent(true); if (g_engine->_events->_leftMouseButton == 0) { mouseReleased = true; } else { xfade = g_engine->_events->_mouseX; } if (xfade < 86) { xfade = 86; } else if (xfade > 226) { xfade = 226; } if (oldxfade != xfade) { _graphics->putImg(86, 76, sliderBackground2); _graphics->putImg(xfade, 76, slider); musicVol = xfade - 86; ConfMan.setInt("music_volume", musicVol * 256 / 140); g_engine->syncSoundSettings(); } _screen->update(); } while (!mouseReleased); _mouse->show(); } else if (_mouse->mouseClickY >= 97 && _mouse->mouseClickY <= 107) { exitSoundControls = true; } mouseClicked = false; } g_system->delayMillis(10); _screen->update(); } while (!exitSoundControls && !shouldQuit()); _graphics->putImg(50, 10, soundControlsBackground); _mouse->mouseX = oldMouseX; _mouse->mouseY = oldMouseY; _mouse->mouseMaskIndex = oldMouseMask; _mouse->warpMouse(_mouse->mouseMaskIndex, _mouse->mouseX, _mouse->mouseY); free(soundControlsBackground); free(slider); free(sliderBackground1); free(sliderBackground2); if (_cpCounter > 7) showError(274); _mouse->setMouseArea(Common::Rect(0, 0, 305, 185)); } void TotEngine::loadBat() { Common::File animFile; _isSecondaryAnimationEnabled = true; if (!animFile.open("MURCIE.DAT")) { showError(265); } _secondaryAnimFrameSize = animFile.readUint16LE(); _secondaryAnimationFrameCount = animFile.readByte(); _secondaryAnimDirCount = animFile.readByte(); newSecondaryAnimationFrame(); loadAnimationForDirection(&animFile, 0); animFile.close(); } void TotEngine::loadDevil() { Common::File animFile; _isSecondaryAnimationEnabled = true; if (!animFile.open("ROJOMOV.DAT")) { showError(265); } _secondaryAnimFrameSize = animFile.readUint16LE(); _secondaryAnimationFrameCount = animFile.readByte(); _secondaryAnimDirCount = animFile.readByte(); newSecondaryAnimationFrame(); if (_secondaryAnimDirCount != 0) { _secondaryAnimationFrameCount = _secondaryAnimationFrameCount / 4; for (int i = 0; i <= 3; i++) { loadAnimationForDirection(&animFile, i); } } animFile.close(); } void TotEngine::assembleCompleteBackground(byte *image, uint coordx, uint coordy) { uint16 w, h; uint16 wFondo; w = READ_LE_UINT16(image); h = READ_LE_UINT16(image + 2); wFondo = READ_LE_UINT16(_sceneBackground); wFondo++; w++; h++; for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int color = image[4 + j * w + i]; if (color != 0) { _sceneBackground[4 + (coordy + j) * wFondo + (coordx + i)] = color; } } } } /** * Assemble the screen for scroll assembles only the objects because scrolling screens * never have secondary animations and character animation is assembled elsewhere. */ void TotEngine::assembleScreen(bool scroll) { for (int indice = 0; indice < kDepthLevelCount; indice++) { if (_screenLayers[indice] != nullptr) { assembleCompleteBackground(_screenLayers[indice], _depthMap[indice].posx, _depthMap[indice].posy); } if (!scroll && _mainCharAnimation.depth == indice) { assembleCompleteBackground(_mainCharAnimation.bitmap[_charFacingDirection][_iframe], _characterPosX, _characterPosY); } if (!scroll && _currentRoomData->animationFlag && _secondaryAnimation.depth == indice) { assembleCompleteBackground(_curSecondaryAnimationFrame, _secondaryAnimation.posx, _secondaryAnimation.posy); } } } void TotEngine::disableSecondAnimation() { setRoomTrajectories(_secondaryAnimHeight, _secondaryAnimWidth, RESTORE); _currentRoomData->animationFlag = false; clearAnimation(); _graphics->restoreBackground(); assembleScreen(); } void TotEngine::setRoomTrajectories(int animationHeight, int animationWidth, TRAJECTORIES_OP op, bool fixGrids) { // add to restore the room, subtract to adjust before loading the screen if (_currentRoomData->animationFlag && _currentRoomData->animationName != "QQQQQQQQ") { for (int i = 0; i < _currentRoomData->secondaryTrajectoryLength; i++) { if (op == RESTORE) { _currentRoomData->secondaryAnimTrajectory[i].x = _currentRoomData->secondaryAnimTrajectory[i].x + (animationWidth >> 1); _currentRoomData->secondaryAnimTrajectory[i].y = _currentRoomData->secondaryAnimTrajectory[i].y + animationHeight; } else { _currentRoomData->secondaryAnimTrajectory[i].x = _currentRoomData->secondaryAnimTrajectory[i].x - (animationWidth >> 1); _currentRoomData->secondaryAnimTrajectory[i].y = _currentRoomData->secondaryAnimTrajectory[i].y - animationHeight; } } if (fixGrids) { for (int i = 0; i < _maxXGrid; i++) { for (int j = 0; j < _maxYGrid; j++) { if (op == RESTORE) { _currentRoomData->walkAreasGrid[_oldposx + i][_oldposy + j] = _movementGridForSecondaryAnim[i][j]; _currentRoomData->mouseGrid[_oldposx + i][_oldposy + j] = _mouseGridForSecondaryAnim[i][j]; } else { if (_maskGridSecondaryAnim[i][j] > 0) _currentRoomData->walkAreasGrid[_oldposx + i][_oldposy + j] = _maskGridSecondaryAnim[i][j]; if (_maskMouseSecondaryAnim[i][j] > 0) _currentRoomData->mouseGrid[_oldposx + i][_oldposy + j] = _maskMouseSecondaryAnim[i][j]; } } } } } } } // End of namespace Tot