mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Backported the code injection system for game hooks from 4.1
Split HookScripts.cpp/h to multiple sets in HookScripts\ as 4.x.
Reverted tile_num to stdcall (commit a5f57d4)
This commit is contained in:
+4
-1
@@ -321,7 +321,7 @@ Movie17=credits.mve
|
|||||||
|
|
||||||
;To change the limit of the distance away from the player to which you're allowed to scroll the local maps, uncomment the next two lines
|
;To change the limit of the distance away from the player to which you're allowed to scroll the local maps, uncomment the next two lines
|
||||||
;Defaults are 480 in the x direction and 400 in the y direction.
|
;Defaults are 480 in the x direction and 400 in the y direction.
|
||||||
;Not compatible with the res patch!
|
;Not compatible with the hi-res patch!
|
||||||
;LocalMapXLimit=480
|
;LocalMapXLimit=480
|
||||||
;LocalMapYLimit=400
|
;LocalMapYLimit=400
|
||||||
|
|
||||||
@@ -852,6 +852,9 @@ MapGridToggleKey=0
|
|||||||
;Has pretty nasty side effects when saving/reloading, so don't use for regular gameplay
|
;Has pretty nasty side effects when saving/reloading, so don't use for regular gameplay
|
||||||
DontDeleteProtos=0
|
DontDeleteProtos=0
|
||||||
|
|
||||||
|
;Set to 1 to force sfall to inject all hooks code into the game, even if corresponding hook scripts don't exist
|
||||||
|
InjectAllGameHooks=0
|
||||||
|
|
||||||
;Set to 1 to force sfall to search for global/hook scripts every time the game loads rather than only the first time
|
;Set to 1 to force sfall to search for global/hook scripts every time the game loads rather than only the first time
|
||||||
AlwaysFindScripts=0
|
AlwaysFindScripts=0
|
||||||
|
|
||||||
|
|||||||
@@ -150,9 +150,10 @@ long __fastcall db_init(const char* path_dat, const char* path_patches) {
|
|||||||
WRAP_WATCOM_FCALL2(db_init_, path_dat, path_patches);
|
WRAP_WATCOM_FCALL2(db_init_, path_dat, path_patches);
|
||||||
}
|
}
|
||||||
|
|
||||||
long __fastcall tile_num(long x, long y) {
|
long __stdcall tile_num(long x, long y) {
|
||||||
__asm xor ebx, ebx; // don't delete (bug in tile_num_)
|
__asm push ebx; // don't delete (bug in tile_num_)
|
||||||
WRAP_WATCOM_FCALL2(tile_num_, x, y);
|
WRAP_WATCOM_CALL2(tile_num_, x, y);
|
||||||
|
__asm pop ebx;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWORD elevation, void* func) {
|
GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWORD elevation, void* func) {
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ void __declspec() interpretError(const char* fmt, ...);
|
|||||||
|
|
||||||
long __fastcall db_init(const char* path_dat, const char* path_patches);
|
long __fastcall db_init(const char* path_dat, const char* path_patches);
|
||||||
|
|
||||||
long __fastcall tile_num(long x, long y);
|
long __stdcall tile_num(long x, long y);
|
||||||
|
|
||||||
GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWORD elevation, void* func);
|
GameObject* __fastcall obj_blocking_at_wrapper(GameObject* obj, DWORD tile, DWORD elevation, void* func);
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "..\main.h"
|
#include "..\main.h"
|
||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
|
|
||||||
#include "..\Modules\HookScripts.h"
|
#include "..\Modules\HookScripts\CombatHs.h"
|
||||||
|
|
||||||
#include "items.h"
|
#include "items.h"
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,10 @@
|
|||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
|
|
||||||
#include "..\Modules\HeroAppearance.h"
|
#include "..\Modules\HeroAppearance.h"
|
||||||
#include "..\Modules\HookScripts.h"
|
|
||||||
#include "..\Modules\PartyControl.h"
|
#include "..\Modules\PartyControl.h"
|
||||||
|
|
||||||
|
#include "..\Modules\HookScripts\InventoryHs.h"
|
||||||
|
|
||||||
#include "inventory.h"
|
#include "inventory.h"
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
#include "..\main.h"
|
#include "..\main.h"
|
||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
|
|
||||||
#include "..\Modules\HookScripts.h"
|
#include "..\Modules\HookScripts\CombatHs.h"
|
||||||
|
#include "..\Modules\HookScripts\InventoryHs.h"
|
||||||
|
#include "..\Modules\HookScripts\ObjectHs.h"
|
||||||
#include "..\Modules\Perks.h"
|
#include "..\Modules\Perks.h"
|
||||||
#include "..\Modules\Unarmed.h"
|
#include "..\Modules\Unarmed.h"
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "..\main.h"
|
#include "..\main.h"
|
||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
|
|
||||||
#include "..\Modules\HookScripts.h"
|
#include "..\Modules\HookScripts\MiscHs.h"
|
||||||
|
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace sf = sfall;
|
|||||||
|
|
||||||
//static std::vector<int> buildLineTiles;
|
//static std::vector<int> buildLineTiles;
|
||||||
|
|
||||||
//static bool __stdcall TileExists(long tile) {
|
//static bool TileExists(long tile) {
|
||||||
// return (std::find(buildLineTiles.cbegin(), buildLineTiles.cend(), tile) != buildLineTiles.cend());
|
// return (std::find(buildLineTiles.cbegin(), buildLineTiles.cend(), tile) != buildLineTiles.cend());
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "FalloutEngine\Fallout2.h"
|
#include "FalloutEngine\Fallout2.h"
|
||||||
#include "Modules\DebugEditor.h"
|
#include "Modules\DebugEditor.h"
|
||||||
#include "Modules\Graphics.h"
|
#include "Modules\Graphics.h"
|
||||||
#include "Modules\HookScripts.h"
|
#include "Modules\HookScripts\Common.h"
|
||||||
#include "Modules\Inventory.h"
|
#include "Modules\Inventory.h"
|
||||||
#include "Modules\ScriptExtender.h"
|
#include "Modules\ScriptExtender.h"
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
#include "..\Translate.h"
|
#include "..\Translate.h"
|
||||||
|
|
||||||
|
#include "HookScripts\InventoryHs.h"
|
||||||
|
|
||||||
#include "..\Game\objects.h"
|
#include "..\Game\objects.h"
|
||||||
|
|
||||||
#include "HookScripts.h"
|
|
||||||
#include "LoadGameHook.h"
|
#include "LoadGameHook.h"
|
||||||
#include "ScriptExtender.h"
|
#include "ScriptExtender.h"
|
||||||
#include "Worldmap.h"
|
#include "Worldmap.h"
|
||||||
|
|||||||
@@ -20,10 +20,11 @@
|
|||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
#include "..\SimplePatch.h"
|
#include "..\SimplePatch.h"
|
||||||
#include "..\Translate.h"
|
#include "..\Translate.h"
|
||||||
|
|
||||||
#include "HookScripts.h"
|
#include "HookScripts.h"
|
||||||
#include "Objects.h"
|
#include "Objects.h"
|
||||||
|
|
||||||
|
#include "HookScripts\CombatHS.h"
|
||||||
|
|
||||||
#include "Combat.h"
|
#include "Combat.h"
|
||||||
|
|
||||||
namespace sfall
|
namespace sfall
|
||||||
@@ -193,7 +194,11 @@ long __fastcall Combat::check_item_ammo_cost(fo::GameObject* weapon, fo::AttackT
|
|||||||
|
|
||||||
DWORD newRounds = rounds;
|
DWORD newRounds = rounds;
|
||||||
|
|
||||||
AmmoCostHook_Script(1, weapon, newRounds); // newRounds returns the new "ammo" value multiplied by the cost
|
if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) {
|
||||||
|
AmmoCostHook_Script(1, weapon, newRounds); // newRounds returns the new "ammo" value multiplied by the cost
|
||||||
|
} else if (rounds == 1) { // NOTE: it doesn't make sense to call item_w_compute_ammo_cost for rounds greater than one
|
||||||
|
fo::func::item_w_compute_ammo_cost(weapon, &newRounds);
|
||||||
|
}
|
||||||
|
|
||||||
// calculate the cost
|
// calculate the cost
|
||||||
long cost = (newRounds != rounds) ? newRounds / rounds : 1; // 1 - default cost
|
long cost = (newRounds != rounds) ? newRounds / rounds : 1; // 1 - default cost
|
||||||
@@ -253,8 +258,10 @@ tryAttack:
|
|||||||
static long __fastcall divide_burst_rounds_by_ammo_cost(long currAmmo, fo::GameObject* weapon, long burstRounds) {
|
static long __fastcall divide_burst_rounds_by_ammo_cost(long currAmmo, fo::GameObject* weapon, long burstRounds) {
|
||||||
DWORD roundsCost = 1; // default burst cost
|
DWORD roundsCost = 1; // default burst cost
|
||||||
|
|
||||||
roundsCost = burstRounds; // rounds in burst (the number of rounds fired in the burst)
|
if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) {
|
||||||
AmmoCostHook_Script(2, weapon, roundsCost); // roundsCost returns the new cost
|
roundsCost = burstRounds; // rounds in burst (the number of rounds fired in the burst)
|
||||||
|
AmmoCostHook_Script(2, weapon, roundsCost); // roundsCost returns the new cost
|
||||||
|
}
|
||||||
|
|
||||||
long cost = burstRounds * roundsCost; // amount of ammo required for this burst (multiplied by 1 or by the value returned from HOOK_AMMOCOST)
|
long cost = burstRounds * roundsCost; // amount of ammo required for this burst (multiplied by 1 or by the value returned from HOOK_AMMOCOST)
|
||||||
if (cost > currAmmo) cost = currAmmo; // if cost ammo more than current ammo, set it to current
|
if (cost > currAmmo) cost = currAmmo; // if cost ammo more than current ammo, set it to current
|
||||||
|
|||||||
+89
-1870
File diff suppressed because it is too large
Load Diff
@@ -56,6 +56,12 @@ enum HookType
|
|||||||
HOOK_COUNT
|
HOOK_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct HookFile {
|
||||||
|
int id;
|
||||||
|
// std::string filePath;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
class HookScripts {
|
class HookScripts {
|
||||||
public:
|
public:
|
||||||
static const char* name() { return "HookScripts"; }
|
static const char* name() { return "HookScripts"; }
|
||||||
@@ -70,40 +76,13 @@ public:
|
|||||||
|
|
||||||
static bool HookHasScript(int hookId);
|
static bool HookHasScript(int hookId);
|
||||||
|
|
||||||
|
static void InjectingHook(int hookId);
|
||||||
|
static bool IsInjectHook(int hookId);
|
||||||
|
|
||||||
// register hook by proc num (special values: -1 - use default (start) procedure, 0 - unregister)
|
// register hook by proc num (special values: -1 - use default (start) procedure, 0 - unregister)
|
||||||
static void RegisterHook(fo::Program* script, int id, int procNum, bool specReg);
|
static void RegisterHook(fo::Program* script, int id, int procNum, bool specReg);
|
||||||
|
|
||||||
static void RunHookScriptsAtProc(DWORD procId);
|
static void RunHookScriptsAtProc(DWORD procId);
|
||||||
};
|
};
|
||||||
|
|
||||||
class HookCommon {
|
|
||||||
public:
|
|
||||||
static DWORD GetHSArgCount();
|
|
||||||
static DWORD GetHSArg();
|
|
||||||
static DWORD GetHSArgAt(DWORD id);
|
|
||||||
static DWORD* GetHSArgs();
|
|
||||||
static void SetHSArg(DWORD id, DWORD value);
|
|
||||||
static void __stdcall SetHSReturn(DWORD d);
|
|
||||||
|
|
||||||
static void GameModeChangeHook(DWORD exit);
|
|
||||||
static void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey);
|
|
||||||
static void __stdcall MouseClickHook(DWORD button, bool pressed);
|
|
||||||
|
|
||||||
static void Reset();
|
|
||||||
};
|
|
||||||
|
|
||||||
int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds);
|
|
||||||
|
|
||||||
void InvenUnwield_HookDrop();
|
|
||||||
void InvenUnwield_HookMove();
|
|
||||||
|
|
||||||
void __stdcall SetRemoveObjectType(long rmType);
|
|
||||||
|
|
||||||
void __stdcall AdjustFidHook(DWORD vanillaFid);
|
|
||||||
|
|
||||||
long __stdcall CalcApCostHook_Invoke(fo::GameObject* source, long hitMode, long isCalled, long cost, fo::GameObject* weapon);
|
|
||||||
long __stdcall UseObjOnHook_Invoke(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target);
|
|
||||||
long __stdcall PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result);
|
|
||||||
long __stdcall InvenWieldHook_Invoke(fo::GameObject* critter, fo::GameObject* item, long flags);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,394 @@
|
|||||||
|
#include "..\..\FalloutEngine\Fallout2.h"
|
||||||
|
#include "..\..\SafeWrite.h"
|
||||||
|
#include "..\Combat.h"
|
||||||
|
#include "..\DamageMod.h"
|
||||||
|
#include "..\HookScripts.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "CombatHs.h"
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
static void __declspec(naked) ToHitHook() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[4], eax; // attacker
|
||||||
|
mov args[8], ebx; // target
|
||||||
|
mov args[12], ecx; // body part
|
||||||
|
mov args[16], edx; // source tile
|
||||||
|
mov eax, [esp + 8];
|
||||||
|
mov args[24], eax; // is ranged
|
||||||
|
push eax;
|
||||||
|
mov eax, [esp + 8];
|
||||||
|
mov args[20], eax; // attack type
|
||||||
|
push eax;
|
||||||
|
mov eax, args[4]; // restore
|
||||||
|
call fo::funcoffs::determine_to_hit_func_;
|
||||||
|
mov args[0], eax;
|
||||||
|
mov ebx, eax;
|
||||||
|
}
|
||||||
|
argCount = 8;
|
||||||
|
|
||||||
|
args[7] = Combat::determineHitChance;
|
||||||
|
RunHookScript(HOOK_TOHIT);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
retn 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static DWORD __fastcall AfterHitRollHook_Script(fo::ComputeAttackResult &ctd, DWORD hitChance, DWORD hit) {
|
||||||
|
BeginHook();
|
||||||
|
argCount = 5;
|
||||||
|
|
||||||
|
args[0] = hit;
|
||||||
|
args[1] = (DWORD)ctd.attacker; // Attacker
|
||||||
|
args[2] = (DWORD)ctd.target; // Target
|
||||||
|
args[3] = ctd.bodyPart; // bodypart
|
||||||
|
args[4] = hitChance;
|
||||||
|
|
||||||
|
RunHookScript(HOOK_AFTERHITROLL);
|
||||||
|
if (cRet > 0) {
|
||||||
|
hit = rets[0];
|
||||||
|
if (cRet > 1) {
|
||||||
|
ctd.bodyPart = rets[1];
|
||||||
|
if (cRet > 2) ctd.target = (fo::GameObject*)rets[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndHook();
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) AfterHitRollHook() {
|
||||||
|
using namespace fo;
|
||||||
|
__asm {
|
||||||
|
mov ecx, esi; // ctd
|
||||||
|
mov edx, [esp + 0x18 + 4]; // hit chance
|
||||||
|
push eax; // was it a hit?
|
||||||
|
call AfterHitRollHook_Script;
|
||||||
|
// engine code
|
||||||
|
mov ebx, eax;
|
||||||
|
cmp eax, ROLL_FAILURE;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static long CalcApCostHook_Script(fo::GameObject* source, long hitMode, long isCalled, long cost, fo::GameObject* weapon) {
|
||||||
|
BeginHook();
|
||||||
|
argCount = 5;
|
||||||
|
|
||||||
|
args[0] = (DWORD)source;
|
||||||
|
args[1] = hitMode;
|
||||||
|
args[2] = isCalled;
|
||||||
|
args[3] = cost;
|
||||||
|
args[4] = (DWORD)weapon;
|
||||||
|
|
||||||
|
RunHookScript(HOOK_CALCAPCOST);
|
||||||
|
|
||||||
|
if (cRet > 0) cost = rets[0];
|
||||||
|
EndHook();
|
||||||
|
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static void __declspec(naked) CalcApCostHook() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], eax;
|
||||||
|
mov args[4], edx;
|
||||||
|
mov args[8], ebx;
|
||||||
|
call fo::funcoffs::item_w_mp_cost_;
|
||||||
|
mov args[12], eax;
|
||||||
|
mov ebx, eax;
|
||||||
|
push ecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 5;
|
||||||
|
args[4] = 0;
|
||||||
|
|
||||||
|
RunHookScript(HOOK_CALCAPCOST);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// this is for using non-weapon items, always 2 AP in vanilla
|
||||||
|
static void __declspec(naked) CalcApCostHook2() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], ecx; // critter
|
||||||
|
mov args[4], edx; // attack type (to determine hand)
|
||||||
|
mov args[8], ebx;
|
||||||
|
mov ebx, 2; // vanilla cost value
|
||||||
|
mov args[12], ebx;
|
||||||
|
//push ecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 5;
|
||||||
|
args[4] = 0;
|
||||||
|
|
||||||
|
RunHookScript(HOOK_CALCAPCOST);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
//pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DWORD rounds, DWORD multiplier) {
|
||||||
|
BeginHook();
|
||||||
|
argCount = 13;
|
||||||
|
|
||||||
|
args[0] = (DWORD)ctd.target; // Target
|
||||||
|
args[1] = (DWORD)ctd.attacker; // Attacker
|
||||||
|
args[2] = ctd.targetDamage; // amountTarget
|
||||||
|
args[3] = ctd.attackerDamage; // amountSource
|
||||||
|
args[4] = ctd.targetFlags; // flagsTarget
|
||||||
|
args[5] = ctd.attackerFlags; // flagsSource
|
||||||
|
args[6] = (DWORD)ctd.weapon;
|
||||||
|
args[7] = ctd.bodyPart;
|
||||||
|
args[8] = multiplier; // damage multiplier
|
||||||
|
args[9] = rounds; // number of rounds
|
||||||
|
args[10] = ctd.knockbackValue;
|
||||||
|
args[11] = ctd.hitMode; // attack type
|
||||||
|
args[12] = (DWORD)&ctd; // main_ctd/shoot_ctd/explosion_ctd
|
||||||
|
|
||||||
|
RunHookScript(HOOK_COMBATDAMAGE);
|
||||||
|
|
||||||
|
if (cRet > 0) {
|
||||||
|
ctd.targetDamage = rets[0];
|
||||||
|
if (cRet > 1) {
|
||||||
|
ctd.attackerDamage = rets[1];
|
||||||
|
if (cRet > 2) {
|
||||||
|
ctd.targetFlags = rets[2]; // flagsTarget
|
||||||
|
if (cRet > 3) {
|
||||||
|
ctd.attackerFlags = rets[3]; // flagsSource
|
||||||
|
if (cRet > 4) ctd.knockbackValue = rets[4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) ComputeDamageHook() {
|
||||||
|
__asm {
|
||||||
|
push ecx;
|
||||||
|
push ebx; // store dmg multiplier args[8]
|
||||||
|
push edx; // store num of rounds args[9]
|
||||||
|
push eax; // store ctd
|
||||||
|
call fo::funcoffs::compute_damage_;
|
||||||
|
pop ecx; // restore ctd (eax)
|
||||||
|
pop edx; // restore num of rounds
|
||||||
|
call ComputeDamageHook_Script; // stack - arg multiplier
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __fastcall FindTargetHook_Script(DWORD* target, fo::GameObject* attacker) {
|
||||||
|
BeginHook();
|
||||||
|
argCount = 5;
|
||||||
|
|
||||||
|
args[0] = (DWORD)attacker;
|
||||||
|
args[1] = target[0];
|
||||||
|
args[2] = target[1];
|
||||||
|
args[3] = target[2];
|
||||||
|
args[4] = target[3];
|
||||||
|
|
||||||
|
RunHookScript(HOOK_FINDTARGET);
|
||||||
|
|
||||||
|
if (cRet > 0) {
|
||||||
|
if (rets[0] != -1) target[0] = rets[0];
|
||||||
|
if (cRet > 1 && rets[1] != -1) target[1] = rets[1];
|
||||||
|
if (cRet > 2 && rets[2] != -1) target[2] = rets[2];
|
||||||
|
if (cRet > 3 && rets[3] != -1) target[3] = rets[3];
|
||||||
|
}
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) FindTargetHook() {
|
||||||
|
__asm {
|
||||||
|
push eax;
|
||||||
|
call fo::funcoffs::qsort_;
|
||||||
|
pop ecx; // targets (base)
|
||||||
|
mov edx, esi; // attacker
|
||||||
|
jmp FindTargetHook_Script;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) ItemDamageHook() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], eax; // min
|
||||||
|
mov args[4], edx; // max
|
||||||
|
mov args[8], edi; // weapon
|
||||||
|
mov args[12], ecx; // critter
|
||||||
|
mov args[16], esi; // type
|
||||||
|
mov args[20], ebp; // non-zero for weapon melee attack (add to min/max melee damage)
|
||||||
|
pushadc;
|
||||||
|
}
|
||||||
|
argCount = 6;
|
||||||
|
|
||||||
|
// tweak for 0x4784AA (obsolete)
|
||||||
|
//if (args[2] == 0) { // weapon arg
|
||||||
|
// args[4] += 8; // type arg
|
||||||
|
//}
|
||||||
|
|
||||||
|
RunHookScript(HOOK_ITEMDAMAGE);
|
||||||
|
|
||||||
|
__asm popadc;
|
||||||
|
if (cRet > 0) {
|
||||||
|
__asm mov eax, rets[0]; // set min
|
||||||
|
if (cRet > 1) {
|
||||||
|
__asm mov edx, rets[4]; // set max
|
||||||
|
} else {
|
||||||
|
HookEnd;
|
||||||
|
__asm retn; // no calc random
|
||||||
|
}
|
||||||
|
}
|
||||||
|
HookEnd;
|
||||||
|
__asm jmp fo::funcoffs::roll_random_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds) {
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
BeginHook();
|
||||||
|
argCount = 4;
|
||||||
|
|
||||||
|
args[0] = (DWORD)weapon;
|
||||||
|
args[1] = rounds; // rounds in attack
|
||||||
|
args[3] = hookType;
|
||||||
|
|
||||||
|
if (hookType == 2) { // burst hook
|
||||||
|
rounds = 1; // set default multiply for check burst attack
|
||||||
|
} else {
|
||||||
|
result = fo::func::item_w_compute_ammo_cost(weapon, &rounds);
|
||||||
|
if (result == -1) goto failed; // computation failed
|
||||||
|
}
|
||||||
|
args[2] = rounds; // rounds as computed by game (cost)
|
||||||
|
|
||||||
|
RunHookScript(HOOK_AMMOCOST);
|
||||||
|
|
||||||
|
if (cRet > 0) rounds = rets[0]; // override rounds
|
||||||
|
|
||||||
|
failed:
|
||||||
|
EndHook();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) AmmoCostHook() {
|
||||||
|
using namespace fo;
|
||||||
|
__asm {
|
||||||
|
xor ecx, ecx; // type of hook (0)
|
||||||
|
cmp dword ptr [esp + 0x1C + 4], ANIM_fire_burst;
|
||||||
|
jl skip;
|
||||||
|
cmp dword ptr [esp + 0x1C + 4], ANIM_fire_continuous;
|
||||||
|
jg skip;
|
||||||
|
mov ecx, 3; // hook type burst
|
||||||
|
skip:
|
||||||
|
xchg eax, edx;
|
||||||
|
push eax; // rounds in attack ref
|
||||||
|
call AmmoCostHook_Script; // edx - weapon
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void Inject_ToHitHook() {
|
||||||
|
const DWORD toHitHkAddr[] = {
|
||||||
|
0x421686, // combat_safety_invalidate_weapon_func_
|
||||||
|
0x4231D9, // check_ranged_miss_
|
||||||
|
0x42331F, // shoot_along_path_
|
||||||
|
0x4237FC, // compute_attack_
|
||||||
|
0x424379, // determine_to_hit_
|
||||||
|
0x42438D, // determine_to_hit_no_range_
|
||||||
|
0x42439C, // determine_to_hit_from_tile_
|
||||||
|
0x42679A // combat_to_hit_
|
||||||
|
};
|
||||||
|
HookCalls(ToHitHook, toHitHkAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_AfterHitRollHook() {
|
||||||
|
MakeCall(0x423893, AfterHitRollHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_CalcApCostHook() {
|
||||||
|
//const DWORD calcApCostHkAddr[] = {
|
||||||
|
// 0x42307A,
|
||||||
|
// 0x42669F,
|
||||||
|
// 0x42687B,
|
||||||
|
// 0x42A625,
|
||||||
|
// 0x42A655,
|
||||||
|
// 0x42A686,
|
||||||
|
// 0x42AE32,
|
||||||
|
// 0x42AE71,
|
||||||
|
// 0x460048,
|
||||||
|
// 0x47807B
|
||||||
|
//};
|
||||||
|
//HookCalls(CalcApCostHook, calcApCostHkAddr);
|
||||||
|
MakeCall(0x478083, CalcApCostHook2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_CombatDamageHook() {
|
||||||
|
const DWORD computeDamageHkAddr[] = {
|
||||||
|
0x42326C, // check_ranged_miss()
|
||||||
|
0x4233E3, // shoot_along_path() - for extra burst targets
|
||||||
|
0x423AB7, // compute_attack()
|
||||||
|
0x423BBF, // compute_attack()
|
||||||
|
// 0x423DE7, // compute_explosion_on_extras()
|
||||||
|
0x423E69, // compute_explosion_on_extras()
|
||||||
|
0x424220, // attack_crit_failure()
|
||||||
|
0x4242FB // attack_crit_failure()
|
||||||
|
};
|
||||||
|
HookCalls(ComputeDamageHook, computeDamageHkAddr);
|
||||||
|
MakeCall(0x423DEB, ComputeDamageHook); // compute_explosion_on_extras() - fix for the attacker
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_FindTargetHook() {
|
||||||
|
HookCall(0x429143, FindTargetHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_ItemDamageHook() {
|
||||||
|
HookCall(0x478560, ItemDamageHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_AmmoCostHook() {
|
||||||
|
HookCall(0x423A7C, AmmoCostHook); // compute_attack_
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitCombatHookScripts() {
|
||||||
|
HookScripts::LoadHookScript("hs_tohit", HOOK_TOHIT);
|
||||||
|
HookScripts::LoadHookScript("hs_afterhitroll", HOOK_AFTERHITROLL);
|
||||||
|
HookScripts::LoadHookScript("hs_calcapcost", HOOK_CALCAPCOST);
|
||||||
|
HookScripts::LoadHookScript("hs_combatdamage", HOOK_COMBATDAMAGE);
|
||||||
|
HookScripts::LoadHookScript("hs_findtarget", HOOK_FINDTARGET);
|
||||||
|
HookScripts::LoadHookScript("hs_itemdamage", HOOK_ITEMDAMAGE);
|
||||||
|
HookScripts::LoadHookScript("hs_ammocost", HOOK_AMMOCOST);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Combat-related hook scripts
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
void InitCombatHookScripts();
|
||||||
|
|
||||||
|
void Inject_ToHitHook();
|
||||||
|
void Inject_AfterHitRollHook();
|
||||||
|
void Inject_CalcApCostHook();
|
||||||
|
void Inject_CombatDamageHook();
|
||||||
|
void Inject_FindTargetHook();
|
||||||
|
void Inject_ItemDamageHook();
|
||||||
|
void Inject_AmmoCostHook();
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
#include "..\..\FalloutEngine\Fallout2.h"
|
||||||
|
#include "..\LoadGameHook.h"
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
static const int maxArgs = 16; // Maximum number of hook arguments
|
||||||
|
static const int maxRets = 8; // Maximum number of return values
|
||||||
|
static const int maxDepth = 8; // Maximum recursion depth for hook calls
|
||||||
|
|
||||||
|
struct {
|
||||||
|
DWORD hookID;
|
||||||
|
DWORD argCount;
|
||||||
|
DWORD cArg;
|
||||||
|
DWORD cRet;
|
||||||
|
DWORD cRetTmp;
|
||||||
|
DWORD oldArgs[maxArgs];
|
||||||
|
DWORD oldRets[maxRets];
|
||||||
|
} savedArgs[maxDepth];
|
||||||
|
|
||||||
|
static DWORD callDepth;
|
||||||
|
static DWORD currentRunHook = -1;
|
||||||
|
|
||||||
|
DWORD args[maxArgs]; // current hook arguments
|
||||||
|
DWORD rets[maxRets]; // current hook return values
|
||||||
|
|
||||||
|
DWORD argCount;
|
||||||
|
DWORD cArg; // how many arguments were taken by current hook script
|
||||||
|
DWORD cRet; // how many return values were set by current hook script
|
||||||
|
DWORD cRetTmp; // how many return values were set by specific hook script (when using register_hook)
|
||||||
|
|
||||||
|
std::vector<HookScript> hooks[HOOK_COUNT];
|
||||||
|
|
||||||
|
DWORD HookCommon::GetHSArgCount() {
|
||||||
|
return argCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD HookCommon::GetHSArg() {
|
||||||
|
return (cArg == argCount) ? 0 : args[cArg++];
|
||||||
|
}
|
||||||
|
|
||||||
|
void HookCommon::SetHSArg(DWORD id, DWORD value) {
|
||||||
|
if (id < argCount) args[id] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD* HookCommon::GetHSArgs() {
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD HookCommon::GetHSArgAt(DWORD id) {
|
||||||
|
return args[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall HookCommon::SetHSReturn(DWORD value) {
|
||||||
|
if (cRetTmp < maxRets) {
|
||||||
|
rets[cRetTmp++] = value;
|
||||||
|
}
|
||||||
|
if (cRetTmp > cRet) {
|
||||||
|
cRet = cRetTmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall BeginHook() {
|
||||||
|
if (callDepth && callDepth <= maxDepth) {
|
||||||
|
// save all values of the current hook if another hook was called during the execution of the current hook
|
||||||
|
int cDepth = callDepth - 1;
|
||||||
|
savedArgs[cDepth].hookID = currentRunHook;
|
||||||
|
savedArgs[cDepth].argCount = argCount; // number of arguments of the current hook
|
||||||
|
savedArgs[cDepth].cArg = cArg; // current count of taken arguments
|
||||||
|
savedArgs[cDepth].cRet = cRet; // number of return values for the current hook
|
||||||
|
savedArgs[cDepth].cRetTmp = cRetTmp;
|
||||||
|
std::memcpy(&savedArgs[cDepth].oldArgs, args, maxArgs * sizeof(DWORD)); // values of the arguments
|
||||||
|
if (cRet) std::memcpy(&savedArgs[cDepth].oldRets, rets, maxRets * sizeof(DWORD)); // return values
|
||||||
|
|
||||||
|
//devlog_f("\nSaved cArgs/cRet: %d / %d(%d)\n", DL_HOOK, savedArgs[cDepth].argCount, savedArgs[cDepth].cRet, cRetTmp);
|
||||||
|
//for (unsigned int i = 0; i < maxArgs; i++) {
|
||||||
|
// devlog_f("Saved Args/Rets: %d / %d\n", DL_HOOK, savedArgs[cDepth].oldArgs[i], ((i < maxRets) ? savedArgs[cDepth].oldRets[i] : -1));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
callDepth++;
|
||||||
|
|
||||||
|
devlog_f("Begin running hook, current depth: %d, current executable hook: %d\n", DL_HOOK, callDepth, currentRunHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __stdcall RunSpecificHookScript(HookScript *hook) {
|
||||||
|
cArg = 0;
|
||||||
|
cRetTmp = 0;
|
||||||
|
if (hook->callback != -1) {
|
||||||
|
fo::func::executeProcedure(hook->prog.ptr, hook->callback);
|
||||||
|
} else {
|
||||||
|
hook->callback = RunScriptStartProc(&hook->prog); // run start
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall RunHookScript(DWORD hook) {
|
||||||
|
cRet = 0;
|
||||||
|
if (!hooks[hook].empty()) {
|
||||||
|
if (callDepth > 8) {
|
||||||
|
fo::func::debug_printf("\n[SFALL] The hook ID: %d cannot be executed.", hook);
|
||||||
|
dlog_f("The hook %d cannot be executed due to exceeding depth limit\n", DL_MAIN, hook);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentRunHook = hook;
|
||||||
|
size_t hooksCount = hooks[hook].size();
|
||||||
|
dlog_f("Running hook %d, which has %0d entries attached, depth: %d\n", DL_HOOK, hook, hooksCount, callDepth);
|
||||||
|
for (int i = hooksCount - 1; i >= 0; i--) {
|
||||||
|
RunSpecificHookScript(&hooks[hook][i]);
|
||||||
|
|
||||||
|
//devlog_f("> Hook: %d, script entry: %d done\n", DL_HOOK, hook, i);
|
||||||
|
//devlog_f("> Check cArg/cRet: %d / %d(%d)\n", DL_HOOK, cArg, cRet, cRetTmp);
|
||||||
|
//for (unsigned int i = 0; i < maxArgs; i++) {
|
||||||
|
// devlog_f("> Check Args/Rets: %d / %d\n", DL_HOOK, args[i], ((i < maxRets) ? rets[i] : -1));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cArg = 0;
|
||||||
|
|
||||||
|
devlog_f(">>> Try running hook ID: %d\n", DL_HOOK, hook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall EndHook() {
|
||||||
|
devlog_f("End running hook %d, current depth: %d\n", DL_HOOK, currentRunHook, callDepth);
|
||||||
|
|
||||||
|
callDepth--;
|
||||||
|
if (callDepth) {
|
||||||
|
if (callDepth <= maxDepth) {
|
||||||
|
// restore all saved values of the previous hook
|
||||||
|
int cDepth = callDepth - 1;
|
||||||
|
currentRunHook = savedArgs[cDepth].hookID;
|
||||||
|
argCount = savedArgs[cDepth].argCount;
|
||||||
|
cArg = savedArgs[cDepth].cArg;
|
||||||
|
cRet = savedArgs[cDepth].cRet;
|
||||||
|
cRetTmp = savedArgs[cDepth].cRetTmp; // also restore current count of the number of return values
|
||||||
|
std::memcpy(args, &savedArgs[cDepth].oldArgs, maxArgs * sizeof(DWORD));
|
||||||
|
if (cRet) std::memcpy(rets, &savedArgs[cDepth].oldRets, maxRets * sizeof(DWORD));
|
||||||
|
|
||||||
|
//devlog_f("Restored cArgs/cRet: %d / %d(%d)\n", DL_HOOK, argCount, cRet, cRetTmp);
|
||||||
|
//for (unsigned int i = 0; i < maxArgs; i++) {
|
||||||
|
// devlog_f("Restored Args/Rets: %d / %d\n", DL_HOOK, args[i], ((i < maxRets) ? rets[i] : -1));
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
currentRunHook = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BEGIN HOOKS
|
||||||
|
void __stdcall HookCommon::KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey) {
|
||||||
|
if (!IsGameLoaded() || !HookScripts::HookHasScript(HOOK_KEYPRESS)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BeginHook();
|
||||||
|
argCount = 3;
|
||||||
|
args[0] = (DWORD)pressed;
|
||||||
|
args[1] = *dxKey;
|
||||||
|
args[2] = vKey;
|
||||||
|
RunHookScript(HOOK_KEYPRESS);
|
||||||
|
if (cRet != 0) {
|
||||||
|
long retKey = rets[0];
|
||||||
|
if (retKey > 0 && retKey < 264) *dxKey = retKey;
|
||||||
|
}
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __stdcall HookCommon::MouseClickHook(DWORD button, bool pressed) {
|
||||||
|
if (!IsGameLoaded() || !HookScripts::HookHasScript(HOOK_MOUSECLICK)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BeginHook();
|
||||||
|
argCount = 2;
|
||||||
|
args[0] = (DWORD)pressed;
|
||||||
|
args[1] = button;
|
||||||
|
RunHookScript(HOOK_MOUSECLICK);
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long previousGameMode = 0;
|
||||||
|
|
||||||
|
void HookCommon::GameModeChangeHook(DWORD exit) {
|
||||||
|
if (HookScripts::HookHasScript(HOOK_GAMEMODECHANGE)) {
|
||||||
|
BeginHook();
|
||||||
|
argCount = 2;
|
||||||
|
args[0] = exit;
|
||||||
|
args[1] = previousGameMode;
|
||||||
|
RunHookScript(HOOK_GAMEMODECHANGE);
|
||||||
|
EndHook();
|
||||||
|
}
|
||||||
|
previousGameMode = GetLoopFlags();
|
||||||
|
}
|
||||||
|
// END HOOKS
|
||||||
|
|
||||||
|
void HookCommon::Reset() {
|
||||||
|
previousGameMode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "..\HookScripts.h"
|
||||||
|
#include "..\ScriptExtender.h"
|
||||||
|
|
||||||
|
// Common variables and functions for hook script implementations
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
class HookCommon {
|
||||||
|
public:
|
||||||
|
static DWORD GetHSArgCount();
|
||||||
|
static DWORD GetHSArg();
|
||||||
|
static DWORD GetHSArgAt(DWORD id);
|
||||||
|
static DWORD* GetHSArgs();
|
||||||
|
static void SetHSArg(DWORD id, DWORD value);
|
||||||
|
static void __stdcall SetHSReturn(DWORD d);
|
||||||
|
|
||||||
|
static void GameModeChangeHook(DWORD exit);
|
||||||
|
static void __stdcall KeyPressHook(DWORD* dxKey, bool pressed, DWORD vKey);
|
||||||
|
static void __stdcall MouseClickHook(DWORD button, bool pressed);
|
||||||
|
|
||||||
|
static void Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Struct for registered hook script
|
||||||
|
struct HookScript {
|
||||||
|
ScriptProgram prog;
|
||||||
|
int callback; // procedure position in script's proc table
|
||||||
|
bool isGlobalScript; // false for hs_* scripts, true for gl* scripts
|
||||||
|
};
|
||||||
|
|
||||||
|
// All currently registered hook scripts
|
||||||
|
extern std::vector<HookScript> hooks[];
|
||||||
|
|
||||||
|
extern DWORD args[]; // current hook arguments
|
||||||
|
extern DWORD rets[]; // current hook return values
|
||||||
|
|
||||||
|
extern DWORD argCount;
|
||||||
|
extern DWORD cArg; // how many arguments were taken by current hook script
|
||||||
|
extern DWORD cRet; // how many return values were set by current hook script
|
||||||
|
extern DWORD cRetTmp; // how many return values were set by specific hook script (when using register_hook)
|
||||||
|
|
||||||
|
void __stdcall BeginHook();
|
||||||
|
void __stdcall RunHookScript(DWORD hook);
|
||||||
|
void __stdcall EndHook();
|
||||||
|
|
||||||
|
#define HookBegin pushadc __asm call BeginHook popadc
|
||||||
|
#define HookEnd pushadc __asm call EndHook popadc
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
#include "..\..\FalloutEngine\Fallout2.h"
|
||||||
|
#include "..\..\SafeWrite.h"
|
||||||
|
#include "..\HookScripts.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "DeathHs.h"
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
static bool registerHookDeathAnim1 = false;
|
||||||
|
static bool registerHookDeathAnim2 = false;
|
||||||
|
|
||||||
|
static DWORD __fastcall CalcDeathAnimHook_Script(DWORD damage, fo::GameObject* target, fo::GameObject* attacker, fo::GameObject* weapon, int animation, int hitBack) {
|
||||||
|
BeginHook();
|
||||||
|
argCount = 5; // was 4
|
||||||
|
|
||||||
|
args[1] = (DWORD)attacker;
|
||||||
|
args[2] = (DWORD)target;
|
||||||
|
args[3] = damage;
|
||||||
|
|
||||||
|
// weapon_ptr
|
||||||
|
args[0] = (weapon) ? weapon->protoId : -1; // attack is unarmed
|
||||||
|
|
||||||
|
bool createNewObj = false;
|
||||||
|
if (registerHookDeathAnim1) {
|
||||||
|
args[4] = -1; // set 'no anim' for combined hooks use
|
||||||
|
RunHookScript(HOOK_DEATHANIM1);
|
||||||
|
if (cRet > 0) {
|
||||||
|
DWORD pid = rets[0];
|
||||||
|
args[0] = pid; // replace for HOOK_DEATHANIM2
|
||||||
|
fo::GameObject* object = nullptr;
|
||||||
|
if (fo::func::obj_pid_new((fo::GameObject*)&object, pid) != -1) { // create new object
|
||||||
|
createNewObj = true;
|
||||||
|
weapon = object; // replace pointer with newly created weapon object
|
||||||
|
}
|
||||||
|
cRet = 0; // reset rets from HOOK_DEATHANIM1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD animDeath = fo::func::pick_death(attacker, target, weapon, damage, animation, hitBack); // vanilla pick death
|
||||||
|
|
||||||
|
if (registerHookDeathAnim2) {
|
||||||
|
args[4] = animDeath;
|
||||||
|
RunHookScript(HOOK_DEATHANIM2);
|
||||||
|
|
||||||
|
if (cRet > 0) animDeath = rets[0];
|
||||||
|
}
|
||||||
|
EndHook();
|
||||||
|
|
||||||
|
if (createNewObj) fo::func::obj_erase_object(weapon, 0); // delete created object
|
||||||
|
|
||||||
|
return animDeath;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) CalcDeathAnimHook() {
|
||||||
|
__asm {
|
||||||
|
push ecx;
|
||||||
|
push edx;
|
||||||
|
push [esp + 4 + 12]; // hit_from_back
|
||||||
|
push [esp + 4 + 12]; // animation
|
||||||
|
push ebx; // weapon_ptr
|
||||||
|
push eax; // attacker
|
||||||
|
call CalcDeathAnimHook_Script; // ecx - damage, edx - target
|
||||||
|
pop edx;
|
||||||
|
pop ecx;
|
||||||
|
retn 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) CalcDeathAnim2Hook() {
|
||||||
|
__asm {
|
||||||
|
call fo::funcoffs::check_death_; // call original function
|
||||||
|
mov ebx, eax;
|
||||||
|
call BeginHook;
|
||||||
|
mov eax, [esp + 60];
|
||||||
|
mov args[4], eax; // attacker
|
||||||
|
mov args[8], esi; // target
|
||||||
|
mov eax, [esp + 12];
|
||||||
|
mov args[12], eax; // dmgAmount
|
||||||
|
mov args[16], ebx; // calculated animID
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 5;
|
||||||
|
args[0] = -1; // weaponPid
|
||||||
|
RunHookScript(HOOK_DEATHANIM2);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) OnDeathHook() {
|
||||||
|
using namespace fo::Fields;
|
||||||
|
__asm {
|
||||||
|
push edx;
|
||||||
|
call BeginHook;
|
||||||
|
mov args[0], esi;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 1;
|
||||||
|
RunHookScript(HOOK_ONDEATH);
|
||||||
|
EndHook();
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
pop edx;
|
||||||
|
// engine code
|
||||||
|
mov eax, [esi + protoId];
|
||||||
|
mov ebp, ebx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) OnDeathHook2() {
|
||||||
|
__asm {
|
||||||
|
call fo::funcoffs::partyMemberRemove_;
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], esi;
|
||||||
|
pushadc;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 1;
|
||||||
|
RunHookScript(HOOK_ONDEATH);
|
||||||
|
EndHook();
|
||||||
|
|
||||||
|
__asm popadc;
|
||||||
|
__asm retn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_DeathAnim1Hook() {
|
||||||
|
registerHookDeathAnim1 = true;
|
||||||
|
if (!registerHookDeathAnim2) {
|
||||||
|
HookCall(0x4109DE, CalcDeathAnimHook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_DeathAnim2Hook() {
|
||||||
|
const DWORD calcDeathAnim2HkAddr[] = {
|
||||||
|
0x410981, // show_damage_to_object_
|
||||||
|
0x4109A1, // show_damage_to_object_
|
||||||
|
0x4109BF // show_damage_to_object_
|
||||||
|
};
|
||||||
|
HookCalls(CalcDeathAnim2Hook, calcDeathAnim2HkAddr);
|
||||||
|
registerHookDeathAnim2 = true;
|
||||||
|
if (!registerHookDeathAnim1) {
|
||||||
|
HookCall(0x4109DE, CalcDeathAnimHook); // show_damage_to_object_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_OnDeathHook() {
|
||||||
|
MakeCall(0x42DA6D, OnDeathHook); // critter_kill_
|
||||||
|
HookCall(0x425161, OnDeathHook2); // damage_object_
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitDeathHookScripts() {
|
||||||
|
HookScripts::LoadHookScript("hs_deathanim1", HOOK_DEATHANIM1);
|
||||||
|
HookScripts::LoadHookScript("hs_deathanim2", HOOK_DEATHANIM2);
|
||||||
|
HookScripts::LoadHookScript("hs_ondeath", HOOK_ONDEATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Hook scripts related to critter Death
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
void InitDeathHookScripts();
|
||||||
|
|
||||||
|
void Inject_DeathAnim1Hook();
|
||||||
|
void Inject_DeathAnim2Hook();
|
||||||
|
void Inject_OnDeathHook();
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
#include "..\..\FalloutEngine\Fallout2.h"
|
||||||
|
#include "..\..\SafeWrite.h"
|
||||||
|
#include "..\HookScripts.h"
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "HexBlockingHs.h"
|
||||||
|
|
||||||
|
namespace sfall
|
||||||
|
{
|
||||||
|
|
||||||
|
static void __declspec(naked) HexMoveBlockingHook() {
|
||||||
|
static const DWORD _obj_blocking_at = 0x48B84E;
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], eax;
|
||||||
|
mov args[4], edx;
|
||||||
|
mov args[8], ebx;
|
||||||
|
push return;
|
||||||
|
// engine code
|
||||||
|
push ecx;
|
||||||
|
push esi;
|
||||||
|
push edi;
|
||||||
|
push ebp;
|
||||||
|
mov ecx, eax;
|
||||||
|
// end engine code
|
||||||
|
jmp _obj_blocking_at;
|
||||||
|
return:
|
||||||
|
mov args[12], eax;
|
||||||
|
mov ebx, eax;
|
||||||
|
push ecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 4;
|
||||||
|
RunHookScript(HOOK_HEXMOVEBLOCKING);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) HexAIBlockingHook() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], eax;
|
||||||
|
mov args[4], edx;
|
||||||
|
mov args[8], ebx;
|
||||||
|
call fo::funcoffs::obj_ai_blocking_at_;
|
||||||
|
mov args[12], eax;
|
||||||
|
mov ebx, eax;
|
||||||
|
push ecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 4;
|
||||||
|
RunHookScript(HOOK_HEXAIBLOCKING);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) HexShootBlockingHook() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], eax;
|
||||||
|
mov args[4], edx;
|
||||||
|
mov args[8], ebx;
|
||||||
|
call fo::funcoffs::obj_shoot_blocking_at_;
|
||||||
|
mov args[12], eax;
|
||||||
|
mov ebx, eax;
|
||||||
|
push ecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 4;
|
||||||
|
RunHookScript(HOOK_HEXSHOOTBLOCKING);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) HexSightBlockingHook() {
|
||||||
|
__asm {
|
||||||
|
HookBegin;
|
||||||
|
mov args[0], eax;
|
||||||
|
mov args[4], edx;
|
||||||
|
mov args[8], ebx;
|
||||||
|
call fo::funcoffs::obj_sight_blocking_at_;
|
||||||
|
mov args[12], eax;
|
||||||
|
mov ebx, eax;
|
||||||
|
push ecx;
|
||||||
|
}
|
||||||
|
|
||||||
|
argCount = 4;
|
||||||
|
RunHookScript(HOOK_HEXSIGHTBLOCKING);
|
||||||
|
|
||||||
|
__asm {
|
||||||
|
cmp cRet, 1;
|
||||||
|
cmovge ebx, rets[0];
|
||||||
|
call EndHook;
|
||||||
|
mov eax, ebx;
|
||||||
|
pop ecx;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_HexSightBlockHook() {
|
||||||
|
SafeWrite32(0x413979, (DWORD)&HexSightBlockingHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_HexShootBlockHook() {
|
||||||
|
const DWORD shootBlockingAddr[] = {0x4C1A88, 0x423178, 0x4232D4, 0x423B4D, 0x426CF8, 0x42A570};
|
||||||
|
SafeWriteBatch<DWORD>((DWORD)&HexShootBlockingHook, shootBlockingAddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_HexIABlockHook() {
|
||||||
|
SafeWrite32(0x42A0A4, (DWORD)&HexAIBlockingHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Inject_HexMoveBlockHook() {
|
||||||
|
MakeJump(0x48B848, HexMoveBlockingHook);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitHexBlockingHookScripts() {
|
||||||
|
HookScripts::LoadHookScript("hs_hexmoveblocking", HOOK_HEXMOVEBLOCKING);
|
||||||
|
HookScripts::LoadHookScript("hs_hexaiblocking", HOOK_HEXAIBLOCKING);
|
||||||
|
HookScripts::LoadHookScript("hs_hexshootblocking", HOOK_HEXSHOOTBLOCKING);
|
||||||
|
HookScripts::LoadHookScript("hs_hexsightblocking", HOOK_HEXSIGHTBLOCKING);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user