From 9fa59a0d75be1d1b041a98e8a1a10dcf0b85d00f Mon Sep 17 00:00:00 2001 From: "mr.Stalin" <21695363+FakelsHub@users.noreply.github.com> Date: Tue, 8 May 2018 07:18:44 +0300 Subject: [PATCH] Rest hook and functions (#144) * Added new HOOK_RESTTIMER (#89) * Added "set_rest_mode" and "set_rest_heal_time" script functions. --- artifacts/scripting/headers/sfall.h | 8 +++ artifacts/scripting/sfall function notes.txt | 4 ++ sfall/Modules/HookScripts.h | 1 + sfall/Modules/HookScripts/MiscHs.cpp | 68 +++++++++++++++++++ sfall/Modules/Scripting/Handlers/Metarule.cpp | 2 + sfall/Modules/Scripting/Handlers/Worldmap.cpp | 8 +++ sfall/Modules/Scripting/Handlers/Worldmap.h | 4 ++ sfall/Modules/Worldmap.cpp | 46 +++++++++++++ sfall/Modules/Worldmap.h | 2 + 9 files changed, 143 insertions(+) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index b1496ea3..bb40ae8e 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -50,6 +50,7 @@ #define HOOK_COMBATTURN (27) #define HOOK_CARTRAVEL (28) #define HOOK_SETGLOBALVAR (29) +#define HOOK_RESTTIMER (30) //Valid arguments to list_begin #define LIST_CRITTERS (0) @@ -206,6 +207,11 @@ #define BLOCKING_TYPE_AI (2) #define BLOCKING_TYPE_SIGHT (3) // not really useful (works not as you would expect), game uses this only when checking if you can talk to a person +//Rest mode flags +#define DISABLE_REST (1) +#define DISABLE_REST_FIX (2) +#define DISABLE_REST_HEAL (4) + #define party_member_list_critters party_member_list(0) #define party_member_list_all party_member_list(1) @@ -236,6 +242,8 @@ #define set_ini_setting(setting, value) sfall_func2("set_ini_setting", setting, value) #define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot) #define set_outline(obj, color) sfall_func2("set_outline", obj, color) +#define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time) +#define set_rest_mode(mode) sfall_func1("set_rest_mode", mode) #define set_unjam_locks_time(time) sfall_func1("set_unjam_locks_time", time) #define spatial_radius(obj) sfall_func1("spatial_radius", obj) #define tile_refresh_display sfall_func0("tile_refresh_display") diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 2bc82c74..204617e0 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -465,6 +465,10 @@ Some utility/math functions are available: - setting the tile to 0 will put the player on the start hex (default tile and elevation) of the map - works only in map_enter_p_proc procedure +> void sfall_func1("set_rest_heal_time", int minutes) + +> void sfall_func1("set_rest_mode", int mode) + ------------------------ ------ MORE INFO ------- ------------------------ diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index 803cea31..f3a99ca0 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -56,6 +56,7 @@ enum HookType HOOK_COMBATTURN = 27, HOOK_CARTRAVEL = 28, HOOK_SETGLOBALVAR = 29, + HOOK_RESTTIMER = 30, HOOK_COUNT }; diff --git a/sfall/Modules/HookScripts/MiscHs.cpp b/sfall/Modules/HookScripts/MiscHs.cpp index f5f3eeed..7f171cba 100644 --- a/sfall/Modules/HookScripts/MiscHs.cpp +++ b/sfall/Modules/HookScripts/MiscHs.cpp @@ -289,6 +289,70 @@ static void __declspec(naked) SetGlobalVarHook() { } } +static int restTicks; // previous ticks +static void _stdcall RestTimerHookScript() { + int addrHook; + __asm { + mov addrHook, ebx; + mov args[0], eax; + mov args[8], ecx; + mov args[12], edx; + } + + BeginHook(); + argCount = 4; + addrHook -= 5; + if (addrHook == 0x499CA1 || addrHook == 0x499B63) { + args[0] = restTicks; + args[1] = -1; + } else { + restTicks = args[0]; + args[1] = (addrHook == 0x499DF2 || (args[2] == 0 && addrHook == 0x499BE0)) ? 1 : 0; + } + RunHookScript(HOOK_RESTTIMER); + EndHook(); +} + +static void __declspec(naked) RestTimerLoopHook() { + __asm { + pushad; + mov ebx, [esp + 32]; + mov ecx, [esp+36+0x40]; // hours_ + mov edx, [esp+36+0x44]; // minutes_ + call RestTimerHookScript; + popad; + cmp cRet, 1; + jl skip; + cmp rets[0], 1; + jnz skip; + mov edi, 1; +skip: + jmp fo::funcoffs::set_game_time_; + } +} + +static void __declspec(naked) RestTimerEscapeHook() { + __asm { + cmp eax, 0x1B; + jnz skip; + pushad; + mov ebx, [esp+32]; + mov ecx, [esp+36+0x40]; // hours_ + mov edx, [esp+36+0x44]; // minutes_ + call RestTimerHookScript; + popad; + cmp cRet, 1; + jl skip; + cmp rets[0], 0; + jnz skip; + mov edi, 0; // cancel escape + retn; +skip: + mov edi, 1; + retn; + } +} + void InitMiscHookScripts() { LoadHookScript("hs_useobjon", HOOK_USEOBJON); HookCalls(UseObjOnHook, { 0x49C606, 0x473619 }); @@ -334,6 +398,10 @@ void InitMiscHookScripts() { LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR); HookCall(0x455A6D, SetGlobalVarHook); + + LoadHookScript("hs_resttimer", HOOK_RESTTIMER); + HookCalls(RestTimerLoopHook, { 0x499B4B, 0x499BE0, 0x499D2C, 0x499DF2 }); + MakeCalls(RestTimerEscapeHook, { 0x499B63, 0x499CA1 }); } diff --git a/sfall/Modules/Scripting/Handlers/Metarule.cpp b/sfall/Modules/Scripting/Handlers/Metarule.cpp index dd0fc395..98f31b6a 100644 --- a/sfall/Modules/Scripting/Handlers/Metarule.cpp +++ b/sfall/Modules/Scripting/Handlers/Metarule.cpp @@ -104,6 +104,8 @@ static const SfallMetarule metarules[] = { {"set_ini_setting", sf_set_ini_setting, 2, 2, {ARG_STRING, ARG_INTSTR}}, {"set_map_enter_position", sf_set_map_enter_position, 3, 3, {ARG_INT, ARG_INT, ARG_INT}}, {"set_outline", sf_set_outline, 2, 2, {ARG_OBJECT, ARG_INT}}, + {"set_rest_heal_time", sf_set_rest_heal_time, 1, 1, {ARG_INT}}, + {"set_rest_mode", sf_set_rest_mode, 1, 1, {ARG_INT}}, {"set_unjam_locks_time", sf_set_unjam_locks_time, 1, 1, {ARG_INT}}, {"spatial_radius", sf_spatial_radius, 1, 1, {ARG_OBJECT}}, {"tile_refresh_display", sf_tile_refresh_display, 0, 0}, diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.cpp b/sfall/Modules/Scripting/Handlers/Worldmap.cpp index 05bf9202..8dca5b2e 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.cpp +++ b/sfall/Modules/Scripting/Handlers/Worldmap.cpp @@ -255,5 +255,13 @@ void sf_get_map_enter_position(OpcodeContext& ctx) { ctx.setReturn(id, DataType::INT); } +void sf_set_rest_heal_time(OpcodeContext& ctx) { + Worldmap::SetRestHealTime(ctx.arg(0).asInt()); +} + +void sf_set_rest_mode(OpcodeContext& ctx) { + Worldmap::SetRestMode(ctx.arg(0).asInt()); +} + } } diff --git a/sfall/Modules/Scripting/Handlers/Worldmap.h b/sfall/Modules/Scripting/Handlers/Worldmap.h index 560e18ae..ffcd0f25 100644 --- a/sfall/Modules/Scripting/Handlers/Worldmap.h +++ b/sfall/Modules/Scripting/Handlers/Worldmap.h @@ -46,5 +46,9 @@ void sf_set_map_enter_position(OpcodeContext&); void sf_get_map_enter_position(OpcodeContext&); +void sf_set_rest_heal_time(OpcodeContext&); + +void sf_set_rest_mode(OpcodeContext&); + } } diff --git a/sfall/Modules/Worldmap.cpp b/sfall/Modules/Worldmap.cpp index a4466281..863b674e 100644 --- a/sfall/Modules/Worldmap.cpp +++ b/sfall/Modules/Worldmap.cpp @@ -32,6 +32,9 @@ static Delegate<> onWorldmapLoop; static DWORD ViewportX; static DWORD ViewportY; +static bool restMode; +static bool restTime; + static __declspec(naked) void GetDateWrapper() { __asm { push ecx; @@ -420,6 +423,9 @@ void Worldmap::init() { LoadGameHook::OnGameReset() += []() { SetCarInterfaceArt(0x1B1); + if (restTime) + SetRestHealTime(180); + RestRestore(); }; } @@ -431,4 +437,44 @@ void Worldmap::SetCarInterfaceArt(DWORD artIndex) { SafeWrite32(0x4C2D9B, artIndex); } +static void SetRestHealTime(DWORD minutes) { + if (minutes > 0) { + SafeWrite32(0x499FDE, minutes); + restTime = (minutes != 180); + } +} + +static void SetRestMode(DWORD mode) { + RestRestore(); // restore default + + restMode = ((mode & 0x7) > 0); + if (!restMode) return; + + if (mode & 1) { // bit1 - disable rest + SafeWrite8(0x49952C, 0x31); //test to xor + SafeWrite8(0x497557, 0x31); + return; + } + if (mode & 2) { // bit2 - fix rest + SafeWrite8(0x42E587, 0xE9); + SafeWrite32(0x42E588, 0x94); + } + if (mode & 4) { // bit3 - disable heal + SafeWrite16(0x499FD4, 0x9090); + SafeWrite16(0x499E93, 0x8FEB); + } +} + +static void RestRestore() { + if (!restMode) return; + + restMode = false; + SafeWrite8(0x49952C, 0x85); + SafeWrite8(0x497557, 0x85); + SafeWrite8(0x42E587, 0xC7); + SafeWrite32(0x42E588, 0x10C2444); + SafeWrite16(0x499FD4, 0xC201); + SafeWrite16(0x499E93, 0x0574); +} + } diff --git a/sfall/Modules/Worldmap.h b/sfall/Modules/Worldmap.h index 88b1cd18..ecf22c3f 100644 --- a/sfall/Modules/Worldmap.h +++ b/sfall/Modules/Worldmap.h @@ -32,6 +32,8 @@ public: static Delegate<>& OnWorldmapLoop(); static void SetCarInterfaceArt(DWORD artIndex); + static void SetRestHealTime(DWORD minutes); + static void SetRestMode(DWORD mode); }; }