From 3ea0658449721b53809bc654abd254931f83e2a9 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 7 Oct 2020 15:44:08 +0200 Subject: [PATCH] - split the savegame manager into a game dependent and a reusable game indepenent part. - added menu/advance sound alias. --- src/CMakeLists.txt | 1 + src/common/menu/savegamemanager.cpp | 541 ++++++++++++++++++ src/common/menu/savegamemanager.h | 61 ++ src/menu/doommenu.h | 54 +- src/menu/loadsavemenu.cpp | 472 +-------------- .../static/filter/game-doomchex/sndinfo.txt | 1 + wadsrc/static/filter/game-heretic/sndinfo.txt | 1 + wadsrc/static/filter/game-hexen/sndinfo.txt | 1 + wadsrc/static/filter/game-strife/sndinfo.txt | 1 + wadsrc/static/zscript/base.zs | 9 + wadsrc/static/zscript/doombase.zs | 6 +- 11 files changed, 640 insertions(+), 508 deletions(-) create mode 100644 src/common/menu/savegamemanager.cpp create mode 100644 src/common/menu/savegamemanager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 087b49dcd..77afa1c61 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1125,6 +1125,7 @@ set (PCH_SOURCES common/menu/optionmenu.cpp common/menu/resolutionmenu.cpp common/menu/menudef.cpp + common/menu/savegamemanager.cpp common/rendering/v_framebuffer.cpp common/rendering/v_video.cpp diff --git a/src/common/menu/savegamemanager.cpp b/src/common/menu/savegamemanager.cpp new file mode 100644 index 000000000..935b6dedd --- /dev/null +++ b/src/common/menu/savegamemanager.cpp @@ -0,0 +1,541 @@ +/* +** loadsavemenu.cpp +** The load game and save game menus +** +**--------------------------------------------------------------------------- +** Copyright 2001-2010 Randy Heit +** Copyright 2010-2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include "menu.h" +#include "version.h" +#include "m_png.h" +#include "filesystem.h" +#include "v_text.h" +#include "gstrings.h" +#include "serializer.h" +#include "vm.h" +#include "i_system.h" +#include "v_video.h" +#include "findfile.h" +#include "v_draw.h" +#include "savegamemanager.h" + + + +//============================================================================= +// +// Save data maintenance +// +//============================================================================= + +void FSavegameManagerBase::ClearSaveGames() +{ + for (unsigned i = 0; ibNoDelete) + delete SaveGames[i]; + } + SaveGames.Clear(); +} + +FSavegameManagerBase::~FSavegameManagerBase() +{ + ClearSaveGames(); +} + +//============================================================================= +// +// Save data maintenance +// +//============================================================================= + +int FSavegameManagerBase::RemoveSaveSlot(int index) +{ + int listindex = SaveGames[0]->bNoDelete ? index - 1 : index; + if (listindex < 0) return index; + + remove(SaveGames[index]->Filename.GetChars()); + UnloadSaveData(); + + FSaveGameNode *file = SaveGames[index]; + + if (quickSaveSlot == SaveGames[index]) + { + quickSaveSlot = nullptr; + } + if (!file->bNoDelete) delete file; + + if (LastSaved == listindex) LastSaved = -1; + else if (LastSaved > listindex) LastSaved--; + if (LastAccessed == listindex) LastAccessed = -1; + else if (LastAccessed > listindex) LastAccessed--; + + SaveGames.Delete(index); + if ((unsigned)index >= SaveGames.Size()) index--; + ExtractSaveData(index); + return index; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + ACTION_RETURN_INT(self->RemoveSaveSlot(sel)); +} + +//============================================================================= +// +// +// +//============================================================================= + +int FSavegameManagerBase::InsertSaveNode(FSaveGameNode *node) +{ + if (SaveGames.Size() == 0) + { + return SaveGames.Push(node); + } + + if (node->bOldVersion) + { // Add node at bottom of list + return SaveGames.Push(node); + } + else + { // Add node at top of list + unsigned int i = 0; + //if (SaveGames[0] == &NewSaveNode) i++; // To not insert above the "new savegame" dummy entry. + for (; i < SaveGames.Size(); i++) + { + if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0) + { + break; + } + } + SaveGames.Insert(i, node); + return i; + } +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave) +{ + FSaveGameNode *node; + + if (file.IsEmpty()) + return; + + ReadSaveStrings(); + + // See if the file is already in our list + for (unsigned i = 0; iFilename.Compare(file) == 0) +#else + if (node->Filename.CompareNoCase(file) == 0) +#endif + { + node->SaveTitle = title; + node->bOldVersion = false; + node->bMissingWads = false; + if (okForQuicksave) + { + if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; + LastAccessed = LastSaved = i; + } + return; + } + } + + node = new FSaveGameNode; + node->SaveTitle = title; + node->Filename = file; + node->bOldVersion = false; + node->bMissingWads = false; + int index = InsertSaveNode(node); + + if (okForQuicksave) + { + if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; + LastAccessed = LastSaved = index; + } + else + { + LastAccessed = ++LastSaved; + } +} + + +//============================================================================= +// +// Loads the savegame +// +//============================================================================= + +void FSavegameManagerBase::LoadSavegame(int Selected) +{ + PerformLoadGame(SaveGames[Selected]->Filename.GetChars(), true); + if (quickSaveSlot == (FSaveGameNode*)1) + { + quickSaveSlot = SaveGames[Selected]; + } + M_ClearMenus(); + LastAccessed = Selected; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + self->LoadSavegame(sel); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::DoSave(int Selected, const char *savegamestring) +{ + if (Selected != 0) + { + auto node = SaveGames[Selected]; + PerformSaveGame(node->Filename.GetChars(), savegamestring); + } + else + { + // Find an unused filename and save as that + FString filename; + int i; + + for (i = 0;; ++i) + { + filename = BuildSaveName("save", i); + if (!FileExists(filename)) + { + break; + } + } + PerformSaveGame(filename, savegamestring); + } + M_ClearMenus(); +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + PARAM_STRING(name); + self->DoSave(sel, name); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +unsigned FSavegameManagerBase::ExtractSaveData(int index) +{ + FResourceFile *resf; + FSaveGameNode *node; + + if (index == -1) + { + if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete) + { + index = LastSaved + 1; + } + else + { + index = LastAccessed < 0? 0 : LastAccessed; + } + } + + UnloadSaveData(); + + if ((unsigned)index < SaveGames.Size() && + (node = SaveGames[index]) && + !node->Filename.IsEmpty() && + !node->bOldVersion && + (resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr) + { + FResourceLump *info = resf->FindLump("info.json"); + if (info == nullptr) + { + // this should not happen because the file has already been verified. + return index; + } + + void* data = info->Lock(); + FSerializer arc; + if (!arc.OpenReader((const char*)data, info->LumpSize)) + { + info->Unlock(); + return index; + } + info->Unlock(); + + SaveCommentString = ExtractSaveComment(arc); + + FResourceLump *pic = resf->FindLump("savepic.png"); + if (pic != nullptr) + { + FileReader picreader; + + picreader.OpenMemoryArray([=](TArray &array) + { + auto cache = pic->Lock(); + array.Resize(pic->LumpSize); + memcpy(&array[0], cache, pic->LumpSize); + pic->Unlock(); + return true; + }); + PNGHandle *png = M_VerifyPNG(picreader); + if (png != nullptr) + { + SavePic = PNGTexture_CreateFromFile(png, node->Filename); + delete png; + if (SavePic && SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1) + { + delete SavePic; + SavePic = nullptr; + } + } + } + delete resf; + } + return index; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::UnloadSaveData() +{ + if (SavePic != nullptr) + { + delete SavePic; + } + + SaveCommentString = ""; + SavePic = nullptr; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->UnloadSaveData(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::ClearSaveStuff() +{ + UnloadSaveData(); + if (quickSaveSlot == (FSaveGameNode*)1) + { + quickSaveSlot = nullptr; + } +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->ClearSaveStuff(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool FSavegameManagerBase::DrawSavePic(int x, int y, int w, int h) +{ + if (SavePic == nullptr) return false; + DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE); + return true; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(x); + PARAM_INT(y); + PARAM_INT(w); + PARAM_INT(h); + ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h)); +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::SetFileInfo(int Selected) +{ + if (!SaveGames[Selected]->Filename.IsEmpty()) + { + SaveCommentString.Format("File on disk:\n%s", SaveGames[Selected]->Filename.GetChars()); + } +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(i); + self->SetFileInfo(i); + return 0; +} + + +//============================================================================= +// +// +// +//============================================================================= + +unsigned FSavegameManagerBase::SavegameCount() +{ + return SaveGames.Size(); +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + ACTION_RETURN_INT(self->SavegameCount()); +} + +//============================================================================= +// +// +// +//============================================================================= + +FSaveGameNode *FSavegameManagerBase::GetSavegame(int i) +{ + return SaveGames[i]; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(i); + ACTION_RETURN_POINTER(self->GetSavegame(i)); +} + +//============================================================================= +// +// +// +//============================================================================= + +void FSavegameManagerBase::InsertNewSaveNode() +{ + NewSaveNode.SaveTitle = GStrings("NEWSAVE"); + NewSaveNode.bNoDelete = true; + SaveGames.Insert(0, &NewSaveNode); +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->InsertNewSaveNode(); + return 0; +} + +//============================================================================= +// +// +// +//============================================================================= + +bool FSavegameManagerBase::RemoveNewSaveNode() +{ + if (SaveGames[0] == &NewSaveNode) + { + SaveGames.Delete(0); + return true; + } + return false; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + ACTION_RETURN_INT(self->RemoveNewSaveNode()); +} + + +DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + self->ReadSaveStrings(); + return 0; +} + +DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) +{ + PARAM_SELF_STRUCT_PROLOGUE(FSavegameManagerBase); + PARAM_INT(sel); + ACTION_RETURN_INT(self->ExtractSaveData(sel)); +} + + +DEFINE_FIELD(FSaveGameNode, SaveTitle); +DEFINE_FIELD(FSaveGameNode, Filename); +DEFINE_FIELD(FSaveGameNode, bOldVersion); +DEFINE_FIELD(FSaveGameNode, bMissingWads); +DEFINE_FIELD(FSaveGameNode, bNoDelete); + +DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, WindowSize); +DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, quickSaveSlot); +DEFINE_FIELD_X(SavegameManager, FSavegameManagerBase, SaveCommentString); + diff --git a/src/common/menu/savegamemanager.h b/src/common/menu/savegamemanager.h new file mode 100644 index 000000000..754ddce23 --- /dev/null +++ b/src/common/menu/savegamemanager.h @@ -0,0 +1,61 @@ +#pragma once + +#include "zstring.h" +#include "tarray.h" + +class FGameTexture; +class FSerializer; + +// The savegame manager contains too much code that is game specific. Parts are shareable but need more work first. +struct FSaveGameNode +{ + FString SaveTitle; + FString Filename; + bool bOldVersion = false; + bool bMissingWads = false; + bool bNoDelete = false; +}; + +struct FSavegameManagerBase +{ +protected: + TArray SaveGames; + FSaveGameNode NewSaveNode; + int LastSaved = -1; + int LastAccessed = -1; + FGameTexture *SavePic = nullptr; + +public: + int WindowSize = 0; + FString SaveCommentString; + FSaveGameNode *quickSaveSlot = nullptr; + virtual ~FSavegameManagerBase(); + +protected: + int InsertSaveNode(FSaveGameNode *node); + virtual void PerformSaveGame(const char *fn, const char *sgdesc) = 0; + virtual void PerformLoadGame(const char *fn, bool) = 0; + virtual FString ExtractSaveComment(FSerializer &arc) = 0; + virtual FString BuildSaveName(const char* prefix, int slot) = 0; +public: + void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave); + void ClearSaveGames(); + + virtual void ReadSaveStrings() = 0; + void UnloadSaveData(); + + int RemoveSaveSlot(int index); + void LoadSavegame(int Selected); + void DoSave(int Selected, const char *savegamestring); + unsigned ExtractSaveData(int index); + void ClearSaveStuff(); + bool DrawSavePic(int x, int y, int w, int h); + void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor); + void SetFileInfo(int Selected); + unsigned SavegameCount(); + FSaveGameNode *GetSavegame(int i); + void InsertNewSaveNode(); + bool RemoveNewSaveNode(); + +}; + diff --git a/src/menu/doommenu.h b/src/menu/doommenu.h index ad6946fad..2de0bdb7f 100644 --- a/src/menu/doommenu.h +++ b/src/menu/doommenu.h @@ -1,5 +1,6 @@ #pragma once #include "menu.h" +#include "savegamemanager.h" void M_StartControlPanel (bool makeSound, bool scaleoverride = false); @@ -16,53 +17,14 @@ void M_StartupEpisodeMenu(FNewGameStartup *gs); void M_StartupSkillMenu(FNewGameStartup *gs); void M_CreateGameMenus(); void SetDefaultMenuColors(); -// The savegame manager contains too much code that is game specific. Parts are shareable but need more work first. -struct FSaveGameNode + +class FSavegameManager : public FSavegameManagerBase { - FString SaveTitle; - FString Filename; - bool bOldVersion = false; - bool bMissingWads = false; - bool bNoDelete = false; -}; - -struct FSavegameManager -{ -private: - TArray SaveGames; - FSaveGameNode NewSaveNode; - int LastSaved = -1; - int LastAccessed = -1; - FGameTexture *SavePic = nullptr; - -public: - int WindowSize = 0; - FString SaveCommentString; - FSaveGameNode *quickSaveSlot = nullptr; - ~FSavegameManager(); - -private: - int InsertSaveNode(FSaveGameNode *node); -public: - void NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave); - void ClearSaveGames(); - - void ReadSaveStrings(); - void UnloadSaveData(); - - int RemoveSaveSlot(int index); - void LoadSavegame(int Selected); - void DoSave(int Selected, const char *savegamestring); - unsigned ExtractSaveData(int index); - void ClearSaveStuff(); - bool DrawSavePic(int x, int y, int w, int h); - void DrawSaveComment(FFont *font, int cr, int x, int y, int scalefactor); - void SetFileInfo(int Selected); - unsigned SavegameCount(); - FSaveGameNode *GetSavegame(int i); - void InsertNewSaveNode(); - bool RemoveNewSaveNode(); - + void PerformSaveGame(const char *fn, const char *sgdesc) override; + void PerformLoadGame(const char *fn, bool) override; + FString ExtractSaveComment(FSerializer &arc) override; + FString BuildSaveName(const char* prefix, int slot) override; + void ReadSaveStrings() override; }; extern FSavegameManager savegameManager; diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 3200d379d..23d05b58d 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -4,7 +4,7 @@ ** **--------------------------------------------------------------------------- ** Copyright 2001-2010 Randy Heit -** Copyright 2010-2017 Christoph Oelckers +** Copyright 2010-2020 Christoph Oelckers ** All rights reserved. ** ** Redistribution and use in source and binary forms, with or without @@ -50,100 +50,6 @@ // Save name length limit for old binary formats. #define OLDSAVESTRINGSIZE 24 -//============================================================================= -// -// Save data maintenance -// -//============================================================================= - -void FSavegameManager::ClearSaveGames() -{ - for (unsigned i = 0; ibNoDelete) - delete SaveGames[i]; - } - SaveGames.Clear(); -} - -FSavegameManager::~FSavegameManager() -{ - ClearSaveGames(); -} - -//============================================================================= -// -// Save data maintenance -// -//============================================================================= - -int FSavegameManager::RemoveSaveSlot(int index) -{ - int listindex = SaveGames[0]->bNoDelete ? index - 1 : index; - if (listindex < 0) return index; - - remove(SaveGames[index]->Filename.GetChars()); - UnloadSaveData(); - - FSaveGameNode *file = SaveGames[index]; - - if (quickSaveSlot == SaveGames[index]) - { - quickSaveSlot = nullptr; - } - if (!file->bNoDelete) delete file; - - if (LastSaved == listindex) LastSaved = -1; - else if (LastSaved > listindex) LastSaved--; - if (LastAccessed == listindex) LastAccessed = -1; - else if (LastAccessed > listindex) LastAccessed--; - - SaveGames.Delete(index); - if ((unsigned)index >= SaveGames.Size()) index--; - ExtractSaveData(index); - return index; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveSaveSlot) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - ACTION_RETURN_INT(self->RemoveSaveSlot(sel)); -} - - -//============================================================================= -// -// -// -//============================================================================= - -int FSavegameManager::InsertSaveNode(FSaveGameNode *node) -{ - if (SaveGames.Size() == 0) - { - return SaveGames.Push(node); - } - - if (node->bOldVersion) - { // Add node at bottom of list - return SaveGames.Push(node); - } - else - { // Add node at top of list - unsigned int i; - for (i = 0; i < SaveGames.Size(); i++) - { - if (SaveGames[i]->bOldVersion || node->SaveTitle.CompareNoCase(SaveGames[i]->SaveTitle) <= 0) - { - break; - } - } - SaveGames.Insert(i, node); - return i; - } -} - //============================================================================= // // M_ReadSaveStrings @@ -303,92 +209,15 @@ void FSavegameManager::ReadSaveStrings() } } -DEFINE_ACTION_FUNCTION(FSavegameManager, ReadSaveStrings) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->ReadSaveStrings(); - return 0; -} - - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::NotifyNewSave(const FString &file, const FString &title, bool okForQuicksave, bool forceQuicksave) -{ - FSaveGameNode *node; - - if (file.IsEmpty()) - return; - - ReadSaveStrings(); - - // See if the file is already in our list - for (unsigned i = 0; iFilename.Compare(file) == 0) -#else - if (node->Filename.CompareNoCase(file) == 0) -#endif - { - node->SaveTitle = title; - node->bOldVersion = false; - node->bMissingWads = false; - if (okForQuicksave) - { - if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; - LastAccessed = LastSaved = i; - } - return; - } - } - - node = new FSaveGameNode; - node->SaveTitle = title; - node->Filename = file; - node->bOldVersion = false; - node->bMissingWads = false; - int index = InsertSaveNode(node); - - if (okForQuicksave) - { - if (quickSaveSlot == nullptr || quickSaveSlot == (FSaveGameNode*)1 || forceQuicksave) quickSaveSlot = node; - LastAccessed = LastSaved = index; - } - else - { - LastAccessed = ++LastSaved; - } -} - //============================================================================= // // Loads the savegame // //============================================================================= -void FSavegameManager::LoadSavegame(int Selected) +void FSavegameManager::PerformLoadGame(const char *fn, bool flag) { - G_LoadGame(SaveGames[Selected]->Filename.GetChars(), true); - if (quickSaveSlot == (FSaveGameNode*)1) - { - quickSaveSlot = SaveGames[Selected]; - } - M_ClearMenus(); - LastAccessed = Selected; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - self->LoadSavegame(sel); - return 0; + G_LoadGame(fn, flag); } //============================================================================= @@ -397,39 +226,9 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, LoadSavegame) // //============================================================================= -void FSavegameManager::DoSave(int Selected, const char *savegamestring) +void FSavegameManager::PerformSaveGame(const char *fn, 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; - - for (i = 0;; ++i) - { - filename = G_BuildSaveName("save", i); - if (!FileExists(filename)) - { - break; - } - } - G_SaveGame(filename, savegamestring); - } - M_ClearMenus(); -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - PARAM_STRING(name); - self->DoSave(sel, name); - return 0; + G_SaveGame(fn, savegamestring); } //============================================================================= @@ -438,87 +237,22 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, DoSave) // //============================================================================= -unsigned FSavegameManager::ExtractSaveData(int index) +FString FSavegameManager::ExtractSaveComment(FSerializer &arc) { - FResourceFile *resf; - FSaveGameNode *node; + FString comment; - if (index == -1) - { - if (SaveGames.Size() > 0 && SaveGames[0]->bNoDelete) - { - index = LastSaved + 1; - } - else - { - index = LastAccessed < 0? 0 : LastAccessed; - } - } + FString time = arc.GetString("Creation Time"); + FString pcomment = arc.GetString("Comment"); - UnloadSaveData(); - - if ((unsigned)index < SaveGames.Size() && - (node = SaveGames[index]) && - !node->Filename.IsEmpty() && - !node->bOldVersion && - (resf = FResourceFile::OpenResourceFile(node->Filename.GetChars(), true)) != nullptr) - { - FResourceLump *info = resf->FindLump("info.json"); - if (info == nullptr) - { - // this should not happen because the file has already been verified. - return index; - } - void *data = info->Lock(); - FSerializer arc; - if (arc.OpenReader((const char *)data, info->LumpSize)) - { - FString comment; - - FString time = arc.GetString("Creation Time"); - FString pcomment = arc.GetString("Comment"); - - comment = time; - if (time.Len() > 0) comment += "\n"; - comment += pcomment; - SaveCommentString = comment; - - // Extract pic - FResourceLump *pic = resf->FindLump("savepic.png"); - if (pic != nullptr) - { - FileReader picreader; - - picreader.OpenMemoryArray([=](TArray &array) - { - auto cache = pic->Lock(); - array.Resize(pic->LumpSize); - memcpy(&array[0], cache, pic->LumpSize); - return true; - }); - PNGHandle *png = M_VerifyPNG(picreader); - if (png != nullptr) - { - SavePic = PNGTexture_CreateFromFile(png, node->Filename); - delete png; - if (SavePic && SavePic->GetDisplayWidth() == 1 && SavePic->GetDisplayHeight() == 1) - { - delete SavePic; - SavePic = nullptr; - } - } - } - } - delete resf; - } - return index; + comment = time; + if (time.Len() > 0) comment += "\n"; + comment += pcomment; + return comment; } -DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) +FString FSavegameManager::BuildSaveName(const char* prefix, int slot) { - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(sel); - ACTION_RETURN_INT(self->ExtractSaveData(sel)); + return G_BuildSaveName(prefix, slot); } //============================================================================= @@ -527,170 +261,6 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, ExtractSaveData) // //============================================================================= -void FSavegameManager::UnloadSaveData() -{ - if (SavePic != nullptr) - { - delete SavePic; - } - - SaveCommentString = ""; - SavePic = nullptr; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, UnloadSaveData) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->UnloadSaveData(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::ClearSaveStuff() -{ - UnloadSaveData(); - if (quickSaveSlot == (FSaveGameNode*)1) - { - quickSaveSlot = nullptr; - } -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, ClearSaveStuff) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->ClearSaveStuff(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -bool FSavegameManager::DrawSavePic(int x, int y, int w, int h) -{ - if (SavePic == nullptr) return false; - DrawTexture(twod, SavePic, x, y, DTA_DestWidth, w, DTA_DestHeight, h, DTA_Masked, false, TAG_DONE); - return true; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, DrawSavePic) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(x); - PARAM_INT(y); - PARAM_INT(w); - PARAM_INT(h); - ACTION_RETURN_BOOL(self->DrawSavePic(x, y, w, h)); -} - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::SetFileInfo(int Selected) -{ - if (!SaveGames[Selected]->Filename.IsEmpty()) - { - SaveCommentString.Format("File on disk:\n%s", SaveGames[Selected]->Filename.GetChars()); - } -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, SetFileInfo) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(i); - self->SetFileInfo(i); - return 0; -} - - -//============================================================================= -// -// -// -//============================================================================= - -unsigned FSavegameManager::SavegameCount() -{ - return SaveGames.Size(); -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, SavegameCount) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - ACTION_RETURN_INT(self->SavegameCount()); -} - -//============================================================================= -// -// -// -//============================================================================= - -FSaveGameNode *FSavegameManager::GetSavegame(int i) -{ - return SaveGames[i]; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, GetSavegame) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - PARAM_INT(i); - ACTION_RETURN_POINTER(self->GetSavegame(i)); -} - -//============================================================================= -// -// -// -//============================================================================= - -void FSavegameManager::InsertNewSaveNode() -{ - NewSaveNode.SaveTitle = GStrings["NEWSAVE"]; - NewSaveNode.bNoDelete = true; - SaveGames.Insert(0, &NewSaveNode); -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, InsertNewSaveNode) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - self->InsertNewSaveNode(); - return 0; -} - -//============================================================================= -// -// -// -//============================================================================= - -bool FSavegameManager::RemoveNewSaveNode() -{ - if (SaveGames[0] == &NewSaveNode) - { - SaveGames.Delete(0); - return true; - } - return false; -} - -DEFINE_ACTION_FUNCTION(FSavegameManager, RemoveNewSaveNode) -{ - PARAM_SELF_STRUCT_PROLOGUE(FSavegameManager); - ACTION_RETURN_INT(self->RemoveNewSaveNode()); -} - - FSavegameManager savegameManager; DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager) @@ -699,15 +269,3 @@ DEFINE_ACTION_FUNCTION(FSavegameManager, GetManager) ACTION_RETURN_POINTER(&savegameManager); } - - -DEFINE_FIELD(FSaveGameNode, SaveTitle); -DEFINE_FIELD(FSaveGameNode, Filename); -DEFINE_FIELD(FSaveGameNode, bOldVersion); -DEFINE_FIELD(FSaveGameNode, bMissingWads); -DEFINE_FIELD(FSaveGameNode, bNoDelete); - -DEFINE_FIELD(FSavegameManager, WindowSize); -DEFINE_FIELD(FSavegameManager, quickSaveSlot); -DEFINE_FIELD(FSavegameManager, SaveCommentString); - diff --git a/wadsrc/static/filter/game-doomchex/sndinfo.txt b/wadsrc/static/filter/game-doomchex/sndinfo.txt index c103f493c..d90b8167f 100644 --- a/wadsrc/static/filter/game-doomchex/sndinfo.txt +++ b/wadsrc/static/filter/game-doomchex/sndinfo.txt @@ -440,6 +440,7 @@ menu/invalid dsoof // Menu not available menu/dismiss dsswtchx // Dismiss a prompt message menu/choose dspistol // Choose a menu item menu/clear dsswtchx // Close top menu +$alias menu/advance menu/choose // Open a submenu $random menu/quit1 { player/male/death1 demon/pain grunt/pain misc/gibbed misc/teleport grunt/sight1 grunt/sight3 demon/melee } $random menu/quit2 { vile/active misc/p_pkup brain/cube misc/gibbed skeleton/swing knight/death baby/active demon/melee } diff --git a/wadsrc/static/filter/game-heretic/sndinfo.txt b/wadsrc/static/filter/game-heretic/sndinfo.txt index 53017a49a..60a0cda6f 100644 --- a/wadsrc/static/filter/game-heretic/sndinfo.txt +++ b/wadsrc/static/filter/game-heretic/sndinfo.txt @@ -283,6 +283,7 @@ menu/change keyup menu/invalid plroof menu/dismiss dorcls menu/clear dorcls +$alias menu/advance menu/choose misc/secret dssecret diff --git a/wadsrc/static/filter/game-hexen/sndinfo.txt b/wadsrc/static/filter/game-hexen/sndinfo.txt index 2e36ab321..06598288c 100644 --- a/wadsrc/static/filter/game-hexen/sndinfo.txt +++ b/wadsrc/static/filter/game-hexen/sndinfo.txt @@ -165,6 +165,7 @@ $alias menu/invalid DoorCloseMetal // Hexen does not use this, but I do $alias menu/dismiss PlatformStop $alias menu/choose DoorCloseLight $alias menu/clear PlatformStop +$alias menu/advance menu/choose // Hexen does not have ripslop sound like Heretic misc/ripslop dsempty diff --git a/wadsrc/static/filter/game-strife/sndinfo.txt b/wadsrc/static/filter/game-strife/sndinfo.txt index f602a969b..f029373dd 100644 --- a/wadsrc/static/filter/game-strife/sndinfo.txt +++ b/wadsrc/static/filter/game-strife/sndinfo.txt @@ -107,6 +107,7 @@ menu/invalid dsoof // Menu not available menu/dismiss dsswish // Dismiss a prompt message menu/choose dsrifl // Choose a menu item menu/clear dsmtalht // Close top menu +$alias menu/advance menu/choose misc/startupdone dspsdtha misc/teleport dstelept diff --git a/wadsrc/static/zscript/base.zs b/wadsrc/static/zscript/base.zs index b6c654356..65b9fefaf 100644 --- a/wadsrc/static/zscript/base.zs +++ b/wadsrc/static/zscript/base.zs @@ -652,3 +652,12 @@ struct StringStruct native native int CodePointCount() const; native int, int GetNextCodePoint(int position) const; } + +struct Translation version("2.4") +{ + static int MakeID(int group, int num) + { + return (group << 16) + num; + } +} + diff --git a/wadsrc/static/zscript/doombase.zs b/wadsrc/static/zscript/doombase.zs index e675ac6a4..d4c4129a5 100644 --- a/wadsrc/static/zscript/doombase.zs +++ b/wadsrc/static/zscript/doombase.zs @@ -42,17 +42,13 @@ extend struct Screen } } -struct Translation version("2.4") +extend struct Translation { Color colors[256]; native int AddTranslation(); native static bool SetPlayerTranslation(int group, int num, int plrnum, PlayerClass pclass); native static int GetID(Name transname); - static int MakeID(int group, int num) - { - return (group << 16) + num; - } } struct DamageTypeDefinition native