diff --git a/common/eq_limits.cpp b/common/eq_limits.cpp index 1bfbb6d29..56a370ceb 100644 --- a/common/eq_limits.cpp +++ b/common/eq_limits.cpp @@ -48,6 +48,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers ClientUnknown::constants::EXPANSIONS_MASK, ClientUnknown::INULL, ClientUnknown::INULL, + ClientUnknown::INULL, ClientUnknown::INULL ), /*[ClientVersion::Client62] =*/ @@ -57,6 +58,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers Client62::constants::EXPANSIONS_MASK, Client62::INULL, Client62::INULL, + Client62::INULL, Client62::INULL ), /*[ClientVersion::Titanium] =*/ @@ -66,6 +68,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers Titanium::constants::EXPANSIONS_MASK, Titanium::constants::CHARACTER_CREATION_LIMIT, Titanium::constants::SAY_LINK_BODY_SIZE, + Titanium::INULL, Titanium::INULL ), /*[ClientVersion::SoF] =*/ @@ -75,6 +78,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers SoF::constants::EXPANSIONS_MASK, SoF::constants::CHARACTER_CREATION_LIMIT, SoF::constants::SAY_LINK_BODY_SIZE, + SoF::INULL, SoF::INULL ), /*[ClientVersion::SoD] =*/ @@ -84,6 +88,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers SoD::constants::EXPANSIONS_MASK, SoD::constants::CHARACTER_CREATION_LIMIT, SoD::constants::SAY_LINK_BODY_SIZE, + SoD::INULL, SoD::INULL ), /*[ClientVersion::UF] =*/ @@ -93,6 +98,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers UF::constants::EXPANSIONS_MASK, UF::constants::CHARACTER_CREATION_LIMIT, UF::constants::SAY_LINK_BODY_SIZE, + UF::INULL, UF::INULL ), /*[ClientVersion::RoF] =*/ @@ -102,6 +108,7 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers RoF::constants::EXPANSIONS_MASK, RoF::constants::CHARACTER_CREATION_LIMIT, RoF::constants::SAY_LINK_BODY_SIZE, + RoF::INULL, RoF::INULL ), /*[ClientVersion::RoF2] =*/ @@ -111,7 +118,8 @@ static const EQ::constants::LookupEntry constants_static_lookup_entries[EQ::vers RoF2::constants::EXPANSIONS_MASK, RoF2::constants::CHARACTER_CREATION_LIMIT, RoF2::constants::SAY_LINK_BODY_SIZE, - RoF2::constants::MAX_BAZAAR_TRADERS + RoF2::constants::MAX_BAZAAR_TRADERS, + RoF2::constants::MAX_BAZAAR_TRANSACTION ) }; diff --git a/common/eq_limits.h b/common/eq_limits.h index 6c00e411e..ab10edce3 100644 --- a/common/eq_limits.h +++ b/common/eq_limits.h @@ -43,6 +43,7 @@ namespace EQ int16 CharacterCreationLimit; size_t SayLinkBodySize; uint32 BazaarTraderLimit; + uint32 BazaarMaxTransaction; LookupEntry(const LookupEntry *lookup_entry) { } LookupEntry( @@ -51,14 +52,16 @@ namespace EQ uint32 ExpansionsMask, int16 CharacterCreationLimit, size_t SayLinkBodySize, - uint32 BazaarTraderLimit + uint32 BazaarTraderLimit, + uint32 BazaarMaxTransaction ) : Expansion(Expansion), ExpansionBit(ExpansionBit), ExpansionsMask(ExpansionsMask), CharacterCreationLimit(CharacterCreationLimit), SayLinkBodySize(SayLinkBodySize), - BazaarTraderLimit(BazaarTraderLimit) + BazaarTraderLimit(BazaarTraderLimit), + BazaarMaxTransaction(BazaarMaxTransaction) { } }; diff --git a/common/servertalk.h b/common/servertalk.h index cfc0d49df..2180d9c85 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -369,12 +369,13 @@ enum { }; enum { - BazaarPurchaseFailed = 0, - BazaarPurchaseSuccess = 1, - BazaarPurchaseSellerFailed = 2, - BazaarPurchaseSellerSuccess = 3, - BazaarPurchaseBuyerFailed = 4, - BazaarPurchaseBuyerSuccess = 5 + BazaarPurchaseFailed = 0, + BazaarPurchaseSuccess = 1, + BazaarPurchaseBuyerCompleteSendToSeller = 2, + BazaarPurchaseSellerCompleteSendToBuyer = 3, + BazaarPurchaseBuyerFailed = 4, + BazaarPurchaseBuyerSuccess = 5, + BazaarPurchaseTraderFailed = 6 }; /************ PACKET RELATED STRUCT ************/ class ServerPacket @@ -1783,10 +1784,13 @@ struct BazaarPurchaseMessaging_Struct { uint32 item_aug_5; uint32 item_aug_6; uint32 buyer_id; - uint32 item_charges; + uint32 item_quantity; + int16 item_charges; uint32 id; uint32 trader_zone_id; uint32 trader_zone_instance_id; + uint32 buyer_zone_id; + uint32 buyer_zone_instance_id; uint32 transaction_status; }; diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index f428aa87b..4a372cb79 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -1674,21 +1674,23 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { break; } case ServerOP_BazaarPurchase: { - auto in = (BazaarPurchaseMessaging_Struct *)pack->pBuffer; - if (in->trader_buy_struct.trader_id <= 0) { - LogTrading( - "World Message [{}] received with invalid trader_id [{}]", - "ServerOP_BazaarPurchase", - in->trader_buy_struct.trader_id - ); - return; + auto in = reinterpret_cast(pack->pBuffer); + switch (in->transaction_status) { + case BazaarPurchaseBuyerCompleteSendToSeller: { + zoneserver_list.SendPacket(in->trader_zone_id, in->trader_zone_instance_id, pack); + break; + } + case BazaarPurchaseTraderFailed: + case BazaarPurchaseSuccess: { + zoneserver_list.SendPacket(in->buyer_zone_id, in->buyer_zone_instance_id, pack); + break; + } + default: { + LogError( + "ServerOP_BazaarPurchase received with no corresponding action for [{}]", + in->transaction_status); + } } - - auto trader = ClientList::Instance()->FindCLEByCharacterID(in->trader_buy_struct.trader_id); - if (trader) { - ZSList::Instance()->SendPacket(in->trader_zone_id, in->trader_zone_instance_id, pack); - } - break; } case ServerOP_BuyerMessaging: { diff --git a/zone/trading.cpp b/zone/trading.cpp index 473ebc5cf..f082d2865 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1462,11 +1462,11 @@ void Client::BuyTraderItem(const EQApplicationPacket *app) } uint64 total_transaction_value = static_cast(in->price) * static_cast(quantity); - if (total_transaction_value > RoF2::constants::MAX_BAZAAR_TRANSACTION) { + if (total_transaction_value > EQ::constants::StaticLookup(ClientVersion())->BazaarMaxTransaction) { Message( Chat::Red, "That would exceed the single transaction limit of %u platinum.", - RoF2::constants::MAX_BAZAAR_TRANSACTION / 1000 + EQ::constants::StaticLookup(ClientVersion())->BazaarMaxTransaction / 1000 ); TradeRequestFailed(app); return; @@ -2853,9 +2853,9 @@ void Client::BuyTraderItemFromBazaarWindow(const EQApplicationPacket *app) TraderRepository::UpdateActiveTransaction(database, trader_item.id, true); uint32 quantity = in->quantity; - int16 charges = 1; - auto item = database.GetItem(trader_item.item_id); + auto item = database.GetItem(trader_item.item_id); + int16 charges = 1; if (trader_item.item_charges > 0 || item->Stackable || item->MaxCharges > 0) { charges = trader_item.item_charges; } @@ -2870,12 +2870,12 @@ void Client::BuyTraderItemFromBazaarWindow(const EQApplicationPacket *app) in->item_unique_id ); - uint64 total_cost = static_cast(in->price) * static_cast(in->quantity); - if (total_cost > RoF2::constants::MAX_BAZAAR_TRANSACTION) { + uint64 total_cost = static_cast(in->price) * static_cast(quantity); + if (total_cost > EQ::constants::StaticLookup(ClientVersion())->BazaarMaxTransaction) { Message( Chat::Red, "That would exceed the single transaction limit of %u platinum.", - RoF2::constants::MAX_BAZAAR_TRANSACTION / 1000 + EQ::constants::StaticLookup(ClientVersion())->BazaarMaxTransaction / 1000 ); TraderRepository::UpdateActiveTransaction(database, trader_item.id, false); TradeRequestFailed(app); @@ -2895,114 +2895,10 @@ void Client::BuyTraderItemFromBazaarWindow(const EQApplicationPacket *app) LogTrading("Customer [{}] Paid: [{}] to trader [{}]", CharacterID(), DetermineMoneyString(total_cost), trader_item.character_id); LogTradingDetail("Step 2:Bazaar Purchase. Took [{}] from Buyer [{}] ", DetermineMoneyString(total_cost), CharacterID()); - if (buy_item && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_PURCHASE)) { - auto e = PlayerEvent::TraderPurchaseEvent{ - .item_id = trader_item.item_id, - .augment_1_id = trader_item.augment_one, - .augment_2_id = trader_item.augment_two, - .augment_3_id = trader_item.augment_three, - .augment_4_id = trader_item.augment_four, - .augment_5_id = trader_item.augment_five, - .augment_6_id = trader_item.augment_six, - .item_name = in->item_name, - .trader_id = in->trader_id, - .trader_name = in->seller_name, - .price = in->price, - .quantity = in->quantity, - .charges = trader_item.item_charges, - .total_cost = total_cost, - .player_money_balance = GetCarriedMoney(), - }; - - RecordPlayerEventLog(PlayerEvent::TRADER_PURCHASE, e); - } - - CharacterParcelsRepository::CharacterParcels parcel_out{}; - parcel_out.from_name = in->seller_name; - parcel_out.note = "Delivered from a Bazaar Purchase"; - parcel_out.sent_date = time(nullptr); - parcel_out.quantity = charges; - parcel_out.item_id = trader_item.item_id; - parcel_out.aug_slot_1 = trader_item.augment_one; - parcel_out.aug_slot_2 = trader_item.augment_two; - parcel_out.aug_slot_3 = trader_item.augment_three; - parcel_out.aug_slot_4 = trader_item.augment_four; - parcel_out.aug_slot_5 = trader_item.augment_five; - parcel_out.aug_slot_6 = trader_item.augment_six; - parcel_out.char_id = CharacterID(); - parcel_out.slot_id = next_slot; - parcel_out.id = 0; - - auto result = CharacterParcelsRepository::InsertOne(database, parcel_out); - if (!result.id) { - LogError("Failed to add parcel to database. From {} to {} item {} quantity {}", - parcel_out.from_name, - GetCleanName(), - parcel_out.item_id, - parcel_out.quantity - ); - Message(Chat::Yellow, "Unable to save parcel to the database. Please contact an administrator."); - in->method = BazaarByParcel; - in->sub_action = Failed; - TraderRepository::UpdateActiveTransaction(database, trader_item.id, false); - AddMoneyToPP(total_cost + fee); - TradeRequestFailed(app); - return; - } - - ReturnTraderReq(app, in->quantity, trader_item.item_id); - if (PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::PARCEL_SEND)) { - PlayerEvent::ParcelSend e{}; - e.from_player_name = parcel_out.from_name; - e.to_player_name = GetCleanName(); - e.item_id = parcel_out.item_id; - e.augment_1_id = parcel_out.aug_slot_1; - e.augment_2_id = parcel_out.aug_slot_2; - e.augment_3_id = parcel_out.aug_slot_3; - 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 = in->quantity; - e.charges = trader_item.item_charges; - e.sent_date = parcel_out.sent_date; - - RecordPlayerEventLog(PlayerEvent::PARCEL_SEND, e); - } - - Parcel_Struct ps{}; - ps.item_slot = parcel_out.slot_id; - strn0cpy(ps.send_to, GetCleanName(), sizeof(ps.send_to)); - SendParcelDeliveryToWorld(ps); - - LogTradingDetail("Step 3:Bazaar Purchase. Sent parcel to Buyer [{}] Item ID [{}] Quantity [{}] Charges [{}]", - CharacterID(), - trader_item.item_id, - quantity, - charges - ); - - if (item->Stackable && quantity != charges) { - TraderRepository::UpdateQuantity(database, in->item_unique_id, trader_item.item_charges - quantity); - LogTradingDetail( - "Step 4a:Bazaar Purchase. Decreased database id {} from [{}] to [{}] charges", - trader_item.item_id, - trader_item.item_charges, - charges - ); - } - else { - TraderRepository::DeleteOne(database, trader_item.id); - LogTradingDetail( - "Step 4b:Bazaar Purchase. Deleted database id [{}] because database quantity [{}] equals [{}] purchased quantity", - trader_item.id, - trader_item.item_charges, - charges - ); - } - auto out_server = std::make_unique(ServerOP_BazaarPurchase, sizeof(BazaarPurchaseMessaging_Struct)); - auto out_data = (BazaarPurchaseMessaging_Struct *) out_server->pBuffer; + auto out_data = reinterpret_cast(out_server->pBuffer); + out_data->transaction_status = BazaarPurchaseBuyerCompleteSendToSeller; out_data->trader_buy_struct.action = in->action; out_data->trader_buy_struct.method = in->method; out_data->trader_buy_struct.already_sold = in->already_sold; @@ -3010,7 +2906,7 @@ void Client::BuyTraderItemFromBazaarWindow(const EQApplicationPacket *app) out_data->trader_buy_struct.price = in->price; out_data->trader_buy_struct.quantity = in->quantity; out_data->trader_buy_struct.sub_action = in->sub_action; - out_data->trader_buy_struct.trader_id = in->trader_id; + out_data->trader_buy_struct.trader_id = trader_item.character_id; out_data->buyer_id = CharacterID(); out_data->item_aug_1 = trader_item.augment_one; out_data->item_aug_2 = trader_item.augment_two; @@ -3018,10 +2914,13 @@ void Client::BuyTraderItemFromBazaarWindow(const EQApplicationPacket *app) out_data->item_aug_4 = trader_item.augment_four; out_data->item_aug_5 = trader_item.augment_five; out_data->item_aug_6 = trader_item.augment_six; - out_data->item_charges = trader_item.item_charges; + out_data->item_quantity = quantity; + out_data->item_charges = charges; out_data->id = trader_item.id; out_data->trader_zone_id = trader_item.char_zone_id; out_data->trader_zone_instance_id = trader_item.char_zone_instance_id; + out_data->buyer_zone_id = GetZoneID(); + out_data->buyer_zone_instance_id = GetInstanceID(); strn0cpy(out_data->trader_buy_struct.buyer_name, GetCleanName(), sizeof(out_data->trader_buy_struct.buyer_name)); strn0cpy(out_data->trader_buy_struct.seller_name, in->seller_name, sizeof(out_data->trader_buy_struct.seller_name)); strn0cpy(out_data->trader_buy_struct.item_name, in->item_name, sizeof(out_data->trader_buy_struct.item_name)); diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index d17bfbfb7..4be8a4dbe 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -3774,62 +3774,226 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) break; } case ServerOP_BazaarPurchase: { - auto in = (BazaarPurchaseMessaging_Struct *) pack->pBuffer; - auto trader_pc = entity_list.GetClientByCharID(in->trader_buy_struct.trader_id); - if (!trader_pc) { - LogTrading("Request trader_id [{}] could not be found in zone_id [{}]", - in->trader_buy_struct.trader_id, - zone->GetZoneID() - ); - return; - } + auto in = reinterpret_cast(pack->pBuffer); + switch (in->transaction_status) { + case BazaarPurchaseBuyerCompleteSendToSeller: { + auto trader_pc = entity_list.GetClientByCharID(in->trader_buy_struct.trader_id); + if (!trader_pc) { + LogTrading( + "Request trader_id [{}] could not be found in zone_id [{}]", + in->trader_buy_struct.trader_id, + zone->GetZoneID()); + return; + } - if (trader_pc->IsThereACustomer()) { - auto customer = entity_list.GetClientByID(trader_pc->GetCustomerID()); - if (customer) { - customer->CancelTraderTradeWindow(); + auto item = trader_pc->FindTraderItemByUniqueID(in->trader_buy_struct.item_unique_id); + if (!item) { + in->transaction_status = BazaarPurchaseTraderFailed; + TraderRepository::UpdateActiveTransaction(database, in->id, false); + worldserver.SendPacket(pack); + break; + } + + //if there is a customer currently browsing, close to ensure no conflict of purchase + if (trader_pc->IsThereACustomer()) { + auto customer = entity_list.GetClientByID(trader_pc->GetCustomerID()); + if (customer) { + customer->CancelTraderTradeWindow(); + } + } + + //Update the trader's db entries + if (item->IsStackable() && in->item_quantity != in->item_charges) { + TraderRepository::UpdateQuantity(database, in->trader_buy_struct.item_unique_id, item->GetCharges() - in->item_quantity); + LogTradingDetail( + "Step 4a:Bazaar Purchase. Decreased database id {} from [{}] to [{}] charges", + in->trader_buy_struct.item_id, + in->item_charges, + in->item_charges + ); + } + else { + TraderRepository::DeleteOne(database, in->trader_buy_struct.item_id); + LogTradingDetail( + "Step 4b:Bazaar Purchase. Deleted database id [{}] because database quantity [{}] equals [{}] purchased quantity", + in->trader_buy_struct.item_id, + in->item_charges, + in->item_charges + ); + } + + //at this time, buyer checks ok, seller checks ok. + //perform actions to trader + uint64 total_cost = static_cast(in->trader_buy_struct.price) * static_cast(in->item_quantity); + if (!trader_pc->RemoveItemByItemUniqueId(in->trader_buy_struct.item_unique_id, in->item_quantity)) { + in->transaction_status = BazaarPurchaseTraderFailed; + TraderRepository::UpdateActiveTransaction(database, in->id, false); + worldserver.SendPacket(pack); + break; + } + + trader_pc->AddMoneyToPP(total_cost, true); + + //Update the trader to indicate the sale has completed + EQApplicationPacket outapp(OP_Trader, sizeof(TraderBuy_Struct)); + auto data = reinterpret_cast(outapp.pBuffer); + + memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct)); + trader_pc->QueuePacket(&outapp); + + if (item && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_SELL)) { + auto e = PlayerEvent::TraderSellEvent{ + .item_id = item->GetID(), + .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, + .quantity = in->item_quantity, + .charges = in->item_charges, + .total_cost = total_cost, + .player_money_balance = trader_pc->GetCarriedMoney(), + }; + RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e); + } + + in->transaction_status = BazaarPurchaseSuccess; + TraderRepository::UpdateActiveTransaction(database, in->id, false); + worldserver.SendPacket(pack); + + break; + } + case BazaarPurchaseTraderFailed: { + auto buyer = entity_list.GetClientByCharID(in->buyer_id); + if (!buyer) { + LogTrading( + "Requested buyer_id [{}] could not be found in zone_id [{}] instance_id [{}]", + in->trader_buy_struct.trader_id, + zone->GetZoneID(), + zone->GetInstanceID() + ); + return; + } + + // return buyer's money including the fee + uint64 total_cost = + static_cast(in->trader_buy_struct.price) * static_cast(in->item_quantity); + uint64 fee = std::round(total_cost * RuleR(Bazaar, ParcelDeliveryCostMod)); + buyer->AddMoneyToPP(total_cost + fee, false); + buyer->SendMoneyUpdate(); + + break; + } + case BazaarPurchaseSuccess: { + auto buyer = entity_list.GetClientByCharID(in->buyer_id); + if (!buyer) { + LogTrading( + "Requested buyer_id [{}] could not be found in zone_id [{}] instance_id [{}]", + in->trader_buy_struct.trader_id, + zone->GetZoneID(), + zone->GetInstanceID() + ); + return; + } + uint64 total_cost = + static_cast(in->trader_buy_struct.price) * static_cast(in->item_quantity); + + if (player_event_logs.IsEventEnabled(PlayerEvent::TRADER_PURCHASE)) { + auto e = PlayerEvent::TraderPurchaseEvent{ + .item_id = in->trader_buy_struct.item_id, + .augment_1_id = in->item_aug_1, + .augment_2_id = in->item_aug_2, + .augment_3_id = in->item_aug_3, + .augment_4_id = in->item_aug_4, + .augment_5_id = in->item_aug_5, + .augment_6_id = in->item_aug_6, + .item_name = in->trader_buy_struct.item_name, + .trader_id = in->trader_buy_struct.trader_id, + .trader_name = in->trader_buy_struct.seller_name, + .price = in->trader_buy_struct.price, + .quantity = in->item_quantity, + .charges = in->item_charges, + .total_cost = total_cost, + .player_money_balance = buyer->GetCarriedMoney(), + }; + + RecordPlayerEventLogWithClient(buyer, PlayerEvent::TRADER_PURCHASE, e); + } + + auto item = database.GetItem(in->trader_buy_struct.item_id); + auto quantity = in->item_quantity; + if (item->MaxCharges > 0) { + quantity = in->item_charges; + } + + //Send the item via parcel + CharacterParcelsRepository::CharacterParcels parcel_out{}; + parcel_out.from_name = in->trader_buy_struct.seller_name; + parcel_out.note = "Delivered from a Bazaar Purchase"; + parcel_out.sent_date = time(nullptr); + parcel_out.quantity = quantity; + parcel_out.item_id = in->trader_buy_struct.item_id; + parcel_out.aug_slot_1 = in->item_aug_1; + parcel_out.aug_slot_2 = in->item_aug_2; + parcel_out.aug_slot_3 = in->item_aug_3; + parcel_out.aug_slot_4 = in->item_aug_4; + parcel_out.aug_slot_5 = in->item_aug_5; + parcel_out.aug_slot_6 = in->item_aug_6; + parcel_out.char_id = buyer->CharacterID(); + parcel_out.slot_id = buyer->FindNextFreeParcelSlot(buyer->CharacterID()); + parcel_out.id = 0; + + CharacterParcelsRepository::InsertOne(database, parcel_out); + + if (player_event_logs.IsEventEnabled(PlayerEvent::PARCEL_SEND)) { + PlayerEvent::ParcelSend e{}; + e.from_player_name = parcel_out.from_name; + e.to_player_name = buyer->GetCleanName(); + e.item_id = parcel_out.item_id; + e.augment_1_id = parcel_out.aug_slot_1; + e.augment_2_id = parcel_out.aug_slot_2; + e.augment_3_id = parcel_out.aug_slot_3; + 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 = in->item_quantity; + e.charges = in->item_charges; + e.sent_date = parcel_out.sent_date; + + RecordPlayerEventLogWithClient(buyer, PlayerEvent::PARCEL_SEND, e); + } + + Parcel_Struct ps{}; + ps.item_slot = parcel_out.slot_id; + strn0cpy(ps.send_to, buyer->GetCleanName(), sizeof(ps.send_to)); + buyer->SendParcelDeliveryToWorld(ps); + + LogTradingDetail( + "Step 3:Bazaar Purchase. Sent parcel to Buyer [{}] Item ID [{}] Quantity [{}] Charges [{}]", + buyer->CharacterID(), + in->trader_buy_struct.item_id, + in->item_quantity, + in->item_charges + ); + + //Update the buyer to indicate the sale has completed + EQApplicationPacket outapp(OP_Trader, sizeof(TraderBuy_Struct)); + auto data = reinterpret_cast(outapp.pBuffer); + + memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct)); + buyer->ReturnTraderReq(&outapp, in->item_quantity, in->trader_buy_struct.item_id); + + break; + } + default: { } } - auto sn = std::string(in->trader_buy_struct.item_unique_id); - auto outapp = std::make_unique(OP_Trader, static_cast(sizeof(TraderBuy_Struct))); - auto data = (TraderBuy_Struct *) outapp->pBuffer; - - memcpy(data, &in->trader_buy_struct, sizeof(TraderBuy_Struct)); - - if (trader_pc->ClientVersion() < EQ::versions::ClientVersion::RoF) { - data->price = in->trader_buy_struct.price * in->trader_buy_struct.quantity; - } - - TraderRepository::UpdateActiveTransaction(database, in->id, false); - - auto item = trader_pc->FindTraderItemBySerialNumber(sn); - - if (item && PlayerEventLogs::Instance()->IsEventEnabled(PlayerEvent::TRADER_SELL)) { - 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, - .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(), - }; - RecordPlayerEventLogWithClient(trader_pc, PlayerEvent::TRADER_SELL, e); - } - - trader_pc->RemoveItemByItemUniqueId(sn, in->trader_buy_struct.quantity); - trader_pc->AddMoneyToPP(in->trader_buy_struct.price * in->trader_buy_struct.quantity, true); - trader_pc->QueuePacket(outapp.get()); - break; } case ServerOP_BuyerMessaging: {