From 48ee0864eacaac1a2f58f9dbb660d22f332ca52d Mon Sep 17 00:00:00 2001 From: Trsdy <914137150@qq.com> Date: Wed, 4 Mar 2026 12:12:06 +0800 Subject: [PATCH 1/2] legacy shit --- src/Misc/SavedGamesInSubdir.cpp | 89 +++++++++++++++++++++++++++++++++ src/Spawner/Spawner.Config.cpp | 1 + src/Spawner/Spawner.Config.h | 2 + src/Spawner/Spawner.Hook.cpp | 7 +++ src/Spawner/Spawner.cpp | 2 +- 5 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/Misc/SavedGamesInSubdir.cpp b/src/Misc/SavedGamesInSubdir.cpp index 6a9ce5bf..3bf72031 100644 --- a/src/Misc/SavedGamesInSubdir.cpp +++ b/src/Misc/SavedGamesInSubdir.cpp @@ -284,6 +284,8 @@ DEFINE_HOOK(0x67D2E3, SaveGame_AdditionalInfoForClient, 0x6) { if (Spawner::GetConfig()->CustomMissionID) WriteToStorage(pStorage); + if (Spawner::GetConfig()->DisableSaveLoad)// you fucking cheater + pStorage->DestroyElement(L"CONTENTS"); } return 0; @@ -343,3 +345,90 @@ DEFINE_HOOK(0x55DC85, MainLoop_SaveGame_SanitizeFilename, 0x7) return 0x55DC90; } + +#pragma region nosaveload +#include +#include + +DEFINE_HOOK(0x686089, DoLose_RetryDialogForCampaigns, 0x7) +{ + if (!Spawner::GetConfig()->DisableSaveLoad) return 0; + + WWMessageBox::Instance.Process( + PRIMARYLANGID(GetUserDefaultUILanguage()) == LANG_CHINESE ? L"\u83dc" : L"GG", + StringTable::LoadString("TXT_OK"), nullptr, nullptr); + + return 0x6860EE; +} + +// disable load, save and delete buttons on the ingame menu +DEFINE_HOOK(0x4F17F6, sub_4F1720_DisableSaves, 0x6) +{ + if (!Spawner::GetConfig()->DisableSaveLoad) return 0; + GET(HWND, hDlg, EBP); + + enum { LoadGameButton = 1310, DeleteGameButton = 1312 }; + + for (int item = LoadGameButton; item <= DeleteGameButton; ++item) + { + if (HWND hItem = GetDlgItem(hDlg, item)) + EnableWindow(hItem, FALSE); + } + + return 0x4F1834; +} +inline const wchar_t* get_TXT_HARDCORE_MODE() +{ + std::wstring_view msg = StringTable::LoadString("TXT_HARDCORE_MODE"); + if (msg.empty() || msg.starts_with(L"MISSING")) + msg = L"HARDCORE"; + return msg.data(); +} +DEFINE_HOOK(0x553076, LoadProgressMgr_Draw_ExtraText_Campaign, 0x5) +{ + GET(LoadProgressManager*, self, EBP); + if (!Spawner::GetConfig()->DisableSaveLoad) return 0; + + Point2D pos + { + self->TitleBarRect.X + self->TitleBarRect.Width - 100, + self->TitleBarRect.Y + 10 + }; + LEA_STACK(RectangleStruct*, pBnd, STACK_OFFSET(0x1268, -0x1204)); + if (auto logo = FileSystem::LoadSHPFile("hardcorelogo.shp")) + { + self->ProgressSurface->DrawSHP(FileSystem::PALETTE_PAL, logo, 0, &pos, pBnd, BlitterFlags::bf_400, 0, 0, ZGradient::Ground, 1000, 0, nullptr, 0, 0, 0); + } + else + { + self->ProgressSurface->DrawText(get_TXT_HARDCORE_MODE(), &pos, COLOR_RED); + } + + return 0; +} + +DEFINE_HOOK(0x4F4573, GScreenClass_Draw_SpawnerShit, 0x5) +{ + if (!Spawner::GetConfig()->DisableSaveLoad) return 0; + wchar_t buffer[0x20] {}; + int seconds = Unsorted::CurrentFrame / 15; + swprintf(buffer, std::size(buffer), L"%s %d:%02d", get_TXT_HARDCORE_MODE(), seconds / 60, seconds % 60); + auto wanted = Drawing::GetTextDimensions(buffer, { 0,0 }, 0, 2, 0); + + RectangleStruct rect = { + DSurface::Composite->GetWidth() - wanted.Width - 20, + 0, + wanted.Width + 10, + wanted.Height + 10 + }; + + Point2D location { rect.X - 5,5 }; + + DSurface::Composite->FillRect(&rect, COLOR_BLACK); + DSurface::Composite->DrawText(buffer, &location, COLOR_WHITE); + + //Fucking Phobos + R->ECX(*(int*)0x887640); + return 0x4F4589; +} +#pragma endregion diff --git a/src/Spawner/Spawner.Config.cpp b/src/Spawner/Spawner.Config.cpp index f7297e85..2126991b 100644 --- a/src/Spawner/Spawner.Config.cpp +++ b/src/Spawner/Spawner.Config.cpp @@ -118,6 +118,7 @@ void SpawnerConfig::LoadFromINIFile(CCINIClass* pINI) ContinueWithoutHumans = pINI->ReadBool(pSettingsSection, "ContinueWithoutHumans", ContinueWithoutHumans); DefeatedBecomesObserver = pINI->ReadBool(pSettingsSection, "DefeatedBecomesObserver", DefeatedBecomesObserver); Observer_ShowAIOnSidebar = pINI->ReadBool(pSettingsSection, "Observer.ShowAIOnSidebar", Observer_ShowAIOnSidebar); + DisableSaveLoad = pINI->ReadBool(pSettingsSection, "DisableSaveLoad", false) && IsCampaign && !LoadSaveGame; } } diff --git a/src/Spawner/Spawner.Config.h b/src/Spawner/Spawner.Config.h index 44c7248b..0360df01 100644 --- a/src/Spawner/Spawner.Config.h +++ b/src/Spawner/Spawner.Config.h @@ -147,6 +147,7 @@ class SpawnerConfig bool ContinueWithoutHumans; bool DefeatedBecomesObserver; bool Observer_ShowAIOnSidebar; + bool DisableSaveLoad; SpawnerConfig() // default values // Game Mode Options @@ -242,6 +243,7 @@ class SpawnerConfig , ContinueWithoutHumans { false } , DefeatedBecomesObserver { false } , Observer_ShowAIOnSidebar { false } + , DisableSaveLoad { false } { } void LoadFromINIFile(CCINIClass* pINI); diff --git a/src/Spawner/Spawner.Hook.cpp b/src/Spawner/Spawner.Hook.cpp index 0659dcad..0b2ddc29 100644 --- a/src/Spawner/Spawner.Hook.cpp +++ b/src/Spawner/Spawner.Hook.cpp @@ -73,6 +73,13 @@ DEFINE_HOOK(0x6BD7C5, WinMain_SpawnerInit, 0x6) // Skip load *.PKT, *.YRO and *.YRM map files Patch::Apply_LJMP(0x699AD9, 0x69A1B2); // SessionClass::Read_Scenario_Descriptions + + if (Spawner::GetConfig()->DisableSaveLoad) + { + Patch::Apply_LJMP(0x55DBCD, 0x55DC99); // Disable MainLoop_SaveGame (Spawner&Phobos) + Patch::Apply_RAW(0x67CEF0, { 0x33,0xC0,0xC3 }); // Corrupt savegame function + Patch::Apply_TYPED(0x83D560, { (DWORD)std::rand() }); // Corrupt save game magicn + } } return 0; diff --git a/src/Spawner/Spawner.cpp b/src/Spawner/Spawner.cpp index 2cc048db..e3b6e296 100644 --- a/src/Spawner/Spawner.cpp +++ b/src/Spawner/Spawner.cpp @@ -315,7 +315,7 @@ bool Spawner::StartScenario(const char* pScenarioName) bool result = ScenarioClass::StartScenario(pScenarioName, 1, 0); - if (Spawner::Config->CustomMissionID != 0) // after parsing + if (Spawner::Config->CustomMissionID != 0 || Spawner::Config->DisableSaveLoad) // after parsing ScenarioClass::Instance->EndOfGame = true; return result; From 0a0c8fb6bd289ae52cbae11e9cc20fa8f445fffe Mon Sep 17 00:00:00 2001 From: Trsdy <914137150@qq.com> Date: Wed, 6 May 2026 17:24:26 +0800 Subject: [PATCH 2/2] plz test if savegame still works in normal gamemodes --- src/Misc/SavedGamesInSubdir.cpp | 52 +++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/src/Misc/SavedGamesInSubdir.cpp b/src/Misc/SavedGamesInSubdir.cpp index 3bf72031..3000a0c1 100644 --- a/src/Misc/SavedGamesInSubdir.cpp +++ b/src/Misc/SavedGamesInSubdir.cpp @@ -284,8 +284,6 @@ DEFINE_HOOK(0x67D2E3, SaveGame_AdditionalInfoForClient, 0x6) { if (Spawner::GetConfig()->CustomMissionID) WriteToStorage(pStorage); - if (Spawner::GetConfig()->DisableSaveLoad)// you fucking cheater - pStorage->DestroyElement(L"CONTENTS"); } return 0; @@ -350,12 +348,20 @@ DEFINE_HOOK(0x55DC85, MainLoop_SaveGame_SanitizeFilename, 0x7) #include #include +const wchar_t* Fetch_CSF_Text(const char* label, const wchar_t* defaultText) +{ + std::wstring_view msg = StringTable::LoadString(label); + if (msg.empty() || msg.starts_with(L"MISSING")) + return defaultText; + return msg.data(); +} + DEFINE_HOOK(0x686089, DoLose_RetryDialogForCampaigns, 0x7) { if (!Spawner::GetConfig()->DisableSaveLoad) return 0; WWMessageBox::Instance.Process( - PRIMARYLANGID(GetUserDefaultUILanguage()) == LANG_CHINESE ? L"\u83dc" : L"GG", + Fetch_CSF_Text("TXT_HARDCORE_FAILURE", L"GG"), StringTable::LoadString("TXT_OK"), nullptr, nullptr); return 0x6860EE; @@ -377,13 +383,7 @@ DEFINE_HOOK(0x4F17F6, sub_4F1720_DisableSaves, 0x6) return 0x4F1834; } -inline const wchar_t* get_TXT_HARDCORE_MODE() -{ - std::wstring_view msg = StringTable::LoadString("TXT_HARDCORE_MODE"); - if (msg.empty() || msg.starts_with(L"MISSING")) - msg = L"HARDCORE"; - return msg.data(); -} +std::wstring HardCoreText {}; DEFINE_HOOK(0x553076, LoadProgressMgr_Draw_ExtraText_Campaign, 0x5) { GET(LoadProgressManager*, self, EBP); @@ -394,6 +394,8 @@ DEFINE_HOOK(0x553076, LoadProgressMgr_Draw_ExtraText_Campaign, 0x5) self->TitleBarRect.X + self->TitleBarRect.Width - 100, self->TitleBarRect.Y + 10 }; + if(HardCoreText.empty()) + HardCoreText = Fetch_CSF_Text("TXT_HARDCORE_MODE", L"HardCore"); LEA_STACK(RectangleStruct*, pBnd, STACK_OFFSET(0x1268, -0x1204)); if (auto logo = FileSystem::LoadSHPFile("hardcorelogo.shp")) { @@ -401,7 +403,7 @@ DEFINE_HOOK(0x553076, LoadProgressMgr_Draw_ExtraText_Campaign, 0x5) } else { - self->ProgressSurface->DrawText(get_TXT_HARDCORE_MODE(), &pos, COLOR_RED); + self->ProgressSurface->DrawText(HardCoreText.c_str(), &pos, COLOR_RED); } return 0; @@ -411,23 +413,37 @@ DEFINE_HOOK(0x4F4573, GScreenClass_Draw_SpawnerShit, 0x5) { if (!Spawner::GetConfig()->DisableSaveLoad) return 0; wchar_t buffer[0x20] {}; - int seconds = Unsorted::CurrentFrame / 15; - swprintf(buffer, std::size(buffer), L"%s %d:%02d", get_TXT_HARDCORE_MODE(), seconds / 60, seconds % 60); + int total_seconds = Unsorted::CurrentFrame / 15; + + int hours = total_seconds / 3600; + int minutes = (total_seconds / 60) % 60; + int seconds = total_seconds % 60; + + if (hours > 0) + { + swprintf(buffer, std::size(buffer), L"%ls %d:%02d:%02d", HardCoreText.c_str(), hours, minutes, seconds); + } + else + { + swprintf(buffer, std::size(buffer), L"%ls %02d:%02d", HardCoreText.c_str(), minutes, seconds); + } + auto wanted = Drawing::GetTextDimensions(buffer, { 0,0 }, 0, 2, 0); RectangleStruct rect = { - DSurface::Composite->GetWidth() - wanted.Width - 20, + DSurface::Composite->GetWidth() - wanted.Width - 30, 0, wanted.Width + 10, wanted.Height + 10 }; - Point2D location { rect.X - 5,5 }; - - DSurface::Composite->FillRect(&rect, COLOR_BLACK); + Point2D location { rect.X +5 ,5 }; + ColorStruct color { 0x0, 0x0 ,0x0}; + DSurface::Composite->FillRectTrans(&rect, &color, 50); + DSurface::Composite->DrawRect(&rect, COLOR_WHITE); DSurface::Composite->DrawText(buffer, &location, COLOR_WHITE); - //Fucking Phobos + //Phobos' extended tooltips interferred R->ECX(*(int*)0x887640); return 0x4F4589; }