Fixed the functions of the engine op_obj_can_see_obj_/op_obj_can_hear_obj_ (#189)

Added one additional argument for the hook HOOK_WITHINPERCEPTION.
This commit is contained in:
Mr.Stalin
2018-08-18 23:56:03 +08:00
committed by NovaRain
parent a7c66685b9
commit 032e1d13f3
4 changed files with 134 additions and 14 deletions
@@ -0,0 +1,58 @@
/*
Example engine algorithm.
* The AllowUnsafeScripting option must be enabled.
*/
#include "define_lite.h"
#include "command.h"
#include "sfall.h"
#include "define_extra.h"
#define can_see_(source, target) call_offset_r2(0x412BEC, source, target)
#define obj_dist_(target, source) call_offset_r2(0x48BBD4, target, source)
procedure start;
procedure start begin
if not(init_hook) then begin
variable source := get_sfall_arg,
target := get_sfall_arg,
original := get_sfall_arg,
type := get_sfall_arg, /* new arg */
result := 0,
distance;
if target then begin
distance := get_critter_stat(source, STAT_pe);
if can_see_(source, target) then begin
distance *= 5;
if (get_flags(target) bwand FLAG_TRANSGLASS) then distance /= 2;
end
else if combat_is_initialized then distance *= 2;
if target == dude_obj then begin
if sneak_success then begin
distance /= 4;
if has_skill(target, SKILL_SNEAK) > 120 then distance -= 1;
end
else if dude_is_sneaking then distance := distance * 2 / 3;
end
if obj_dist_(target, source) <= distance then result := 1;
// example
if (result) then begin
display_msg("hs_withinperception: " + obj_name(source) + " does he see > " + obj_name(target) + " [original: " + original + " script: " + result + "]");
end else begin
display_msg("hs_withinperception: " + obj_name(source) + " he does not see > " + obj_name(target) + " [original: " + original + " script: " + result + "]");
end
end
//set_sfall_return(result);
end
end
+1
View File
@@ -401,6 +401,7 @@ This is fired after the default calculation is made.
Critter arg1 - Watcher object
Obj arg2 - Target object
int arg3 - Result of vanilla function: 1 - within perception range, 0 - otherwise
int arg4 - The type of the called hook: 1 - from the script function obj_can_see_obj, 2 - from the script function obj_can_hear_obj (need option CanHearObjFix enabled), 0 for all other cases
int ret1 - overrides the returned result of the function: 0 - not in range (can't see), 1 - in range (will see if not blocked), 2 - forced detection (will see regardless, only used in obj_can_see_obj scripting function which is called by every critter in the game)
+38
View File
@@ -1292,6 +1292,30 @@ skip:
}
}
static void __declspec(naked) op_obj_can_see_obj_hack() {
__asm {
mov eax, [esp + 0x2C - 0x28 + 4]; // source
mov ecx, [eax + tile]; // source.tile
cmp ecx, -1;
jz end;
mov eax, [eax + elevation];
mov edi, [edx + elevation]; // target.elev
cmp eax, edi; // check source.elev == target.elev
retn;
end:
dec ecx; // reset ZF
retn;
}
}
static void __declspec(naked) op_obj_can_hear_obj_hack() {
__asm {
mov eax, [esp + 0x28 - 0x28 + 4]; // target
mov edx, [esp + 0x28 - 0x24 + 4]; // source
retn;
}
}
void BugFixes::init()
{
@@ -1648,6 +1672,20 @@ void BugFixes::init()
HookCall(0x4C0AEB, wmRndEncounterOccurred_hook);
dlogr(" Done", DL_INIT);
}
// Fix op_obj_can_see_obj_
MakeCall(0x456B63, op_obj_can_see_obj_hack);
SafeWrite16(0x456B76, 0x23EB); // jz > jmp (skip unused engine code)
//Fix broken op_obj_can_hear_obj_ (enable a function)
if (GetConfigInt("Misc", "CanHearObjFix", 0) != 0) {
dlog("Applying obj_can_hear_obj opcode fix.", DL_INIT);
SafeWrite8(0x4583D8, 0x3B); // change jz offset
SafeWrite8(0x4583DE, 0x74); // jnz > jz
MakeCall(0x4583E0, op_obj_can_hear_obj_hack);
SafeWrite8(0x4583E5, 0x90);
dlogr(" Done", DL_INIT);
}
}
}
+37 -14
View File
@@ -139,39 +139,62 @@ defaultHandler:
}
}
static void __declspec(naked) PerceptionRangeHook() {
static void __stdcall PerceptionRangeHook_Script(int type) {
__asm {
HookBegin;
mov args[0], eax; // watcher
mov args[4], edx; // target
call fo::funcoffs::is_within_perception_;
mov args[8], eax; // check result
pushad;
push eax;
}
argCount = 3;
args[3] = type;
argCount = 4;
RunHookScript(HOOK_WITHINPERCEPTION);
EndHook();
__asm {
popad;
pop eax;
cmp cRet, 1;
cmovnb eax, rets[0];
}
}
static void __declspec(naked) PerceptionRangeHook() {
__asm {
push ecx;
push 0;
call PerceptionRangeHook_Script;
pop ecx;
retn;
}
}
static const DWORD PerceptionRangeBonusHack_back = 0x456BA7;
static const DWORD PerceptionRangeBonusHack_skip = 0x456BDC;
static void __declspec(naked) PerceptionRangeBonusHack() {
static void __declspec(naked) PerceptionRangeSeeHook() {
__asm {
call PerceptionRangeHook;
push ecx;
push 1;
call PerceptionRangeHook_Script;
pop ecx;
cmp eax, 2;
jne nevermind; // return
mov dword ptr[esp + 16], 1;
jmp PerceptionRangeBonusHack_skip; // skip blocking check
jne nevermind; // normal return
dec eax;
mov dword ptr[esp + 0x2C - 0x1C + 4], eax; // set 1, skip blocking check
dec eax;
nevermind:
jmp PerceptionRangeBonusHack_back;
retn;
}
}
static void __declspec(naked) PerceptionRangeHearHook() {
__asm {
push ecx;
push 2;
call PerceptionRangeHook_Script;
pop ecx;
retn;
}
}
@@ -396,9 +419,9 @@ void Inject_WithinPerceptionHook() {
0x42BC87,
0x42BC9F,
0x42BD04,
0x458403
});
MakeJump(0x456BA2, PerceptionRangeBonusHack);
HookCall(0x456BA2, PerceptionRangeSeeHook);
HookCall(0x458403, PerceptionRangeHearHook);
}
void Inject_CarTravelHook() {