Loading...   

  • Created By Uleat On: 08:04 PM September 12, 2014
  • Link

 common/item.cpp        | 224 +++++++++++++++++++++++++++++++++++++++++++++++--
 common/item.h          |  56 ++++++++++---
 common/shareddb.cpp    |  15 +++-
 zone/client_packet.cpp |  25 ++++--
 zone/command.cpp       |  18 ++--
 zone/forage.cpp        |  14 +++-
 zone/inventory.cpp     |  40 +++++++--
 zone/spell_effects.cpp |  14 +++-
 8 files changed, 354 insertions(+), 52 deletions(-)

diff --git a/common/item.cpp b/common/item.cpp
index 513ddb2..2a653d9 100644
--- a/common/item.cpp
+++ b/common/item.cpp
@@ -57,44 +57,250 @@ static inline int32 GetNextItemInstSerialNumber() {
 //
 // class ItemInstQueue
 //
+ItemInstQueue::ItemInstQueue() {
+	m_use_limbo_array = false;
+	m_last_insert = nullptr;
+	m_cursor_ = nullptr;
+	for (int i = MAIN_BEGIN; i < EmuConstants::MAP_LIMBO_SIZE; ++i)
+		m_limbo_array[i] = nullptr;
+}
+
 ItemInstQueue::~ItemInstQueue() {
+	// these are duplicates of what is contained in m_external - no deletes required
+	m_last_insert = nullptr;
+	m_cursor_ = nullptr;
+	for (int i = MAIN_BEGIN; i < EmuConstants::MAP_LIMBO_SIZE; ++i)
+		m_limbo_array[i] = nullptr;
+	m_limbo_list.clear();
+	m_overflow_list.clear();
+
+	// this iteration will delete the actual memory instances
 	iter_queue cur, end;
-	cur = m_list.begin();
-	end = m_list.end();
+	cur = m_external_list.begin();
+	end = m_external_list.end();
 	for (; cur != end; ++cur) {
 		ItemInst *tmp = *cur;
 		safe_delete(tmp);
 	}
-	m_list.clear();
+	m_external_list.clear();
+}
+
+bool ItemInstQueue::overflow_can_move() {
+	if (m_overflow_list.size()) {
+		if (m_use_limbo_array) {
+			if (limbo_ptr() < EmuConstants::MAP_LIMBO_SIZE) {
+				return true;
+			}
+		}
+		else {
+			if (m_limbo_list.size() < EmuConstants::MAP_LIMBO_SIZE) {
+				return true;
+			}
+		}
+	}
+
+	return false;
 }
 
 // Put item onto back of queue
 void ItemInstQueue::push(ItemInst* inst)
 {
-	m_list.push_back(inst);
+	if (!inst) {
+		m_last_insert = nullptr;
+		rebuild_queue();
+		return;
+	}
+
+	int16 ptr = limbo_ptr();
+
+	if (ptr < EmuConstants::MAP_LIMBO_SIZE) {
+		if (m_use_limbo_array) {
+			inst->SetCurrentSlot(ptr);
+			m_limbo_array[ptr] = inst;
+		}
+		else {
+			inst->SetCurrentSlot(MAIN_BEGIN);
+			m_limbo_list.push_back(inst);
+		}
+	}
+	else {
+		inst->SetCurrentSlot(EmuConstants::MAP_LIMBO_SIZE);
+		m_overflow_list.push_back(inst);
+	}
+
+	m_last_insert = inst;
+
+	rebuild_queue();
 }
 
 // Put item onto front of queue
 void ItemInstQueue::push_front(ItemInst* inst)
 {
-	m_list.push_front(inst);
+	if (!inst) {
+		m_last_insert = nullptr;
+		rebuild_queue();
+		return;
+	}
+
+	if (m_cursor_) {
+		int16 ptr = limbo_ptr();
+
+		if (m_use_limbo_array) {
+			if (ptr < EmuConstants::MAP_LIMBO_SIZE) {
+				m_cursor_->SetCurrentSlot(ptr);
+				m_limbo_array[ptr] = m_cursor_;
+			}
+			else {
+				m_cursor_->SetCurrentSlot(EmuConstants::MAP_LIMBO_SIZE);
+				m_overflow_list.push_back(m_cursor_);
+			}
+		}
+		else {
+			if (ptr < EmuConstants::MAP_LIMBO_SIZE) {
+				m_cursor_->SetCurrentSlot(MAIN_BEGIN);
+				m_limbo_list.push_back(m_cursor_);
+			}
+			else {
+				m_cursor_->SetCurrentSlot(EmuConstants::MAP_LIMBO_SIZE);
+				m_overflow_list.push_back(m_cursor_);
+			}
+		}
+	}
+
+	inst->SetCurrentSlot(MAIN_BEGIN);
+	m_cursor_ = inst;
+	m_last_insert = inst;
+
+	rebuild_queue();
 }
 
 // Remove item from front of queue
 ItemInst* ItemInstQueue::pop()
 {
-	if (m_list.size() == 0)
+	m_last_insert = nullptr;
+
+	if (m_cursor_ == nullptr) { // original behavior
 		return nullptr;
+	}
+
+	ItemInst* inst = m_cursor_;
+	m_cursor_ = pull_limbo_front();
 
-	ItemInst* inst = m_list.front();
-	m_list.pop_front();
 	return inst;
 }
 
 // Look at item at front of queue
 ItemInst* ItemInstQueue::peek_front() const
 {
-	return (m_list.size() == 0) ? nullptr : m_list.front();
+	// we could just return m_cursor_..but, this provides the original behavior to all external code
+	return (m_external_list.size() == 0) ? nullptr : m_external_list.front();
+}
+
+int16 ItemInstQueue::limbo_ptr() {
+	if (m_use_limbo_array) {
+		for (int i = MAIN_BEGIN; i < EmuConstants::MAP_LIMBO_SIZE; ++i) {
+			if (m_limbo_array[i] == nullptr) {
+				return i;
+			}
+		}
+	}
+	else {
+		// we don't assign unique ItemInst::current_slot ids when using the list buffer - extra work for something the client doesn't use...
+		if (m_limbo_list.size() < EmuConstants::MAP_LIMBO_SIZE) {
+			return MAIN_BEGIN;
+		}
+	}
+
+	return EmuConstants::MAP_LIMBO_SIZE;
+}
+
+ItemInst* ItemInstQueue::pull_overflow_front() {
+	m_last_insert = nullptr;
+
+	if (m_overflow_list.size() && (limbo_ptr() != EmuConstants::MAP_LIMBO_SIZE)) {
+		ItemInst* inst = m_overflow_list.front();
+		m_overflow_list.pop_front();
+		inst->SetCurrentSlot(MAIN_BEGIN);
+		return inst;
+	}
+	else {
+		return nullptr;
+	}
+}
+
+const ItemInst* ItemInstQueue::last_insert() {
+	const ItemInst* inst = m_last_insert;
+	m_last_insert = nullptr;
+	return inst;
+}
+
+void ItemInstQueue::initialize_limbo_array() {
+	if (m_limbo_list.size()) {
+		while (m_limbo_list.size()) {
+			int16 ptr = limbo_ptr();
+
+			if (ptr < EmuConstants::MAP_LIMBO_SIZE) {
+				m_limbo_array[ptr] = m_limbo_list.front();
+				m_limbo_array[ptr]->SetCurrentSlot(ptr);
+				m_limbo_list.pop_front();
+			}
+			else {
+				m_overflow_list.push_back(m_limbo_list.front());
+				m_overflow_list.back()->SetCurrentSlot(EmuConstants::MAP_LIMBO_SIZE);
+				m_limbo_list.pop_front();
+			}
+		}
+
+		rebuild_queue();
+	}
+
+	m_last_insert = nullptr;
+}
+
+ItemInst* ItemInstQueue::pull_limbo_front() {
+	ItemInst* inst = nullptr;
+
+	if (m_use_limbo_array) {
+		for (int i = MAIN_BEGIN; i < EmuConstants::MAP_LIMBO_SIZE; ++i) {
+			if (m_limbo_array[i] != nullptr) {
+				inst = m_limbo_array[i];
+				m_limbo_array[i] = nullptr;
+				break;
+			}
+		}
+	}
+	else {
+		if (m_limbo_list.size()) {
+			inst = m_limbo_list.front();
+			m_limbo_list.pop_front();
+		}
+	}
+
+	if (inst)
+		inst->SetCurrentSlot(MAIN_BEGIN);
+
+	m_last_insert = nullptr;
+
+	return inst;
+}
+
+void ItemInstQueue::rebuild_queue() {
+	m_external_list.clear();
+
+	if (m_use_limbo_array) {
+		for (int i = MAIN_BEGIN; i < EmuConstants::MAP_LIMBO_SIZE; ++i)
+			if (m_limbo_array[i])
+				m_external_list.push_back(m_limbo_array[i]);
+	}
+	else {
+		m_external_list = m_limbo_list;
+	}
+
+	if (m_cursor_)
+		m_external_list.push_front(m_cursor_);
+
+	if (m_overflow_list.size())
+		m_external_list.merge(m_overflow_list);
 }
 
 
diff --git a/common/item.h b/common/item.h
index c24c708..fb7331c 100644
--- a/common/item.h
+++ b/common/item.h
@@ -87,27 +87,51 @@ enum {
 class ItemInstQueue
 {
 public:
+	ItemInstQueue();
 	~ItemInstQueue();
-	/////////////////////////
-	// Public Methods
-	/////////////////////////
 
-	inline iter_queue begin()	{ return m_list.begin(); }
-	inline iter_queue end()		{ return m_list.end(); }
+	// RoF+ clients require a special work-around to use limbo properly
+	// this lets ItemInstQueue know to use the special adaptation
+	void set_limbo_array_use(bool array_flag) {
+		if (!m_use_limbo_flag_set) {
+			if (m_use_limbo_array = array_flag)
+				initialize_limbo_array();
+			m_use_limbo_flag_set = true;
+		}
+	}
+
+	bool overflow_can_move();			// checks for available limbo slot and overflow item to move
+	ItemInst* pull_overflow_front();	// return (with pop) front of overflow_list - checks for room in limbo before releasing
+	const ItemInst* last_insert();
+
+	iter_queue begin()	{ return m_external_list.begin(); }
+	iter_queue end()	{ return m_external_list.end(); }
 
 	void push(ItemInst* inst);
 	void push_front(ItemInst* inst);
+
 	ItemInst* pop();
 	ItemInst* peek_front() const;
-	inline int size()		{ return static_cast<int>(m_list.size()); }
 
-protected:
-	/////////////////////////
-	// Protected Members
-	/////////////////////////
-
-	std::list<ItemInst*> m_list;
+	int size() { return static_cast<int>(m_external_list.size()); }
 
+protected:
+	int16 limbo_ptr();						// returns available index (available: [list: 0, array: {0..35}] full: 36)
+
+	std::list<ItemInst*> m_external_list;	// all clients external cursor list (db saves, hasitem(), etc...)
+
+private:
+	void initialize_limbo_array();			// moves any early placed items from m_limbo_list to m_limbo_array
+	ItemInst* pull_limbo_front();			// removes first ItemInst* from limbo based on buffer bias
+	void rebuild_queue();					// rearranges m_external for array or list buffer bias
+	
+	bool m_use_limbo_flag_set;				// flag to avoid resetting m_use_limbo_array state
+	bool m_use_limbo_array;					// use array or list flag
+	const ItemInst* m_last_insert;			// pointer to last ItemInst inserted into the queue (cleared on access)
+	ItemInst* m_cursor_;					// all clients visible cursor
+	ItemInst* m_limbo_array[36];			// RoF+ limbo array buffer (should instantiate with EmuConstants::MAP_LIMBO_SIZE)
+	std::list<ItemInst*> m_limbo_list;		// UF- limbo list buffer
+	std::list<ItemInst*> m_overflow_list;	// all clients overflow (these are not sent to the client..but, still need to be tracked)
 };
 
 // ########################################
@@ -130,9 +154,15 @@ public:
 	ItemInst* GetItem(int16 slot_id) const;
 	ItemInst* GetItem(int16 slot_id, uint8 bagidx) const;
 
+	// ItemInstQueue accessors
+	void SetLimboArrayFlag(bool array_flag)	{ m_cursor.set_limbo_array_use(array_flag); }
+	bool LimboUpdateAvailable()				{ return m_cursor.overflow_can_move(); }
+	ItemInst* GetNextCursorOverflow()		{ return m_cursor.pull_overflow_front(); }	// this must be handled when called
+	const ItemInst* GetLastQueueInsert() 	{ return m_cursor.last_insert(); }
+
 	inline iter_queue cursor_begin()	{ return m_cursor.begin(); }
 	inline iter_queue cursor_end()		{ return m_cursor.end(); }
-	inline bool CursorEmpty()		{ return (m_cursor.size() == 0); }
+	inline bool CursorEmpty()			{ return (m_cursor.size() == 0); }
 
 	// Retrieve a read-only item from inventory
 	inline const ItemInst* operator[](int16 slot_id) const { return GetItem(slot_id); }
diff --git a/common/shareddb.cpp b/common/shareddb.cpp
index 10e3d20..404ae6b 100644
--- a/common/shareddb.cpp
+++ b/common/shareddb.cpp
@@ -398,6 +398,7 @@ bool SharedDatabase::SetStartingItems(PlayerProfile_Struct* pp, Inventory* inv,
 		ItemInst* myinst = CreateBaseItem(myitem, charges);
 		if(slot < 0)
 			slot = inv->FindFreeSlot(0,0);
+		_log(INVENTORY__ERROR, "SharedDatabase::SetStartingItems() - Calling inventory->PutItem() with %s", (myinst) ? "ItemInst*" : "nullptr");
 		inv->PutItem(slot, *myinst);
 		safe_delete(myinst);
 	}
@@ -477,7 +478,7 @@ bool SharedDatabase::GetSharedBank(uint32 id, Inventory* inv, bool is_charid) {
 						}
 					}
 				}
