@@ -280,10 +280,12 @@ DEFINE_HOOK(0x67D2E3, SaveGame_AdditionalInfoForClient, 0x6)
280280 GET_STACK (IStorage*, pStorage, STACK_OFFSET (0x4A0 , -0x490 ));
281281 using namespace SavedGames ;
282282
283- if (pStorage)
283+ if (SessionClass::IsCampaign () && pStorage)
284284 {
285- if (SessionClass::IsCampaign () && Spawner::GetConfig ()->CustomMissionID )
285+ if (Spawner::GetConfig ()->CustomMissionID )
286286 AppendToStorage<CustomMissionID>(pStorage);
287+ if (Spawner::GetConfig ()->DisableSaveLoad )// you fucking cheater
288+ pStorage->DestroyElement (L" CONTENTS" );
287289 }
288290
289291 return 0 ;
@@ -343,3 +345,88 @@ DEFINE_HOOK(0x55DC85, MainLoop_SaveGame_SanitizeFilename, 0x7)
343345
344346 return 0x55DC90 ;
345347}
348+
349+ #pragma region nosaveload
350+ #include < WWMessageBox.h>
351+ #include < LoadProgressManager.h>
352+ DEFINE_HOOK (0x686089 , DoLose_RetryDialogForCampaigns, 0x7 )
353+ {
354+ if (!Spawner::GetConfig ()->DisableSaveLoad ) return 0 ;
355+
356+ WWMessageBox::Instance.Process (
357+ PRIMARYLANGID (GetUserDefaultUILanguage ()) == LANG_CHINESE ? L" \u83dc " : L" GG" ,
358+ StringTable::LoadString (GameStrings::TXT_OK), nullptr , nullptr );
359+ return 0x6860EE ;
360+ }
361+
362+ // disable load, save and delete buttons on the ingame menu
363+ DEFINE_HOOK (0x4F17F6 , sub_4F1720_DisableSaves, 0x6 )
364+ {
365+ if (!Spawner::GetConfig ()->DisableSaveLoad ) return 0 ;
366+ GET (HWND, hDlg, EBP);
367+
368+ enum { LoadGameButton = 1310 , DeleteGameButton = 1312 };
369+
370+ for (int item = LoadGameButton; item <= DeleteGameButton; ++item)
371+ {
372+ if (HWND hItem = GetDlgItem (hDlg, item))
373+ EnableWindow (hItem, FALSE );
374+ }
375+
376+ return 0x4F1834 ;
377+ }
378+ inline const wchar_t * get_TXT_HARDCORE_MODE ()
379+ {
380+ std::wstring_view msg = StringTable::LoadString (" TXT_HARDCORE_MODE" );
381+ if (msg.empty () || msg.starts_with (L" MISSING" ))
382+ msg = L" HARDCORE" ;
383+ return msg.data ();
384+ }
385+ DEFINE_HOOK (0x553076 , LoadProgressMgr_Draw_ExtraText_Campaign, 0x5 )
386+ {
387+ GET (LoadProgressManager*, self, EBP);
388+ if (!Spawner::GetConfig ()->DisableSaveLoad ) return 0 ;
389+
390+ Point2D pos
391+ {
392+ self->TitleBarRect .X + self->TitleBarRect .Width - 100 ,
393+ self->TitleBarRect .Y + 10
394+ };
395+ LEA_STACK (RectangleStruct*, pBnd, STACK_OFFSET (0x1268 , -0x1204 ));
396+ if (auto logo = FileSystem::LoadSHPFile (" hardcorelogo.shp" ))
397+ {
398+ self->ProgressSurface ->DrawSHP (FileSystem::PALETTE_PAL, logo, 0 , &pos, pBnd, BlitterFlags::bf_400, 0 , 0 , ZGradient::Ground, 1000 , 0 , nullptr , 0 , 0 , 0 );
399+ }
400+ else
401+ {
402+ self->ProgressSurface ->DrawText (get_TXT_HARDCORE_MODE (), &pos, COLOR_RED);
403+ }
404+
405+ return 0 ;
406+ }
407+
408+ DEFINE_HOOK (0x4F4573 , GScreenClass_Draw_SpawnerShit, 0x5 )
409+ {
410+ if (!Spawner::GetConfig ()->DisableSaveLoad ) return 0 ;
411+ wchar_t buffer[0x20 ] {};
412+ int seconds = Unsorted::CurrentFrame / 15 ;
413+ std::format_to (buffer, L" {} {}:{:02}" , get_TXT_HARDCORE_MODE (), seconds / 60 , seconds % 60 );
414+ auto wanted = Drawing::GetTextDimensions (buffer, { 0 ,0 }, 0 , 2 , 0 );
415+
416+ RectangleStruct rect = {
417+ DSurface::Composite->GetWidth () - wanted.Width - 20 ,
418+ 0 ,
419+ wanted.Width + 10 ,
420+ wanted.Height + 10
421+ };
422+
423+ Point2D location { rect.X - 5 ,5 };
424+
425+ DSurface::Composite->FillRect (&rect, COLOR_BLACK);
426+ DSurface::Composite->DrawText (buffer, &location, COLOR_WHITE);
427+
428+ // Fucking Phobos
429+ R->ECX (*(int *)0x887640u );
430+ return 0x4F4589 ;
431+ }
432+ #pragma endregion
0 commit comments