Added a new argument to HOOK_TOHIT (#339)

Added hook type 3 to HOOK_WITHINPERCEPTION (when AI selects a target)

Extended the upper limit of set_pickpocket_max and set_hit_chance_max
script functions to 999.

Added a fix for combat_is_shot_blocked_ not taking the flags of critters
in the line of fire into account.

Minor edits to ASM code of some hooks.
This commit is contained in:
NovaRain
2020-09-22 15:43:26 +08:00
parent 008692bec7
commit 876616fc7d
12 changed files with 80 additions and 59 deletions
+9 -5
View File
@@ -80,13 +80,14 @@ HOOK_TOHIT (hs_tohit.int)
Runs when Fallout is calculating the chances of an attack striking a target
Runs after the hit chance is fully calculated normally, including applying the 95% cap
int arg1 - The unmodified hit chance
int arg1 - The hit chance (capped)
critter arg2 - The attacker
critter arg3 - The target of the attack
int arg4 - The targeted bodypart
int arg5 - Source tile (may differ from attacker's tile, when AI is considering potential fire position)
int arg6 - Attack Type (one of ATKTYPE_*)
int arg7 - Ranged flag (0 or 1, actually passed 1 even for unarmed attacks, may be a vanilla bug)
int arg7 - Ranged flag. 1 means the hit chance is calculated by taking into account the bonuses/penalties of the distance to the target
int arg8 - The raw hit chance before applying the cap
int ret1 - the new hit chance
@@ -192,7 +193,7 @@ Critter arg1 - The critter that just died
HOOK_FINDTARGET (hs_findtarget.int)
Runs when the ai is trying to pick a target in combat. Fallout first chooses a list of 4 likely suspects, then normally sorts them in order of weakness/distance/etc depending on the ai caps of the attacker.
Runs when the AI is trying to pick a target in combat. Fallout first chooses a list of 4 likely suspects, then normally sorts them in order of weakness/distance/etc depending on the AI caps of the attacker.
This hook replaces that sorting function, allowing you to sort the targets in some arbitrary way.
The return values can include critters that weren't in the list of possible targets, but the additional targets may still be discarded later on in the combat turn if they are out of the attackers perception or the chance of a successful hit is too low. The list of possible targets often includes duplicated entries, but this is fixed in sfall 4.2.3/3.8.23.
@@ -417,8 +418,11 @@ 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 - Type of hook: 1 - when being called from obj_can_see_obj script function, 2 when being called from obj_can_hear_obj script function (need to set ObjCanHearObjFix=1 in ddraw.ini), 0 for all other cases
int arg4 - Type of hook:
1 - when being called from obj_can_see_obj script function
2 - when being called from obj_can_hear_obj script function (need to set ObjCanHearObjFix=1 in ddraw.ini)
3 - when AI determines whether it sees a potential target when selecting attack targets
0 - 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)
-------------------------------------------
+4 -4
View File
@@ -19,7 +19,7 @@ The read_xxx functions take a memory address as the parameter and can read arbit
The get/set_pc_base/extra_stat functions are equivalent to calling get/set_critter_base/extra_stat with dude_obj as the critter pointer. None of these stat functions take perks into account, and neither do they do range clamping to make sure the stats are valid. Use the normal get_critter_stat function to get a correctly perk adjusted and range clamped value for a stat.
The set_stat_max/min functions can be used to set the valid ranges on stats. Values returned by get_current_stat will be clamped to this range. The set_pc_ function only effect the player, the set_npc_ functions only effect other critters, and the set_ functions effect both.
The set_stat_max/min functions can be used to set the valid ranges on stats. Values returned by get_current_stat will be clamped to this range. The set_pc_ function only affects the player, the set_npc_ functions only affects other critters, and the set_ functions affects both.
The input functions are only available if the user has the input hook turned on in ddraw.ini. Use input_funcs_available to check.
@@ -43,7 +43,7 @@ The 'type' value in the weapon knockback functions can be 0 or 1. If 0, the valu
The get/set_sfall_global functions require an 8 characters long case sensitive string for the variable name. The variables behave the same as normal Fallout globals, except that they don't have to be declared beforehand in vault13.gam. Trying to get a variable which hasn't been set will always return 0. These functions are intended for use when a patch to a mod requires the addition of a new global variable, a case which would otherwise require the player to start a new game.
set_pickpocket_max and set_hit_chance_max effect all critters rather than just the player. set_skill_max can't be used to increase the skill cap above 300. set_perk_level_mod sets a modifier between +25 and -25 that is added/subtracted from the player's level for the purposes of deciding which perks can be chosen.
set_pickpocket_max and set_hit_chance_max affect all critters rather than just the player and can set the maximum in range from 0 to 999. set_skill_max can't be used to increase the skill cap above 300. set_perk_level_mod sets a modifier between +25 and -25 that is added/subtracted from the player's level for the purposes of deciding which perks can be chosen.
set_fake_trait and set_fake_perk can be used to add additional traits and perks to the character screen. They will be saved correctly when the player saves and reloads games, but by themselves they will have no further effect on the character. For perks, the allowed range for levels is between 0 and 100; setting the level to 0 removes that perk. For traits, the level must be 0 or 1. The image is a numeric id that corresponds to an entry in skilldex.lst. The name is limited to 63 characters and the description to 255 characters by sfall, but internal Fallout limits may be lower.
@@ -57,7 +57,7 @@ get/set_bodypart_hit_modifier alter the hit percentage modifiers for aiming at s
(re)set/get_critical_table are used for modifying the critical table. For details see 'http://falloutmods.wikia.com/wiki/Critical_hit_tables'. Changes are not saved, and will reset to the defaults, (or to the contents of CriticalOverrides.ini, if it exists,) at each game reload. These function also require OverrideCriticalTable to be set to 1 in ddraw.ini. (Disabled by default, because it noticably increases loading times.)
get/set_unspent_ap_bonus alter the AC bonus you receive per unused action point at the end of your turn in combat. To allow for fractional values, the value given if divided by 4. (Hence the default value is 4 and not 1.) get/set_unspent_ap_perk_bonus are similar, but effect the extra AC granted by the h2h evade perk. (The default value of this is also 4, equivalent to doubling the original bonus.)
get/set_unspent_ap_bonus alter the AC bonus you receive per unused action point at the end of your turn in combat. To allow for fractional values, the value given if divided by 4. (Hence the default value is 4 and not 1.) get/set_unspent_ap_perk_bonus are similar, but affect the extra AC granted by the HtH Evade perk. (The default value of this is also 4, equivalent to doubling the original bonus.)
nb_* functions are reserved for the brotherhood tactical training mod, and should be avoided.
@@ -615,7 +615,7 @@ Some utility/math functions are available:
> void sfall_func5("draw_image", string/int pathFile/artId, int frame, int x, int y, bool noTransparent)
> void sfall_func6("draw_image_scaled", string/int pathFile/artId, int frame, int x, int y, int width, int height)
- displays the specified PCX or FRM image in the active window created by vanilla CreateWin or sfall's create_win script function
- pathFile/artId: path to the PCX/FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 117440550, see specification of the FID format)
- pathFile/artId: path to the PCX/FRM file (e.g. "art\\inven\\5mmap.frm"), or its FRM ID number (e.g. 0x7000026, see specification of the FID format)
optional arguments:
- frame: frame number, the first frame starts from zero
- x/y: offset relative to the top-left corner of the window
+5
View File
@@ -3564,6 +3564,11 @@ void BugFixes::init()
// Fix to limit the maximum distance for the knockback animation
MakeCall(0x4104D5, action_knockback_hack);
// Fix for combat_is_shot_blocked_ engine function not checking critters and their flags correctly
// when calculating the hit chance penalty based on the number of critters in the line of fire
SafeWriteBatch<BYTE>(0x41, {0x426D46, 0x426D4E}); // edi > ecx (replace target with object critter)
SafeWrite8(0x426D48, fo::DAM_DEAD | fo::DAM_KNOCKED_DOWN | fo::DAM_KNOCKED_OUT);
}
}
+3
View File
@@ -72,6 +72,8 @@ struct KnockbackModifier {
double value;
};
long Combat::rawHitChance; // the value of hit chance w/o any cap
static std::vector<long> noBursts; // object id
static std::vector<KnockbackModifier> mTargets;
@@ -240,6 +242,7 @@ static void __declspec(naked) compute_dmg_damage_hack() {
}
static int __fastcall HitChanceMod(int base, fo::GameObject* critter) {
Combat::rawHitChance = base;
for (size_t i = 0; i < hitChanceMods.size(); i++) {
if (critter->id == hitChanceMods[i].id) {
return min(base + hitChanceMods[i].mod, hitChanceMods[i].maximum);
+2
View File
@@ -28,6 +28,8 @@ public:
const char* name() { return "Combat"; }
void init();
static long rawHitChance;
static DWORD __fastcall check_item_ammo_cost(fo::GameObject* weapon, DWORD hitMode);
};
+6 -4
View File
@@ -1,5 +1,6 @@
#include "..\..\FalloutEngine\Fallout2.h"
#include "..\..\SafeWrite.h"
#include "..\Combat.h"
#include "..\DamageMod.h"
#include "..\HookScripts.h"
#include "Common.h"
@@ -28,13 +29,14 @@ static void __declspec(naked) ToHitHook() {
pushadc;
}
argCount = 7;
argCount = 8;
args[7] = Combat::rawHitChance;
RunHookScript(HOOK_TOHIT);
__asm {
popadc;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn 8;
}
@@ -119,7 +121,7 @@ static void __declspec(naked) CalcApCostHook() {
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
@@ -143,7 +145,7 @@ static void __declspec(naked) CalcApCostHook2() {
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
+1 -1
View File
@@ -89,7 +89,7 @@ static void __declspec(naked) CalcDeathAnim2Hook() {
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
+4 -4
View File
@@ -35,7 +35,7 @@ return:
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
@@ -58,7 +58,7 @@ static void __declspec(naked) HexABlockingHook() {
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
@@ -81,7 +81,7 @@ static void __declspec(naked) HexShootBlockingHook() {
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
@@ -104,7 +104,7 @@ static void __declspec(naked) HexSightBlockingHook() {
__asm {
popad;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
+1 -1
View File
@@ -58,7 +58,7 @@ static void __declspec(naked) MoveCostHook() {
__asm {
popadc;
cmp cRet, 1;
cmovnb eax, rets[0];
cmovge eax, rets[0];
HookEnd;
retn;
}
+26 -27
View File
@@ -190,7 +190,7 @@ static void __declspec(naked) UseSkillHook() {
__asm {
popad;
cmp cRet, 1;
jb defaultHandler;
jl defaultHandler;
cmp rets[0], -1;
je defaultHandler;
mov eax, rets[0];
@@ -218,7 +218,7 @@ static void __declspec(naked) StealCheckHook() {
__asm {
popadc;
cmp cRet, 1;
jb defaultHandler;
jl defaultHandler;
cmp rets[0], -1;
je defaultHandler;
mov eax, rets[0];
@@ -256,37 +256,14 @@ skip:
}
}
// Implementation of is_within_perception_ engine function with the hook
long __fastcall sf_is_within_perception(fo::GameObject* watcher, fo::GameObject* target) {
static long __fastcall PerceptionRangeHook_Script(fo::GameObject* watcher, fo::GameObject* target, int type) {
long result = fo::func::is_within_perception(watcher, target);
if (!HookScripts::HookHasScript(HOOK_WITHINPERCEPTION)) return result;
BeginHook();
args[0] = (DWORD)watcher;
args[1] = (DWORD)target;
args[2] = result;
args[3] = 0; // type
argCount = 4;
RunHookScript(HOOK_WITHINPERCEPTION);
if (cRet > 0) result = rets[0];
EndHook();
return result;
}
static long __stdcall PerceptionRangeHook_Script(int type) {
long result;
__asm {
HookBegin;
mov args[0], eax; // watcher
mov args[4], edx; // target
call fo::funcoffs::is_within_perception_;
mov result, eax; // check result
}
args[2] = result;
args[3] = type;
argCount = 4;
@@ -298,10 +275,19 @@ static long __stdcall PerceptionRangeHook_Script(int type) {
return result;
}
// Implementation of is_within_perception_ engine function with the hook
long __fastcall sf_is_within_perception(fo::GameObject* watcher, fo::GameObject* target) { // TODO: add type arg
if (HookScripts::HookHasScript(HOOK_WITHINPERCEPTION)) {
return PerceptionRangeHook_Script(watcher, target, 0);
}
return fo::func::is_within_perception(watcher, target);
}
static void __declspec(naked) PerceptionRangeHook() {
__asm {
push ecx;
push 0;
mov ecx, eax;
call PerceptionRangeHook_Script;
pop ecx;
retn;
@@ -312,6 +298,7 @@ static void __declspec(naked) PerceptionRangeSeeHook() {
__asm {
push ecx;
push 1;
mov ecx, eax;
call PerceptionRangeHook_Script;
pop ecx;
cmp eax, 2;
@@ -328,6 +315,18 @@ static void __declspec(naked) PerceptionRangeHearHook() {
__asm {
push ecx;
push 2;
mov ecx, eax;
call PerceptionRangeHook_Script;
pop ecx;
retn;
}
}
static void __declspec(naked) PerceptionSearchTargetHook() {
__asm {
push ecx;
push 3;
mov ecx, eax;
call PerceptionRangeHook_Script;
pop ecx;
retn;
@@ -663,12 +662,12 @@ void Inject_SneakCheckHook() {
void Inject_WithinPerceptionHook() {
HookCalls(PerceptionRangeHook, {
0x429157,
0x42B4ED,
0x42BC87,
0x42BC9F,
0x42BD04,
});
HookCall(0x429157, PerceptionSearchTargetHook);
HookCall(0x456BA2, PerceptionRangeSeeHook);
HookCall(0x458403, PerceptionRangeHearHook);
}
+3 -3
View File
@@ -24,7 +24,7 @@ static void __declspec(naked) UseObjOnHook() {
__asm {
popad;
cmp cRet, 1;
jb defaultHandler;
jl defaultHandler;
cmp rets[0], -1;
je defaultHandler;
mov eax, rets[0];
@@ -51,7 +51,7 @@ static void __declspec(naked) Drug_UseObjOnHook() {
__asm {
popad;
cmp cRet, 1;
jb defaultHandler;
jl defaultHandler;
cmp rets[0], -1;
je defaultHandler;
mov eax, rets[0];
@@ -77,7 +77,7 @@ static void __declspec(naked) UseObjHook() {
__asm {
popad;
cmp cRet, 1;
jb defaultHandler;
jl defaultHandler;
cmp rets[0], -1;
je defaultHandler;
mov eax, rets[0];
+16 -10
View File
@@ -247,12 +247,15 @@ void __declspec(naked) op_set_pickpocket_max() {
__asm {
mov esi, ecx;
_GET_ARG_INT(end);
mov ecx, 100;
xor edx, edx;
test eax, eax;
cmovs eax, edx; // max < 0
mov ecx, 999;
cmp eax, ecx;
cmova eax, ecx; // 0 - 100
push 0;
push eax;
push 0xFFFFFFFF;
cmova eax, ecx; // 0 - 999 (maximum)
push edx; // mod (0)
push eax; // maximum
push 0xFFFFFFFF; // critter
call SetPickpocketMax;
end:
mov ecx, esi;
@@ -264,12 +267,15 @@ void __declspec(naked) op_set_hit_chance_max() {
__asm {
mov esi, ecx;
_GET_ARG_INT(end);
mov ecx, 100;
xor edx, edx;
test eax, eax;
cmovs eax, edx; // max < 0
mov ecx, 999;
cmp eax, ecx;
cmova eax, ecx; // 0 - 100
push 0;
push eax;
push 0xFFFFFFFF;
cmova eax, ecx; // 0 - 999 (maximum)
push edx; // mod (0)
push eax; // maximum
push 0xFFFFFFFF; // critter
call SetHitChanceMax;
end:
mov ecx, esi;