-
+				_log(INVENTORY__ERROR, "SharedDatabase::GetSharedBank() - Calling inventory->PutItem() with %s", (inst) ? "ItemInst*" : "nullptr");
 				put_slot_id = inv->PutItem(slot_id, *inst);
 				safe_delete(inst);
 
@@ -586,6 +587,7 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
 				}
 
 				if (slot_id >= 8000 && slot_id <= 8999) {
+					_log(INVENTORY__ERROR, "SharedDatabase::GetInventory(1) - Calling inventory->PushCursor() with %s", (inst) ? "ItemInst*" : "nullptr");
 					put_slot_id = inv->PushCursor(*inst);
 				}
 				// Admins: please report any occurrences of this error
@@ -593,9 +595,11 @@ bool SharedDatabase::GetInventory(uint32 char_id, Inventory* inv) {
 					LogFile->write(EQEMuLog::Error,
 						"Warning: Defunct location for item in inventory: charid=%i, item_id=%i, slot_id=%i .. pushing to cursor...",
 						char_id, item_id, slot_id);
+					_log(INVENTORY__ERROR, "SharedDatabase::GetInventory(2) - Calling inventory->PushCursor() with %s", (inst) ? "ItemInst*" : "nullptr");
 					put_slot_id = inv->PushCursor(*inst);
 				}
 				else {
+					_log(INVENTORY__ERROR, "SharedDatabase::GetInventory(1) - Calling inventory->PutItem() with %s", (inst) ? "ItemInst*" : "nullptr");
 					put_slot_id = inv->PutItem(slot_id, *inst);
 				}
 
