diff --git a/common/inventory.cpp b/common/inventory.cpp index e90322b93..3c558910c 100644 --- a/common/inventory.cpp +++ b/common/inventory.cpp @@ -22,6 +22,7 @@ #include "data_verification.h" #include "string_util.h" #include +#include bool EQEmu::InventorySlot::IsValid() const { if(type_ == InvTypePersonal && EQEmu::ValueWithin(slot_, PersonalSlotCharm, PersonalSlotCursor)) { @@ -225,7 +226,28 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, return true; } - if(!src.IsValid() || !dest.IsValid()) { + if(!src.IsValid()) { + return false; + } + + if(src.Type() == InvTypeCursorBuffer || dest.Type() == InvTypeCursorBuffer) { + return true; + } + + if(dest.IsDelete()) { + impl_->data_model_->Begin(); + bool v = _destroy(src); + if(v) { + impl_->data_model_->Commit(); + } + else { + impl_->data_model_->Rollback(); + } + + return v; + } + + if(!dest.IsValid()) { return false; } @@ -252,17 +274,6 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, } impl_->data_model_->Begin(); - if(dest.IsDelete()) { - bool v = _destroy(src); - if(v) { - impl_->data_model_->Commit(); - } else { - impl_->data_model_->Rollback(); - } - - return v; - } - if(i_src->IsStackable()) { //move # charges from src to dest @@ -356,6 +367,109 @@ bool EQEmu::Inventory::Swap(const InventorySlot &src, const InventorySlot &dest, return true; } +bool EQEmu::Inventory::Summon(const InventorySlot &slot, std::shared_ptr inst) { + if(!inst) + return false; + + if(CheckLoreConflict(inst->GetBaseItem())) { + return false; + } + + auto cur = Get(slot); + if(cur) { + if(slot.IsCursor()) { + PushToCursorBuffer(inst); + } + + return false; + } + + impl_->data_model_->Begin(); + bool v = Put(slot, inst); + if(v) { + impl_->data_model_->Insert(slot, inst); + impl_->data_model_->Commit(); + } else { + impl_->data_model_->Rollback(); + } + + return v; +} + +bool EQEmu::Inventory::PushToCursorBuffer(std::shared_ptr inst) { + if(impl_->containers_.count(InvTypeCursorBuffer) == 0) { + impl_->containers_.insert(std::pair(InvTypeCursorBuffer, ItemContainer())); + } + + int32 top = 0; + auto &container = impl_->containers_[InvTypeCursorBuffer]; + auto iter = container.Begin(); + while(iter != container.End()) { + top = iter->first; + ++iter; + } + + InventorySlot slot(InvTypeCursorBuffer, top + 1); + impl_->data_model_->Begin(); + bool v = Put(slot, inst); + if(v) { + impl_->data_model_->Insert(slot, inst); + impl_->data_model_->Commit(); + } + else { + impl_->data_model_->Rollback(); + } + + return v; +} + +bool EQEmu::Inventory::PopFromCursorBuffer() { + InventorySlot cursor(InvTypePersonal, PersonalSlotCursor); + auto inst = Get(cursor); + if(inst) { + return false; + } + + if(impl_->containers_.count(InvTypeCursorBuffer) == 0) { + return false; + } + + int32 top = 0; + auto &container = impl_->containers_[InvTypeCursorBuffer]; + auto iter = container.Begin(); + while(iter != container.End()) { + top = iter->first; + ++iter; + } + + InventorySlot slot(InvTypeCursorBuffer, top); + inst = Get(slot); + + if(inst) { + impl_->data_model_->Begin(); + + bool v = _destroy(slot); + impl_->data_model_->Delete(slot); + + if(!v) { + impl_->data_model_->Rollback(); + return false; + } + + v = Put(cursor, inst); + impl_->data_model_->Insert(cursor, inst); + if(!v) { + impl_->data_model_->Rollback(); + return false; + } + + impl_->data_model_->Commit(); + return true; + } + + return false; +} + int EQEmu::Inventory::CalcMaterialFromSlot(const InventorySlot &slot) { if(slot.Type() != 0) return _MaterialInvalid; @@ -441,17 +555,59 @@ bool EQEmu::Inventory::CanEquip(std::shared_ptr inst, const return false; } + //todo: check deity if(!item->IsEquipable(impl_->race_, impl_->class_)) { return false; } + //Checking augments + auto iter = inst->GetContainer()->Begin(); + auto end = inst->GetContainer()->End(); + while(iter != end) { + if(!CanEquip(iter->second, InventorySlot(slot.Type(), slot.Slot(), slot.BagIndex(), iter->first))) { + return false; + } + ++iter; + } + return true; } +bool EQEmu::Inventory::CheckLoreConflict(const ItemData *item) { + if(!item) + return false; + + if(!item->LoreFlag) + return false; + + if(item->LoreGroup == 0) + return false; + + if(item->LoreGroup == 0xFFFFFFFF) { + //look everywhere except shared bank + for(auto &container : impl_->containers_) { + if(container.first != InvTypeSharedBank && container.second.HasItem(item->ID)) { + return true; + } + } + } + else { + //look everywhere except shared bank + for(auto &container : impl_->containers_) { + if(container.first != InvTypeSharedBank && container.second.HasItemByLoreGroup(item->LoreGroup)) { + return true; + } + } + } + + return false; +} + bool EQEmu::Inventory::Serialize(MemoryBuffer &buf) { buf.SetWritePosition(0); buf.SetReadPosition(0); buf.Resize(0); + buf.Write(105); bool value = false; for(auto &iter : impl_->containers_) { diff --git a/common/inventory.h b/common/inventory.h index d4ef2a8cf..48b1614bf 100644 --- a/common/inventory.h +++ b/common/inventory.h @@ -135,11 +135,15 @@ namespace EQEmu std::shared_ptr Get(const InventorySlot &slot); bool Put(const InventorySlot &slot, std::shared_ptr inst); bool Swap(const InventorySlot &src, const InventorySlot &dest, int charges); + bool Summon(const InventorySlot &slot, std::shared_ptr inst); + bool PushToCursorBuffer(std::shared_ptr inst); + bool PopFromCursorBuffer(); //utility static int CalcMaterialFromSlot(const InventorySlot &slot); static InventorySlot CalcSlotFromMaterial(int material); bool CanEquip(std::shared_ptr inst, const EQEmu::InventorySlot &slot); + bool CheckLoreConflict(const ItemData *item); bool Serialize(MemoryBuffer &buf); //testing diff --git a/common/inventory_db_data_model.cpp b/common/inventory_db_data_model.cpp index 080467341..63035f67c 100644 --- a/common/inventory_db_data_model.cpp +++ b/common/inventory_db_data_model.cpp @@ -153,9 +153,23 @@ void EQEmu::InventoryDatabaseDataModel::Insert(const InventorySlot &slot, std::s DataEvent evt; evt.evt = DB_Insert; evt.inst = iter->second; - evt.slot = InventorySlot(slot.Type(), slot.Slot(), -1, iter->first); + evt.slot = InventorySlot(slot.Type(), slot.Slot(), iter->first, -1); impl_->events_.push_back(evt); + //do augments here + if(evt.inst->GetBaseItem()->ItemClass == ItemClassCommon) { + auto inst_container = evt.inst->GetContainer(); + auto inst_iter = inst_container->Begin(); + while(inst_iter != inst_container->End()) { + DataEvent evt; + evt.evt = DB_Insert; + evt.inst = inst_iter->second; + evt.slot = InventorySlot(slot.Type(), slot.Slot(), iter->first, inst_iter->first); + impl_->events_.push_back(evt); + ++inst_iter; + } + } + ++iter; } } @@ -166,14 +180,15 @@ void EQEmu::InventoryDatabaseDataModel::Insert(const InventorySlot &slot, std::s DataEvent evt; evt.evt = DB_Insert; evt.inst = iter->second; - evt.slot = InventorySlot(slot.Type(), slot.Slot(), iter->first); + evt.slot = InventorySlot(slot.Type(), slot.Slot(), -1, iter->first); impl_->events_.push_back(evt); ++iter; } } } - else if(inst->GetBaseItem()->ItemClass == ItemClassCommon) { + else if(slot.AugIndex() < 0 && inst->GetBaseItem()->ItemClass == ItemClassCommon) { + //bag item that can have augs //if common put all augment contents in auto container = inst->GetContainer(); auto iter = container->Begin(); @@ -181,9 +196,9 @@ void EQEmu::InventoryDatabaseDataModel::Insert(const InventorySlot &slot, std::s DataEvent evt; evt.evt = DB_Insert; evt.inst = iter->second; - evt.slot = InventorySlot(slot.Type(), slot.Slot(), iter->first, slot.BagIndex()); + evt.slot = InventorySlot(slot.Type(), slot.Slot(), slot.BagIndex(), iter->first); impl_->events_.push_back(evt); - + ++iter; } } diff --git a/common/inventory_null_data_model.h b/common/inventory_null_data_model.h index 460fe1b3b..ed1872393 100644 --- a/common/inventory_null_data_model.h +++ b/common/inventory_null_data_model.h @@ -29,11 +29,11 @@ namespace EQEmu InventoryNullDataModel() { } virtual ~InventoryNullDataModel() { } - virtual void Begin() { printf("NDM: Begin\n"); } - virtual bool Commit() { printf("NDM: Commit\n"); return true; } - virtual void Rollback() { printf("NDM: Rollback\n"); } - virtual void Insert(const InventorySlot &slot, std::shared_ptr inst) { printf("NDM: Insert %s %s\n", slot.ToString().c_str(), inst ? inst->GetBaseItem()->Name : "Null" ); } - virtual void Delete(const InventorySlot &slot) { printf("NDM: Delete %s\n", slot.ToString().c_str()); } + virtual void Begin() { } + virtual bool Commit() { return true; } + virtual void Rollback() { } + virtual void Insert(const InventorySlot &slot, std::shared_ptr inst) { } + virtual void Delete(const InventorySlot &slot) { } }; } // EQEmu diff --git a/common/item_container.cpp b/common/item_container.cpp index f78d28461..5a38b009a 100644 --- a/common/item_container.cpp +++ b/common/item_container.cpp @@ -65,6 +65,29 @@ bool EQEmu::ItemContainer::Put(const int slot_id, std::shared_ptr return false; } +bool EQEmu::ItemContainer::HasItem(uint32 item_id) { + for(auto &item : impl_->items_) { + if(item.second->GetBaseItem()->ID == item_id) { + return true; + } + } + + return false; +} + +bool EQEmu::ItemContainer::HasItemByLoreGroup(uint32 loregroup) { + if(loregroup == 0xFFFFFFFF) + return false; + + for(auto &item : impl_->items_) { + if(item.second->GetBaseItem()->LoreGroup == loregroup) { + return true; + } + } + + return false; +} + uint32 EQEmu::ItemContainer::Size() { return (uint32)impl_->items_.size(); } diff --git a/common/item_container.h b/common/item_container.h index 7900c3840..2ea0829ec 100644 --- a/common/item_container.h +++ b/common/item_container.h @@ -42,6 +42,11 @@ namespace EQEmu std::shared_ptr Get(const int slot_id); bool Put(const int slot_id, std::shared_ptr inst); bool Delete(const int slot_id); + + //Utility + bool HasItem(uint32 item_id); + bool HasItemByLoreGroup(uint32 loregroup); + uint32 Size(); uint32 Size() const; diff --git a/common/item_container_default_serialization.cpp b/common/item_container_default_serialization.cpp index 4bcec1e17..0e51896a6 100644 --- a/common/item_container_default_serialization.cpp +++ b/common/item_container_default_serialization.cpp @@ -9,6 +9,8 @@ bool EQEmu::ItemContainerDefaultSerialization::Serialize(MemoryBuffer &buf, cons for(auto &iter : items) { buf.Write(container_number); buf.Write(iter.first); + buf.Write(-1); + buf.Write(-1); buf.Write(iter.second.get()); ret = true; } diff --git a/common/item_container_personal_serialization.cpp b/common/item_container_personal_serialization.cpp index eefd8423a..2a242a645 100644 --- a/common/item_container_personal_serialization.cpp +++ b/common/item_container_personal_serialization.cpp @@ -10,6 +10,8 @@ bool EQEmu::ItemContainerPersonalSerialization::Serialize(MemoryBuffer &buf, con if(iter.first < 33) { buf.Write(container_number); buf.Write(iter.first); + buf.Write(-1); + buf.Write(-1); buf.Write(iter.second.get()); ret = true; } diff --git a/common/item_data.h b/common/item_data.h index 0df9a86a0..ccb6b6411 100644 --- a/common/item_data.h +++ b/common/item_data.h @@ -72,6 +72,8 @@ struct InternalSerializedItem_Struct { struct SerializedItemInstance_Struct { int32 container_id; int32 slot_id; + int32 bag_id; + int32 aug_id; void *inst; }; diff --git a/common/patches/rof2.cpp b/common/patches/rof2.cpp index e2f0c02b3..6bc16c8d5 100644 --- a/common/patches/rof2.cpp +++ b/common/patches/rof2.cpp @@ -602,18 +602,18 @@ namespace RoF2 EQApplicationPacket *in = *p; *p = nullptr; - size_t entry_size = sizeof(int32) * 2 + sizeof(void*); - size_t entries = in->size / entry_size; + size_t entry_size = sizeof(SerializedItemInstance_Struct); + size_t entries = (in->size - sizeof(int32)) / entry_size; - if(entries == 0 || in->size % entry_size != 0) { + if(entries == 0 || (in->size - sizeof(int32)) % entry_size != 0) { Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", - opcodes->EmuToName(in->GetOpcode()), in->size, entry_size); + opcodes->EmuToName(in->GetOpcode()), (in->size - sizeof(int32)), entry_size); delete in; return; } unsigned char *__emu_buffer = in->pBuffer; - SerializedItemInstance_Struct *sis = (SerializedItemInstance_Struct*)__emu_buffer; + SerializedItemInstance_Struct *sis = (SerializedItemInstance_Struct*)(__emu_buffer + sizeof(int32)); EQEmu::MemoryBuffer packet_data; packet_data.Write(entries); @@ -1490,33 +1490,41 @@ namespace RoF2 ENCODE(OP_ItemPacket) { - delete *p; + EQApplicationPacket *in = *p; + *p = nullptr; - ////consume the packet - //EQApplicationPacket *in = *p; - //*p = nullptr; - // - //unsigned char *__emu_buffer = in->pBuffer; - //ItemPacket_Struct *old_item_pkt = (ItemPacket_Struct *)__emu_buffer; - //InternalSerializedItem_Struct *int_struct = (InternalSerializedItem_Struct *)(old_item_pkt->SerializedItem); - // - //uint32 length; - //char *serialized = SerializeItem((ItemInst *)int_struct->inst, int_struct->slot_id, &length, 0, old_item_pkt->PacketType); - // - //if (!serialized) { - // Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Serialization failed on item slot %d.", int_struct->slot_id); - // delete in; - // return; - //} - //in->size = length + 4; - //in->pBuffer = new unsigned char[in->size]; - //ItemPacket_Struct *new_item_pkt = (ItemPacket_Struct *)in->pBuffer; - //new_item_pkt->PacketType = old_item_pkt->PacketType; - //memcpy(new_item_pkt->SerializedItem, serialized, length); - // - //delete[] __emu_buffer; - //safe_delete_array(serialized); - //dest->FastQueuePacket(&in, ack_req); + size_t entry_size = sizeof(SerializedItemInstance_Struct); + size_t entries = (in->size - sizeof(int32)) / entry_size; + + if(entries == 0 || entries > 1 || (in->size - sizeof(int32)) % entry_size != 0) { + Log.Out(Logs::General, Logs::Netcode, "[STRUCTS] Wrong size on outbound %s: Got %d, expected multiple of %d", + opcodes->EmuToName(in->GetOpcode()), (in->size - sizeof(int32)), entry_size); + delete in; + return; + } + + unsigned char *__emu_buffer = in->pBuffer; + + int32 *packet_type = (int32*)(__emu_buffer); + SerializedItemInstance_Struct *sis = (SerializedItemInstance_Struct*)(__emu_buffer + sizeof(int32)); + EQEmu::MemoryBuffer packet_data; + packet_data.Write(*packet_type); + + EQEmu::ItemInstance *inst = (EQEmu::ItemInstance*)sis->inst; + if(!inst) { + delete in; + return; + } + + SerializeItem(packet_data, inst, sis->container_id, sis->slot_id, sis->bag_id, sis->slot_id); + + in->pBuffer = new uchar[packet_data.Size()]; + in->size = packet_data.Size(); + memcpy(in->pBuffer, packet_data, in->size); + + + delete[] __emu_buffer; + dest->FastQueuePacket(&in, ack_req); } ENCODE(OP_ItemVerifyReply) diff --git a/zone/client.h b/zone/client.h index 923401f60..5b6580b1e 100644 --- a/zone/client.h +++ b/zone/client.h @@ -818,13 +818,28 @@ public: 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); + 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); void SetStats(uint8 type,int16 set_val); void IncStats(uint8 type,int16 increase_val); void DropItem(int16 slot_id); //New Inventory bool SwapItem(const EQEmu::InventorySlot &src, const EQEmu::InventorySlot &dest, int number_in_stack); + bool SummonItem(uint32 item_id, + int16 charges, + const EQEmu::InventorySlot &slot, + uint32 aug1 = 0, + uint32 aug2 = 0, + uint32 aug3 = 0, + uint32 aug4 = 0, + uint32 aug5 = 0, + uint32 aug6 = 0, + bool attuned = false, + uint32 ornament_icon = 0, + uint32 ornament_idfile = 0, + uint32 ornament_hero_model = 0); // // class Client::TextLink @@ -881,6 +896,9 @@ public: bool IsValidSlot(uint32 slot); bool IsBankSlot(uint32 slot); + //inv2 + void SendItemPacket(const EQEmu::InventorySlot &slot, std::shared_ptr inst, ItemPacketType packet_type); + inline bool IsTrader() const { return(Trader); } inline bool IsBuyer() const { return(Buyer); } eqFilterMode GetFilter(eqFilterType filter_id) const { return ClientFilters[filter_id]; } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 09f64e8b2..c67c334ab 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -1722,14 +1722,11 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app) */ if (loaditems) { /* Dont load if a length error occurs */ BulkSendInventoryItems(); - // /* Send stuff on the cursor which isnt sent in bulk */ - // for (auto iter = m_inv.cursor_cbegin(); iter != m_inv.cursor_cend(); ++iter) { - // /* First item cursor is sent in bulk inventory packet */ - // if (iter == m_inv.cursor_cbegin()) - // continue; - // const ItemInst *inst = *iter; - // SendItemPacket(MainCursor, inst, ItemPacketSummonItem); - // } + EQEmu::InventorySlot slot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor); + auto cursor = m_inventory.Get(slot); + if(cursor) { + SendItemPacket(slot, cursor, ItemPacketSummonItem); + } } /* Task Packets */ diff --git a/zone/command.cpp b/zone/command.cpp index fed5c7807..e24e2425b 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -5418,24 +5418,25 @@ void command_summonitem(Client *c, const Seperator *sep) item_status = static_cast(item->MinStatus); } + EQEmu::InventorySlot cursor(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor); if (item_status > c->Admin()) c->Message(13, "Error: Insufficient status to summon this item."); else if (sep->argnum==2 && sep->IsNumber(2)) - c->SummonItem(itemid, atoi(sep->arg[2])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor); else if (sep->argnum==3) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor, atoi(sep->arg[3])); else if (sep->argnum==4) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor, atoi(sep->arg[3]), atoi(sep->arg[4])); else if (sep->argnum==5) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor, atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5])); else if (sep->argnum==6) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor, atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6])); else if (sep->argnum==7) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor, atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7])); else if (sep->argnum==8) - c->SummonItem(itemid, atoi(sep->arg[2]), atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7]), atoi(sep->arg[8])); + c->SummonItem(itemid, atoi(sep->arg[2]), cursor, atoi(sep->arg[3]), atoi(sep->arg[4]), atoi(sep->arg[5]), atoi(sep->arg[6]), atoi(sep->arg[7]), atoi(sep->arg[8])); else { - c->SummonItem(itemid); + c->SummonItem(itemid, -1, cursor); } } } diff --git a/zone/inventory.cpp b/zone/inventory.cpp index bdb800add..68ee62dc1 100644 --- a/zone/inventory.cpp +++ b/zone/inventory.cpp @@ -2427,52 +2427,74 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const // Send an item packet (including all subitems of the item) void Client::SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type) { - if (!inst) +// if (!inst) +// return; +// +// // Serialize item into |-delimited string +// std::string packet = inst->Serialize(slot_id); +// +// EmuOpcode opcode = OP_Unknown; +// EQApplicationPacket* outapp = nullptr; +// ItemPacket_Struct* itempacket = nullptr; +// +// // Construct packet +// opcode = (packet_type==ItemPacketViewLink) ? OP_ItemLinkResponse : OP_ItemPacket; +// outapp = new EQApplicationPacket(opcode, packet.length()+sizeof(ItemPacket_Struct)); +// itempacket = (ItemPacket_Struct*)outapp->pBuffer; +// memcpy(itempacket->SerializedItem, packet.c_str(), packet.length()); +// itempacket->PacketType = packet_type; +// +//#if EQDEBUG >= 9 +// DumpPacket(outapp); +//#endif +// FastQueuePacket(&outapp); +} + +void Client::SendItemPacket(const EQEmu::InventorySlot &slot, std::shared_ptr inst, ItemPacketType packet_type) { + if(!inst) { return; + } - // Serialize item into |-delimited string - std::string packet = inst->Serialize(slot_id); - + EQEmu::MemoryBuffer item; EmuOpcode opcode = OP_Unknown; - EQApplicationPacket* outapp = nullptr; - ItemPacket_Struct* itempacket = nullptr; + opcode = (packet_type == ItemPacketViewLink) ? OP_ItemLinkResponse : OP_ItemPacket; - // Construct packet - opcode = (packet_type==ItemPacketViewLink) ? OP_ItemLinkResponse : OP_ItemPacket; - outapp = new EQApplicationPacket(opcode, packet.length()+sizeof(ItemPacket_Struct)); - itempacket = (ItemPacket_Struct*)outapp->pBuffer; - memcpy(itempacket->SerializedItem, packet.c_str(), packet.length()); - itempacket->PacketType = packet_type; - -#if EQDEBUG >= 9 - DumpPacket(outapp); -#endif - FastQueuePacket(&outapp); + item.Write((int32)packet_type); + item.Write(slot.Type()); + item.Write(slot.Slot()); + item.Write(slot.BagIndex()); + item.Write(slot.AugIndex()); + item.Write(inst.get()); + + EQApplicationPacket outapp(opcode, item.Size()); + memcpy(outapp.pBuffer, item, item.Size()); + QueuePacket(&outapp); } EQApplicationPacket* Client::ReturnItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type) { - if (!inst) - return nullptr; - - // Serialize item into |-delimited string - std::string packet = inst->Serialize(slot_id); - - EmuOpcode opcode = OP_Unknown; - EQApplicationPacket* outapp = nullptr; - BulkItemPacket_Struct* itempacket = nullptr; - - // Construct packet - opcode = OP_ItemPacket; - outapp = new EQApplicationPacket(opcode, packet.length()+1); - itempacket = (BulkItemPacket_Struct*)outapp->pBuffer; - memcpy(itempacket->SerializedItem, packet.c_str(), packet.length()); - -#if EQDEBUG >= 9 - DumpPacket(outapp); -#endif - - return outapp; + return nullptr; +// if (!inst) +// return nullptr; +// +// // Serialize item into |-delimited string +// std::string packet = inst->Serialize(slot_id); +// +// EmuOpcode opcode = OP_Unknown; +// EQApplicationPacket* outapp = nullptr; +// BulkItemPacket_Struct* itempacket = nullptr; +// +// // Construct packet +// opcode = OP_ItemPacket; +// outapp = new EQApplicationPacket(opcode, packet.length()+1); +// itempacket = (BulkItemPacket_Struct*)outapp->pBuffer; +// memcpy(itempacket->SerializedItem, packet.c_str(), packet.length()); +// +//#if EQDEBUG >= 9 +// DumpPacket(outapp); +//#endif +// +// return outapp; } static int16 BandolierSlotToWeaponSlot(int BandolierSlot) @@ -3143,7 +3165,16 @@ bool Client::SwapItem(const EQEmu::InventorySlot &src, const EQEmu::InventorySlo } else { Message(0, "Swap failure!\n"); //should kick the player here... + } + EQEmu::InventorySlot cursor(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor); + if(!m_inventory.Get(cursor)) { + if(m_inventory.PopFromCursorBuffer()) { + auto c_inst = m_inventory.Get(cursor); + if(c_inst) { + SendItemPacket(EQEmu::InventorySlot(EQEmu::InvTypePersonal, EQEmu::PersonalSlotCursor), c_inst, ItemPacketSummonItem); + } + } } if(auto_attack && res && recalc_weapon_speed) { @@ -3157,3 +3188,90 @@ bool Client::SwapItem(const EQEmu::InventorySlot &src, const EQEmu::InventorySlo return res; } +bool Client::SummonItem(uint32 item_id, + int16 charges, + const EQEmu::InventorySlot &slot, + uint32 aug1, + uint32 aug2, + uint32 aug3, + uint32 aug4, + uint32 aug5, + uint32 aug6, + bool attuned, + uint32 ornament_icon, + uint32 ornament_idfile, + uint32 ornament_hero_model) +{ + std::shared_ptr inst = database.CreateItem(item_id, charges); + if(!inst) + return false; + + if(inst->GetBaseItem()->ItemClass == ItemClassCommon) { + if(aug1) { + std::shared_ptr aug = database.CreateItem(aug1); + if(!aug) + return false; + + if(!inst->Put(0, aug)) { + return false; + } + } + + if(aug2) { + std::shared_ptr aug = database.CreateItem(aug2); + if(!aug) + return false; + + if(!inst->Put(1, aug)) { + return false; + } + } + + if(aug3) { + std::shared_ptr aug = database.CreateItem(aug3); + if(!aug) + return false; + + if(!inst->Put(2, aug)) { + return false; + } + } + + if(aug4) { + std::shared_ptr aug = database.CreateItem(aug4); + if(!aug) + return false; + + if(!inst->Put(3, aug)) { + return false; + } + } + + if(aug5) { + std::shared_ptr aug = database.CreateItem(aug5); + if(!aug) + return false; + + if(!inst->Put(4, aug)) { + return false; + } + } + + if(aug6) { + std::shared_ptr aug = database.CreateItem(aug6); + if(!aug) + return false; + + if(!inst->Put(5, aug)) { + return false; + } + } + } + + auto res = m_inventory.Summon(slot, inst); + if(res) { + SendItemPacket(slot, inst, ItemPacketSummonItem); + } + + return res; +}