From dcf0561653c273620f07f16b48217377a67a8b31 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Wed, 10 Apr 2019 17:13:00 +0800 Subject: [PATCH] Added new HOOK_SNEAK (from Mr.Stalin) --- artifacts/example_mods/Sneak/gl_sneak.ssl | 46 +++++++++++++++++++++++ artifacts/scripting/headers/sfall.h | 1 + artifacts/scripting/hookscripts.txt | 14 +++++++ sfall/Modules/HookScripts.cpp | 1 + sfall/Modules/HookScripts.h | 1 + sfall/Modules/HookScripts/MiscHs.cpp | 31 +++++++++++++++ sfall/Modules/HookScripts/MiscHs.h | 1 + 7 files changed, 95 insertions(+) create mode 100644 artifacts/example_mods/Sneak/gl_sneak.ssl diff --git a/artifacts/example_mods/Sneak/gl_sneak.ssl b/artifacts/example_mods/Sneak/gl_sneak.ssl new file mode 100644 index 00000000..2bd8ed15 --- /dev/null +++ b/artifacts/example_mods/Sneak/gl_sneak.ssl @@ -0,0 +1,46 @@ +/* + Example implementation of the algorithm of how the game engine checks the Sneak skill +*/ + +#include "..\headers\define.h" +#include "..\headers\command.h" +#include "..\headers\sfall\sfall.h" + +procedure start; + +procedure start begin + if game_loaded then begin + register_hook(HOOK_SNEAK); + end else begin + variable sneakIsSuccess, time, level; + + level := critter_skill_level(dude_obj, SKILL_SNEAK); + if (roll_vs_skill(dude_obj, SKILL_SNEAK, 0) < ROLL_SUCCESS) then begin + sneakIsSuccess := false; + time := ONE_GAME_MINUTE; + if (level <= 250) then + if (level <= 200) then + if (level <= 170) then + if (level <= 135) then + if (level <= 100) then + if (level > 80) then + time := 400; // 40 secs + else + time := 300; // 30 secs + else + time := 200; // 20 secs + else + time := 150; // 15 secs + else + time := 120; // 12 secs + else + time := 100; // 10 secs for skill level > 250 + end + else begin + sneakIsSuccess := true; + time := ONE_GAME_MINUTE; + end + set_sfall_return(sneakIsSuccess); + set_sfall_return(time); + end +end diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 06137961..16aece47 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -60,6 +60,7 @@ #define HOOK_ONEXPLOSION (36) #define HOOK_SUBCOMBATDAMAGE (37) #define HOOK_SETLIGHTING (38) +#define HOOK_SNEAK (39) //Valid arguments to list_begin #define LIST_CRITTERS (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 4c634c7d..7ad52661 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -617,3 +617,17 @@ int arg3 - the light radius, or -1 when setting the light level for a map int ret1 - overrides the light intensity. Intensity range is from 0 to 65536 int ret2 - overrides the light radius. Radius range is from 0 to 8 (works only for the object) + +------------------------------------------- + +HOOK_SNEAK (hs_sneak.int) + +Runs when the Sneak skill is activated, or when the game rolls another Sneak check after the duration for the current one is over. +You can override the result of a random Sneak check or the duration time for the current result. + +int arg1 - Sneak check result: 1 - success, 0 - failure +int arg2 - the duration in ticks for the current Sneak check (time is based on the Sneak skill level) +Critter arg3 - the critter (usually dude_obj) + +int ret1 - overrides the Sneak check result +int ret2 - overrides the duration time for the current result diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index 33c56230..4b0c0f0b 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -83,6 +83,7 @@ static HooksInjectInfo injectHooks[] = { {HOOK_ONEXPLOSION, Inject_OnExplosionHook, false}, {HOOK_SUBCOMBATDAMAGE, Inject_SubCombatDamageHook, false}, // replace the code logic {HOOK_SETLIGHTING, Inject_SetLightingHook, false}, + {HOOK_SNEAK, Inject_SneakCheckHook, false}, }; bool HookScripts::injectAllHooks; diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index e0eea7fd..61485585 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -65,6 +65,7 @@ enum HookType HOOK_ONEXPLOSION = 36, HOOK_SUBCOMBATDAMAGE = 37, HOOK_SETLIGHTING = 38, + HOOK_SNEAK = 39, HOOK_COUNT }; diff --git a/sfall/Modules/HookScripts/MiscHs.cpp b/sfall/Modules/HookScripts/MiscHs.cpp index 3175d4f4..8b7c964c 100644 --- a/sfall/Modules/HookScripts/MiscHs.cpp +++ b/sfall/Modules/HookScripts/MiscHs.cpp @@ -225,6 +225,32 @@ defaultHandler: } } +static void __declspec(naked) SneakCheckHook() { + __asm { + HookBegin; + mov esi, ds:[FO_VAR_sneak_working]; + mov args[0], esi; // 1 = successful sneak + mov args[4], eax; // timer + mov args[8], edx; // critter + pushadc; + } + + argCount = 3; + RunHookScript(HOOK_SNEAK); + + __asm { + popadc; + cmp cRet, 1; + jb skip; + mov esi, rets[0]; + mov ds:[FO_VAR_sneak_working], esi; + cmova eax, rets[4]; // override timer +skip: + HookEnd; + jmp fo::funcoffs::queue_add_; + } +} + static long __stdcall PerceptionRangeHook_Script(int type) { long result; __asm { @@ -513,6 +539,10 @@ void Inject_StealCheckHook() { HookCalls(StealCheckHook, { 0x4749A2, 0x474A69 }); } +void Inject_SneakCheckHook() { + HookCall(0x42E3D9, SneakCheckHook); +} + void Inject_WithinPerceptionHook() { HookCalls(PerceptionRangeHook, { 0x429157, @@ -558,6 +588,7 @@ void InitMiscHookScripts() { LoadHookScript("hs_useskillon", HOOK_USESKILLON); LoadHookScript("hs_useskill", HOOK_USESKILL); LoadHookScript("hs_steal", HOOK_STEAL); + LoadHookScript("hs_sneak", HOOK_SNEAK); LoadHookScript("hs_withinperception", HOOK_WITHINPERCEPTION); LoadHookScript("hs_cartravel", HOOK_CARTRAVEL); LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR); diff --git a/sfall/Modules/HookScripts/MiscHs.h b/sfall/Modules/HookScripts/MiscHs.h index bcf98e07..5e549fd1 100644 --- a/sfall/Modules/HookScripts/MiscHs.h +++ b/sfall/Modules/HookScripts/MiscHs.h @@ -9,6 +9,7 @@ namespace sfall void Inject_UseSkillOnHook(); void Inject_UseSkillHook(); void Inject_StealCheckHook(); + void Inject_SneakCheckHook(); void Inject_WithinPerceptionHook(); void Inject_CarTravelHook(); void Inject_SetGlobalVarHook();