Backported CritterInvSizeLimitMode related fixes/improvements from the develop branch:

* Changed item_total_weight/item_c_curr_size engine functions to return the weight and size of equipped(hidden) items on NPCs when exchanging/bartering items.
* Fixed CritterInvSizeLimitMode not properly checking the weight of equipped items when mode is set to 4+.
* Added inventory size check to "Take All" button.
* Added additional note to CritterInvSizeLimitMode in ddraw.ini, and changed CritterInvSizeLimit to its default value.
This commit is contained in:
NovaRain
2018-09-20 09:48:27 +08:00
parent 9a4cbd4fa9
commit 1679f7c59d
7 changed files with 183 additions and 99 deletions
+2 -2
View File
@@ -468,10 +468,10 @@ BoostScriptDialogLimit=0
;These options modify the checks to see if a critter can carry an additional item, changing which items are counted towards the weight limit and adding an additional size check ;These options modify the checks to see if a critter can carry an additional item, changing which items are counted towards the weight limit and adding an additional size check
;Set the mode to 0 to disable the size check, 1 to apply to the PC only, 2 to apply to the PC and party members, or 3 to apply to all critters ;Set the mode to 0 to disable the size check, 1 to apply to the PC only, 2 to apply to the PC and party members, or 3 to apply to all critters
;Only the PC uses CritterInvSizeLimit. Other critters will use the extra unused stat (STAT_unused = 10) ;Only the PC uses CritterInvSizeLimit. Other critters will use the unused stat (STAT_unused = 10) or have the size limit of 100 if the stat is not set
;Add 4 to the mode to limit the weight check to used items only ;Add 4 to the mode to limit the weight check to used items only
CritterInvSizeLimitMode=0 CritterInvSizeLimitMode=0
CritterInvSizeLimit=200 CritterInvSizeLimit=100
;Some bit flags to alter behaviour of the motion sensor ;Some bit flags to alter behaviour of the motion sensor
;1 - Allow sensor use on automap when motion sensor is in pack rather than hands ;1 - Allow sensor use on automap when motion sensor is in pack rather than hands
+136 -61
View File
@@ -5,7 +5,15 @@
#include "FalloutEngine.h" #include "FalloutEngine.h"
#include "ScriptExtender.h" #include "ScriptExtender.h"
DWORD WeightOnBody = 0; static DWORD critterBody = 0;
static DWORD sizeOnBody = 0;
static DWORD weightOnBody = 0;
void ResetBodyState() {
_asm mov critterBody, 0;
_asm mov sizeOnBody, 0;
_asm mov weightOnBody, 0;
}
static void __declspec(naked) SharpShooterFix() { static void __declspec(naked) SharpShooterFix() {
__asm { __asm {
@@ -394,84 +402,145 @@ end:
} }
} }
// Calculate weight & size of equipped items
static void __declspec(naked) loot_container_hack() { static void __declspec(naked) loot_container_hack() {
__asm { __asm {
mov eax, [esp+0x114+0x4] mov critterBody, ebp; // target
test eax, eax push esi;
jz noLeftWeapon mov esi, [esp + 0x114 + 8]; // item lhand
call item_weight_ mov sizeOnBody, esi;
mov eax, esi;
test esi, esi;
jz noLeftWeapon;
call item_size_;
mov sizeOnBody, eax;
mov eax, esi;
call item_weight_;
noLeftWeapon: noLeftWeapon:
mov WeightOnBody, eax mov weightOnBody, eax;
mov eax, [esp+0x118+0x4] mov esi, [esp + 0x118 + 8]; // item rhand
test eax, eax test esi, esi;
jz noRightWeapon jz noRightWeapon;
call item_weight_ mov eax, esi;
call item_size_;
add sizeOnBody, eax;
mov eax, esi;
call item_weight_;
add weightOnBody, eax;
noRightWeapon: noRightWeapon:
add WeightOnBody, eax mov esi, [esp + 0x11C + 8]; // item armor
mov eax, [esp+0x11C+0x4] test esi, esi;
test eax, eax jz noArmor;
jz noArmor mov eax, esi;
call item_weight_ call item_size_;
add sizeOnBody, eax;
mov eax, esi;
call item_weight_;
add weightOnBody, eax;
noArmor: noArmor:
add WeightOnBody, eax mov esi, [esp + 0xF8 + 8]; // check JESSE_CONTAINER
xor eax, eax mov eax, esi;
inc eax call item_c_curr_size_;
inc eax add sizeOnBody, eax;
retn mov eax, esi;
call item_total_weight_;
add weightOnBody, eax;
pop esi;
mov eax, 2; // overwritten code
retn;
} }
} }
static void __declspec(naked) barter_inventory_hack() { static void __declspec(naked) barter_inventory_hook() {
__asm { __asm {
mov eax, [esp+0x20+0x4] mov critterBody, eax; // target
test eax, eax call item_move_all_hidden_;
jz noArmor push esi;
call item_weight_ mov esi, [esp + 0x20 + 8]; // armor
mov sizeOnBody, esi;
mov eax, esi;
test eax, eax;
jz noArmor;
call item_size_;
mov sizeOnBody, eax
mov eax, esi;
call item_weight_;
noArmor: noArmor:
mov WeightOnBody, eax mov weightOnBody, eax;
mov eax, [esp+0x1C+0x4] mov esi, [esp + 0x1C + 8]; // weapon
test eax, eax test esi, esi;
jnz haveWeapon jnz haveWeapon;
cmp dword ptr ds:[_dialog_target_is_party], eax cmp ds:[_dialog_target_is_party], esi; // esi = 0
jne end // This is a party member jne skip; // This is a party member
mov eax, [esp+0x18+0x4] mov eax, [esp + 0x18 + 8]; // item_weapon
test eax, eax test eax, eax;
jz end jz skip;
haveWeapon: haveWeapon:
call item_weight_ mov eax, esi;
add WeightOnBody, eax call item_size_;
end: add sizeOnBody, eax;
mov ebx, PID_JESSE_CONTAINER mov eax, esi;
retn call item_weight_;
add weightOnBody, eax;
skip:
mov esi, [esp + 0x10 + 8]; // check JESSE_CONTAINER
mov eax, esi;
call item_c_curr_size_;
add sizeOnBody, eax
mov eax, esi;
call item_total_weight_;
add weightOnBody, eax
pop esi;
retn;
} }
} }
static void __declspec(naked) barter_attempt_transaction_hook() { // Add weightOnBody to item_total_weight_ function
static void __declspec(naked) item_total_weight_hack() {
__asm { __asm {
call stat_level_ // eax = Max weight xor edx, edx;
sub eax, WeightOnBody // Accounting for weight of target's equipped armor and weapon mov ebx, [edi]; // Inventory.inv_size
retn xor esi, esi;
//------
cmp eax, dword ptr ds:[_obj_dude]; // eax - source
jz skip;
cmp critterBody, eax; // if condition is true, then now it's exchanging/bartering with source object
cmovz esi, weightOnBody; // take the weight of target's equipped items into account
skip:
retn;
} }
} }
static DWORD Looting = 0; // Add sizeOnBody to item_c_curr_size_ function
static void __declspec(naked) move_inventory_hook() { static void __declspec(naked) item_c_curr_size_hack() {
__asm { __asm {
inc Looting xor esi, esi;
call move_inventory_ mov edx, [ecx]; // Inventory.inv_size
dec Looting xor edi, edi;
retn //------
cmp eax, dword ptr ds:[_obj_dude]; // eax - source
jz skip;
cmp critterBody, eax; // if condition is true, then now it's exchanging/bartering with source object
cmovz edi, sizeOnBody; // take the size of target's equipped items into account
skip:
retn;
} }
} }
static void __declspec(naked) item_add_mult_hook() { // simple hooks from 4.x LoadGameHook.cpp without new game mode flags
static void __declspec(naked) LootContainerWrapper() {
__asm { __asm {
call stat_level_ // eax = Max weight call loot_container_;
cmp Looting, 0 jmp ResetBodyState;
je end }
sub eax, WeightOnBody // Accounting for weight of target's equipped armor and weapon }
end:
retn static void __declspec(naked) BarterInventoryWrapper() {
__asm {
push [esp + 4];
call barter_inventory_;
call ResetBodyState;
retn 4;
} }
} }
@@ -1336,14 +1405,20 @@ void BugsInit()
HookCall(0x437B26, &StatButtonDown_hook); HookCall(0x437B26, &StatButtonDown_hook);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
// Fix for not counting in the weight of equipped items on NPC when stealing or bartering // Fix for not counting in the weight/size of equipped items on NPC when stealing or bartering
//if (GetPrivateProfileIntA("Misc", "NPCWeightFix", 1, ini)) { //if (GetPrivateProfileIntA("Misc", "NPCWeightFix", 1, ini)) {
dlog("Applying fix for not counting in weight of equipped items on NPC.", DL_INIT); dlog("Applying fix for not counting in weight of equipped items on NPC.", DL_INIT);
MakeCall(0x473B4E, loot_container_hack); MakeCall(0x473B4E, loot_container_hack);
MakeCall(0x47588A, barter_inventory_hack); HookCall(0x4758AB, barter_inventory_hook);
HookCall(0x474CB8, &barter_attempt_transaction_hook); MakeCall(0x477EAB, item_total_weight_hack);
HookCall(0x4742AD, &move_inventory_hook); SafeWrite8(0x477EB0, 0x90);
HookCall(0x4771B5, &item_add_mult_hook); MakeCall(0x479A2F, item_c_curr_size_hack);
SafeWrite8(0x479A34, 0x90);
// Reset object pointer after exiting loot/barter screens
HookCall(0x4746EC, LootContainerWrapper);
HookCall(0x4A4369, LootContainerWrapper);
HookCall(0x4A4565, LootContainerWrapper);
HookCall(0x4466C7, BarterInventoryWrapper);
dlogr(" Done", DL_INIT); dlogr(" Done", DL_INIT);
//} //}
+1 -1
View File
@@ -1,5 +1,5 @@
#pragma once #pragma once
extern DWORD WeightOnBody; extern void ResetBodyState();
void BugsInit(); void BugsInit();
+3
View File
@@ -247,6 +247,7 @@ const DWORD art_ptr_unlock_ = 0x419260;
const DWORD attack_crit_success_ = 0x423EB4; const DWORD attack_crit_success_ = 0x423EB4;
const DWORD automap_ = 0x41B8BC; const DWORD automap_ = 0x41B8BC;
const DWORD barter_compute_value_ = 0x474B2C; const DWORD barter_compute_value_ = 0x474B2C;
const DWORD barter_inventory_ = 0x4757F0;
const DWORD buf_to_buf_ = 0x4D36D4; const DWORD buf_to_buf_ = 0x4D36D4;
const DWORD check_death_ = 0x410814; const DWORD check_death_ = 0x410814;
const DWORD Check4Keys_ = 0x43F73C; const DWORD Check4Keys_ = 0x43F73C;
@@ -396,6 +397,7 @@ const DWORD item_m_cell_pid_ = 0x479454;
const DWORD item_m_dec_charges_ = 0x4795A4; const DWORD item_m_dec_charges_ = 0x4795A4;
const DWORD item_m_turn_off_ = 0x479898; const DWORD item_m_turn_off_ = 0x479898;
const DWORD item_move_all_ = 0x4776AC; const DWORD item_move_all_ = 0x4776AC;
const DWORD item_move_all_hidden_ = 0x4776E0;
const DWORD item_move_force_ = 0x4776A4; const DWORD item_move_force_ = 0x4776A4;
const DWORD item_mp_cost_ = 0x478040; const DWORD item_mp_cost_ = 0x478040;
const DWORD item_remove_mult_ = 0x477490; const DWORD item_remove_mult_ = 0x477490;
@@ -429,6 +431,7 @@ const DWORD loadColorTable_ = 0x4C78E4;
const DWORD LoadGame_ = 0x47C640; const DWORD LoadGame_ = 0x47C640;
const DWORD loadProgram_ = 0x4A3B74; const DWORD loadProgram_ = 0x4A3B74;
const DWORD LoadSlot_ = 0x47DC68; const DWORD LoadSlot_ = 0x47DC68;
const DWORD loot_container_ = 0x473904;
const DWORD main_game_loop_ = 0x480E48; const DWORD main_game_loop_ = 0x480E48;
const DWORD main_menu_hide_ = 0x481A00; const DWORD main_menu_hide_ = 0x481A00;
const DWORD main_menu_loop_ = 0x481AEC; const DWORD main_menu_loop_ = 0x481AEC;
+3
View File
@@ -426,6 +426,7 @@ extern const DWORD art_ptr_unlock_;
extern const DWORD attack_crit_success_; extern const DWORD attack_crit_success_;
extern const DWORD automap_; extern const DWORD automap_;
extern const DWORD barter_compute_value_; extern const DWORD barter_compute_value_;
extern const DWORD barter_inventory_;
extern const DWORD buf_to_buf_; extern const DWORD buf_to_buf_;
extern const DWORD check_death_; extern const DWORD check_death_;
extern const DWORD Check4Keys_; extern const DWORD Check4Keys_;
@@ -574,6 +575,7 @@ extern const DWORD item_m_cell_pid_;
extern const DWORD item_m_dec_charges_; extern const DWORD item_m_dec_charges_;
extern const DWORD item_m_turn_off_; extern const DWORD item_m_turn_off_;
extern const DWORD item_move_all_; extern const DWORD item_move_all_;
extern const DWORD item_move_all_hidden_;
extern const DWORD item_move_force_; extern const DWORD item_move_force_;
extern const DWORD item_mp_cost_; extern const DWORD item_mp_cost_;
extern const DWORD item_remove_mult_; extern const DWORD item_remove_mult_;
@@ -607,6 +609,7 @@ extern const DWORD loadColorTable_;
extern const DWORD LoadGame_; extern const DWORD LoadGame_;
extern const DWORD loadProgram_; // loads script from scripts/ folder by file name and returns pointer to it: char* <eax> - file name (w/o extension) extern const DWORD loadProgram_; // loads script from scripts/ folder by file name and returns pointer to it: char* <eax> - file name (w/o extension)
extern const DWORD LoadSlot_; extern const DWORD LoadSlot_;
extern const DWORD loot_container_;
extern const DWORD main_game_loop_; extern const DWORD main_game_loop_;
extern const DWORD main_menu_hide_; extern const DWORD main_menu_hide_;
extern const DWORD main_menu_loop_; extern const DWORD main_menu_loop_;
+36 -33
View File
@@ -92,32 +92,8 @@ void InventoryKeyPressedHook(DWORD dxKey, bool pressed, DWORD vKey) {
} }
} }
/*static DWORD _stdcall item_total_size(void* critter) {
//TODO: Don't really want to be overwriting stuff like this after init. Rewrite properly.
HookCall(0x477EBD, (void*)0x477B68);
HookCall(0x477EF6, (void*)0x477B68);
HookCall(0x477F12, (void*)0x477B68);
HookCall(0x477F2A, (void*)0x477B68);
DWORD result;
__asm {
mov eax, critter;
call item_total_weight_;
mov result, eax;
}
HookCall(0x477EBD, (void*)0x477B88);
HookCall(0x477EF6, (void*)0x477B88);
HookCall(0x477F12, (void*)0x477B88);
HookCall(0x477F2A, (void*)0x477B88);
return result;
}*/
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
static DWORD __stdcall sf_item_total_size(TGameObj* critter) { static DWORD __stdcall sf_item_total_size(TGameObj* critter) {
int totalSize; int totalSize;
__asm { __asm {
mov eax, critter; mov eax, critter;
@@ -127,17 +103,17 @@ static DWORD __stdcall sf_item_total_size(TGameObj* critter) {
if ((critter->artFID & 0xF000000) == (OBJ_TYPE_CRITTER << 24)) { if ((critter->artFID & 0xF000000) == (OBJ_TYPE_CRITTER << 24)) {
TGameObj* item = InvenRightHand(critter); TGameObj* item = InvenRightHand(critter);
if (item && !(item->flags & OBJFLAG_HELD_IN_RIGHT << 8)) { if (item && !(item->flags & 0x2000000)) {
totalSize += ItemSize(item); totalSize += ItemSize(item);
} }
TGameObj* itemL = InvenLeftHand(critter); TGameObj* itemL = InvenLeftHand(critter);
if (itemL && item != itemL && !(itemL->flags & OBJFLAG_HELD_IN_LEFT << 8)) { if (itemL && item != itemL && !(itemL->flags & 0x1000000)) {
totalSize += ItemSize(itemL); totalSize += ItemSize(itemL);
} }
item = InvenWorn(critter); item = InvenWorn(critter);
if (item && !(item->flags & OBJFLAG_WORN << 8)) { if (item && !(item->flags & 0x4000000)) {
totalSize += ItemSize(item); totalSize += ItemSize(item);
} }
} }
@@ -240,11 +216,11 @@ fail:
} }
} }
static int __fastcall BarterAttemptTransaction(TGameObj* critter, TGameObj* targetTable) { static int __fastcall BarterAttemptTransaction(TGameObj* critter, TGameObj* table) {
int size = CritterGetMaxSize(critter); int size = CritterGetMaxSize(critter);
if (size == 0) return 1; if (size == 0) return 1;
int sizeTable = sf_item_total_size(targetTable); int sizeTable = sf_item_total_size(table);
if (sizeTable == 0) return 1; if (sizeTable == 0) return 1;
size -= sf_item_total_size(critter); size -= sf_item_total_size(critter);
@@ -258,8 +234,8 @@ static __declspec(naked) void barter_attempt_transaction_hack_pc() {
/* cmp eax, edx */ /* cmp eax, edx */
jg fail; // if there's no available weight jg fail; // if there's no available weight
//------ //------
mov ecx, edi; mov ecx, edi; // source (pc)
mov edx, ebp; mov edx, ebp; // npc table
call BarterAttemptTransaction; call BarterAttemptTransaction;
test eax, eax; test eax, eax;
jz fail; jz fail;
@@ -277,8 +253,8 @@ static __declspec(naked) void barter_attempt_transaction_hack_pm() {
/* cmp eax, edx */ /* cmp eax, edx */
jg fail; // if there's no available weight jg fail; // if there's no available weight
//------ //------
mov ecx, ebx; mov ecx, ebx; // target (npc)
mov edx, esi; mov edx, esi; // pc table
call BarterAttemptTransaction; call BarterAttemptTransaction;
test eax, eax; test eax, eax;
jz fail; jz fail;
@@ -289,6 +265,26 @@ fail:
} }
} }
static __declspec(naked) void loot_container_hook_btn() {
__asm {
push ecx;
push edx; // source current weight
mov edx, eax; // target
mov ecx, [esp + 0x150 - 0x1C + 12]; // source
call BarterAttemptTransaction;
pop edx;
pop ecx;
test eax, eax;
jz fail;
mov eax, ebp; // target
jmp item_total_weight_;
fail:
mov eax, edx;
inc eax; // weight + 1
retn;
}
}
static char InvenFmt[32]; static char InvenFmt[32];
static const char* InvenFmt1 = "%s %d/%d %s %d/%d"; static const char* InvenFmt1 = "%s %d/%d %s %d/%d";
static const char* InvenFmt2 = "%s %d/%d"; static const char* InvenFmt2 = "%s %d/%d";
@@ -716,7 +712,11 @@ void InventoryInit() {
if (sizeLimitMode > 0 && sizeLimitMode <= 7) { if (sizeLimitMode > 0 && sizeLimitMode <= 7) {
if (sizeLimitMode >= 4) { if (sizeLimitMode >= 4) {
sizeLimitMode -= 4; sizeLimitMode -= 4;
// item_total_weight_ patch
SafeWrite8(0x477EB3, 0xEB); SafeWrite8(0x477EB3, 0xEB);
SafeWrite8(0x477EF5, 0);
SafeWrite8(0x477F11, 0);
SafeWrite8(0x477F29, 0);
} }
invSizeMaxLimit = GetPrivateProfileInt("Misc", "CritterInvSizeLimit", 100, ini); invSizeMaxLimit = GetPrivateProfileInt("Misc", "CritterInvSizeLimit", 100, ini);
@@ -730,6 +730,9 @@ void InventoryInit() {
SafeWrite16(0x474C7A, 0x9090); SafeWrite16(0x474C7A, 0x9090);
MakeJump(0x474C7C, barter_attempt_transaction_hack_pc); MakeJump(0x474C7C, barter_attempt_transaction_hack_pc);
// Check player's capacity when using "Take All" button
HookCall(0x47410B, loot_container_hook_btn);
// Display total weight/size on the inventory screen // Display total weight/size on the inventory screen
MakeJump(0x4725E0, display_stats_hack); MakeJump(0x4725E0, display_stats_hack);
SafeWrite32(0x4725FF, (DWORD)&InvenFmt); SafeWrite32(0x4725FF, (DWORD)&InvenFmt);