diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 1392eb39..2de164b0 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -72,6 +72,7 @@ #define HOOK_ADJUSTPOISON (44) #define HOOK_ADJUSTRADS (45) #define HOOK_ROLLCHECK (46) +#define HOOK_BESTWEAPON (47) //Valid arguments to list_begin #define LIST_CRITTERS (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 05532b9e..1c7da284 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -317,7 +317,7 @@ int arg1 - the tile number being checked int arg2 - the elevation being checked int arg3 - 1 if the hex would normally be blocking -object* ret0 - 0 if the hex doesn't block, or any sort of object pointer if it does +Obj ret0 - 0 if the hex doesn't block, or any sort of object pointer if it does ------------------------------------------- @@ -748,3 +748,18 @@ 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 + +------------------------------------------- + +HOOK_BESTWEAPON (hs_bestweapon.int) + +Runs when the game (AI) decides which weapon is the best while searching the inventory for a weapon to equip in combat. +This is also runs when the player presses the "Use Best Weapon" button on the party member control panel. + +Critter arg0 - the critter searching for a weapon +Item arg1 - the best weapon chosen from two items +Item arg2 - the first choice of weapon +Item arg3 - the second choice of weapon +Critter arg4 - the target of the critter (can be 0) + +Item ret0 - overrides the chosen best weapon diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index ae4b3865..a1a0eed4 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -108,6 +108,7 @@ static HooksInjectInfo injectHooks[] = { {HOOK_ADJUSTPOISON, Inject_AdjustPoisonHook, 0}, {HOOK_ADJUSTRADS, Inject_AdjustRadsHook, 1}, // always embedded for party control fix {HOOK_ROLLCHECK, Inject_RollCheckHook, 0}, + {HOOK_BESTWEAPON, Inject_BestWeaponHook, 0}, }; void HookScripts::InjectingHook(int hookId) { diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index d3803957..beb6391d 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -73,6 +73,7 @@ enum HookType HOOK_ADJUSTPOISON = 44, HOOK_ADJUSTRADS = 45, HOOK_ROLLCHECK = 46, + HOOK_BESTWEAPON = 47, HOOK_COUNT }; diff --git a/sfall/Modules/HookScripts/CombatHs.cpp b/sfall/Modules/HookScripts/CombatHs.cpp index e9e08f52..d88974f6 100644 --- a/sfall/Modules/HookScripts/CombatHs.cpp +++ b/sfall/Modules/HookScripts/CombatHs.cpp @@ -99,8 +99,8 @@ static long CalcApCostHook_Script(fo::GameObject* source, long hitMode, long isC long CalcApCostHook_Invoke(fo::GameObject* source, long hitMode, long isCalled, long cost, fo::GameObject* weapon) { return (HookScripts::HookHasScript(HOOK_CALCAPCOST)) - ? CalcApCostHook_Script(source, hitMode, isCalled, cost, weapon) - : cost; + ? CalcApCostHook_Script(source, hitMode, isCalled, cost, weapon) + : cost; } static void __declspec(naked) CalcApCostHook() { @@ -578,6 +578,43 @@ default: } } +static fo::GameObject* __stdcall BestWeaponHook_Script(fo::GameObject* bestWeapon, fo::GameObject* source, fo::GameObject* weapon1, fo::GameObject* weapon2, fo::GameObject* target) { + BeginHook(); + argCount = 5; + + args[0] = (DWORD)source; + args[1] = (DWORD)bestWeapon; + args[2] = (DWORD)weapon1; + args[3] = (DWORD)weapon2; + args[4] = (DWORD)target; + + RunHookScript(HOOK_BESTWEAPON); + + if (cRet > 0) bestWeapon = (fo::GameObject*)rets[0]; + + EndHook(); + return bestWeapon; +} + +static void __declspec(naked) ai_search_inven_weap_hook() { + __asm { + push ecx; + push ebx; + push edx; + push eax; + call fo::funcoffs::ai_best_weapon_; + push eax; + call BestWeaponHook_Script; + retn; + } +} + +fo::GameObject* BestWeaponHook_Invoke(fo::GameObject* bestWeapon, fo::GameObject* source, fo::GameObject* weapon1, fo::GameObject* weapon2, fo::GameObject* target) { + return (HookScripts::HookHasScript(HOOK_BESTWEAPON)) + ? BestWeaponHook_Script(bestWeapon, source, weapon1, weapon2, target) + : bestWeapon; +} + void Inject_ToHitHook() { HookCalls(ToHitHook, { 0x421686, // combat_safety_invalidate_weapon_func_ @@ -664,6 +701,10 @@ void Inject_TargetObjectHook() { SafeWrite8(0x44C26E, 0x17); } +void Inject_BestWeaponHook() { + HookCall(0x429A59, ai_search_inven_weap_hook); +} + void InitCombatHookScripts() { HookScripts::LoadHookScript("hs_tohit", HOOK_TOHIT); HookScripts::LoadHookScript("hs_afterhitroll", HOOK_AFTERHITROLL); @@ -676,6 +717,7 @@ void InitCombatHookScripts() { HookScripts::LoadHookScript("hs_onexplosion", HOOK_ONEXPLOSION); HookScripts::LoadHookScript("hs_subcombatdmg", HOOK_SUBCOMBATDAMAGE); HookScripts::LoadHookScript("hs_targetobject", HOOK_TARGETOBJECT); + HookScripts::LoadHookScript("hs_bestweapon", HOOK_BESTWEAPON); } } diff --git a/sfall/Modules/HookScripts/CombatHs.h b/sfall/Modules/HookScripts/CombatHs.h index 2e08797d..0863b5ac 100644 --- a/sfall/Modules/HookScripts/CombatHs.h +++ b/sfall/Modules/HookScripts/CombatHs.h @@ -18,10 +18,12 @@ void Inject_CombatTurnHook(); void Inject_OnExplosionHook(); void Inject_SubCombatDamageHook(); void Inject_TargetObjectHook(); +void Inject_BestWeaponHook(); int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds); long CalcApCostHook_Invoke(fo::GameObject* source, long hitMode, long isCalled, long cost, fo::GameObject* weapon); //void FindTargetHook_Invoke(fo::GameObject* targets[], fo::GameObject* attacker); +fo::GameObject* BestWeaponHook_Invoke(fo::GameObject* bestWeapon, fo::GameObject* source, fo::GameObject* weapon1, fo::GameObject* weapon2, fo::GameObject* target); }