From 5053ab564dad23ba8a507a2019158da3c4e34dee Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 20 Nov 2019 10:14:30 +0800 Subject: [PATCH] Added a new argument to HOOK_GAMEMODECHANGE * now the previous game mode can be checked with arg2 (#211) Fixed GAMEMODECHANGE hook being triggered even when the game mode is not changed. Added 'SPECIAL' flag to the game mode functions (when switching from DIALOG mode to BARTER). --- artifacts/scripting/headers/sfall.h | 2 +- artifacts/scripting/hookscripts.txt | 1 + sfall/Modules/HookScripts.cpp | 18 ++++++++++++------ sfall/Modules/LoadGameHook.cpp | 13 ++++++++++++- sfall/Modules/LoadGameHook.h | 6 +++--- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 748de311..ad5c4e6a 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -1,6 +1,5 @@ //Recognised modes for set_shader_mode and get_game_mode #define WORLDMAP (0x1) -#define LOCALMAP (0x2) //No point hooking this: would always be 1 at any point at which scripts are running #define DIALOG (0x4) #define ESCMENU (0x8) #define SAVEGAME (0x10) @@ -20,6 +19,7 @@ #define HEROWIN (0x40000) #define DIALOGVIEW (0x80000) #define COUNTERWIN (0x100000) // counter window for moving multiple items or setting a timer +#define SPECIAL (0x80000000) //Valid arguments to register_hook #define HOOK_TOHIT (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 882d70ad..da2ce2ef 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -514,6 +514,7 @@ HOOK_GAMEMODECHANGE (hs_gamemodechange.int) Runs once every time when the game mode was changed, like opening/closing the inventory, character screen, pipboy, etc. int arg1 - event type: 1 - when the player exits the game, 0 - otherwise +int arg2 - the previous game mode ------------------------------------------- diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index 1a8a50ae..6c812360 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -124,13 +124,18 @@ void _stdcall MouseClickHook(DWORD button, bool pressed) { EndHook(); } +static unsigned long previousGameMode = 0; + void HookScripts::GameModeChangeHook(DWORD exit) { - if (!HookHasScript(HOOK_GAMEMODECHANGE)) return; - BeginHook(); - argCount = 1; - args[0] = exit; - RunHookScript(HOOK_GAMEMODECHANGE); - EndHook(); + if (HookHasScript(HOOK_GAMEMODECHANGE)) { + BeginHook(); + argCount = 2; + args[0] = exit; + args[1] = previousGameMode; + RunHookScript(HOOK_GAMEMODECHANGE); + EndHook(); + } + previousGameMode = GetLoopFlags(); } // END HOOKS @@ -237,6 +242,7 @@ void HookScriptClear() { hooks[i].clear(); } memset(hooksInfo, 0, HOOK_COUNT * sizeof(HooksPositionInfo)); + previousGameMode = 0; } void LoadHookScripts() { diff --git a/sfall/Modules/LoadGameHook.cpp b/sfall/Modules/LoadGameHook.cpp index 5138b5ee..1c3cdf8b 100644 --- a/sfall/Modules/LoadGameHook.cpp +++ b/sfall/Modules/LoadGameHook.cpp @@ -105,12 +105,13 @@ static void __stdcall GameModeChange(DWORD state) { } void _stdcall SetInLoop(DWORD mode, LoopFlag flag) { + DWORD _flag = GetLoopFlags(); if (mode) { SetLoopFlag(flag); } else { ClearLoopFlag(flag); } - GameModeChange(0); + if (GetLoopFlags() != _flag) GameModeChange(0); } void GetSavePath(char* buf, char* ftype) { @@ -579,6 +580,7 @@ static void __declspec(naked) LootContainerHook() { static void __declspec(naked) BarterInventoryHook() { __asm { + and inLoop, ~SPECIAL; // unset flag _InLoop(1, BARTER); push [esp + 4]; call fo::funcoffs::barter_inventory_; @@ -638,6 +640,13 @@ static void __declspec(naked) exit_move_timer_win_Hook() { } } +static void __declspec(naked) gdialog_bk_hook() { + __asm { + _InLoop2(1, SPECIAL); + jmp fo::funcoffs::gdialog_window_destroy_; + } +} + void LoadGameHook::init() { saveInCombatFix = GetConfigInt("Misc", "SaveInCombatFix", 1); if (saveInCombatFix > 2) saveInCombatFix = 0; @@ -697,6 +706,8 @@ void LoadGameHook::init() { HookCall(0x445D30, DialogReviewExitHook); HookCall(0x476AC6, setup_move_timer_win_Hook); // before init win HookCall(0x477067, exit_move_timer_win_Hook); + + HookCall(0x447A7E, gdialog_bk_hook); // Set the Special flag before animating the dialog interface when switching from dialog mode to barter } Delegate<>& LoadGameHook::OnBeforeGameInit() { diff --git a/sfall/Modules/LoadGameHook.h b/sfall/Modules/LoadGameHook.h index a93b6f8c..a9198726 100644 --- a/sfall/Modules/LoadGameHook.h +++ b/sfall/Modules/LoadGameHook.h @@ -71,9 +71,9 @@ DWORD InCombat(); DWORD InDialog(); -enum LoopFlag : unsigned long { +enum LoopFlag : long { WORLDMAP = 1 << 0, // 0x1 - LOCALMAP = 1 << 1, // 0x2 No point hooking this: would always be 1 at any point at which scripts are running +// RESERVED = 1 << 1, // 0x2 (unused) DIALOG = 1 << 2, // 0x4 ESCMENU = 1 << 3, // 0x8 SAVEGAME = 1 << 4, // 0x10 @@ -94,7 +94,7 @@ enum LoopFlag : unsigned long { DIALOGVIEW = 1 << 19, // 0x80000 COUNTERWIN = 1 << 20, // 0x100000 Counter window for moving multiple items or setting a timer - // RESERVED = 1 << 31 + SPECIAL = 1 << 31 // 0x80000000 Additional special flag for all modes }; DWORD GetLoopFlags();