From c657a9ef86afdebed5328d3cded1fa7428b40bc9 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Mon, 17 Aug 2020 15:07:41 +0800 Subject: [PATCH] Added a fix to prevent the player from leaving the map during death anim * when the death animation causes the player to cross an exit grid. Fixed the height of the black background for the subtitles on death screens when using the hi-res patch. Added MakeJumps method to SafeWrite.cpp and devlog_f to Logging.cpp. --- sfall/FalloutEngine/Functions.cpp | 2 +- sfall/FalloutEngine/Functions.h | 2 +- sfall/Logging.cpp | 21 +++++++++++-- sfall/Logging.h | 12 ++++++-- sfall/Modules/BugFixes.cpp | 35 ++++++++++++++++++++++ sfall/Modules/HookScripts/Common.cpp | 44 ++++++++++++---------------- sfall/Modules/MiscPatches.cpp | 6 ++++ sfall/Modules/ScriptExtender.cpp | 8 +++-- sfall/SafeWrite.cpp | 6 ++++ sfall/SafeWrite.h | 1 + 10 files changed, 103 insertions(+), 34 deletions(-) diff --git a/sfall/FalloutEngine/Functions.cpp b/sfall/FalloutEngine/Functions.cpp index d2e3ec69..c496509c 100644 --- a/sfall/FalloutEngine/Functions.cpp +++ b/sfall/FalloutEngine/Functions.cpp @@ -26,7 +26,7 @@ namespace fo namespace func { -// Prints debug message to debug.log file for develop build +// Prints debug message to game debug.log file for develop build #ifndef NDEBUG void __declspec(naked) dev_printf(const char* fmt, ...) { __asm jmp fo::funcoffs::debug_printf_; diff --git a/sfall/FalloutEngine/Functions.h b/sfall/FalloutEngine/Functions.h index 0fb5aead..1971fec2 100644 --- a/sfall/FalloutEngine/Functions.h +++ b/sfall/FalloutEngine/Functions.h @@ -29,8 +29,8 @@ namespace fo namespace func { -// Prints debug message to debug.log file for develop build #ifndef NDEBUG +// Prints debug message to game debug.log file for develop build void dev_printf(const char* fmt, ...); #else void dev_printf(...); diff --git a/sfall/Logging.cpp b/sfall/Logging.cpp index 682b920b..4a00c069 100644 --- a/sfall/Logging.cpp +++ b/sfall/Logging.cpp @@ -23,7 +23,7 @@ #include -namespace sfall +namespace sfall { static int DebugTypes = 0; @@ -43,7 +43,7 @@ void dlogr(const std::string& a, int type) { } } -void dlog_f(const char *fmt, int type, ...) { +void dlog_f(const char* fmt, int type, ...) { if (isDebug && (type == DL_MAIN || (type & DebugTypes))) { va_list args; va_start(args, type); @@ -55,6 +55,23 @@ void dlog_f(const char *fmt, int type, ...) { } } +// Prints debug message to sfall log file for develop build +#ifndef NDEBUG +void devlog_f(const char* fmt, int type, ...) { + if (type == DL_MAIN || (type & DebugTypes)) { + va_list args; + va_start(args, type); + char buf[1024]; + vsnprintf_s(buf, sizeof(buf), _TRUNCATE, fmt, args); + Log << buf; + Log.flush(); + va_end(args); + } +} +#else +void devlog_f(...) {} +#endif + void LoggingInit() { Log.open("sfall-log.txt", std::ios_base::out | std::ios_base::trunc); if (iniGetInt("Debugging", "Init", 0, ::sfall::ddrawIni)) { diff --git a/sfall/Logging.h b/sfall/Logging.h index 3cab718f..a0239fc7 100644 --- a/sfall/Logging.h +++ b/sfall/Logging.h @@ -26,12 +26,20 @@ #include #include -namespace sfall +namespace sfall { void dlog(const std::string&, int type); void dlogr(const std::string&, int type); -void dlog_f(const char *format, int type, ...); +void dlog_f(const char* fmt, int type, ...); + +#ifndef NDEBUG +// Prints debug message to sfall log file for develop build +void devlog_f(const char* fmt, int type, ...); +#else +void devlog_f(...); +#endif + void LoggingInit(); } diff --git a/sfall/Modules/BugFixes.cpp b/sfall/Modules/BugFixes.cpp index febec675..b1357c25 100644 --- a/sfall/Modules/BugFixes.cpp +++ b/sfall/Modules/BugFixes.cpp @@ -2777,6 +2777,35 @@ skip: } } +static bool dudeIsAnimDeath = false; + +static void __declspec(naked) show_damage_to_object_hack() { + static const DWORD show_damage_to_object_Ret = 0x410B90; + __asm { + jnz isDeath; + add esp, 4; + jmp show_damage_to_object_Ret; +isDeath: + cmp esi, ds:[FO_VAR_obj_dude]; + sete dudeIsAnimDeath; + retn; + } +} + +static void __declspec(naked) obj_move_to_tile_hack_ondeath() { + static const DWORD obj_move_to_tile_Ret = 0x48A759; + __asm { + test esi, esi; + jz skip; + cmp dudeIsAnimDeath, 0; + jnz skip; + retn; +skip: + add esp, 4; + jmp obj_move_to_tile_Ret; + } +} + void BugFixes::init() { #ifndef NDEBUG @@ -2786,6 +2815,7 @@ void BugFixes::init() // Missing game initialization LoadGameHook::OnBeforeGameInit() += Initialization; + LoadGameHook::OnGameReset() += []() { dudeIsAnimDeath = false; }; // Fix vanilla negate operator for float values MakeCall(0x46AB68, NegateFixHack); @@ -3503,6 +3533,11 @@ void BugFixes::init() // Fix to prevent the execution of critter_p_proc and game events when playing movies (same as when the dialog is active) HookCall(0x4A3C89, doBkProcesses_hook); + + // Fix to prevent the player from leaving the map when the death animation causes the player to cross an exit grid + // (e.g. fire dance or knockback animation) + MakeCall(0x41094B, show_damage_to_object_hack, 1); + MakeCall(0x48A6CB, obj_move_to_tile_hack_ondeath, 1); } } diff --git a/sfall/Modules/HookScripts/Common.cpp b/sfall/Modules/HookScripts/Common.cpp index d7279618..07641387 100644 --- a/sfall/Modules/HookScripts/Common.cpp +++ b/sfall/Modules/HookScripts/Common.cpp @@ -92,16 +92,14 @@ void __stdcall BeginHook() { memcpy(&savedArgs[cDepth].oldArgs, args, argCount * sizeof(DWORD)); // values of the arguments if (cRet) memcpy(&savedArgs[cDepth].oldRets, rets, cRet * sizeof(DWORD)); // return values - // for debugging - /*dlog_f("\nSaved cArgs/cRets: %d / %d(%d)\n", DL_HOOK, savedArgs[cDepth].argCount, savedArgs[cDepth].cRet, cRetTmp); - for (unsigned int i = 0; i < maxArgs; i++) { - dlog_f("Saved Args/Rets: %d / %d\n", DL_HOOK, savedArgs[cDepth].oldArgs[i], ((i < maxRets) ? savedArgs[cDepth].oldRets[i] : -1)); - }*/ + //devlog_f("\nSaved cArgs/cRet: %d / %d(%d)\n", DL_HOOK, savedArgs[cDepth].argCount, savedArgs[cDepth].cRet, cRetTmp); + //for (unsigned int i = 0; i < maxArgs; i++) { + // devlog_f("Saved Args/Rets: %d / %d\n", DL_HOOK, savedArgs[cDepth].oldArgs[i], ((i < maxRets) ? savedArgs[cDepth].oldRets[i] : -1)); + //} } callDepth++; - #ifndef NDEBUG - dlog_f("Begin running hook, current depth: %d, current executable hook: %d\n", DL_HOOK, callDepth, currentRunHook); - #endif + + devlog_f("Begin running hook, current depth: %d, current executable hook: %d\n", DL_HOOK, callDepth, currentRunHook); } static void __stdcall RunSpecificHookScript(HookScript *hook) { @@ -130,25 +128,22 @@ void __stdcall RunHookScript(DWORD hook) { for (int i = hooksCount - 1; i >= 0; i--) { RunSpecificHookScript(&hooks[hook][i]); - // for debugging - /*dlog_f("> Hook: %d, script entry: %d done\n", DL_HOOK, hook, i); - dlog_f("> Check cArg/cRet: %d / %d(%d)\n", DL_HOOK, cArg, cRet, cRetTmp); - for (unsigned int i = 0; i < maxArgs; i++) { - dlog_f("> Check Args/Rets: %d / %d\n", DL_HOOK, args[i], ((i < maxRets) ? rets[i] : -1)); - }*/ + //devlog_f("> Hook: %d, script entry: %d done\n", DL_HOOK, hook, i); + //devlog_f("> Check cArg/cRet: %d / %d(%d)\n", DL_HOOK, cArg, cRet, cRetTmp); + //for (unsigned int i = 0; i < maxArgs; i++) { + // devlog_f("> Check Args/Rets: %d / %d\n", DL_HOOK, args[i], ((i < maxRets) ? rets[i] : -1)); + //} } } else { cArg = 0; - #ifndef NDEBUG - dlog_f(">>> Try running hook ID: %d\n", DL_HOOK, hook); - #endif + + devlog_f(">>> Try running hook ID: %d\n", DL_HOOK, hook); } } void __stdcall EndHook() { - #ifndef NDEBUG - dlog_f("End running hook %d, current depth: %d\n", DL_HOOK, currentRunHook, callDepth); - #endif + devlog_f("End running hook %d, current depth: %d\n", DL_HOOK, currentRunHook, callDepth); + callDepth--; if (callDepth) { if (callDepth <= maxDepth) { @@ -162,11 +157,10 @@ void __stdcall EndHook() { memcpy(args, &savedArgs[cDepth].oldArgs, argCount * sizeof(DWORD)); if (cRet) memcpy(rets, &savedArgs[cDepth].oldRets, cRet * sizeof(DWORD)); - // for debugging - /*dlog_f("Restored cArgs/cRets: %d / %d(%d)\n", DL_HOOK, argCount, cRet, cRetTmp); - for (unsigned int i = 0; i < maxArgs; i++) { - dlog_f("Restored Args/Rets: %d / %d\n", args[i], ((i < maxRets) ? rets[i] : -1)); - }*/ + //devlog_f("Restored cArgs/cRet: %d / %d(%d)\n", DL_HOOK, argCount, cRet, cRetTmp); + //for (unsigned int i = 0; i < maxArgs; i++) { + // devlog_f("Restored Args/Rets: %d / %d\n", DL_HOOK, args[i], ((i < maxRets) ? rets[i] : -1)); + //} } } else { currentRunHook = -1; diff --git a/sfall/Modules/MiscPatches.cpp b/sfall/Modules/MiscPatches.cpp index 22c4205e..4dafcc3f 100644 --- a/sfall/Modules/MiscPatches.cpp +++ b/sfall/Modules/MiscPatches.cpp @@ -804,6 +804,12 @@ void MiscPatches::init() { HookCall(0x48A954, obj_move_to_tile_hook); HookCall(0x483726, map_check_state_hook); + // Corrects the height of the black background for the subtitles on death screens + if (hrpVersionValid) { + SafeWrite8(HRPAddress(0x10011738), 10); + SafeWrite8(0x481345, 4); // main_death_scene_ + } + F1EngineBehaviorPatch(); DialogueFix(); AdditionalWeaponAnimsPatch(); diff --git a/sfall/Modules/ScriptExtender.cpp b/sfall/Modules/ScriptExtender.cpp index 864ef215..62b842f6 100644 --- a/sfall/Modules/ScriptExtender.cpp +++ b/sfall/Modules/ScriptExtender.cpp @@ -478,7 +478,7 @@ bool IsGameScript(const char* filename) { static void LoadGlobalScriptsList() { ScriptProgram prog; for (auto& item : globalScriptFilesList) { - auto scriptFile = item.second; + auto &scriptFile = item.second; dlog("> " + scriptFile, DL_SCRIPT); isGlobalScriptLoading = 1; LoadScriptProgram(prog, scriptFile.c_str(), true); @@ -521,7 +521,7 @@ static void PrepareGlobalScriptsListByMask() { fo::func::debug_printf("\n[SFALL] Script: %s will not be executed. A script with the same name already exists in another directory.", fullPath); continue; } - globalScriptFilesList.insert(std::make_pair(baseName, fullPath)); + globalScriptFilesList.insert(std::make_pair(baseName, fullPath)); // script files should be sorted in alphabetical order } } fo::func::db_free_file_list(&filenames, 0); @@ -662,10 +662,12 @@ static DWORD HandleTimedEventScripts() { executeTimedEventDepth++; fo::func::dev_printf("\n[TimedEventScripts] Time: %d / Depth: %d", currentTime, executeTimedEventDepth); + for (auto it = timerEventScripts.cbegin(); it != timerEventScripts.cend(); ++it) { + fo::func::dev_printf("\n[TimedEventScripts] Event: %d", it->time); + } bool eventsWereRunning = false; for (auto timerIt = timerEventScripts.cbegin(); timerIt != timerEventScripts.cend(); ++timerIt) { - fo::func::dev_printf("\n[TimedEventScripts] Event: %d", timerIt->time); if (timerIt->isActive == false) continue; if (currentTime >= timerIt->time) { if (timedEvent) executeTimedEvents.push(timedEvent); // store a pointer to the currently running event diff --git a/sfall/SafeWrite.cpp b/sfall/SafeWrite.cpp index 13870e22..c9b7b8d3 100644 --- a/sfall/SafeWrite.cpp +++ b/sfall/SafeWrite.cpp @@ -117,6 +117,12 @@ void MakeCalls(void* func, std::initializer_list addrs) { } } +void MakeJumps(void* func, std::initializer_list addrs) { + for (auto& addr : addrs) { + MakeJump(addr, func); + } +} + void SafeMemSet(DWORD addr, BYTE val, int len) { DWORD oldProtect; diff --git a/sfall/SafeWrite.h b/sfall/SafeWrite.h index 3c1c63fc..1369c94d 100644 --- a/sfall/SafeWrite.h +++ b/sfall/SafeWrite.h @@ -61,5 +61,6 @@ void BlockCall(DWORD addr); void HookCalls(void* func, std::initializer_list addrs); void MakeCalls(void* func, std::initializer_list addrs); +void MakeJumps(void* func, std::initializer_list addrs); }