diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 6af56a50..87d8fc0e 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -71,6 +71,7 @@ #define HOOK_ENCOUNTER (43) #define HOOK_ADJUSTPOISON (44) #define HOOK_ADJUSTRADS (45) +#define HOOK_ROLLCHECK (46) //Valid arguments to list_begin #define LIST_CRITTERS (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 3bea8d76..9aac02c2 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -718,3 +718,26 @@ Critter arg0 - the critter (usually dude_obj) int arg1 - the amount of radiation being added/removed int ret0 - the new amount of radiation being added/removed + +------------------------------------------- + +HOOK_ROLLCHECK (hs_rollcheck.int) + +Runs when a game event performs a random roll to check the chance of success or failure. + +int arg0 - event type: + 1 - checks the chance of an attack hitting the target + 2 - checks the chance of a bullet from a burst hitting the target (for burst attacks) + 3 - checks the chance when using skills (not listed below) + 4 - check the chance of using Repair skill + 5 - check the chance of using Doctor skill + 6 - check the chance of using Steal skill for the thief + 7 - the second Steal skill chance check for the target to catch the thief, in which the target's failure is the thief's success result +int arg1 - the value of roll result (see ROLL_* constants), which is calculated as: + for ROLL_CRITICAL_SUCCESS: random(1, 100) <= (random_chance / 10) + bonus + for ROLL_CRITICAL_FAILURE: random(1, 100) <= -random_chance / 10 +int arg2 - the chance value +int arg3 - the bonus value, used when checking critical success +int arg4 - random chance (calculated as: chance - random(1, 100)), where a negative value is a failure check (ROLL_FAILURE) + +int ret0 - overrides the roll result diff --git a/sfall/Modules/CritterPoison.cpp b/sfall/Modules/CritterPoison.cpp index 5c83639d..8487ea8b 100644 --- a/sfall/Modules/CritterPoison.cpp +++ b/sfall/Modules/CritterPoison.cpp @@ -116,7 +116,7 @@ static void __declspec(naked) critter_check_rads_hack() { } void CritterPoison::init() { - // Allow changing the poison level for critters + // Allow changing the poison level for NPCs MakeCall(0x42D226, critter_adjust_poison_hack); SafeWrite8(0x42D22C, 0xDA); // jmp 0x42D30A diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index 24a4c81e..7ec62742 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -107,10 +107,11 @@ static HooksInjectInfo injectHooks[] = { {HOOK_ENCOUNTER, Inject_EncounterHook, 0}, {HOOK_ADJUSTPOISON, Inject_AdjustPoisonHook, 0}, {HOOK_ADJUSTRADS, Inject_AdjustRadsHook, 1}, // always embedded for party control fix + {HOOK_ROLLCHECK, Inject_RollCheckHook, 0}, }; void HookScripts::InjectingHook(int hookId) { - if (!IsInjectHook(hookId) && injectHooks[hookId].id == hookId) { + if (IsInjectHook(hookId) == false && injectHooks[hookId].id == hookId) { injectHooks[hookId].injectState = 2; injectHooks[hookId].inject(); devlog_f("Inject hook ID: %d\n", DL_INIT, hookId); diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index ba4a6851..badee929 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -72,6 +72,7 @@ enum HookType HOOK_ENCOUNTER = 43, HOOK_ADJUSTPOISON = 44, HOOK_ADJUSTRADS = 45, + HOOK_ROLLCHECK = 46, HOOK_COUNT }; diff --git a/sfall/Modules/HookScripts/MiscHs.cpp b/sfall/Modules/HookScripts/MiscHs.cpp index 33438ff6..8797e6a0 100644 --- a/sfall/Modules/HookScripts/MiscHs.cpp +++ b/sfall/Modules/HookScripts/MiscHs.cpp @@ -631,6 +631,57 @@ cancelEnc: } } +static long __stdcall RollCheckHook_Script(long roll, long chance, long bonus, long randomChance, long calledFrom) { + long hookType; + switch (calledFrom - 5) { + case 0x42388E: // compute_attack_ + // compute_spray_ + case 0x4234D1: hookType = 1; break; // single and burst attack hit event + // compute_spray_ + case 0x42356C: hookType = 2; break; // burst attack bullet hit event + // skill_result_ + case 0x4AAB29: hookType = 3; break; // common skill check event + // skill_use_ + case 0x4AB3B6: hookType = 4; break; // SKILL_REPAIR + case 0x4AB8B5: hookType = 5; break; // SKILL_DOCTOR + // skill_check_stealing_ // SKILL_STEAL + case 0x4ABC9F: hookType = 6; break; // source stealing check event + case 0x4ABCE6: hookType = 7; break; // target stealing check event (fail for success stealing) + default: + return roll; // unsupported hook + } + + BeginHook(); + argCount = 5; + + args[0] = hookType; + args[1] = roll; + args[2] = chance; + args[3] = bonus; + args[4] = randomChance; + + RunHookScript(HOOK_ROLLCHECK); + if (cRet) roll = rets[0]; + + EndHook(); + return roll; +} + +static void __declspec(naked) roll_check_hook() { + __asm { + push ecx; + push [esp + 0xC + 8]; // calledFrom + push ebx; // random chance value + push esi; // bonus + push edi; // chance value + call fo::funcoffs::roll_check_critical_; + push eax; // roll result + call RollCheckHook_Script; + pop ecx; + retn; + } +} + void Inject_BarterPriceHook() { HookCalls(BarterPriceHook, { 0x474D4C, // barter_attempt_transaction_ (offers button) @@ -698,6 +749,10 @@ void Inject_EncounterHook() { HookCall(0x4C095C, wmRndEncounterOccurred_hook); } +void Inject_RollCheckHook() { + HookCall(0x4A3020, roll_check_hook); +} + void InitMiscHookScripts() { HookScripts::LoadHookScript("hs_barterprice", HOOK_BARTERPRICE); HookScripts::LoadHookScript("hs_useskillon", HOOK_USESKILLON); @@ -710,6 +765,7 @@ void InitMiscHookScripts() { HookScripts::LoadHookScript("hs_resttimer", HOOK_RESTTIMER); HookScripts::LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER); HookScripts::LoadHookScript("hs_encounter", HOOK_ENCOUNTER); + HookScripts::LoadHookScript("hs_rollcheck", HOOK_ROLLCHECK); } } diff --git a/sfall/Modules/HookScripts/MiscHs.h b/sfall/Modules/HookScripts/MiscHs.h index 3ac9f13c..6c0cc6be 100644 --- a/sfall/Modules/HookScripts/MiscHs.h +++ b/sfall/Modules/HookScripts/MiscHs.h @@ -16,6 +16,7 @@ namespace sfall void Inject_RestTimerHook(); void Inject_ExplosiveTimerHook(); void Inject_EncounterHook(); + void Inject_RollCheckHook(); // Implementation of is_within_perception_ engine function with the hook long __fastcall sf_is_within_perception(fo::GameObject* watcher, fo::GameObject* target);