Added a new hook: HOOK_ENCOUNTER

Added procedure and macros for unsigned integer comparison to lib.math.h.
This commit is contained in:
NovaRain
2020-01-19 12:18:14 +08:00
parent bf4c47d1c0
commit 957ed92498
8 changed files with 130 additions and 0 deletions
+11
View File
@@ -5,6 +5,17 @@
Numbers...
*/
#define above(a, b) (unsigned_comp(a, b) > 0)
#define above_equal(a, b) (unsigned_comp(a, b) >= 0)
#define below(a, b) (unsigned_comp(a, b) < 0)
#define below_equal(a, b) (unsigned_comp(a, b) <= 0)
procedure unsigned_comp(variable a, variable b) begin
if (a bwxor b) then return 0;
if (b == 0) then return 1;
return 1 if (a / b) else -1;
end
#define MAX(x, y) ((x > y) * x + (x <= y) * y)
#define MIN(x, y) ((x < y) * x + (x >= y) * y)
#define in_range(x, from, to) (x >= from and x <= to)
+1
View File
@@ -65,6 +65,7 @@
#define HOOK_STDPROCEDURE (40)
#define HOOK_STDPROCEDURE_END (41)
#define HOOK_TARGETOBJECT (42)
#define HOOK_ENCOUNTER (43)
//Valid arguments to list_begin
#define LIST_CRITTERS (0)
+14
View File
@@ -669,3 +669,17 @@ int arg2 - 1 when the target object is valid to attack, 0 otherwise
Obj arg3 - the target object
mixed ret1 - 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 arg1 - event type: 0 - when a random encounter occurs, 1 - when the player enters from the world map
int arg2 - the map ID that the encounter will load (see MAPS.h or Maps.txt)
int arg3 - 1 when the encounter occurs is a special encounter, 0 otherwise
int ret1 - overrides the map ID, or pass -1 to cancel the encounter and continue traveling (only for event type 0)
int ret2 - pass 1 to cancel the encounter and load the specified map from the ret1 (only for event type 0)
+3
View File
@@ -60,6 +60,7 @@
#define FO_VAR_edit_win 0x57060C
#define FO_VAR_Educated 0x57082C
#define FO_VAR_elevation 0x631D2C
#define FO_VAR_EncounterMapID 0x672E4C
#define FO_VAR_Experience_ 0x6681B4
#define FO_VAR_fade_steps 0x6642D0
#define FO_VAR_fallout_game_time 0x51C720
@@ -158,6 +159,8 @@
#define FO_VAR_obj_seen_check 0x6610BC
#define FO_VAR_objectTable 0x639DA0
#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_optionsButtonDown 0x59D400
#define FO_VAR_optionsButtonDown1 0x570518
+1
View File
@@ -93,6 +93,7 @@ static HooksInjectInfo injectHooks[] = {
{HOOK_STDPROCEDURE, Inject_ScriptProcedureHook, false},
{HOOK_STDPROCEDURE_END, Inject_ScriptProcedureHook2, false},
{HOOK_TARGETOBJECT, Inject_TargetObjectHook, false},
{HOOK_ENCOUNTER, Inject_EncounterHook, false},
};
bool HookScripts::injectAllHooks;
+1
View File
@@ -69,6 +69,7 @@ enum HookType
HOOK_STDPROCEDURE = 40,
HOOK_STDPROCEDURE_END = 41,
HOOK_TARGETOBJECT = 42,
HOOK_ENCOUNTER = 43,
HOOK_COUNT
};
+98
View File
@@ -525,6 +525,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 (not verified)
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
*(DWORD*)FO_VAR_old_world_xpos = fo::var::world_xpos;
*(DWORD*)FO_VAR_old_world_ypos = fo::var::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
je break;
jmp fo::funcoffs::wmInterfaceRefresh_;
break:
mov eax, hkEncounterMapID;
cmp ds:[FO_VAR_Move_on_Car], 1;
jne noCar;
mov edx, FO_VAR_carCurrentArea;
call fo::funcoffs::wmMatchAreaContainingMapIdx_;
mov eax, hkEncounterMapID;
noCar:
call fo::funcoffs::map_load_idx_;
xor eax, eax;
//mov ds:[0x672E48], eax; // _wmUnkVar00
mov hkEncounterMapID, -1;
cancelEnc:
inc eax; // 0 - continue movement, 1 - interrupt
add esp, 4;
mov ebx, 0x4C0BC7;
jmp ebx;
}
}
void Inject_BarterPriceHook() {
HookCalls(BarterPriceHook, {
0x474D4C, // barter_attempt_transaction_ (offers button)
@@ -587,6 +679,11 @@ void Inject_UseSkillOnHook() {
SafeWriteBatch<DWORD>((DWORD)&sourceSkillOn, {0x4AB0EF, 0x4AB5C0, 0x4ABAF2}); // fix for time
}
void Inject_EncounterHook() {
HookCall(0x4C02AF, wmWorldMap_hook);
HookCall(0x4C095C, wmRndEncounterOccurred_hook);
}
void InitMiscHookScripts() {
LoadHookScript("hs_barterprice", HOOK_BARTERPRICE);
LoadHookScript("hs_useskillon", HOOK_USESKILLON);
@@ -598,6 +695,7 @@ void InitMiscHookScripts() {
LoadHookScript("hs_setglobalvar", HOOK_SETGLOBALVAR);
LoadHookScript("hs_resttimer", HOOK_RESTTIMER);
LoadHookScript("hs_explosivetimer", HOOK_EXPLOSIVETIMER);
LoadHookScript("hs_encounter", HOOK_ENCOUNTER);
}
}
+1
View File
@@ -15,4 +15,5 @@ namespace sfall
void Inject_SetGlobalVarHook();
void Inject_RestTimerHook();
void Inject_ExplosiveTimerHook();
void Inject_EncounterHook();
}