mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
798 lines
20 KiB
C++
798 lines
20 KiB
C++
#include "..\..\FalloutEngine\Fallout2.h"
|
|
#include "..\..\SafeWrite.h"
|
|
#include "..\Combat.h"
|
|
#include "..\DamageMod.h"
|
|
#include "..\HookScripts.h"
|
|
#include "Common.h"
|
|
|
|
#include "CombatHs.h"
|
|
|
|
namespace sfall
|
|
{
|
|
|
|
static void __declspec(naked) ToHitHook() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[4], eax; // attacker
|
|
mov args[8], ebx; // target
|
|
mov args[12], ecx; // body part
|
|
mov args[16], edx; // source tile
|
|
mov eax, [esp + 8];
|
|
mov args[24], eax; // is ranged
|
|
push eax;
|
|
mov eax, [esp + 8];
|
|
mov args[20], eax; // attack type
|
|
push eax;
|
|
mov eax, args[4]; // restore
|
|
call fo::funcoffs::determine_to_hit_func_;
|
|
mov args[0], eax;
|
|
mov ebx, eax;
|
|
}
|
|
argCount = 8;
|
|
|
|
args[7] = Combat::determineHitChance;
|
|
RunHookScript(HOOK_TOHIT);
|
|
|
|
__asm {
|
|
cmp cRet, 1;
|
|
cmovge ebx, rets[0];
|
|
call EndHook;
|
|
mov eax, ebx;
|
|
retn 8;
|
|
}
|
|
}
|
|
|
|
static DWORD __fastcall AfterHitRollHook_Script(fo::ComputeAttackResult &ctd, DWORD hitChance, DWORD hit) {
|
|
BeginHook();
|
|
argCount = 5;
|
|
|
|
args[0] = hit;
|
|
args[1] = (DWORD)ctd.attacker; // Attacker
|
|
args[2] = (DWORD)ctd.target; // Target
|
|
args[3] = ctd.bodyPart; // bodypart
|
|
args[4] = hitChance;
|
|
|
|
RunHookScript(HOOK_AFTERHITROLL);
|
|
if (cRet > 0) {
|
|
hit = rets[0];
|
|
if (cRet > 1) {
|
|
ctd.bodyPart = rets[1];
|
|
if (cRet > 2) ctd.target = (fo::GameObject*)rets[2];
|
|
}
|
|
}
|
|
EndHook();
|
|
|
|
return hit;
|
|
}
|
|
|
|
static void __declspec(naked) AfterHitRollHook() {
|
|
using namespace fo;
|
|
__asm {
|
|
mov ecx, esi; // ctd
|
|
mov edx, [esp + 0x18 + 4]; // hit chance
|
|
push eax; // was it a hit?
|
|
call AfterHitRollHook_Script;
|
|
// engine code
|
|
mov ebx, eax;
|
|
cmp eax, ROLL_FAILURE;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static long CalcApCostHook_Script(fo::GameObject* source, long hitMode, long isCalled, long cost, fo::GameObject* weapon) {
|
|
BeginHook();
|
|
argCount = 5;
|
|
|
|
args[0] = (DWORD)source;
|
|
args[1] = hitMode;
|
|
args[2] = isCalled;
|
|
args[3] = cost;
|
|
args[4] = (DWORD)weapon;
|
|
|
|
RunHookScript(HOOK_CALCAPCOST);
|
|
|
|
if (cRet > 0) cost = rets[0];
|
|
EndHook();
|
|
|
|
return cost;
|
|
}
|
|
|
|
long CalcApCostHook_Invoke(fo::GameObject* source, long hitMode, long isCalled, long cost, fo::GameObject* weapon) {
|
|
return (HookScripts::HookHasScript(HOOK_CALCAPCOST))
|
|
? CalcApCostHook_Script(source, hitMode, isCalled, cost, weapon)
|
|
: cost;
|
|
}
|
|
/*
|
|
static void __declspec(naked) CalcApCostHook() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[0], eax;
|
|
mov args[4], edx;
|
|
mov args[8], ebx;
|
|
call fo::funcoffs::item_w_mp_cost_;
|
|
mov args[12], eax;
|
|
mov ebx, eax;
|
|
push ecx;
|
|
}
|
|
|
|
argCount = 5;
|
|
args[4] = 0;
|
|
|
|
RunHookScript(HOOK_CALCAPCOST);
|
|
|
|
__asm {
|
|
cmp cRet, 1;
|
|
cmovge ebx, rets[0];
|
|
call EndHook;
|
|
mov eax, ebx;
|
|
pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
*/
|
|
// this is for using non-weapon items, always 2 AP in vanilla
|
|
static void __declspec(naked) CalcApCostHook2() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[0], ecx; // critter
|
|
mov args[4], edx; // attack type (to determine hand)
|
|
mov args[8], ebx;
|
|
mov ebx, 2; // vanilla cost value
|
|
mov args[12], ebx;
|
|
//push ecx;
|
|
}
|
|
|
|
argCount = 5;
|
|
args[4] = 0;
|
|
|
|
RunHookScript(HOOK_CALCAPCOST);
|
|
|
|
__asm {
|
|
cmp cRet, 1;
|
|
cmovge ebx, rets[0];
|
|
call EndHook;
|
|
mov eax, ebx;
|
|
//pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __fastcall ComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DWORD rounds, DWORD multiplier) {
|
|
BeginHook();
|
|
argCount = 13;
|
|
|
|
args[0] = (DWORD)ctd.target; // Target
|
|
args[1] = (DWORD)ctd.attacker; // Attacker
|
|
args[2] = ctd.targetDamage; // amountTarget
|
|
args[3] = ctd.attackerDamage; // amountSource
|
|
args[4] = ctd.targetFlags; // flagsTarget
|
|
args[5] = ctd.attackerFlags; // flagsSource
|
|
args[6] = (DWORD)ctd.weapon;
|
|
args[7] = ctd.bodyPart;
|
|
args[8] = multiplier; // damage multiplier
|
|
args[9] = rounds; // number of rounds
|
|
args[10] = ctd.knockbackValue;
|
|
args[11] = ctd.hitMode; // attack type
|
|
args[12] = (DWORD)&ctd; // main_ctd/shoot_ctd/explosion_ctd
|
|
|
|
RunHookScript(HOOK_COMBATDAMAGE);
|
|
|
|
if (cRet > 0) {
|
|
ctd.targetDamage = rets[0];
|
|
if (cRet > 1) {
|
|
ctd.attackerDamage = rets[1];
|
|
if (cRet > 2) {
|
|
ctd.targetFlags = rets[2]; // flagsTarget
|
|
if (cRet > 3) {
|
|
ctd.attackerFlags = rets[3]; // flagsSource
|
|
if (cRet > 4) ctd.knockbackValue = rets[4];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EndHook();
|
|
}
|
|
|
|
static void __declspec(naked) ComputeDamageHook() {
|
|
__asm {
|
|
push ecx;
|
|
push ebx; // store dmg multiplier args[8]
|
|
push edx; // store num of rounds args[9]
|
|
push eax; // store ctd
|
|
call fo::funcoffs::compute_damage_;
|
|
pop ecx; // restore ctd (eax)
|
|
pop edx; // restore num of rounds
|
|
call ComputeDamageHook_Script; // stack - arg multiplier
|
|
pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __fastcall SubComputeDamageHook_Script(fo::ComputeAttackResult &ctd, DWORD armorDR, DWORD &accumulatedDamage, DWORD armorDT, DWORD bonusRangedDamage, DWORD rounds, DWORD multiplyDamage, DWORD difficulty) {
|
|
// calculated internal ammo mod damage
|
|
switch (DamageMod::formula) {
|
|
case 1:
|
|
case 2:
|
|
DamageMod::DamageGlovz(ctd, accumulatedDamage, rounds, armorDT, armorDR, bonusRangedDamage, multiplyDamage, difficulty);
|
|
return;
|
|
case 5:
|
|
DamageMod::DamageYAAM(ctd, accumulatedDamage, rounds, armorDT, armorDR, bonusRangedDamage, multiplyDamage, difficulty);
|
|
return;
|
|
}
|
|
|
|
BeginHook();
|
|
argCount = 12;
|
|
|
|
args[0] = (DWORD)ctd.attacker;
|
|
args[1] = (DWORD)ctd.target;
|
|
args[2] = (DWORD)ctd.weapon;
|
|
args[3] = (DWORD)ctd.hitMode;
|
|
args[4] = rounds;
|
|
args[5] = armorDR;
|
|
args[6] = armorDT;
|
|
args[7] = bonusRangedDamage;
|
|
args[8] = multiplyDamage;
|
|
args[9] = difficulty;
|
|
args[10] = accumulatedDamage;
|
|
args[11] = (DWORD)&ctd; // main_ctd/shoot_ctd/explosion_ctd
|
|
|
|
RunHookScript(HOOK_SUBCOMBATDAMAGE);
|
|
|
|
if (cRet == 1) accumulatedDamage = rets[0];
|
|
EndHook();
|
|
}
|
|
|
|
static void __declspec(naked) SubComputeDamageHook() {
|
|
__asm {
|
|
mov ecx, dword ptr [esp + 0x20]; // Difficulty
|
|
push ecx;
|
|
mov eax, dword ptr [esp + 0x24 + 4]; // MultiplyDamage
|
|
push eax;
|
|
mov ecx, dword ptr [esp + 0x1C + 8]; // Rounds
|
|
push ecx;
|
|
mov eax, dword ptr [esp + 0x18 + 12]; // BonusRangedDamage
|
|
push eax;
|
|
mov ecx, dword ptr [esp + 0x28 + 16]; // ResistDT
|
|
push ecx;
|
|
push edi; // AccumulatedDamage
|
|
mov ecx, esi; // cdt
|
|
push 0x424A63; // return to address
|
|
jmp SubComputeDamageHook_Script; // edx - ResistDR
|
|
}
|
|
}
|
|
|
|
static void __fastcall FindTargetHook_Script(DWORD* target, fo::GameObject* attacker) {
|
|
BeginHook();
|
|
argCount = 5;
|
|
|
|
args[0] = (DWORD)attacker;
|
|
args[1] = target[0];
|
|
args[2] = target[1];
|
|
args[3] = target[2];
|
|
args[4] = target[3];
|
|
|
|
RunHookScript(HOOK_FINDTARGET);
|
|
|
|
if (cRet > 0) {
|
|
if (rets[0] != -1) target[0] = rets[0];
|
|
if (cRet > 1 && rets[1] != -1) target[1] = rets[1];
|
|
if (cRet > 2 && rets[2] != -1) target[2] = rets[2];
|
|
if (cRet > 3 && rets[3] != -1) target[3] = rets[3];
|
|
}
|
|
EndHook();
|
|
}
|
|
/*
|
|
void FindTargetHook_Invoke(fo::GameObject* targets[], fo::GameObject* attacker) {
|
|
if (HookScripts::HookHasScript(HOOK_FINDTARGET)) FindTargetHook_Script((DWORD*)targets, attacker);
|
|
}
|
|
*/
|
|
static void __declspec(naked) FindTargetHook() {
|
|
__asm {
|
|
push eax;
|
|
call fo::funcoffs::qsort_;
|
|
pop ecx; // targets (base)
|
|
mov edx, esi; // attacker
|
|
jmp FindTargetHook_Script;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) ItemDamageHook() {
|
|
__asm {
|
|
HookBegin;
|
|
mov args[0], eax; // min
|
|
mov args[4], edx; // max
|
|
mov args[8], edi; // weapon
|
|
mov args[12], ecx; // critter
|
|
mov args[16], esi; // type
|
|
mov args[20], ebp; // non-zero for weapon melee attack (add to min/max melee damage)
|
|
pushadc;
|
|
}
|
|
argCount = 6;
|
|
|
|
// tweak for 0x4784AA (obsolete)
|
|
//if (args[2] == 0) { // weapon arg
|
|
// args[4] += 8; // type arg
|
|
//}
|
|
|
|
RunHookScript(HOOK_ITEMDAMAGE);
|
|
|
|
__asm popadc;
|
|
if (cRet > 0) {
|
|
__asm mov eax, rets[0]; // set min
|
|
if (cRet > 1) {
|
|
__asm mov edx, rets[4]; // set max
|
|
} else {
|
|
HookEnd;
|
|
__asm retn; // no calc random
|
|
}
|
|
}
|
|
HookEnd;
|
|
__asm jmp fo::funcoffs::roll_random_;
|
|
}
|
|
|
|
int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD &rounds) {
|
|
int result = 0;
|
|
|
|
BeginHook();
|
|
argCount = 4;
|
|
|
|
args[0] = (DWORD)weapon;
|
|
args[1] = rounds; // rounds in attack
|
|
args[3] = hookType;
|
|
|
|
if (hookType == 2) { // burst hook
|
|
rounds = 1; // set default multiply for check burst attack
|
|
} else {
|
|
result = fo::func::item_w_compute_ammo_cost(weapon, &rounds);
|
|
if (result == -1) goto failed; // computation failed
|
|
}
|
|
args[2] = rounds; // rounds as computed by game (cost)
|
|
|
|
RunHookScript(HOOK_AMMOCOST);
|
|
|
|
if (cRet > 0 && (long)rets[0] >= 0) rounds = rets[0]; // override rounds
|
|
|
|
failed:
|
|
EndHook();
|
|
return result;
|
|
}
|
|
|
|
static void __declspec(naked) AmmoCostHook() {
|
|
using namespace fo;
|
|
__asm {
|
|
xor ecx, ecx; // type of hook (0)
|
|
cmp dword ptr [esp + 0x1C + 4], ANIM_fire_burst;
|
|
jl skip;
|
|
cmp dword ptr [esp + 0x1C + 4], ANIM_fire_continuous;
|
|
jg skip;
|
|
mov ecx, 3; // hook type burst
|
|
skip:
|
|
xchg eax, edx;
|
|
push eax; // rounds in attack ref
|
|
call AmmoCostHook_Script; // edx - weapon
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static long combatTurnResult = 0;
|
|
|
|
// hooks combat_turn function
|
|
static long __fastcall CombatTurnHook_Script(fo::GameObject* critter, long dudeBegin) {
|
|
BeginHook();
|
|
argCount = 3;
|
|
|
|
args[0] = 1; // turn begin
|
|
args[1] = (DWORD)critter; // who begins turn
|
|
args[2] = dudeBegin; // true - dude begins/ends turn after loading a game saved in combat mode
|
|
|
|
RunHookScript(HOOK_COMBATTURN); // Start of turn
|
|
|
|
combatTurnResult = 0;
|
|
if (cRet > 0 && rets[0] == 1) { // skip turn
|
|
goto endHook; // exit hook
|
|
}
|
|
|
|
// set_sfall_return is not used, proceed normally
|
|
combatTurnResult = fo::func::combat_turn(critter, dudeBegin);
|
|
args[0] = combatTurnResult;
|
|
|
|
if (fo::var::combat_end_due_to_load && combatTurnResult == -1) goto endHook; // don't run end of turn hook when the game was loaded during the combat
|
|
|
|
//cRet = 0; // reset number of return values
|
|
RunHookScript(HOOK_COMBATTURN); // End of turn
|
|
|
|
if (cRet > 0 && rets[0] == -1) combatTurnResult = -1; // override result of turn
|
|
|
|
endHook:
|
|
EndHook();
|
|
return combatTurnResult;
|
|
}
|
|
|
|
static void __declspec(naked) CombatTurnHook() {
|
|
__asm {
|
|
push ecx;
|
|
mov ecx, eax;
|
|
call CombatTurnHook_Script; // edx - dudeBegin
|
|
pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) CombatTurnHook_End() {
|
|
if (combatTurnResult >= 0) {
|
|
BeginHook();
|
|
argCount = 3;
|
|
|
|
args[0] = -2; // combat ended normally
|
|
args[1] = fo::var::getInt(FO_VAR_combat_turn_obj);
|
|
args[2] = 0;
|
|
|
|
RunHookScript(HOOK_COMBATTURN);
|
|
EndHook();
|
|
}
|
|
__asm jmp fo::funcoffs::combat_over_;
|
|
}
|
|
|
|
// hack to exit from combat_add_noncoms function without crashing when you load game during PM/NPC turn
|
|
static long countCombat = 0;
|
|
static void __declspec(naked) CombatTurnHook_AddNoncoms() {
|
|
__asm {
|
|
push ecx;
|
|
mov ecx, eax;
|
|
call CombatTurnHook_Script; // edx - dudeBegin
|
|
pop ecx;
|
|
cmp eax, -1;
|
|
je endCombat;
|
|
retn;
|
|
endCombat:
|
|
mov ecx, [esp + 4]; // list
|
|
xor edx, edx;
|
|
cmp ds:[FO_VAR_combat_end_due_to_load], edx;
|
|
jz skip;
|
|
mov eax, ds:[FO_VAR_list_com];
|
|
test eax, eax;
|
|
jz skip;
|
|
mov countCombat, eax;
|
|
skip:
|
|
mov ds:[FO_VAR_list_com], edx; // edx = 0
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) combat_hook_fix_load() {
|
|
static const DWORD combat_hook_end_combat = 0x422E91;
|
|
__asm {
|
|
call fo::funcoffs::combat_sequence_;
|
|
mov eax, countCombat;
|
|
test eax, eax;
|
|
jnz forceEndCombat;
|
|
retn;
|
|
forceEndCombat:
|
|
mov ds:[FO_VAR_list_com], eax;
|
|
mov countCombat, 0;
|
|
add esp, 4;
|
|
jmp combat_hook_end_combat;
|
|
}
|
|
}
|
|
|
|
fo::GameObject* __fastcall ComputeExplosionOnExtrasHook_Script(fo::GameObject* object, DWORD isCheck, DWORD checkTile, fo::ComputeAttackResult* ctdSource, DWORD isThrowing, fo::GameObject* who) {
|
|
fo::GameObject* result = object;
|
|
|
|
BeginHook();
|
|
argCount = 7;
|
|
|
|
args[0] = isCheck;
|
|
args[1] = (DWORD)ctdSource->attacker;
|
|
args[2] = ctdSource->targetTile;
|
|
args[3] = checkTile;
|
|
args[4] = (DWORD)object;
|
|
args[5] = (DWORD)who;
|
|
args[6] = isThrowing;
|
|
|
|
RunHookScript(HOOK_ONEXPLOSION);
|
|
|
|
if (cRet > 0) result = (fo::GameObject*)rets[0]; // override object
|
|
|
|
EndHook();
|
|
return result;
|
|
}
|
|
|
|
static void __declspec(naked) ComputeExplosionOnExtrasHook() {
|
|
__asm {
|
|
cmp dword ptr [esp + 0x34 + 4], 0x429533; // skip hook when AI assesses the situation in choosing the best weapon
|
|
jz end;
|
|
cmp dword ptr [esp + 0x34 + 4], 0x4296BC;
|
|
jnz hook;
|
|
end:
|
|
jmp fo::funcoffs::obj_blocking_at_;
|
|
hook:
|
|
push ecx;
|
|
push eax; // who (target/source)
|
|
call fo::funcoffs::obj_blocking_at_;
|
|
push [esp + 0x34 - 0x24 + 12]; // isThrowing
|
|
xor edx, edx;
|
|
cmp dword ptr [esp + 0x34 + 16], 0x412F11; // check called from action_explode_
|
|
jz skip;
|
|
mov edx, [esp + 0x34 - 0x34 + 16]; // isCheck (bypass damage)
|
|
skip:
|
|
push esi; // source ctd
|
|
push edi; // check tile
|
|
mov ecx, eax; // object
|
|
call ComputeExplosionOnExtrasHook_Script; // edx - isCheck
|
|
pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
static fo::GameObject* __stdcall BestWeaponHook_Script(fo::GameObject* bestWeapon, fo::GameObject* source, fo::GameObject* weapon1, fo::GameObject* weapon2, fo::GameObject* target) {
|
|
BeginHook();
|
|
argCount = 5;
|
|
|
|
args[0] = (DWORD)source;
|
|
args[1] = (DWORD)bestWeapon;
|
|
args[2] = (DWORD)weapon1;
|
|
args[3] = (DWORD)weapon2;
|
|
args[4] = (DWORD)target;
|
|
|
|
RunHookScript(HOOK_BESTWEAPON);
|
|
|
|
if (cRet > 0) bestWeapon = (fo::GameObject*)rets[0];
|
|
|
|
EndHook();
|
|
return bestWeapon;
|
|
}
|
|
|
|
static void __declspec(naked) ai_search_inven_weap_hook() {
|
|
__asm {
|
|
push ecx; // target
|
|
push ebx; // weapon2 (secondary)
|
|
push edx; // weapon1 (primary)
|
|
push eax; // source
|
|
call fo::funcoffs::ai_best_weapon_;
|
|
push eax; // bestWeapon
|
|
call BestWeaponHook_Script;
|
|
retn;
|
|
}
|
|
}
|
|
/*
|
|
fo::GameObject* BestWeaponHook_Invoke(fo::GameObject* bestWeapon, fo::GameObject* source, fo::GameObject* weapon1, fo::GameObject* weapon2, fo::GameObject* target) {
|
|
return (HookScripts::HookHasScript(HOOK_BESTWEAPON))
|
|
? BestWeaponHook_Script(bestWeapon, source, weapon1, weapon2, target)
|
|
: bestWeapon;
|
|
}
|
|
*/
|
|
static bool __stdcall CanUseWeaponHook_Script(bool result, fo::GameObject* source, fo::GameObject* weapon, long hitMode) {
|
|
BeginHook();
|
|
argCount = 4;
|
|
|
|
args[0] = (DWORD)source;
|
|
args[1] = (DWORD)weapon;
|
|
args[2] = hitMode;
|
|
args[3] = result;
|
|
|
|
RunHookScript(HOOK_CANUSEWEAPON);
|
|
|
|
if (cRet > 0) result = (rets[0]) ? true : false;
|
|
|
|
EndHook();
|
|
return result; // only 0 and 1
|
|
}
|
|
|
|
static void __declspec(naked) AICanUseWeaponHook() {
|
|
__asm {
|
|
push ecx;
|
|
push ebx; // hitMode
|
|
push edx; // weapon
|
|
push eax; // source
|
|
call fo::funcoffs::ai_can_use_weapon_;
|
|
push eax; // result
|
|
call CanUseWeaponHook_Script;
|
|
//and eax, 1;
|
|
pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
|
|
static void __declspec(naked) CanUseWeaponHook() {
|
|
__asm {
|
|
push ecx;
|
|
push edx;
|
|
push -1; // hitMode (indefinite)
|
|
push eax; // weapon
|
|
push ds:[FO_VAR_obj_dude]; // source
|
|
call fo::funcoffs::can_use_weapon_; // 1 - can't use
|
|
xor al, 1;
|
|
push eax; // result
|
|
call CanUseWeaponHook_Script;
|
|
xor al, 1; // invert
|
|
pop edx;
|
|
pop ecx;
|
|
retn;
|
|
}
|
|
}
|
|
/*
|
|
bool CanUseWeaponHook_Invoke(bool result, fo::GameObject* source, fo::GameObject* weapon, long hitMode) {
|
|
return (HookScripts::HookHasScript(HOOK_CANUSEWEAPON))
|
|
? CanUseWeaponHook_Script(result, source, weapon, hitMode)
|
|
: result;
|
|
}
|
|
*/
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void Inject_ToHitHook() {
|
|
HookCalls(ToHitHook, {
|
|
0x421686, // combat_safety_invalidate_weapon_func_
|
|
0x4231D9, // check_ranged_miss_
|
|
0x42331F, // shoot_along_path_
|
|
0x4237FC, // compute_attack_
|
|
0x424379, // determine_to_hit_
|
|
0x42438D, // determine_to_hit_no_range_
|
|
0x42439C, // determine_to_hit_from_tile_
|
|
0x42679A // combat_to_hit_
|
|
});
|
|
}
|
|
|
|
void Inject_AfterHitRollHook() {
|
|
MakeCall(0x423893, AfterHitRollHook);
|
|
}
|
|
|
|
void Inject_CalcApCostHook() {
|
|
//HookCalls(CalcApCostHook, {
|
|
// 0x42307A,
|
|
// 0x42669F,
|
|
// 0x42687B,
|
|
// 0x42A625,
|
|
// 0x42A655,
|
|
// 0x42A686,
|
|
// 0x42AE32,
|
|
// 0x42AE71,
|
|
// 0x460048,
|
|
// 0x47807B
|
|
//});
|
|
MakeCall(0x478083, CalcApCostHook2);
|
|
}
|
|
|
|
void Inject_CombatDamageHook() {
|
|
HookCalls(ComputeDamageHook, {
|
|
0x42326C, // check_ranged_miss()
|
|
0x4233E3, // shoot_along_path() - for extra burst targets
|
|
0x423AB7, // compute_attack()
|
|
0x423BBF, // compute_attack()
|
|
// 0x423DE7, // compute_explosion_on_extras()
|
|
0x423E69, // compute_explosion_on_extras()
|
|
0x424220, // attack_crit_failure()
|
|
0x4242FB // attack_crit_failure()
|
|
});
|
|
MakeCall(0x423DEB, ComputeDamageHook); // compute_explosion_on_extras() - fix for the attacker
|
|
}
|
|
|
|
void Inject_FindTargetHook() {
|
|
HookCall(0x429143, FindTargetHook);
|
|
}
|
|
|
|
void Inject_ItemDamageHook() {
|
|
HookCall(0x478560, ItemDamageHook);
|
|
}
|
|
|
|
void Inject_AmmoCostHook() {
|
|
HookCall(0x423A7C, AmmoCostHook); // compute_attack_
|
|
}
|
|
|
|
void Inject_CombatTurnHook() {
|
|
HookCall(0x422354, CombatTurnHook_AddNoncoms);
|
|
HookCalls(CombatTurnHook, { 0x422D87, 0x422E20 });
|
|
HookCalls(CombatTurnHook_End, {
|
|
0x422E85, // combat_
|
|
0x422196 // combat_over_from_load_
|
|
});
|
|
|
|
HookCall(0x422E4D, combat_hook_fix_load);
|
|
}
|
|
|
|
void Inject_OnExplosionHook() {
|
|
HookCall(0x423D70, ComputeExplosionOnExtrasHook);
|
|
}
|
|
|
|
void Inject_SubCombatDamageHook() {
|
|
MakeJump(0x42499C, SubComputeDamageHook);
|
|
}
|
|
|
|
void Inject_TargetObjectHook() {
|
|
MakeCall(0x44BB16, gmouse_bk_process_hook, 1);
|
|
SafeWrite8(0x44BB00, 0x15);
|
|
|
|
MakeCall(0x44C286, gmouse_handle_event_hook, 1);
|
|
SafeWrite8(0x44C26E, 0x17);
|
|
}
|
|
|
|
void Inject_BestWeaponHook() {
|
|
HookCall(0x429A59, ai_search_inven_weap_hook);
|
|
}
|
|
|
|
void Inject_CanUseWeaponHook() {
|
|
HookCalls(AICanUseWeaponHook, {
|
|
0x429A1B, // ai_search_inven_weap_
|
|
0x429CF2, // ai_search_environ_
|
|
0x429E1C // ai_pick_hit_mode_
|
|
});
|
|
HookCalls(CanUseWeaponHook, { 0x45F05E, 0x45F1C1, 0x45F203, 0x45F36A }); // intface_update_items_
|
|
}
|
|
|
|
void InitCombatHookScripts() {
|
|
HookScripts::LoadHookScript("hs_tohit", HOOK_TOHIT);
|
|
HookScripts::LoadHookScript("hs_afterhitroll", HOOK_AFTERHITROLL);
|
|
HookScripts::LoadHookScript("hs_calcapcost", HOOK_CALCAPCOST);
|
|
HookScripts::LoadHookScript("hs_combatdamage", HOOK_COMBATDAMAGE);
|
|
HookScripts::LoadHookScript("hs_findtarget", HOOK_FINDTARGET);
|
|
HookScripts::LoadHookScript("hs_itemdamage", HOOK_ITEMDAMAGE);
|
|
HookScripts::LoadHookScript("hs_ammocost", HOOK_AMMOCOST);
|
|
HookScripts::LoadHookScript("hs_combatturn", HOOK_COMBATTURN);
|
|
HookScripts::LoadHookScript("hs_onexplosion", HOOK_ONEXPLOSION);
|
|
HookScripts::LoadHookScript("hs_subcombatdmg", HOOK_SUBCOMBATDAMAGE);
|
|
HookScripts::LoadHookScript("hs_targetobject", HOOK_TARGETOBJECT);
|
|
HookScripts::LoadHookScript("hs_bestweapon", HOOK_BESTWEAPON);
|
|
HookScripts::LoadHookScript("hs_canuseweapon", HOOK_CANUSEWEAPON);
|
|
}
|
|
|
|
}
|