From e57a789dce374d9a28944c0d30a9491eed6951e8 Mon Sep 17 00:00:00 2001 From: Mitch Freeman <65987027+neckkola@users.noreply.github.com> Date: Fri, 11 Apr 2025 23:25:52 -0300 Subject: [PATCH] Trader Direct purchase updated and tested --- zone/inventory.cpp | 90 +++++++++++++++++++++++++++++++++++++++++----- zone/trading.cpp | 32 +++++++++++------ 2 files changed, 103 insertions(+), 19 deletions(-) diff --git a/zone/inventory.cpp b/zone/inventory.cpp index 340ede084..60ab0cd33 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -4673,19 +4673,93 @@ bool Client::HasItemOnCorpse(uint32 item_id) bool Client::PutItemInInventoryWithStacking(EQ::ItemInstance *inst) { - auto free_id = GetInv().FindFirstFreeSlotThatFitsItem(inst->GetItem()); - if (inst->IsStackable()) { - if (TryStacking(inst, ItemPacketTrade, true, false)) { + struct temp { + int16 slot_id; + int32 quantity; + }; + + std::vector queue; + auto free_id = GetInv().FindFirstFreeSlotThatFitsItem(inst->GetItem()); + auto quantity = inst->GetCharges(); // 2 + auto remaining_quantity = 0; + auto item_size = inst->GetItem()->Size; + + for (int i = EQ::invslot::GENERAL_BEGIN; i <= EQ::invslot::GENERAL_END; i++) { + auto inv_inst = GetInv().GetItem(i); + if (!inv_inst) { + LogError("Found a slot {} in general inventory", i); + PutItemInInventory(i, *inst, true); return true; } - } - if (free_id != INVALID_INDEX) { - if (PutItemInInventory(free_id, *inst, true)) { - return true; + + int16 base_slot_id = EQ::InventoryProfile::CalcSlotId(i, EQ::invbag::SLOT_BEGIN); + uint8 bag_size = inv_inst->GetItem()->BagSlots; + + for (uint8 bag_slot = EQ::invbag::SLOT_BEGIN; bag_slot < bag_size; bag_slot++) { + auto bag_inst = GetInv().GetItem(base_slot_id + bag_slot); + if (!bag_inst && inv_inst->GetItem()->BagSize >= inst->GetItem()->Size) { + LogError("Found a parent {} base_slot_id {} bag_slot {} in bag", i, base_slot_id, bag_slot); + PutItemInInventory(base_slot_id + bag_slot, *inst, true); + return true; + } + + if (bag_inst && bag_inst->IsStackable() && bag_inst->GetID() == inst->GetID()) { + auto stack_size = bag_inst->GetItem()->StackSize; // 100 + auto bag_inst_quantity = bag_inst->GetCharges(); + int16 temp_slot = base_slot_id + bag_slot; + if (stack_size - bag_inst_quantity >= quantity) { + temp tmp = { temp_slot, quantity }; + queue.push_back(tmp); + quantity = 0; + LogError( + "Found an item parent {} base_slot_id {} bag_slot {} in bag with ENOUGH space", + i, + base_slot_id, + bag_slot + ); + break; + } + + if (stack_size - bag_inst_quantity > 0) { + temp tmp = { temp_slot, stack_size - bag_inst_quantity }; + queue.push_back(tmp); + quantity -= stack_size - bag_inst_quantity; + LogError( + "Found an item parent {} base_slot_id {} bag_slot {} in bag with SOME space", + i, + base_slot_id, + bag_slot + ); + } + } } } + + if (!queue.empty()) { + database.TransactionBegin(); + for (auto const &i: queue) { + auto bag_inst = GetInv().GetItem(i.slot_id); + if (!bag_inst) { + LogError("Client inventory error occurred. Character ID {} Slot_ID {}", CharacterID(), i.slot_id); + continue; + } + bag_inst->SetCharges(i.quantity + bag_inst->GetCharges()); + PutItemInInventory(i.slot_id, *bag_inst, true); + LogError("Write out data. Item {} quantity {} slot {}", bag_inst->GetItem()->Name, i.quantity, i.slot_id); + } + + database.TransactionCommit(); + quantity = 0; + } + + if (quantity == 0) { + LogError("Quantity was zero. All items placed in inventory."); + return true; + } + + LogError("Could not find enough room"); return false; -}; +} bool Client::FindNumberOfFreeInventorySlotsWithSizeCheck(std::vector items) { diff --git a/zone/trading.cpp b/zone/trading.cpp index 2aecdaafa..a7f8d3706 100644 --- a/zone/trading.cpp +++ b/zone/trading.cpp @@ -1386,7 +1386,9 @@ void Client::BuyTraderItem(const EQApplicationPacket *app) auto data = reinterpret_cast(trader_packet->pBuffer); auto buy_inst = trader->FindTraderItemByUniqueID(in->item_unique_id); - if (!buy_inst) { + std::unique_ptr inst_copy(buy_inst ? buy_inst->Clone() : nullptr); + + if (!buy_inst || !inst_copy) { LogTrading("Unable to find item id [{}] item_sn [{}] on trader", in->item_id, in->item_unique_id); Message(Chat::Red, "The trader no longer has the item for sale. Please refresh the merchant window."); TradeRequestFailed(app); @@ -1394,6 +1396,11 @@ void Client::BuyTraderItem(const EQApplicationPacket *app) } uint32 quantity = in->quantity; + inst_copy->SetCharges(quantity); + if (inst_copy->IsStackable()) { + inst_copy->CreateUniqueID(); + } + LogTrading( "Name: [{}] IsStackable: [{}] Requested Quantity: [{}]", buy_inst->GetItem()->Name, @@ -1458,10 +1465,6 @@ void Client::BuyTraderItem(const EQApplicationPacket *app) return; } - if (quantity != 1) { - buy_inst->SetCharges(quantity); - } - if (!trader->RemoveItemByItemUniqueId(buy_inst->GetUniqueID(), quantity)) { Message(Chat::Red, "The Trader no longer has the item. Please refresh the merchant window."); TradeRequestFailed(app); @@ -1470,7 +1473,13 @@ void Client::BuyTraderItem(const EQApplicationPacket *app) trader->AddMoneyToPP(copper, silver, gold, platinum, true); - if (!AutoPutLootInInventory(*buy_inst, false, true)) { + // if (buy_inst->IsStackable() && !TryStacking(buy_inst, ItemPacketTrade, false, false)) { + // MessageString(Chat::Red, HOW_CAN_YOU_BUY_MORE, trader->GetCleanName()); + // TradeRequestFailed(app); + // return; + // } + + if (!PutItemInInventoryWithStacking(inst_copy.get())) { MessageString(Chat::Red, HOW_CAN_YOU_BUY_MORE, trader->GetCleanName()); TradeRequestFailed(app); return; @@ -1490,13 +1499,14 @@ void Client::BuyTraderItem(const EQApplicationPacket *app) trader->QueuePacket(trader_packet.get()); if (merchant_quantity > quantity) { - buy_inst->SetMerchantCount(merchant_quantity - quantity); - buy_inst->SetMerchantSlot(slot_id); - buy_inst->SetPrice(in->price); + std::unique_ptr vendor_inst(buy_inst ? buy_inst->Clone() : nullptr); + vendor_inst->SetMerchantCount(merchant_quantity - quantity); + vendor_inst->SetMerchantSlot(slot_id); + vendor_inst->SetPrice(in->price); auto list = GetTraderMerchantList(); - std::get<0>(list->at(slot_id)) -= quantity; - SendItemPacket(slot_id, buy_inst, ItemPacketMerchant); TraderRepository::UpdateQuantity(database, item_unique_id, merchant_quantity - quantity); + std::get<0>(list->at(slot_id)) -= quantity; + SendItemPacket(slot_id, vendor_inst.get(), ItemPacketMerchant); } else { auto client_packet = new EQApplicationPacket(OP_ShopDelItem, static_cast(sizeof(Merchant_DelItem_Struct)));