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
|
||||
;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
|
||||
;LocalMapYLimit=400
|
||||
|
||||
@@ -852,6 +852,9 @@ MapGridToggleKey=0
|
||||
;Has pretty nasty side effects when saving/reloading, so don't use for regular gameplay
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
long __fastcall tile_num(long x, long y) {
|
||||
__asm xor ebx, ebx; // don't delete (bug in tile_num_)
|
||||
WRAP_WATCOM_FCALL2(tile_num_, x, y);
|
||||
long __stdcall tile_num(long x, long y) {
|
||||
__asm push ebx; // don't delete (bug in tile_num_)
|
||||
WRAP_WATCOM_CALL2(tile_num_, x, y);
|
||||
__asm pop ebx;
|
||||
}
|
||||
|
||||
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 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);
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
|
||||
#include "..\Modules\HookScripts.h"
|
||||
#include "..\Modules\HookScripts\CombatHs.h"
|
||||
|
||||
#include "items.h"
|
||||
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
|
||||
#include "..\Modules\HeroAppearance.h"
|
||||
#include "..\Modules\HookScripts.h"
|
||||
#include "..\Modules\PartyControl.h"
|
||||
|
||||
#include "..\Modules\HookScripts\InventoryHs.h"
|
||||
|
||||
#include "inventory.h"
|
||||
|
||||
namespace game
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
#include "..\main.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\Unarmed.h"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
|
||||
#include "..\Modules\HookScripts.h"
|
||||
#include "..\Modules\HookScripts\MiscHs.h"
|
||||
|
||||
#include "objects.h"
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace sf = sfall;
|
||||
|
||||
//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());
|
||||
//}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "FalloutEngine\Fallout2.h"
|
||||
#include "Modules\DebugEditor.h"
|
||||
#include "Modules\Graphics.h"
|
||||
#include "Modules\HookScripts.h"
|
||||
#include "Modules\HookScripts\Common.h"
|
||||
#include "Modules\Inventory.h"
|
||||
#include "Modules\ScriptExtender.h"
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
#include "..\Translate.h"
|
||||
|
||||
#include "HookScripts\InventoryHs.h"
|
||||
|
||||
#include "..\Game\objects.h"
|
||||
|
||||
#include "HookScripts.h"
|
||||
#include "LoadGameHook.h"
|
||||
#include "ScriptExtender.h"
|
||||
#include "Worldmap.h"
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
#include "..\SimplePatch.h"
|
||||
#include "..\Translate.h"
|
||||
|
||||
#include "HookScripts.h"
|
||||
#include "Objects.h"
|
||||
|
||||
#include "HookScripts\CombatHS.h"
|
||||
|
||||
#include "Combat.h"
|
||||
|
||||
namespace sfall
|
||||
@@ -193,7 +194,11 @@ long __fastcall Combat::check_item_ammo_cost(fo::GameObject* weapon, fo::AttackT
|
||||
|
||||
DWORD newRounds = rounds;
|
||||
|
||||
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
|
||||
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) {
|
||||
DWORD roundsCost = 1; // default burst cost
|
||||
|
||||
if (HookScripts::IsInjectHook(HOOK_AMMOCOST)) {
|
||||
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)
|
||||
if (cost > currAmmo) cost = currAmmo; // if cost ammo more than current ammo, set it to current
|
||||
|
||||
+86
-1867
File diff suppressed because it is too large
Load Diff
@@ -56,6 +56,12 @@ enum HookType
|
||||
HOOK_COUNT
|
||||
};
|
||||
|
||||
struct HookFile {
|
||||
int id;
|
||||
// std::string filePath;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
class HookScripts {
|
||||
public:
|
||||
static const char* name() { return "HookScripts"; }
|
||||
@@ -70,40 +76,13 @@ public:
|
||||
|
||||
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)
|
||||
static void RegisterHook(fo::Program* script, int id, int procNum, bool specReg);
|
||||
|
||||
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