diff --git a/sfall/FalloutEngine/VariableOffsets.h b/sfall/FalloutEngine/VariableOffsets.h index 2a41d1a2..62f1eec3 100644 --- a/sfall/FalloutEngine/VariableOffsets.h +++ b/sfall/FalloutEngine/VariableOffsets.h @@ -13,6 +13,9 @@ #define FO_VAR_art_name 0x56C9E4 #define FO_VAR_art_vault_guy_num 0x5108A4 #define FO_VAR_art_vault_person_nums 0x5108A8 +#define FO_VAR_aTextSCuts 0x501A8C +#define FO_VAR_aTextSCutsS 0x503530 +#define FO_VAR_aTextSCutsSS 0x50B01C #define FO_VAR_bboxslot 0x5970E0 #define FO_VAR_bckgnd 0x5707A4 #define FO_VAR_black_palette 0x663FD0 diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 1b6a9c35..c0f48f83 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -50,6 +50,7 @@ namespace sfall _asm call SetInLoop } static Delegate<> onGameInit; +static Delegate<> onGameExit; static Delegate<> onGameReset; static Delegate<> onBeforeGameStart; static Delegate<> onAfterGameStarted; @@ -290,6 +291,10 @@ static void __stdcall GameInitialized() { onGameInit.invoke(); } +static void __stdcall GameExit() { + onGameExit.invoke(); +} + static void __declspec(naked) main_init_system_hook() { __asm { pushad; @@ -329,6 +334,15 @@ static void __declspec(naked) before_game_exit_hook() { } } +static void __declspec(naked) after_game_exit_hook() { + __asm { + pushad; + call GameExit; + popad; + jmp fo::funcoffs::main_menu_create_; + } +} + static void __declspec(naked) WorldMapHook() { __asm { _InLoop(1, WORLDMAP); @@ -556,6 +570,7 @@ void LoadGameHook::init() { 0x47F491, // PrepLoad_ (the very first step during save game loading) }); HookCalls(before_game_exit_hook, {0x480ACE, 0x480BC7}); + HookCalls(after_game_exit_hook, {0x480AEB, 0x480BE4}); HookCalls(WorldMapHook, {0x483668, 0x4A4073}); HookCalls(WorldMapHook2, {0x4C4855}); @@ -585,6 +600,10 @@ Delegate<>& LoadGameHook::OnGameInit() { return onGameInit; } +Delegate<>& LoadGameHook::OnGameExit() { + return onGameExit; +} + Delegate<>& LoadGameHook::OnGameReset() { return onGameReset; } diff --git a/sfall/Modules/LoadGameHook.h b/sfall/Modules/LoadGameHook.h index 9c0f9f2e..dc68c19e 100644 --- a/sfall/Modules/LoadGameHook.h +++ b/sfall/Modules/LoadGameHook.h @@ -32,6 +32,9 @@ public: // Invoked when the game has initialized (game_init_ was called). static Delegate<>& OnGameInit(); + // Invoked when the game exits to main menu + static Delegate<>& OnGameExit(); + // Invoked when game state is being reset (before loading a save, after quitting, etc.) static Delegate<>& OnGameReset(); diff --git a/sfall/Modules/LoadOrder.cpp b/sfall/Modules/LoadOrder.cpp index 50efcce6..309e5915 100644 --- a/sfall/Modules/LoadOrder.cpp +++ b/sfall/Modules/LoadOrder.cpp @@ -25,13 +25,35 @@ namespace sfall { -static const char* msgFemaleFolder = "dialog_female\\%s.msg"; +static long femaleMsgs; + +static const char* cutsEndGameFemale = "text\\%s\\cuts_female\\"; +static const char* cutsSubFemale = "text\\%s\\cuts_female\\%s"; +static const char* cutsDeathFemale = "text\\%s\\cuts_female\\%s%s"; +static const char* msgFemaleFolder = "dialog_female\\%s.msg"; + static bool isFemale = false; static bool femaleCheck = false; // flag for check female dialog file static DWORD format; +static bool cutsPatch = false; static void CheckPlayerGender() { isFemale = fo::HeroIsFemale(); + + if (femaleMsgs > 1) { + if (isFemale) { + if (cutsPatch) return; + cutsPatch = true; + SafeWrite32(0x43FA9F, (DWORD)cutsEndGameFemale); + SafeWrite32(0x44EB5B, (DWORD)cutsSubFemale); + SafeWrite32(0x48152E, (DWORD)cutsDeathFemale); + } else if (cutsPatch) { + SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts); + SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS); + SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS); + cutsPatch = false; + } + } } static const DWORD scr_get_dialog_msg_file_Back = 0x4A6BD2; @@ -67,6 +89,16 @@ exist: } } +static void __declspec(naked) gnw_main_hack() { + __asm { + push eax; + call CheckPlayerGender; + pop eax; + mov edx, 4; // overwritten engine code + retn; + } +} + static void __declspec(naked) removeDatabase() { __asm { cmp eax, -1 @@ -144,12 +176,24 @@ void LoadOrder::init() { dlogr(" Done", DL_INIT); } - if (GetConfigInt("Misc", "FemaleDialogMsgs", 0)) { + femaleMsgs = GetConfigInt("Misc", "FemaleDialogMsgs", 0); + if (femaleMsgs) { dlog("Applying alternative female dialog files patch.", DL_INIT); MakeJump(0x4A6BCD, scr_get_dialog_msg_file_hack1); MakeJump(0x4A6BF5, scr_get_dialog_msg_file_hack2); - dlogr(" Done", DL_INIT); LoadGameHook::OnAfterGameStarted() += CheckPlayerGender; + if (femaleMsgs > 1) { + MakeCall(0x480A95, gnw_main_hack); // before new game start from main menu. TODO: need moved to address 0x480A9A (it busy in movies.cpp) + LoadGameHook::OnGameExit() += []() { + if (cutsPatch) { // restore + SafeWrite32(0x43FA9F, FO_VAR_aTextSCuts); + SafeWrite32(0x44EB5B, FO_VAR_aTextSCutsS); + SafeWrite32(0x48152E, FO_VAR_aTextSCutsSS); + cutsPatch = false; + } + }; + } + dlogr(" Done", DL_INIT); } }