HPL1: use standard naming scheme for saves

This commit is contained in:
grisenti 2022-08-23 15:52:22 +02:00 committed by Eugene Sandulenko
parent fa822ef0c2
commit 630623c997
No known key found for this signature in database
GPG Key ID: 014D387312D34F08
8 changed files with 85 additions and 53 deletions

View File

@ -195,22 +195,23 @@ bool cSerializeClass::SaveToFile(iSerializable *apData, const tWString &asFile,
glTabs = 0;
// FIXME: string types
Common::String filename(cString::To8Char(asFile).c_str());
Common::String saveDesc(cString::To8Char(asFile).c_str());
Common::String filename(Hpl1::g_engine->createSaveFile(saveDesc));
TiXmlDocument pXmlDoc;
// Create root
TiXmlElement XmlRoot(asRoot.c_str());
TiXmlElement *pRootElem = static_cast<TiXmlElement *>(pXmlDoc.InsertEndChild(XmlRoot));
Common::ScopedPtr<Common::OutSaveFile> savefile(g_engine->getSaveFileManager()->openForSaving(filename));
if (!savefile) {
Hpl1::logError(Hpl1::kDebugSaves, "could't open file %s for saving\n", asFile.c_str());
Hpl1::logError(Hpl1::kDebugSaves, "could't open file %s for saving\n", filename.c_str());
return false;
}
SaveToElement(apData, "", pRootElem);
if (!pXmlDoc.SaveFile(*savefile)) {
Hpl1::logError(Hpl1::kDebugSaves, "couldn't save to file '%s'\n", asFile.c_str());
Hpl1::logError(Hpl1::kDebugSaves, "couldn't save to file '%s'\n", filename.c_str());
return false;
}
g_engine->getMetaEngine()->appendExtendedSave(savefile.get(), g_engine->getTotalPlayTime(), "", filename.contains("auto"));
g_engine->getMetaEngine()->appendExtendedSave(savefile.get(), g_engine->getTotalPlayTime(), saveDesc, filename.contains("auto"));
return true;
}
@ -279,15 +280,15 @@ bool cSerializeClass::LoadFromFile(iSerializable *apData, const tWString &asFile
// Load document
TiXmlDocument pXmlDoc;
// FIXME: string types
Common::String filename(cString::To8Char(asFile).c_str());
Common::String filename(Hpl1::g_engine->mapInternalSaveToFile(cString::To8Char(asFile).c_str()));
Common::ScopedPtr<Common::InSaveFile> saveFile(g_engine->getSaveFileManager()->openForLoading(filename));
if (!saveFile) {
Hpl1::logError(Hpl1::kDebugSaves | Hpl1::kDebugResourceLoading, "save file %s could not be opened\n", filename.c_str());
return false;
}
ExtendedSavegameHeader header;
if (MetaEngine::readSavegameHeader(saveFile.get(), &header)) {
Hpl1::logError(Hpl1::kDebugResourceLoading | Hpl1::kDebugSaves, "couldn't load heaer from save file %s\n", filename.c_str());
if (!MetaEngine::readSavegameHeader(saveFile.get(), &header)) {
Hpl1::logError(Hpl1::kDebugResourceLoading | Hpl1::kDebugSaves, "couldn't load header from save file %s\n", filename.c_str());
return false;
}
g_engine->setTotalPlayTime(header.playtime);

View File

@ -30,6 +30,7 @@
#include "graphics/palette.h"
#include "hpl1/console.h"
#include "hpl1/detection.h"
#include "hpl1/debug.h"
extern int hplMain(const hpl::tString &asCommandLine);
@ -54,11 +55,58 @@ Common::String Hpl1Engine::getGameId() const {
return _gameDescription->gameId;
}
static void initSaves(const char *target, Common::BitArray &slots, Common::HashMap<Common::String, int> &savemap) {
slots.set_size(g_engine->getMetaEngine()->getMaximumSaveSlot());
SaveStateList saves = g_engine->getMetaEngine()->listSaves(target);
for (auto &s : saves) {
savemap.setVal(s.getDescription(), s.getSaveSlot());
slots.set(s.getSaveSlot());
}
}
Common::Error Hpl1Engine::run() {
initSaves(_targetName.c_str(), _saveSlots, _internalSaves);
hplMain("");
return Common::kNoError;
}
static int freeSaveSlot(Common::BitArray &slots, const int size) {
for (int i = 0; i < size; ++i) {
if (!slots.get(i))
return i;
}
return -1;
}
Common::String Hpl1Engine::createSaveFile(const Common::String &internalName) {
const int freeSlot = freeSaveSlot(_saveSlots, getMetaEngine()->getMaximumSaveSlot());
if (freeSlot == -1) {
warning("game out of save slots");
return "";
}
_saveSlots.set(freeSlot);
_internalSaves.setVal(internalName, freeSlot);
return getSaveStateName(freeSlot);
}
Common::String Hpl1Engine::mapInternalSaveToFile(const Common::String &internalName) {
const int slot = _internalSaves.getValOrDefault(internalName, -1);
if (slot == -1) {
logError(Hpl1::kDebugLevelError, "trying to map invalid save name: %s\n", internalName.c_str());
return "";
}
return getSaveStateName(slot);
}
Common::StringArray Hpl1Engine::listInternalSaves(const Common::String &pattern) {
Common::StringArray saves;
for(auto &kv : _internalSaves) {
if (kv._key.matchString(pattern))
saves.push_back(kv._key);
}
return saves;
}
Common::Error Hpl1Engine::syncGame(Common::Serializer &s) {
// The Serializer has methods isLoading() and isSaving()
// if you need to specific steps; for example setting

View File

@ -33,6 +33,7 @@
#include "engines/engine.h"
#include "engines/savestate.h"
#include "graphics/screen.h"
#include "common/bitarray.h"
#include "hpl1/detection.h"
@ -44,6 +45,8 @@ class Hpl1Engine : public Engine {
private:
const ADGameDescription *_gameDescription;
Common::RandomSource _randomSource;
Common::HashMap<Common::String, int> _internalSaves;
Common::BitArray _saveSlots;
protected:
// Engine APIs
@ -84,6 +87,12 @@ public:
return true;
}
Common::String createSaveFile(const Common::String &internalName);
Common::String mapInternalSaveToFile(const Common::String &internalName);
Common::StringArray listInternalSaves(const Common::String &pattern);
/**
* Uses a serializer to allow implementing savegame
* loading and saving using a single method

View File

@ -59,26 +59,6 @@ void Hpl1MetaEngine::getSavegameThumbnail(Graphics::Surface &thumbnail) {
scaledScreen->free();
}
static Common::U32String formatSave(const Common::String &filename) {
const int begin = filename.findFirstOf('.') + 1;
const int len = filename.findLastOf('_') - begin;
Common::String name = filename.substr(begin, len);
Common::replace(name.begin(), name.end(), '.', ':');
Common::replace(name.begin(), name.end(), '_', ' ');
return name;
}
SaveStateList Hpl1MetaEngine::listSaves(const char *target) const {
SaveStateList saveList;
Common::StringArray filenames = g_system->getSavefileManager()->listSavefiles("hpl1-po-????.*");
int i = 0;
for (auto &save : filenames) {
if (!save.contains("favourite"))
saveList.push_back(SaveStateDescriptor(this, ++i, formatSave(save)));
}
return saveList;
}
Common::Action *createKeyBoardAction(const char *id, const Common::U32String &desc, const char *defaultMap, const Common::KeyState &key) {
Common::Action *act = new Common::Action(id, desc);
act->setKeyEvent(key);

View File

@ -37,8 +37,6 @@ public:
*/
bool hasFeature(MetaEngineFeature f) const override;
SaveStateList listSaves(const char *target) const override;
void getSavegameThumbnail(Graphics::Surface &thumbnail) override;
Common::Array<Common::Keymap *> initKeymaps(const char *target) const override;

View File

@ -104,7 +104,7 @@ void cDeathMenuButton::OnMouseOver(bool abOver) {
//-----------------------------------------------------------------------
void cDeathMenuButton_Continue::OnMouseDown() {
tWString save = mpInit->mpSaveHandler->GetLatest(_W("hpl1-po-????.*.sav"));
tWString save = mpInit->mpSaveHandler->GetLatest(_W("????:*"));
if (save != _W(""))
mpInit->mpSaveHandler->LoadGameFromFile(save);
}
@ -301,7 +301,7 @@ void cDeathMenu::SetActive(bool abX) {
STLDeleteAll(mlstButtons);
// Continue
tWString latestSave = mpInit->mpSaveHandler->GetLatest(_W("hpl1-po-????.*.sav"));
tWString latestSave = mpInit->mpSaveHandler->GetLatest(_W("????:*"));
if (latestSave != _W("")) {
mlstButtons.push_back(hplNew(cDeathMenuButton_Continue, (mpInit, cVector2f(400, 290), kTranslate("DeathMenu", "Continue"))));
}

View File

@ -634,7 +634,7 @@ void cMainMenuWidget_Continue::OnMouseDown(eMButton aButton) {
mpInit->mpMainMenu->SetActive(false);
tWString latestSave = mpInit->mpSaveHandler->GetLatest(_W("hpl1-po-????.*.sav"));
tWString latestSave = mpInit->mpSaveHandler->GetLatest(_W("????:*"));
if (latestSave != _W(""))
mpInit->mpSaveHandler->LoadGameFromFile(latestSave);
}
@ -784,9 +784,11 @@ public:
return;
tWString originalName = gvSaveGameFileVec[mlNum][lSelected];
tWString newName = _W("save-favorite.") + cString::SubW(originalName, originalName.find_first_of('.') + 1);
tWString newName = _W("favorite-") + cString::SubW(originalName, originalName.find_first_of('.') + 1);
Hpl1::logInfo(Hpl1::kDebugSaves, "adding save %s to favourites\n", cString::To8Char(newName).c_str());
g_engine->getSaveFileManager()->copySavefile(cString::To8Char(originalName).c_str(), cString::To8Char(newName).c_str());
Common::String originalFile(Hpl1::g_engine->mapInternalSaveToFile(cString::To8Char(originalName).c_str()));
Common::String newFile(Hpl1::g_engine->createSaveFile(cString::To8Char(newName).c_str()));
g_engine->getSaveFileManager()->copySavefile(originalFile, newFile);
mpInit->mpMainMenu->UpdateWidgets();
}
@ -2480,7 +2482,7 @@ void cMainMenu::CreateWidgets() {
AddWidgetToState(eMainMenuState_Start, hplNew(cMainMenuWidget_Resume, (mpInit, vPos, kTranslate("MainMenu", "Resume"))));
vPos.y += 60;
} else {
tWString latestSave = mpInit->mpSaveHandler->GetLatest(_W("hpl1-po-????.*.sav"));
tWString latestSave = mpInit->mpSaveHandler->GetLatest(_W("????:*"));
if (latestSave != _W("")) {
AddWidgetToState(eMainMenuState_Start, hplNew(cMainMenuWidget_MainButton, (mpInit, vPos, kTranslate("MainMenu", "Continue"), eMainMenuState_Continue)));
@ -2577,18 +2579,18 @@ void cMainMenu::CreateWidgets() {
vPos.y += 46 + 30;
vPos.x += 15;
tWString sDir = _W("hpl1-po-spot");
tWString sDir = _W("spot:");
if (i == 1)
sDir = _W("hpl1-po-auto");
sDir = _W("auto:");
else if (i == 2)
sDir = _W("hpl1-po-favorite");
sDir = _W("favorite:");
gpSaveGameList[i] = hplNew(cMainMenuWidget_SaveGameList, (
mpInit, vPos, cVector2f(355, 170), 15, sDir, (int)i));
AddWidgetToState(state, gpSaveGameList[i]);
tTempFileAndDataSet setTempFiles;
Common::StringArray saves = g_engine->getSaveFileManager()->listSavefiles( cString::To8Char(sDir).c_str() + Common::String("*.sav"));
Common::StringArray saves = Hpl1::g_engine->listInternalSaves(cString::To8Char(sDir).c_str() + Common::String("*"));
for (auto &s : saves) {
tWString sFile = cString::To16Char(s.c_str());
cDate date = cSaveHandler::parseDate(s);
@ -2605,13 +2607,7 @@ void cMainMenu::CreateWidgets() {
gvSaveGameFileVec[i].push_back(sFile);
sFile = cString::SetFileExtW(sFile, _W(""));
sFile = cString::SubW(sFile, sFile.find_first_of(_W(".")) + 1);
sFile = cString::SubW(sFile, 0, (int)sFile.length() - 3);
sFile = cString::ReplaceCharToW(sFile, _W("_"), _W(" "));
sFile = cString::ReplaceCharToW(sFile, _W("."), _W(":"));
// TODO: PROBLEM!!!
sFile = cString::SubW(sFile, sFile.find_first_of(_W(":")) + 1);
gpSaveGameList[i]->AddEntry(sFile);
// gpSaveGameList[i]->AddEntry(sFile);
}

View File

@ -610,7 +610,7 @@ void cSaveHandler::AutoSave(const tWString &asDir, int alMaxSaves) {
sMapName = cString::ReplaceCharToW(sMapName, _W(":"), _W(" "));
cDate date = mpInit->mpGame->GetSystem()->GetLowLevel()->getDate();
wchar_t sTemp[512];
swprintf(sTemp, 512, _W("hpl1-po-%ls.%ls %d-%02d-%02d_%02d.%02d.%02d_%02d.sav"),
swprintf(sTemp, 512, _W("%ls: %ls %d-%02d-%02d %02d:%02d:%02d"),
asDir.c_str(),
sMapName.c_str(),
date.year,
@ -618,8 +618,7 @@ void cSaveHandler::AutoSave(const tWString &asDir, int alMaxSaves) {
date.month_day,
date.hours,
date.minutes,
date.seconds,
cMath::RandRectl(0, 99));
date.seconds);
tWString sFile = sTemp;
SaveGameToFile(sFile);
@ -629,7 +628,7 @@ void cSaveHandler::AutoSave(const tWString &asDir, int alMaxSaves) {
//-----------------------------------------------------------------------
void cSaveHandler::AutoLoad(const tWString &asDir) {
tWString latestSave = GetLatest(_W("hpl1-po-") + asDir + _W(".*.sav"));
tWString latestSave = GetLatest( asDir + _W(":*"));
LoadGameFromFile(latestSave);
mpInit->mpGame->ResetLogicTimer();
}
@ -700,14 +699,15 @@ void cSaveHandler::DeleteOldestIfMax(const tWString &asDir, const tWString &asMa
cDate cSaveHandler::parseDate(const Common::String &saveFile) {
cDate date;
Common::String strDate = saveFile.substr(saveFile.findLastOf(" "));
sscanf(strDate.c_str(), "%d-%d-%d_%d.%d.%d.sav", &date.year, &date.month, &date.month_day, &date.hours, &date.minutes, &date.seconds);
auto firstDigit = Common::find_if(saveFile.begin(), saveFile.end(), Common::isDigit);
Common::String strDate = saveFile.substr(Common::distance(saveFile.begin(), firstDigit));
sscanf(strDate.c_str(), "%d-%d-%d %d:%d:%d", &date.year, &date.month, &date.month_day, &date.hours, &date.minutes, &date.seconds);
return date;
}
tWString cSaveHandler::GetLatest(const tWString &asMask) {
// FIXME: string types
Common::StringArray saves = g_engine->getSaveFileManager()->listSavefiles(cString::To8Char(asMask).c_str());
Common::StringArray saves = Hpl1::g_engine->listInternalSaves(cString::To8Char(asMask).c_str());
if (saves.empty())
return _W("");
cDate latestDate = parseDate(saves.front());