mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Auto balance barter tables when dragging caps around
This commit is contained in:
@@ -662,6 +662,9 @@ ReloadReserve=-1
|
|||||||
;Set to 1 to change the counter in the 'Move Items' window to start with maximum number, except in the barter screen
|
;Set to 1 to change the counter in the 'Move Items' window to start with maximum number, except in the barter screen
|
||||||
ItemCounterDefaultMax=0
|
ItemCounterDefaultMax=0
|
||||||
|
|
||||||
|
;Set to 1 to set default value in 'Move Items' window to amount of caps that will balance the tables
|
||||||
|
ItemCounterAutoCaps=0
|
||||||
|
|
||||||
;Set to 1 to leave the music playing in dialogue with talking heads
|
;Set to 1 to leave the music playing in dialogue with talking heads
|
||||||
EnableMusicInDialogue=0
|
EnableMusicInDialogue=0
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Enums.h"
|
#include "Enums.h"
|
||||||
|
#include "GamePids.h"
|
||||||
#include "FunctionOffsets.h"
|
#include "FunctionOffsets.h"
|
||||||
#include "Structs.h"
|
#include "Structs.h"
|
||||||
#include "EngineUtils.h"
|
#include "EngineUtils.h"
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ VAR_(bckgnd, BYTE*)
|
|||||||
VAR_(black_palette, DWORD)
|
VAR_(black_palette, DWORD)
|
||||||
VAR_(BlueColor, BYTE)
|
VAR_(BlueColor, BYTE)
|
||||||
VAR_(bottom_line, DWORD)
|
VAR_(bottom_line, DWORD)
|
||||||
VAR_(btable, DWORD)
|
VAR_(btable, fo::GameObject*)
|
||||||
VAR_(btncnt, DWORD)
|
VAR_(btncnt, DWORD)
|
||||||
VAR_(buf_length_2, long)
|
VAR_(buf_length_2, long)
|
||||||
VARD(cap, fo::AIcap) // dynamic array
|
VARD(cap, fo::AIcap) // dynamic array
|
||||||
@@ -198,7 +198,7 @@ VARA(procTableStrs, const char*, (int)fo::Scripts::ScriptProc::coun
|
|||||||
VAR_(proto_main_msg_file, fo::MessageList)
|
VAR_(proto_main_msg_file, fo::MessageList)
|
||||||
VARA(proto_msg_files, fo::MessageList, 6) // array of 6 elements
|
VARA(proto_msg_files, fo::MessageList, 6) // array of 6 elements
|
||||||
VARA(protoLists, fo::ProtoList, 11)
|
VARA(protoLists, fo::ProtoList, 11)
|
||||||
VAR_(ptable, DWORD)
|
VAR_(ptable, fo::GameObject*)
|
||||||
VAR_(pud, DWORD)
|
VAR_(pud, DWORD)
|
||||||
VAR_(queue, fo::Queue*)
|
VAR_(queue, fo::Queue*)
|
||||||
VAR_(quick_done, DWORD)
|
VAR_(quick_done, DWORD)
|
||||||
@@ -222,7 +222,7 @@ VAR_(speech_volume, DWORD)
|
|||||||
VARA(square, DWORD*, 3) // use (square && 0xFFF) to get ground fid, and ((square >> 16) && 0xFFF) to get roof
|
VARA(square, DWORD*, 3) // use (square && 0xFFF) to get ground fid, and ((square >> 16) && 0xFFF) to get roof
|
||||||
VAR_(square_rect, fo::SquareRect) // _square_y
|
VAR_(square_rect, fo::SquareRect) // _square_y
|
||||||
VAR_(squares, DWORD*)
|
VAR_(squares, DWORD*)
|
||||||
VARA(stack, DWORD, 10)
|
VARA(stack, fo::GameObject*, 10)
|
||||||
VARA(stack_offset, DWORD, 10)
|
VARA(stack_offset, DWORD, 10)
|
||||||
VARA(stat_data, fo::StatInfo, fo::STAT_real_max_stat)
|
VARA(stat_data, fo::StatInfo, fo::STAT_real_max_stat)
|
||||||
VAR_(stat_flag, DWORD)
|
VAR_(stat_flag, DWORD)
|
||||||
@@ -232,7 +232,7 @@ VAR_(Tag_, DWORD)
|
|||||||
VAR_(tag_skill, DWORD)
|
VAR_(tag_skill, DWORD)
|
||||||
VAR_(target_curr_stack, DWORD)
|
VAR_(target_curr_stack, DWORD)
|
||||||
VAR_(target_pud, DWORD*)
|
VAR_(target_pud, DWORD*)
|
||||||
VARA(target_stack, DWORD, 10)
|
VARA(target_stack, fo::GameObject*, 10)
|
||||||
VARA(target_stack_offset, DWORD, 10)
|
VARA(target_stack_offset, DWORD, 10)
|
||||||
VAR_(target_str, DWORD)
|
VAR_(target_str, DWORD)
|
||||||
VAR_(target_xpos, DWORD)
|
VAR_(target_xpos, DWORD)
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
namespace sfall
|
namespace sfall
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static DWORD lastTableCostPC; // keep last cost for pc
|
||||||
|
static DWORD lastTableCostNPC;
|
||||||
|
|
||||||
// The hook is executed twice when entering the barter screen and after transaction: the first time is for the player; the second time is for NPC
|
// The hook is executed twice when entering the barter screen and after transaction: the first time is for the player; the second time is for NPC
|
||||||
static DWORD __fastcall BarterPriceHook_Script(fo::GameObject* source, fo::GameObject* target, DWORD callAddr) {
|
static DWORD __fastcall BarterPriceHook_Script(fo::GameObject* source, fo::GameObject* target, DWORD callAddr) {
|
||||||
bool barterIsParty = (fo::var::dialog_target_is_party != 0);
|
bool barterIsParty = (fo::var::dialog_target_is_party != 0);
|
||||||
@@ -22,12 +25,12 @@ static DWORD __fastcall BarterPriceHook_Script(fo::GameObject* source, fo::GameO
|
|||||||
args[1] = (DWORD)target;
|
args[1] = (DWORD)target;
|
||||||
args[2] = !barterIsParty ? computeCost : 0;
|
args[2] = !barterIsParty ? computeCost : 0;
|
||||||
|
|
||||||
fo::GameObject* bTable = (fo::GameObject*)fo::var::btable;
|
fo::GameObject* bTable = fo::var::btable;
|
||||||
args[3] = (DWORD)bTable;
|
args[3] = (DWORD)bTable;
|
||||||
args[4] = fo::func::item_caps_total(bTable);
|
args[4] = fo::func::item_caps_total(bTable);
|
||||||
args[5] = fo::func::item_total_cost(bTable);
|
args[5] = fo::func::item_total_cost(bTable);
|
||||||
|
|
||||||
fo::GameObject* pTable = (fo::GameObject*)fo::var::ptable;
|
fo::GameObject* pTable = fo::var::ptable;
|
||||||
args[6] = (DWORD)pTable;
|
args[6] = (DWORD)pTable;
|
||||||
|
|
||||||
long pcCost = 0;
|
long pcCost = 0;
|
||||||
@@ -52,6 +55,11 @@ static DWORD __fastcall BarterPriceHook_Script(fo::GameObject* source, fo::GameO
|
|||||||
cost = rets[0]; // new cost for npc
|
cost = rets[0]; // new cost for npc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isPCHook) {
|
||||||
|
lastTableCostPC = cost;
|
||||||
|
} else {
|
||||||
|
lastTableCostNPC = cost;
|
||||||
|
}
|
||||||
EndHook();
|
EndHook();
|
||||||
return cost;
|
return cost;
|
||||||
}
|
}
|
||||||
@@ -70,7 +78,6 @@ static void __declspec(naked) BarterPriceHook() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD offersGoodsCost; // keep last cost for pc
|
|
||||||
static void __declspec(naked) PC_BarterPriceHook() {
|
static void __declspec(naked) PC_BarterPriceHook() {
|
||||||
__asm {
|
__asm {
|
||||||
push edx;
|
push edx;
|
||||||
@@ -82,18 +89,27 @@ static void __declspec(naked) PC_BarterPriceHook() {
|
|||||||
call BarterPriceHook_Script;
|
call BarterPriceHook_Script;
|
||||||
pop ecx;
|
pop ecx;
|
||||||
pop edx;
|
pop edx;
|
||||||
mov offersGoodsCost, eax;
|
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __declspec(naked) OverrideCost_BarterPriceHook() {
|
static void __declspec(naked) OverrideCost_BarterPriceHook() {
|
||||||
__asm {
|
__asm {
|
||||||
mov eax, offersGoodsCost;
|
mov eax, lastTableCostPC;
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BarterGetTableCosts(long* outPcTableCost, long* outNpcTableCost) {
|
||||||
|
if (!HookScripts::HookHasScript(HOOK_BARTERPRICE)) {
|
||||||
|
*outPcTableCost = fo::func::item_total_cost(fo::var::ptable);
|
||||||
|
*outNpcTableCost = fo::func::barter_compute_value(fo::var::obj_dude, fo::var::target_stack[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*outPcTableCost = lastTableCostPC;
|
||||||
|
*outNpcTableCost = lastTableCostNPC;
|
||||||
|
}
|
||||||
|
|
||||||
static fo::GameObject* sourceSkillOn = nullptr;
|
static fo::GameObject* sourceSkillOn = nullptr;
|
||||||
void SourceUseSkillOnInit() { sourceSkillOn = fo::var::obj_dude; }
|
void SourceUseSkillOnInit() { sourceSkillOn = fo::var::obj_dude; }
|
||||||
|
|
||||||
|
|||||||
@@ -21,4 +21,6 @@ void Inject_RollCheckHook();
|
|||||||
|
|
||||||
long PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result);
|
long PerceptionRangeHook_Invoke(fo::GameObject* watcher, fo::GameObject* target, long type, long result);
|
||||||
|
|
||||||
|
void BarterGetTableCosts(long* outPcTableCost, long* outNpcTableCost);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "..\Translate.h"
|
#include "..\Translate.h"
|
||||||
|
|
||||||
#include "LoadGameHook.h"
|
#include "LoadGameHook.h"
|
||||||
|
#include "HookScripts\MiscHs.h"
|
||||||
|
|
||||||
#include "..\Game\inventory.h"
|
#include "..\Game\inventory.h"
|
||||||
#include "..\Game\items.h"
|
#include "..\Game\items.h"
|
||||||
@@ -618,12 +619,70 @@ end:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long CalculateSuggestedMoveCount(fo::GameObject* item, long maxQuantity, bool fromPlayer, bool fromInventory) {
|
||||||
|
if (maxQuantity <= 1) {
|
||||||
|
return maxQuantity;
|
||||||
|
}
|
||||||
|
long suggestedValue = 1;
|
||||||
|
if (item->protoId == fo::PID_BOTTLE_CAPS && !fo::var::dialog_target_is_party) {
|
||||||
|
// Calculate change money automatically
|
||||||
|
long totalCostPlayer;
|
||||||
|
long totalCostNpc;
|
||||||
|
BarterGetTableCosts(&totalCostPlayer, &totalCostNpc);
|
||||||
|
// Actor's balance: negative - the actor must add money to balance the tables and vice versa
|
||||||
|
long balance = fromPlayer ? totalCostPlayer - totalCostNpc : totalCostNpc - totalCostPlayer;
|
||||||
|
|
||||||
|
if ( (balance < 0 && fromInventory) || (balance > 0 && !fromInventory) ) {
|
||||||
|
suggestedValue = min(std::abs(balance), maxQuantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return suggestedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool itemCounterDefaultMax;
|
||||||
|
static bool itemCounterAutoCaps;
|
||||||
|
static long __fastcall CalculateDefaultMoveCount(fo::GameObject* item, DWORD retAddr, DWORD maxValue) {
|
||||||
|
maxValue = min(maxValue, 99999); // capped like in vanilla
|
||||||
|
if ((GetLoopFlags() & BARTER) != 0) {
|
||||||
|
if (itemCounterAutoCaps && maxValue > 0) {
|
||||||
|
bool fromPlayer;
|
||||||
|
bool fromInventory;
|
||||||
|
switch (retAddr) {
|
||||||
|
case 0x474F96: // barter_move_inventory
|
||||||
|
fromPlayer = true;
|
||||||
|
fromInventory = true;
|
||||||
|
break;
|
||||||
|
case 0x475015: // barter_move_inventory
|
||||||
|
fromPlayer = false;
|
||||||
|
fromInventory = true;
|
||||||
|
break;
|
||||||
|
case 0x475261: // barter_move_from_table_inventory
|
||||||
|
fromPlayer = true;
|
||||||
|
fromInventory = false;
|
||||||
|
break;
|
||||||
|
case 0x4752DE: // barter_move_from_table_inventory
|
||||||
|
fromPlayer = false;
|
||||||
|
fromInventory = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return CalculateSuggestedMoveCount(item, maxValue, fromPlayer, fromInventory);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return itemCounterDefaultMax ? maxValue : 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void __declspec(naked) do_move_timer_hack() {
|
static void __declspec(naked) do_move_timer_hack() {
|
||||||
__asm {
|
__asm {
|
||||||
mov ebx, 1;
|
pushadc;
|
||||||
call GetLoopFlags;
|
push ebp; // max
|
||||||
test eax, BARTER;
|
mov edx, dword ptr[esp + 40]; // return address
|
||||||
cmovz ebx, ebp; // set max when not in barter
|
mov ecx, dword ptr[esp + 28]; // item
|
||||||
|
call CalculateDefaultMoveCount;
|
||||||
|
mov ebx, eax;
|
||||||
|
popadc;
|
||||||
retn;
|
retn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -755,7 +814,9 @@ void Inventory::init() {
|
|||||||
skipFromContainer = IniReader::GetConfigInt("Input", "FastMoveFromContainer", 0);
|
skipFromContainer = IniReader::GetConfigInt("Input", "FastMoveFromContainer", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IniReader::GetConfigInt("Misc", "ItemCounterDefaultMax", 0)) {
|
itemCounterDefaultMax = IniReader::GetConfigInt("Misc", "ItemCounterDefaultMax", 0);
|
||||||
|
itemCounterAutoCaps = IniReader::GetConfigInt("Misc", "ItemCounterAutoCaps", 0);
|
||||||
|
if (itemCounterDefaultMax || itemCounterAutoCaps) {
|
||||||
MakeCall(0x4768A3, do_move_timer_hack);
|
MakeCall(0x4768A3, do_move_timer_hack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user