From fc4e1ffcdfed24fb22618fe1ccdb72ff2c5728e8 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 11 Feb 2017 17:20:12 +0100 Subject: [PATCH] - separated the savegame menu code into an internal class managing the savegame data and the actual menu. The manager class cannot be scriptified because it provides the internal implementation which may change at some point in the future. It also encapsulates all access to the file level because if that part is not protected, modders could write malware mods. --- src/g_game.cpp | 2 +- src/menu/loadsavemenu.cpp | 693 +++++++++++++++++++------------------- src/menu/menu.h | 32 +- src/menu/menudef.cpp | 2 +- src/menu/messagebox.cpp | 19 +- 5 files changed, 392 insertions(+), 356 deletions(-) diff --git a/src/g_game.cpp b/src/g_game.cpp index 9417f40b9..44c727b72 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -2307,7 +2307,7 @@ void G_DoSaveGame (bool okForQuicksave, FString filename, const char *descriptio WriteZip(filename, savegame_filenames, savegame_content); - M_NotifyNewSave (filename.GetChars(), description, okForQuicksave); + savegameManager.NotifyNewSave (filename.GetChars(), description, okForQuicksave); // delete the JSON buffers we created just above. Everything else will // either still be needed or taken care of automatically. diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 8d9dc15e9..74c943480 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2001-2010 Randy Heit -** Copyright 2010 Christoph Oelckers +** Copyright 2010-2017 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -50,116 +50,47 @@ #include "resourcefiles/resourcefile.h" - - -class DLoadSaveMenu : public DListMenu -{ - DECLARE_CLASS(DLoadSaveMenu, DListMenu) - friend void ClearSaveGames(); - -protected: - static TArray SaveGames; - static int LastSaved; - static int LastAccessed; - - int Selected; - int TopItem; - - - int savepicLeft; - int savepicTop; - int savepicWidth; - int savepicHeight; - - int rowHeight; - int listboxLeft; - int listboxTop; - int listboxWidth; - - int listboxRows; - int listboxHeight; - int listboxRight; - int listboxBottom; - - int commentLeft; - int commentTop; - int commentWidth; - int commentHeight; - int commentRight; - int commentBottom; - - // this needs to be kept in memory so that the texture can access it when it needs to. - FileReader *currentSavePic; - TArray SavePicData; - - - static int InsertSaveNode (FSaveGameNode *node); - static void ReadSaveStrings (); - - - FTexture *SavePic; - FBrokenLines *SaveComment; - bool mEntering; - char savegamestring[SAVESTRINGSIZE]; - - DLoadSaveMenu(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); - void OnDestroy() override; - - int RemoveSaveSlot (int index); - void UnloadSaveData (); - void ClearSaveStuff (); - void ExtractSaveData (int index); - void Drawer (); - bool MenuEvent (int mkey, bool fromcontroller); - bool MouseEvent(int type, int x, int y); - bool Responder(event_t *ev); - -public: - static void NotifyNewSave (const char *file, const char *title, bool okForQuicksave); - -}; - -IMPLEMENT_CLASS(DLoadSaveMenu, false, false) - -TArray DLoadSaveMenu::SaveGames; -int DLoadSaveMenu::LastSaved = -1; -int DLoadSaveMenu::LastAccessed = -1; - -FSaveGameNode *quickSaveSlot; - //============================================================================= // -// Save data maintenance (stored statically) +// This should remain native because exposing 'remove' would allow +// the creation of actual malware mods! // //============================================================================= -void ClearSaveGames() +void SavegameManager::DeleteEntry(int Selected) { - for(unsigned i=0;ibNoDelete) - delete DLoadSaveMenu::SaveGames[i]; - } - DLoadSaveMenu::SaveGames.Clear(); + remove(SaveGames[Selected]->Filename.GetChars()); } //============================================================================= // -// Save data maintenance (stored statically) +// Save data maintenance // //============================================================================= -int DLoadSaveMenu::RemoveSaveSlot (int index) +void SavegameManager::ClearSaveGames() +{ + for (unsigned i = 0; ibNoDelete) + delete SaveGames[i]; + } + SaveGames.Clear(); +} + +//============================================================================= +// +// Save data maintenance +// +//============================================================================= + +int SavegameManager::RemoveSaveSlot(int index) { FSaveGameNode *file = SaveGames[index]; if (quickSaveSlot == SaveGames[index]) { - quickSaveSlot = NULL; - } - if (Selected == index) - { - Selected = -1; + quickSaveSlot = nullptr; } if (!file->bNoDelete) delete file; SaveGames.Delete(index); @@ -173,7 +104,7 @@ int DLoadSaveMenu::RemoveSaveSlot (int index) // //============================================================================= -int DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node) +int SavegameManager::InsertSaveNode(FSaveGameNode *node) { if (SaveGames.Size() == 0) { @@ -187,10 +118,10 @@ int DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node) else { // Add node at top of list unsigned int i; - for(i = 0; i < SaveGames.Size(); i++) + for (i = 0; i < SaveGames.Size(); i++) { if (SaveGames[i]->bOldVersion || - stricmp (node->Title, SaveGames[i]->Title) <= 0) + stricmp(node->Title, SaveGames[i]->Title) <= 0) { break; } @@ -200,7 +131,6 @@ int DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node) } } - //============================================================================= // // M_ReadSaveStrings @@ -209,7 +139,7 @@ int DLoadSaveMenu::InsertSaveNode (FSaveGameNode *node) // //============================================================================= -void DLoadSaveMenu::ReadSaveStrings () +void SavegameManager::ReadSaveStrings() { if (SaveGames.Size() == 0) { @@ -218,15 +148,15 @@ void DLoadSaveMenu::ReadSaveStrings () FString filter; LastSaved = LastAccessed = -1; - quickSaveSlot = NULL; - filter = G_BuildSaveName ("*." SAVEGAME_EXT, -1); - filefirst = I_FindFirst (filter.GetChars(), &c_file); + quickSaveSlot = nullptr; + filter = G_BuildSaveName("*." SAVEGAME_EXT, -1); + filefirst = I_FindFirst(filter.GetChars(), &c_file); if (filefirst != ((void *)(-1))) { do { // I_FindName only returns the file's name and not its full path - FString filepath = G_BuildSaveName (I_FindName(&c_file), -1); + FString filepath = G_BuildSaveName(I_FindName(&c_file), -1); FResourceFile *savegame = FResourceFile::OpenResourceFile(filepath, nullptr, true, true); if (savegame != nullptr) @@ -290,12 +220,12 @@ void DLoadSaveMenu::ReadSaveStrings () } else // check for old formats. { - FILE *file = fopen (filepath, "rb"); - if (file != NULL) + FILE *file = fopen(filepath, "rb"); + if (file != nullptr) { PNGHandle *png; char sig[16]; - char title[SAVESTRINGSIZE+1]; + char title[SAVESTRINGSIZE + 1]; bool oldVer = true; bool addIt = false; bool missing = false; @@ -310,10 +240,10 @@ void DLoadSaveMenu::ReadSaveStrings () title[SAVESTRINGSIZE] = 0; - if (NULL != (png = M_VerifyPNG (file))) + if (nullptr != (png = M_VerifyPNG(file))) { - char *ver = M_GetPNGText (png, "ZDoom Save Version"); - if (ver != NULL) + char *ver = M_GetPNGText(png, "ZDoom Save Version"); + if (ver != nullptr) { // An old version if (!M_GetPNGText(png, "Title", title, SAVESTRINGSIZE)) @@ -327,23 +257,23 @@ void DLoadSaveMenu::ReadSaveStrings () } else { - fseek (file, 0, SEEK_SET); - if (fread (sig, 1, 16, file) == 16) + fseek(file, 0, SEEK_SET); + if (fread(sig, 1, 16, file) == 16) { - if (strncmp (sig, "ZDOOMSAVE", 9) == 0) + if (strncmp(sig, "ZDOOMSAVE", 9) == 0) { - if (fread (title, 1, SAVESTRINGSIZE, file) == SAVESTRINGSIZE) + if (fread(title, 1, SAVESTRINGSIZE, file) == SAVESTRINGSIZE) { addIt = true; } } else { - memcpy (title, sig, 16); - if (fread (title + 16, 1, SAVESTRINGSIZE-16, file) == SAVESTRINGSIZE-16 && - fread (sig, 1, 16, file) == 16 && - strncmp (sig, "ZDOOMSAVE", 9) == 0) + memcpy(title, sig, 16); + if (fread(title + 16, 1, SAVESTRINGSIZE - 16, file) == SAVESTRINGSIZE - 16 && + fread(sig, 1, 16, file) == 16 && + strncmp(sig, "ZDOOMSAVE", 9) == 0) { addIt = true; } @@ -357,50 +287,49 @@ void DLoadSaveMenu::ReadSaveStrings () node->Filename = filepath; node->bOldVersion = true; node->bMissingWads = false; - memcpy (node->Title, title, SAVESTRINGSIZE); - InsertSaveNode (node); + memcpy(node->Title, title, SAVESTRINGSIZE); + InsertSaveNode(node); } - fclose (file); + fclose(file); } } - } while (I_FindNext (filefirst, &c_file) == 0); - I_FindClose (filefirst); + } while (I_FindNext(filefirst, &c_file) == 0); + I_FindClose(filefirst); } } } - //============================================================================= // // // //============================================================================= -void DLoadSaveMenu::NotifyNewSave (const char *file, const char *title, bool okForQuicksave) +void SavegameManager::NotifyNewSave(const char *file, const char *title, bool okForQuicksave) { FSaveGameNode *node; - if (file == NULL) + if (file == nullptr) return; - ReadSaveStrings (); + ReadSaveStrings(); // See if the file is already in our list - for (unsigned i=0; iFilename.Compare (file) == 0) + if (node->Filename.Compare(file) == 0) #else - if (node->Filename.CompareNoCase (file) == 0) + if (node->Filename.CompareNoCase(file) == 0) #endif { - strcpy (node->Title, title); + strcpy(node->Title, title); node->bOldVersion = false; node->bMissingWads = false; if (okForQuicksave) { - if (quickSaveSlot == NULL) quickSaveSlot = node; + if (quickSaveSlot == nullptr) quickSaveSlot = node; LastAccessed = LastSaved = i; } return; @@ -408,107 +337,71 @@ void DLoadSaveMenu::NotifyNewSave (const char *file, const char *title, bool okF } node = new FSaveGameNode; - strcpy (node->Title, title); + strcpy(node->Title, title); node->Filename = file; node->bOldVersion = false; node->bMissingWads = false; - int index = InsertSaveNode (node); + int index = InsertSaveNode(node); if (okForQuicksave) { - if (quickSaveSlot == NULL) quickSaveSlot = node; + if (quickSaveSlot == nullptr) quickSaveSlot = node; LastAccessed = LastSaved = index; } } -void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave) +//============================================================================= +// +// Loads the savegame +// +//============================================================================= + +void SavegameManager::LoadSavegame(int Selected) { - DLoadSaveMenu::NotifyNewSave(file, title, okForQuicksave); -} - -//============================================================================= -// -// End of static savegame maintenance code -// -//============================================================================= - -DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, DListMenuDescriptor *desc) -: DListMenu(parent, desc) -{ - ReadSaveStrings(); - - savepicLeft = 10; - savepicTop = 54*CleanYfac; - savepicWidth = 216*screen->GetWidth()/640; - savepicHeight = 135*screen->GetHeight()/400; - - rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac; - listboxLeft = savepicLeft + savepicWidth + 14; - listboxTop = savepicTop; - listboxWidth = screen->GetWidth() - listboxLeft - 10; - int listboxHeight1 = screen->GetHeight() - listboxTop - 10; - listboxRows = (listboxHeight1 - 1) / rowHeight; - listboxHeight = listboxRows * rowHeight + 1; - listboxRight = listboxLeft + listboxWidth; - listboxBottom = listboxTop + listboxHeight; - currentSavePic = nullptr; - - commentLeft = savepicLeft; - commentTop = savepicTop + savepicHeight + 16; - commentWidth = savepicWidth; - commentHeight = (51+(screen->GetHeight()>200?10:0))*CleanYfac; - commentRight = commentLeft + commentWidth; - commentBottom = commentTop + commentHeight; -} - -void DLoadSaveMenu::OnDestroy() -{ - if (currentSavePic != nullptr) delete currentSavePic; - currentSavePic = nullptr; - ClearSaveStuff (); - Super::OnDestroy(); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DLoadSaveMenu::UnloadSaveData () -{ - if (SavePic != nullptr) - { - delete SavePic; - } - if (SaveComment != nullptr) - { - V_FreeBrokenLines (SaveComment); - } - if (currentSavePic != nullptr) - { - delete currentSavePic; - } - - SavePic = nullptr; - SaveComment = nullptr; - currentSavePic = nullptr; - SavePicData.Clear(); -} - -//============================================================================= -// -// -// -//============================================================================= - -void DLoadSaveMenu::ClearSaveStuff () -{ - UnloadSaveData(); + G_LoadGame(SaveGames[Selected]->Filename.GetChars(), true); if (quickSaveSlot == (FSaveGameNode*)1) { - quickSaveSlot = NULL; + quickSaveSlot = SaveGames[Selected]; } + M_ClearMenus(); + V_SetBorderNeedRefresh(); + LastAccessed = Selected; +} + +//============================================================================= +// +// +// +//============================================================================= + +void SavegameManager::DoSave(int Selected, const char *savegamestring) +{ + if (Selected != 0) + { + auto node = SaveGames[Selected]; + G_SaveGame(node->Filename.GetChars(), savegamestring); + } + else + { + // Find an unused filename and save as that + FString filename; + int i; + FILE *test; + + for (i = 0;; ++i) + { + filename = G_BuildSaveName("save", i); + test = fopen(filename, "rb"); + if (test == nullptr) + { + break; + } + fclose(test); + } + G_SaveGame(filename, savegamestring); + } + M_ClearMenus(); + V_SetBorderNeedRefresh(); } //============================================================================= @@ -517,12 +410,12 @@ void DLoadSaveMenu::ClearSaveStuff () // //============================================================================= -void DLoadSaveMenu::ExtractSaveData (int index) +void SavegameManager::ExtractSaveData(int index) { FResourceFile *resf; FSaveGameNode *node; - UnloadSaveData (); + UnloadSaveData(); if ((unsigned)index < SaveGames.Size() && (node = SaveGames[index]) && @@ -548,8 +441,8 @@ void DLoadSaveMenu::ExtractSaveData (int index) comment = time; if (time.Len() > 0) comment += "\n\n"; comment += pcomment; - - SaveComment = V_BreakLines (SmallFont, 216*screen->GetWidth()/640/CleanXfac, comment.GetChars()); + + SaveComment = V_BreakLines(SmallFont, WindowSize, comment.GetChars()); // Extract pic FResourceLump *pic = resf->FindLump("savepic.png"); @@ -592,6 +485,181 @@ void DLoadSaveMenu::ExtractSaveData (int index) // //============================================================================= +void SavegameManager::UnloadSaveData() +{ + if (SavePic != nullptr) + { + delete SavePic; + } + if (SaveComment != nullptr) + { + V_FreeBrokenLines(SaveComment); + } + if (currentSavePic != nullptr) + { + delete currentSavePic; + } + + SavePic = nullptr; + SaveComment = nullptr; + currentSavePic = nullptr; + SavePicData.Clear(); +} + +//============================================================================= +// +// +// +//============================================================================= + +void SavegameManager::ClearSaveStuff() +{ + UnloadSaveData(); + if (quickSaveSlot == (FSaveGameNode*)1) + { + quickSaveSlot = nullptr; + } +} + + +//============================================================================= +// +// +// +//============================================================================= + +bool SavegameManager::DrawSavePic(int x, int y, int w, int h) +{ + if (SavePic == nullptr) return false; + screen->DrawTexture(SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE); + return true; +} + +//============================================================================= +// +// +// +//============================================================================= + +void SavegameManager::SetFileInfo(int Selected) +{ + if (!SaveGames[Selected]->Filename.IsEmpty()) + { + char workbuf[512]; + + mysnprintf(workbuf, countof(workbuf), "File on disk:\n%s", SaveGames[Selected]->Filename.GetChars()); + if (SaveComment != nullptr) + { + V_FreeBrokenLines(SaveComment); + } + SaveComment = V_BreakLines(SmallFont, WindowSize, workbuf); + } +} + +SavegameManager savegameManager; + + + + +class DLoadSaveMenu : public DListMenu +{ + DECLARE_CLASS(DLoadSaveMenu, DListMenu) + +protected: + + SavegameManager *manager; + + int Selected; + int TopItem; + + + int savepicLeft; + int savepicTop; + int savepicWidth; + int savepicHeight; + + int rowHeight; + int listboxLeft; + int listboxTop; + int listboxWidth; + + int listboxRows; + int listboxHeight; + int listboxRight; + int listboxBottom; + + int commentLeft; + int commentTop; + int commentWidth; + int commentHeight; + int commentRight; + int commentBottom; + + // this needs to be kept in memory so that the texture can access it when it needs to. + bool mEntering; + char savegamestring[SAVESTRINGSIZE]; + + DLoadSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); + void OnDestroy() override; + + void Drawer (); + bool MenuEvent (int mkey, bool fromcontroller); + bool MouseEvent(int type, int x, int y); + bool Responder(event_t *ev); +}; + +IMPLEMENT_CLASS(DLoadSaveMenu, false, false) + + + +//============================================================================= +// +// End of static savegame maintenance code +// +//============================================================================= + +DLoadSaveMenu::DLoadSaveMenu(DMenu *parent, DListMenuDescriptor *desc) +: DListMenu(parent, desc) +{ + manager = &savegameManager; + manager->ReadSaveStrings(); + + savepicLeft = 10; + savepicTop = 54*CleanYfac; + savepicWidth = 216*screen->GetWidth()/640; + savepicHeight = 135*screen->GetHeight()/400; + manager->WindowSize = savepicWidth; + + rowHeight = (SmallFont->GetHeight() + 1) * CleanYfac; + listboxLeft = savepicLeft + savepicWidth + 14; + listboxTop = savepicTop; + listboxWidth = screen->GetWidth() - listboxLeft - 10; + int listboxHeight1 = screen->GetHeight() - listboxTop - 10; + listboxRows = (listboxHeight1 - 1) / rowHeight; + listboxHeight = listboxRows * rowHeight + 1; + listboxRight = listboxLeft + listboxWidth; + listboxBottom = listboxTop + listboxHeight; + + commentLeft = savepicLeft; + commentTop = savepicTop + savepicHeight + 16; + commentWidth = savepicWidth; + commentHeight = (51+(screen->GetHeight()>200?10:0))*CleanYfac; + commentRight = commentLeft + commentWidth; + commentBottom = commentTop + commentHeight; +} + +void DLoadSaveMenu::OnDestroy() +{ + manager->ClearSaveStuff (); + Super::OnDestroy(); +} + +//============================================================================= +// +// +// +//============================================================================= + void DLoadSaveMenu::Drawer () { Super::Drawer(); @@ -608,23 +676,15 @@ void DLoadSaveMenu::Drawer () } V_DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight); - if (SavePic != NULL) - { - screen->DrawTexture(SavePic, savepicLeft, savepicTop, - DTA_DestWidth, savepicWidth, - DTA_DestHeight, savepicHeight, - DTA_Masked, false, - TAG_DONE); - } - else + if (!manager->DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight)) { screen->Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0); - if (SaveGames.Size() > 0) + if (manager->SaveGames.Size() > 0) { const char *text = - (Selected == -1 || !SaveGames[Selected]->bOldVersion) + (Selected == -1 || !manager->SaveGames[Selected]->bOldVersion) ? GStrings("MNU_NOPICTURE") : GStrings("MNU_DIFFVERSION"); const int textlen = SmallFont->StringWidth (text)*CleanXfac; @@ -637,15 +697,15 @@ void DLoadSaveMenu::Drawer () // Draw comment area V_DrawFrame (commentLeft, commentTop, commentWidth, commentHeight); screen->Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0); - if (SaveComment != NULL) + if (manager->SaveComment != nullptr) { - // I'm not sure why SaveComment would go NULL in this loop, but I got - // a crash report where it was NULL when i reached 1, so now I check + // I'm not sure why SaveComment would go nullptr in this loop, but I got + // a crash report where it was nullptr when i reached 1, so now I check // for that. - for (i = 0; SaveComment != NULL && SaveComment[i].Width >= 0 && i < 6; ++i) + for (i = 0; manager->SaveComment != nullptr && manager->SaveComment[i].Width >= 0 && i < 6; ++i) { screen->DrawText (SmallFont, CR_GOLD, commentLeft, commentTop - + SmallFont->GetHeight()*i*CleanYfac, SaveComment[i].Text, + + SmallFont->GetHeight()*i*CleanYfac, manager->SaveComment[i].Text, DTA_CleanNoMove, true, TAG_DONE); } } @@ -654,7 +714,7 @@ void DLoadSaveMenu::Drawer () V_DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight); screen->Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0); - if (SaveGames.Size() == 0) + if (manager->SaveGames.Size() == 0) { const char * text = GStrings("MNU_NOFILES"); const int textlen = SmallFont->StringWidth (text)*CleanXfac; @@ -665,10 +725,10 @@ void DLoadSaveMenu::Drawer () return; } - for (i = 0, j = TopItem; i < listboxRows && j < SaveGames.Size(); i++,j++) + for (i = 0, j = TopItem; i < listboxRows && j < manager->SaveGames.Size(); i++,j++) { int color; - node = SaveGames[j]; + node = manager->SaveGames[j]; if (node->bOldVersion) { color = CR_BLUE; @@ -732,59 +792,59 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) switch (mkey) { case MKEY_Up: - if (SaveGames.Size() > 1) + if (manager->SaveGames.Size() > 1) { if (Selected == -1) Selected = TopItem; else { - if (--Selected < 0) Selected = SaveGames.Size()-1; + if (--Selected < 0) Selected = manager->SaveGames.Size()-1; if (Selected < TopItem) TopItem = Selected; else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); } - UnloadSaveData (); - ExtractSaveData (Selected); + manager->UnloadSaveData (); + manager->ExtractSaveData (Selected); } return true; case MKEY_Down: - if (SaveGames.Size() > 1) + if (manager->SaveGames.Size() > 1) { if (Selected == -1) Selected = TopItem; else { - if (unsigned(++Selected) >= SaveGames.Size()) Selected = 0; + if (unsigned(++Selected) >= manager->SaveGames.Size()) Selected = 0; if (Selected < TopItem) TopItem = Selected; else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1); } - UnloadSaveData (); - ExtractSaveData (Selected); + manager->UnloadSaveData (); + manager->ExtractSaveData (Selected); } return true; case MKEY_PageDown: - if (SaveGames.Size() > 1) + if (manager->SaveGames.Size() > 1) { - if (TopItem >= (int)SaveGames.Size() - listboxRows) + if (TopItem >= (int)manager->SaveGames.Size() - listboxRows) { TopItem = 0; if (Selected != -1) Selected = 0; } else { - TopItem = MIN(TopItem + listboxRows, SaveGames.Size() - listboxRows); + TopItem = MIN(TopItem + listboxRows, manager->SaveGames.Size() - listboxRows); if (TopItem > Selected && Selected != -1) Selected = TopItem; } - UnloadSaveData (); - ExtractSaveData (Selected); + manager->UnloadSaveData (); + manager->ExtractSaveData (Selected); } return true; case MKEY_PageUp: - if (SaveGames.Size() > 1) + if (manager->SaveGames.Size() > 1) { if (TopItem == 0) { - TopItem = SaveGames.Size() - listboxRows; + TopItem = manager->SaveGames.Size() - listboxRows; if (Selected != -1) Selected = TopItem; } else @@ -792,8 +852,8 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) TopItem = MAX(TopItem - listboxRows, 0); if (Selected >= TopItem + listboxRows) Selected = TopItem; } - UnloadSaveData (); - ExtractSaveData (Selected); + manager->UnloadSaveData (); + manager->ExtractSaveData (Selected); } return true; @@ -802,18 +862,18 @@ bool DLoadSaveMenu::MenuEvent (int mkey, bool fromcontroller) case MKEY_MBYes: { - if ((unsigned)Selected < SaveGames.Size()) + if ((unsigned)Selected < manager->SaveGames.Size()) { - int listindex = SaveGames[0]->bNoDelete? Selected-1 : Selected; - remove (SaveGames[Selected]->Filename.GetChars()); - UnloadSaveData (); - Selected = RemoveSaveSlot (Selected); - ExtractSaveData (Selected); + int listindex = manager->SaveGames[0]->bNoDelete? Selected-1 : Selected; + manager->DeleteEntry(Selected); + manager->UnloadSaveData (); + Selected = manager->RemoveSaveSlot (Selected); + manager->ExtractSaveData (Selected); - if (LastSaved == listindex) LastSaved = -1; - else if (LastSaved > listindex) LastSaved--; - if (LastAccessed == listindex) LastAccessed = -1; - else if (LastAccessed > listindex) LastAccessed--; + if (manager->LastSaved == listindex) manager->LastSaved = -1; + else if (manager->LastSaved > listindex) manager->LastSaved--; + if (manager->LastAccessed == listindex) manager->LastAccessed = -1; + else if (manager->LastAccessed > listindex) manager->LastAccessed--; } return true; } @@ -836,11 +896,11 @@ bool DLoadSaveMenu::MouseEvent(int type, int x, int y) { int lineno = (y - listboxTop) / rowHeight; - if (TopItem + lineno < (int)SaveGames.Size()) + if (TopItem + lineno < (int)manager->SaveGames.Size()) { Selected = TopItem + lineno; - UnloadSaveData (); - ExtractSaveData (Selected); + manager->UnloadSaveData (); + manager->ExtractSaveData (Selected); if (type == MOUSE_Release) { if (MenuEvent(MKEY_Enter, true)) @@ -868,22 +928,12 @@ bool DLoadSaveMenu::Responder (event_t *ev) { if (ev->subtype == EV_GUI_KeyDown) { - if ((unsigned)Selected < SaveGames.Size()) + if ((unsigned)Selected < manager->SaveGames.Size()) { switch (ev->data1) { case GK_F1: - if (!SaveGames[Selected]->Filename.IsEmpty()) - { - char workbuf[512]; - - mysnprintf (workbuf, countof(workbuf), "File on disk:\n%s", SaveGames[Selected]->Filename.GetChars()); - if (SaveComment != NULL) - { - V_FreeBrokenLines (SaveComment); - } - SaveComment = V_BreakLines (SmallFont, 216*screen->GetWidth()/640/CleanXfac, workbuf); - } + manager->SetFileInfo(Selected); return true; case GK_DEL: @@ -891,7 +941,7 @@ bool DLoadSaveMenu::Responder (event_t *ev) { FString EndString; EndString.Format("%s" TEXTCOLOR_WHITE "%s" TEXTCOLOR_NORMAL "?\n\n%s", - GStrings("MNU_DELETESG"), SaveGames[Selected]->Title, GStrings("PRESSYN")); + GStrings("MNU_DELETESG"), manager->SaveGames[Selected]->Title, GStrings("PRESSYN")); M_StartMessage (EndString, 0); } return true; @@ -905,7 +955,7 @@ bool DLoadSaveMenu::Responder (event_t *ev) } else if (ev->subtype == EV_GUI_WheelDown) { - if (TopItem < (int)SaveGames.Size() - listboxRows) TopItem++; + if (TopItem < (int)manager->SaveGames.Size() - listboxRows) TopItem++; return true; } } @@ -927,9 +977,8 @@ class DSaveMenu : public DLoadSaveMenu public: - DSaveMenu(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); + DSaveMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); void OnDestroy() override; - void DoSave (FSaveGameNode *node); bool Responder (event_t *ev); bool MenuEvent (int mkey, bool fromcontroller); @@ -949,17 +998,17 @@ DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) { strcpy (NewSaveNode.Title, GStrings["NEWSAVE"]); NewSaveNode.bNoDelete = true; - SaveGames.Insert(0, &NewSaveNode); + manager->SaveGames.Insert(0, &NewSaveNode); TopItem = 0; - if (LastSaved == -1) + if (manager->LastSaved == -1) { Selected = 0; } else { - Selected = LastSaved + 1; + Selected = manager->LastSaved + 1; } - ExtractSaveData (Selected); + manager->ExtractSaveData (Selected); } //============================================================================= @@ -970,50 +1019,15 @@ DSaveMenu::DSaveMenu(DMenu *parent, DListMenuDescriptor *desc) void DSaveMenu::OnDestroy() { - if (SaveGames[0] == &NewSaveNode) + if (manager->SaveGames[0] == &NewSaveNode) { - SaveGames.Delete(0); + manager->SaveGames.Delete(0); if (Selected == 0) Selected = -1; else Selected--; } Super::OnDestroy(); } -//============================================================================= -// -// -// -//============================================================================= - -void DSaveMenu::DoSave (FSaveGameNode *node) -{ - if (node != &NewSaveNode) - { - G_SaveGame (node->Filename.GetChars(), savegamestring); - } - else - { - // Find an unused filename and save as that - FString filename; - int i; - FILE *test; - - for (i = 0;; ++i) - { - filename = G_BuildSaveName ("save", i); - test = fopen (filename, "rb"); - if (test == NULL) - { - break; - } - fclose (test); - } - G_SaveGame (filename, savegamestring); - } - M_ClearMenus(); - V_SetBorderNeedRefresh(); -} - //============================================================================= // // @@ -1035,7 +1049,7 @@ bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller) { if (Selected != 0) { - strcpy (savegamestring, SaveGames[Selected]->Title); + strcpy (savegamestring, manager->SaveGames[Selected]->Title); } else { @@ -1048,7 +1062,7 @@ bool DSaveMenu::MenuEvent (int mkey, bool fromcontroller) else if (mkey == MKEY_Input) { mEntering = false; - DoSave(SaveGames[Selected]); + manager->DoSave(Selected, savegamestring); } else if (mkey == MKEY_Abort) { @@ -1079,7 +1093,7 @@ bool DSaveMenu::Responder (event_t *ev) case 'N': Selected = TopItem = 0; - UnloadSaveData (); + manager->UnloadSaveData (); return true; } } @@ -1099,7 +1113,7 @@ class DLoadMenu : public DLoadSaveMenu public: - DLoadMenu(DMenu *parent = NULL, DListMenuDescriptor *desc = NULL); + DLoadMenu(DMenu *parent = nullptr, DListMenuDescriptor *desc = nullptr); bool MenuEvent (int mkey, bool fromcontroller); }; @@ -1117,11 +1131,11 @@ DLoadMenu::DLoadMenu(DMenu *parent, DListMenuDescriptor *desc) : DLoadSaveMenu(parent, desc) { TopItem = 0; - if (LastAccessed != -1) + if (manager->LastAccessed != -1) { - Selected = LastAccessed; + Selected = manager->LastAccessed; } - ExtractSaveData (Selected); + manager->ExtractSaveData (Selected); } @@ -1137,21 +1151,14 @@ bool DLoadMenu::MenuEvent (int mkey, bool fromcontroller) { return true; } - if (Selected == -1 || SaveGames.Size() == 0) + if (Selected == -1 || manager->SaveGames.Size() == 0) { return false; } if (mkey == MKEY_Enter) { - G_LoadGame (SaveGames[Selected]->Filename.GetChars(), true); - if (quickSaveSlot == (FSaveGameNode*)1) - { - quickSaveSlot = SaveGames[Selected]; - } - M_ClearMenus(); - V_SetBorderNeedRefresh(); - LastAccessed = Selected; + manager->LoadSavegame(Selected); return true; } return false; diff --git a/src/menu/menu.h b/src/menu/menu.h index 3af5e0efb..7ffb1aab8 100644 --- a/src/menu/menu.h +++ b/src/menu/menu.h @@ -22,6 +22,7 @@ class FFont; enum EColorRange : int; class FPlayerClass; class FKeyBindings; +struct FBrokenLines; enum EMenuKey { @@ -66,7 +67,37 @@ struct FSaveGameNode FSaveGameNode() { bNoDelete = false; } }; +struct SavegameManager +{ + TArray SaveGames; + int LastSaved = -1; + int LastAccessed = -1; + int WindowSize = 0; + FSaveGameNode *quickSaveSlot = nullptr; + FileReader *currentSavePic = nullptr; + TArray SavePicData; + + FTexture *SavePic = nullptr; + FBrokenLines *SaveComment = nullptr; + + void ClearSaveGames(); + int InsertSaveNode(FSaveGameNode *node); + int RemoveSaveSlot(int index); + void ReadSaveStrings(); + void NotifyNewSave(const char *file, const char *title, bool okForQuicksave); + void LoadSavegame(int Selected); + void DoSave(int Selected, const char *savegamestring); + void DeleteEntry(int Selected); + void ExtractSaveData(int index); + void UnloadSaveData(); + void ClearSaveStuff(); + bool DrawSavePic(int x, int y, int w, int h); + void SetFileInfo(int Selected); + +}; + +extern SavegameManager savegameManager; //============================================================================= // @@ -707,7 +738,6 @@ void M_StartupSkillMenu(FGameStartup *gs); int M_GetDefaultSkill(); void M_StartControlPanel (bool makeSound); void M_SetMenu(FName menu, int param = -1); -void M_NotifyNewSave (const char *file, const char *title, bool okForQuicksave); void M_StartMessage(const char *message, int messagemode, FName action = NAME_None); DMenu *StartPickerMenu(DMenu *parent, const char *name, FColorCVar *cvar); void M_RefreshModesList (); diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 05bb16007..86f168747 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -148,7 +148,7 @@ static void DeinitMenus() MenuDescriptors.Clear(); OptionValues.Clear(); DMenu::CurrentMenu = nullptr; - ClearSaveGames(); + savegameManager.ClearSaveGames(); } static FTextureID GetMenuTexture(const char* const name) diff --git a/src/menu/messagebox.cpp b/src/menu/messagebox.cpp index a910ad3ad..e15940acb 100644 --- a/src/menu/messagebox.cpp +++ b/src/menu/messagebox.cpp @@ -47,7 +47,6 @@ #include "g_game.h" -extern FSaveGameNode *quickSaveSlot; EXTERN_CVAR (Bool, saveloadconfirmation) // [mxd] class DMessageBoxMenu : public DMenu @@ -549,7 +548,7 @@ DQuickSaveMenu::DQuickSaveMenu(bool playsound) { FString tempstring; - tempstring.Format(GStrings("QSPROMPT"), quickSaveSlot->Title); + tempstring.Format(GStrings("QSPROMPT"), savegameManager.quickSaveSlot->Title); Init(NULL, tempstring, 0, playsound); } @@ -563,7 +562,7 @@ void DQuickSaveMenu::HandleResult(bool res) { if (res) { - G_SaveGame (quickSaveSlot->Filename.GetChars(), quickSaveSlot->Title); + G_SaveGame (savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title); S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); M_ClearMenus(); } @@ -591,7 +590,7 @@ CCMD (quicksave) if (gamestate != GS_LEVEL) return; - if (quickSaveSlot == NULL) + if (savegameManager.quickSaveSlot == NULL) { S_Sound(CHAN_VOICE | CHAN_UI, "menu/activate", snd_menuvolume, ATTN_NONE); M_StartControlPanel(false); @@ -602,7 +601,7 @@ CCMD (quicksave) // [mxd]. Just save the game, no questions asked. if (!saveloadconfirmation) { - G_SaveGame(quickSaveSlot->Filename.GetChars(), quickSaveSlot->Title); + G_SaveGame(savegameManager.quickSaveSlot->Filename.GetChars(), savegameManager.quickSaveSlot->Title); return; } @@ -645,7 +644,7 @@ DQuickLoadMenu::DQuickLoadMenu(bool playsound) { FString tempstring; - tempstring.Format(GStrings("QLPROMPT"), quickSaveSlot->Title); + tempstring.Format(GStrings("QLPROMPT"), savegameManager.quickSaveSlot->Title); Init(NULL, tempstring, 0, playsound); } @@ -659,7 +658,7 @@ void DQuickLoadMenu::HandleResult(bool res) { if (res) { - G_LoadGame (quickSaveSlot->Filename.GetChars()); + G_LoadGame (savegameManager.quickSaveSlot->Filename.GetChars()); S_Sound (CHAN_VOICE | CHAN_UI, "menu/dismiss", snd_menuvolume, ATTN_NONE); M_ClearMenus(); } @@ -685,11 +684,11 @@ CCMD (quickload) return; } - if (quickSaveSlot == NULL) + if (savegameManager.quickSaveSlot == NULL) { M_StartControlPanel(true); // signal that whatever gets loaded should be the new quicksave - quickSaveSlot = (FSaveGameNode *)1; + savegameManager.quickSaveSlot = (FSaveGameNode *)1; M_SetMenu(NAME_Loadgamemenu); return; } @@ -697,7 +696,7 @@ CCMD (quickload) // [mxd]. Just load the game, no questions asked. if (!saveloadconfirmation) { - G_LoadGame(quickSaveSlot->Filename.GetChars()); + G_LoadGame(savegameManager.quickSaveSlot->Filename.GetChars()); return; }