mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 12:41:30 +00:00
[Fix] Parcel Delivery Updates (#4688)
* Fix two parcel bugs Fix two Parcel Bugs - If a player was at their parcel limit and perform a bazaar purchase via parcel delivery, their money would be lost - If a container with items was delivered via parcel, the parcel under certain inventory conditions could be delivered into an incorrect slot resulting in the container being lost. * Incorrect field used for BagSize vs ItemSize. Silly mistake. * Remove duplicate check and reorder stacking check * Fix edge case when Parcel Window remains open and Bazaar purchases are made. * Repair - bazaar purchase of items with charges reverting to 1 charge in error - bazaar visual error with selling price. Was caused by the parcel fee not being properly reflected in the client - corrected a type mismatch with parcel fee uint32 vs uin64 - corrected a few TraderPurchase and TraderSell event data points by splitting quantity and charges * Formatting * Use pre-existing AddMoney and TakeMoney and remove unnecessary routines * Updates after rebase
This commit is contained in:
parent
c09fad5a75
commit
ab4e1191ef
@ -882,8 +882,9 @@ namespace PlayerEvent {
|
||||
uint32 trader_id;
|
||||
std::string trader_name;
|
||||
uint32 price;
|
||||
uint32 charges;
|
||||
uint32 total_cost;
|
||||
uint32 quantity;
|
||||
int32 charges;
|
||||
uint64 total_cost;
|
||||
uint64 player_money_balance;
|
||||
|
||||
|
||||
@ -903,6 +904,7 @@ namespace PlayerEvent {
|
||||
CEREAL_NVP(trader_id),
|
||||
CEREAL_NVP(trader_name),
|
||||
CEREAL_NVP(price),
|
||||
CEREAL_NVP(quantity),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(total_cost),
|
||||
CEREAL_NVP(player_money_balance)
|
||||
@ -922,8 +924,9 @@ namespace PlayerEvent {
|
||||
uint32 buyer_id;
|
||||
std::string buyer_name;
|
||||
uint32 price;
|
||||
uint32 charges;
|
||||
uint32 total_cost;
|
||||
uint32 quantity;
|
||||
int32 charges;
|
||||
uint64 total_cost;
|
||||
uint64 player_money_balance;
|
||||
|
||||
|
||||
@ -943,6 +946,7 @@ namespace PlayerEvent {
|
||||
CEREAL_NVP(buyer_id),
|
||||
CEREAL_NVP(buyer_name),
|
||||
CEREAL_NVP(price),
|
||||
CEREAL_NVP(quantity),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(total_cost),
|
||||
CEREAL_NVP(player_money_balance)
|
||||
@ -1152,6 +1156,7 @@ namespace PlayerEvent {
|
||||
uint32 augment_5_id;
|
||||
uint32 augment_6_id;
|
||||
uint32 quantity;
|
||||
int32 charges;
|
||||
std::string from_player_name;
|
||||
std::string to_player_name;
|
||||
uint32 sent_date;
|
||||
@ -1169,6 +1174,7 @@ namespace PlayerEvent {
|
||||
CEREAL_NVP(augment_5_id),
|
||||
CEREAL_NVP(augment_6_id),
|
||||
CEREAL_NVP(quantity),
|
||||
CEREAL_NVP(charges),
|
||||
CEREAL_NVP(from_player_name),
|
||||
CEREAL_NVP(to_player_name),
|
||||
CEREAL_NVP(sent_date)
|
||||
|
||||
@ -2028,3 +2028,57 @@ int16 EQ::InventoryProfile::_HasEvolvingItem(ItemInstQueue &iqueue, uint64 evolv
|
||||
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
|
||||
int16 EQ::InventoryProfile::FindFirstFreeSlotThatFitsItemWithStacking(ItemInstance *item_inst) const
|
||||
{
|
||||
auto item_data = item_inst->GetItem();
|
||||
if (!item_data) {
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
for (int16 i = invslot::GENERAL_BEGIN; i <= invslot::GENERAL_END; i++) {
|
||||
auto const inv_item = GetItem(i);
|
||||
if (!inv_item) {
|
||||
// Found available slot in personal inventory
|
||||
// Anything will fit here
|
||||
return i;
|
||||
}
|
||||
|
||||
if (item_data->IsClassBag() && item_inst->IsNoneEmptyContainer()) {
|
||||
// If the inbound item is a bag with items, it cannot be stored within a bag
|
||||
// Move to next potential slot
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inv_item->GetID() == item_data->ID && item_data->Stackable) {
|
||||
if (item_inst->GetCharges() + inv_item->GetCharges() <= item_data->StackSize) {
|
||||
// Found a personal inventory slot that has room for a stackable addition
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (inv_item->IsClassBag() && CanItemFitInContainer(item_data, inv_item->GetItem())) {
|
||||
int16 const base_slot_id = CalcSlotId(i, invbag::SLOT_BEGIN);
|
||||
uint8 const bag_size = inv_item->GetItem()->BagSlots;
|
||||
uint8 const item_size = item_data->Size;
|
||||
|
||||
for (uint8 bag_slot = invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) {
|
||||
auto bag_item = GetItem(base_slot_id + bag_slot);
|
||||
if (!bag_item) {
|
||||
// Found available slot within bag that will hold inbound item
|
||||
return base_slot_id + bag_slot;
|
||||
}
|
||||
|
||||
if (bag_item && item_data->Stackable && bag_item->GetID() == item_data->ID) {
|
||||
if (item_inst->GetCharges() + bag_item->GetCharges() <= item_data->StackSize) {
|
||||
// Found a bag slot has room for a stackable addition
|
||||
return base_slot_id + bag_slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID_INDEX;
|
||||
}
|
||||
|
||||
@ -179,6 +179,7 @@ namespace EQ
|
||||
int16 FindFreeSlot(bool for_bag, bool try_cursor, uint8 min_size = 0, bool is_arrow = false);
|
||||
int16 FindFreeSlotForTradeItem(const ItemInstance* inst, int16 general_start = invslot::GENERAL_BEGIN, uint8 bag_start = invbag::SLOT_BEGIN);
|
||||
int16 FindFirstFreeSlotThatFitsItem(const EQ::ItemData *inst);
|
||||
int16 FindFirstFreeSlotThatFitsItemWithStacking(ItemInstance *inst) const;
|
||||
|
||||
// Calculate slot_id for an item within a bag
|
||||
static int16 CalcSlotId(int16 slot_id); // Calc parent bag's slot_id
|
||||
|
||||
101
zone/client.cpp
101
zone/client.cpp
@ -12969,107 +12969,6 @@ void Client::RemoveItemBySerialNumber(uint32 serial_number, uint32 quantity)
|
||||
}
|
||||
}
|
||||
|
||||
void Client::AddMoneyToPPWithOverflow(uint64 copper, bool update_client)
|
||||
{
|
||||
//I noticed in the ROF2 client that the client auto updates the currency values using overflow
|
||||
//Therefore, I created this method to ensure that the db matches and clients don't see 10 pp 5 gp
|
||||
//becoming 9pp 15 gold with the current AddMoneyToPP method.
|
||||
|
||||
auto add_pp = copper / 1000;
|
||||
auto add_gp = (copper - add_pp * 1000) / 100;
|
||||
auto add_sp = (copper - add_pp * 1000 - add_gp * 100) / 10;
|
||||
auto add_cp = copper - add_pp * 1000 - add_gp * 100 - add_sp * 10;
|
||||
|
||||
m_pp.copper += add_cp;
|
||||
if (m_pp.copper >= 10) {
|
||||
m_pp.silver += m_pp.copper / 10;
|
||||
m_pp.copper = m_pp.copper % 10;
|
||||
}
|
||||
|
||||
m_pp.silver += add_sp;
|
||||
if (m_pp.silver >= 10) {
|
||||
m_pp.gold += m_pp.silver / 10;
|
||||
m_pp.silver = m_pp.silver % 10;
|
||||
}
|
||||
|
||||
m_pp.gold += add_gp;
|
||||
if (m_pp.gold >= 10) {
|
||||
m_pp.platinum += m_pp.gold / 10;
|
||||
m_pp.gold = m_pp.gold % 10;
|
||||
}
|
||||
|
||||
m_pp.platinum += add_pp;
|
||||
|
||||
if (update_client) {
|
||||
SendMoneyUpdate();
|
||||
}
|
||||
|
||||
RecalcWeight();
|
||||
SaveCurrency();
|
||||
|
||||
LogDebug("Client::AddMoneyToPPWithOverflow() [{}] should have: plat:[{}] gold:[{}] silver:[{}] copper:[{}]",
|
||||
GetName(),
|
||||
m_pp.platinum,
|
||||
m_pp.gold,
|
||||
m_pp.silver,
|
||||
m_pp.copper
|
||||
);
|
||||
}
|
||||
|
||||
bool Client::TakeMoneyFromPPWithOverFlow(uint64 copper, bool update_client)
|
||||
{
|
||||
int32 remove_pp = copper / 1000;
|
||||
int32 remove_gp = (copper - remove_pp * 1000) / 100;
|
||||
int32 remove_sp = (copper - remove_pp * 1000 - remove_gp * 100) / 10;
|
||||
int32 remove_cp = copper - remove_pp * 1000 - remove_gp * 100 - remove_sp * 10;
|
||||
|
||||
uint64 current_money = GetCarriedMoney();
|
||||
|
||||
if (copper > current_money) {
|
||||
return false; //client does not have enough money on them
|
||||
}
|
||||
|
||||
m_pp.copper -= remove_cp;
|
||||
if (m_pp.copper < 0) {
|
||||
m_pp.silver -= 1;
|
||||
m_pp.copper = m_pp.copper + 10;
|
||||
if (m_pp.copper >= 10) {
|
||||
m_pp.silver += m_pp.copper / 10;
|
||||
m_pp.copper = m_pp.copper % 10;
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.silver -= remove_sp;
|
||||
if (m_pp.silver < 0) {
|
||||
m_pp.gold -= 1;
|
||||
m_pp.silver = m_pp.silver + 10;
|
||||
if (m_pp.silver >= 10) {
|
||||
m_pp.gold += m_pp.silver / 10;
|
||||
m_pp.silver = m_pp.silver % 10;
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.gold -= remove_gp;
|
||||
if (m_pp.gold < 0) {
|
||||
m_pp.platinum -= 1;
|
||||
m_pp.gold = m_pp.gold + 10;
|
||||
if (m_pp.gold >= 10) {
|
||||
m_pp.platinum += m_pp.gold / 10;
|
||||
m_pp.gold = m_pp.gold % 10;
|
||||
}
|
||||
}
|
||||
|
||||
m_pp.platinum -= remove_pp;
|
||||
|
||||
if (update_client) {
|
||||
SendMoneyUpdate();
|
||||
}
|
||||
|
||||
SaveCurrency();
|
||||
RecalcWeight();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Client::SendTopLevelInventory()
|
||||
{
|
||||
EQ::ItemInstance* inst = nullptr;
|
||||
|
||||
@ -879,11 +879,9 @@ public:
|
||||
void QuestReadBook(const char* text, uint8 type);
|
||||
void SendMoneyUpdate();
|
||||
bool TakeMoneyFromPP(uint64 copper, bool update_client = false);
|
||||
bool TakeMoneyFromPPWithOverFlow(uint64 copper, bool update_client);
|
||||
bool TakePlatinum(uint32 platinum, bool update_client = false);
|
||||
void AddMoneyToPP(uint64 copper, bool update_client = false);
|
||||
void AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client = false);
|
||||
void AddMoneyToPPWithOverflow(uint64 copper, bool update_client);
|
||||
void AddPlatinum(uint32 platinu, bool update_client = false);
|
||||
bool HasMoney(uint64 copper);
|
||||
uint64 GetCarriedMoney();
|
||||
|
||||
204
zone/parcels.cpp
204
zone/parcels.cpp
@ -632,7 +632,13 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
||||
return;
|
||||
}
|
||||
|
||||
auto p = m_parcels.find(parcel_in.parcel_slot_id);
|
||||
auto p = std::find_if(
|
||||
m_parcels.begin(),
|
||||
m_parcels.end(),
|
||||
[&](const std::pair<uint32, CharacterParcelsRepository::CharacterParcels> &x) {
|
||||
return x.first == parcel_in.parcel_slot_id && x.second.item_id == parcel_in.parcel_item_id;
|
||||
}
|
||||
);
|
||||
if (p != m_parcels.end()) {
|
||||
uint32 item_id = parcel_in.parcel_item_id;
|
||||
uint32 item_quantity = p->second.quantity;
|
||||
@ -656,25 +662,70 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
||||
p->second.aug_slot_6
|
||||
)
|
||||
);
|
||||
|
||||
if (!inst) {
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst->IsStackable()) {
|
||||
inst->SetCharges(item_quantity > 0 ? item_quantity : 1);
|
||||
}
|
||||
|
||||
switch (parcel_in.parcel_item_id) {
|
||||
case PARCEL_MONEY_ITEM_ID: {
|
||||
AddMoneyToPP(p->second.quantity, true);
|
||||
MessageString(
|
||||
Chat::Yellow,
|
||||
PARCEL_DELIVERED,
|
||||
merchant->GetCleanName(),
|
||||
"Money",
|
||||
p->second.from_name.c_str()
|
||||
Chat::Yellow, PARCEL_DELIVERED, merchant->GetCleanName(), "Money", p->second.from_name.c_str()
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
auto free_id = GetInv().FindFreeSlot(false, false);
|
||||
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> results{};
|
||||
if (inst->IsClassBag() && inst->GetItem()->BagSlots > 0) {
|
||||
auto contents = inst->GetContents();
|
||||
results = CharacterParcelsContainersRepository::GetWhere(
|
||||
database, fmt::format("`parcels_id` = {}", p->second.id)
|
||||
);
|
||||
for (auto i: results) {
|
||||
auto item = database.CreateItem(
|
||||
i.item_id,
|
||||
i.quantity,
|
||||
i.aug_slot_1,
|
||||
i.aug_slot_2,
|
||||
i.aug_slot_3,
|
||||
i.aug_slot_4,
|
||||
i.aug_slot_5,
|
||||
i.aug_slot_6
|
||||
);
|
||||
|
||||
if (!item) {
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckLoreConflict(item->GetItem())) {
|
||||
if (RuleB(Parcel, DeleteOnDuplicate)) {
|
||||
MessageString(Chat::Yellow, PARCEL_DUPLICATE_DELETE, inst->GetItem()->Name);
|
||||
continue;
|
||||
}
|
||||
|
||||
MessageString(Chat::Yellow, DUP_LORE);
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
|
||||
contents->emplace(i.slot_id, item);
|
||||
}
|
||||
}
|
||||
|
||||
auto const free_id = GetInv().FindFirstFreeSlotThatFitsItemWithStacking(inst.get());
|
||||
if (free_id == INVALID_INDEX) {
|
||||
SendParcelRetrieveAck();
|
||||
MessageString(Chat::White, PARCEL_INV_FULL, merchant->GetCleanName());
|
||||
return;
|
||||
}
|
||||
|
||||
if (CheckLoreConflict(inst->GetItem())) {
|
||||
if (RuleB(Parcel, DeleteOnDuplicate)) {
|
||||
MessageString(Chat::Yellow, PARCEL_DUPLICATE_DELETE, inst->GetItem()->Name);
|
||||
@ -685,108 +736,33 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (inst->IsStackable()) {
|
||||
inst->SetCharges(item_quantity);
|
||||
if (TryStacking(inst.get(), ItemPacketTrade, true, false)) {
|
||||
MessageString(
|
||||
Chat::Yellow,
|
||||
PARCEL_DELIVERED_2,
|
||||
merchant->GetCleanName(),
|
||||
std::to_string(item_quantity).c_str(),
|
||||
inst->GetItem()->Name,
|
||||
p->second.from_name.c_str()
|
||||
);
|
||||
}
|
||||
else if (free_id != INVALID_INDEX) {
|
||||
inst->SetCharges(item_quantity);
|
||||
if (PutItemInInventory(free_id, *inst, true)) {
|
||||
MessageString(
|
||||
Chat::Yellow,
|
||||
PARCEL_DELIVERED_2,
|
||||
merchant->GetCleanName(),
|
||||
std::to_string(item_quantity).c_str(),
|
||||
inst->GetItem()->Name,
|
||||
p->second.from_name.c_str()
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
MessageString(Chat::Yellow, PARCEL_INV_FULL, merchant->GetCleanName());
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
|
||||
if (AutoPutLootInInventory(*inst.get(), false, true)) {
|
||||
MessageString(
|
||||
Chat::Yellow,
|
||||
PARCEL_DELIVERED_2,
|
||||
merchant->GetCleanName(),
|
||||
std::to_string(item_quantity).c_str(),
|
||||
inst->GetItem()->Name,
|
||||
p->second.from_name.c_str()
|
||||
);
|
||||
}
|
||||
else if (free_id != INVALID_INDEX) {
|
||||
std::vector<CharacterParcelsContainersRepository::CharacterParcelsContainers> results{};
|
||||
|
||||
if (inst->IsClassBag() && inst->GetItem()->BagSlots > 0) {
|
||||
results = CharacterParcelsContainersRepository::GetWhere(database, fmt::format("`parcels_id` = {}", p->second.id));
|
||||
for (auto const &i : results) {
|
||||
std::unique_ptr<EQ::ItemInstance> item(
|
||||
database.CreateItem(
|
||||
i.item_id,
|
||||
i.quantity,
|
||||
i.aug_slot_1,
|
||||
i.aug_slot_2,
|
||||
i.aug_slot_3,
|
||||
i.aug_slot_4,
|
||||
i.aug_slot_5,
|
||||
i.aug_slot_6
|
||||
)
|
||||
);
|
||||
if (CheckLoreConflict(item->GetItem())) {
|
||||
Message(
|
||||
Chat::Yellow,
|
||||
fmt::format("Lore Item Found in Inventory: {}", item->GetItem()->Name).c_str());
|
||||
MessageString(Chat::Yellow, DUP_LORE);
|
||||
Message(Chat::Red, "Unable to retrieve parcel.");
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inst->SetCharges(item_quantity > 0 ? item_quantity : 1);
|
||||
if (PutItemInInventory(free_id, *inst.get(), true)) {
|
||||
if (inst->IsClassBag() && inst->GetItem()->BagSlots > 0) {
|
||||
for (auto const &i: results) {
|
||||
std::unique_ptr<EQ::ItemInstance> item(
|
||||
database.CreateItem(
|
||||
i.item_id,
|
||||
i.quantity,
|
||||
i.aug_slot_1,
|
||||
i.aug_slot_2,
|
||||
i.aug_slot_3,
|
||||
i.aug_slot_4,
|
||||
i.aug_slot_5,
|
||||
i.aug_slot_6
|
||||
)
|
||||
);
|
||||
auto bag_slot = EQ::InventoryProfile::CalcSlotId(free_id, i.slot_id);
|
||||
PutItemInInventory(bag_slot, *item.get(), true);
|
||||
}
|
||||
}
|
||||
MessageString(
|
||||
Chat::Yellow,
|
||||
PARCEL_DELIVERED,
|
||||
merchant->GetCleanName(),
|
||||
inst->GetItem()->Name,
|
||||
p->second.from_name.c_str()
|
||||
);
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::PARCEL_RETRIEVE)) {
|
||||
PlayerEvent::ParcelRetrieve e{};
|
||||
e.from_player_name = p->second.from_name;
|
||||
e.item_id = p->second.item_id;
|
||||
e.augment_1_id = p->second.aug_slot_1;
|
||||
e.augment_2_id = p->second.aug_slot_2;
|
||||
e.augment_3_id = p->second.aug_slot_3;
|
||||
e.augment_4_id = p->second.aug_slot_4;
|
||||
e.augment_5_id = p->second.aug_slot_5;
|
||||
e.augment_6_id = p->second.aug_slot_6;
|
||||
e.quantity = p->second.quantity;
|
||||
e.sent_date = p->second.sent_date;
|
||||
RecordPlayerEventLog(PlayerEvent::PARCEL_RETRIEVE, e);
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::PARCEL_RETRIEVE)) {
|
||||
PlayerEvent::ParcelRetrieve e{};
|
||||
e.from_player_name = p->second.from_name;
|
||||
e.item_id = p->second.item_id;
|
||||
e.augment_1_id = p->second.aug_slot_1;
|
||||
e.augment_2_id = p->second.aug_slot_2;
|
||||
e.augment_3_id = p->second.aug_slot_3;
|
||||
e.augment_4_id = p->second.aug_slot_4;
|
||||
e.augment_5_id = p->second.aug_slot_5;
|
||||
e.augment_6_id = p->second.aug_slot_6;
|
||||
e.quantity = p->second.quantity;
|
||||
e.sent_date = p->second.sent_date;
|
||||
RecordPlayerEventLog(PlayerEvent::PARCEL_RETRIEVE, e);
|
||||
|
||||
for (auto const &i:results) {
|
||||
for (auto const &i:results) {
|
||||
e.from_player_name = p->second.from_name;
|
||||
e.item_id = i.item_id;
|
||||
e.augment_1_id = i.aug_slot_1;
|
||||
@ -798,19 +774,9 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
||||
e.quantity = i.quantity;
|
||||
e.sent_date = p->second.sent_date;
|
||||
RecordPlayerEventLog(PlayerEvent::PARCEL_RETRIEVE, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
MessageString(Chat::Yellow, PARCEL_INV_FULL, merchant->GetCleanName());
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
MessageString(Chat::Yellow, PARCEL_INV_FULL, merchant->GetCleanName());
|
||||
SendParcelRetrieveAck();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -819,6 +785,7 @@ void Client::DoParcelRetrieve(const ParcelRetrieve_Struct &parcel_in)
|
||||
SendParcelDelete(parcel_in);
|
||||
m_parcels.erase(p);
|
||||
}
|
||||
|
||||
SendParcelRetrieveAck();
|
||||
SendParcelIconStatus();
|
||||
}
|
||||
@ -831,7 +798,6 @@ bool Client::DeleteParcel(uint32 parcel_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = std::find_if(m_parcels.cbegin(), m_parcels.cend(), [&](const auto &x) { return x.second.id == parcel_id; });
|
||||
SetParcelCount(GetParcelCount() - 1);
|
||||
|
||||
return true;
|
||||
|
||||
@ -1458,12 +1458,13 @@ void Client::BuyTraderItem(TraderBuy_Struct *tbs, Client *Trader, const EQApplic
|
||||
.trader_id = Trader->CharacterID(),
|
||||
.trader_name = Trader->GetCleanName(),
|
||||
.price = tbs->price,
|
||||
.charges = outtbs->quantity,
|
||||
.quantity = outtbs->quantity,
|
||||
.charges = buy_item->GetCharges(),
|
||||
.total_cost = (tbs->price * outtbs->quantity),
|
||||
.player_money_balance = GetCarriedMoney(),
|
||||
};
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::TRADER_PURCHASE, e);
|
||||
RecordPlayerEventLog(PlayerEvent::TRADER_PURCHASE, e);
|
||||
}
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::TRADER_SELL)) {
|
||||
@ -1479,7 +1480,8 @@ void Client::BuyTraderItem(TraderBuy_Struct *tbs, Client *Trader, const EQApplic
|
||||
.buyer_id = CharacterID(),
|
||||
.buyer_name = GetCleanName(),
|
||||
.price = tbs->price,
|
||||
.charges = outtbs->quantity,
|
||||
.quantity = outtbs->quantity,
|
||||
.charges = buy_item->GetCharges(),
|
||||
.total_cost = (tbs->price * outtbs->quantity),
|
||||
.player_money_balance = Trader->GetCarriedMoney(),
|
||||
};
|
||||
@ -1960,8 +1962,8 @@ void Client::SellToBuyer(const EQApplicationPacket *app)
|
||||
}
|
||||
|
||||
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
|
||||
AddMoneyToPPWithOverflow(total_cost, false);
|
||||
buyer->TakeMoneyFromPPWithOverFlow(total_cost, false);
|
||||
AddMoneyToPP(total_cost, false);
|
||||
buyer->TakeMoneyFromPP(total_cost, false);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::BARTER_TRANSACTION)) {
|
||||
PlayerEvent::BarterTransaction e{};
|
||||
@ -2879,6 +2881,21 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
return;
|
||||
}
|
||||
|
||||
auto next_slot = FindNextFreeParcelSlot(CharacterID());
|
||||
if (next_slot == INVALID_INDEX) {
|
||||
LogTrading(
|
||||
"{} attempted to purchase {} from the bazaar with parcel delivery. Unfortunately their parcel limit was reached. "
|
||||
"Purchase unsuccessful.",
|
||||
GetCleanName(),
|
||||
buy_item->GetItem()->Name
|
||||
);
|
||||
in->method = BazaarByParcel;
|
||||
in->sub_action = TooManyParcels;
|
||||
TraderRepository::UpdateActiveTransaction(database, trader_item.id, false);
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
}
|
||||
|
||||
LogTrading(
|
||||
"Name: <green>[{}] IsStackable: <green>[{}] Requested Quantity: <green>[{}] Charges on Item <green>[{}]",
|
||||
buy_item->GetItem()->Name,
|
||||
@ -2888,23 +2905,24 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
);
|
||||
|
||||
// Determine the actual quantity for the purchase
|
||||
int32 charges = static_cast<int32>(tbs->quantity);
|
||||
if (!buy_item->IsStackable()) {
|
||||
tbs->quantity = 1;
|
||||
}
|
||||
else {
|
||||
int32 item_charges = buy_item->GetCharges();
|
||||
if (item_charges <= 0) {
|
||||
tbs->quantity = 1;
|
||||
if (buy_item->GetCharges() <= 0) {
|
||||
charges = 1;
|
||||
}
|
||||
else if (static_cast<uint32>(item_charges) < tbs->quantity) {
|
||||
tbs->quantity = item_charges;
|
||||
else {
|
||||
charges = buy_item->GetCharges();
|
||||
}
|
||||
}
|
||||
|
||||
LogTrading("Actual quantity that will be traded is <green>[{}]", tbs->quantity);
|
||||
LogTrading(
|
||||
"Actual quantity that will be traded is <green>[{}] {}",
|
||||
tbs->quantity,
|
||||
buy_item->GetCharges() ? fmt::format("with {} charges", buy_item->GetCharges()) : ""
|
||||
);
|
||||
|
||||
uint64 total_transaction_value = static_cast<uint64>(tbs->price) * static_cast<uint64>(tbs->quantity);
|
||||
if (total_transaction_value > MAX_TRANSACTION_VALUE) {
|
||||
uint64 total_cost = static_cast<uint64>(tbs->price) * static_cast<uint64>(tbs->quantity);
|
||||
if (total_cost > MAX_TRANSACTION_VALUE) {
|
||||
Message(
|
||||
Chat::Red,
|
||||
"That would exceed the single transaction limit of %u platinum.",
|
||||
@ -2915,9 +2933,8 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 total_cost = tbs->price * tbs->quantity;
|
||||
uint32 fee = static_cast<uint32>(std::round((uint32) total_cost * RuleR(Bazaar, ParcelDeliveryCostMod)));
|
||||
if (!TakeMoneyFromPP(total_cost + fee)) {
|
||||
uint64 fee = std::round(total_cost * RuleR(Bazaar, ParcelDeliveryCostMod));
|
||||
if (!TakeMoneyFromPP(total_cost + fee, false)) {
|
||||
RecordPlayerEventLog(
|
||||
PlayerEvent::POSSIBLE_HACK,
|
||||
PlayerEvent::PossibleHackEvent{
|
||||
@ -2951,7 +2968,8 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
.trader_id = tbs->trader_id,
|
||||
.trader_name = tbs->seller_name,
|
||||
.price = tbs->price,
|
||||
.charges = tbs->quantity,
|
||||
.quantity = tbs->quantity,
|
||||
.charges = buy_item->IsStackable() ? 1 : charges,
|
||||
.total_cost = total_cost,
|
||||
.player_money_balance = GetCarriedMoney(),
|
||||
};
|
||||
@ -2960,24 +2978,10 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
}
|
||||
|
||||
CharacterParcelsRepository::CharacterParcels parcel_out{};
|
||||
auto next_slot = FindNextFreeParcelSlot(CharacterID());
|
||||
if (next_slot == INVALID_INDEX) {
|
||||
LogTrading(
|
||||
"{} attempted to purchase {} from the bazaar with parcel delivery. Unfortunately their parcel limit was reached. "
|
||||
"Purchase unsuccessful.",
|
||||
GetCleanName(),
|
||||
buy_item->GetItem()->Name
|
||||
);
|
||||
in->method = BazaarByParcel;
|
||||
in->sub_action = TooManyParcels;
|
||||
TraderRepository::UpdateActiveTransaction(database, trader_item.id, false);
|
||||
TradeRequestFailed(app);
|
||||
return;
|
||||
}
|
||||
parcel_out.from_name = tbs->seller_name;
|
||||
parcel_out.note = "Delivered from a Bazaar Purchase";
|
||||
parcel_out.sent_date = time(nullptr);
|
||||
parcel_out.quantity = buy_item->IsStackable() ? tbs->quantity : buy_item->GetCharges();
|
||||
parcel_out.quantity = charges;
|
||||
parcel_out.item_id = buy_item->GetItem()->ID;
|
||||
parcel_out.aug_slot_1 = buy_item->GetAugmentItemID(0);
|
||||
parcel_out.aug_slot_2 = buy_item->GetAugmentItemID(1);
|
||||
@ -3017,7 +3021,8 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
e.augment_4_id = parcel_out.aug_slot_4;
|
||||
e.augment_5_id = parcel_out.aug_slot_5;
|
||||
e.augment_6_id = parcel_out.aug_slot_6;
|
||||
e.quantity = parcel_out.quantity;
|
||||
e.quantity = tbs->quantity;
|
||||
e.charges = buy_item->IsStackable() ? 1 : charges;
|
||||
e.sent_date = parcel_out.sent_date;
|
||||
|
||||
RecordPlayerEventLog(PlayerEvent::PARCEL_SEND, e);
|
||||
@ -3060,6 +3065,8 @@ void Client::BuyTraderItemOutsideBazaar(TraderBuy_Struct *tbs, const EQApplicati
|
||||
strn0cpy(out_data->trader_buy_struct.buyer_name, GetCleanName(), sizeof(out_data->trader_buy_struct.buyer_name));
|
||||
|
||||
worldserver.SendPacket(out_server.get());
|
||||
|
||||
SendMoneyUpdate();
|
||||
}
|
||||
|
||||
void Client::SetBuyerWelcomeMessage(const char *welcome_message)
|
||||
|
||||
@ -4002,21 +4002,23 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
|
||||
TraderRepository::UpdateActiveTransaction(database, in->id, false);
|
||||
|
||||
auto item = trader_pc->FindTraderItemBySerialNumber(item_sn);
|
||||
|
||||
if (player_event_logs.IsEventEnabled(PlayerEvent::TRADER_SELL)) {
|
||||
auto buy_item = trader_pc->FindTraderItemBySerialNumber(item_sn);
|
||||
auto e = PlayerEvent::TraderSellEvent{
|
||||
.item_id = in->trader_buy_struct.item_id,
|
||||
.augment_1_id = buy_item->GetAugmentItemID(0),
|
||||
.augment_2_id = buy_item->GetAugmentItemID(1),
|
||||
.augment_3_id = buy_item->GetAugmentItemID(2),
|
||||
.augment_4_id = buy_item->GetAugmentItemID(3),
|
||||
.augment_5_id = buy_item->GetAugmentItemID(4),
|
||||
.augment_6_id = buy_item->GetAugmentItemID(5),
|
||||
auto e = PlayerEvent::TraderSellEvent{
|
||||
.item_id = item ? item->GetID() : 0,
|
||||
.augment_1_id = item->GetAugmentItemID(0),
|
||||
.augment_2_id = item->GetAugmentItemID(1),
|
||||
.augment_3_id = item->GetAugmentItemID(2),
|
||||
.augment_4_id = item->GetAugmentItemID(3),
|
||||
.augment_5_id = item->GetAugmentItemID(4),
|
||||
.augment_6_id = item->GetAugmentItemID(5),
|
||||
.item_name = in->trader_buy_struct.item_name,
|
||||
.buyer_id = in->buyer_id,
|
||||
.buyer_name = in->trader_buy_struct.buyer_name,
|
||||
.price = in->trader_buy_struct.price,
|
||||
.charges = in->trader_buy_struct.quantity,
|
||||
.quantity = in->trader_buy_struct.quantity,
|
||||
.charges = item ? item->IsStackable() ? 1 : item->GetCharges() : 0,
|
||||
.total_cost = (in->trader_buy_struct.price * in->trader_buy_struct.quantity),
|
||||
.player_money_balance = trader_pc->GetCarriedMoney(),
|
||||
};
|
||||
@ -4121,7 +4123,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
sell_line.seller_quantity,
|
||||
sell_line.item_name,
|
||||
buyer->GetCleanName());
|
||||
buyer->AddMoneyToPPWithOverflow(total_cost, true);
|
||||
buyer->AddMoneyToPP(total_cost, true);
|
||||
buyer->RemoveItem(sell_line.item_id, sell_line.seller_quantity);
|
||||
|
||||
buyer->Message(
|
||||
@ -4220,7 +4222,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
if (inst->IsStackable()) {
|
||||
if (!buyer->PutItemInInventoryWithStacking(inst.get())) {
|
||||
buyer->Message(Chat::Red, "Error putting item in your inventory.");
|
||||
buyer->AddMoneyToPPWithOverflow(total_cost, true);
|
||||
buyer->AddMoneyToPP(total_cost, true);
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
@ -4232,7 +4234,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
inst->SetCharges(1);
|
||||
if (!buyer->PutItemInInventoryWithStacking(inst.get())) {
|
||||
buyer->Message(Chat::Red, "Error putting item in your inventory.");
|
||||
buyer->AddMoneyToPPWithOverflow(total_cost, true);
|
||||
buyer->AddMoneyToPP(total_cost, true);
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
@ -4241,7 +4243,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
}
|
||||
}
|
||||
|
||||
if (!buyer->TakeMoneyFromPPWithOverFlow(total_cost, false)) {
|
||||
if (!buyer->TakeMoneyFromPP(total_cost, false)) {
|
||||
in->action = Barter_FailedTransaction;
|
||||
in->sub_action = Barter_FailedBuyerChecks;
|
||||
worldserver.SendPacket(pack);
|
||||
@ -4306,7 +4308,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
||||
|
||||
uint64 total_cost = (uint64) sell_line.item_cost * (uint64) sell_line.seller_quantity;
|
||||
seller->RemoveItem(in->buy_item_id, in->seller_quantity);
|
||||
seller->AddMoneyToPPWithOverflow(total_cost, false);
|
||||
seller->AddMoneyToPP(total_cost, false);
|
||||
seller->SendBarterBuyerClientMessage(
|
||||
sell_line,
|
||||
Barter_SellerTransactionComplete,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user