From 6319017186b8df662eaa3a907e7c4bc3bbd5578e Mon Sep 17 00:00:00 2001 From: NovaRain Date: Tue, 30 Oct 2018 11:19:19 +0800 Subject: [PATCH] Added new HOOK_ONEXPLOSION and a new mode "set_explosion_max_targets" to metarule2_explosions (from Mr.Stalin) (#35) --- artifacts/scripting/headers/sfall.h | 2 + artifacts/scripting/hookscripts.txt | 17 ++++++ artifacts/scripting/sfall function notes.txt | 3 + sfall/Modules/Explosions.cpp | 17 +++++- sfall/Modules/HookScripts.cpp | 1 + sfall/Modules/HookScripts.h | 1 + sfall/Modules/HookScripts/CombatHs.cpp | 59 +++++++++++++++++--- sfall/Modules/HookScripts/CombatHs.h | 1 + 8 files changed, 93 insertions(+), 8 deletions(-) diff --git a/artifacts/scripting/headers/sfall.h b/artifacts/scripting/headers/sfall.h index 45c169af..57744323 100644 --- a/artifacts/scripting/headers/sfall.h +++ b/artifacts/scripting/headers/sfall.h @@ -57,6 +57,7 @@ #define HOOK_EXPLOSIVETIMER (33) #define HOOK_DESCRIPTIONOBJ (34) #define HOOK_USESKILLON (35) +#define HOOK_ONEXPLOSION (36) //Valid arguments to list_begin #define LIST_CRITTERS (0) @@ -148,6 +149,7 @@ #define get_explosion_damage(itemPid) metarule2_explosions(6, itemPid, 0) #define set_dynamite_damage(minDmg, maxDmg) metarule2_explosions(7, minDmg, maxDmg) #define set_plastic_damage(minDmg, maxDmg) metarule2_explosions(8, minDmg, maxDmg) +#define set_explosion_max_targets(x) metarule2_explosions(9, x, 0) #define GAME_MSG_COMBAT (0) diff --git a/artifacts/scripting/hookscripts.txt b/artifacts/scripting/hookscripts.txt index 1d8b1059..ed62539e 100644 --- a/artifacts/scripting/hookscripts.txt +++ b/artifacts/scripting/hookscripts.txt @@ -561,3 +561,20 @@ int arg3 - skill being used int ret1 - a new critter to override the user critter. Pass -1 to cancel the skill use, pass 0 to skip this return value int ret2 - pass 1 to allow the skill being used in combat (only for dude_obj or critter being controlled by the player) + +------------------------------------------- + +HOOK_ONEXPLOSION (hs_onexplosion.int) + +Runs when an explosion occurs and Fallout is checking all the tiles within the explosion radius for targets. +The tile checking will be interrupted when 6 additional targets (critters) are received. + +int arg1 - event type: 1 - when the explosion is from an explosive item, 0 - otherwise +Critter arg2 - The attacker +int arg3 - The tile on which the explosion occurs +int arg4 - checked tile within the explosion radius +Obj arg5 - first found object on the checked tile as an additional target +Critter arg6 - The target critter, may be 0 or equal to the attacker +int arg7 - 1 when using throwing weapons (e.g. grenades), 0 otherwise + +int ret1 - overrides the found object on the checked tile, pass 0 to skip the object diff --git a/artifacts/scripting/sfall function notes.txt b/artifacts/scripting/sfall function notes.txt index 978ff6db..ddb92292 100644 --- a/artifacts/scripting/sfall function notes.txt +++ b/artifacts/scripting/sfall function notes.txt @@ -246,6 +246,9 @@ was made as a dirty easy hack to allow dynamically change some explosion paramet - sets the minimum and maximum damage for Plastic Explosives. - changed damage will be reset each time the player reloads the game. +> void set_explosion_max_targets(x) +- sets the maximum number of additional targets for an explosion, valid range: 1..6 (default is 6) + Some utility/math functions are available: diff --git a/sfall/Modules/Explosions.cpp b/sfall/Modules/Explosions.cpp index 096d1602..e30a0fbe 100644 --- a/sfall/Modules/Explosions.cpp +++ b/sfall/Modules/Explosions.cpp @@ -48,6 +48,7 @@ static bool onlyOnce = false; static bool lightingEnabled = false; static bool explosionsMetaruleReset = false; static bool explosionsDamageReset = false; +static bool explosionMaxTargetReset = false; static const DWORD ranged_attack_lighting_fix_back = 0x4118F8; @@ -363,7 +364,8 @@ enum MetaruleExplosionsMode { EXPL_STATIC_EXPLOSION_RADIUS = 5, EXPL_GET_EXPLOSION_DAMAGE = 6, EXPL_SET_DYNAMITE_EXPLOSION_DAMAGE = 7, - EXPL_SET_PLASTIC_EXPLOSION_DAMAGE = 8 + EXPL_SET_PLASTIC_EXPLOSION_DAMAGE = 8, + EXPL_SET_EXPLOSION_MAX_TARGET = 9, }; static void SetExplosionRadius(int arg1, int arg2) { @@ -444,6 +446,14 @@ int _stdcall ExplosionsMetaruleFunc(int mode, int arg1, int arg2) { case EXPL_SET_PLASTIC_EXPLOSION_DAMAGE: SetExplosionDamage(fo::ProtoId::PID_PLASTIC_EXPLOSIVES, arg1, arg2); return 0; + case EXPL_SET_EXPLOSION_MAX_TARGET: + if (arg1 > 0 && arg1 < 7) { + SafeWrite8(0x423C93, arg1); + explosionMaxTargetReset = true; + } else { + return 0; + } + break; default: return -1; } @@ -466,6 +476,11 @@ void ResetExplosionSettings() { for (int i = 0; i < numDmgChecks; i++) { SafeWrite8(explosion_dmg_check_adr[i], fo::DamageType::DMG_explosion); } + // explosion max target count + if (explosionMaxTargetReset) { + SafeWrite8(0x423C93, 6); + explosionMaxTargetReset = false; + } explosionsMetaruleReset = false; } diff --git a/sfall/Modules/HookScripts.cpp b/sfall/Modules/HookScripts.cpp index bb722465..d7e60d89 100644 --- a/sfall/Modules/HookScripts.cpp +++ b/sfall/Modules/HookScripts.cpp @@ -80,6 +80,7 @@ static HooksInjectInfo injectHooks[] = { {HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false}, {HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false}, {HOOK_USESKILLON, Inject_UseSkillOnHook, false}, + {HOOK_ONEXPLOSION, Inject_OnExplosionHook, false}, }; bool HookScripts::injectAllHooks; diff --git a/sfall/Modules/HookScripts.h b/sfall/Modules/HookScripts.h index 4ecf1a07..7a042883 100644 --- a/sfall/Modules/HookScripts.h +++ b/sfall/Modules/HookScripts.h @@ -62,6 +62,7 @@ enum HookType HOOK_EXPLOSIVETIMER = 33, HOOK_DESCRIPTIONOBJ = 34, HOOK_USESKILLON = 35, + HOOK_ONEXPLOSION = 36, HOOK_COUNT }; diff --git a/sfall/Modules/HookScripts/CombatHs.cpp b/sfall/Modules/HookScripts/CombatHs.cpp index ee30d745..6c114146 100644 --- a/sfall/Modules/HookScripts/CombatHs.cpp +++ b/sfall/Modules/HookScripts/CombatHs.cpp @@ -40,7 +40,6 @@ static void __declspec(naked) ToHitHook() { } static void __fastcall AfterHitRollHook_Script(fo::ComputeAttackResult &ctd, DWORD hitChance, DWORD hit) { - BeginHook(); argCount = 5; @@ -125,7 +124,6 @@ static void __declspec(naked) CalcApCostHook2() { } static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DWORD rounds, DWORD multiply) { - BeginHook(); argCount = 12; @@ -168,7 +166,7 @@ static void __declspec(naked) ComputeDamageHook() { push eax; // store ctd call fo::funcoffs::compute_damage_; pop ecx; // restore ctd (eax) - pop edx; // restore num rounds + pop edx; // restore num rounds call ComputeDamageHook_Script; pop ecx; retn; @@ -176,7 +174,6 @@ static void __declspec(naked) ComputeDamageHook() { } static void __fastcall FindTargetHook_Script(DWORD* target, DWORD attacker) { - BeginHook(); argCount = 5; @@ -281,7 +278,7 @@ static void __declspec(naked) AmmoCostHook() { cmp dword ptr [esp + 0x1C + 4], ANIM_fire_continuous; jg skip; mov ecx, 3; // hook type burst -skip: +skip: xchg eax, edx; push eax; // rounds in attack call AmmoCostHook_Script; // edx - weapon @@ -344,6 +341,51 @@ normalTurn: } } +fo::GameObject* __fastcall ComputeExplosionOnExtrasHook_Script(fo::GameObject* object, DWORD checkTile, fo::ComputeAttackResult* ctdSource, DWORD isCheck, DWORD isThrowing, fo::GameObject* who) { + fo::GameObject* result = object; + + BeginHook(); + argCount = 7; + + args[0] = isCheck; + args[1] = (DWORD)ctdSource->attacker; + args[2] = ctdSource->targetTile; + args[3] = checkTile; + args[4] = (DWORD)object; + args[5] = (DWORD)who; + args[6] = isThrowing; + + RunHookScript(HOOK_ONEXPLOSION); + + if (cRet > 0) result = (fo::GameObject*)rets[0]; // override object + + EndHook(); + return result; +} + +static void _declspec(naked) ComputeExplosionOnExtrasHook() { + __asm { + cmp dword ptr [esp + 0x34 + 4], 0x429533; // skip hook when AI assesses the situation in choosing the best weapon + jz end; + cmp dword ptr [esp + 0x34 + 4], 0x4296BC; + jnz hook; +end: + jmp fo::funcoffs::obj_blocking_at_; +hook: + push ecx; + push eax; // who (target/source) + call fo::funcoffs::obj_blocking_at_; + push [esp + 0x34 - 0x24 + 12]; // isThrowing + push [esp + 0x34 - 0x34 + 16]; // isCheck (bypass damage) + push esi; // source ctd + mov ecx, eax; // object + mov edx, edi; // check tile + call ComputeExplosionOnExtrasHook_Script; + pop ecx; + retn; + } +} + void Inject_ToHitHook() { HookCalls(ToHitHook, { 0x421686, // combat_safety_invalidate_weapon_func_ @@ -407,8 +449,11 @@ void Inject_CombatTurnHook() { HookCalls(CombatTurnHook, { 0x422D87, 0x422E20 }); } -void InitCombatHookScripts() { +void Inject_OnExplosionHook() { + HookCall(0x423D70, ComputeExplosionOnExtrasHook); +} +void InitCombatHookScripts() { LoadHookScript("hs_tohit", HOOK_TOHIT); LoadHookScript("hs_afterhitroll", HOOK_AFTERHITROLL); LoadHookScript("hs_calcapcost", HOOK_CALCAPCOST); @@ -417,7 +462,7 @@ void InitCombatHookScripts() { LoadHookScript("hs_itemdamage", HOOK_ITEMDAMAGE); LoadHookScript("hs_ammocost", HOOK_AMMOCOST); LoadHookScript("hs_combatturn", HOOK_COMBATTURN); - + LoadHookScript("hs_onexplosion", HOOK_ONEXPLOSION); } } diff --git a/sfall/Modules/HookScripts/CombatHs.h b/sfall/Modules/HookScripts/CombatHs.h index e402f2cf..546ab85b 100644 --- a/sfall/Modules/HookScripts/CombatHs.h +++ b/sfall/Modules/HookScripts/CombatHs.h @@ -15,5 +15,6 @@ void Inject_FindTargetHook(); void Inject_ItemDamageHook(); void Inject_AmmoCostHook(); void Inject_CombatTurnHook(); +void Inject_OnExplosionHook(); }