mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Refactoring combat hooks (#174)
* Fixed and improved the functionality of HOOK_AMMOCOST when CheckWeaponAmmoCost is enabled. * Fixed the instant death critical fix not working if there's no script using HOOK_COMBATDAMAGE, due to the new hooks injection implementation.
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "Functions.h"
|
#include "Functions.h"
|
||||||
#include "Structs.h"
|
#include "Structs.h"
|
||||||
|
#include "Variables.h"
|
||||||
#include "VariableOffsets.h"
|
#include "VariableOffsets.h"
|
||||||
|
|
||||||
#include "EngineUtils.h"
|
#include "EngineUtils.h"
|
||||||
@@ -79,7 +80,7 @@ int _fastcall GetItemType(GameObject* item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType slot) {
|
_declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType slot) {
|
||||||
GameObject* itemPtr = 0;
|
GameObject* itemPtr = nullptr;
|
||||||
switch (slot) {
|
switch (slot) {
|
||||||
case fo::INVEN_TYPE_LEFT_HAND:
|
case fo::INVEN_TYPE_LEFT_HAND:
|
||||||
itemPtr = fo::func::inven_left_hand(critter);
|
itemPtr = fo::func::inven_left_hand(critter);
|
||||||
@@ -94,6 +95,14 @@ _declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType sl
|
|||||||
return itemPtr;
|
return itemPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long& GetActiveItemMode() {
|
||||||
|
return fo::var::itemButtonItems[fo::var::itemCurrentItem].mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameObject* GetActiveItem() {
|
||||||
|
return fo::var::itemButtonItems[fo::var::itemCurrentItem].item;
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------
|
//---------------------------------------------------------
|
||||||
//print text to surface
|
//print text to surface
|
||||||
void PrintText(char *DisplayText, BYTE ColourIndex, DWORD Xpos, DWORD Ypos, DWORD TxtWidth, DWORD ToWidth, BYTE *ToSurface) {
|
void PrintText(char *DisplayText, BYTE ColourIndex, DWORD Xpos, DWORD Ypos, DWORD TxtWidth, DWORD ToWidth, BYTE *ToSurface) {
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ int _fastcall GetItemType(GameObject* item);
|
|||||||
|
|
||||||
_declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType slot);
|
_declspec(noinline) GameObject* GetItemPtrSlot(GameObject* critter, InvenType slot);
|
||||||
|
|
||||||
|
long& GetActiveItemMode();
|
||||||
|
|
||||||
|
GameObject* GetActiveItem();
|
||||||
|
|
||||||
// Print text to surface
|
// Print text to surface
|
||||||
void PrintText(char *displayText, BYTE colorIndex, DWORD x, DWORD y, DWORD textWidth, DWORD destWidth, BYTE *surface);
|
void PrintText(char *displayText, BYTE colorIndex, DWORD x, DWORD y, DWORD textWidth, DWORD destWidth, BYTE *surface);
|
||||||
// gets the height of the currently selected font
|
// gets the height of the currently selected font
|
||||||
|
|||||||
@@ -632,4 +632,52 @@ enum RollResult
|
|||||||
ROLL_CRITICAL_SUCCESS = 0x3,
|
ROLL_CRITICAL_SUCCESS = 0x3,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Fields {
|
||||||
|
enum CommonObj : long
|
||||||
|
{
|
||||||
|
id = 0x00,
|
||||||
|
tile = 0x04,
|
||||||
|
x = 0x08,
|
||||||
|
y = 0x0C,
|
||||||
|
sx = 0x10,
|
||||||
|
sy = 0x14,
|
||||||
|
frm = 0x18,
|
||||||
|
rotation = 0x1C,
|
||||||
|
artFid = 0x20,
|
||||||
|
flags = 0x24,
|
||||||
|
elevation = 0x28,
|
||||||
|
inventory = 0x2C,
|
||||||
|
protoId = 0x64,
|
||||||
|
cid = 0x68,
|
||||||
|
lightDistance = 0x6C,
|
||||||
|
lightIntensity = 0x70,
|
||||||
|
outline = 0x74,
|
||||||
|
scriptId = 0x78,
|
||||||
|
owner = 0x7C,
|
||||||
|
scriptIndex = 0x80,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CritterObj : long
|
||||||
|
{
|
||||||
|
reaction = 0x38,
|
||||||
|
combatState = 0x3C,
|
||||||
|
movePoints = 0x40,
|
||||||
|
damageFlags = 0x44,
|
||||||
|
damageLastTurn = 0x48,
|
||||||
|
aiPacket = 0x4C,
|
||||||
|
teamNum = 0x50,
|
||||||
|
whoHitMe = 0x54,
|
||||||
|
health = 0x58,
|
||||||
|
rads = 0x5C,
|
||||||
|
poison = 0x60,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ItemObj : long
|
||||||
|
{
|
||||||
|
updatedFlags = 0x38,
|
||||||
|
charges = 0x3C,
|
||||||
|
ammoPid = 0x40,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,12 @@ WRAP_WATCOM_FUNC0(long, intface_is_item_right_hand)
|
|||||||
WRAP_WATCOM_FUNC0(void, intface_toggle_item_state)
|
WRAP_WATCOM_FUNC0(void, intface_toggle_item_state)
|
||||||
WRAP_WATCOM_FUNC0(void, intface_use_item)
|
WRAP_WATCOM_FUNC0(void, intface_use_item)
|
||||||
WRAP_WATCOM_FUNC0(long, is_pc_sneak_working)
|
WRAP_WATCOM_FUNC0(long, is_pc_sneak_working)
|
||||||
WRAP_WATCOM_FUNC1(long, item_w_max_ammo, GameObject*, item)
|
WRAP_WATCOM_FUNC1(long, item_w_anim_code, GameObject*, item)
|
||||||
|
WRAP_WATCOM_FUNC2(long, item_w_anim_weap, GameObject*, item, DWORD, hitMode)
|
||||||
|
WRAP_WATCOM_FUNC2(long, item_w_compute_ammo_cost, GameObject*, item, DWORD*, rounds)
|
||||||
WRAP_WATCOM_FUNC1(long, item_w_curr_ammo, GameObject*, item)
|
WRAP_WATCOM_FUNC1(long, item_w_curr_ammo, GameObject*, item)
|
||||||
|
WRAP_WATCOM_FUNC1(long, item_w_rounds, GameObject*, item)
|
||||||
|
WRAP_WATCOM_FUNC1(long, item_w_max_ammo, GameObject*, item)
|
||||||
WRAP_WATCOM_FUNC1(long, item_weight, GameObject*, item)
|
WRAP_WATCOM_FUNC1(long, item_weight, GameObject*, item)
|
||||||
// returns light level at given tile
|
// returns light level at given tile
|
||||||
WRAP_WATCOM_FUNC2(long, light_get_tile, long, elevation, long, tileNum)
|
WRAP_WATCOM_FUNC2(long, light_get_tile, long, elevation, long, tileNum)
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ struct GameObject {
|
|||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
char gap_38[4];
|
char updatedFlags[4];
|
||||||
// for weapons - ammo in magazine, for ammo - amount of ammo in last ammo pack
|
// for weapons - ammo in magazine, for ammo - amount of ammo in last ammo pack
|
||||||
long charges;
|
long charges;
|
||||||
// current type of ammo loaded in magazine
|
// current type of ammo loaded in magazine
|
||||||
@@ -151,8 +151,8 @@ struct ComputeAttackResult {
|
|||||||
GameObject* target;
|
GameObject* target;
|
||||||
long targetTile;
|
long targetTile;
|
||||||
long bodyPart;
|
long bodyPart;
|
||||||
long damage;
|
long targetDamage;
|
||||||
long flags;
|
long targetFlags;
|
||||||
long knockbackValue;
|
long knockbackValue;
|
||||||
GameObject* mainTarget;
|
GameObject* mainTarget;
|
||||||
long numExtras;
|
long numExtras;
|
||||||
|
|||||||
+63
-33
@@ -7,6 +7,7 @@
|
|||||||
namespace sfall
|
namespace sfall
|
||||||
{
|
{
|
||||||
using namespace fo;
|
using namespace fo;
|
||||||
|
using namespace Fields;
|
||||||
|
|
||||||
DWORD WeightOnBody = 0;
|
DWORD WeightOnBody = 0;
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ skip:
|
|||||||
|
|
||||||
static void __declspec(naked) protinst_default_use_item_hack() {
|
static void __declspec(naked) protinst_default_use_item_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
mov eax, dword ptr [edx+0x64] // eax = target pid
|
mov eax, dword ptr [edx + protoId] // eax = target pid
|
||||||
cmp eax, PID_DRIVABLE_CAR
|
cmp eax, PID_DRIVABLE_CAR
|
||||||
je isCar
|
je isCar
|
||||||
cmp eax, PID_CAR_TRUNK
|
cmp eax, PID_CAR_TRUNK
|
||||||
@@ -300,7 +301,7 @@ static void __declspec(naked) invenWieldFunc_item_get_type_hook() {
|
|||||||
call fo::funcoffs::item_remove_mult_
|
call fo::funcoffs::item_remove_mult_
|
||||||
xchg ebx, eax
|
xchg ebx, eax
|
||||||
mov eax, esi
|
mov eax, esi
|
||||||
test cl, 0x2 // Right hand?
|
test cl, INVEN_TYPE_LEFT_HAND // Right hand?
|
||||||
jz leftHand // No
|
jz leftHand // No
|
||||||
call fo::funcoffs::inven_right_hand_
|
call fo::funcoffs::inven_right_hand_
|
||||||
jmp removeFlag
|
jmp removeFlag
|
||||||
@@ -543,7 +544,7 @@ static void __declspec(naked) drop_ammo_into_weapon_hook() {
|
|||||||
mov edx, [esp+0x24+4] // from_slot
|
mov edx, [esp+0x24+4] // from_slot
|
||||||
cmp edx, 1006 // Hands?
|
cmp edx, 1006 // Hands?
|
||||||
jge skip // Yes
|
jge skip // Yes
|
||||||
lea edx, [eax+0x2C] // Inventory
|
lea edx, [eax + inventory] // Inventory
|
||||||
mov ecx, [edx] // itemsCount
|
mov ecx, [edx] // itemsCount
|
||||||
jcxz skip // inventory is empty (another excess check, but leave it)
|
jcxz skip // inventory is empty (another excess check, but leave it)
|
||||||
mov edx, [edx+8] // FirstItem
|
mov edx, [edx+8] // FirstItem
|
||||||
@@ -617,13 +618,13 @@ end:
|
|||||||
static void __declspec(naked) action_melee_hack() {
|
static void __declspec(naked) action_melee_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
mov edx, 0x4113DC
|
mov edx, 0x4113DC
|
||||||
mov ebx, [eax+0x20] // objStruct->FID
|
mov ebx, [eax + artFid] // objStruct->FID
|
||||||
and ebx, 0x0F000000
|
and ebx, 0x0F000000
|
||||||
sar ebx, 0x18
|
sar ebx, 0x18
|
||||||
cmp ebx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
|
cmp ebx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
|
||||||
jne end // if object not a critter leave jump condition flags
|
jne end // if object not a critter leave jump condition flags
|
||||||
// set to skip dodge animation
|
// set to skip dodge animation
|
||||||
test byte ptr [eax+0x44], 0x3 // (original code) DAM_KNOCKED_OUT or DAM_KNOCKED_DOWN
|
test byte ptr [eax + damageFlags], DAM_KNOCKED_OUT or DAM_KNOCKED_DOWN // (original code)
|
||||||
jnz end
|
jnz end
|
||||||
mov edx, 0x4113FE
|
mov edx, 0x4113FE
|
||||||
end:
|
end:
|
||||||
@@ -634,13 +635,13 @@ end:
|
|||||||
static void __declspec(naked) action_ranged_hack() {
|
static void __declspec(naked) action_ranged_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
mov edx, 0x411B6D
|
mov edx, 0x411B6D
|
||||||
mov ebx, [eax+0x20] // objStruct->FID
|
mov ebx, [eax + artFid] // objStruct->FID
|
||||||
and ebx, 0x0F000000
|
and ebx, 0x0F000000
|
||||||
sar ebx, 0x18
|
sar ebx, 0x18
|
||||||
cmp ebx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
|
cmp ebx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
|
||||||
jne end // if object not a critter leave jump condition flags
|
jne end // if object not a critter leave jump condition flags
|
||||||
// set to skip dodge animation
|
// set to skip dodge animation
|
||||||
test byte ptr [eax+0x44], 0x3 // (original code) DAM_KNOCKED_OUT or DAM_KNOCKED_DOWN
|
test byte ptr [eax + damageFlags], DAM_KNOCKED_OUT or DAM_KNOCKED_DOWN // (original code)
|
||||||
jnz end
|
jnz end
|
||||||
mov edx, 0x411BD2
|
mov edx, 0x411BD2
|
||||||
end:
|
end:
|
||||||
@@ -650,7 +651,7 @@ end:
|
|||||||
|
|
||||||
static void __declspec(naked) set_new_results_hack() {
|
static void __declspec(naked) set_new_results_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
test ah, 0x1 // DAM_KNOCKED_OUT?
|
test ah, DAM_KNOCKED_OUT // DAM_KNOCKED_OUT?
|
||||||
jz end // No
|
jz end // No
|
||||||
mov eax, esi
|
mov eax, esi
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
@@ -666,12 +667,12 @@ end:
|
|||||||
static void __declspec(naked) critter_wake_clear_hack() {
|
static void __declspec(naked) critter_wake_clear_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
jne end // This is not a critter
|
jne end // This is not a critter
|
||||||
mov dl, [esi+0x44]
|
mov dl, [esi + damageFlags]
|
||||||
test dl, 0x80 // DAM_DEAD?
|
test dl, DAM_DEAD // DAM_DEAD?
|
||||||
jnz end // This is a corpse
|
jnz end // This is a corpse
|
||||||
and dl, 0xFE // Unset DAM_KNOCKED_OUT
|
and dl, ~DAM_KNOCKED_OUT // 0xFE Unset DAM_KNOCKED_OUT
|
||||||
or dl, 0x2 // Set DAM_KNOCKED_DOWN
|
or dl, DAM_KNOCKED_DOWN // Set DAM_KNOCKED_DOWN
|
||||||
mov [esi+0x44], dl
|
mov [esi + damageFlags], dl
|
||||||
end:
|
end:
|
||||||
xor eax, eax
|
xor eax, eax
|
||||||
inc eax
|
inc eax
|
||||||
@@ -686,11 +687,11 @@ static void __declspec(naked) obj_load_func_hack() {
|
|||||||
__asm {
|
__asm {
|
||||||
test byte ptr [eax+0x25], 0x4 // Temp_
|
test byte ptr [eax+0x25], 0x4 // Temp_
|
||||||
jnz end
|
jnz end
|
||||||
mov edi, [eax+0x64]
|
mov edi, [eax + protoId]
|
||||||
shr edi, 0x18
|
shr edi, 0x18
|
||||||
cmp edi, OBJ_TYPE_CRITTER
|
cmp edi, OBJ_TYPE_CRITTER
|
||||||
jne skip
|
jne skip
|
||||||
test byte ptr [eax+0x44], 0x2 // DAM_KNOCKED_DOWN?
|
test byte ptr [eax + damageFlags], DAM_KNOCKED_DOWN
|
||||||
jz clear // No
|
jz clear // No
|
||||||
pushad
|
pushad
|
||||||
xor ecx, ecx
|
xor ecx, ecx
|
||||||
@@ -701,7 +702,7 @@ static void __declspec(naked) obj_load_func_hack() {
|
|||||||
call fo::funcoffs::queue_add_
|
call fo::funcoffs::queue_add_
|
||||||
popad
|
popad
|
||||||
clear:
|
clear:
|
||||||
and word ptr [eax+0x44], 0x7FFD // not (DAM_LOSE_TURN or DAM_KNOCKED_DOWN)
|
and word ptr [eax + damageFlags], ~(DAM_LOSE_TURN or DAM_KNOCKED_DOWN) // 0x7FFD
|
||||||
skip:
|
skip:
|
||||||
push 0x488F14
|
push 0x488F14
|
||||||
retn
|
retn
|
||||||
@@ -713,7 +714,7 @@ end:
|
|||||||
|
|
||||||
static void __declspec(naked) partyMemberPrepLoadInstance_hook() {
|
static void __declspec(naked) partyMemberPrepLoadInstance_hook() {
|
||||||
__asm {
|
__asm {
|
||||||
and word ptr [eax+0x44], 0x7FFD // not (DAM_LOSE_TURN or DAM_KNOCKED_DOWN)
|
and word ptr [eax + damageFlags], ~(DAM_LOSE_TURN or DAM_KNOCKED_DOWN) // 0x7FFD
|
||||||
jmp fo::funcoffs::dude_stand_
|
jmp fo::funcoffs::dude_stand_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -721,10 +722,10 @@ static void __declspec(naked) partyMemberPrepLoadInstance_hook() {
|
|||||||
static void __declspec(naked) combat_ctd_init_hack() {
|
static void __declspec(naked) combat_ctd_init_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
mov [esi+0x24], eax // ctd.targetTile
|
mov [esi+0x24], eax // ctd.targetTile
|
||||||
mov eax, [ebx+0x54] // pobj.who_hit_me
|
mov eax, [ebx + whoHitMe] // pobj.who_hit_me
|
||||||
inc eax
|
inc eax
|
||||||
jnz end
|
jnz end
|
||||||
mov [ebx+0x54], eax // pobj.who_hit_me
|
mov [ebx + whoHitMe], eax // pobj.who_hit_me
|
||||||
end:
|
end:
|
||||||
push 0x422F11
|
push 0x422F11
|
||||||
retn
|
retn
|
||||||
@@ -737,7 +738,7 @@ static void __declspec(naked) obj_save_hack() {
|
|||||||
jz end
|
jz end
|
||||||
dec eax
|
dec eax
|
||||||
mov edx, [esp+0x1C] // combat_data
|
mov edx, [esp+0x1C] // combat_data
|
||||||
mov eax, [eax+0x68] // pobj.who_hit_me.cid
|
mov eax, [eax + cid] // pobj.who_hit_me.cid
|
||||||
test byte ptr ds:[FO_VAR_combat_state], 1 // in combat?
|
test byte ptr ds:[FO_VAR_combat_state], 1 // in combat?
|
||||||
jz clear // No
|
jz clear // No
|
||||||
cmp dword ptr [edx], 0 // in combat?
|
cmp dword ptr [edx], 0 // in combat?
|
||||||
@@ -757,7 +758,7 @@ static void __declspec(naked) action_explode_hack() {
|
|||||||
using fo::ScriptProc::destroy_p_proc;
|
using fo::ScriptProc::destroy_p_proc;
|
||||||
__asm {
|
__asm {
|
||||||
mov edx, destroy_p_proc
|
mov edx, destroy_p_proc
|
||||||
mov eax, [esi+0x78] // pobj.sid
|
mov eax, [esi + scriptId] // pobj.sid
|
||||||
call fo::funcoffs::exec_script_proc_
|
call fo::funcoffs::exec_script_proc_
|
||||||
xor edx, edx
|
xor edx, edx
|
||||||
dec edx
|
dec edx
|
||||||
@@ -777,9 +778,9 @@ static void __declspec(naked) action_explode_hack1() {
|
|||||||
|
|
||||||
static void __declspec(naked) barter_attempt_transaction_hack() {
|
static void __declspec(naked) barter_attempt_transaction_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
cmp dword ptr [eax+0x64], PID_ACTIVE_GEIGER_COUNTER
|
cmp dword ptr [eax + protoId], PID_ACTIVE_GEIGER_COUNTER
|
||||||
je found
|
je found
|
||||||
cmp dword ptr [eax+0x64], PID_ACTIVE_STEALTH_BOY
|
cmp dword ptr [eax + protoId], PID_ACTIVE_STEALTH_BOY
|
||||||
je found
|
je found
|
||||||
mov eax, 0x474D34
|
mov eax, 0x474D34
|
||||||
jmp eax
|
jmp eax
|
||||||
@@ -812,10 +813,10 @@ static void __declspec(naked) combat_hack() {
|
|||||||
skip:
|
skip:
|
||||||
pop edx
|
pop edx
|
||||||
xchg edx, eax // eax = source, edx = Max action points
|
xchg edx, eax // eax = source, edx = Max action points
|
||||||
mov [eax+0x40], edx // pobj.curr_mp
|
mov [eax + movePoints], edx // pobj.curr_mp
|
||||||
test byte ptr ds:[FO_VAR_combat_state], 1 // in combat?
|
test byte ptr ds:[FO_VAR_combat_state], 1 // in combat?
|
||||||
jz end // No
|
jz end // No
|
||||||
mov edx, [eax+0x68] // pobj.cid
|
mov edx, [eax + cid] // pobj.cid
|
||||||
cmp edx, -1
|
cmp edx, -1
|
||||||
je end
|
je end
|
||||||
push eax
|
push eax
|
||||||
@@ -924,19 +925,19 @@ static void __declspec(naked) switch_hand_hack() {
|
|||||||
mov eax, ds:[FO_VAR_inven_dude]
|
mov eax, ds:[FO_VAR_inven_dude]
|
||||||
push eax
|
push eax
|
||||||
mov [edi], ebp
|
mov [edi], ebp
|
||||||
inc ecx
|
inc ecx // if ecx == -1
|
||||||
jz skip
|
jz skip
|
||||||
xor ebx, ebx
|
xor ebx, ebx
|
||||||
inc ebx
|
inc ebx
|
||||||
mov edx, ebp
|
mov edx, ebp
|
||||||
call fo::funcoffs::item_remove_mult_
|
call fo::funcoffs::item_remove_mult_
|
||||||
skip:
|
skip:
|
||||||
pop edx
|
pop edx // _inven_dude
|
||||||
mov eax, ebp
|
mov eax, ebp
|
||||||
call fo::funcoffs::item_get_type_
|
call fo::funcoffs::item_get_type_
|
||||||
cmp eax, item_type_container
|
cmp eax, item_type_container
|
||||||
jne end
|
jne end
|
||||||
mov [ebp+0x7C], edx // iobj.owner = _inven_dude
|
mov [ebp + owner], edx // iobj.owner = _inven_dude
|
||||||
end:
|
end:
|
||||||
pop ebp
|
pop ebp
|
||||||
pop edi
|
pop edi
|
||||||
@@ -949,7 +950,7 @@ static void __declspec(naked) inven_item_wearing() {
|
|||||||
__asm {
|
__asm {
|
||||||
mov esi, ds:[FO_VAR_inven_dude]
|
mov esi, ds:[FO_VAR_inven_dude]
|
||||||
xchg ebx, eax // ebx = source
|
xchg ebx, eax // ebx = source
|
||||||
mov eax, [esi+0x20]
|
mov eax, [esi + artFid]
|
||||||
and eax, 0xF000000
|
and eax, 0xF000000
|
||||||
sar eax, 0x18
|
sar eax, 0x18
|
||||||
test eax, eax // check if object FID type flag is set to item
|
test eax, eax // check if object FID type flag is set to item
|
||||||
@@ -962,7 +963,7 @@ static void __declspec(naked) inven_item_wearing() {
|
|||||||
call fo::funcoffs::obj_top_environment_
|
call fo::funcoffs::obj_top_environment_
|
||||||
test eax, eax // has an owner?
|
test eax, eax // has an owner?
|
||||||
jz skip // No
|
jz skip // No
|
||||||
mov ecx, [eax+0x20]
|
mov ecx, [eax + artFid]
|
||||||
and ecx, 0xF000000
|
and ecx, 0xF000000
|
||||||
sar ecx, 0x18
|
sar ecx, 0x18
|
||||||
cmp ecx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
|
cmp ecx, OBJ_TYPE_CRITTER // check if object FID type flag is set to critter
|
||||||
@@ -1047,7 +1048,7 @@ static void __declspec(naked) combat_display_hack() {
|
|||||||
__asm {
|
__asm {
|
||||||
mov ebx, 0x42536B;
|
mov ebx, 0x42536B;
|
||||||
je end; // This is a critter
|
je end; // This is a critter
|
||||||
cmp dword ptr [ecx+0x78], -1; // Does the target have a script?
|
cmp dword ptr [ecx + scriptId], -1; // Does the target have a script?
|
||||||
jne end; // Yes
|
jne end; // Yes
|
||||||
mov ebx, 0x425413;
|
mov ebx, 0x425413;
|
||||||
end:
|
end:
|
||||||
@@ -1112,18 +1113,41 @@ map_leave:
|
|||||||
static void __declspec(naked) ai_move_steps_closer_hook() {
|
static void __declspec(naked) ai_move_steps_closer_hook() {
|
||||||
__asm {
|
__asm {
|
||||||
call fo::funcoffs::combat_turn_run_;
|
call fo::funcoffs::combat_turn_run_;
|
||||||
movzx dx, word ptr [esi + 0x44]; // combat_data.results
|
movzx dx, word ptr [esi + damageFlags]; // combat_data.results
|
||||||
test dx, DAM_DEAD or DAM_KNOCKED_OUT or DAM_LOSE_TURN;
|
test dx, DAM_DEAD or DAM_KNOCKED_OUT or DAM_LOSE_TURN;
|
||||||
jz end;
|
jz end;
|
||||||
mov [esi + 0x40], 0; // pobj.curr_mp (source reset ap)
|
mov [esi + movePoints], 0; // pobj.curr_mp (source reset ap)
|
||||||
end:
|
end:
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//zero damage insta death criticals fix (moved from compute_damage hook)
|
||||||
|
static void __fastcall InstantDeathFix(fo::ComputeAttackResult &ctd) {
|
||||||
|
if (ctd.targetDamage == 0 && (ctd.targetFlags & fo::DamageFlag::DAM_DEAD)) {
|
||||||
|
ctd.targetDamage++; // set 1 hp damage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const DWORD ComputeDamageRet = 0x424BA7;
|
||||||
|
static void __declspec(naked) compute_damage_hack() {
|
||||||
|
__asm {
|
||||||
|
mov ecx, esi; // ctd
|
||||||
|
call InstantDeathFix;
|
||||||
|
// overwritted engine code
|
||||||
|
add esp, 0x34;
|
||||||
|
pop ebp;
|
||||||
|
pop edi;
|
||||||
|
jmp ComputeDamageRet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BugFixes::init()
|
void BugFixes::init()
|
||||||
{
|
{
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (isDebug && (GetConfigInt("Debugging", "BugFixes", 1) == 0)) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
//if (GetConfigInt("Misc", "SharpshooterFix", 1)) {
|
//if (GetConfigInt("Misc", "SharpshooterFix", 1)) {
|
||||||
dlog("Applying Sharpshooter patch.", DL_INIT);
|
dlog("Applying Sharpshooter patch.", DL_INIT);
|
||||||
// http://www.nma-fallout.com/threads/fo2-engine-tweaks-sfall.178390/page-119#post-4050162
|
// http://www.nma-fallout.com/threads/fo2-engine-tweaks-sfall.178390/page-119#post-4050162
|
||||||
@@ -1436,6 +1460,12 @@ void BugFixes::init()
|
|||||||
// Fix for critters killed in combat by scripting still being able to move in their combat turn if the distance parameter
|
// Fix for critters killed in combat by scripting still being able to move in their combat turn if the distance parameter
|
||||||
// in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled
|
// in their AI packages is set to stay_close/charge, or NPCsTryToSpendExtraAP is enabled
|
||||||
HookCall(0x42A1A8, ai_move_steps_closer_hook); // 0x42B24D
|
HookCall(0x42A1A8, ai_move_steps_closer_hook); // 0x42B24D
|
||||||
|
|
||||||
|
// Fix instant death critical
|
||||||
|
dlog("Applying instant death fix.", DL_INIT);
|
||||||
|
MakeJump(0x424BA2, compute_damage_hack);
|
||||||
|
dlogr(" Done", DL_INIT);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ void HookScriptClear();
|
|||||||
void LoadHookScripts();
|
void LoadHookScripts();
|
||||||
|
|
||||||
extern DWORD initingHookScripts;
|
extern DWORD initingHookScripts;
|
||||||
extern void __declspec() AmmoCostHookWrapper();
|
extern int __fastcall AmmoCostHook_Script(DWORD hookType, fo::GameObject* weapon, DWORD* rounds);
|
||||||
void _stdcall RunHookScriptsAtProc(DWORD procId);
|
void _stdcall RunHookScriptsAtProc(DWORD procId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+52
-68
@@ -1,4 +1,4 @@
|
|||||||
/*
|
/*
|
||||||
* sfall
|
* sfall
|
||||||
* Copyright (C) 2011 Timeslip
|
* Copyright (C) 2011 Timeslip
|
||||||
*
|
*
|
||||||
@@ -37,23 +37,15 @@ static DWORD maxItemSize;
|
|||||||
static DWORD reloadWeaponKey = 0;
|
static DWORD reloadWeaponKey = 0;
|
||||||
static DWORD itemFastMoveKey = 0;
|
static DWORD itemFastMoveKey = 0;
|
||||||
|
|
||||||
long& GetActiveItemMode() {
|
|
||||||
return fo::var::itemButtonItems[fo::var::itemCurrentItem].mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
fo::GameObject* GetActiveItem() {
|
|
||||||
return fo::var::itemButtonItems[fo::var::itemCurrentItem].item;
|
|
||||||
}
|
|
||||||
|
|
||||||
void InventoryKeyPressedHook(DWORD dxKey, bool pressed, DWORD vKey) {
|
void InventoryKeyPressedHook(DWORD dxKey, bool pressed, DWORD vKey) {
|
||||||
// TODO: move this out into a script
|
// TODO: move this out into a script
|
||||||
if (pressed && reloadWeaponKey && dxKey == reloadWeaponKey && IsMapLoaded() && (GetLoopFlags() & ~(COMBAT | PCOMBAT)) == 0) {
|
if (pressed && reloadWeaponKey && dxKey == reloadWeaponKey && IsMapLoaded() && (GetLoopFlags() & ~(COMBAT | PCOMBAT)) == 0) {
|
||||||
DWORD maxAmmo, curAmmo;
|
DWORD maxAmmo, curAmmo;
|
||||||
fo::GameObject* item = GetActiveItem();
|
fo::GameObject* item = fo::GetActiveItem();
|
||||||
maxAmmo = fo::func::item_w_max_ammo(item);
|
maxAmmo = fo::func::item_w_max_ammo(item);
|
||||||
curAmmo = fo::func::item_w_curr_ammo(item);
|
curAmmo = fo::func::item_w_curr_ammo(item);
|
||||||
if (maxAmmo != curAmmo) {
|
if (maxAmmo != curAmmo) {
|
||||||
long ¤tMode = GetActiveItemMode();
|
long ¤tMode = fo::GetActiveItemMode();
|
||||||
long previusMode = currentMode;
|
long previusMode = currentMode;
|
||||||
currentMode = 5; // reload mode
|
currentMode = 5; // reload mode
|
||||||
fo::func::intface_use_item();
|
fo::func::intface_use_item();
|
||||||
@@ -450,66 +442,57 @@ static void __declspec(naked) inven_ap_cost_hook() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const DWORD add_check_for_item_ammo_cost_back = 0x4266EE;
|
static DWORD __fastcall add_check_for_item_ammo_cost(register fo::GameObject* weapon, DWORD hitMode) {
|
||||||
// adds check for weapons which require more than 1 ammo for single shot (super cattle prod & mega power fist)
|
DWORD rounds = 1;
|
||||||
static void __declspec(naked) add_check_for_item_ammo_cost() {
|
DWORD anim = fo::func::item_w_anim_weap(weapon, hitMode);
|
||||||
|
if (anim == fo::Animation::ANIM_fire_burst || anim == fo::Animation::ANIM_fire_continuous) {
|
||||||
|
rounds = fo::func::item_w_rounds(weapon);
|
||||||
|
}
|
||||||
|
|
||||||
|
AmmoCostHook_Script(1, weapon, &rounds);
|
||||||
|
|
||||||
|
DWORD currAmmo = fo::func::item_w_curr_ammo(weapon);
|
||||||
|
DWORD cost = (DWORD)ceilf((float)rounds / currAmmo); // get rounds cost from hook
|
||||||
|
return (cost > currAmmo) ? 0 : 1; // 0 - this will force "Out of ammo", 1 - this will force success (enough ammo)
|
||||||
|
}
|
||||||
|
|
||||||
|
// adds check for weapons which require more than 1 ammo for single shot (super cattle prod & mega power fist) and burst rounds
|
||||||
|
static void __declspec(naked) combat_check_bad_shot_hook() {
|
||||||
__asm {
|
__asm {
|
||||||
push edx
|
push edx;
|
||||||
push ebx
|
push ebx;
|
||||||
sub esp, 4
|
push ecx; // weapon
|
||||||
call fo::funcoffs::item_w_curr_ammo_
|
mov edx, edi; // hitMode
|
||||||
mov ebx, eax
|
call add_check_for_item_ammo_cost;
|
||||||
mov eax, ecx // weapon
|
pop ecx;
|
||||||
mov edx, esp
|
pop ebx;
|
||||||
mov dword ptr [esp], 1
|
pop edx;
|
||||||
pushad
|
retn;
|
||||||
push 1 // hook type
|
|
||||||
call AmmoCostHookWrapper
|
|
||||||
add esp, 4
|
|
||||||
popad
|
|
||||||
mov eax, [esp]
|
|
||||||
cmp eax, ebx
|
|
||||||
jle enoughammo
|
|
||||||
xor eax, eax // this will force "Out of ammo"
|
|
||||||
jmp end
|
|
||||||
enoughammo:
|
|
||||||
mov eax, 1 // this will force success
|
|
||||||
end:
|
|
||||||
add esp, 4
|
|
||||||
pop ebx
|
|
||||||
pop edx
|
|
||||||
jmp add_check_for_item_ammo_cost_back; // jump back
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const DWORD divide_burst_rounds_by_ammo_cost_back = 0x4234B9;
|
static DWORD __fastcall divide_burst_rounds_by_ammo_cost(fo::GameObject* weapon, register DWORD currAmmo, DWORD burstRounds) {
|
||||||
static void __declspec(naked) divide_burst_rounds_by_ammo_cost() {
|
DWORD rounds = burstRounds; // rounds in burst (количество патронов израсходуемое в очереди)
|
||||||
|
|
||||||
|
AmmoCostHook_Script(2, weapon, &rounds);
|
||||||
|
|
||||||
|
DWORD cost = burstRounds * rounds; // so much ammo is required for this burst (количество патронов в очереди умноженное на 1 или на значения возвращаемое из скрипта)
|
||||||
|
if (cost > currAmmo) cost = currAmmo; // if cost ammo more than current ammo, set it to current
|
||||||
|
|
||||||
|
return (cost / rounds); // divide back to get proper number of rounds for damage calculations
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) compute_spray_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
// ecx - current ammo, eax - burst rounds; need to set ebp
|
push edx; // weapon
|
||||||
push edx
|
push ecx; // current ammo in weapon
|
||||||
sub esp, 4
|
xchg ecx, edx;
|
||||||
mov ebp, eax
|
push eax; // eax - rounds in burst attack, need to set ebp
|
||||||
mov eax, edx // weapon
|
call divide_burst_rounds_by_ammo_cost;
|
||||||
mov dword ptr [esp], 1
|
mov ebp, eax; // overwriten code (в ebp устанавливаем правильное значение)
|
||||||
mov edx, esp // *rounds
|
pop ecx;
|
||||||
pushad
|
pop edx;
|
||||||
push 2
|
retn;
|
||||||
call AmmoCostHookWrapper
|
|
||||||
add esp, 4
|
|
||||||
popad
|
|
||||||
mov edx, 0
|
|
||||||
mov eax, ebp // rounds in burst
|
|
||||||
imul dword ptr [esp] // so much ammo is required for this burst
|
|
||||||
cmp eax, ecx
|
|
||||||
jle skip
|
|
||||||
mov eax, ecx // if more than current ammo, set it to current
|
|
||||||
skip:
|
|
||||||
idiv dword ptr [esp] // divide back to get proper number of rounds for damage calculations
|
|
||||||
mov ebp, eax
|
|
||||||
add esp, 4
|
|
||||||
pop edx
|
|
||||||
// end overwriten code
|
|
||||||
jmp divide_burst_rounds_by_ammo_cost_back; // jump back
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -868,8 +851,9 @@ void Inventory::init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (GetConfigInt("Misc", "CheckWeaponAmmoCost", 0)) {
|
if (GetConfigInt("Misc", "CheckWeaponAmmoCost", 0)) {
|
||||||
MakeJump(0x4266E9, add_check_for_item_ammo_cost);
|
HookCall(0x4266E9, combat_check_bad_shot_hook);
|
||||||
MakeJump(0x4234B3, divide_burst_rounds_by_ammo_cost);
|
MakeCall(0x4234B3, compute_spray_hack);
|
||||||
|
SafeWrite8(0x4234B8, 0x90);
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadWeaponKey = GetConfigInt("Input", "ReloadWeaponKey", 0);
|
reloadWeaponKey = GetConfigInt("Input", "ReloadWeaponKey", 0);
|
||||||
|
|||||||
@@ -367,9 +367,9 @@ static void __declspec(naked) objCanSeeObj_ShootThru_Fix() {//(EAX *objStruct, E
|
|||||||
|
|
||||||
static DWORD __fastcall GetWeaponSlotMode(DWORD itemPtr, DWORD mode) {
|
static DWORD __fastcall GetWeaponSlotMode(DWORD itemPtr, DWORD mode) {
|
||||||
int slot = (mode > 0) ? 1 : 0;
|
int slot = (mode > 0) ? 1 : 0;
|
||||||
auto itemButton = fo::var::itemButtonItems;
|
fo::ItemButtonItem* itemButton = &fo::var::itemButtonItems[slot];
|
||||||
if ((DWORD)itemButton[slot].item == itemPtr) {
|
if ((DWORD)itemButton->item == itemPtr) {
|
||||||
int slotMode = itemButton[slot].mode;
|
int slotMode = itemButton->mode;
|
||||||
if (slotMode == 3 || slotMode == 4) {
|
if (slotMode == 3 || slotMode == 4) {
|
||||||
mode++;
|
mode++;
|
||||||
}
|
}
|
||||||
@@ -407,7 +407,7 @@ static void __fastcall SwapHandSlots(fo::GameObject* item, DWORD* toSlot) {
|
|||||||
memcpy(item, rightSlot, 0x14);
|
memcpy(item, rightSlot, 0x14);
|
||||||
item[0].primaryAttack = fo::AttackType::ATKTYPE_LWEAPON_PRIMARY;
|
item[0].primaryAttack = fo::AttackType::ATKTYPE_LWEAPON_PRIMARY;
|
||||||
item[0].secondaryAttack = fo::AttackType::ATKTYPE_LWEAPON_SECONDARY;
|
item[0].secondaryAttack = fo::AttackType::ATKTYPE_LWEAPON_SECONDARY;
|
||||||
slot = leftSlot;// Rslot > Lslot;
|
slot = leftSlot; // Rslot > Lslot
|
||||||
} else {
|
} else {
|
||||||
memcpy(item, leftSlot, 0x14);
|
memcpy(item, leftSlot, 0x14);
|
||||||
item[0].primaryAttack = fo::AttackType::ATKTYPE_RWEAPON_PRIMARY;
|
item[0].primaryAttack = fo::AttackType::ATKTYPE_RWEAPON_PRIMARY;
|
||||||
@@ -416,19 +416,14 @@ static void __fastcall SwapHandSlots(fo::GameObject* item, DWORD* toSlot) {
|
|||||||
}
|
}
|
||||||
memcpy(slot, item, 0x14);
|
memcpy(slot, item, 0x14);
|
||||||
} else { // swap slot
|
} else { // swap slot
|
||||||
fo::ItemButtonItem swapLBuf[1];
|
auto swapBuf = fo::var::itemButtonItems;
|
||||||
fo::ItemButtonItem swapRBuf[1];
|
swapBuf[0].primaryAttack = fo::AttackType::ATKTYPE_RWEAPON_PRIMARY;
|
||||||
|
swapBuf[0].secondaryAttack = fo::AttackType::ATKTYPE_RWEAPON_SECONDARY;
|
||||||
|
swapBuf[1].primaryAttack = fo::AttackType::ATKTYPE_LWEAPON_PRIMARY;
|
||||||
|
swapBuf[1].secondaryAttack = fo::AttackType::ATKTYPE_LWEAPON_SECONDARY;
|
||||||
|
|
||||||
memcpy(swapLBuf, leftSlot, 0x14);
|
memcpy(leftSlot, &swapBuf[1], 0x14); // buf Rslot > Lslot
|
||||||
memcpy(swapRBuf, rightSlot, 0x14);
|
memcpy(rightSlot, &swapBuf[0], 0x14); // buf Lslot > Rslot
|
||||||
|
|
||||||
swapLBuf[0].primaryAttack = fo::AttackType::ATKTYPE_RWEAPON_PRIMARY;
|
|
||||||
swapLBuf[0].secondaryAttack = fo::AttackType::ATKTYPE_RWEAPON_SECONDARY;
|
|
||||||
swapRBuf[0].primaryAttack = fo::AttackType::ATKTYPE_LWEAPON_PRIMARY;
|
|
||||||
swapRBuf[0].secondaryAttack = fo::AttackType::ATKTYPE_LWEAPON_SECONDARY;
|
|
||||||
|
|
||||||
memcpy(leftSlot, swapRBuf, 0x14); // buf Rslot > Lslot;
|
|
||||||
memcpy(rightSlot, swapLBuf, 0x14); // buf Lslot > Rslot;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user