scummvm/engines/cryomni3d/versailles/saveload.cpp
Le Philousophe 38bead0c37 JANITORIAL/CRYOMNI3D: Fix warnings in MSVC
Most of them were due to setting -1 to unsigned values
Else it was bogus unintialized values
2019-06-30 16:46:32 +02:00

310 lines
9.1 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 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/archive.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/system.h"
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
Common::Error CryOmni3DEngine_Versailles::loadGameState(int slot) {
_loadedSave = slot + 1;
_abortCommand = kAbortLoadGame;
return Common::kNoError;
}
Common::Error CryOmni3DEngine_Versailles::saveGameState(int slot, const Common::String &desc) {
saveGame(_isVisiting, slot + 1, desc);
return Common::kNoError;
}
Common::String CryOmni3DEngine_Versailles::getSaveFileName(bool visit, uint saveNum) const {
return Common::String::format("%s%s.%04u", _targetName.c_str(), visit ? "_visit" : "", saveNum);
}
bool CryOmni3DEngine_Versailles::canVisit() const {
// Build a custom SearchSet
const Common::FSNode gameDataDir(ConfMan.get("path"));
Common::SearchSet visitsSearchSet;
visitsSearchSet.addSubDirectoryMatching(gameDataDir, "savegame/visite", 1);
return visitsSearchSet.hasFile("game0001.sav");
}
void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &saveNames) {
char saveName[kSaveDescriptionLen + 1];
saveName[kSaveDescriptionLen] = '\0';
Common::String pattern = Common::String::format("%s%s.????", _targetName.c_str(),
visit ? "_visit" : "");
Common::StringArray filenames = _saveFileMan->listSavefiles(pattern);
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
saveNames.clear();
saveNames.reserve(100);
int num = 1;
int slotNum;
if (visit) {
// Add bootstrap visit
const Common::FSNode gameDataDir(ConfMan.get("path"));
Common::SearchSet visitsSearchSet;
visitsSearchSet.addSubDirectoryMatching(gameDataDir, "savegame/visite", 1);
if (visitsSearchSet.hasFile("game0001.sav")) {
Common::File visitFile;
if (!visitFile.open("game0001.sav", visitsSearchSet)) {
error("Can't load visit file");
}
visitFile.read(saveName, kSaveDescriptionLen);
saveNames.push_back(saveName);
} else {
warning("visiting mode but no bootstrap");
// No bootstrap visit, too bad
saveNames.push_back(_messages[55]); //Fill with free slot
}
num++;
}
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end();
++file) {
// Obtain the last 4 digits of the filename, since they correspond to the save slot
slotNum = atoi(file->c_str() + file->size() - 4);
if (slotNum >= 1 && slotNum <= 99) {
while (num < slotNum) {
saveNames.push_back(_messages[55]); //Fill with free slot
num++;
}
num++;
Common::InSaveFile *in = _saveFileMan->openForLoading(*file);
if (in) {
if (in->read(saveName, kSaveDescriptionLen) == kSaveDescriptionLen) {
saveNames.push_back(saveName);
}
delete in;
}
}
}
for (uint i = saveNames.size(); i < 100; i++) {
saveNames.push_back(_messages[55]);
}
}
void CryOmni3DEngine_Versailles::saveGame(bool visit, uint saveNum,
const Common::String &saveName) {
if (visit && saveNum == 1) {
error("Can't erase bootstrap visit");
}
Common::String saveFileName = getSaveFileName(visit, saveNum);
Common::OutSaveFile *out;
if (!(out = _saveFileMan->openForSaving(saveFileName))) {
return;
}
// Sync countdown to game variable before saving it to file
syncCountdown();
// Write save name
char saveNameC[kSaveDescriptionLen];
memset(saveNameC, 0, sizeof(saveNameC));
strncpy(saveNameC, saveName.c_str(), sizeof(saveNameC));
out->write(saveNameC, sizeof(saveNameC));
// dummy values
out->writeUint32LE(0);
out->writeUint32BE(0);
out->writeUint32BE(0);
// Dialog variables
assert(_dialogsMan.size() < 200);
for (uint i = 0; i < _dialogsMan.size(); i++) {
out->writeByte(_dialogsMan[i]);
}
for (uint i = _dialogsMan.size(); i < 200; i++) {
out->writeByte(0);
}
// Inventory
assert(_inventory.size() == 50);
for (Inventory::const_iterator it = _inventory.begin(); it != _inventory.end(); it++) {
uint objId = uint(-1);
if (*it != nullptr) {
// Inventory contains pointers to objects stored in _objects
objId = *it - _objects.begin();
}
out->writeUint32BE(objId);
}
// Offset of inventory in toolbar
out->writeUint32BE(_toolbar.inventoryOffset());
// Level, place, warp position
out->writeUint32BE(_currentLevel);
out->writeUint32BE(_currentPlaceId);
out->writeDoubleBE(_omni3dMan.getAlpha());
out->writeDoubleBE(_omni3dMan.getBeta());
// Places states
assert(_placeStates.size() <= 100);
Common::Array<PlaceState>::const_iterator placeIt = _placeStates.begin();
for (uint i = 0; placeIt != _placeStates.end(); placeIt++, i++) {
out->writeUint32BE(placeIt->state);
}
for (uint i = _placeStates.size(); i < 100; i++) {
out->writeUint32BE(0);
}
// Game variables
assert(_gameVariables.size() < 100);
for (Common::Array<uint>::const_iterator it = _gameVariables.begin();
it != _gameVariables.end(); it++) {
out->writeUint32BE(*it);
}
for (uint i = _gameVariables.size(); i < 100; i++) {
out->writeUint32BE(0);
}
out->finalize();
delete out;
}
bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
Common::SeekableReadStream *in;
if (visit && saveNum == 1) {
// Load bootstrap visit
const Common::FSNode gameDataDir(ConfMan.get("path"));
Common::SearchSet visitsSearchSet;
visitsSearchSet.addSubDirectoryMatching(gameDataDir, "savegame/visite", 1);
Common::File *visitFile = new Common::File();
if (!visitFile->open("game0001.sav", visitsSearchSet)) {
delete visitFile;
error("Can't load visit file");
}
in = visitFile;
} else {
Common::String saveFileName = getSaveFileName(visit, saveNum);
in = _saveFileMan->openForLoading(saveFileName);
}
if (!in || in->size() != 1260) {
return false;
}
musicStop();
// Load save name but don't use it
char saveNameC[kSaveDescriptionLen];
in->read(saveNameC, sizeof(saveNameC));
// dummy values
(void) in->readUint32LE();
(void) in->readUint32BE();
(void) in->readUint32BE();
// Dialog variables
assert(_dialogsMan.size() < 200);
for (uint i = 0; i < _dialogsMan.size(); i++) {
_dialogsMan[i] = in->readByte();
}
for (uint i = _dialogsMan.size(); i < 200; i++) {
// Read the remaining bytes but don't use them
(void) in->readByte();
}
// Inventory
assert(_inventory.size() == 50);
for (Inventory::iterator it = _inventory.begin(); it != _inventory.end(); it++) {
uint objId = in->readUint32BE();
if (objId >= _objects.size()) {
objId = uint(-1);
}
if (objId != uint(-1)) {
*it = _objects.begin() + objId;
} else {
*it = nullptr;
}
}
// Offset of inventory in toolbar
_toolbar.setInventoryOffset(in->readUint32BE());
// Level, place, warp position
_currentLevel = in->readUint32BE();
// Use nextPlace to force place move
_nextPlaceId = in->readUint32BE();
// Store alpha and beta for later use
double alpha = in->readDoubleBE();
double beta = in->readDoubleBE();
// Places states
// Store them and use them once we called initNewLevel, we can't call it before because it needs _gameVariables (and especially kCurrentTime) to be correctly set
uint32 placesStates[100];
for (uint i = 0; i < 100; i++) {
placesStates[i] = in->readUint32BE();
}
// Game variables
assert(_gameVariables.size() < 100);
for (Common::Array<uint>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
it++) {
*it = in->readUint32BE();
}
for (uint i = _gameVariables.size(); i < 100; i++) {
// Read the remaining variables but don't use them
(void) in->readUint32BE();
}
delete in;
if (_gameVariables[GameVariables::kCurrentTime] == 0) {
_gameVariables[GameVariables::kCurrentTime] = 1;
}
initCountdown();
// Everything has been loaded, setup new level
// We will set places states and warp coordinates just after that to avoid them from being reset
initNewLevel(_currentLevel);
_omni3dMan.setAlpha(alpha);
_omni3dMan.setBeta(beta);
// _placeStates has just been resized in initNewLevel
uint i = 0;
for (Common::Array<PlaceState>::iterator placeIt = _placeStates.begin();
placeIt != _placeStates.end() && i < ARRAYSIZE(placesStates); placeIt++, i++) {
placeIt->state = placesStates[i];
}
return true;
}
} // End of namespace Versailles
} // End of namespace CryOmni3D