Files
scummvm-cursorfix/engines/tot/tot.cpp
2026-02-02 04:50:13 +01:00

1334 lines
39 KiB
C++

/* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "common/events.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "engines/util.h"
#include "tot/anims.h"
#include "tot/chrono.h"
#include "tot/console.h"
#include "tot/detection.h"
#include "tot/debug.h"
#include "tot/dialog.h"
#include "tot/events.h"
#include "tot/sound.h"
#include "tot/tot.h"
#include "tot/util.h"
namespace Tot {
TotEngine *g_engine;
TotEngine::TotEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst),
_gameDescription(gameDesc), _randomSource("Tot") {
g_engine = this;
_lang = _gameDescription->language;
_rooms = nullptr;
_conversationData = nullptr;
_sceneObjectsData = nullptr;
for (uint dir = 0; dir < 4; dir++) {
for (uint frame = 0; frame < kWalkFrameCount + 30; frame++) {
_mainCharAnimation.bitmap[dir][frame] = nullptr;
}
}
for (uint dir = 0; dir < 4; dir++) {
for (uint frame = 0; frame < kWalkFrameCount + 30; frame++) {
_secondaryAnimation.bitmap[dir][frame] = nullptr;
}
}
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 4; j++) {
_niche[i][j] = 0;
}
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
_movementGridForSecondaryAnim[i][j] = 0;
_mouseGridForSecondaryAnim[i][j] = 0;
_maskGridSecondaryAnim[i][j] = 0;
_maskMouseSecondaryAnim[i][j] = 0;
}
}
}
TotEngine::~TotEngine() {
clearGame();
delete _screen;
delete _graphics;
delete _sound;
delete _chrono;
delete _mouse;
delete _events;
}
uint32 TotEngine::getFeatures() const {
return _gameDescription->flags;
}
Common::String TotEngine::getGameId() const {
return _gameDescription->gameId;
}
Common::Error TotEngine::run() {
// Initialize 320x200 paletted graphics mode
initGraphics(320, 200);
ConfMan.registerDefault("introSeen", false);
//Static initializations
_screen = new Graphics::Screen();
_graphics = new GraphicsManager();
_sound = new SoundManager(_mixer);
_chrono = new ChronoManager();
_mouse = new MouseManager();
_events = new TotEventManager();
_sound->init();
syncSoundSettings();
_graphics->init();
initVars();
_isIntroSeen = ConfMan.getBool("introSeen");
// Set the engine's debugger console
setDebugger(new TotConsole(this));
// If a savegame was selected from the launcher, load it
int saveSlot = ConfMan.getInt("save_slot");
if (saveSlot != -1)
(void)loadGameState(saveSlot);
engineStart();
return Common::kNoError;
}
void TotEngine::syncSoundSettings() {
Engine::syncSoundSettings();
_sound->syncSoundSettings();
}
int TotEngine::engineStart() {
if (ConfMan.hasKey("save_slot")) {
return startGame();
}
_graphics->clear();
displayLoading();
loadCharAnimation();
loadInventory();
// The track "SILENT" (a short fanfare) plays at 0 volume in the original code.
// Not sure if this is intended or a bug... It is called "SILENT", but why play
// it at all? It can be played at normal volume by uncommenting the playMidi line.
//_sound->setMidiVolume(0, 0);
//_sound->playMidi("SILENT", false);
_mouse->setMouseArea(Common::Rect(0, 0, 305, 185));
//_sound->playMidi("SILENT", true);
_graphics->totalFadeOut(0);
_graphics->clear();
_graphics->loadPaletteFromFile("DEFAULT");
initScreenPointers();
initialLogo();
_sound->playMidi("INTRODUC", true);
//_sound->setMidiVolume(3, 3);
firstIntroduction();
_mouse->warpMouse(1, _mouse->mouseX, _mouse->mouseY);
mainMenu(_firstTimeDone);
if (_startNewGame && !shouldQuit()) {
newGame();
} else if (_continueGame && !shouldQuit()) {
resumeGame();
}
return startGame();
}
void TotEngine::resumeGame() {
loadGameState(getMetaEngine()->getAutosaveSlot());
}
void TotEngine::processEvents(bool &escapePressed) {
_events->pollEvent();
if (_events->_escKeyFl) {
escapePressed = true;
} else if (_events->_gameKey == KEY_VOLUME) {
soundControls();
g_engine->_events->zeroEvents();
} else if (_events->_gameKey == KEY_SAVELOAD) {
if (ConfMan.getBool("originalsaveload"))
originalSaveLoadScreen();
else
openMainMenuDialog();
g_engine->_events->zeroEvents();
} else if (_events->_gameKey == KEY_OPEN) {
_actionCode = 5;
action();
_oldGridX = 0;
_oldGridY = 0;
} else if (_events->_gameKey == KEY_CLOSE) {
_actionCode = 6;
action();
_oldGridX = 0;
_oldGridY = 0;
} else if (_events->_gameKey == KEY_PICKUP) {
_actionCode = 2;
action();
_oldGridX = 0;
_oldGridY = 0;
} else if (_events->_gameKey == KEY_TALK) {
_actionCode = 1;
action();
_oldGridX = 0;
_oldGridY = 0;
} else if (_events->_gameKey == KEY_LOOKAT) {
_actionCode = 3;
action();
_oldGridX = 0;
_oldGridY = 0;
} else if (_events->_gameKey == KEY_USE) {
_actionCode = 4;
action();
_oldGridX = 0;
_oldGridY = 0;
} else if (_events->_gameKey == KEY_NONE && _events->_keyPressed) {
_actionCode = 0; // go to
action();
}
if (_events->_leftMouseButton == 1) {
_mouse->mouseClickX = _events->_mouseX;
_mouse->mouseClickY = _events->_mouseY;
if (_mouse->mouseClickY > 0 && _mouse->mouseClickY < 131) {
switch (_actionCode) {
case 0: // go to
_cpCounter2 = _cpCounter;
// gets the zone where the character is now standing. Zone is calculated using xframe,yframe plus some adjustments to get the center of the feet
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
if (_currentZone < 10) {
_xframe2 = _mouse->mouseClickX + 7;
_yframe2 = _mouse->mouseClickY + 7;
// obtains the target zone from the clicked coordinates
_targetZone = _currentRoomData->walkAreasGrid[_xframe2 / kXGridCount][_yframe2 / kYGridCount];
if (_currentRoomData->code == 21 && _currentRoomData->animationFlag) {
if ((_targetZone >= 1 && _targetZone <= 5) ||
(_targetZone >= 9 && _targetZone <= 13) ||
(_targetZone >= 18 && _targetZone <= 21) ||
_targetZone == 24 || _targetZone == 25) {
_targetZone = 7;
_mouse->mouseClickX = 232;
_mouse->mouseClickY = 75;
_xframe2 = _mouse->mouseClickX + 7;
_yframe2 = _mouse->mouseClickY + 7;
}
}
if (_oldTargetZone != _targetZone || _targetZone < 10) {
_oldTargetZone = _targetZone;
// Resets the entire route
calculateRoute(_currentZone, _targetZone);
_doorIndex = 0;
_roomChange = false;
for (_doorIndex = 0; _doorIndex < 5; _doorIndex++) {
if (_currentRoomData->doors[_doorIndex].doorcode == _targetZone) {
if (_currentRoomData->doors[_doorIndex].openclosed == 1) {
_roomChange = true;
break;
} else if ((_currentRoomData->code == 5 && _targetZone == 27) || (_currentRoomData->code == 6 && _targetZone == 21)) {
;
} else {
_trajectorySteps -= 1;
}
}
}
// Sets xframe2 again due to the substraction when closed doors
_xframe2 = _trajectorySteps;
} else
_xframe2 = 0;
}
break;
case 1: // talk
_roomChange = false;
_actionCode = 0;
talkToSceneObject();
_cpCounter2 = _cpCounter;
break;
case 2: // pick up
_roomChange = false;
_actionCode = 0;
pickupScreenObject();
_cpCounter = _cpCounter2;
break;
case 3: // look at
_roomChange = false;
_destinationX = _mouse->getClickCoordsWithinGrid().x;
_destinationY = _mouse->getClickCoordsWithinGrid().y;
if (_currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[_destinationX][_destinationY]]->fileIndex > 0) {
goToObject(
_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount],
_currentRoomData->walkAreasGrid[_destinationX][_destinationY]);
if (_currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[_destinationX][_destinationY]]->fileIndex == 562)
switch (_currentRoomData->code) {
case 20:
if (_niche[0][_niche[0][3]] > 0)
readObject(_niche[0][_niche[0][3]]);
else
readObject(562);
break;
case 24:
if (_niche[1][_niche[1][3]] > 0)
readObject(_niche[1][_niche[1][3]]);
else
readObject(562);
break;
}
else
readObject(_currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[_destinationX][_destinationY]]->fileIndex);
if (_curObject->lookAtTextRef > 0)
drawText(_curObject->lookAtTextRef);
_actionCode = 0;
}
break;
case 4: // use
_roomChange = false;
_actionCode = 0;
useScreenObject();
_cpCounter = _cpCounter2;
break;
case 5: // open
_roomChange = false;
_actionCode = 0;
openScreenObject();
break;
case 6: { // close
_roomChange = false;
_actionCode = 0;
closeScreenObject();
_cpCounter = _cpCounter2;
} break;
}
} else if (_mouse->mouseClickY > 148 && _mouse->mouseClickY < 158) {
if (_mouse->mouseClickX >= 3 && _mouse->mouseClickX <= 53) {
_actionCode = 1;
action();
} else if (_mouse->mouseClickX >= 58 && _mouse->mouseClickX <= 103) {
_actionCode = 2;
action();
} else if (_mouse->mouseClickX >= 108 && _mouse->mouseClickX <= 153) {
_actionCode = 3;
action();
} else if (_mouse->mouseClickX >= 158 && _mouse->mouseClickX <= 198) {
_actionCode = 4;
action();
} else if (_mouse->mouseClickX >= 203 && _mouse->mouseClickX <= 248) {
_actionCode = 5;
action();
} else if (_mouse->mouseClickX >= 253 && _mouse->mouseClickX <= 311) {
_actionCode = 6;
action();
} else {
_actionCode = 0;
action();
_cpCounter2 = _cpCounter;
}
} else if (_mouse->mouseClickY > 166 && _mouse->mouseClickY < 199) {
if (_mouse->mouseClickX >= 3 && _mouse->mouseClickX <= 19) {
drawInventory(0, 33);
} else if (_mouse->mouseClickX >= 26 && _mouse->mouseClickX <= 65) {
handleAction(_inventoryPosition);
} else if (_mouse->mouseClickX >= 70 && _mouse->mouseClickX <= 108) {
handleAction(_inventoryPosition + 1);
} else if (_mouse->mouseClickX >= 113 && _mouse->mouseClickX <= 151) {
handleAction(_inventoryPosition + 2);
} else if (_mouse->mouseClickX >= 156 && _mouse->mouseClickX <= 194) {
handleAction(_inventoryPosition + 3);
} else if (_mouse->mouseClickX >= 199 && _mouse->mouseClickX <= 237) {
handleAction(_inventoryPosition + 4);
} else if (_mouse->mouseClickX >= 242 && _mouse->mouseClickX <= 280) {
handleAction(_inventoryPosition + 5);
} else if (_mouse->mouseClickX >= 290 && _mouse->mouseClickX <= 311) {
drawInventory(1, 33);
} else {
_actionCode = 0;
action();
}
}
} else if (_events->_rightMouseButton) {
_mouse->mouseClickX = _events->_mouseX;
_mouse->mouseClickY = _events->_mouseY;
Common::Point p = _mouse->getClickCoordsWithinGrid();
_destinationX = p.x;
_destinationY = p.y;
_cpCounter2 = _cpCounter;
if (_destinationY < 28) {
RoomObjectListEntry obj = *_currentRoomData->screenObjectIndex[_currentRoomData->mouseGrid[_destinationX][_destinationY]];
if (obj.fileIndex > 0) {
drawLookAtItem(obj);
goToObject(_currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount], _currentRoomData->walkAreasGrid[_destinationX][_destinationY]);
if (obj.fileIndex == 562)
switch (_currentRoomData->code) {
case 20:
if (_niche[0][_niche[0][3]] > 0)
readObject(_niche[0][_niche[0][3]]);
else
readObject(562);
break;
case 24:
if (_niche[1][_niche[1][3]] > 0)
readObject(_niche[1][_niche[1][3]]);
else
readObject(562);
break;
}
else
readObject(obj.fileIndex);
if (_curObject->lookAtTextRef > 0)
drawText(_curObject->lookAtTextRef);
_actionCode = 0;
}
}
}
}
int TotEngine::startGame() {
if (shouldQuit()) {
return 0;
}
_sound->fadeOutMusic();
switch (_gamePart) {
case 1:
_sound->playMidi("PRIMERA", true);
break;
case 2:
_sound->playMidi("SEGUNDA", true);
break;
}
_cpCounter2 = _cpCounter;
_sound->fadeInMusic();
_inGame = true;
while (!_shouldQuitGame && !shouldQuit()) {
bool escapePressed = false;
_chrono->updateChrono();
_mouse->animateMouseIfNeeded();
processEvents(escapePressed);
checkMouseGrid();
advanceAnimations(false, true);
if(shouldQuit()) break;
// Scene changes
if (_xframe2 == 0 && _roomChange) {
changeRoom();
}
if (escapePressed && _xframe2 == 0) {
clearAnimation();
clearScreenLayers();
_cpCounter2 = _cpCounter;
_startNewGame = false;
_continueGame = false;
saveAutosaveIfEnabled();
_graphics->totalFadeOut(0);
_sound->fadeOutMusic();
_graphics->clear();
_sound->playMidi("INTRODUC", true);
_sound->fadeInMusic();
mainMenu(true);
if (_startNewGame && !shouldQuit()) {
newGame();
} else if (_continueGame && !shouldQuit())
resumeGame();
else {
_isSavingDisabled = true;
openMainMenuDialog();
_cpCounter = _cpCounter2;
_isSavingDisabled = false;
}
_sound->fadeOutMusic();
switch (_gamePart) {
case 1:
_sound->playMidi("PRIMERA", true);
break;
case 2:
_sound->playMidi("SEGUNDA", true);
break;
}
_sound->fadeInMusic();
}
switch (_gamePart) {
case 1:
if (_list1Complete && _list2Complete) {
if (!isDemo()) {
_list1Complete = false;
_list2Complete = false;
_cpCounter = _cpCounter2;
_gamePart = 2;
_iframe = 0;
freeInventory();
clearAnimation();
clearScreenLayers();
_mouse->hide();
_graphics->partialFadeOut(234);
_sound->fadeOutMusic();
_sound->playMidi("CREDITOS", true);
_sound->fadeInMusic();
if (_cpCounter2 > 43)
showError(274);
sacrificeScene();
_graphics->clear();
loadInventory();
_graphics->loadPaletteFromFile("SEGUNDA");
_currentTrajectoryIndex = 0;
_characterPosX = 160;
_characterPosY = 60;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
loadScreenData(20);
_sound->fadeOutMusic();
_sound->playMidi("SEGUNDA", true);
_sound->fadeInMusic();
_graphics->sceneTransition(false, _sceneBackground, 1);
drawInventoryMask();
_inventoryPosition = 0;
drawInventory();
_mouse->show();
copyProtection();
_firstTimeTopicA[8] = true;
_oldGridX = 0;
_oldGridY = 0;
checkMouseGrid();
} else {
_shouldQuitGame = true;
}
}
break;
}
// Debug graphics
{
// _graphics->euroText(Common::String::format("Room: %d", currentRoomNumber), 0, 0, 220, Graphics::kTextAlignLeft);
// _mouseManager->printPos(xraton, yraton, 220, 0);
// printPos(characterPosX, characterPosY, 220, 10, "CharPos");
if (_showMouseGrid) {
drawMouseGrid(_currentRoomData);
}
if (_showScreenGrid) {
drawScreenGrid(_currentRoomData);
}
if (_showGameGrid) {
drawGrid();
}
if (_drawObjectAreas) {
for (int i = 0; i < kDepthLevelCount; i++) {
if (_screenLayers[i] != nullptr) {
if (true) {
// debug
uint16 w = READ_LE_UINT16(_screenLayers[i]);
uint16 h = READ_LE_UINT16(_screenLayers[i] + 2);
Common::Rect r = Common::Rect(_depthMap[i].posx, _depthMap[i].posy, _depthMap[i].posx + w, _depthMap[i].posy + h);
drawRect(180, _depthMap[i].posx, _depthMap[i].posy, _depthMap[i].posx + w, _depthMap[i].posy + h);
littText(r.left, r.top, Common::String().format("%d", i), 0);
}
}
}
}
}
_screen->update();
g_system->delayMillis(10);
}
_mouse->hide();
if (!shouldQuit() && !isDemo()) {
ending();
}
Common::String photoFileName;
if (!shouldQuit()) {
obtainName(photoFileName);
}
if (!shouldQuit()) {
generateDiploma(photoFileName);
}
if (!shouldQuit() && !isDemo()) {
credits();
}
return EXIT_SUCCESS;
}
void TotEngine::newGame() {
_saveAllowed = true;
_mouse->hide();
obtainName(_characterName);
if (!shouldQuit()) {
_graphics->totalFadeOut(0);
_graphics->clear();
displayLoading();
freeInventory();
resetGameState();
loadInventory();
_inGame = true;
for (int i = 0; i < kInventoryIconCount; i++) {
_inventory[i].bitmapIndex = 34;
_inventory[i].code = 0;
_inventory[i].objectName = getObjectName(10);
}
readConversationFile();
initializeScreenFile();
initializeObjectFile();
_graphics->loadPaletteFromFile("DEFAULT");
loadScreenData(1);
_graphics->sceneTransition(false, _sceneBackground, 13);
drawInventoryMask();
_inventoryPosition = 0;
drawInventory();
_iframe = 0;
_mouse->show();
}
}
void TotEngine::changeRoom() {
_roomChange = false;
_cpCounter = _cpCounter2;
setRoomTrajectories(_secondaryAnimHeight, _secondaryAnimWidth, RESTORE);
saveRoomData(_currentRoomData, _rooms);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
if (_currentRoomData->doors[_doorIndex].nextScene != 255) {
clearAnimation();
clearScreenLayers();
}
switch (_currentRoomData->doors[_doorIndex].nextScene) {
case 2: {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
_sound->stopVoc();
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
if (_cpCounter > 89)
showError(274);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
if (_isTVOn)
_sound->autoPlayVoc("PARASITO", 355778, 20129);
else
loadTV();
_graphics->sceneTransition(false, _sceneBackground);
_cpCounter = _cpCounter2;
_mouse->show();
} break;
case 5: {
if (_currentRoomData->code != 6) {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY + 15;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
_sound->stopVoc();
_sound->autoPlayVoc("CALDERA", 6433, 15386);
_sound->setSfxVolume(_sound->_leftSfxVol, 0);
_graphics->sceneTransition(false, _sceneBackground);
_mouse->show();
} else {
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
_targetZone = 21;
goToObject(_currentZone, _targetZone);
_mouse->hide();
_sound->setSfxVolume(_sound->_leftSfxVol, 0);
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, true, 22, -2);
_mouse->show();
}
} break;
case 6: {
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
_targetZone = 27;
goToObject(_currentZone, _targetZone);
_mouse->hide();
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, false, 22, 2);
_mouse->show();
} break;
case 9: {
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
_graphics->sceneTransition(false, _sceneBackground);
_mouse->show();
if (getRandom(2) == 0) copyProtection();
} break;
case 12: {
if (_currentRoomData->code != 13) {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
_graphics->sceneTransition(false, _sceneBackground);
_mouse->show();
} else {
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
goToObject(_currentZone, _targetZone);
_mouse->hide();
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, false, 64, 0);
_mouse->show();
}
} break;
case 13: {
switch (_currentRoomData->code) {
case 12: {
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
goToObject(_currentZone, _targetZone);
_mouse->hide();
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, true, 64, 0);
_mouse->show();
} break;
case 14: {
_currentZone = _currentRoomData->walkAreasGrid[(_characterPosX + kCharacterCorrectionX) / kXGridCount][(_characterPosY + kCharacerCorrectionY) / kYGridCount];
goToObject(_currentZone, _targetZone);
_mouse->hide();
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, false, 56, 0);
_mouse->show();
} break;
}
} break;
case 14: {
if (_currentRoomData->code != 13) {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
_graphics->sceneTransition(false, _sceneBackground);
_mouse->show();
} else {
_currentZone = _currentRoomData->walkAreasGrid[((_characterPosX + kCharacterCorrectionX) / kXGridCount)][((_characterPosY + kCharacerCorrectionY) / kYGridCount)];
goToObject(_currentZone, _targetZone);
_mouse->hide();
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, true, 56, 0);
_mouse->show();
}
} break;
case 17: {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
_sound->stopVoc();
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
if (_bookTopic[0] == true && _currentRoomData->animationFlag == true)
disableSecondAnimation();
if (_cpCounter > 89)
showError(274);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
_graphics->sceneTransition(false, _sceneBackground);
_cpCounter = _cpCounter2;
_mouse->show();
} break;
case 18: {
if (_currentRoomData->code != 19) {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
_graphics->sceneTransition(false, _sceneBackground);
_mouse->show();
} else {
_currentZone = _currentRoomData->walkAreasGrid[((_characterPosX + kCharacterCorrectionX) / kXGridCount)][((_characterPosY + kCharacerCorrectionY) / kYGridCount)];
goToObject(_currentZone, _targetZone);
_mouse->hide();
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, true, 131, -1);
_mouse->show();
}
} break;
case 19: {
if (_currentRoomData->code != 18) {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
_graphics->sceneTransition(false, _sceneBackground);
_mouse->show();
} else {
_currentZone = _currentRoomData->walkAreasGrid[((_characterPosX + kCharacterCorrectionX) / kXGridCount)][((_characterPosY + kCharacerCorrectionY) / kYGridCount)];
goToObject(_currentZone, _targetZone);
_mouse->hide();
loadScrollData(_currentRoomData->doors[_doorIndex].nextScene, false, 131, 1);
_mouse->show();
}
} break;
case 20: {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
_sound->stopVoc();
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
switch (_niche[0][_niche[0][3]]) {
case 0:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(4);
break;
case 561:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(5);
break;
case 563:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(6);
break;
case 615:
_currentRoomData->screenObjectIndex[9]->objectName = getObjectName(7);
break;
}
if (_cpCounter > 89)
showError(274);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
if (_currentRoomData->code == 4)
_sound->loadVoc("GOTA", 140972, 1029);
_graphics->sceneTransition(false, _sceneBackground);
_cpCounter = _cpCounter2;
_mouse->show();
} break;
case 24: {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
_sound->stopVoc();
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
switch (_niche[1][_niche[1][3]]) {
case 0:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(4);
break;
case 561:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(5);
break;
case 615:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(7);
break;
case 622:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(8);
break;
case 623:
_currentRoomData->screenObjectIndex[8]->objectName = getObjectName(9);
break;
}
if (_cpCounter > 89)
showError(274);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
if (_isTrapSet) {
_currentRoomData->animationFlag = true;
loadAnimation(_currentRoomData->animationName);
_iframe2 = 0;
_currentSecondaryTrajectoryIndex = 1;
_currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x = 214 - 15;
_currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y = 115 - 42;
_secondaryAnimation.dir = _currentRoomData->secondaryAnimDirections[_currentSecondaryTrajectoryIndex - 1];
_secondaryAnimation.posx = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].x;
_secondaryAnimation.posy = _currentRoomData->secondaryAnimTrajectory[_currentSecondaryTrajectoryIndex - 1].y;
_secondaryAnimation.depth = 14;
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];
}
assembleScreen();
}
_graphics->sceneTransition(false, _sceneBackground);
if ((_isRedDevilCaptured == false) && (_isTrapSet == false))
runaroundRed();
_cpCounter = _cpCounter2;
_mouse->show();
} break;
case 255:
wcScene();
break;
default: {
_iframe = 0;
_currentTrajectoryIndex = 0;
_characterPosX = _currentRoomData->doors[_doorIndex].exitPosX - kCharacterCorrectionX;
_characterPosY = _currentRoomData->doors[_doorIndex].exitPosY - kCharacerCorrectionY;
_trajectory[_currentTrajectoryIndex].x = _characterPosX;
_trajectory[_currentTrajectoryIndex].y = _characterPosY;
_mouse->hide();
_graphics->sceneTransition(true, nullptr);
_sound->stopVoc();
loadScreenData(_currentRoomData->doors[_doorIndex].nextScene);
if (_cpCounter > 89)
showError(274);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
switch (_currentRoomData->code) {
case 4:
_sound->loadVoc("GOTA", 140972, 1029);
break;
case 23:
_sound->autoPlayVoc("FUENTE", 0, 0);
break;
}
_graphics->sceneTransition(false, _sceneBackground);
_cpCounter = _cpCounter2;
_mouse->show();
}
}
if (_currentRoomData->doors[_doorIndex].nextScene != 255) {
_oldGridX = 0;
_oldGridY = 0;
checkMouseGrid();
}
_oldTargetZone = 0;
}
/**
* Originally the Room file contains 8 copies of each room, one for every save plus the baseline (which is 0).
* To put this into memory we need to get the baseline of each room and then put them continuously in a byte stream.addr
* Whenever the game access a room instead of accessing the room for the autosave or the current save,
* we assume only one room register is there.
*
* To save a game we merely copy the entire stream into the save.
*/
void TotEngine::initializeScreenFile() {
Common::File roomFile;
if (!roomFile.open(Common::Path("PANTALLA.DAT"))) {
showError(320);
}
int64 fileSize = roomFile.size();
delete (_rooms);
byte *roomData = (byte *)malloc(kRoomRegSize * 32);
int roomCount = 0;
while (!roomFile.eos()) {
if (fileSize - roomFile.pos() >= kRoomRegSize) {
roomFile.read(roomData + kRoomRegSize * roomCount, kRoomRegSize);
// This one doesn't work for some reason:
// rooms->writeStream(roomFile.readStream(roomRegSize), roomRegSize);
roomFile.skip(kRoomRegSize * 7);
roomCount++;
} else {
break;
}
}
_rooms = new Common::MemorySeekableReadWriteStream(roomData, kRoomRegSize * roomCount, DisposeAfterUse::NO);
roomFile.close();
}
void TotEngine::resetGameState() {
_characterPosX = 160;
_characterPosY = 80;
_iframe = 0;
_trajectory[0].x = _characterPosX;
_trajectory[0].y = _characterPosY;
_xframe2 = 0;
_yframe2 = 1;
_currentZone = 1;
_targetZone = 1;
_oldTargetZone = 0;
_charFacingDirection = 1;
for (int i = 0; i < 9; i++) {
_firstTimeTopicA[i] = true;
_firstTimeTopicB[i] = false;
_firstTimeTopicC[i] = false;
_bookTopic[i] = false;
_mintTopic[i] = false;
}
for (int i = 0; i < 5; i++) {
_caves[i] = false;
}
_isSecondaryAnimationEnabled = false;
_mainCharAnimation.depth = 0;
_isDrawingEnabled = true;
_isSavingDisabled = false;
_startNewGame = false;
_shouldQuitGame = false;
_obtainedList1 = false;
_obtainedList2 = false;
_list1Complete = false;
_list2Complete = false;
_graphics->_paletteAnimFrame = 0;
_gamePart = 1;
_isVasePlaced = false;
_isScytheTaken = false;
_isTridentTaken = false;
_isPottersWheelDelivered = false;
_isMudDelivered = false;
_isSealRemoved = false;
_isGreenDevilDelivered = false;
_isRedDevilCaptured = false;
_isCupboardOpen = false;
_isChestOpen = false;
_isTVOn = false;
_isTrapSet = false;
_graphics->_palAnimStep = 0;
_niche[0][0] = 563;
_niche[0][1] = 561;
_niche[0][2] = 0;
_niche[0][3] = 2;
_niche[1][0] = 615;
_niche[1][1] = 622;
_niche[1][2] = 623;
_niche[1][3] = 0;
_currentTrajectoryIndex = 0;
_inventoryPosition = 0;
}
void TotEngine::initVars() {
_isLoadingFromLauncher = false;
_decryptionKey = "23313212133122121312132132312312122132322131221322222112121"
"32121121212112111212112333131232323213222132123211213221231"
"32132213232333333213132132132322113212132121322123121232332"
"23123221322213233221112312231221233232122332211112233122321"
"222312211322312223";
for(int i = 0; i < kNumScreenOverlays; i++) {
_screenLayers[i] = nullptr;
}
for(int i = 0; i < kInventoryIconCount; i++) {
_inventoryIconBitmaps[i] = nullptr;
}
for(int i = 0; i < 4; i++) {
for(int j = 0; j < kWalkFrameCount + 30; j++) {
_mainCharAnimation.bitmap[i][j] = nullptr;
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < kSecAnimationFrameCount; j++) {
_secondaryAnimation.bitmap[i][j] = nullptr;
}
}
_curSecondaryAnimationFrame = nullptr;
_characterDirtyRect = nullptr;
resetGameState();
_chrono->_gameTick = false;
for (int i = 0; i < kNumScreenOverlays; i++) {
_screenLayers[i] = nullptr;
}
_firstList[0] = 222;
_firstList[1] = 295;
_firstList[2] = 402;
_firstList[3] = 223;
_firstList[4] = 521;
_secondList[0] = 221;
_secondList[1] = 423;
_secondList[2] = 308;
_secondList[3] = 362;
_secondList[4] = 537;
_cpCounter = 0;
_cpCounter2 = 0;
_continueGame = true;
_firstTimeDone = false;
_isIntroSeen = false;
_inGame = false;
_sceneBackground = nullptr;
_backgroundCopy = nullptr;
_conversationData = nullptr;
_rooms = nullptr;
_sceneObjectsData = nullptr;
}
void TotEngine::clearVars() {
if (_sceneBackground != nullptr) {
free(_sceneBackground);
}
if (_backgroundCopy != nullptr) {
free(_backgroundCopy);
}
if (_conversationData != nullptr) {
delete _conversationData;
}
if (_rooms != nullptr) {
delete _rooms;
}
if (_sceneObjectsData != nullptr) {
delete _sceneObjectsData;
}
if(_curObject != nullptr) {
delete _curObject;
_curObject = nullptr;
}
if (_currentRoomData) {
delete _currentRoomData;
}
clearScreenLayers();
for (int i = 0; i < kInventoryIconCount; i++) {
if (_inventoryIconBitmaps[i] != nullptr) {
free(_inventoryIconBitmaps[i]);
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < kWalkFrameCount + 30; j++) {
if (_mainCharAnimation.bitmap[i][j] != nullptr) {
free(_mainCharAnimation.bitmap[i][j]);
}
}
}
if(_curSecondaryAnimationFrame != nullptr) {
free(_curSecondaryAnimationFrame);
}
for (int i = 0; i < _secondaryAnimDirCount; i++) {
for (int j = 0; j < _secondaryAnimationFrameCount; j++) {
if (_secondaryAnimation.bitmap[i][j] != nullptr) {
free(_secondaryAnimation.bitmap[i][j]);
}
}
}
}
void TotEngine::mainMenu(bool fade) {
bool bar = false;
bool validOption = false;
_sound->stopVoc();
int32 offset = getOffsetsByCurrentLanguage()[1];
_mouse->hide();
if (fade)
drawFlc(0, 0, offset, 0, 9, 0, true, false, false, bar);
else
drawFlc(0, 0, offset, 0, 9, 0, false, false, false, bar);
if (_cpCounter2 > 10)
showError(274);
_mouse->mouseX = 160;
_mouse->mouseY = 95;
_mouse->mouseMaskIndex = 1;
_mouse->warpMouse(_mouse->mouseMaskIndex, _mouse->mouseX, _mouse->mouseY);
_mouse->show();
do {
_chrono->updateChrono();
_mouse->animateMouseIfNeeded();
_events->pollEvent();
if (_events->_escKeyFl) {
exitToDOS();
}
if (_events->_leftMouseButton) {
uint x = _events->_mouseX + 7;
uint y = _events->_mouseY + 7;
if (y > 105 && y < 120) {
if (x > 46 && x < 145) {
_startNewGame = true;
_continueGame = false;
validOption = true;
} else if (x > 173 && x < 267) {
credits();
if (!g_engine->shouldQuit()) {
drawFlc(0, 0, offset, 0, 9, 0, true, false, false, bar);
}
}
} else if (y > 140 && y < 155) {
if (x > 173 && x < 292) {
_graphics->totalFadeOut(0);
_screen->clear();
introduction();
if (!g_engine->shouldQuit()) {
drawFlc(0, 0, offset, 0, 9, 0, true, false, false, bar);
}
} else if (x >= 18 && x <= 145) {
_isSavingDisabled = true;
if (ConfMan.getBool("originalsaveload")) {
originalSaveLoadScreen();
validOption = true;
} else {
bool result = loadGameDialog();
if (result) {
validOption = true;
}
}
_startNewGame = false;
_continueGame = false;
_isSavingDisabled = false;
}
} else if (y > 174 && y < 190) {
if (x > 20 && x < 145) {
_startNewGame = false;
validOption = true;
_continueGame = true;
} else if (x > 173 && x < 288) {
exitToDOS();
}
}
}
_screen->update();
g_system->delayMillis(10);
} while (!validOption && !shouldQuit());
}
void exitGame() {
g_engine->_graphics->clear();
g_engine->quitGame();
}
void TotEngine::clearGame() {
resetGameState();
clearVars();
}
void TotEngine::exitToDOS() {
uint oldMousePosX, oldMousePosY, dialogSize;
byte oldMouseMask;
char exitChar;
oldMousePosX = _mouse->mouseX;
oldMousePosY = _mouse->mouseY;
oldMouseMask = _mouse->mouseMaskIndex;
_mouse->hide();
dialogSize = imagesize(58, 48, 262, 120);
byte *dialogBackground = (byte *)malloc(dialogSize);
_graphics->getImg(58, 48, 262, 120, dialogBackground);
drawMenu(7);
_mouse->mouseX = 160;
_mouse->mouseY = 90;
_mouse->mouseMaskIndex = 1;
_mouse->setMouseArea(Common::Rect(115, 80, 190, 100));
_mouse->warpMouse(_mouse->mouseMaskIndex, _mouse->mouseX, _mouse->mouseY);
exitChar = '@';
do {
_chrono->updateChrono();
_mouse->animateMouseIfNeeded();
_events->pollEvent();
if (_events->_escKeyFl) {
exitChar = '\33';
} else if (_events->_gameKey == KEY_YES) {
exitGame();
} else if (_events->_gameKey == KEY_NO) {
exitChar = '\33';
}
else if (_events->_leftMouseButton) {
uint x = g_engine->_mouse->mouseClickX;
if (x < 145) {
exitGame();
} else if (x > 160) {
exitChar = '\33';
}
}
_screen->update();
} while (exitChar != '\33' && !shouldQuit());
if (shouldQuit()) {
free(dialogBackground);
return;
}
_graphics->putImg(58, 48, dialogBackground);
_mouse->mouseX = oldMousePosX;
_mouse->mouseY = oldMousePosY;
_mouse->mouseMaskIndex = oldMouseMask;
_mouse->show();
free(dialogBackground);
_mouse->setMouseArea(Common::Rect(0, 0, 305, 185));
}
} // End of namespace Tot