fix: Fixes exploits with bank box deposits. Makes stacking more efficient (#2337)
### Summary - Fix AccountGold gold duplication exploit: When AccountGold.Enabled was true, double-clicking a BankCheck deposited the full value to the account but then continued creating physical gold piles for the same amount, duplicating the value - Fix Deposit/DepositUpTo partial deposit exploit: Both methods created new max-size gold piles and checks without first filling existing partial stacks, wasting container slots and causing premature "bank full" failures that could be leveraged to manipulate gold distribution - Fix BagOfSending bank stacking: Gold and BankCheck items sent via BagOfSending now use Banker.Deposit for efficient stacking instead of naive TryDropItem, which could fail on a full bank even when existing piles had room - Improve gold/check deposit efficiency: Banker.Deposit and Banker.DepositUpTo now top off existing gold piles (up to 60k) and bank checks (up to 1M) before creating new items, maximizing use of available container slots
This commit is contained in:
parent
f7eab79adb
commit
4b392079e9
3 changed files with 232 additions and 102 deletions
|
|
@ -137,68 +137,69 @@ public partial class BankCheck : Item
|
|||
return;
|
||||
}
|
||||
|
||||
var deposited = 0;
|
||||
var toAdd = _worth;
|
||||
|
||||
if (AccountGold.Enabled && from.Account?.DepositGold(toAdd) == true)
|
||||
if (AccountGold.Enabled)
|
||||
{
|
||||
deposited = toAdd;
|
||||
}
|
||||
|
||||
while (toAdd > 0)
|
||||
{
|
||||
var amount = Math.Min(toAdd, 60000);
|
||||
|
||||
var gold = new Gold(amount);
|
||||
|
||||
if (box.TryDropItem(from, gold, false))
|
||||
if (from.Account?.DepositGold(_worth) != true)
|
||||
{
|
||||
toAdd -= amount;
|
||||
deposited += amount;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
gold.Delete();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (deposited >= _worth)
|
||||
{
|
||||
Delete();
|
||||
|
||||
// Gold was deposited in your account:
|
||||
from.SendLocalizedMessage(1042672, true, $"{_worth:N0}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Worth -= deposited;
|
||||
}
|
||||
// Internalize the check to free its slot for deposit.
|
||||
// reserveSlots: 1 conditionally keeps a slot free for the check to bounce back
|
||||
// only if the full amount won't fit — if it fits, no reservation is needed.
|
||||
RecordBounce();
|
||||
Internalize();
|
||||
|
||||
var deposited = Banker.DepositUpTo(from, _worth, false, 1);
|
||||
|
||||
if (deposited >= _worth)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else if (deposited > 0)
|
||||
{
|
||||
Worth -= deposited;
|
||||
Bounce(from);
|
||||
}
|
||||
else
|
||||
{
|
||||
Bounce(from);
|
||||
from.SendLocalizedMessage(500390); // Your bank box is full.
|
||||
return;
|
||||
}
|
||||
|
||||
if (deposited > 0)
|
||||
{
|
||||
// Gold was deposited in your account:
|
||||
from.SendLocalizedMessage(1042672, true, $"{deposited:N0}");
|
||||
}
|
||||
|
||||
if (from is PlayerMobile pm)
|
||||
if (from is PlayerMobile pm)
|
||||
{
|
||||
var qs = pm.Quest;
|
||||
|
||||
if (qs is DarkTidesQuest)
|
||||
{
|
||||
var qs = pm.Quest;
|
||||
var obj = qs.FindObjective<CashBankCheckObjective>();
|
||||
|
||||
if (qs is DarkTidesQuest)
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
var obj = qs.FindObjective<CashBankCheckObjective>();
|
||||
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
obj.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
if (qs is UzeraanTurmoilQuest)
|
||||
if (qs is UzeraanTurmoilQuest)
|
||||
{
|
||||
var obj = qs.FindObjective(typeof(Engines.Quests.Haven.CashBankCheckObjective));
|
||||
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
var obj = qs.FindObjective(typeof(Engines.Quests.Haven.CashBankCheckObjective));
|
||||
|
||||
if (obj?.Completed == false)
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
obj.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using Server.ContextMenus;
|
|||
using Server.Engines.Quests;
|
||||
using Server.Regions;
|
||||
using Server.Spells;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Items;
|
||||
|
|
@ -233,16 +234,35 @@ public partial class BagOfSending : Item, TranslocationItem
|
|||
{
|
||||
from.SendLocalizedMessage(1079932); // You don't have enough charges to send that much weight
|
||||
}
|
||||
else if (!from.BankBox.TryDropItem(from, item, false))
|
||||
{
|
||||
_bag.SendLocalizedMessageTo(from, 1054110, 0x59); // Your bank box is full.
|
||||
}
|
||||
else
|
||||
{
|
||||
_bag.Charges -= Core.ML ? reqCharges : 1;
|
||||
bool sent;
|
||||
|
||||
// The item was placed in your bank box.
|
||||
_bag.SendLocalizedMessageTo(from, 1054150, 0x59);
|
||||
if (item is Gold or BankCheck)
|
||||
{
|
||||
var amount = (item as Gold)?.Amount ?? ((BankCheck)item).Worth;
|
||||
sent = Banker.Deposit(from, amount);
|
||||
if (sent)
|
||||
{
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sent = from.BankBox.TryDropItem(from, item, false);
|
||||
}
|
||||
|
||||
if (sent)
|
||||
{
|
||||
_bag.Charges -= Core.ML ? reqCharges : 1;
|
||||
|
||||
// The item was placed in your bank box.
|
||||
_bag.SendLocalizedMessageTo(from, 1054150, 0x59);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bag.SendLocalizedMessageTo(from, 1054110, 0x59); // Your bank box is full.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue