mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added a new hook: HOOK_ENCOUNTER
Added procedure and macros for unsigned integer comparison to lib.math.h.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -69,6 +69,7 @@ enum HookType
|
||||
HOOK_STDPROCEDURE = 40,
|
||||
HOOK_STDPROCEDURE_END = 41,
|
||||
HOOK_TARGETOBJECT = 42,
|
||||
HOOK_ENCOUNTER = 43,
|
||||
HOOK_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,4 +15,5 @@ namespace sfall
|
||||
void Inject_SetGlobalVarHook();
|
||||
void Inject_RestTimerHook();
|
||||
void Inject_ExplosiveTimerHook();
|
||||
void Inject_EncounterHook();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user