@@ -698,10 +702,15 @@ bool SharedDatabase::GetInventory(uint32 account_id, char* name, Inventory* inv)
 					}
 				}
 			}
-			if (slot_id>=8000 && slot_id <= 8999)
+			if (slot_id >= 8000 && slot_id <= 8999) {
+				_log(INVENTORY__ERROR, "SharedDatabase::GetInventory(3) - Calling inventory->PushCursor() with %s", (inst) ? "ItemInst*" : "nullptr");
 				put_slot_id = inv->PushCursor(*inst);
-			else
+			}
+			else {
+				_log(INVENTORY__ERROR, "SharedDatabase::GetInventory(2) - Calling inventory->PutItem() with %s", (inst) ? "ItemInst*" : "nullptr");
 				put_slot_id = inv->PutItem(slot_id, *inst);
+			}
+
 			safe_delete(inst);
 
 			// Save ptr to item in inventory
diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp
index 9d7c9e0..05f30b9 100644
--- a/zone/client_packet.cpp
+++ b/zone/client_packet.cpp
@@ -513,6 +513,9 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
 	ClientVersion = Connection()->ClientVersion();
 	ClientVersionBit = 1 << (ClientVersion - 1);
 
+	// tell the cursor queue whether to use array (RoF+) or list (UF-) format
+	GetInv().SetLimboArrayFlag(ClientVersion >= EQClientRoF && ClientVersion < _EQClientCount);
+
 	// Antighost code
 	// tmp var is so the search doesnt find this object
 	Client* client = entity_list.GetClientByName(cze->char_name);
