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

816 lines
26 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/hashmap.h"
#include "common/savefile.h"
#include "common/translation.h"
#include "graphics/thumbnail.h"
#include "gui/message.h"
#include "tot/forest.h"
#include "tot/tot.h"
namespace Tot {
#define SAVEGAME_CURRENT_VERSION 1
bool syncGeneralData(Common::Serializer &s, SavedGame *game) {
// Uint16
s.syncAsUint16LE(game->roomCode);
s.syncAsUint16LE(game->trajectoryLength);
s.syncAsUint16LE(game->currentTrajectoryIndex);
s.syncAsUint16LE(game->backpackObjectCode);
s.syncAsUint16LE(game->rightSfxVol);
s.syncAsUint16LE(game->leftSfxVol);
s.syncAsUint16LE(game->musicVolRight);
s.syncAsUint16LE(game->musicVolLeft);
s.syncAsUint16LE(game->oldGridX);
s.syncAsUint16LE(game->oldGridY);
s.syncAsUint16LE(game->secAnimDepth);
s.syncAsUint16LE(game->secAnimDir);
s.syncAsUint16LE(game->secAnimX);
s.syncAsUint16LE(game->secAnimY);
s.syncAsUint16LE(game->secAnimIFrame);
// Bytes
s.syncAsByte(game->currentZone);
s.syncAsByte(game->targetZone);
s.syncAsByte(game->oldTargetZone);
s.syncAsByte(game->inventoryPosition);
s.syncAsByte(game->actionCode);
s.syncAsByte(game->oldActionCode);
s.syncAsByte(game->steps);
s.syncAsByte(game->doorIndex);
s.syncAsByte(game->characterFacingDir);
s.syncAsByte(game->iframe);
s.syncAsByte(game->gamePart);
// Booleans
s.syncAsByte(game->isSealRemoved);
s.syncAsByte(game->obtainedList1);
s.syncAsByte(game->obtainedList2);
s.syncAsByte(game->list1Complete);
s.syncAsByte(game->list2Complete);
s.syncAsByte(game->isVasePlaced);
s.syncAsByte(game->isScytheTaken);
s.syncAsByte(game->isTridentTaken);
s.syncAsByte(game->isPottersWheelDelivered);
s.syncAsByte(game->isMudDelivered);
s.syncAsByte(game->isGreenDevilDelivered);
s.syncAsByte(game->isRedDevilCaptured);
s.syncAsByte(game->isPottersManualDelivered);
s.syncAsByte(game->isCupboardOpen);
s.syncAsByte(game->isChestOpen);
s.syncAsByte(game->isTVOn);
s.syncAsByte(game->isTrapSet);
for (int i = 0; i < kInventoryIconCount; i++) {
s.syncAsUint16LE(game->mobj[i].bitmapIndex);
s.syncAsUint16LE(game->mobj[i].code);
s.syncString(game->mobj[i].objectName);
}
// integers
s.syncAsSint32LE(game->element1);
s.syncAsSint32LE(game->element2);
s.syncAsSint32LE(game->characterPosX);
s.syncAsSint32LE(game->characterPosY);
s.syncAsSint32LE(game->xframe2);
s.syncAsSint32LE(game->yframe2);
// Strings
s.syncString(game->oldInventoryObjectName);
s.syncString(game->objetomoinventoryObjectNamehila);
s.syncString(game->characterName);
for (int i = 0; i < kRoutePointCount; i++) {
s.syncAsSint16LE(game->mainRoute[i].x);
s.syncAsSint16LE(game->mainRoute[i].y);
}
for (int i = 0; i < 300; i++) {
s.syncAsSint16LE(game->trajectory[i].x);
s.syncAsSint16LE(game->trajectory[i].y);
}
for (int indiaux = 0; indiaux < kCharacterCount; indiaux++) {
// interleave them just to avoid creating many loops
s.syncAsByte(game->firstTimeTopicA[indiaux]);
s.syncAsByte(game->firstTimeTopicB[indiaux]);
s.syncAsByte(game->firstTimeTopicC[indiaux]);
s.syncAsByte(game->bookTopic[indiaux]);
s.syncAsByte(game->mintTopic[indiaux]);
}
for (int indiaux = 0; indiaux < 5; indiaux++) {
s.syncAsByte(game->caves[indiaux]);
s.syncAsUint16LE(game->firstList[indiaux]);
s.syncAsUint16LE(game->secondList[indiaux]);
}
for (int indiaux = 0; indiaux < 4; indiaux++) {
s.syncAsUint16LE(game->niche[0][indiaux]);
s.syncAsUint16LE(game->niche[1][indiaux]);
}
return true;
}
bool syncRoomData(Common::Serializer &s, Common::MemorySeekableReadWriteStream *roomStream) {
if (s.isSaving()) {
// Restore trajectory
g_engine->setRoomTrajectories(g_engine->_secondaryAnimHeight, g_engine->_secondaryAnimWidth, RESTORE);
// Make sure to save any unsaved changes in the room
g_engine->saveRoomData(g_engine->_currentRoomData, g_engine->_rooms);
// Do not fix screen grids, they will be fixed differently below
g_engine->setRoomTrajectories(g_engine->_secondaryAnimHeight, g_engine->_secondaryAnimWidth, SET_WITH_ANIM);
int size = roomStream->size();
byte *roomBuf = (byte *)malloc(size);
roomStream->seek(0, 0);
roomStream->read(roomBuf, size);
s.syncBytes(roomBuf, size);
free(roomBuf);
}
if (s.isLoading()) {
int size = g_engine->_rooms->size();
delete (g_engine->_rooms);
byte *roomBuf = (byte *)malloc(size);
s.syncBytes(roomBuf, size);
g_engine->_rooms = new Common::MemorySeekableReadWriteStream(roomBuf, size, DisposeAfterUse::NO);
}
return true;
}
bool syncConversationData(Common::Serializer &s, Common::MemorySeekableReadWriteStream *conversations) {
int size = conversations->size();
if (s.isSaving()) {
byte *convBuf = (byte *)malloc(size);
conversations->seek(0, 0);
conversations->read(convBuf, size);
s.syncBytes(convBuf, size);
free(convBuf);
}
if (s.isLoading()) {
delete (g_engine->_conversationData);
byte *convBuf = (byte *)malloc(size);
s.syncBytes(convBuf, size);
g_engine->_conversationData = new Common::MemorySeekableReadWriteStream(convBuf, size, DisposeAfterUse::NO);
}
return true;
}
bool syncItemData(Common::Serializer &s, Common::MemorySeekableReadWriteStream *sceneObjects) {
int size = sceneObjects->size();
if (s.isSaving()) {
byte *objBuf = (byte *)malloc(size);
sceneObjects->seek(0, 0);
sceneObjects->read(objBuf, size);
s.syncBytes(objBuf, size);
free(objBuf);
}
if (s.isLoading()) {
delete (g_engine->_sceneObjectsData);
byte *objBuf = (byte *)malloc(size);
s.syncBytes(objBuf, size);
g_engine->_sceneObjectsData = new Common::MemorySeekableReadWriteStream(objBuf, size, DisposeAfterUse::NO);
}
return true;
}
Common::Error syncSaveData(Common::Serializer &ser, SavedGame *game) {
if (!syncGeneralData(ser, game)) {
warning("Error while synchronizing general data");
return Common::kUnknownError;
}
if (!syncRoomData(ser, g_engine->_rooms)) {
warning("Error while synchronizing room data");
return Common::kUnknownError;
}
if (!syncItemData(ser, g_engine->_sceneObjectsData)) {
warning("Error while syncrhonizing object data");
return Common::kUnknownError;
}
if (!syncConversationData(ser, g_engine->_conversationData)) {
warning("Error while syncrhonizing conversation data");
return Common::kUnknownError;
}
if (ser.err()) {
warning("Error while synchronizing");
return Common::kUnknownError;
}
return Common::kNoError;
}
Common::Error TotEngine::syncGame(Common::Serializer &s) {
Common::Error result;
if (s.isLoading()) {
SavedGame *loadedGame = new SavedGame();
// Means we are loading from before the game has started
// if(rooms == nullptr) {
_graphics->clear();
displayLoading();
loadCharAnimation();
loadInventory();
_graphics->loadPaletteFromFile("DEFAULT");
initScreenPointers();
_graphics->totalFadeOut(0);
_graphics->clear();
initializeScreenFile();
initializeObjectFile();
readConversationFile();
result = syncSaveData(s, loadedGame);
loadGame(loadedGame);
} else {
SavedGame *saveGame = saveGameToRegister();
result = syncSaveData(s, saveGame);
free(saveGame);
}
return result;
}
Common::Error TotEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
const byte version = SAVEGAME_CURRENT_VERSION;
Common::Serializer s(nullptr, stream);
s.setVersion(version);
stream->writeByte(version);
return syncGame(s);
}
Common::Error TotEngine::loadGameStream(Common::SeekableReadStream *stream) {
byte version = stream->readByte();
if (version > SAVEGAME_CURRENT_VERSION) {
GUI::MessageDialog dialog(_("Saved game was created with a newer version of ScummVM. Unable to load."));
dialog.runModal();
return Common::kUnknownError;
}
Common::Serializer s(stream, nullptr);
s.setVersion(version);
return syncGame(s);
}
bool TotEngine::canLoadGameStateCurrently(Common::U32String *msg) {
return true;
}
bool TotEngine::canSaveGameStateCurrently(Common::U32String *msg) {
return _inGame && _saveAllowed;
}
SavedGame *TotEngine::saveGameToRegister() {
SavedGame *_savedGame = new SavedGame();
_savedGame->roomCode = _currentRoomData->code;
_savedGame->trajectoryLength = _trajectoryLength;
_savedGame->currentTrajectoryIndex = _currentTrajectoryIndex;
_savedGame->backpackObjectCode = _backpackObjectCode;
_savedGame->rightSfxVol = _sound->_rightSfxVol;
_savedGame->leftSfxVol = _sound->_leftSfxVol;
_savedGame->musicVolRight = _sound->_musicVolRight;
_savedGame->musicVolLeft = _sound->_musicVolLeft;
_savedGame->oldGridX = _oldGridX;
_savedGame->oldGridY = _oldGridY;
_savedGame->secAnimDepth = _secondaryAnimation.depth;
_savedGame->secAnimDir = _secondaryAnimation.dir;
_savedGame->secAnimX = _secondaryAnimation.posx;
_savedGame->secAnimY = _secondaryAnimation.posy;
_savedGame->secAnimIFrame = _iframe2;
_savedGame->currentZone = _currentZone;
_savedGame->targetZone = _targetZone;
_savedGame->oldTargetZone = _oldTargetZone;
_savedGame->inventoryPosition = _inventoryPosition;
_savedGame->actionCode = _actionCode;
_savedGame->oldActionCode = _oldActionCode;
_savedGame->steps = _trajectorySteps;
_savedGame->doorIndex = _doorIndex;
_savedGame->characterFacingDir = _charFacingDirection;
_savedGame->iframe = _iframe;
_savedGame->gamePart = _gamePart;
_savedGame->isSealRemoved = _isSealRemoved;
_savedGame->obtainedList1 = _obtainedList1;
_savedGame->obtainedList2 = _obtainedList2;
_savedGame->list1Complete = _list1Complete;
_savedGame->list2Complete = _list2Complete;
_savedGame->isVasePlaced = _isVasePlaced;
_savedGame->isScytheTaken = _isScytheTaken;
_savedGame->isTridentTaken = _isTridentTaken;
_savedGame->isPottersWheelDelivered = _isPottersWheelDelivered;
_savedGame->isMudDelivered = _isMudDelivered;
_savedGame->isGreenDevilDelivered = _isGreenDevilDelivered;
_savedGame->isRedDevilCaptured = _isRedDevilCaptured;
_savedGame->isPottersManualDelivered = _isPottersManualDelivered;
_savedGame->isCupboardOpen = _isCupboardOpen;
_savedGame->isChestOpen = _isChestOpen;
_savedGame->isTVOn = _isTVOn;
_savedGame->isTrapSet = _isTrapSet;
for (int i = 0; i < kInventoryIconCount; i++) {
_savedGame->mobj[i].bitmapIndex = _inventory[i].bitmapIndex;
_savedGame->mobj[i].code = _inventory[i].code;
_savedGame->mobj[i].objectName = _inventory[i].objectName;
}
_savedGame->element1 = _element1;
_savedGame->element2 = _element2;
_savedGame->characterPosX = _characterPosX;
_savedGame->characterPosY = _characterPosY;
_savedGame->xframe2 = _xframe2;
_savedGame->yframe2 = _yframe2;
_savedGame->oldInventoryObjectName = _oldInventoryObjectName;
_savedGame->objetomoinventoryObjectNamehila = _inventoryObjectName;
_savedGame->characterName = _characterName;
for (int i = 0; i < kRoutePointCount; i++) {
_savedGame->mainRoute[i].x = _mainRoute[i].x;
_savedGame->mainRoute[i].y = _mainRoute[i].y;
}
for (int i = 0; i < 300; i++) {
_savedGame->trajectory[i].x = _trajectory[i].x;
_savedGame->trajectory[i].y = _trajectory[i].y;
}
for (int i = 0; i < kCharacterCount; i++) {
_savedGame->firstTimeTopicA[i] = _firstTimeTopicA[i];
_savedGame->firstTimeTopicB[i] = _firstTimeTopicB[i];
_savedGame->firstTimeTopicC[i] = _firstTimeTopicC[i];
_savedGame->bookTopic[i] = _bookTopic[i];
_savedGame->mintTopic[i] = _mintTopic[i];
}
for (int i = 0; i < 5; i++) {
_savedGame->caves[i] = _caves[i];
_savedGame->firstList[i] = _firstList[i];
_savedGame->secondList[i] = _secondList[i];
}
for (int i = 0; i < 4; i++) {
_savedGame->niche[0][i] = _niche[0][i];
_savedGame->niche[1][i] = _niche[1][i];
}
return _savedGame;
}
void TotEngine::loadGame(SavedGame *game) {
clearAnimation();
clearScreenLayers();
_trajectoryLength = game->trajectoryLength;
_currentTrajectoryIndex = game->currentTrajectoryIndex;
_backpackObjectCode = game->backpackObjectCode;
_sound->_rightSfxVol = game->rightSfxVol;
_sound->_leftSfxVol = game->leftSfxVol;
_sound->_musicVolRight = game->musicVolRight;
_sound->_musicVolLeft = game->musicVolLeft;
_oldGridX = game->oldGridX;
_oldGridY = game->oldGridY;
_secondaryAnimation.depth = game->secAnimDepth;
_secondaryAnimation.dir = game->secAnimDir;
_secondaryAnimation.posx = game->secAnimX;
_secondaryAnimation.posy = game->secAnimY;
_iframe2 = game->secAnimIFrame;
_currentZone = game->currentZone;
_targetZone = game->targetZone;
_oldTargetZone = game->oldTargetZone;
_inventoryPosition = game->inventoryPosition;
_actionCode = game->actionCode;
_oldActionCode = game->oldActionCode;
_trajectorySteps = game->steps;
_doorIndex = game->doorIndex;
_charFacingDirection = game->characterFacingDir;
_iframe = game->iframe;
if (game->gamePart != _gamePart) {
_gamePart = game->gamePart;
for (int i = 0; i < kInventoryIconCount; i++) {
free(_inventoryIconBitmaps[i]);
}
loadInventory();
}
_isSealRemoved = game->isSealRemoved;
_obtainedList1 = game->obtainedList1;
_obtainedList2 = game->obtainedList2;
_list1Complete = game->list1Complete;
_list2Complete = game->list2Complete;
_isVasePlaced = game->isVasePlaced;
_isScytheTaken = game->isScytheTaken;
if (_cpCounter > 24)
showError(274);
_isTridentTaken = game->isTridentTaken;
_isPottersWheelDelivered = game->isPottersWheelDelivered;
_isMudDelivered = game->isMudDelivered;
_isGreenDevilDelivered = game->isGreenDevilDelivered;
_isRedDevilCaptured = game->isRedDevilCaptured;
_isPottersManualDelivered = game->isPottersManualDelivered;
_isCupboardOpen = game->isCupboardOpen;
_isChestOpen = game->isChestOpen;
_isTVOn = game->isTVOn;
_isTrapSet = game->isTrapSet;
for (int i = 0; i < kInventoryIconCount; i++) {
_inventory[i].bitmapIndex = game->mobj[i].bitmapIndex;
_inventory[i].code = game->mobj[i].code;
_inventory[i].objectName = game->mobj[i].objectName;
}
_element1 = game->element1;
_element2 = game->element2;
_characterPosX = game->characterPosX;
_characterPosY = game->characterPosY;
_xframe2 = game->xframe2;
_yframe2 = game->yframe2;
_oldInventoryObjectName = game->oldInventoryObjectName;
_inventoryObjectName = game->objetomoinventoryObjectNamehila;
_characterName = game->characterName;
for (int i = 0; i < kRoutePointCount; i++) {
_mainRoute[i].x = game->mainRoute[i].x;
_mainRoute[i].y = game->mainRoute[i].y;
}
for (int indiaux = 0; indiaux < 300; indiaux++) {
_trajectory[indiaux].x = game->trajectory[indiaux].x;
_trajectory[indiaux].y = game->trajectory[indiaux].y;
}
for (int i = 0; i < kCharacterCount; i++) {
_firstTimeTopicA[i] = game->firstTimeTopicA[i];
_firstTimeTopicB[i] = game->firstTimeTopicB[i];
_firstTimeTopicC[i] = game->firstTimeTopicC[i];
_bookTopic[i] = game->bookTopic[i];
_mintTopic[i] = game->mintTopic[i];
}
for (int i = 0; i < 5; i++) {
_caves[i] = game->caves[i];
_firstList[i] = game->firstList[i];
_secondList[i] = game->secondList[i];
}
for (int i = 0; i < 4; i++) {
_niche[0][i] = game->niche[0][i];
_niche[1][i] = game->niche[1][i];
}
_graphics->totalFadeOut(0);
_screen->clear();
_graphics->loadPaletteFromFile("DEFAULT");
loadScreenData(game->roomCode);
switch (_currentRoomData->code) {
case 2: {
if (_isTVOn)
_sound->autoPlayVoc("PARASITO", 355778, 20129);
else
loadTV();
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
} break;
case 4: {
_sound->loadVoc("GOTA", 140972, 1029);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
} break;
case 5: {
_sound->setSfxVolume(_sound->_leftSfxVol, 0);
_sound->autoPlayVoc("CALDERA", 6433, 15386);
} break;
case 6: {
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
_sound->autoPlayVoc("CALDERA", 6433, 15386);
} break;
case 17: {
if (_bookTopic[0] == true && _currentRoomData->animationFlag)
disableSecondAnimation();
} break;
case 20: {
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;
}
} break;
case 23: {
_sound->autoPlayVoc("Fuente", 0, 0);
_sound->setSfxVolume(_sound->_leftSfxVol, _sound->_rightSfxVol);
} break;
case 24: {
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 (_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();
} break;
}
drawInventoryMask();
_inventoryPosition = 0;
drawInventory();
if (_isRedDevilCaptured == false && _currentRoomData->code == 24 && _isTrapSet == false)
runaroundRed();
_graphics->sceneTransition(false, _sceneBackground);
_saveAllowed = true;
}
const int kMaxSaveSlots = 100;
Common::String drawAndSelectSaves(int pageNumber, const Common::HashMap<int, SaveStateDescriptor> &saveMap, uint selectedSlot) {
g_engine->_mouse->hide();
const char *availableText = getHardcodedTextsByCurrentLanguage()[11];
ExtendedSavegameHeader header;
int selectedGame = selectedSlot + pageNumber * 6;
Common::String selectedGameDesc = "";
for (uint i = 0; i < 6; i++) {
int saveSlot = i + pageNumber * 6;
int color = saveSlot == selectedGame ? 255 : 253;
bar(60, 31 + (i * 15), 259, 39 + (i * 15), 251);
if (saveSlot >= kMaxSaveSlots) {
continue;
;
}
Common::String desc = "";
if (saveMap.contains(saveSlot)) {
desc = saveMap[saveSlot].getDescription();
if (saveSlot == selectedGame) {
selectedGameDesc = saveMap[saveSlot].getDescription();
}
}
if (desc.empty() == false) {
euroText(65, 29 + (i * 15), desc, color);
} else {
euroText(65, 29 + (i * 15), Common::String::format(availableText, saveSlot), color);
}
}
g_engine->_mouse->show();
return selectedGameDesc;
}
void TotEngine::originalSaveLoadScreen() {
uint oldMouseX, oldMouseY;
int selectedSlot = 1;
bool modified = false;
Common::String saveName = "";
bool exitSaveLoadMenu = false;
oldMouseX = _mouse->mouseX;
oldMouseY = _mouse->mouseY;
_mouse->hide();
uint menuBgSize = imagesize(20, 10, 300, 120);
byte *menuBgPointer = (byte *)malloc(menuBgSize);
_graphics->getImg(20, 10, 300, 120, menuBgPointer);
for (int i = 0; i < 6; i++) {
uint textY = i + 1;
buttonBorder((120 - (textY * 10)), (80 - (textY * 10)), (200 + (textY * 10)), (60 + (textY * 10)), 251, 251, 251, 251, 0);
}
drawMenu(2); // 220 x 110 at xmenu = 50;ymenu = 10;
// 50, 10, 270, 120
// Arrows are 20, 18
drawLeftArrow(20, 65);
line(20, 65, 39, 65, 255);
line(20, 65, 20, 80, 255);
line(40, 66, 40, 82, 249);
line(40, 82, 21, 82, 249);
drawRightArrow(280, 65);
line(280, 65, 299, 65, 255);
line(280, 65, 280, 80, 255);
line(300, 66, 300, 82, 249);
line(300, 82, 292, 82, 249);
if (!_saveAllowed) {
bar(61, 15, 122, 23, 253);
bar(201, 15, 259, 23, 253);
}
int pageNumber = 0;
SaveStateList listSaves = getMetaEngine()->listSaves(_targetName.c_str());
Common::HashMap<int, SaveStateDescriptor> saveMap;
// Iterate and populate
for (const SaveStateDescriptor &desc : listSaves) {
int slot = desc.getSaveSlot();
saveMap[slot] = desc;
}
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
if (_cpCounter2 > 17)
showError(274);
_mouse->mouseX = 150;
_mouse->mouseY = 60;
_mouse->mouseMaskIndex = 1;
_mouse->setMouseArea(Common::Rect(13, 13, 293, 105));
_mouse->warpMouse(1, 150, 60);
do {
bool mouseClicked = false;
bool keyPressed = false;
Common::Event lastKeyboardEvent = Common::Event();
do {
_chrono->updateChrono();
if (_chrono->_gameTick) {
_mouse->animateMouseIfNeeded();
}
_events->pollEvent();
if (_events->_leftMouseButton || _events->_rightMouseButton) {
mouseClicked = true;
} else if (_events->_keyPressed) {
keyPressed = true;
lastKeyboardEvent = _events->_lastKeyEvent;
}
_screen->update();
g_system->delayMillis(10);
} while (!keyPressed && !mouseClicked && !shouldQuit());
if (mouseClicked) {
if (_mouse->mouseX > 13 && _mouse->mouseX < 33 && _mouse->mouseY >= 58 && _mouse->mouseY <= 73) { // Left arrow
if (pageNumber > 0)
pageNumber--;
else
_sound->beep(100, 300);
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
} else if (_mouse->mouseX > 273 && _mouse->mouseX < 293 && _mouse->mouseY >= 58 && _mouse->mouseY <= 73) { // Right arrow
if (pageNumber < kMaxSaveSlots / 6)
pageNumber++;
else
_sound->beep(100, 300);
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
} else if (_mouse->mouseY >= 13 && _mouse->mouseY <= 16) {
if (_mouse->mouseX >= 54 && _mouse->mouseX <= 124) { // Save
if (selectedSlot > 0 && _saveAllowed && saveName != "") {
saveGameState(selectedSlot + pageNumber * 6, saveName, false);
_graphics->putImg(20, 10, menuBgPointer);
exitSaveLoadMenu = true;
selectedSlot = -1;
} else {
_sound->beep(100, 300);
}
} else if (_mouse->mouseX >= 130 && _mouse->mouseX <= 194) {
if (selectedSlot >= 0 && !modified) { // Load
if (selectedSlot < (int)listSaves.size()) {
_mouse->hide();
_graphics->putImg(20, 10, menuBgPointer);
free(menuBgPointer);
if (_saveAllowed) {
clearAnimation();
clearScreenLayers();
}
loadGameState(selectedSlot + pageNumber * 6);
_mouse->mouseX = oldMouseX;
_mouse->mouseY = oldMouseY;
_mouse->show();
_mouse->setMouseArea(Common::Rect(0, 0, 305, 185));
exitSaveLoadMenu = true;
selectedSlot = -1;
return;
} else {
_sound->beep(100, 300);
}
} else {
_sound->beep(100, 300);
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
_mouse->show();
}
} else if (_mouse->mouseClickX >= 200 && _mouse->mouseClickX <= 250) { // Exit
if (_inGame && _saveAllowed) {
_graphics->putImg(20, 10, menuBgPointer);
exitSaveLoadMenu = true;
selectedSlot = -1;
} else {
_sound->beep(100, 300);
}
}
} else {
if (_mouse->mouseClickY >= 24 && _mouse->mouseClickY <= 32) {
if (0 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 0;
modified = false;
}
} else if (_mouse->mouseClickY >= 39 && _mouse->mouseClickY <= 47) {
if (1 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 1;
modified = false;
}
} else if (_mouse->mouseClickY >= 54 && _mouse->mouseClickY <= 62) {
if (2 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 2;
modified = false;
}
} else if (_mouse->mouseClickY >= 69 && _mouse->mouseClickY <= 77) {
if (3 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 3;
modified = false;
}
} else if (_mouse->mouseClickY >= 84 && _mouse->mouseClickY <= 92) {
if (4 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 4;
modified = false;
}
} else if (_mouse->mouseClickY >= 99 && _mouse->mouseClickY <= 107) {
if (5 + pageNumber * 6 >= kMaxSaveSlots) {
_sound->beep(100, 300);
} else {
selectedSlot = 5;
modified = false;
}
}
saveName = drawAndSelectSaves(pageNumber, saveMap, selectedSlot);
}
}
if (keyPressed && _saveAllowed) {
_mouse->hide();
byte ytext = 29 + (selectedSlot * 15);
readAlphaGraphSmall(saveName, 30, 65, ytext, 251, 254, lastKeyboardEvent);
modified = true;
_mouse->show();
keyPressed = false;
}
} while (!exitSaveLoadMenu && !shouldQuit());
_mouse->mouseX = oldMouseX;
_mouse->mouseY = oldMouseY;
_mouse->warpMouse(_mouse->mouseMaskIndex, _mouse->mouseX, _mouse->mouseY);
free(menuBgPointer);
_mouse->setMouseArea(Common::Rect(0, 0, 305, 185));
}
} // End of namespace Tot