OP_MoveItem encode/decode for RoF2, disabled other patches for now (until i get rof2 packets and mechanics working well enough to go back and fix those)

This commit is contained in:
KimLS
2015-02-23 22:45:50 -08:00
parent 8bce7893ed
commit 69612b44d4
20 changed files with 1560 additions and 1352 deletions
+3 -3
View File
@@ -813,9 +813,9 @@ public:
bool PushItemOnCursor(const ItemInst& inst, bool client_update = false);
void SendCursorBuffer();
void DeleteItemInInventory(int16 slot_id, int8 quantity = 0, bool client_update = false, bool update_db = true);
bool SwapItem(MoveItem_Struct* move_in);
void SwapItemResync(MoveItem_Struct* move_slots);
void QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call = false);
bool SwapItem(MoveItemOld_Struct* move_in);
void SwapItemResync(MoveItemOld_Struct* move_slots);
void QSSwapItemAuditor(MoveItemOld_Struct* move_in, bool postaction_call = false);
void PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data = 0);
bool AutoPutLootInInventory(ItemInst& inst, bool try_worn = false, bool try_cursor = true, ServerLootItem_Struct** bag_item_data = 0);
bool SummonItem(uint32 item_id, int16 charges = -1, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0, uint32 aug5 = 0, uint32 aug6 = 0, bool attuned = false, uint16 to_slot = MainCursor, uint32 ornament_icon = 0, uint32 ornament_idfile = 0, uint32 ornament_hero_model = 0);
+64 -55
View File
@@ -9586,68 +9586,77 @@ void Client::Handle_OP_MoveItem(const EQApplicationPacket *app)
{
return;
}
if (app->size != sizeof(MoveItem_Struct)) {
Log.Out(Logs::General, Logs::Error, "Wrong size: OP_MoveItem, size=%i, expected %i", app->size, sizeof(MoveItem_Struct));
return;
}
MoveItem_Struct* mi = (MoveItem_Struct*)app->pBuffer;
if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
{
if (mi->from_slot != mi->to_slot && (mi->from_slot <= EmuConstants::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
{
char *detect = nullptr;
const ItemInst *itm_from = GetInv().GetItem(mi->from_slot);
const ItemInst *itm_to = GetInv().GetItem(mi->to_slot);
MakeAnyLenString(&detect, "Player issued a move item from %u(item id %u) to %u(item id %u) while casting %u.",
mi->from_slot,
itm_from ? itm_from->GetID() : 0,
mi->to_slot,
itm_to ? itm_to->GetID() : 0,
casting_spell_id);
database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
safe_delete_array(detect);
Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
return;
}
}
auto res = m_inventory.Swap(EQEmu::InventorySlot(mi->from_type, mi->from_slot, mi->from_bag_slot, mi->from_aug_slot),
EQEmu::InventorySlot(mi->to_type, mi->to_slot, mi->to_bag_slot, mi->to_aug_slot),
mi->number_in_stack);
// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
bool mi_hack = false;
//printf("%i %i %i %i --> %i %i %i %i (%u)\n",
// mi->from_type, mi->from_slot, mi->from_bag_slot, mi->from_aug_slot,
// mi->to_type, mi->to_slot, mi->to_bag_slot, mi->to_aug_slot,
// mi->number_in_stack);
if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) {
if (mi->from_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
else {
int16 from_parent = m_inv.CalcSlotId(mi->from_slot);
if (!m_inv[from_parent]) { mi_hack = true; }
else if (!m_inv[from_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
else if (m_inv.CalcBagIdx(mi->from_slot) >= m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi->to_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->to_slot <= EmuConstants::CURSOR_BAG_END) {
if (mi->to_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
else {
int16 to_parent = m_inv.CalcSlotId(mi->to_slot);
if (!m_inv[to_parent]) { mi_hack = true; }
else if (!m_inv[to_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
else if (m_inv.CalcBagIdx(mi->to_slot) >= m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }
}
}
if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); }
if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
SwapItemResync(mi);
bool error = false;
InterrogateInventory(this, false, true, false, error, false);
if (error)
InterrogateInventory(this, true, false, true, error);
}
return;
//if (spellend_timer.Enabled() && casting_spell_id && !IsBardSong(casting_spell_id))
//{
// if (mi->from_slot != mi->to_slot && (mi->from_slot <= EmuConstants::GENERAL_END || mi->from_slot > 39) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
// {
// char *detect = nullptr;
// const ItemInst *itm_from = GetInv().GetItem(mi->from_slot);
// const ItemInst *itm_to = GetInv().GetItem(mi->to_slot);
// MakeAnyLenString(&detect, "Player issued a move item from %u(item id %u) to %u(item id %u) while casting %u.",
// mi->from_slot,
// itm_from ? itm_from->GetID() : 0,
// mi->to_slot,
// itm_to ? itm_to->GetID() : 0,
// casting_spell_id);
// database.SetMQDetectionFlag(AccountName(), GetName(), detect, zone->GetShortName());
// safe_delete_array(detect);
// Kick(); // Kick client to prevent client and server from getting out-of-sync inventory slots
// return;
// }
//}
//
//// Illegal bagslot usage checks. Currently, user only receives a message if this check is triggered.
//bool mi_hack = false;
//
//if (mi->from_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->from_slot <= EmuConstants::CURSOR_BAG_END) {
// if (mi->from_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
// else {
// int16 from_parent = m_inv.CalcSlotId(mi->from_slot);
// if (!m_inv[from_parent]) { mi_hack = true; }
// else if (!m_inv[from_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
// else if (m_inv.CalcBagIdx(mi->from_slot) >= m_inv[from_parent]->GetItem()->BagSlots) { mi_hack = true; }
// }
//}
//
//if (mi->to_slot >= EmuConstants::GENERAL_BAGS_BEGIN && mi->to_slot <= EmuConstants::CURSOR_BAG_END) {
// if (mi->to_slot >= EmuConstants::CURSOR_BAG_BEGIN) { mi_hack = true; }
// else {
// int16 to_parent = m_inv.CalcSlotId(mi->to_slot);
// if (!m_inv[to_parent]) { mi_hack = true; }
// else if (!m_inv[to_parent]->IsType(ItemClassContainer)) { mi_hack = true; }
// else if (m_inv.CalcBagIdx(mi->to_slot) >= m_inv[to_parent]->GetItem()->BagSlots) { mi_hack = true; }
// }
//}
//
//if (mi_hack) { Message(15, "Caution: Illegal use of inaccessible bag slots!"); }
//
//if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot)) {
// SwapItemResync(mi);
//
// bool error = false;
// InterrogateInventory(this, false, true, false, error, false);
// if (error)
// InterrogateInventory(this, true, false, true, error);
//}
//
//return;
}
void Client::Handle_OP_OpenContainer(const EQApplicationPacket *app)
+71 -71
View File
@@ -3119,77 +3119,77 @@ void command_listpetition(Client *c, const Seperator *sep)
void command_equipitem(Client *c, const Seperator *sep)
{
uint32 slot_id = atoi(sep->arg[1]);
if (sep->IsNumber(1) && ((slot_id >= EmuConstants::EQUIPMENT_BEGIN) && (slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource))) {
const ItemInst* from_inst = c->GetInv().GetItem(MainCursor);
const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
bool partialmove = false;
int16 movecount;
if (from_inst && from_inst->IsType(ItemClassCommon)) {
EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
MoveItem_Struct* mi = (MoveItem_Struct*)outapp->pBuffer;
mi->from_slot = MainCursor;
mi->to_slot = slot_id;
// mi->number_in_stack = from_inst->GetCharges(); // replaced with con check for stacking
// crude stackable check to only 'move' the difference count on client instead of entire stack when applicable
if (to_inst && to_inst->IsStackable() &&
(to_inst->GetItem()->ID == from_inst->GetItem()->ID) &&
(to_inst->GetCharges() < to_inst->GetItem()->StackSize) &&
(from_inst->GetCharges() > to_inst->GetItem()->StackSize - to_inst->GetCharges())) {
movecount = to_inst->GetItem()->StackSize - to_inst->GetCharges();
mi->number_in_stack = (uint32)movecount;
partialmove = true;
}
else
mi->number_in_stack = from_inst->GetCharges();
// Save move changes
// Added conditional check to packet send..would have sent change even on a swap failure..whoops!
if (partialmove) { // remove this con check if someone can figure out removing charges from cursor stack issue below
// mi->number_in_stack is always from_inst->GetCharges() when partialmove is false
c->Message(13, "Error: Partial stack added to existing stack exceeds allowable stacksize");
return;
}
else if(c->SwapItem(mi)) {
c->FastQueuePacket(&outapp);
// if the below code is still needed..just send an an item trade packet to each slot..it should overwrite the client instance
// below code has proper logic, but client does not like to have cursor charges changed
// (we could delete the cursor item and resend, but issues would arise if there are queued items)
//if (partialmove) {
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// DeleteItem_Struct* di = (DeleteItem_Struct*)outapp2->pBuffer;
// di->from_slot = SLOT_CURSOR;
// di->to_slot = 0xFFFFFFFF;
// di->number_in_stack = 0xFFFFFFFF;
// c->Message(0, "Deleting %i charges from stack", movecount); // debug line..delete
// for (int16 deletecount=0; deletecount < movecount; deletecount++)
// have to use 'movecount' because mi->number_in_stack is 'ENCODED' at this point (i.e., 99 charges returns 22...)
// c->QueuePacket(outapp2);
// safe_delete(outapp2);
//}
}
else {
c->Message(13, "Error: Unable to equip current item");
}
safe_delete(outapp);
// also send out a wear change packet?
}
else if (from_inst == nullptr)
c->Message(13, "Error: There is no item on your cursor");
else
c->Message(13, "Error: Item on your cursor cannot be equipped");
}
else
c->Message(0, "Usage: #equipitem slotid[0-21] - equips the item on your cursor to the position");
// uint32 slot_id = atoi(sep->arg[1]);
// if (sep->IsNumber(1) && ((slot_id >= EmuConstants::EQUIPMENT_BEGIN) && (slot_id <= EmuConstants::EQUIPMENT_END) || (slot_id == MainPowerSource))) {
// const ItemInst* from_inst = c->GetInv().GetItem(MainCursor);
// const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
// bool partialmove = false;
// int16 movecount;
//
// if (from_inst && from_inst->IsType(ItemClassCommon)) {
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
// MoveItem_Struct* mi = (MoveItem_Struct*)outapp->pBuffer;
// mi->from_slot = MainCursor;
// mi->to_slot = slot_id;
// // mi->number_in_stack = from_inst->GetCharges(); // replaced with con check for stacking
//
// // crude stackable check to only 'move' the difference count on client instead of entire stack when applicable
// if (to_inst && to_inst->IsStackable() &&
// (to_inst->GetItem()->ID == from_inst->GetItem()->ID) &&
// (to_inst->GetCharges() < to_inst->GetItem()->StackSize) &&
// (from_inst->GetCharges() > to_inst->GetItem()->StackSize - to_inst->GetCharges())) {
// movecount = to_inst->GetItem()->StackSize - to_inst->GetCharges();
// mi->number_in_stack = (uint32)movecount;
// partialmove = true;
// }
// else
// mi->number_in_stack = from_inst->GetCharges();
//
// // Save move changes
// // Added conditional check to packet send..would have sent change even on a swap failure..whoops!
//
// if (partialmove) { // remove this con check if someone can figure out removing charges from cursor stack issue below
// // mi->number_in_stack is always from_inst->GetCharges() when partialmove is false
// c->Message(13, "Error: Partial stack added to existing stack exceeds allowable stacksize");
// return;
// }
// else if(c->SwapItem(mi)) {
// c->FastQueuePacket(&outapp);
//
// // if the below code is still needed..just send an an item trade packet to each slot..it should overwrite the client instance
//
// // below code has proper logic, but client does not like to have cursor charges changed
// // (we could delete the cursor item and resend, but issues would arise if there are queued items)
// //if (partialmove) {
// // EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// // DeleteItem_Struct* di = (DeleteItem_Struct*)outapp2->pBuffer;
// // di->from_slot = SLOT_CURSOR;
// // di->to_slot = 0xFFFFFFFF;
// // di->number_in_stack = 0xFFFFFFFF;
//
// // c->Message(0, "Deleting %i charges from stack", movecount); // debug line..delete
//
// // for (int16 deletecount=0; deletecount < movecount; deletecount++)
// // have to use 'movecount' because mi->number_in_stack is 'ENCODED' at this point (i.e., 99 charges returns 22...)
// // c->QueuePacket(outapp2);
//
// // safe_delete(outapp2);
// //}
// }
// else {
// c->Message(13, "Error: Unable to equip current item");
// }
// safe_delete(outapp);
//
// // also send out a wear change packet?
// }
// else if (from_inst == nullptr)
// c->Message(13, "Error: There is no item on your cursor");
// else
// c->Message(13, "Error: Item on your cursor cannot be equipped");
// }
// else
// c->Message(0, "Usage: #equipitem slotid[0-21] - equips the item on your cursor to the position");
}
void command_zonelock(Client *c, const Seperator *sep)
+119 -119
View File
@@ -716,122 +716,122 @@ void Client::SendCursorBuffer()
// Remove item from inventory
void Client::DeleteItemInInventory(int16 slot_id, int8 quantity, bool client_update, bool update_db) {
#if (EQDEBUG >= 5)
Log.Out(Logs::General, Logs::None, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
#endif
// Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
// - cursor queue slots were slipping through and crashing client
if(!m_inv[slot_id]) {
// Make sure the client deletes anything in this slot to match the server.
if(client_update && IsValidSlot(slot_id)) {
EQApplicationPacket* outapp;
outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp);
safe_delete(outapp);
}
return;
}
// start QS code
if(RuleB(QueryServ, PlayerLogDeletes)) {
uint16 delete_count = 0;
if(m_inv[slot_id]) { delete_count += m_inv.GetItem(slot_id)->GetTotalItemCount(); }
ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogDeletes, sizeof(QSPlayerLogDelete_Struct) + (sizeof(QSDeleteItems_Struct) * delete_count));
QSPlayerLogDelete_Struct* qsaudit = (QSPlayerLogDelete_Struct*)qspack->pBuffer;
uint16 parent_offset = 0;
qsaudit->char_id = character_id;
qsaudit->stack_size = quantity;
qsaudit->char_count = delete_count;
qsaudit->items[parent_offset].char_slot = slot_id;
qsaudit->items[parent_offset].item_id = m_inv[slot_id]->GetID();
qsaudit->items[parent_offset].charges = m_inv[slot_id]->GetCharges();
qsaudit->items[parent_offset].aug_1 = m_inv[slot_id]->GetAugmentItemID(1);
qsaudit->items[parent_offset].aug_2 = m_inv[slot_id]->GetAugmentItemID(2);
qsaudit->items[parent_offset].aug_3 = m_inv[slot_id]->GetAugmentItemID(3);
qsaudit->items[parent_offset].aug_4 = m_inv[slot_id]->GetAugmentItemID(4);
qsaudit->items[parent_offset].aug_5 = m_inv[slot_id]->GetAugmentItemID(5);
if(m_inv[slot_id]->IsType(ItemClassContainer)) {
for(uint8 bag_idx = SUB_BEGIN; bag_idx < m_inv[slot_id]->GetItem()->BagSlots; bag_idx++) {
ItemInst* bagitem = m_inv[slot_id]->GetItem(bag_idx);
if(bagitem) {
int16 bagslot_id = InventoryOld::CalcSlotId(slot_id, bag_idx);
qsaudit->items[++parent_offset].char_slot = bagslot_id;
qsaudit->items[parent_offset].item_id = bagitem->GetID();
qsaudit->items[parent_offset].charges = bagitem->GetCharges();
qsaudit->items[parent_offset].aug_1 = bagitem->GetAugmentItemID(1);
qsaudit->items[parent_offset].aug_2 = bagitem->GetAugmentItemID(2);
qsaudit->items[parent_offset].aug_3 = bagitem->GetAugmentItemID(3);
qsaudit->items[parent_offset].aug_4 = bagitem->GetAugmentItemID(4);
qsaudit->items[parent_offset].aug_5 = bagitem->GetAugmentItemID(5);
}
}
}
qspack->Deflate();
if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
safe_delete(qspack);
}
// end QS code
bool isDeleted = m_inv.DeleteItem(slot_id, quantity);
const ItemInst* inst = nullptr;
if (slot_id == MainCursor) {
auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
if(update_db)
database.SaveCursor(character_id, s, e);
}
else {
// Save change to database
inst = m_inv[slot_id];
if(update_db)
database.SaveInventory(character_id, inst, slot_id);
}
if(client_update && IsValidSlot(slot_id)) {
EQApplicationPacket* outapp = nullptr;
if(inst) {
if (!inst->IsStackable() && !isDeleted) {
// Non stackable item with charges = Item with clicky spell effect ? Delete a charge.
outapp = new EQApplicationPacket(OP_DeleteCharge, sizeof(MoveItem_Struct));
}
else {
// Stackable, arrows, etc ? Delete one from the stack
outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct));
}
DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;
for(int loop=0;loop<quantity;loop++)
QueuePacket(outapp);
safe_delete(outapp);
}
else {
outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
MoveItem_Struct* delitem = (MoveItem_Struct*)outapp->pBuffer;
delitem->from_slot = slot_id;
delitem->to_slot = 0xFFFFFFFF;
delitem->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp);
safe_delete(outapp);
}
}
// #if (EQDEBUG >= 5)
// Log.Out(Logs::General, Logs::None, "DeleteItemInInventory(%i, %i, %s)", slot_id, quantity, (client_update) ? "true":"false");
// #endif
//
// // Added 'IsSlotValid(slot_id)' check to both segments of client packet processing.
// // - cursor queue slots were slipping through and crashing client
// if(!m_inv[slot_id]) {
// // Make sure the client deletes anything in this slot to match the server.
// if(client_update && IsValidSlot(slot_id)) {
// EQApplicationPacket* outapp;
// outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
// DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
// delitem->from_slot = slot_id;
// delitem->to_slot = 0xFFFFFFFF;
// delitem->number_in_stack = 0xFFFFFFFF;
// QueuePacket(outapp);
// safe_delete(outapp);
// }
// return;
// }
//
// // start QS code
// if(RuleB(QueryServ, PlayerLogDeletes)) {
// uint16 delete_count = 0;
//
// if(m_inv[slot_id]) { delete_count += m_inv.GetItem(slot_id)->GetTotalItemCount(); }
//
// ServerPacket* qspack = new ServerPacket(ServerOP_QSPlayerLogDeletes, sizeof(QSPlayerLogDelete_Struct) + (sizeof(QSDeleteItems_Struct) * delete_count));
// QSPlayerLogDelete_Struct* qsaudit = (QSPlayerLogDelete_Struct*)qspack->pBuffer;
// uint16 parent_offset = 0;
//
// qsaudit->char_id = character_id;
// qsaudit->stack_size = quantity;
// qsaudit->char_count = delete_count;
//
// qsaudit->items[parent_offset].char_slot = slot_id;
// qsaudit->items[parent_offset].item_id = m_inv[slot_id]->GetID();
// qsaudit->items[parent_offset].charges = m_inv[slot_id]->GetCharges();
// qsaudit->items[parent_offset].aug_1 = m_inv[slot_id]->GetAugmentItemID(1);
// qsaudit->items[parent_offset].aug_2 = m_inv[slot_id]->GetAugmentItemID(2);
// qsaudit->items[parent_offset].aug_3 = m_inv[slot_id]->GetAugmentItemID(3);
// qsaudit->items[parent_offset].aug_4 = m_inv[slot_id]->GetAugmentItemID(4);
// qsaudit->items[parent_offset].aug_5 = m_inv[slot_id]->GetAugmentItemID(5);
//
// if(m_inv[slot_id]->IsType(ItemClassContainer)) {
// for(uint8 bag_idx = SUB_BEGIN; bag_idx < m_inv[slot_id]->GetItem()->BagSlots; bag_idx++) {
// ItemInst* bagitem = m_inv[slot_id]->GetItem(bag_idx);
//
// if(bagitem) {
// int16 bagslot_id = InventoryOld::CalcSlotId(slot_id, bag_idx);
//
// qsaudit->items[++parent_offset].char_slot = bagslot_id;
// qsaudit->items[parent_offset].item_id = bagitem->GetID();
// qsaudit->items[parent_offset].charges = bagitem->GetCharges();
// qsaudit->items[parent_offset].aug_1 = bagitem->GetAugmentItemID(1);
// qsaudit->items[parent_offset].aug_2 = bagitem->GetAugmentItemID(2);
// qsaudit->items[parent_offset].aug_3 = bagitem->GetAugmentItemID(3);
// qsaudit->items[parent_offset].aug_4 = bagitem->GetAugmentItemID(4);
// qsaudit->items[parent_offset].aug_5 = bagitem->GetAugmentItemID(5);
// }
// }
// }
//
// qspack->Deflate();
// if(worldserver.Connected()) { worldserver.SendPacket(qspack); }
// safe_delete(qspack);
// }
// // end QS code
//
// bool isDeleted = m_inv.DeleteItem(slot_id, quantity);
//
// const ItemInst* inst = nullptr;
// if (slot_id == MainCursor) {
// auto s = m_inv.cursor_cbegin(), e = m_inv.cursor_cend();
// if(update_db)
// database.SaveCursor(character_id, s, e);
// }
// else {
// // Save change to database
// inst = m_inv[slot_id];
// if(update_db)
// database.SaveInventory(character_id, inst, slot_id);
// }
//
// if(client_update && IsValidSlot(slot_id)) {
// EQApplicationPacket* outapp = nullptr;
// if(inst) {
// if (!inst->IsStackable() && !isDeleted) {
// // Non stackable item with charges = Item with clicky spell effect ? Delete a charge.
// outapp = new EQApplicationPacket(OP_DeleteCharge, sizeof(MoveItem_Struct));
// }
// else {
// // Stackable, arrows, etc ? Delete one from the stack
// outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(MoveItem_Struct));
// }
//
// DeleteItem_Struct* delitem = (DeleteItem_Struct*)outapp->pBuffer;
// delitem->from_slot = slot_id;
// delitem->to_slot = 0xFFFFFFFF;
// delitem->number_in_stack = 0xFFFFFFFF;
//
// for(int loop=0;loop<quantity;loop++)
// QueuePacket(outapp);
// safe_delete(outapp);
// }
// else {
// outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
// MoveItem_Struct* delitem = (MoveItem_Struct*)outapp->pBuffer;
// delitem->from_slot = slot_id;
// delitem->to_slot = 0xFFFFFFFF;
// delitem->number_in_stack = 0xFFFFFFFF;
//
// QueuePacket(outapp);
// safe_delete(outapp);
// }
// }
}
bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
@@ -1315,7 +1315,7 @@ bool Client::IsBankSlot(uint32 slot)
// Moves items around both internally and in the database
// In the future, this can be optimized by pushing all changes through one database REPLACE call
bool Client::SwapItem(MoveItem_Struct* move_in) {
bool Client::SwapItem(MoveItemOld_Struct* move_in) {
uint32 src_slot_check = move_in->from_slot;
uint32 dst_slot_check = move_in->to_slot;
@@ -1788,7 +1788,7 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
return true;
}
void Client::SwapItemResync(MoveItem_Struct* move_slots) {
void Client::SwapItemResync(MoveItemOld_Struct* move_slots) {
// wow..this thing created a helluva memory leak...
// with any luck..this won't be needed in the future
@@ -1883,7 +1883,7 @@ void Client::SwapItemResync(MoveItem_Struct* move_slots) {
}
}
void Client::QSSwapItemAuditor(MoveItem_Struct* move_in, bool postaction_call) {
void Client::QSSwapItemAuditor(MoveItemOld_Struct* move_in, bool postaction_call) {
int16 from_slot_id = static_cast<int16>(move_in->from_slot);
int16 to_slot_id = static_cast<int16>(move_in->to_slot);
int16 move_amount = static_cast<int16>(move_in->number_in_stack);
+403 -403
View File
@@ -1333,68 +1333,68 @@ uint16 Client::FindTraderItem(int32 SerialNumber, uint16 Quantity){
}
void Client::NukeTraderItem(uint16 Slot,int16 Charges,uint16 Quantity,Client* Customer,uint16 TraderSlot, int32 SerialNumber, int32 itemid) {
if(!Customer)
return;
Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
if(Quantity < Charges)
{
Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
m_inv.DeleteItem(Slot, Quantity);
}
else
{
EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
tdis->Unknown000 = 0;
tdis->TraderID = Customer->GetID();
if (Customer->GetClientVersion() >= ClientVersion::RoF)
{
// RoF+ use Item IDs for now
tdis->ItemID = itemid;
}
else
{
tdis->ItemID = SerialNumber;
}
tdis->Unknown012 = 0;
Customer->QueuePacket(outapp);
safe_delete(outapp);
m_inv.DeleteItem(Slot);
}
// This updates the trader. Removes it from his trading bags.
//
const ItemInst* Inst = m_inv[Slot];
database.SaveInventory(CharacterID(), Inst, Slot);
EQApplicationPacket* outapp2;
if(Quantity < Charges)
outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
else
outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = Slot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
if(Quantity >= Charges)
Quantity = 1;
for(int i = 0; i < Quantity; i++) {
this->QueuePacket(outapp2);
}
safe_delete(outapp2);
//
// if(!Customer)
// return;
//
// Log.Out(Logs::Detail, Logs::Trading, "NukeTraderItem(Slot %i, Charges %i, Quantity %i", Slot, Charges, Quantity);
//
// if(Quantity < Charges)
// {
// Customer->SendSingleTraderItem(this->CharacterID(), SerialNumber);
// m_inv.DeleteItem(Slot, Quantity);
// }
// else
// {
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_TraderDelItem,sizeof(TraderDelItem_Struct));
// TraderDelItem_Struct* tdis = (TraderDelItem_Struct*)outapp->pBuffer;
//
// tdis->Unknown000 = 0;
// tdis->TraderID = Customer->GetID();
// if (Customer->GetClientVersion() >= ClientVersion::RoF)
// {
// // RoF+ use Item IDs for now
// tdis->ItemID = itemid;
// }
// else
// {
// tdis->ItemID = SerialNumber;
// }
// tdis->Unknown012 = 0;
//
//
// Customer->QueuePacket(outapp);
// safe_delete(outapp);
//
// m_inv.DeleteItem(Slot);
// }
// // This updates the trader. Removes it from his trading bags.
// //
// const ItemInst* Inst = m_inv[Slot];
//
// database.SaveInventory(CharacterID(), Inst, Slot);
//
// EQApplicationPacket* outapp2;
//
// if(Quantity < Charges)
// outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
// else
// outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = Slot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// if(Quantity >= Charges)
// Quantity = 1;
//
// for(int i = 0; i < Quantity; i++) {
//
// this->QueuePacket(outapp2);
// }
// safe_delete(outapp2);
//
}
void Client::TraderUpdate(uint16 SlotID,uint32 TraderID){
// This method is no longer used.
@@ -2507,347 +2507,347 @@ void Client::ShowBuyLines(const EQApplicationPacket *app) {
}
void Client::SellToBuyer(const EQApplicationPacket *app) {
char* Buf = (char *)app->pBuffer;
char ItemName[64];
/*uint32 Action =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
uint32 Quantity = VARSTRUCT_DECODE_TYPE(uint32, Buf);
uint32 BuyerID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
uint32 BuySlot = VARSTRUCT_DECODE_TYPE(uint32, Buf);
uint32 UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
uint32 ItemID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
/* ItemName */ VARSTRUCT_DECODE_STRING(ItemName, Buf);
/*uint32 Unknown2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
uint32 QtyBuyerWants = VARSTRUCT_DECODE_TYPE(uint32, Buf);
UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
uint32 Price = VARSTRUCT_DECODE_TYPE(uint32, Buf);
/*uint32 BuyerID2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
/*uint32 Unknown3 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
const ItemData *item = database.GetItem(ItemID);
if(!item || !Quantity || !Price || !QtyBuyerWants) return;
if (m_inv.HasItem(ItemID, Quantity, invWhereWorn | invWherePersonal | invWhereCursor) == INVALID_INDEX) {
Message(13, "You do not have %i %s on you.", Quantity, item->Name);
return;
}
Client *Buyer = entity_list.GetClientByID(BuyerID);
if(!Buyer || !Buyer->IsBuyer()) {
Message(13, "The Buyer has gone away.");
return;
}
// For Stackable items, HasSpaceForItem will try check if there is space to stack with existing stacks in
// the buyer inventory.
if(!(Buyer->GetInv().HasSpaceForItem(item, Quantity))) {
Message(13, "The Buyer does not have space for %i %s", Quantity, item->Name);
return;
}
if((static_cast<uint64>(Quantity) * static_cast<uint64>(Price)) > MAX_TRANSACTION_VALUE) {
Message(13, "That would exceed the single transaction limit of %u platinum.", MAX_TRANSACTION_VALUE / 1000);
return;
}
if(!Buyer->HasMoney(Quantity * Price)) {
Message(13, "The Buyer does not have sufficient money to purchase that quantity of %s.", item->Name);
Buyer->Message(13, "%s tried to sell you %i %s, but you have insufficient funds.", GetName(), Quantity, item->Name);
return;
}
if(Buyer->CheckLoreConflict(item)) {
Message(13, "That item is LORE and the Buyer already has one.");
Buyer->Message(13, "%s tried to sell you %s but this item is LORE and you already have one.",
GetName(), item->Name);
return;
}
if(item->NoDrop == 0) {
Message(13, "That item is NODROP.");
return;
}
if(!item->Stackable) {
for(uint32 i = 0; i < Quantity; i++) {
int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
// This shouldn't happen, as we already checked there was space in the Buyer's inventory
if (SellerSlot == INVALID_INDEX) {
if(i > 0) {
// Set the Quantity to the actual number we successfully transferred.
Quantity = i;
break;
}
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
return;
}
ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
if(!ItemToTransfer || !Buyer->MoveItemToInventory(ItemToTransfer, true)) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
if(ItemToTransfer)
safe_delete(ItemToTransfer);
return;
}
database.SaveInventory(CharacterID(), 0, SellerSlot);
safe_delete(ItemToTransfer);
// Remove the item from inventory, clientside
//
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = SellerSlot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp2);
safe_delete(outapp2);
}
}
else {
// Stackable
//
uint32 QuantityMoved = 0;
while(QuantityMoved < Quantity) {
// Find the slot on the seller that has a stack of at least 1 of the item
int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
if (SellerSlot == INVALID_INDEX) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
return;
}
ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
if(!ItemToTransfer) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
return;
}
// If the stack we found has less than the quantity we are selling ...
if(ItemToTransfer->GetCharges() <= (Quantity - QuantityMoved)) {
// Transfer the entire stack
QuantityMoved += ItemToTransfer->GetCharges();
if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
safe_delete(ItemToTransfer);
return;
}
// Delete the entire stack from the seller's inventory
database.SaveInventory(CharacterID(), 0, SellerSlot);
safe_delete(ItemToTransfer);
// and tell the client to do the same.
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = SellerSlot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
QueuePacket(outapp2);
safe_delete(outapp2);
}
else {
//Move the amount we need, and put the rest of the stack back in the seller's inventory
//
int QuantityToRemoveFromStack = Quantity - QuantityMoved;
ItemToTransfer->SetCharges(ItemToTransfer->GetCharges() - QuantityToRemoveFromStack);
m_inv.PutItem(SellerSlot, *ItemToTransfer);
database.SaveInventory(CharacterID(), ItemToTransfer, SellerSlot);
ItemToTransfer->SetCharges(QuantityToRemoveFromStack);
if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
Message(13, "Internal error while processing transaction.");
safe_delete(ItemToTransfer);
return;
}
safe_delete(ItemToTransfer);
EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
mis->from_slot = SellerSlot;
mis->to_slot = 0xFFFFFFFF;
mis->number_in_stack = 0xFFFFFFFF;
for(int i = 0; i < QuantityToRemoveFromStack; i++)
QueuePacket(outapp2);
safe_delete(outapp2);
QuantityMoved = Quantity;
}
}
}
Buyer->TakeMoneyFromPP(Quantity * Price);
AddMoneyToPP(Quantity * Price, false);
if(RuleB(Bazaar, AuditTrail))
BazaarAuditTrail(GetName(), Buyer->GetName(), ItemName, Quantity, Quantity * Price, 1);
// We now send a packet to the Seller, which causes it to display 'You have sold <Qty> <Item> to <Player> for <money>'
//
// The PacketLength of 1016 is from the only instance of this packet I have seen, which is from Live, November 2008
// The Titanium/6.2 struct is slightly different in that it appears to use fixed length strings instead of variable
// length as used on Live. The extra space in the packet is also likely to be used for Item compensation, if we ever
// implement that.
//
uint32 PacketLength = 1016;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, PacketLength);
Buf = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_SellerTransactionComplete);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
if(GetClientVersion() >= ClientVersion::SoD)
{
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
}
sprintf(Buf, "%s", Buyer->GetName()); Buf += 64;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
sprintf(Buf, "%s", ItemName); Buf += 64;
QueuePacket(outapp);
// This next packet goes to the Buyer and produces the 'You've bought <Qty> <Item> from <Seller> for <money>'
//
Buf = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerTransactionComplete);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
if(Buyer->GetClientVersion() >= ClientVersion::SoD)
{
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
}
sprintf(Buf, "%s", GetName()); Buf += 64;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
sprintf(Buf, "%s", ItemName); Buf += 64;
Buyer->QueuePacket(outapp);
safe_delete(outapp);
// Next we update the buyer table in the database to reflect the reduced quantity the Buyer wants to buy.
//
database.UpdateBuyLine(Buyer->CharacterID(), BuySlot, QtyBuyerWants - Quantity);
// Next we update the Seller's Barter Window to reflect the reduced quantity the Buyer is now looking to buy.
//
EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_Barter, 936);
Buf = (char *)outapp3->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, Buf,ItemID);
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
// If the amount we have just sold completely satisfies the quantity the Buyer was looking for,
// setting the next byte to 0 will remove the item from the Barter Window.
//
if(QtyBuyerWants - Quantity > 0) {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
}
else {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
}
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
QueuePacket(outapp3);
safe_delete(outapp3);
// The next packet updates the /buyer window with the reduced quantity, and toggles the buy line off if the
// quantity they wanted to buy has been met.
//
EQApplicationPacket* outapp4 = new EQApplicationPacket(OP_Barter, 936);
Buf = (char*)outapp4->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerItemUpdate);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
VARSTRUCT_ENCODE_STRING(Buf, ItemName);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
if((QtyBuyerWants - Quantity) > 0) {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
}
else {
VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
}
VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x08f4); // Unknown
VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
Buyer->QueuePacket(outapp4);
safe_delete(outapp4);
return;
//
// char* Buf = (char *)app->pBuffer;
//
// char ItemName[64];
//
// /*uint32 Action =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
// uint32 Quantity = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// uint32 BuyerID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// uint32 BuySlot = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// uint32 UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
// uint32 ItemID = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// /* ItemName */ VARSTRUCT_DECODE_STRING(ItemName, Buf);
// /*uint32 Unknown2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
// uint32 QtyBuyerWants = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// UnknownByte = VARSTRUCT_DECODE_TYPE(uint8, Buf);
// uint32 Price = VARSTRUCT_DECODE_TYPE(uint32, Buf);
// /*uint32 BuyerID2 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
// /*uint32 Unknown3 =*/ VARSTRUCT_SKIP_TYPE(uint32, Buf); //unused
//
// const ItemData *item = database.GetItem(ItemID);
//
// if(!item || !Quantity || !Price || !QtyBuyerWants) return;
//
// if (m_inv.HasItem(ItemID, Quantity, invWhereWorn | invWherePersonal | invWhereCursor) == INVALID_INDEX) {
// Message(13, "You do not have %i %s on you.", Quantity, item->Name);
// return;
// }
//
//
// Client *Buyer = entity_list.GetClientByID(BuyerID);
//
// if(!Buyer || !Buyer->IsBuyer()) {
// Message(13, "The Buyer has gone away.");
// return;
// }
//
// // For Stackable items, HasSpaceForItem will try check if there is space to stack with existing stacks in
// // the buyer inventory.
// if(!(Buyer->GetInv().HasSpaceForItem(item, Quantity))) {
// Message(13, "The Buyer does not have space for %i %s", Quantity, item->Name);
// return;
// }
//
// if((static_cast<uint64>(Quantity) * static_cast<uint64>(Price)) > MAX_TRANSACTION_VALUE) {
// Message(13, "That would exceed the single transaction limit of %u platinum.", MAX_TRANSACTION_VALUE / 1000);
// return;
// }
//
// if(!Buyer->HasMoney(Quantity * Price)) {
// Message(13, "The Buyer does not have sufficient money to purchase that quantity of %s.", item->Name);
// Buyer->Message(13, "%s tried to sell you %i %s, but you have insufficient funds.", GetName(), Quantity, item->Name);
// return;
// }
//
// if(Buyer->CheckLoreConflict(item)) {
// Message(13, "That item is LORE and the Buyer already has one.");
// Buyer->Message(13, "%s tried to sell you %s but this item is LORE and you already have one.",
// GetName(), item->Name);
// return;
// }
//
// if(item->NoDrop == 0) {
// Message(13, "That item is NODROP.");
// return;
// }
//
// if(!item->Stackable) {
//
// for(uint32 i = 0; i < Quantity; i++) {
//
// int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
//
// // This shouldn't happen, as we already checked there was space in the Buyer's inventory
// if (SellerSlot == INVALID_INDEX) {
//
// if(i > 0) {
// // Set the Quantity to the actual number we successfully transferred.
// Quantity = i;
// break;
// }
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// return;
// }
//
// ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
//
// if(!ItemToTransfer || !Buyer->MoveItemToInventory(ItemToTransfer, true)) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
//
// if(ItemToTransfer)
// safe_delete(ItemToTransfer);
//
// return;
// }
//
// database.SaveInventory(CharacterID(), 0, SellerSlot);
//
// safe_delete(ItemToTransfer);
//
// // Remove the item from inventory, clientside
// //
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = SellerSlot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// QueuePacket(outapp2);
// safe_delete(outapp2);
//
// }
// }
// else {
// // Stackable
// //
// uint32 QuantityMoved = 0;
//
// while(QuantityMoved < Quantity) {
//
// // Find the slot on the seller that has a stack of at least 1 of the item
// int16 SellerSlot = m_inv.HasItem(ItemID, 1, invWhereWorn|invWherePersonal|invWhereCursor);
//
// if (SellerSlot == INVALID_INDEX) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// return;
// }
//
// ItemInst* ItemToTransfer = m_inv.PopItem(SellerSlot);
//
// if(!ItemToTransfer) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// return;
// }
//
// // If the stack we found has less than the quantity we are selling ...
// if(ItemToTransfer->GetCharges() <= (Quantity - QuantityMoved)) {
// // Transfer the entire stack
//
// QuantityMoved += ItemToTransfer->GetCharges();
//
// if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// safe_delete(ItemToTransfer);
// return;
// }
// // Delete the entire stack from the seller's inventory
// database.SaveInventory(CharacterID(), 0, SellerSlot);
//
// safe_delete(ItemToTransfer);
//
// // and tell the client to do the same.
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_MoveItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = SellerSlot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// QueuePacket(outapp2);
// safe_delete(outapp2);
// }
// else {
// //Move the amount we need, and put the rest of the stack back in the seller's inventory
// //
// int QuantityToRemoveFromStack = Quantity - QuantityMoved;
//
// ItemToTransfer->SetCharges(ItemToTransfer->GetCharges() - QuantityToRemoveFromStack);
//
// m_inv.PutItem(SellerSlot, *ItemToTransfer);
//
// database.SaveInventory(CharacterID(), ItemToTransfer, SellerSlot);
//
// ItemToTransfer->SetCharges(QuantityToRemoveFromStack);
//
// if(!Buyer->MoveItemToInventory(ItemToTransfer, true)) {
// Log.Out(Logs::General, Logs::Error, "Unexpected error while moving item from seller to buyer.");
// Message(13, "Internal error while processing transaction.");
// safe_delete(ItemToTransfer);
// return;
// }
//
// safe_delete(ItemToTransfer);
//
// EQApplicationPacket* outapp2 = new EQApplicationPacket(OP_DeleteItem,sizeof(MoveItem_Struct));
//
// MoveItem_Struct* mis = (MoveItem_Struct*)outapp2->pBuffer;
// mis->from_slot = SellerSlot;
// mis->to_slot = 0xFFFFFFFF;
// mis->number_in_stack = 0xFFFFFFFF;
//
// for(int i = 0; i < QuantityToRemoveFromStack; i++)
// QueuePacket(outapp2);
//
// safe_delete(outapp2);
//
// QuantityMoved = Quantity;
// }
// }
//
// }
//
// Buyer->TakeMoneyFromPP(Quantity * Price);
//
// AddMoneyToPP(Quantity * Price, false);
//
// if(RuleB(Bazaar, AuditTrail))
// BazaarAuditTrail(GetName(), Buyer->GetName(), ItemName, Quantity, Quantity * Price, 1);
//
// // We now send a packet to the Seller, which causes it to display 'You have sold <Qty> <Item> to <Player> for <money>'
// //
// // The PacketLength of 1016 is from the only instance of this packet I have seen, which is from Live, November 2008
// // The Titanium/6.2 struct is slightly different in that it appears to use fixed length strings instead of variable
// // length as used on Live. The extra space in the packet is also likely to be used for Item compensation, if we ever
// // implement that.
// //
// uint32 PacketLength = 1016;
//
// EQApplicationPacket* outapp = new EQApplicationPacket(OP_Barter, PacketLength);
//
// Buf = (char *)outapp->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_SellerTransactionComplete);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
//
// if(GetClientVersion() >= ClientVersion::SoD)
// {
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
// }
//
// sprintf(Buf, "%s", Buyer->GetName()); Buf += 64;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
//
// sprintf(Buf, "%s", ItemName); Buf += 64;
//
// QueuePacket(outapp);
//
// // This next packet goes to the Buyer and produces the 'You've bought <Qty> <Item> from <Seller> for <money>'
// //
//
// Buf = (char *)outapp->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerTransactionComplete);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Quantity * Price);
//
// if(Buyer->GetClientVersion() >= ClientVersion::SoD)
// {
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0); // Think this is the upper 32 bits of a 64 bit price
// }
//
// sprintf(Buf, "%s", GetName()); Buf += 64;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0x01);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x00);
//
// sprintf(Buf, "%s", ItemName); Buf += 64;
//
// Buyer->QueuePacket(outapp);
//
// safe_delete(outapp);
//
// // Next we update the buyer table in the database to reflect the reduced quantity the Buyer wants to buy.
// //
// database.UpdateBuyLine(Buyer->CharacterID(), BuySlot, QtyBuyerWants - Quantity);
//
// // Next we update the Seller's Barter Window to reflect the reduced quantity the Buyer is now looking to buy.
// //
// EQApplicationPacket* outapp3 = new EQApplicationPacket(OP_Barter, 936);
//
// Buf = (char *)outapp3->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerInspectWindow);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // Unknown
// VARSTRUCT_ENCODE_TYPE(uint32, Buf,ItemID);
// VARSTRUCT_ENCODE_STRING(Buf, ItemName);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
//
// // If the amount we have just sold completely satisfies the quantity the Buyer was looking for,
// // setting the next byte to 0 will remove the item from the Barter Window.
// //
// if(QtyBuyerWants - Quantity > 0) {
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
// }
// else {
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
// }
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Buyer->GetID());
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
//
// VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
//
// QueuePacket(outapp3);
// safe_delete(outapp3);
//
// // The next packet updates the /buyer window with the reduced quantity, and toggles the buy line off if the
// // quantity they wanted to buy has been met.
// //
// EQApplicationPacket* outapp4 = new EQApplicationPacket(OP_Barter, 936);
//
// Buf = (char*)outapp4->pBuffer;
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Barter_BuyerItemUpdate);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, BuySlot);
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, ItemID);
// VARSTRUCT_ENCODE_STRING(Buf, ItemName);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, item->Icon);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, QtyBuyerWants - Quantity);
//
// if((QtyBuyerWants - Quantity) > 0) {
//
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 1); // 0 = Toggle Off, 1 = Toggle On
// }
// else {
// VARSTRUCT_ENCODE_TYPE(uint8, Buf, 0); // 0 = Toggle Off, 1 = Toggle On
// }
//
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, Price);
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0x08f4); // Unknown
// VARSTRUCT_ENCODE_TYPE(uint32, Buf, 0);
// VARSTRUCT_ENCODE_STRING(Buf, Buyer->GetName());
//
// Buyer->QueuePacket(outapp4);
// safe_delete(outapp4);
//
// return;
}
void Client::SendBuyerPacket(Client* Buyer) {