@@ -9438,13 +9441,16 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) {
 		BulkSendInventoryItems();
 
 		// Send stuff on the cursor which isnt sent in bulk
-		iter_queue it;
-		for (it=m_inv.cursor_begin();it!=m_inv.cursor_end();++it) {
-			// First item cursor is sent in bulk inventory packet
-			if (it==m_inv.cursor_begin())
-				continue;
-			const ItemInst *inst=*it;
-			SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
+		iter_queue it = m_inv.cursor_begin();
+
+		if (it != m_inv.cursor_end()) // skip 'front' (MainCursor) since it was sent in BulkSendInventoryItems()
+			++it;
+
+		for (; it != m_inv.cursor_end(); ++it) {
+			const ItemInst* limbo_inst = *it;
+
+			if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE)) // don't send overflow..they're lost and cause a desync
+				SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
 		}
 	}
 
@@ -12109,7 +12115,10 @@ void Client::Handle_OP_GuildBank(const EQApplicationPacket *app)
 			{
 				PushItemOnCursor(*inst);
 
-				SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
+				const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+				if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+					SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
 
 				GuildBanks->DeleteItem(GuildID(), gbwis->Area, gbwis->SlotID, gbwis->Quantity);
 			}
diff --git a/zone/command.cpp b/zone/command.cpp
index cf180f2..f4699a8 100644
--- a/zone/command.cpp
+++ b/zone/command.cpp
@@ -11393,11 +11393,14 @@ void command_zopp(Client *c, const Seperator *sep)
 	else {
 		ItemPacketType packettype;
 
-		if (strcasecmp(sep->arg[1], "trade") == 0 || strcasecmp(sep->arg[1], "t") == 0) {
+		if (strcasecmp(sep->arg[1], "trade") == 0 || strcasecmp(sep->arg[1], "t") == 0)
 			packettype = ItemPacketTrade;
-		}
-		else {
+		else
 			packettype = ItemPacketSummonItem;
+
+		if ((c->GetClientVersion() >= EQClientRoF) && (packettype == ItemPacketSummonItem)) {
+			c->Message(15, "ItemPacketSummonItem zopp packets are no longer supported in RoF+ clients");
+			return;
 		}
 
 		int16 slotid = atoi(sep->arg[2]);
@@ -11411,13 +11414,10 @@ void command_zopp(Client *c, const Seperator *sep)
 			return;
 		}
 
-		int16 item_status = 0;
 		const Item_Struct* item = database.GetItem(itemid);
-		if(item) {
-			item_status = static_cast<int16>(item->MinStatus);
-		}
-		if (item_status > c->Admin()) {
-			c->Message(13, "Error: Insufficient status to use this command.");
+
+		if (item->MinStatus > c->Admin()) {
+			c->Message(13, "Error: Insufficient status to use this item.");
 			return;
 		}
 
diff --git a/zone/forage.cpp b/zone/forage.cpp
index d100803..77d374b 100644
--- a/zone/forage.cpp
+++ b/zone/forage.cpp
@@ -348,7 +348,12 @@ void Client::GoFish()
 			else
 			{
 				PushItemOnCursor(*inst);
-				SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
+
+				const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+				if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+					SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
+
 				if(RuleB(TaskSystem, EnableTaskSystem))
 					UpdateTasksForItem(ActivityFish, food_id);
 
@@ -464,7 +469,12 @@ void Client::ForageItem(bool guarantee) {
 			}
 			else {
 				PushItemOnCursor(*inst);
-				SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
+
+				const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+				if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+					SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
+
 				if(RuleB(TaskSystem, EnableTaskSystem))
 					UpdateTasksForItem(ActivityForage, foragedfood);
 
diff --git a/zone/inventory.cpp b/zone/inventory.cpp
index a4625bf..bbec3a1 100644
--- a/zone/inventory.cpp
+++ b/zone/inventory.cpp
@@ -581,7 +581,11 @@ bool Client::SummonItem(uint32 item_id, int16 charges, uint32 aug1, uint32 aug2,
 	// put item into inventory
 	if (to_slot == MainCursor) {
 		PushItemOnCursor(*inst);
-		SendItemPacket(MainCursor, inst, ItemPacketSummonItem);
+
+		const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+		if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+			SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
 	}
 	else {
 		PutItemInInventory(to_slot, *inst, true);
@@ -815,7 +819,10 @@ bool Client::PushItemOnCursor(const ItemInst& inst, bool client_update)
 	m_inv.PushCursor(inst);
 
 	if (client_update) {
-		SendItemPacket(MainCursor, &inst, ItemPacketSummonItem);
+		const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+		if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+			SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
 	}
 
 	std::list<ItemInst*>::const_iterator s=m_inv.cursor_begin(),e=m_inv.cursor_end();
@@ -830,8 +837,17 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
 	else
 		m_inv.PutItem(slot_id, inst);
 
-	if (client_update)
-		SendItemPacket(slot_id, &inst, ((slot_id == MainCursor) ? ItemPacketSummonItem : ItemPacketTrade));
+	if (client_update) {
+		if (slot_id == MainCursor) {
+			const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+			if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+				SendItemPacket(slot_id, limbo_inst, ItemPacketSummonItem);
+		}
+		else {
+			SendItemPacket(slot_id, &inst, ItemPacketTrade);
+		}
+	}
 
 	if (slot_id == MainCursor) {
 		std::list<ItemInst*>::const_iterator s = m_inv.cursor_begin(), e = m_inv.cursor_end();
@@ -847,6 +863,7 @@ bool Client::PutItemInInventory(int16 slot_id, const ItemInst& inst, bool client
 void Client::PutLootInInventory(int16 slot_id, const ItemInst &inst, ServerLootItem_Struct** bag_item_data)
 {
 	mlog(INVENTORY__SLOTS, "Putting loot item %s (%d) into slot %d", inst.GetItem()->Name, inst.GetItem()->ID, slot_id);
+	_log(INVENTORY__ERROR, "Client::PutLootInInventory() - Calling inventory->PutItem() with %s", (inst) ? "ItemInst*" : "nullptr");
 	m_inv.PutItem(slot_id, inst);
 
 	SendLootItemInPacket(&inst, slot_id);
@@ -1286,10 +1303,21 @@ bool Client::SwapItem(MoveItem_Struct* move_in) {
 		return false;
 	}
 
-	// This could be expounded upon at some point to let the server know that
-	// the client has moved a buffered cursor item onto the active cursor -U
+	// this is now used to let the server client's ItemInstQueue know that the game client has room in its limbo buffer
 	if (move_in->from_slot == move_in->to_slot) { // Item summon, no further proccessing needed
 		if(RuleB(QueryServ, PlayerLogMoves)) { QSSwapItemAuditor(move_in); } // QS Audit
+
+		const ItemInst* overflow_inst = m_inv.GetNextCursorOverflow();
+
+		PushItemOnCursor(*overflow_inst);
+
+		safe_delete(overflow_inst);
+
+		const ItemInst* limbo_inst = m_inv.GetLastQueueInsert();
+
+		if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+			SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
+
 		return true;
 	}
 
diff --git a/zone/spell_effects.cpp b/zone/spell_effects.cpp
index b10c436..f91fa71 100644
--- a/zone/spell_effects.cpp
+++ b/zone/spell_effects.cpp
@@ -1165,7 +1165,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
 
 						if (SummonedItem) {
 							c->PushItemOnCursor(*SummonedItem);
-							c->SendItemPacket(MainCursor, SummonedItem, ItemPacketSummonItem);
+
+							const ItemInst* limbo_inst = c->GetInv().GetLastQueueInsert();
+
+							if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+								c->SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
+
 							safe_delete(SummonedItem);
 						}
 						SummonedItem = database.CreateItem(spell.base[i], charges);
@@ -2990,7 +2995,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
 	if (SummonedItem) {
 		Client *c=CastToClient();
 		c->PushItemOnCursor(*SummonedItem);
-		c->SendItemPacket(MainCursor, SummonedItem, ItemPacketSummonItem);
+
+		const ItemInst* limbo_inst = c->GetInv().GetLastQueueInsert();
+
+		if (limbo_inst && (limbo_inst->GetCurrentSlot() != EmuConstants::MAP_LIMBO_SIZE))
+			c->SendItemPacket(MainCursor, limbo_inst, ItemPacketSummonItem);
+
 		safe_delete(SummonedItem);
 	}
 

Raw Paste Data