From 1679f7c59d7c28881ab86677ae0543bb6e74b8d6 Mon Sep 17 00:00:00 2001 From: NovaRain Date: Thu, 20 Sep 2018 09:48:27 +0800 Subject: [PATCH] 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. --- artifacts/ddraw.ini | 4 +- sfall/Bugs.cpp | 197 +++++++++++++++++++++++++++------------- sfall/Bugs.h | 2 +- sfall/FalloutEngine.cpp | 3 + sfall/FalloutEngine.h | 3 + sfall/Inventory.cpp | 69 +++++++------- sfall/LoadGameHook.cpp | 4 +- 7 files changed, 183 insertions(+), 99 deletions(-) diff --git a/artifacts/ddraw.ini b/artifacts/ddraw.ini index 73821070..76501368 100644 --- a/artifacts/ddraw.ini +++ b/artifacts/ddraw.ini @@ -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 ;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 CritterInvSizeLimitMode=0 -CritterInvSizeLimit=200 +CritterInvSizeLimit=100 ;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 diff --git a/sfall/Bugs.cpp b/sfall/Bugs.cpp index 13d29b1e..25f1acfe 100644 --- a/sfall/Bugs.cpp +++ b/sfall/Bugs.cpp @@ -5,7 +5,15 @@ #include "FalloutEngine.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() { __asm { @@ -394,84 +402,145 @@ end: } } +// Calculate weight & size of equipped items static void __declspec(naked) loot_container_hack() { __asm { - mov eax, [esp+0x114+0x4] - test eax, eax - jz noLeftWeapon - call item_weight_ + mov critterBody, ebp; // target + push esi; + mov esi, [esp + 0x114 + 8]; // item lhand + mov sizeOnBody, esi; + mov eax, esi; + test esi, esi; + jz noLeftWeapon; + call item_size_; + mov sizeOnBody, eax; + mov eax, esi; + call item_weight_; noLeftWeapon: - mov WeightOnBody, eax - mov eax, [esp+0x118+0x4] - test eax, eax - jz noRightWeapon - call item_weight_ + mov weightOnBody, eax; + mov esi, [esp + 0x118 + 8]; // item rhand + test esi, esi; + jz noRightWeapon; + mov eax, esi; + call item_size_; + add sizeOnBody, eax; + mov eax, esi; + call item_weight_; + add weightOnBody, eax; noRightWeapon: - add WeightOnBody, eax - mov eax, [esp+0x11C+0x4] - test eax, eax - jz noArmor - call item_weight_ + mov esi, [esp + 0x11C + 8]; // item armor + test esi, esi; + jz noArmor; + mov eax, esi; + call item_size_; + add sizeOnBody, eax; + mov eax, esi; + call item_weight_; + add weightOnBody, eax; noArmor: - add WeightOnBody, eax - xor eax, eax - inc eax - inc eax - retn + mov esi, [esp + 0xF8 + 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; + mov eax, 2; // overwritten code + retn; } } -static void __declspec(naked) barter_inventory_hack() { +static void __declspec(naked) barter_inventory_hook() { __asm { - mov eax, [esp+0x20+0x4] - test eax, eax - jz noArmor - call item_weight_ + mov critterBody, eax; // target + call item_move_all_hidden_; + push esi; + 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: - mov WeightOnBody, eax - mov eax, [esp+0x1C+0x4] - test eax, eax - jnz haveWeapon - cmp dword ptr ds:[_dialog_target_is_party], eax - jne end // This is a party member - mov eax, [esp+0x18+0x4] - test eax, eax - jz end + mov weightOnBody, eax; + mov esi, [esp + 0x1C + 8]; // weapon + test esi, esi; + jnz haveWeapon; + cmp ds:[_dialog_target_is_party], esi; // esi = 0 + jne skip; // This is a party member + mov eax, [esp + 0x18 + 8]; // item_weapon + test eax, eax; + jz skip; haveWeapon: - call item_weight_ - add WeightOnBody, eax -end: - mov ebx, PID_JESSE_CONTAINER - retn + mov eax, esi; + call item_size_; + add sizeOnBody, eax; + mov eax, esi; + 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 { - call stat_level_ // eax = Max weight - sub eax, WeightOnBody // Accounting for weight of target's equipped armor and weapon - retn + xor edx, edx; + mov ebx, [edi]; // Inventory.inv_size + 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; -static void __declspec(naked) move_inventory_hook() { +// Add sizeOnBody to item_c_curr_size_ function +static void __declspec(naked) item_c_curr_size_hack() { __asm { - inc Looting - call move_inventory_ - dec Looting - retn + xor esi, esi; + mov edx, [ecx]; // Inventory.inv_size + xor edi, edi; + //------ + 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 { - call stat_level_ // eax = Max weight - cmp Looting, 0 - je end - sub eax, WeightOnBody // Accounting for weight of target's equipped armor and weapon -end: - retn + call loot_container_; + jmp ResetBodyState; + } +} + +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); 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)) { dlog("Applying fix for not counting in weight of equipped items on NPC.", DL_INIT); MakeCall(0x473B4E, loot_container_hack); - MakeCall(0x47588A, barter_inventory_hack); - HookCall(0x474CB8, &barter_attempt_transaction_hook); - HookCall(0x4742AD, &move_inventory_hook); - HookCall(0x4771B5, &item_add_mult_hook); + HookCall(0x4758AB, barter_inventory_hook); + MakeCall(0x477EAB, item_total_weight_hack); + SafeWrite8(0x477EB0, 0x90); + 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); //} diff --git a/sfall/Bugs.h b/sfall/Bugs.h index cef4c0f7..1dc307d5 100644 --- a/sfall/Bugs.h +++ b/sfall/Bugs.h @@ -1,5 +1,5 @@ #pragma once -extern DWORD WeightOnBody; +extern void ResetBodyState(); void BugsInit(); diff --git a/sfall/FalloutEngine.cpp b/sfall/FalloutEngine.cpp index 4c78d459..2cebff4f 100644 --- a/sfall/FalloutEngine.cpp +++ b/sfall/FalloutEngine.cpp @@ -247,6 +247,7 @@ const DWORD art_ptr_unlock_ = 0x419260; const DWORD attack_crit_success_ = 0x423EB4; const DWORD automap_ = 0x41B8BC; const DWORD barter_compute_value_ = 0x474B2C; +const DWORD barter_inventory_ = 0x4757F0; const DWORD buf_to_buf_ = 0x4D36D4; const DWORD check_death_ = 0x410814; 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_turn_off_ = 0x479898; const DWORD item_move_all_ = 0x4776AC; +const DWORD item_move_all_hidden_ = 0x4776E0; const DWORD item_move_force_ = 0x4776A4; const DWORD item_mp_cost_ = 0x478040; const DWORD item_remove_mult_ = 0x477490; @@ -429,6 +431,7 @@ const DWORD loadColorTable_ = 0x4C78E4; const DWORD LoadGame_ = 0x47C640; const DWORD loadProgram_ = 0x4A3B74; const DWORD LoadSlot_ = 0x47DC68; +const DWORD loot_container_ = 0x473904; const DWORD main_game_loop_ = 0x480E48; const DWORD main_menu_hide_ = 0x481A00; const DWORD main_menu_loop_ = 0x481AEC; diff --git a/sfall/FalloutEngine.h b/sfall/FalloutEngine.h index 545e5b84..9bb21766 100644 --- a/sfall/FalloutEngine.h +++ b/sfall/FalloutEngine.h @@ -426,6 +426,7 @@ extern const DWORD art_ptr_unlock_; extern const DWORD attack_crit_success_; extern const DWORD automap_; extern const DWORD barter_compute_value_; +extern const DWORD barter_inventory_; extern const DWORD buf_to_buf_; extern const DWORD check_death_; 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_turn_off_; extern const DWORD item_move_all_; +extern const DWORD item_move_all_hidden_; extern const DWORD item_move_force_; extern const DWORD item_mp_cost_; extern const DWORD item_remove_mult_; @@ -607,6 +609,7 @@ extern const DWORD loadColorTable_; extern const DWORD LoadGame_; extern const DWORD loadProgram_; // loads script from scripts/ folder by file name and returns pointer to it: char* - file name (w/o extension) extern const DWORD LoadSlot_; +extern const DWORD loot_container_; extern const DWORD main_game_loop_; extern const DWORD main_menu_hide_; extern const DWORD main_menu_loop_; diff --git a/sfall/Inventory.cpp b/sfall/Inventory.cpp index 1d947a8f..94a174b0 100644 --- a/sfall/Inventory.cpp +++ b/sfall/Inventory.cpp @@ -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) { - int totalSize; __asm { mov eax, critter; @@ -127,17 +103,17 @@ static DWORD __stdcall sf_item_total_size(TGameObj* critter) { if ((critter->artFID & 0xF000000) == (OBJ_TYPE_CRITTER << 24)) { TGameObj* item = InvenRightHand(critter); - if (item && !(item->flags & OBJFLAG_HELD_IN_RIGHT << 8)) { + if (item && !(item->flags & 0x2000000)) { totalSize += ItemSize(item); } 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); } item = InvenWorn(critter); - if (item && !(item->flags & OBJFLAG_WORN << 8)) { + if (item && !(item->flags & 0x4000000)) { 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); if (size == 0) return 1; - int sizeTable = sf_item_total_size(targetTable); + int sizeTable = sf_item_total_size(table); if (sizeTable == 0) return 1; size -= sf_item_total_size(critter); @@ -258,8 +234,8 @@ static __declspec(naked) void barter_attempt_transaction_hack_pc() { /* cmp eax, edx */ jg fail; // if there's no available weight //------ - mov ecx, edi; - mov edx, ebp; + mov ecx, edi; // source (pc) + mov edx, ebp; // npc table call BarterAttemptTransaction; test eax, eax; jz fail; @@ -277,8 +253,8 @@ static __declspec(naked) void barter_attempt_transaction_hack_pm() { /* cmp eax, edx */ jg fail; // if there's no available weight //------ - mov ecx, ebx; - mov edx, esi; + mov ecx, ebx; // target (npc) + mov edx, esi; // pc table call BarterAttemptTransaction; test eax, eax; 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 const char* InvenFmt1 = "%s %d/%d %s %d/%d"; static const char* InvenFmt2 = "%s %d/%d"; @@ -716,7 +712,11 @@ void InventoryInit() { if (sizeLimitMode > 0 && sizeLimitMode <= 7) { if (sizeLimitMode >= 4) { sizeLimitMode -= 4; + // item_total_weight_ patch SafeWrite8(0x477EB3, 0xEB); + SafeWrite8(0x477EF5, 0); + SafeWrite8(0x477F11, 0); + SafeWrite8(0x477F29, 0); } invSizeMaxLimit = GetPrivateProfileInt("Misc", "CritterInvSizeLimit", 100, ini); @@ -730,6 +730,9 @@ void InventoryInit() { SafeWrite16(0x474C7A, 0x9090); 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 MakeJump(0x4725E0, display_stats_hack); SafeWrite32(0x4725FF, (DWORD)&InvenFmt); diff --git a/sfall/LoadGameHook.cpp b/sfall/LoadGameHook.cpp index 0e05251e..c763a97c 100644 --- a/sfall/LoadGameHook.cpp +++ b/sfall/LoadGameHook.cpp @@ -52,11 +52,11 @@ bool IsMapLoaded() { } DWORD InWorldMap() { - return (InLoop&WORLDMAP) ? 1 : 0; + return (InLoop & WORLDMAP) ? 1 : 0; } DWORD InCombat() { - return (InLoop&COMBAT) ? 1 : 0; + return (InLoop & COMBAT) ? 1 : 0; } DWORD GetCurrentLoops() {