Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions src/Misc/SavedGamesInSubdir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,8 @@ DEFINE_HOOK(0x67D2E3, SaveGame_AdditionalInfoForClient, 0x6)
{
if (Spawner::GetConfig()->CustomMissionID)
WriteToStorage<CustomMissionID>(pStorage);
if (Spawner::GetConfig()->DisableSaveLoad)// you fucking cheater
pStorage->DestroyElement(L"CONTENTS");
}

return 0;
Expand Down Expand Up @@ -343,3 +345,90 @@ DEFINE_HOOK(0x55DC85, MainLoop_SaveGame_SanitizeFilename, 0x7)

return 0x55DC90;
}

#pragma region nosaveload
#include <WWMessageBox.h>
#include <LoadProgressManager.h>

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
1 change: 1 addition & 0 deletions src/Spawner/Spawner.Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/Spawner/Spawner.Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class SpawnerConfig
bool ContinueWithoutHumans;
bool DefeatedBecomesObserver;
bool Observer_ShowAIOnSidebar;
bool DisableSaveLoad;

SpawnerConfig() // default values
// Game Mode Options
Expand Down Expand Up @@ -242,6 +243,7 @@ class SpawnerConfig
, ContinueWithoutHumans { false }
, DefeatedBecomesObserver { false }
, Observer_ShowAIOnSidebar { false }
, DisableSaveLoad { false }
{ }

void LoadFromINIFile(CCINIClass* pINI);
Expand Down
7 changes: 7 additions & 0 deletions src/Spawner/Spawner.Hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/Spawner/Spawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down