mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
449 lines
9.6 KiB
C++
449 lines
9.6 KiB
C++
#include "..\..\FalloutEngine\Fallout2.h"
|
|
#include "..\..\SafeWrite.h"
|
|
#include "..\HookScripts.h"
|
|
#include "..\CritterPoison.h"
|
|
#include "Common.h"
|
|
|
|
#include "ObjectHs.h"
|
|
|
|
// Object hook scripts
|
|
namespace sfall
|
|
{
|
|
|
|
static long UseObjOnHook_Script(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target) {
|
|
BeginHook();
|
|
argCount = 3;
|
|
|
|
args[0] = (DWORD)target; // target
|
|
args[1] = (DWORD)source; // user
|
|
args[2] = (DWORD)item; // item
|
|
|
|
RunHookScript(HOOK_USEOBJON);
|
|
|
|
long result = (cRet > 0) ? rets[0] : -1;
|
|
EndHook();
|
|
|
|
return result; // -1 - default handler
|
|
}
|
|
|
|
long UseObjOnHook_Invoke(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target) {
|
|
if (!HookScripts::HookHasScript(HOOK_USEOBJON)) return -1;
|
|
return UseObjOnHook_Script(source, item, target);
|
|
}
|
|
|
|
static void __declspec(naked) UseObjOnHook() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[0], edx; // target
|
|
mov args[4], eax; // user
|
|
mov args[8], ebx; // object
|
|
pushadc;
|
|
}
|
|
|
|
argCount = 3;
|
|
RunHookScript(HOOK_USEOBJON);
|
|
|
|
__asm {
|
|
popadc;
|
|
cmp cRet, 1;
|
|
jl defaultHandler;
|
|
cmp rets[0], -1;
|
|
je defaultHandler;
|
|
mov eax, rets[0];
|
|
HookEnd;
|
|
retn;
|
|
defaultHandler:
|
|
HookEnd;
|
|
jmp fo::funcoffs::protinst_use_item_on_;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) Drug_UseObjOnHook() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[0], eax; // target
|
|
mov args[4], eax; // user
|
|
mov args[8], edx; // object
|
|
pushadc;
|
|
}
|
|
|
|
argCount = 3;
|
|
RunHookScript(HOOK_USEOBJON);
|
|
|
|
__asm {
|
|
popadc;
|
|
cmp cRet, 1;
|
|
jl defaultHandler;
|
|
cmp rets[0], -1;
|
|
je defaultHandler;
|
|
mov eax, rets[0];
|
|
HookEnd;
|
|
retn;
|
|
defaultHandler:
|
|
HookEnd;
|
|
jmp fo::funcoffs::item_d_take_drug_;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) UseObjHook() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[0], eax; // user
|
|
mov args[4], edx; // object
|
|
pushadc;
|
|
}
|
|
|
|
argCount = 2;
|
|
RunHookScript(HOOK_USEOBJ);
|
|
|
|
__asm {
|
|
popadc;
|
|
cmp cRet, 1;
|
|
jl defaultHandler;
|
|
cmp rets[0], -1;
|
|
je defaultHandler;
|
|
mov eax, rets[0];
|
|
HookEnd;
|
|
retn;
|
|
defaultHandler:
|
|
HookEnd;
|
|
jmp fo::funcoffs::protinst_use_item_;
|
|
}
|
|
}
|
|
|
|
static DWORD __fastcall UseAnimateObjHook_Script(DWORD critter, DWORD animCode, DWORD object) {
|
|
BeginHook();
|
|
argCount = 3;
|
|
|
|
args[0] = critter;
|
|
args[1] = object;
|
|
args[2] = animCode;
|
|
|
|
RunHookScript(HOOK_USEANIMOBJ);
|
|
|
|
if (cRet > 0 && static_cast<long>(rets[0]) <= 64) {
|
|
animCode = rets[0]; // new anim code
|
|
}
|
|
EndHook();
|
|
|
|
return animCode;
|
|
}
|
|
|
|
// Before animation of using map object
|
|
static void __declspec(naked) UseAnimateObjHook() {
|
|
__asm {
|
|
cmp dword ptr [esp], 0x412292 + 5;
|
|
push eax;
|
|
push ecx;
|
|
jne contr;
|
|
push ebp; // map object
|
|
jmp next;
|
|
contr:
|
|
push edi; // map object
|
|
next:
|
|
mov ecx, eax; // source critter
|
|
call UseAnimateObjHook_Script; // edx - anim code
|
|
pop ecx;
|
|
cmp eax, -1; // return anim code
|
|
jle end; // goto no animate
|
|
mov edx, eax; // restore vanilla or hook anim code
|
|
pop eax;
|
|
jmp fo::funcoffs::register_object_animate_;
|
|
end:
|
|
pop eax;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static DWORD __fastcall DescriptionObjHook_Script(DWORD object) {
|
|
BeginHook();
|
|
argCount = 1;
|
|
|
|
args[0] = object;
|
|
|
|
RunHookScript(HOOK_DESCRIPTIONOBJ);
|
|
|
|
DWORD textPrt = (cRet > 0) ? rets[0] : 0;
|
|
EndHook();
|
|
|
|
return textPrt;
|
|
}
|
|
|
|
static void __declspec(naked) DescriptionObjHook() {
|
|
__asm {
|
|
push ecx;
|
|
push edx;
|
|
mov ecx, eax; // object
|
|
call DescriptionObjHook_Script;
|
|
pop edx;
|
|
pop ecx;
|
|
test eax, eax; // pointer to text
|
|
jnz skip;
|
|
mov eax, ebp;
|
|
jmp fo::funcoffs::object_description_;
|
|
skip:
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static bool __fastcall SetLightingHook_Script(DWORD &intensity, DWORD &radius, DWORD object) {
|
|
BeginHook();
|
|
argCount = 3;
|
|
|
|
args[0] = object;
|
|
args[1] = intensity;
|
|
args[2] = radius;
|
|
RunHookScript(HOOK_SETLIGHTING);
|
|
|
|
bool result = false;
|
|
if (cRet > 0) {
|
|
int light = rets[0];
|
|
if (light < 0) light = 0;
|
|
intensity = light;
|
|
if (cRet > 1 && object != -1) {
|
|
int dist = rets[1];
|
|
if (dist < 0) dist = 0;
|
|
radius = dist;
|
|
}
|
|
result = true;
|
|
}
|
|
EndHook();
|
|
return result;
|
|
}
|
|
|
|
static void __declspec(naked) SetObjectLightHook() {
|
|
__asm {
|
|
pushadc;
|
|
push ebp;
|
|
mov edx, esp; // &radius
|
|
push ebx;
|
|
mov ecx, esp; // &intensity
|
|
push esi; // object
|
|
call SetLightingHook_Script;
|
|
test al, al;
|
|
jz skip;
|
|
pop ebx; // return intensity value
|
|
pop ebp; // return radius value
|
|
jmp end;
|
|
skip:
|
|
add esp, 8;
|
|
end:
|
|
popadc;
|
|
jmp fo::funcoffs::obj_turn_off_light_;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) SetMapLightHook() {
|
|
__asm {
|
|
push ecx;
|
|
push ebx;
|
|
mov ecx, esp; // &intensity
|
|
push -1; // no object (it's a map)
|
|
mov edx, esp; // no radius
|
|
call SetLightingHook_Script;
|
|
add esp, 4;
|
|
test al, al;
|
|
jz skip;
|
|
mov ebx, [esp - 4]; // return intensity value
|
|
skip:
|
|
pop ecx;
|
|
cmp ebx, dword ptr ds:[0x47A93D]; // get miminal ambient light intensity (16384)
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static DWORD __fastcall StdProcedureHook_Script(long numHandler, fo::ScriptInstance* script, DWORD procTable) {
|
|
BeginHook();
|
|
argCount = 6;
|
|
|
|
args[0] = numHandler;
|
|
args[1] = (DWORD)script->selfObject;
|
|
args[2] = (DWORD)script->sourceObject;
|
|
args[4] = (DWORD)script->targetObject;
|
|
args[5] = script->fixedParam;
|
|
|
|
if (procTable) {
|
|
args[3] = 0;
|
|
RunHookScript(HOOK_STDPROCEDURE);
|
|
|
|
if (cRet > 0) {
|
|
long retval = rets[0];
|
|
if (retval == -1) procTable = retval;
|
|
}
|
|
} else {
|
|
args[3] = 1;
|
|
RunHookScript(HOOK_STDPROCEDURE_END);
|
|
}
|
|
EndHook();
|
|
return procTable;
|
|
}
|
|
|
|
static void __declspec(naked) ScriptStdProcedureHook() {
|
|
using namespace fo::Scripts;
|
|
__asm {
|
|
mov eax, [eax + 0x54]; // Script.procedure_table
|
|
test eax, eax;
|
|
jle end;
|
|
cmp ecx, critter_p_proc;
|
|
je skip;
|
|
cmp ecx, timed_event_p_proc;
|
|
je skip;
|
|
cmp ecx, map_update_p_proc;
|
|
je skip;
|
|
cmp ecx, start;
|
|
jle skip;
|
|
push ecx;
|
|
push eax; // procTable
|
|
mov edx, esi; // script
|
|
call StdProcedureHook_Script; // ecx - numHandler
|
|
pop ecx;
|
|
skip:
|
|
test eax, eax;
|
|
end:
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) After_ScriptStdProcedureHook() {
|
|
using namespace fo::Scripts;
|
|
__asm {
|
|
call fo::funcoffs::executeProcedure_;
|
|
cmp ecx, critter_p_proc;
|
|
je skip;
|
|
cmp ecx, timed_event_p_proc;
|
|
je skip;
|
|
cmp ecx, map_update_p_proc;
|
|
je skip;
|
|
cmp ecx, start;
|
|
jle skip;
|
|
mov edx, [esp + 0x28 - 0x18 + 4]; // script
|
|
push 0; // procTable
|
|
call StdProcedureHook_Script; // ecx - numHandler
|
|
skip:
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static DWORD __fastcall AdjustPoison_Script(DWORD critter, long amount, DWORD addr) {
|
|
BeginHook();
|
|
argCount = 3;
|
|
|
|
bool checkPoison = (addr == (0x42D32C + 5)); // from critter_check_poison_
|
|
|
|
args[0] = critter;
|
|
args[1] = amount;
|
|
args[2] = (checkPoison) ? CritterPoison::adjustPoisonHP_Default : 0;
|
|
|
|
RunHookScript(HOOK_ADJUSTPOISON);
|
|
|
|
if (cRet > 0) amount = rets[0];
|
|
if (cRet > 1 && checkPoison && (long)rets[1] < 0) CritterPoison::adjustPoisonHP = rets[1];
|
|
|
|
EndHook();
|
|
return amount;
|
|
}
|
|
|
|
static void __declspec(naked) critter_adjust_poison_hack() {
|
|
__asm {
|
|
push [esp + 0x24 + 4]; // called from
|
|
mov ecx, eax; // critter
|
|
call AdjustPoison_Script; // edx - amount
|
|
mov esi, eax; // old/new amount
|
|
mov eax, edi; // restore eax value
|
|
jmp critter_adjust_poison_hack_fix; // in CritterPoison
|
|
}
|
|
}
|
|
|
|
static DWORD __fastcall AdjustRads_Script(DWORD critter, long amount) {
|
|
if (!HookScripts::HookHasScript(HOOK_ADJUSTRADS)) return amount;
|
|
|
|
BeginHook();
|
|
argCount = 2;
|
|
|
|
args[0] = critter; // always dude
|
|
args[1] = amount;
|
|
|
|
RunHookScript(HOOK_ADJUSTRADS);
|
|
if (cRet) amount = rets[0];
|
|
|
|
EndHook();
|
|
return amount;
|
|
}
|
|
|
|
void __declspec(naked) critter_adjust_rads_hack() {
|
|
using namespace fo;
|
|
using namespace Fields;
|
|
__asm {
|
|
cmp dword ptr [eax + protoId], PID_Player; // critter.pid
|
|
jne isNotDude;
|
|
push ecx;
|
|
call AdjustRads_Script; // ecx - critter, edx - amount
|
|
pop ecx;
|
|
mov ebx, eax; // old/new amount
|
|
mov edx, ds:[FO_VAR_obj_dude];
|
|
xor eax, eax; // for continue func
|
|
isNotDude:
|
|
retn;
|
|
}
|
|
}
|
|
|
|
void Inject_UseObjOnHook() {
|
|
HookCalls(UseObjOnHook, { 0x49C606, 0x473619 });
|
|
|
|
// the following hooks allows to catch drug use of AI and from action cursor
|
|
HookCalls(Drug_UseObjOnHook, {
|
|
//0x4285DF, // ai_check_drugs
|
|
//0x4286F8, // ai_check_drugs
|
|
//0x4287F8, // ai_check_drugs
|
|
0x473573 // inven_action_cursor
|
|
});
|
|
}
|
|
|
|
void Inject_UseObjHook() {
|
|
HookCalls(UseObjHook, { 0x42AEBF, 0x473607, 0x49C12E });
|
|
}
|
|
|
|
void Inject_UseAnimateObjHook() {
|
|
HookCalls(UseAnimateObjHook, { 0x4120C1, 0x412292 });
|
|
}
|
|
|
|
void Inject_DescriptionObjHook() {
|
|
HookCall(0x49AE28, DescriptionObjHook);
|
|
}
|
|
|
|
void Inject_SetLightingHook() {
|
|
HookCall(0x48ACA0, SetObjectLightHook);
|
|
MakeCall(0x47A934, SetMapLightHook, 1);
|
|
}
|
|
|
|
void Inject_ScriptProcedureHook() {
|
|
MakeCall(0x4A491F, ScriptStdProcedureHook);
|
|
}
|
|
|
|
void Inject_ScriptProcedureHook2() {
|
|
HookCall(0x4A49A7, After_ScriptStdProcedureHook);
|
|
}
|
|
|
|
void Inject_AdjustPoisonHook() {
|
|
MakeCall(0x42D21C, critter_adjust_poison_hack, 1);
|
|
}
|
|
|
|
void Inject_AdjustRadsHook() {
|
|
MakeCall(0x42D3B0, critter_adjust_rads_hack, 1);
|
|
SafeWrite16(0x42D3B6, 0xC085); // test eax, eax
|
|
}
|
|
|
|
void InitObjectHookScripts() {
|
|
HookScripts::LoadHookScript("hs_useobjon", HOOK_USEOBJON);
|
|
HookScripts::LoadHookScript("hs_useobj", HOOK_USEOBJ);
|
|
HookScripts::LoadHookScript("hs_useanimobj", HOOK_USEANIMOBJ);
|
|
HookScripts::LoadHookScript("hs_descriptionobj", HOOK_DESCRIPTIONOBJ);
|
|
HookScripts::LoadHookScript("hs_setlighting", HOOK_SETLIGHTING);
|
|
HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE); // combo hook
|
|
HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE_END);
|
|
HookScripts::LoadHookScript("hs_adjustpoison", HOOK_ADJUSTPOISON);
|
|
HookScripts::LoadHookScript("hs_adjustrads", HOOK_ADJUSTRADS);
|
|
}
|
|
|
|
}
|