Backported 5 game hooks from 4.1/4.2:

* SNEAK, STDPROCEDURE, STDPROCEDURE_END, TARGETOBJECT, ENCOUNTER.

Updated documents and example mods.
This commit is contained in:
NovaRain
2022-11-29 14:27:10 +08:00
parent 7ecdfe362f
commit bb13e3f219
15 changed files with 422 additions and 2 deletions
+46
View File
@@ -0,0 +1,46 @@
/*
Example implementation of the algorithm of how the game engine checks the Sneak skill
*/
#include "..\headers\define.h"
#include "..\headers\command.h"
#include "..\headers\sfall\sfall.h"
procedure start;
procedure start begin
if game_loaded then begin
register_hook(HOOK_SNEAK);
end else begin
variable sneakIsSuccess, time, level;
level := critter_skill_level(dude_obj, SKILL_SNEAK);
if (roll_vs_skill(dude_obj, SKILL_SNEAK, 0) < ROLL_SUCCESS) then begin
sneakIsSuccess := false;
time := ONE_GAME_MINUTE;
if (level <= 250) then
if (level <= 200) then
if (level <= 170) then
if (level <= 135) then
if (level <= 100) then
if (level > 80) then
time := 400; // 40 secs
else
time := 300; // 30 secs
else
time := 200; // 20 secs
else
time := 150; // 15 secs
else
time := 120; // 12 secs
else
time := 100; // 10 secs for skill level > 250
end
else begin
sneakIsSuccess := true;
time := ONE_GAME_MINUTE;
end
set_sfall_return(sneakIsSuccess);
set_sfall_return(time);
end
end
+6
View File
@@ -60,6 +60,11 @@
#define HOOK_USEANIMOBJ (32) #define HOOK_USEANIMOBJ (32)
#define HOOK_EXPLOSIVETIMER (33) #define HOOK_EXPLOSIVETIMER (33)
#define HOOK_DESCRIPTIONOBJ (34) #define HOOK_DESCRIPTIONOBJ (34)
#define HOOK_SNEAK (39)
#define HOOK_STDPROCEDURE (40)
#define HOOK_STDPROCEDURE_END (41)
#define HOOK_TARGETOBJECT (42)
#define HOOK_ENCOUNTER (43)
// Valid arguments to list_begin // Valid arguments to list_begin
#define LIST_CRITTERS (0) #define LIST_CRITTERS (0)
@@ -321,6 +326,7 @@
#define get_npc_stat_max(stat) sfall_func2("get_stat_max", stat, 1) #define get_npc_stat_max(stat) sfall_func2("get_stat_max", stat, 1)
#define get_npc_stat_min(stat) sfall_func2("get_stat_min", stat, 1) #define get_npc_stat_min(stat) sfall_func2("get_stat_min", stat, 1)
#define get_sfall_arg_at(argNum) sfall_func1("get_sfall_arg_at", argNum) #define get_sfall_arg_at(argNum) sfall_func1("get_sfall_arg_at", argNum)
#define get_string_pointer(text) sfall_func1("get_string_pointer", text)
#define get_terrain_name(x, y) sfall_func2("get_terrain_name", x, y) #define get_terrain_name(x, y) sfall_func2("get_terrain_name", x, y)
#define get_text_width(text) sfall_func1("get_text_width", text) #define get_text_width(text) sfall_func1("get_text_width", text)
#define hide_win sfall_func0("hide_window") #define hide_win sfall_func0("hide_window")
+64
View File
@@ -676,3 +676,67 @@ Obj arg0 - the object
int ret0 - a pointer to the new text received by using the get_string_pointer function int ret0 - a pointer to the new text received by using the get_string_pointer function
``` ```
-------------------------------------------
#### `HOOK_SNEAK (hs_sneak.int)`
Runs when the Sneak skill is activated, or when the game rolls another Sneak check after the duration for the current one is over.\
You can override the result of a random Sneak check or the duration time for the current result.
```
int arg0 - Sneak check result: 1 - success, 0 - failure
int arg1 - the duration in ticks for the current Sneak check (time depends on Sneak skill level)
Critter arg2 - the critter (usually dude_obj)
int ret0 - overrides the result of the Sneak check
int ret1 - overrides the duration time for the current result
```
-------------------------------------------
#### `HOOK_STDPROCEDURE, HOOK_STDPROCEDURE_END (hs_stdprocedure.int)`
Runs before or after Fallout engine executes a standard procedure (handler) in any script of any object.
__NOTE:__ This hook will not be executed for `start`, `critter_p_proc`, `timed_event_p_proc`, and `map_update_p_proc` procedures.
```
int arg0 - the number of the standard script handler (see define.h)
Obj arg1 - the object that owns this handler (self_obj)
Obj arg2 - the object that called this handler (source_obj, can be 0)
int arg3 - 1 after procedure execution (for HOOK_STDPROCEDURE_END), 0 otherwise
int ret0 - pass -1 to cancel the execution of the handler (only for HOOK_STDPROCEDURE)
```
-------------------------------------------
#### `HOOK_TARGETOBJECT (hs_targetobject.int)`
Runs when the targeting cursor hovers over an object, or when the player tries to attack the target object.\
You can override the target object or prevent the player from attacking the chosen target.
```
int arg0 - event type: 0 - when the targeting cursor hovers over the object, 1 - when trying to attack the target object
int arg1 - 1 when the target object is valid to attack, 0 otherwise
Obj arg2 - the target object
mixed ret0 - overrides the target object, or pass -1 to prevent the player from attacking the object
```
-------------------------------------------
#### `HOOK_ENCOUNTER (hs_encounter.int)`
Runs whenever a random encounter occurs (except the Horrigan meeting and scripted encounters), or when the player enters a local map from the world map.\
You can override the map for loading or the encounter.
```
int arg0 - event type: 0 - when a random encounter occurs, 1 - when the player enters from the world map
int arg1 - the map ID that the encounter will load (see MAPS.h or Maps.txt)
int arg2 - 1 when the encounter occurs is a special encounter, 0 otherwise
int ret0 - overrides the map ID, or pass -1 for event type 0 to cancel the encounter and continue traveling
int ret1 - pass 1 to cancel the encounter and load the specified map from the ret0 (only for event type 0)
```
@@ -539,7 +539,11 @@ FUNC(obj_shoot_blocking_at_, 0x48B930)
FUNC(obj_sight_blocking_at_, 0x48BB88) FUNC(obj_sight_blocking_at_, 0x48BB88)
FUNC(obj_top_environment_, 0x48B304) FUNC(obj_top_environment_, 0x48B304)
FUNC(obj_turn_off_, 0x48AE68) // int aObj<eax>, int ???<edx> FUNC(obj_turn_off_, 0x48AE68) // int aObj<eax>, int ???<edx>
FUNC(obj_turn_off_light_, 0x48AD9C)
FUNC(obj_turn_off_outline_, 0x48AF00)
FUNC(obj_turn_on_, 0x48ADF0) FUNC(obj_turn_on_, 0x48ADF0)
FUNC(obj_turn_on_light_, 0x48AD48)
FUNC(obj_turn_on_outline_, 0x48AEE4)
FUNC(obj_unjam_lock_, 0x49D480) FUNC(obj_unjam_lock_, 0x49D480)
FUNC(obj_use_book_, 0x49B9F0) FUNC(obj_use_book_, 0x49B9F0)
FUNC(obj_use_power_on_car_, 0x49BDE8) FUNC(obj_use_power_on_car_, 0x49BDE8)
+3
View File
@@ -81,6 +81,7 @@
#define FO_VAR_edit_win 0x57060C #define FO_VAR_edit_win 0x57060C
#define FO_VAR_Educated 0x57082C #define FO_VAR_Educated 0x57082C
#define FO_VAR_elevation 0x631D2C #define FO_VAR_elevation 0x631D2C
#define FO_VAR_EncounterMapID 0x672E4C
#define FO_VAR_endgame_subtitle_done 0x570BD0 #define FO_VAR_endgame_subtitle_done 0x570BD0
#define FO_VAR_endgame_subtitle_characters 0x51866C #define FO_VAR_endgame_subtitle_characters 0x51866C
#define FO_VAR_endgame_voiceover_loaded 0x570AB8 #define FO_VAR_endgame_voiceover_loaded 0x570AB8
@@ -206,6 +207,8 @@
#define FO_VAR_obj_seen 0x662445 #define FO_VAR_obj_seen 0x662445
#define FO_VAR_objectTable 0x639DA0 #define FO_VAR_objectTable 0x639DA0
#define FO_VAR_objItemOutlineState 0x519798 #define FO_VAR_objItemOutlineState 0x519798
#define FO_VAR_old_world_xpos 0x672E5C
#define FO_VAR_old_world_ypos 0x672E60
#define FO_VAR_optionRect 0x58ECC0 #define FO_VAR_optionRect 0x58ECC0
#define FO_VAR_optionsButtonDown 0x59D400 #define FO_VAR_optionsButtonDown 0x59D400
#define FO_VAR_optionsButtonDown1 0x570518 #define FO_VAR_optionsButtonDown1 0x570518
+9
View File
@@ -97,6 +97,15 @@ static HooksInjectInfo injectHooks[] = {
{HOOK_USEANIMOBJ, Inject_UseAnimateObjHook, false}, {HOOK_USEANIMOBJ, Inject_UseAnimateObjHook, false},
{HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false}, {HOOK_EXPLOSIVETIMER, Inject_ExplosiveTimerHook, false},
{HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false}, {HOOK_DESCRIPTIONOBJ, Inject_DescriptionObjHook, false},
{-1, nullptr, false}, // dummy
{-1, nullptr, false}, // dummy
{-1, nullptr, false}, // dummy
{-1, nullptr, false}, // dummy
{HOOK_SNEAK, Inject_SneakCheckHook, false},
{HOOK_STDPROCEDURE, Inject_ScriptProcedureHook, false},
{HOOK_STDPROCEDURE_END, Inject_ScriptProcedureHook2, false},
{HOOK_TARGETOBJECT, Inject_TargetObjectHook, false},
{HOOK_ENCOUNTER, Inject_EncounterHook, false},
}; };
void HookScripts::InjectingHook(int hookId) { void HookScripts::InjectingHook(int hookId) {
+5
View File
@@ -60,6 +60,11 @@ enum HookType
HOOK_USEANIMOBJ = 32, HOOK_USEANIMOBJ = 32,
HOOK_EXPLOSIVETIMER = 33, HOOK_EXPLOSIVETIMER = 33,
HOOK_DESCRIPTIONOBJ = 34, HOOK_DESCRIPTIONOBJ = 34,
HOOK_SNEAK = 39,
HOOK_STDPROCEDURE = 40,
HOOK_STDPROCEDURE_END = 41,
HOOK_TARGETOBJECT = 42,
HOOK_ENCOUNTER = 43,
HOOK_COUNT HOOK_COUNT
}; };
+69
View File
@@ -317,6 +317,66 @@ skip:
} }
} }
static DWORD targetRet = 0;
static bool targetObjHookHasRet = false;
static long __fastcall TargetObjectHook(DWORD isValid, DWORD object, long type) {
if (isValid > 1) isValid = 1;
BeginHook();
argCount = 3;
args[0] = type; // 0 - mouse hovering over target, 1 - mouse clicking on target
args[1] = isValid; // 1 - target is valid
args[2] = object; // target object
if (isValid == 0) object = 0; // it is necessary for the proper operation of the engine code
if (type == 0) targetRet = 0; // unset ret from the previous execution of the hook
RunHookScript(HOOK_TARGETOBJECT);
if (cRet > 0) {
targetRet = (rets[0] != 0) ? rets[0] : object; // 0 - default object, -1 - invalid target, or object override
object = (targetRet != -1) ? targetRet : 0; // object can't be -1
targetObjHookHasRet = true;
} else if (targetObjHookHasRet && type == 1) {
targetObjHookHasRet = false;
if (targetRet != -1) object = targetRet;
}
EndHook();
return object; // null or object
}
static void __declspec(naked) gmouse_bk_process_hook() {
__asm {
push 0; // type
mov ecx, eax; // 1 - valid(object) or 0 - invalid
mov edx, edi; // object under mouse
call TargetObjectHook;
mov edi, eax;
retn;
}
}
static void __declspec(naked) gmouse_handle_event_hook() {
__asm {
push 1; // type
mov ecx, eax; // 1 - valid(object) or 0 - invalid
cmp dword ptr ds:[targetRet], 0;
je default;
// override
mov ecx, 1;
xor eax, eax;
cmp dword ptr ds:[targetRet], -1;
cmove ecx, eax; // if true - set invalid
cmovne edx, targetRet; // if false - set override object
default:
call TargetObjectHook;
mov edx, eax;
retn;
}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void Inject_ToHitHook() { void Inject_ToHitHook() {
@@ -381,6 +441,14 @@ void Inject_AmmoCostHook() {
HookCall(0x423A7C, AmmoCostHook); // compute_attack_ HookCall(0x423A7C, AmmoCostHook); // compute_attack_
} }
void Inject_TargetObjectHook() {
MakeCall(0x44BB16, gmouse_bk_process_hook, 1);
SafeWrite8(0x44BB00, 0x15);
MakeCall(0x44C286, gmouse_handle_event_hook, 1);
SafeWrite8(0x44C26E, 0x17);
}
void InitCombatHookScripts() { void InitCombatHookScripts() {
HookScripts::LoadHookScript("hs_tohit", HOOK_TOHIT); HookScripts::LoadHookScript("hs_tohit", HOOK_TOHIT);
HookScripts::LoadHookScript("hs_afterhitroll", HOOK_AFTERHITROLL); HookScripts::LoadHookScript("hs_afterhitroll", HOOK_AFTERHITROLL);
@@ -389,6 +457,7 @@ void InitCombatHookScripts() {
HookScripts::LoadHookScript("hs_findtarget", HOOK_FINDTARGET); HookScripts::LoadHookScript("hs_findtarget", HOOK_FINDTARGET);
HookScripts::LoadHookScript("hs_itemdamage", HOOK_ITEMDAMAGE); HookScripts::LoadHookScript("hs_itemdamage", HOOK_ITEMDAMAGE);
HookScripts::LoadHookScript("hs_ammocost", HOOK_AMMOCOST); HookScripts::LoadHookScript("hs_ammocost", HOOK_AMMOCOST);
HookScripts::LoadHookScript("hs_targetobject", HOOK_TARGETOBJECT);
} }
} }
+1
View File
@@ -14,6 +14,7 @@ void Inject_CombatDamageHook();
void Inject_FindTargetHook(); void Inject_FindTargetHook();
void Inject_ItemDamageHook(); void Inject_ItemDamageHook();
void Inject_AmmoCostHook(); void Inject_AmmoCostHook();
void Inject_TargetObjectHook();
int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds); int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds);
+129
View File
@@ -150,6 +150,32 @@ defaultHandler:
} }
} }
static void __declspec(naked) SneakCheckHook() {
__asm {
HookBegin;
mov esi, ds:[FO_VAR_sneak_working];
mov args[0], esi; // 1 = successful sneak
mov args[4], eax; // timer
mov args[8], edx; // critter
pushadc;
}
argCount = 3;
RunHookScript(HOOK_SNEAK);
__asm {
popadc;
cmp cRet, 1;
jb skip;
mov esi, rets[0];
mov ds:[FO_VAR_sneak_working], esi;
cmova eax, rets[4]; // override timer
skip:
HookEnd;
jmp fo::funcoffs::queue_add_;
}
}
static __forceinline long PerceptionRangeHook_Script(fo::GameObject* watcher, fo::GameObject* target, int type, long result) { static __forceinline long PerceptionRangeHook_Script(fo::GameObject* watcher, fo::GameObject* target, int type, long result) {
BeginHook(); BeginHook();
argCount = 4; argCount = 4;
@@ -433,6 +459,98 @@ end:
} }
} }
// Hook does not work for scripted encounters and meeting Horrigan
static long __fastcall EncounterHook_Script(long encounterMapID, long eventType, long encType) {
BeginHook();
argCount = 3;
args[0] = eventType; // 1 - enter local map from the world map
args[1] = encounterMapID;
args[2] = (encType == 3); // 1 - special random encounter
RunHookScript(HOOK_ENCOUNTER);
if (cRet) {
encounterMapID = rets[0];
if (encounterMapID < -1) encounterMapID = -1;
if (eventType == 0 && cRet > 1 && encounterMapID != -1 && rets[1] == 1) { // 1 - cancel the encounter and load the specified map
encounterMapID = -encounterMapID - 2; // map number in negative value
}
if (encounterMapID < 0) {
// set the coordinates of the last encounter
fo::var::setInt(FO_VAR_old_world_xpos) = *fo::ptr::world_xpos;
fo::var::setInt(FO_VAR_old_world_ypos) = *fo::ptr::world_ypos;
}
}
EndHook();
return encounterMapID;
}
static void __declspec(naked) wmWorldMap_hook() {
__asm {
mov ebx, eax; // keep map id
mov edx, 1;
mov ecx, eax;
push 0;
call EncounterHook_Script;
test eax, eax;
cmovl eax, ebx; // restore map if map < 0
jmp fo::funcoffs::map_load_idx_; // eax - map id
}
}
static void __declspec(naked) wmRndEncounterOccurred_hook() {
static long hkEncounterMapID = -1;
__asm {
cmp hkEncounterMapID, -1;
jnz blinkIcon;
test edx, edx;
jz hookRun;
jmp fo::funcoffs::wmInterfaceRefresh_;
hookRun: /////////////////////////////////
push edx;
push ecx;
push ecx; // encType
xor edx, edx;
mov ecx, dword ptr ds:[FO_VAR_EncounterMapID];
call EncounterHook_Script;
pop ecx;
pop edx;
mov dword ptr ds:[FO_VAR_EncounterMapID], eax;
cmp eax, -1;
je cancelEnc;
jl clearEnc;
jmp fo::funcoffs::wmInterfaceRefresh_;
clearEnc: /////////////////////////////////
mov dword ptr ds:[FO_VAR_EncounterMapID], -1;
neg eax;
sub eax, 2; // recover correct map number from negative value
mov hkEncounterMapID, eax;
dec edx;
blinkIcon:
cmp edx, 6; // counter of blinking
jge break;
jmp fo::funcoffs::wmInterfaceRefresh_;
break:
mov eax, hkEncounterMapID;
cmp dword ptr ds:[FO_VAR_Move_on_Car], 0;
je noCar;
mov edx, FO_VAR_carCurrentArea;
call fo::funcoffs::wmMatchAreaContainingMapIdx_;
mov eax, hkEncounterMapID;
noCar:
call fo::funcoffs::map_load_idx_;
xor eax, eax;
mov hkEncounterMapID, -1;
cancelEnc:
inc eax; // 0 - continue movement, 1 - interrupt
mov dword ptr ds:[FO_VAR_wmEncounterIconShow], 0;
add esp, 4;
mov ebx, 0x4C0BC7;
jmp ebx;
}
}
void Inject_BarterPriceHook() { void Inject_BarterPriceHook() {
const DWORD barterPriceHkAddr[] = { const DWORD barterPriceHkAddr[] = {
0x474D4C, // barter_attempt_transaction_ (offers button) 0x474D4C, // barter_attempt_transaction_ (offers button)
@@ -455,6 +573,10 @@ void Inject_StealCheckHook() {
HookCalls(StealCheckHook, stealCheckHkAddr); HookCalls(StealCheckHook, stealCheckHkAddr);
} }
void Inject_SneakCheckHook() {
HookCall(0x42E3D9, SneakCheckHook);
}
void Inject_WithinPerceptionHook() { void Inject_WithinPerceptionHook() {
const DWORD perceptionRngHkAddr[] = { const DWORD perceptionRngHkAddr[] = {
0x42B4ED, 0x42B4ED,
@@ -488,15 +610,22 @@ void Inject_ExplosiveTimerHook() {
HookCall(0x49BDC4, ExplosiveTimerHook); HookCall(0x49BDC4, ExplosiveTimerHook);
} }
void Inject_EncounterHook() {
HookCall(0x4C02AF, wmWorldMap_hook);
HookCall(0x4C095C, wmRndEncounterOccurred_hook);
}
void InitMiscHookScripts() { void InitMiscHookScripts() {
HookScripts::LoadHookScript("hs_barterprice", HOOK_BARTERPRICE); HookScripts::LoadHookScript("hs_barterprice", HOOK_BARTERPRICE);
HookScripts::LoadHookScript("hs_useskill", HOOK_USESKILL); HookScripts::LoadHookScript("hs_useskill", HOOK_USESKILL);
HookScripts::LoadHookScript("hs_steal", HOOK_STEAL); HookScripts::LoadHookScript("hs_steal", HOOK_STEAL);
HookScripts::LoadHookScript("hs_sneak", HOOK_SNEAK);
HookScripts::LoadHookScript("hs_withinperception", HOOK_WITHINPERCEPTION); HookScripts::LoadHookScript("hs_withinperception", HOOK_WITHINPERCEPTION);
HookScripts::LoadHookScript("hs_cartravel", HOOK_CARTRAVEL); HookScripts::LoadHookScript("hs_cartravel", HOOK_CARTRAVEL);
HookScripts::LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR); HookScripts::LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR);
HookScripts::LoadHookScript("hs_resttimer", HOOK_RESTTIMER); HookScripts::LoadHookScript("hs_resttimer", HOOK_RESTTIMER);
HookScripts::LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER); HookScripts::LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER);
HookScripts::LoadHookScript("hs_encounter", HOOK_ENCOUNTER);
} }
} }
+2
View File
@@ -8,11 +8,13 @@ void InitMiscHookScripts();
void Inject_BarterPriceHook(); void Inject_BarterPriceHook();
void Inject_UseSkillHook(); void Inject_UseSkillHook();
void Inject_StealCheckHook(); void Inject_StealCheckHook();
void Inject_SneakCheckHook();
void Inject_WithinPerceptionHook(); void Inject_WithinPerceptionHook();
void Inject_CarTravelHook(); void Inject_CarTravelHook();
void Inject_SetGlobalVarHook(); void Inject_SetGlobalVarHook();
void Inject_RestTimerHook(); void Inject_RestTimerHook();
void Inject_ExplosiveTimerHook(); void Inject_ExplosiveTimerHook();
void Inject_EncounterHook();
long PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result); long PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result);
+80
View File
@@ -185,6 +185,76 @@ skip:
} }
} }
static DWORD __fastcall StdProcedureHook_Script(long numHandler, fo::ScriptInstance* script, DWORD procTable) {
BeginHook();
argCount = 4;
args[0] = numHandler;
args[1] = (DWORD)script->selfObject;
args[2] = (DWORD)script->sourceObject;
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;
}
}
void Inject_UseObjOnHook() { void Inject_UseObjOnHook() {
const DWORD useObjOnHkAddr[] = {0x49C606, 0x473619}; const DWORD useObjOnHkAddr[] = {0x49C606, 0x473619};
HookCalls(UseObjOnHook, useObjOnHkAddr); HookCalls(UseObjOnHook, useObjOnHkAddr);
@@ -212,10 +282,20 @@ void Inject_DescriptionObjHook() {
HookCall(0x49AE28, DescriptionObjHook); HookCall(0x49AE28, DescriptionObjHook);
} }
void Inject_ScriptProcedureHook() {
MakeCall(0x4A491F, ScriptStdProcedureHook);
}
void Inject_ScriptProcedureHook2() {
HookCall(0x4A49A7, After_ScriptStdProcedureHook);
}
void InitObjectHookScripts() { void InitObjectHookScripts() {
HookScripts::LoadHookScript("hs_useobjon", HOOK_USEOBJON); HookScripts::LoadHookScript("hs_useobjon", HOOK_USEOBJON);
HookScripts::LoadHookScript("hs_useobj", HOOK_USEOBJ); HookScripts::LoadHookScript("hs_useobj", HOOK_USEOBJ);
HookScripts::LoadHookScript("hs_descriptionobj", HOOK_DESCRIPTIONOBJ); HookScripts::LoadHookScript("hs_descriptionobj", HOOK_DESCRIPTIONOBJ);
HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE); // combo hook
HookScripts::LoadHookScript("hs_stdprocedure", HOOK_STDPROCEDURE_END);
} }
} }
+2
View File
@@ -9,6 +9,8 @@ void Inject_UseObjOnHook();
void Inject_UseObjHook(); void Inject_UseObjHook();
void Inject_UseAnimateObjHook(); void Inject_UseAnimateObjHook();
void Inject_DescriptionObjHook(); void Inject_DescriptionObjHook();
void Inject_ScriptProcedureHook();
void Inject_ScriptProcedureHook2();
long UseObjOnHook_Invoke(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target); long UseObjOnHook_Invoke(fo::GameObject* source, fo::GameObject* item, fo::GameObject* target);
+1 -1
View File
@@ -45,7 +45,7 @@ static void __declspec(naked) GNW95_process_message_hack() {
__asm { __asm {
push idle; push idle;
call Sleep2; call Sleep2;
cmp ds:[FO_VAR_GNW95_isActive], 0; cmp dword ptr ds:[FO_VAR_GNW95_isActive], 0;
retn; retn;
} }
} }
@@ -73,7 +73,7 @@ static void __declspec(naked) wmRndEncounterOccurred_hack() {
__asm { __asm {
test ForceEncounterFlags, 0x1; // _NoCar flag test ForceEncounterFlags, 0x1; // _NoCar flag
jnz noCar; jnz noCar;
cmp ds:[FO_VAR_Move_on_Car], 0; cmp dword ptr ds:[FO_VAR_Move_on_Car], 0;
jz noCar; jz noCar;
mov edx, FO_VAR_carCurrentArea; mov edx, FO_VAR_carCurrentArea;
mov eax, ForceEncounterMapID; mov eax, ForceEncounterMapID;