From 1867088f27f956d324a014118b9f7a71bfea7167 Mon Sep 17 00:00:00 2001 From: Dextinfire <> Date: Sun, 29 Sep 2024 01:54:03 -0700 Subject: [PATCH] Quick Saving: Create quick load menu by sorting entries by date time Add auto quicksaving and quick saving TODO: Somehow check if quick save already happened so qs button can't get spammed. --- src/data/savesystem.cpp | 13 +++--- src/data/savesystem.h | 17 ++++++-- src/games/cclcc/savemenu.cpp | 38 +++++++++++++++--- src/games/cclcc/savesystem.cpp | 10 +++-- src/games/cclcc/savesystem.h | 2 +- src/games/chlcc/savesystem.cpp | 8 +++- src/games/chlcc/savesystem.h | 2 +- src/games/mo6tw/savesystem.cpp | 9 ++++- src/games/mo6tw/savesystem.h | 2 +- src/ui/widgets/cclcc/saveentrybutton.cpp | 8 ++-- src/ui/widgets/cclcc/saveentrybutton.h | 8 ++-- src/vm/inst_dialogue.cpp | 27 ++++++++++++- src/vm/inst_system.cpp | 50 +++++++++++++++--------- 13 files changed, 141 insertions(+), 53 deletions(-) diff --git a/src/data/savesystem.cpp b/src/data/savesystem.cpp index c6636768..879ae13d 100644 --- a/src/data/savesystem.cpp +++ b/src/data/savesystem.cpp @@ -46,8 +46,9 @@ void LoadMemoryNew(LoadProcess load) { if (Implementation) Implementation->LoadMemoryNew(load); } -void FlushWorkingSaveEntry(SaveType type, int id) { - if (Implementation) Implementation->FlushWorkingSaveEntry(type, id); +void FlushWorkingSaveEntry(SaveType type, int id, int autoSaveType) { + if (Implementation) + Implementation->FlushWorkingSaveEntry(type, id, autoSaveType); } void WriteSaveFile() { @@ -172,11 +173,11 @@ void SetCheckpointId(int id) { if (Implementation) Implementation->SetCheckpointId(id); } -int GetQuickSaveCount() { - if (Implementation) return Implementation->GetQuickSaveCount(); +int GetQuickSaveOpenSlot() { + if (Implementation) return Implementation->GetQuickSaveOpenSlot(); ImpLog(LL_Warning, LC_VMStub, - "%s: save system not implemented, returning 0\n", __func__); - return 0; + "%s: save system not implemented, returning -1\n", __func__); + return -1; } Sprite const& GetSaveThumbnail(SaveType type, int id) { diff --git a/src/data/savesystem.h b/src/data/savesystem.h index efb10543..f0d75f7c 100644 --- a/src/data/savesystem.h +++ b/src/data/savesystem.h @@ -72,7 +72,8 @@ class SaveSystemBase { virtual void SaveMemory() = 0; virtual void LoadEntry(SaveType type, int id) = 0; virtual void LoadMemoryNew(LoadProcess){}; - virtual void FlushWorkingSaveEntry(SaveType type, int id) = 0; + virtual void FlushWorkingSaveEntry(SaveType type, int id, + int autoSaveType) = 0; virtual void WriteSaveFile() = 0; virtual uint32_t GetSavePlayTime(SaveType type, int id) = 0; virtual uint8_t GetSaveFlags(SaveType type, int id) = 0; @@ -93,7 +94,15 @@ class SaveSystemBase { virtual bool GetBgmFlag(int id) = 0; virtual void SetCheckpointId(int id) = 0; virtual Sprite const& GetSaveThumbnail(SaveType type, int id) = 0; - int GetQuickSaveCount() { return QuickSaveCount; } + int GetQuickSaveOpenSlot() { + for (int i = 0; i < MaxSaveEntries; i++) { + if (QuickSaveEntries[i]->Status == 0) return i; + } + for (int i = 0; i < MaxSaveEntries; i++) { + if (GetSaveFlags(SaveQuick, i) != 1) return i; + } + return -1; + } Sprite const& GetWorkingSaveThumbnail() { return WorkingSaveThumbnail; } protected: @@ -113,7 +122,7 @@ SaveError MountSaveFile(); void SaveMemory(); void LoadEntry(SaveType type, int id); void LoadMemoryNew(LoadProcess process); -void FlushWorkingSaveEntry(SaveType type, int id); +void FlushWorkingSaveEntry(SaveType type, int id, int autoSaveType = 0); void WriteSaveFile(); uint32_t GetSavePlayTime(SaveType type, int id); uint8_t GetSaveFlags(SaveType type, int id); @@ -130,7 +139,7 @@ void GetEVStatus(int evId, int* totalVariations, int* viewedVariations); bool GetEVVariationIsUnlocked(int evId, int variationIdx); bool GetBgmFlag(int id); void SetCheckpointId(int id); -int GetQuickSaveCount(); +int GetQuickSaveOpenSlot(); Sprite const& GetSaveThumbnail(SaveType type, int id); Sprite const& GetWorkingSaveThumbnail(); diff --git a/src/games/cclcc/savemenu.cpp b/src/games/cclcc/savemenu.cpp index e9e7c124..984728b0 100644 --- a/src/games/cclcc/savemenu.cpp +++ b/src/games/cclcc/savemenu.cpp @@ -55,6 +55,37 @@ void SaveMenu::Show() { State = Showing; FadeAnimation.StartIn(); int id = 0; + Impacto::SaveSystem::SaveType saveType = + ScrWork[SW_SAVEMENUMODE] == SaveMenuPageType::QuickLoad + ? SaveSystem::SaveType::SaveQuick + : SaveSystem::SaveType::SaveFull; + + std::array saveEntryIds; + for (int i = 0; i < SaveSystem::MaxSaveEntries; i++) { + saveEntryIds[i] = i; + } + if (saveType == SaveSystem::SaveType::SaveQuick) { + // quick saves are sorted by time and status + std::sort(saveEntryIds.begin(), saveEntryIds.end(), + [saveType](int a, int b) { + int statusA = SaveSystem::GetSaveStatus(saveType, a); + int statusB = SaveSystem::GetSaveStatus(saveType, b); + if (statusA == statusB) { + std::tm ta = SaveSystem::GetSaveDate(saveType, a); + std::tm tb = SaveSystem::GetSaveDate(saveType, b); + std::time_t th = std::mktime(&ta); + std::time_t tl = std::mktime(&tb); + if (th == -1 || tl == -1) { + ImpLog(LL_Error, LC_General, + "Failed to convert time to time_t\n"); + return statusA > statusB; + } + return difftime(th, tl) > 0; + } + return statusA > statusB; + }); + } + for (int p = 0; p < Pages; ++p) { MainItems[p] = new Widgets::Group(this); MainItems[p]->WrapFocus = false; @@ -62,16 +93,13 @@ void SaveMenu::Show() { for (int i = 0; i < RowsPerPage; i++) { // Start on right col for (int j = EntriesPerRow - 1; j >= 0; j--) { - Impacto::SaveSystem::SaveType saveType = - ScrWork[SW_SAVEMENUMODE] == SaveMenuPageType::QuickLoad - ? SaveSystem::SaveType::SaveQuick - : SaveSystem::SaveType::SaveFull; glm::vec2 buttonPos = (j == 0) ? glm::vec2{EntryStartXL, EntryStartYL + (i * EntryYPadding)} : glm::vec2{EntryStartXR, EntryStartYR + (i * EntryYPadding)}; SaveEntryButton* saveEntryButton = new SaveEntryButton( - id, EntryHighlightedBoxSprite[ScrWork[SW_SAVEMENUMODE]], + saveEntryIds[id], id, + EntryHighlightedBoxSprite[ScrWork[SW_SAVEMENUMODE]], EntryHighlightedTextSprite[ScrWork[SW_SAVEMENUMODE]], p, buttonPos, SlotLockedSprite[ScrWork[SW_SAVEMENUMODE]], saveType, NoDataSprite[ScrWork[SW_SAVEMENUMODE]], diff --git a/src/games/cclcc/savesystem.cpp b/src/games/cclcc/savesystem.cpp index 9b55a9c2..504187bb 100644 --- a/src/games/cclcc/savesystem.cpp +++ b/src/games/cclcc/savesystem.cpp @@ -232,20 +232,24 @@ SaveError SaveSystem::MountSaveFile() { // return 0; //} -void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id) { +void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id, + int autoSaveType) { SaveFileEntry* entry = 0; switch (type) { case SaveQuick: - entry = (SaveFileEntry*)QuickSaveEntries[QuickSaveCount++]; + entry = (SaveFileEntry*)QuickSaveEntries[id]; break; case SaveFull: entry = (SaveFileEntry*)FullSaveEntries[id]; break; } - if (entry != 0) { + if (entry != 0 && GetSaveFlags(type, id) != 1) { Renderer->FreeTexture(entry->SaveThumbnail.Sheet.Texture); *entry = *WorkingSaveEntry; + if (type == SaveQuick) { + entry->SaveType = autoSaveType; + } time_t rawtime; time(&rawtime); entry->SaveDate = *localtime(&rawtime); diff --git a/src/games/cclcc/savesystem.h b/src/games/cclcc/savesystem.h index f0a86545..098068d9 100644 --- a/src/games/cclcc/savesystem.h +++ b/src/games/cclcc/savesystem.h @@ -32,7 +32,7 @@ class SaveSystem : public SaveSystemBase { void SaveMemory() override; void LoadEntry(SaveType type, int id) override; void LoadMemoryNew(LoadProcess load) override; - void FlushWorkingSaveEntry(SaveType type, int id) override; + void FlushWorkingSaveEntry(SaveType type, int id, int autoSaveType) override; void WriteSaveFile() override; uint32_t GetSavePlayTime(SaveType type, int id) override; uint8_t GetSaveFlags(SaveType type, int id) override; diff --git a/src/games/chlcc/savesystem.cpp b/src/games/chlcc/savesystem.cpp index 8e79cc8c..93f1ebba 100644 --- a/src/games/chlcc/savesystem.cpp +++ b/src/games/chlcc/savesystem.cpp @@ -132,7 +132,8 @@ SaveError SaveSystem::MountSaveFile() { // return 0; //} -void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id) { +void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id, + int autoSaveType) { SaveFileEntry* entry = 0; switch (type) { case SaveQuick: @@ -144,8 +145,11 @@ void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id) { } if (WorkingSaveEntry != 0) { - if (entry != 0) { + if (entry != 0 && GetSaveFlags(type, id) != 1) { *entry = *WorkingSaveEntry; + if (type == SaveQuick) { + entry->SaveType = autoSaveType; + } time_t rawtime; time(&rawtime); entry->SaveDate = *localtime(&rawtime); diff --git a/src/games/chlcc/savesystem.h b/src/games/chlcc/savesystem.h index 6917c26e..75977cd8 100644 --- a/src/games/chlcc/savesystem.h +++ b/src/games/chlcc/savesystem.h @@ -22,7 +22,7 @@ class SaveSystem : public SaveSystemBase { SaveError MountSaveFile() override; void SaveMemory() override; void LoadEntry(SaveType type, int id) override; - void FlushWorkingSaveEntry(SaveType type, int id) override; + void FlushWorkingSaveEntry(SaveType type, int id, int autoSaveType) override; void WriteSaveFile() override; uint32_t GetSavePlayTime(SaveType type, int id) override; uint8_t GetSaveFlags(SaveType type, int id) override; diff --git a/src/games/mo6tw/savesystem.cpp b/src/games/mo6tw/savesystem.cpp index f4c025a6..60e9b943 100644 --- a/src/games/mo6tw/savesystem.cpp +++ b/src/games/mo6tw/savesystem.cpp @@ -190,7 +190,8 @@ SaveError SaveSystem::MountSaveFile() { // return 0; //} -void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id) { +void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id, + int autoSaveType) { SaveFileEntry* entry = 0; switch (type) { case SaveQuick: @@ -202,7 +203,11 @@ void SaveSystem::FlushWorkingSaveEntry(SaveType type, int id) { } if (WorkingSaveEntry != 0) { - if (entry != 0) { + if (entry != 0 && GetSaveFlags(type, id) != 1) { + Renderer->FreeTexture(entry->SaveThumbnail.Sheet.Texture); + if (type == SaveQuick) { + entry->SaveType = autoSaveType; + } entry->Status = 1; std::time_t t = std::time(0); diff --git a/src/games/mo6tw/savesystem.h b/src/games/mo6tw/savesystem.h index 54c3c8ea..ddb376bb 100644 --- a/src/games/mo6tw/savesystem.h +++ b/src/games/mo6tw/savesystem.h @@ -22,7 +22,7 @@ class SaveSystem : public SaveSystemBase { SaveError MountSaveFile() override; void SaveMemory() override; void LoadEntry(SaveType type, int id) override; - void FlushWorkingSaveEntry(SaveType type, int id) override; + void FlushWorkingSaveEntry(SaveType type, int id, int autoSaveType) override; void WriteSaveFile() override; uint32_t GetSavePlayTime(SaveType type, int id) override; uint8_t GetSaveFlags(SaveType type, int id) override; diff --git a/src/ui/widgets/cclcc/saveentrybutton.cpp b/src/ui/widgets/cclcc/saveentrybutton.cpp index 7c6ec238..db8582cb 100644 --- a/src/ui/widgets/cclcc/saveentrybutton.cpp +++ b/src/ui/widgets/cclcc/saveentrybutton.cpp @@ -20,19 +20,17 @@ using namespace Impacto::SaveSystem; glm::vec4 SaveEntryButton::FocusedAlpha = glm::vec4(1.0f); Animation SaveEntryButton::FocusedAlphaFade; -SaveEntryButton::SaveEntryButton(int id, Sprite const& focusedBox, +SaveEntryButton::SaveEntryButton(int id, int index, Sprite const& focusedBox, Sprite const& focusedText, int page, glm::vec2 pos, Sprite lockedSymbol, SaveSystem::SaveType saveType, Sprite NoDataSprite, Sprite BrokenDataSprite) : Widgets::Button( - (saveType == SaveSystem::SaveType::SaveFull - ? id - : SaveSystem::GetQuickSaveCount() - id - 1), + id, Sprite(SpriteSheet(), focusedBox.Bounds.X, focusedBox.Bounds.Y, focusedBox.Bounds.Width, focusedBox.Bounds.Height), Sprite(SpriteSheet(), 0, 0, 0, 0), focusedBox, pos), - Index(id), + Index(index), Page(page), FocusedSpriteLabel(focusedText, glm::vec2{pos.x, pos.y - 34}), LockedSymbol(lockedSymbol, diff --git a/src/ui/widgets/cclcc/saveentrybutton.h b/src/ui/widgets/cclcc/saveentrybutton.h index fe74c3a8..8091776b 100644 --- a/src/ui/widgets/cclcc/saveentrybutton.h +++ b/src/ui/widgets/cclcc/saveentrybutton.h @@ -14,10 +14,10 @@ namespace CCLCC { class SaveEntryButton : public Widgets::Button { public: - SaveEntryButton(int id, Sprite const& focusedBox, Sprite const& focusedText, - int page, glm::vec2 pos, Sprite lockedSymbol, - SaveSystem::SaveType saveType, Sprite noDataSprite, - Sprite brokenDataSprite); + SaveEntryButton(int id, int index, Sprite const& focusedBox, + Sprite const& focusedText, int page, glm::vec2 pos, + Sprite lockedSymbol, SaveSystem::SaveType saveType, + Sprite noDataSprite, Sprite brokenDataSprite); void Render() override; int GetPage() const; void AddNormalSpriteLabel(Sprite norm, glm::vec2 pos); diff --git a/src/vm/inst_dialogue.cpp b/src/vm/inst_dialogue.cpp index 53838576..39902f43 100644 --- a/src/vm/inst_dialogue.cpp +++ b/src/vm/inst_dialogue.cpp @@ -371,7 +371,32 @@ VmInstruction(InstSelect) { switch (type) { case 0: { UI::SelectionMenuPtr->Show(); - SaveIconDisplay::ShowFor(2.4f); + bool flag = GetFlag(1282); + int unk = ScrWork[2108]; + if (unk < 0x100) { + ScrWork[2108] = unk + 0x10; + SetFlag(1286, 1); + ResetInstruction; + BlockThread; + } + SetFlag(thread->DialoguePageId + 1213, 0); + if (ScrWork[2112] == 2) { + thread->Ip += 12; + return; + } else { + SaveSystem::SaveMemory(); + int quicksaveEntries = SaveSystem::GetQuickSaveOpenSlot(); + if (!flag && quicksaveEntries != -1) { + SaveIconDisplay::ShowFor(2.4f); + SaveSystem::FlushWorkingSaveEntry(SaveSystem::SaveType::SaveQuick, + quicksaveEntries, 2); + } + ScrWork[2112] = 0; + if (quicksaveEntries == -1) { + thread->Ip += 12; + } + } + SetFlag(1286, 0); } break; case 1: { if (!UI::SelectionMenuPtr->ChoiceMade) { diff --git a/src/vm/inst_system.cpp b/src/vm/inst_system.cpp index b0642a91..154d6996 100644 --- a/src/vm/inst_system.cpp +++ b/src/vm/inst_system.cpp @@ -710,38 +710,49 @@ VmInstruction(InstDebugData) { } VmInstruction(InstAutoSave) { StartInstruction; + auto quickSave = [&](int autosaveRestartCheck, int saveType) { + SaveSystem::SaveMemory(); + if (ScrWork[2112] != autosaveRestartCheck) { + int quicksaveEntries = SaveSystem::GetQuickSaveOpenSlot(); + if (quicksaveEntries != -1) { + SaveIconDisplay::ShowFor(2.4f); + SaveSystem::FlushWorkingSaveEntry(SaveSystem::SaveType::SaveQuick, + quicksaveEntries, saveType); + } + } + SetFlag(1285, 1); + ScrWork[2112] = 0; + }; + PopUint8(type); switch (type) { case 0: // QuickSave - SaveIconDisplay::ShowFor(2.4f); + case 20: if (ScrWork[SW_TITLE] == 0xffff) break; - SaveSystem::SaveMemory(); - if (ScrWork[2112] != 1) { - // TODO: Quicksave(1) - } - SetFlag(1285, 1); - ScrWork[2112] = 0; + quickSave(1, 1); ImpLogSlow(LL_Warning, LC_VMStub, "STUB instruction AutoSave(type: QuickSave)\n"); break; case 1: // AutoSaveRestart (?) + case 21: if (ScrWork[SW_TITLE] == 0xffff) break; - SaveSystem::SaveMemory(); - if ((ScrWork[2112] != 3)) { - // TODO: Quicksave(3) - } - SetFlag(1285, 1); - ScrWork[2112] = 0; + quickSave(3, 3); ImpLogSlow(LL_Warning, LC_VMStub, "STUB instruction AutoSave(type: %i)\n", type); break; - case 3: // DisableAutoSave - // Check quicksave, quicksave(0) + case 3: { // DisableAutoSave + int quicksaveEntries = SaveSystem::GetQuickSaveOpenSlot(); + if (quicksaveEntries != -1) { + SaveIconDisplay::ShowFor(2.4f); + SaveSystem::FlushWorkingSaveEntry(SaveSystem::SaveType::SaveQuick, + quicksaveEntries, 0); + } + SetFlag(1285, 0); ImpLogSlow(LL_Warning, LC_VMStub, "STUB instruction AutoSave(type: %i)\n", type); - break; - case 5: // EnableAutoSave + } break; + case 5: { // EnableAutoSave ImpLogSlow(LL_Warning, LC_VMStub, "STUB instruction AutoSave(type: %i)\n", type); if (ScrWork[SW_TITLE] != 0xffff) { @@ -749,7 +760,7 @@ VmInstruction(InstAutoSave) { SetFlag(1285, 1); ScrWork[2112] = 0; } - break; + } break; case 10: { // SetCheckpointId if (Profile::Vm::UseReturnIds) { PopUint16(checkpointId); @@ -771,6 +782,9 @@ VmInstruction(InstAutoSave) { ImpLogSlow(LL_Warning, LC_VMStub, "STUB instruction AutoSave(arg1: %i)\n", type); break; + case 0xff: { + BlockThread; + } break; default: // More quicksave cases here break;