Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Server Code Submissions

Reply
 
Thread Tools Display Modes
  #1  
Old 08-23-2012, 06:33 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default COMMITTED: CSD Bandolier Patch

This will be my last patch for some time. I have lost internet access at home and can no longer keep my source code updated nor research when I need to.
(I can hear the sobbing from here...)


This patch attempts to fix the Bandolier Swap issue as well as updates a few things in previous patches. It is also a cumulative patch since neither previous
patch ('CSD Support Patch' nor 'CSD Bugged Corpse Patch') has been committed to the source SVN as yet. It was diff'd against my last SVN update.

[CSD Bandolier Patch]
Code:
Index: zone/client_packet.cpp
===================================================================
--- zone/client_packet.cpp	(revision 2193)
+++ zone/client_packet.cpp	(working copy)
@@ -3310,7 +3310,59 @@
 			return;
 		}
 	}
-	SwapItem(mi);
+
+	// Added checks for illegal bagslot swaps..should help with certain cheats (currently checks personal and cursor bag slots.)
+	// - If a player has used an illegal inventory cheat, they can become bugged at some point (especially concerning lore items.)
+	//* Start
+	bool mi_hack = false;
+
+	if (mi->from_slot >= 251 && mi->from_slot <= 340) {
+		if (mi->from_slot > 330)
+			mi_hack = true; // why are we moving from a cursor bagslot when you can't open it?
+		else {			
+			sint16 from_invslot = Inventory::CalcSlotId(mi->from_slot);
+			const ItemInst *from_invslotitem = GetInv().GetItem(from_invslot); 
+
+			if (!from_invslotitem) // trying to move from bag slots when parent inventory slot is empty
+				mi_hack = true;
+			else if (from_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
+				if ((Inventory::CalcBagIdx(mi->from_slot) + 1) > from_invslotitem->GetItem()->BagSlots)
+					mi_hack = true; // trying to move from slots beyond parent container size
+			}
+			else // trying to move from bag slots when inventory slot item is not a container
+				mi_hack = true;
+		}
+	}
+
+	if (mi->to_slot >= 251 && mi->to_slot <= 340) {
+		if (mi->to_slot > 330)
+			mi_hack = true; // why are we moving to a cursor bagslot when you can't open it?
+		else {
+			sint16 to_invslot = Inventory::CalcSlotId(mi->to_slot);
+			const ItemInst *to_invslotitem = GetInv().GetItem(to_invslot);
+
+			if (!to_invslotitem) // trying to move into bag slots when parent inventory slot is empty
+				mi_hack = true;
+			else if (to_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
+				if ((Inventory::CalcBagIdx(mi->to_slot) + 1) > to_invslotitem->GetItem()->BagSlots)
+					mi_hack = true; // trying to move into slots beyond parent container size
+			}
+			else // trying to move into bag slots when inventory slot item is not a container
+				mi_hack = true;
+		}
+	}
+
+	if (mi_hack) { // a CSD can also cause this condition, but more likely the use of a cheat
+		Message(13, "Hack detected: Illegal use of inventory bag slots!");
+		// TODO: Decide whether to log player as hacker - currently has no teeth...
+		// Kick();
+		// return;
+	} // End */
+
+	// if this swapitem call fails, then the server and client could be de-sync'd
+	if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
+		Message(0, "Client SwapItem request failure - verify inventory integrity.");
+
 	return;
 }
 
Index: zone/command.cpp
===================================================================
--- zone/command.cpp	(revision 2193)
+++ zone/command.cpp	(working copy)
@@ -456,7 +456,8 @@
         command_add("sensetrap", "Analog for ldon sense trap for the newer clients since we still don't have it working.", 0, command_sensetrap) ||
         command_add("picklock", "Analog for ldon pick lock for the newer clients since we still don't have it working.", 0, command_picklock) ||
 		command_add("mysql", "Mysql CLI, see 'help' for options.", 250, command_mysql) ||
-		command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) 
+		command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) ||
+		command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", 250, command_zopp)
 		)
 	{
 		command_deinit();
@@ -3035,15 +3036,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 		}
 	}
@@ -3055,15 +3058,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3072,17 +3077,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:instbag->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:instbag->GetCharges()));
 					}
 				}
 			}
@@ -3091,50 +3098,73 @@
 		{
 			const ItemInst* inst = client->GetInv().GetItem(9999);
 			item = (inst) ? inst->GetItem() : NULL;
-			c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", 9999,
+			c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", 9999,
 			((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-			((item==0)?"null":item->Name), 0x12);
+			((item==0)?"null":item->Name), 0x12,
+			((item==0)?0:inst->GetCharges()));
 		}
 	}
+
+	// Changed to show 'empty' cursors and not to show bag slots on 'queued' cursor slots (cursor bag slots 331 to 340 are not arrayed...)
+	// - was pointless to show bags on anything after slot 30[0], because it only repeated the 30[0] bag items.
 	if (bAll || (strcasecmp(sep->arg[1], "cursor")==0)) {
 		// Personal inventory items
 		bFound = true;
 		iter_queue it;
 		int i=0;
-		for(it=client->GetInv().cursor_begin();it!=client->GetInv().cursor_end();it++,i++) {
-			const ItemInst* inst = *it;
-			item = (inst) ? inst->GetItem() : NULL;
+
+		if(client->GetInv().CursorEmpty()) { // Display 'front' cursor slot even if 'empty' (item(30[0]) == null)
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", SLOT_CURSOR,i,
-					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+					0, 0x12, 0, "null", 0x12, 0);
 			}
 			else
 			{
-				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", SLOT_CURSOR,i,
-					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+					0, 0x12, 0, "null", 0x12, 0);
 			}
+		}
+		else {
+			for(it=client->GetInv().cursor_begin();it!=client->GetInv().cursor_end();it++,i++) {
+				const ItemInst* inst = *it;
+				item = (inst) ? inst->GetItem() : NULL;
+				if (c->GetClientVersion() >= EQClientSoF)
+				{
+					c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+						((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+						((item==0)?"null":item->Name), 0x12,
+						((item==0)?0:inst->GetCharges()));
+				}
+				else
+				{
+					c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+						((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+						((item==0)?"null":item->Name), 0x12,
+						((item==0)?0:inst->GetCharges()));
+				}
 			
-			if (inst && inst->IsType(ItemClassContainer)) {
-				for (uint8 j=0; j<10; j++) {
-					const ItemInst* instbag = client->GetInv().GetItem(SLOT_CURSOR, j);
-					item = (instbag) ? instbag->GetItem() : NULL;
-					if (c->GetClientVersion() >= EQClientSoF)
-					{
-						c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
-							Inventory::CalcSlotId(SLOT_CURSOR, j),
-							SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+				if (inst && inst->IsType(ItemClassContainer) && i==0) { // 'CSD 1' - only display contents of slot 30[0] container..higher ones don't exist
+					for (uint8 j=0; j<10; j++) {
+						const ItemInst* instbag = client->GetInv().GetItem(SLOT_CURSOR, j);
+						item = (instbag) ? instbag->GetItem() : NULL;
+						if (c->GetClientVersion() >= EQClientSoF)
+						{
+							c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
+								Inventory::CalcSlotId(SLOT_CURSOR, j),
+								SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+								((item==0)?"null":item->Name), 0x12,
+								((item==0)?0:instbag->GetCharges()));
+						}
+						else
+						{
+							c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
+								Inventory::CalcSlotId(SLOT_CURSOR, j),
+								SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+								((item==0)?"null":item->Name), 0x12,
+								((item==0)?0:instbag->GetCharges()));
+						}
 					}
-					else
-					{
-						c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
-							Inventory::CalcSlotId(SLOT_CURSOR, j),
-							SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
-					}
 				}
 			}
 		}
@@ -3148,15 +3178,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-			c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+			c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 		}
 	}
@@ -3170,15 +3202,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-			c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+			c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 				
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3187,17 +3221,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 				}
 			}
@@ -3207,15 +3243,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3224,17 +3262,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 				}
 			}
@@ -3248,15 +3288,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3265,17 +3307,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 				
 				}
@@ -3286,7 +3330,7 @@
 	if (!bFound)
 	{
 		c->Message(0, "Usage: #peekinv [worn|cursor|inv|bank|trade|trib|all]");
-		c->Message(0, "  Displays a portion of the targetted user's inventory");
+		c->Message(0, "  Displays a portion of the targeted user's inventory");
 		c->Message(0, "  Caution: 'all' is a lot of information!");
 	}
 }
@@ -3600,21 +3644,67 @@
 {
 	uint32 slot_id = atoi(sep->arg[1]);
 	if (sep->IsNumber(1) && (slot_id>=0) && (slot_id<=21)) {
-		const ItemInst* inst = c->GetInv().GetItem(SLOT_CURSOR);
-		if (inst && inst->IsType(ItemClassCommon)) {
+		const ItemInst* from_inst = c->GetInv().GetItem(SLOT_CURSOR);
+		const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
+		bool partialmove = false;
+		sint16 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		= SLOT_CURSOR;
 			mi->to_slot			= slot_id;
-			mi->number_in_stack	= inst->GetCharges();
+			// 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
-			c->SwapItem(mi);
-			c->FastQueuePacket(&outapp);
-			
+			// 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);
+
+				// 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 (sint16 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);
+
 			// @merth: also send out a wear change packet?
 		}
-		else if (inst == NULL)
+		else if (from_inst == NULL)
 			c->Message(13, "Error: There is no item on your cursor");
 		else
 			c->Message(13, "Error: Item on your cursor cannot be equipped");
@@ -3727,6 +3817,12 @@
 		else
 			c->Message(0, "Insufficient status to modify player corpse.");
 	}
+	else if (strcasecmp(sep->arg[1], "InspectLoot") == 0) {
+		if (target == 0 || !target->IsCorpse())
+			c->Message(0, "Error: Target must be a corpse.");
+		else
+			target->CastToCorpse()->QueryLoot(c);
+	}
 	else if (strcasecmp(sep->arg[1], "lock") == 0) {
 		if (target == 0 || !target->IsCorpse())
 			c->Message(0, "Error: Target must be a corpse.");
@@ -3777,6 +3873,7 @@
 		c->Message(0, "  Lock - GM locks the corpse - cannot be looted by non-GM");
 		c->Message(0, "  UnLock");
 		c->Message(0, "  RemoveCash");
+		c->Message(0, "  InspectLoot");
 		c->Message(0, "  [to remove items from corpses, loot them]");
 		c->Message(0, "Lead-GM status required to delete/modify player corpses");
 		c->Message(0, "  DeletePlayerCorpses");
@@ -11529,3 +11626,51 @@
 	else
 		t->ShowXTargets(c);
 }
+
+void command_zopp(Client *c, const Seperator *sep)
+{ // - Owner only command..non-targetable to eliminate malicious or mischievious activities.
+	if (!c)
+		return;
+	else if (sep->argnum < 3 || sep->argnum > 4)
+		c->Message(0, "Usage: #zopp [trade/summon] [slot id] [item id] [*charges]");
+	else if (!strcasecmp(sep->arg[1], "trade") == 0 && !strcasecmp(sep->arg[1], "t") == 0 && !strcasecmp(sep->arg[1], "summon") == 0 && !strcasecmp(sep->arg[1], "s") == 0)
+		c->Message(0, "Usage: #zopp [trade/summon] [slot id] [item id] [*charges]");
+	else if (!sep->IsNumber(2) || !sep->IsNumber(3) || (sep->argnum == 4 && !sep->IsNumber(4)))
+		c->Message(0, "Usage: #zopp [trade/summon] [slot id] [item id] [*charges]");
+	else {
+		ItemPacketType packettype;
+
+		if (strcasecmp(sep->arg[1], "trade") == 0 || strcasecmp(sep->arg[1], "t") == 0) {
+			packettype = ItemPacketTrade;
+		}
+		else {
+			packettype = ItemPacketSummonItem;
+		}
+
+		sint16 slotid = atoi(sep->arg[2]);
+		uint32 itemid = atoi(sep->arg[3]);
+		sint16 charges = sep->argnum == 4 ? atoi(sep->arg[4]) : 1; // defaults to 1 charge if not specified
+
+		const Item_Struct* FakeItem = database.GetItem(itemid);
+		
+		if (!FakeItem) {
+			c->Message(13, "Error: Item [%u] is not a valid item id.", itemid);
+			return;
+		}
+				
+		if (database.GetItemStatus(itemid) > c->Admin()) {
+			c->Message(13, "Error: Insufficient status to use this command.");
+			return;
+		}
+
+		if (charges < 0 || charges > FakeItem->StackSize) {
+			c->Message(13, "Warning: The specified charge count does not meet expected criteria!");
+			c->Message(0, "Processing request..results may cause unpredictable behavior.");
+		}
+
+		ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges);
+		c->SendItemPacket(slotid, FakeItemInst, packettype);
+		c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", packettype==ItemPacketTrade?"Trade":"Summon", FakeItem->Name, itemid, charges, abs(charges==1)?"charge":"charges", slotid);
+		safe_delete(FakeItemInst);
+	}
+}
\ No newline at end of file
Index: zone/command.h
===================================================================
--- zone/command.h	(revision 2193)
+++ zone/command.h	(working copy)
@@ -320,6 +320,7 @@
 void command_qtest(Client *c, const Seperator *sep);
 void command_mysql(Client *c, const Seperator *sep);
 void command_xtargets(Client *c, const Seperator *sep);
+void command_zopp(Client *c, const Seperator *sep);
 
 #ifdef EMBPERL
 void command_embperl_plugin(Client *c, const Seperator *sep);
Index: zone/forage.cpp
===================================================================
--- zone/forage.cpp	(revision 2193)
+++ zone/forage.cpp	(working copy)
@@ -358,7 +358,7 @@
 			}
 			else
 			{
-				PutItemInInventory(SLOT_CURSOR, *inst);
+				PushItemOnCursor(*inst); // changed from PutItemInInventory(SLOT_CURSOR, *inst); - was additional overhead
 				SendItemPacket(SLOT_CURSOR,inst,ItemPacketSummonItem);
 				if(RuleB(TaskSystem, EnableTaskSystem))
 					UpdateTasksForItem(ActivityFish, food_id);
Index: zone/inventory.cpp
===================================================================
--- zone/inventory.cpp	(revision 2193)
+++ zone/inventory.cpp	(working copy)
@@ -222,6 +222,14 @@
 				inst->SetCharges(1);
 			if ((inst->GetCharges()>0))
 				inst->SetCharges(inst->GetCharges());
+
+			// Added reduction of overcharged items to maximum stacksize
+			if ((inst->GetCharges()>inst->GetItem()->StackSize)) {
+				inst->SetCharges(inst->GetItem()->StackSize);
+				Message(0, "Your summoned item is charged beyond maximum allowable - adjusting to %i charges.", inst->GetCharges());
+			}
+
+			// Corrected the augment references to reflect augment name/id instead of base item name/id
 			if (aug1) {
 				const Item_Struct* augitem1 = database.GetItem(aug1);
 				if (augitem1) {
@@ -229,7 +237,7 @@
 						inst->PutAugment(&database, 0, aug1);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem1->Name, aug1);
 					}
 				}
 			}
@@ -240,7 +248,7 @@
 						inst->PutAugment(&database, 1, aug2);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem2->Name, aug2);
 					}
 				}
 			}
@@ -251,7 +259,7 @@
 						inst->PutAugment(&database, 2, aug3);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem3->Name, aug3);
 					}
 				}
 			}
@@ -262,7 +270,7 @@
 						inst->PutAugment(&database, 3, aug4);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem4->Name, aug4);
 					}
 				}
 			}
@@ -273,7 +281,7 @@
 						inst->PutAugment(&database, 4, aug5);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem5->Name, aug5);
 					}
 				}
 			}
@@ -397,9 +405,11 @@
 		LogFile->write(EQEMuLog::Debug, "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) {
+		if(client_update && IsValidSlot(slot_id)) {
 			EQApplicationPacket* outapp;
 			outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
 			DeleteItem_Struct* delitem	= (DeleteItem_Struct*)outapp->pBuffer;
@@ -427,23 +437,29 @@
 		    database.SaveInventory(character_id, inst, slot_id);
 	}
 
-	if(client_update) {
+	if(client_update && IsValidSlot(slot_id)) {
 		EQApplicationPacket* outapp;
 		if(inst) {
-			if(!inst->IsStackable() && !isDeleted) 
+			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);
+				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);
+
+				if (slot_id == SLOT_CURSOR) {
+					Message(13, "Server Warning! If you just received a MOVE ITEM FAILED IN CLIENT APPLICATION");
+					Message(13, "error message, then you will need to zone or relog to clear this problem.");
+					Message(0, "Do not perform any inventory actions until you do so or permanent item loss is possible.");
+				}
 		}
 		else {
 			outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
@@ -455,7 +471,6 @@
 			safe_delete(outapp);
 		}
 	}
-
 }
 
 // Puts an item into the person's inventory
@@ -1011,7 +1026,8 @@
 			move_in->from_slot = dst_slot_check;
 			move_in->to_slot = src_slot_check;
 			move_in->number_in_stack = dst_inst->GetCharges();
-			SwapItem(move_in);
+			if (!SwapItem(move_in)) // shouldn't fail because call wouldn't exist otherwise, but just in case...
+				this->Message(13, "Error: Internal SwapItem call returned a failure!");
 		}
 		Message(13, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
 		LogFile->write(EQEMuLog::Debug, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
@@ -1188,7 +1204,13 @@
 					mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) has %d (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, src_inst->GetCharges(), usedcharges);
 				}
 			} else {
-				//stack is full, so 
+				//stack is full, so
+
+				// there was no action taken here previously. any moveitem action would cause server to fail swapitem request, but
+				// the calling method still processed a success by continuing on to the end of the procedure. affected methods have
+				// been changed to conditional calls. needed to add this:
+				mlog(INVENTORY__ERROR, "Move from %d to %d with stack size %d. Exceeds dest maximum stack size: %d/%d", src_slot_id, dst_slot_id, move_in->number_in_stack, (src_inst->GetCharges()+dst_inst->GetCharges()), dst_inst->GetItem()->StackSize);
+				return false;
 			}
 		}
 		else {
@@ -1679,7 +1701,7 @@
 	Save();
 }
 
-void	Client::RemoveBandolier(const EQApplicationPacket *app) {
+void Client::RemoveBandolier(const EQApplicationPacket *app) {
 
 	// Delete bandolier with the specified number
 
@@ -1693,7 +1715,7 @@
 	Save();
 }
 
-void	Client::SetBandolier(const EQApplicationPacket *app) {
+void Client::SetBandolier(const EQApplicationPacket *app) {
 
 	// Swap the weapons in the given bandolier set into the character's weapon slots and return
 	// any items currently in the weapon slots to inventory.
@@ -1714,7 +1736,28 @@
 			// Check if the player has the item specified in the bandolier set on them.
 			//
 			slot = m_inv.HasItem(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id, 1, 
-					     invWhereWorn|invWherePersonal|invWhereCursor);
+					     invWhereWorn|invWherePersonal);
+
+			// removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here 
+			if (slot == SLOT_INVALID) {
+				if (m_inv.GetItem(SLOT_CURSOR)) {
+					if (m_inv.GetItem(SLOT_CURSOR)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
+						m_inv.GetItem(SLOT_CURSOR)->GetCharges() >= 1) // '> 0' the same, but this matches Inventory::_HasItem conditional check
+							slot = SLOT_CURSOR;
+					else if (m_inv.GetItem(SLOT_CURSOR)->GetItem()->ItemClass == 1) {
+						for(sint16 CursorBagSlot = 331; CursorBagSlot <= 340; CursorBagSlot++) {
+							if (m_inv.GetItem(CursorBagSlot)) {
+								if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
+									m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto
+										slot = CursorBagSlot;
+										break;
+								}
+							}
+						}
+					}
+				}
+			}
+
 			// if the player has this item in their inventory,
 			if(slot != SLOT_INVALID) {
 				// Pull the item out of the inventory
@@ -1842,7 +1885,7 @@
 	//
 	if(ItemToReturn->IsStackable()) {
 
-		for (sint16 i=22; i<=29; i++) {
+		for (sint16 i=22; i<=30; i++) { // changed slot max to 30 from 29. client will stack into slot 30 (bags too) before moving.
 
 			ItemInst* InvItem = m_inv.GetItem(i);
 
@@ -1905,7 +1948,7 @@
 
 	// We have tried stacking items, now just try and find an empty slot.
 
-	for (sint16 i=22; i<=29; i++) {
+	for (sint16 i=22; i<=30; i++) { // changed slot max to 30 from 29. client will move into slot 30 (bags too) before pushing onto cursor.
 
 		ItemInst* InvItem = m_inv.GetItem(i);
 
Index: zone/PlayerCorpse.cpp
===================================================================
--- zone/PlayerCorpse.cpp	(revision 2193)
+++ zone/PlayerCorpse.cpp	(working copy)
@@ -353,6 +353,8 @@
 		pp->gold = 0;
 		pp->platinum = 0;
 	
+		// 'RespawnFromHover = true' adversely affects client money removal. Server amount remains correct.
+
 		// get their tints
 		memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));
 	
@@ -367,23 +369,28 @@
 			item = client->GetInv().GetItem(i);
 			if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
 			{
-				MoveItemToCorpse(client, item, i);
-                removed_list.push_back(i);
+				removed_list.merge(MoveItemToCorpse(client, item, i));   
 			}
 		}
 
-		// cursor queue
-		iter_queue it;
-		for(it=client->GetInv().cursor_begin(),i=8000; it!=client->GetInv().cursor_end(); it++,i++) {
-			item = *it;
-			if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
-			{
-				MoveItemToCorpse(client, item, i);
-                cursor = true;
+		// cursor queue // change to first client that supports 'death hover' mode, if not SoF.
+		if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) {
+
+			// bumped starting assignment to 8001 because any in-memory 'slot 8000' item was moved above as 'slot 30'
+			// this was mainly for client profile state reflection..should match db player inventory entries now.
+			
+			iter_queue it;
+			for(it=client->GetInv().cursor_begin(),i=8001; it!=client->GetInv().cursor_end(); it++,i++) {
+				item = *it;
+				if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
+				{
+					removed_list.merge(MoveItemToCorpse(client, item, i));
+			        cursor = true;
+				}
 			}
 		}
 		
-        if(removed_list.size() != 0) {
+		if(removed_list.size() != 0) {
             std::stringstream ss("");
             ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
             ss << " AND (";
@@ -401,14 +408,18 @@
             ss << ")";
             database.RunQuery(ss.str().c_str(), ss.str().length());
         }
-        
-        if(cursor) {
-            std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
-            std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
-            database.SaveCursor(client->CharacterID(), 
-                start, finish);
+
+        if(cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false)
+			while(!client->GetInv().CursorEmpty())
+					client->DeleteItemInInventory(SLOT_CURSOR, 0, false, false);           
         }
+		else { // only visible cursor made it to corpse (client >= Sof and RespawnFromHover = true)
+			std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
+			std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
+			database.SaveCursor(client->CharacterID(), start, finish);
+		}
 
+		// client->CalcBonuses(); // will only affect offline profile viewing of dead characters..unneeded overhead
 		client->Save();
 	} //end "not leaving naked corpses"
 	
@@ -417,28 +428,35 @@
 }
 
 // solar: helper function for client corpse constructor
-void Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
+std::list<uint32> Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
 {
 	int bagindex;
 	sint16 interior_slot;
 	ItemInst *interior_item;
+	std::list<uint32> returnlist;
 
 	AddItem(item->GetItem()->ID, item->GetCharges(), equipslot, item->GetAugmentItemID(0), item->GetAugmentItemID(1), item->GetAugmentItemID(2), item->GetAugmentItemID(3), item->GetAugmentItemID(4));
-	if(item->IsType(ItemClassContainer))
+	returnlist.push_back(equipslot);
+
+	// Qualified bag slot iterations. processing bag slots that don't exist is probably not a good idea.
+	if(item->IsType(ItemClassContainer) && ((equipslot >= 22 && equipslot <=30))) // Limit the bag check to inventory and cursor slots.
 	{
 		for(bagindex = 0; bagindex <= 10; bagindex++)
 		{
+			// For empty bags in cursor queue, slot was previously being resolved as SLOT_INVALID (-1)
 			interior_slot = Inventory::CalcSlotId(equipslot, bagindex);
 			interior_item = client->GetInv().GetItem(interior_slot);
 
 			if(interior_item)
 			{
 				AddItem(interior_item->GetItem()->ID, interior_item->GetCharges(), interior_slot, interior_item->GetAugmentItemID(0), interior_item->GetAugmentItemID(1), interior_item->GetAugmentItemID(2), interior_item->GetAugmentItemID(3), interior_item->GetAugmentItemID(4));
+				returnlist.push_back(Inventory::CalcSlotId(equipslot, bagindex));
 				client->DeleteItemInInventory(interior_slot, 0, true, false);
 			}
 		}
 	}
 	client->DeleteItemInInventory(equipslot, 0, true, false);
+	return returnlist;
 }
 
 // To be called from LoadFromDBData
@@ -981,19 +999,41 @@
 		ItemList::iterator cur,end;
 		cur = itemlist.begin();
 		end = itemlist.end();
+
+		int corpselootlimit = 30; // 30 is the original value // con check value in QueryLoot needs to reflect this value
+		
+		/* need actual corpse limit values per client (or client range)..if always 30, then these con checks are unneeded
+		// enumeration shouldn't be needed unless someone finds a use for this info elsewhere
+		
+		if (client->GetClientVersion()>=EQClientVoA)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientHoT)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientUnderfoot)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientSoD)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientSoF) // SoF has 32 visible slots..change untested
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientTitanium)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClient62)
+			corpselootlimit=30;
+		else
+			corpselootlimit=30; // */
+
 		for(; cur != end; cur++) {
 			ServerLootItem_Struct* item_data = *cur;
 			item_data->lootslot = 0xFFFF;
+			
+			// Dont display the item if it's in a bag
 
-			// Dont display the item if it's in a bag
-			if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3)
+			// Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse.
+			if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3 ||
+				(item_data->equipSlot >= 8000 && item_data->equipSlot <= 8999))
 			{
-				if (i >= 30)
+				if (i < corpselootlimit) // < 30 (0 - 29) 
 				{
-						Message(13, "Warning: Too many items to display. Loot some then re-loot the corpse to see the rest");
-				}
-				else
-				{
 					item = database.GetItem(item_data->item_id);
 					if (client && item)
 					{
@@ -1006,9 +1046,24 @@
 						item_data->lootslot = i;
 					}
 				}
+				else if (i == corpselootlimit) // = 30
+				{
+					client->Message(13, "*** This corpse contains more items than can be displayed! ***");
+					client->Message(0, "Remove items and re-loot corpse to access remaining inventory.");
+				}
 				i++;
 			}
 		}
+		if (i > corpselootlimit) // > 30 (remember 'i' is increased again after the last iteration, so no '=')
+			client->Message(0, "(%s contains %i additional %s.)", GetName(), (i-corpselootlimit), (i-corpselootlimit)==1?"item":"items");
+
+		if (IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, corpse contains items, but client doesn't see them...
+			client->Message(13, "This corpse contains items that you do not have permission to access!");
+			client->Message(0, "Contact a GM for assistance to see if item replacement is necessary.");
+			client->Message(0, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetDBID(), GetName(), itemlist.size());
+			// if needed/wanted - create log dump->iterate corpse list..need pointer to log file
+			// could add code to check for owning client and give list of bugged items on corpse
+		}
 	}
 	
 	// Disgrace: Client seems to require that we send the packet back...
@@ -1296,7 +1351,7 @@
 }
 
 void Corpse::QueryLoot(Client* to) {
-	int x = 0;
+	int x = 0, y = 0; // x = visible items, y = total items
 	to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper);
 
 	ItemList::iterator cur,end;
@@ -1304,14 +1359,44 @@
 	end = itemlist.end();
 	for(; cur != end; cur++) {
 		ServerLootItem_Struct* sitem = *cur;
-		const Item_Struct* item = database.GetItem(sitem->item_id);
-		if (item)
-			to->Message(0, "  %d: %s", item->ID, item->Name);
-		else
-			to->Message(0, "  Error: 0x%04x", sitem->item_id);
-		x++;
+
+		if (IsPlayerCorpse()) {
+			if (sitem->equipSlot >= 251 && sitem->equipSlot <= 340)
+				sitem->lootslot = 0xFFFF;
+			else
+				x < 30 ? sitem->lootslot = x : sitem->lootslot = 0xFFFF; // this con value needs to reflect corpselootlimit in MakeLootRequestPackets
+			
+			const Item_Struct* item = database.GetItem(sitem->item_id);
+
+			if (item)
+				to->Message((sitem->lootslot == 0xFFFF), "  LootSlot: %i (EquipSlot: %i) Item: %s (%d) with %i %s", sitem->lootslot, sitem->equipSlot, item->Name, item->ID, sitem->charges, sitem->charges==1?"charge":"charges");
+			else
+				to->Message((sitem->lootslot == 0xFFFF), "  Error: 0x%04x", sitem->item_id);
+			
+			if (sitem->lootslot != 0xFFFF)
+				x++;
+
+			y++;
+		}
+		else {
+			sitem->lootslot=y;
+			const Item_Struct* item = database.GetItem(sitem->item_id);
+			
+			if (item)
+				to->Message(0, "  LootSlot: %i Item: %s (%d) with %i %s", sitem->lootslot, item->Name, item->ID, sitem->charges, sitem->charges==1?"charge":"charges");
+			else
+				to->Message(0, "  Error: 0x%04x", sitem->item_id);
+
+			y++;
+		}
 	}
-	to->Message(0, "%i items on %s.", x, this->GetName());
+
+	if (IsPlayerCorpse()) {
+		to->Message(0, "%i visible %s (%i total) on %s (DBID: %i).", x, x==1?"item":"items", y, this->GetName(), this->GetDBID());
+	}
+	else {
+		to->Message(0, "%i %s on %s.", y, y==1?"item":"items", this->GetName());
+	}
 }
 
 bool Corpse::Summon(Client* client, bool spell, bool CheckDistance)
Index: zone/PlayerCorpse.h
===================================================================
--- zone/PlayerCorpse.h	(revision 2193)
+++ zone/PlayerCorpse.h	(working copy)
@@ -111,7 +111,7 @@
 	inline int GetRezzExp() { return rezzexp; }
 
 protected:
-	void MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot);
+	std::list<uint32> MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot);
 
 private:
 	bool		p_PlayerCorpse;
(I went with 'Lime' headers this time so that wolfwalkereci can read them easier on his default layout )

Change to Client::SetBandolier
The weapon search portion will no longer check the 8000-series of cursor slots. An item could be found and removed on the server, but the client
would not remove the correct item. It would only remove the 'front' cursor item at best. This and C::MITI below were a source of not only de-sync's,
but also 'non-equipped' weapon combat/skill-ups (technically, any de-sync can cause this) and illegal slot equipment (i.e., containers in the weapon
slots.)
(IF a player has become de-sync'd previously, item deletion issues will still arise, just like any item movement with a de-sync'd inventory, but the
bandolier should not cause de-sync's any longer. Test it before you trust it.)

Change to Client::MoveItemToInventory
Increased the slot range check to include cursor (slot 30) and cursor bags (slots 331 - 340.) The client behaves in this manner, but the server did not
match and additional de-sync's were occuring.

(Bandolier testing was performed with as many weapon-type combinations as possible and observations were made to server memory,
database and client states after each swap. Multiple-fast swaps did not induce de-sync's on my server, but public servers with higher ping rates may
still incurr problems..DO NOT RAPIDLY SWAP YOUR BANDOLIER ITEMS! This can't be timered since the client-side move action is accomplished by the
client itself.
)

Change to #equipitem
Non-stackable items were processed correctly when the designated slot was already occupied. However, with stackable items, the swapitem call would
only perform a partial stack move and the stack count on the client would exceed item->stacksize. Added code that will eventually allow partial stack
movement..if someone can figure out the proper client cursor update method. If any quantity will remain on cursor, the procedure is cancelled to avoid
these issues. Notes are in-place on what to do if a solution is found (deletion of the 'partialmove' con check and changing values in the 'outapp2'
EQApplicationPacket data, where the problem lies.) As it is coded in this patch, no de-sync's should occur.

Change to Client::SwapItem
Charge moving to a full stack had no corrective action, only this remark - "//stack is full, so." If this condition were ever true, the swap would not
occur, but the calling method would still process as if it had (#equipitem seems to be the only calling procedure where this could be true. The client
doesn't appear to send item swap requests in this case.) Another source of de-syncs. Also, added code to all calling procedures (command_equipitem,
Client::Handle_OP_MoveItem, and Client::SwapItem) to process the return of these calls..no more 'blind' calls.

Change to Client::GoFish
Previously, the procedure called PutItemInInventory(SLOT_CURSOR, Item)->PushItemOnCursor(Item). Changed it to directly call PushItemOnCursor(Item)
to eliminate unneeded overhead.
(ForageItem already does this.)

Update to Client:eleteItemInInventory
Added a SLOT_CURSOR check inside of delete stackable quantity code to notify client of a possible de-sync condition. This code will fire regardless of
quantity moved. Normal client operations do not appear to trigger this message, but it could arise from scripted/quest processes. The basis of this goes
back to #equipitem cursor charge deletion problem. (The deletion code was copied from this procedure.)
(Quest collection doesn't appear to include cursor/cursor bag slots, so the likely-hood of this message appearing is minimial. Data should be collected on
any activity that does trigger this since it could be a source of de-sync's.)

Update to Client::Handle_OP_MoveItem
This was discussed in the Client::SwapItem notes. The client will receive a message in the case of a server-side swap failure. This does not mean a true
de-sync always exists, but the client should be made aware that the condition could exist and that they should take immediate corrective action to avoid
item loss.
(This and the above message in C:III should catch alot of de-sync cases and notify the player that they are, or could be, bugged.)

Update to #Corpse::QueryLoot
Added charge counts to aid in troubleshooting. Changed to display two item counts - 'total' and 'visible' - to aid in discerning what the player is able to
see when they loot their corpse (they don't see in-container items, only the container itself.) Visible item count only affects player corpses.

Update to #zopp
You can now specify the packet type as 'PacketTypeSummonItem' (summon/s) or 'PackTypeTrade' (trade/t.) Was previously hard-coded as 'trade.'
(With a little experience, you can actually correct de-sync's with this..on yourself.)


Some of these updates were added in the 'Bugged Corpse' patch, but they were either not annotated or have since been re-updated.

[Note: I've seen some suggestions to take tradeskilling results and combine multiple-issue items into a single item with multiple charges. This could be
easily done with a result re-iteration, but it is HIGHLY recommended against for now. If a multi-charge item is found for a combine in slot 30, the same
issues described in the #equipitem notes will likely give rise to a whole new set of problems. I still believe that a mis-placement in the order of client
cursor items is the result of UDP packet arrival time..missing items could be a result of the client ignoring 'late' packet arrivals, multiple packets with the
same time-stamp, or lost packets. Packet collection on the emu could probably verify this when the condition is identified.]

It's still possible there are many conditions that will lead to CSD's, but hopefully there is enough in this patch to correct some and help identify others.


Again, this will probably be my last submission for awhile, but I will still be around to troubleshoot any issues that I may have missed or mis-coded.
__________________
Uleat of Bertoxxulous

Compilin' Dirty

Last edited by cavedude; 09-13-2012 at 01:48 PM..
Reply With Quote
  #2  
Old 08-24-2012, 09:21 AM
wolfwalkereci
Discordant
 
Join Date: Dec 2005
Posts: 435
Default

Quote:
(I went with 'Lime' headers this time so that wolfwalkereci can read them easier on his default layout )
You know I love your posts Just got a minute to read what new and interesting stuff you put together.
Reply With Quote
  #3  
Old 08-28-2012, 04:59 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Ok, Cavedude brought to my attention that this will not compile on Linux.

Since I can't test on a Linux system, I was wondering if someone with knowledge could give me a pointer as to what isn't right about this.

Code:
Corpse::Corpse(Client* client, sint32 in_rezexp)
{...

	std::list<uint32> removed_list;

	...
		removed_list.merge(MoveItemToCorpse(client, item, i));

	...
		removed_list.merge(MoveItemToCorpse(client, item, i));

...}

std::list<uint32> Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
{...

	std::list<uint32> returnlist;

	...
	return returnlist;
}

Obviously, the first function calls the second one for the return list to merge.

Problem is, the compiler is kicking back a 'no matching function for call to std::list<unsigned int>::merge(std::list<unsigned int>)' for both merge calls.

Removed_list is not used between its definition and the first merge call.


I did change the return type for 'MoveItemToCorpse' in the header file..and it does compile and work correctly in windows.


Could it be one of these? (Or something else entirely?)

- Lack of an '#include' or 'using namespace' in the *.h file (because of return type change from uint32)
- The 'removed_list' is defined, but not initiated
- A 'list.merge()' argument can't be a function even though the return type is valid


I am googling this...
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #4  
Old 08-28-2012, 09:01 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

My guess...

The list returned from MoveItemToCorpse is a temporary since it isn't being assigned to anything, and a temporary can't bind to the non-const reference that merge takes as a parameter.

To fix it, assign the temporary to a local variable and pass that to merge.

I'd also guess that Visual Studio may be warning about a non-standard extension there, but it's lost in the sea of other warnings in the project. It may also only show up at warning level 4. The error may also be different in debug versus release since that might change any elided copies from the return.
Reply With Quote
  #5  
Old 08-28-2012, 09:24 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

Looks like there's a warning at level 4 in Visual Studio 2008, but not at level 3.

Code:
#include <list>

typedef std::list<int> IntList;

IntList DoSomething()
{
	IntList RetVal;
	return RetVal;
}

int main()
{
	IntList List;
	List.merge( DoSomething() );
	return 0;
}
Code:
warning C4239: nonstandard extension used : 'argument' : conversion from 'IntList' to 'std::list<_Ty> &'
        with
        [
            _Ty=int
        ]
        A non-const reference may only be bound to an lvalue
Reply With Quote
  #6  
Old 08-28-2012, 10:13 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Thank you Lerxst! You guys tolerate my ignorance pretty well. (I'm too reliant on Intellisense...)

I'll pass along a fix to Cavedude when I get back online tomorrow.
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #7  
Old 08-29-2012, 01:41 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Ok, I passed on the fix and hopefully that will do it.

I understand exactly what you were saying Lerxst. But, I guess that's what happens when you use a non-ISO compliant c/c++ compiler...


As far as VS... I set the level to 4 in VS10 (Express) and it still did not kick out a message about this particular binding issue.

Do you guys know of any 'free' compilers for windows that should be as good as what the Linux guys use? I'll likely still use VS for everything, but do a test build
on this to double-check it. (I think I saw some at sourceforge..otherwise I don't think that my Borland c++ 5.0 complier is going to get me very far...)
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #8  
Old 08-29-2012, 01:55 PM
demonstar55
Demi-God
 
Join Date: Apr 2008
Location: MA
Posts: 1,164
Default

Could always make a Linux VM for testing if it compiles at least. Virtual box should be good enough.
Reply With Quote
  #9  
Old 08-29-2012, 02:15 PM
lerxst2112
Demi-God
 
Join Date: Aug 2010
Posts: 1,742
Default

There's nothing wrong with Visual Studio, and if you wish you can turn extensions off although it is generally not worth it to do so. If you need code to compile on two different platforms, the only way to be sure is to actually compile it on both. A VM, as suggested, is a simple way to do this. You can also use GCC on Windows, but IMO it's a pain to setup and Visual Studio does everything I need.

The warning I saw was in Visual Studio 2008. 2010 supports some of the newer standard, and it may support rvalue references which may make that code correct. GCC also supports much of the latest standard, but it requires additional compile flags which are probably not present in the standard makefiles.
Reply With Quote
  #10  
Old 08-29-2012, 03:50 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Ok, thanks you two!

I'm going to have to give up my 'borrowed' server computer soon anyways, so I may look at the VM when I set up the server on my computer.


I do have VC 2008 installed, so I may try the compiles in it to help minimize issues until I can get a VM up and running.
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #11  
Old 09-01-2012, 12:35 AM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Here is the fix to PlayerCorpse.cpp that corrects the Linux build issue. It also adds a fix that keeps a player's money from transferring to their corpse when
they die with 'RespawnFromHover=true.' (I had a note in place, but missed actually inserting the code.)

Currently, TGC is testing this code out, so it may make the SVN at some point. This patch is only for those who update their code independently and would like
the fix.

It is a direct replacement for the PlayerCorpse.cpp portion of the above patch, once it has been applied. Just 'revert' PlayerCorpse.cpp and apply this patch.

[PlayerCorpse.cpp.patch]
Code:
Index: zone/client_packet.cpp
===================================================================
--- zone/client_packet.cpp	(revision 2193)
+++ zone/client_packet.cpp	(working copy)
@@ -3310,7 +3310,59 @@
 			return;
 		}
 	}
-	SwapItem(mi);
+
+	// Added checks for illegal bagslot swaps..should help with certain cheats (currently checks personal and cursor bag slots.)
+	// - If a player has used an illegal inventory cheat, they can become bugged at some point (especially concerning lore items.)
+	//* Start
+	bool mi_hack = false;
+
+	if (mi->from_slot >= 251 && mi->from_slot <= 340) {
+		if (mi->from_slot > 330)
+			mi_hack = true; // why are we moving from a cursor bagslot when you can't open it?
+		else {			
+			sint16 from_invslot = Inventory::CalcSlotId(mi->from_slot);
+			const ItemInst *from_invslotitem = GetInv().GetItem(from_invslot); 
+
+			if (!from_invslotitem) // trying to move from bag slots when parent inventory slot is empty
+				mi_hack = true;
+			else if (from_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
+				if ((Inventory::CalcBagIdx(mi->from_slot) + 1) > from_invslotitem->GetItem()->BagSlots)
+					mi_hack = true; // trying to move from slots beyond parent container size
+			}
+			else // trying to move from bag slots when inventory slot item is not a container
+				mi_hack = true;
+		}
+	}
+
+	if (mi->to_slot >= 251 && mi->to_slot <= 340) {
+		if (mi->to_slot > 330)
+			mi_hack = true; // why are we moving to a cursor bagslot when you can't open it?
+		else {
+			sint16 to_invslot = Inventory::CalcSlotId(mi->to_slot);
+			const ItemInst *to_invslotitem = GetInv().GetItem(to_invslot);
+
+			if (!to_invslotitem) // trying to move into bag slots when parent inventory slot is empty
+				mi_hack = true;
+			else if (to_invslotitem->GetItem()->ItemClass == 1) { // checking the parent inventory slot for container
+				if ((Inventory::CalcBagIdx(mi->to_slot) + 1) > to_invslotitem->GetItem()->BagSlots)
+					mi_hack = true; // trying to move into slots beyond parent container size
+			}
+			else // trying to move into bag slots when inventory slot item is not a container
+				mi_hack = true;
+		}
+	}
+
+	if (mi_hack) { // a CSD can also cause this condition, but more likely the use of a cheat
+		Message(13, "Hack detected: Illegal use of inventory bag slots!");
+		// TODO: Decide whether to log player as hacker - currently has no teeth...
+		// Kick();
+		// return;
+	} // End */
+
+	// if this swapitem call fails, then the server and client could be de-sync'd
+	if (!SwapItem(mi) && IsValidSlot(mi->from_slot) && IsValidSlot(mi->to_slot))
+		Message(0, "Client SwapItem request failure - verify inventory integrity.");
+
 	return;
 }
 
Index: zone/command.cpp
===================================================================
--- zone/command.cpp	(revision 2193)
+++ zone/command.cpp	(working copy)
@@ -456,7 +456,8 @@
         command_add("sensetrap", "Analog for ldon sense trap for the newer clients since we still don't have it working.", 0, command_sensetrap) ||
         command_add("picklock", "Analog for ldon pick lock for the newer clients since we still don't have it working.", 0, command_picklock) ||
 		command_add("mysql", "Mysql CLI, see 'help' for options.", 250, command_mysql) ||
-		command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) 
+		command_add("xtargets", "Show your targets Extended Targets and optionally set how many xtargets they can have.", 250, command_xtargets) ||
+		command_add("zopp", "Troubleshooting command - Sends a fake item packet to you. No server reference is created.", 250, command_zopp)
 		)
 	{
 		command_deinit();
@@ -3035,15 +3036,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "WornSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 		}
 	}
@@ -3055,15 +3058,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3072,17 +3077,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:instbag->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   InvBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:instbag->GetCharges()));
 					}
 				}
 			}
@@ -3091,50 +3098,73 @@
 		{
 			const ItemInst* inst = client->GetInv().GetItem(9999);
 			item = (inst) ? inst->GetItem() : NULL;
-			c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", 9999,
+			c->Message((item==0), "InvSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", 9999,
 			((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-			((item==0)?"null":item->Name), 0x12);
+			((item==0)?"null":item->Name), 0x12,
+			((item==0)?0:inst->GetCharges()));
 		}
 	}
+
+	// Changed to show 'empty' cursors and not to show bag slots on 'queued' cursor slots (cursor bag slots 331 to 340 are not arrayed...)
+	// - was pointless to show bags on anything after slot 30[0], because it only repeated the 30[0] bag items.
 	if (bAll || (strcasecmp(sep->arg[1], "cursor")==0)) {
 		// Personal inventory items
 		bFound = true;
 		iter_queue it;
 		int i=0;
-		for(it=client->GetInv().cursor_begin();it!=client->GetInv().cursor_end();it++,i++) {
-			const ItemInst* inst = *it;
-			item = (inst) ? inst->GetItem() : NULL;
+
+		if(client->GetInv().CursorEmpty()) { // Display 'front' cursor slot even if 'empty' (item(30[0]) == null)
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", SLOT_CURSOR,i,
-					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+					0, 0x12, 0, "null", 0x12, 0);
 			}
 			else
 			{
-				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", SLOT_CURSOR,i,
-					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+				c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+					0, 0x12, 0, "null", 0x12, 0);
 			}
+		}
+		else {
+			for(it=client->GetInv().cursor_begin();it!=client->GetInv().cursor_end();it++,i++) {
+				const ItemInst* inst = *it;
+				item = (inst) ? inst->GetItem() : NULL;
+				if (c->GetClientVersion() >= EQClientSoF)
+				{
+					c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+						((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+						((item==0)?"null":item->Name), 0x12,
+						((item==0)?0:inst->GetCharges()));
+				}
+				else
+				{
+					c->Message((item==0), "CursorSlot: %i, Depth: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", SLOT_CURSOR,i,
+						((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+						((item==0)?"null":item->Name), 0x12,
+						((item==0)?0:inst->GetCharges()));
+				}
 			
-			if (inst && inst->IsType(ItemClassContainer)) {
-				for (uint8 j=0; j<10; j++) {
-					const ItemInst* instbag = client->GetInv().GetItem(SLOT_CURSOR, j);
-					item = (instbag) ? instbag->GetItem() : NULL;
-					if (c->GetClientVersion() >= EQClientSoF)
-					{
-						c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
-							Inventory::CalcSlotId(SLOT_CURSOR, j),
-							SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+				if (inst && inst->IsType(ItemClassContainer) && i==0) { // 'CSD 1' - only display contents of slot 30[0] container..higher ones don't exist
+					for (uint8 j=0; j<10; j++) {
+						const ItemInst* instbag = client->GetInv().GetItem(SLOT_CURSOR, j);
+						item = (instbag) ? instbag->GetItem() : NULL;
+						if (c->GetClientVersion() >= EQClientSoF)
+						{
+							c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
+								Inventory::CalcSlotId(SLOT_CURSOR, j),
+								SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+								((item==0)?"null":item->Name), 0x12,
+								((item==0)?0:instbag->GetCharges()));
+						}
+						else
+						{
+							c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
+								Inventory::CalcSlotId(SLOT_CURSOR, j),
+								SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
+								((item==0)?"null":item->Name), 0x12,
+								((item==0)?0:instbag->GetCharges()));
+						}
 					}
-					else
-					{
-						c->Message((item==0), "   CursorBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
-							Inventory::CalcSlotId(SLOT_CURSOR, j),
-							SLOT_CURSOR, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
-					}
 				}
 			}
 		}
@@ -3148,15 +3178,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-			c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+			c->Message((item==0), "TributeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 		}
 	}
@@ -3170,15 +3202,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-			c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+			c->Message((item==0), "BankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 				((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-				((item==0)?"null":item->Name), 0x12);
+				((item==0)?"null":item->Name), 0x12,
+				((item==0)?0:inst->GetCharges()));
 			}
 				
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3187,17 +3221,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   BankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 				}
 			}
@@ -3207,15 +3243,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "ShBankSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3224,17 +3262,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   ShBankBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 				}
 			}
@@ -3248,15 +3288,17 @@
 			item = (inst) ? inst->GetItem() : NULL;
 			if (c->GetClientVersion() >= EQClientSoF)
 			{
-				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			else
 			{
-				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c)", i,
+				c->Message((item==0), "TradeSlot: %i, Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i", i,
 					((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-					((item==0)?"null":item->Name), 0x12);
+					((item==0)?"null":item->Name), 0x12,
+					((item==0)?0:inst->GetCharges()));
 			}
 			
 			if (inst && inst->IsType(ItemClassContainer)) {
@@ -3265,17 +3307,19 @@
 					item = (instbag) ? instbag->GetItem() : NULL;
 					if (c->GetClientVersion() >= EQClientSoF)
 					{
-						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X00000000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 					else
 					{
-						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c)",
+						c->Message((item==0), "   TradeBagSlot: %i (Slot #%i, Bag #%i), Item: %i (%c%06X000000000000000000000000000000000000000%s%c), Charges: %i",
 							Inventory::CalcSlotId(i, j),
 							i, j, ((item==0)?0:item->ID),0x12, ((item==0)?0:item->ID),
-							((item==0)?"null":item->Name), 0x12);
+							((item==0)?"null":item->Name), 0x12,
+							((item==0)?0:inst->GetCharges()));
 					}
 				
 				}
@@ -3286,7 +3330,7 @@
 	if (!bFound)
 	{
 		c->Message(0, "Usage: #peekinv [worn|cursor|inv|bank|trade|trib|all]");
-		c->Message(0, "  Displays a portion of the targetted user's inventory");
+		c->Message(0, "  Displays a portion of the targeted user's inventory");
 		c->Message(0, "  Caution: 'all' is a lot of information!");
 	}
 }
@@ -3600,21 +3644,67 @@
 {
 	uint32 slot_id = atoi(sep->arg[1]);
 	if (sep->IsNumber(1) && (slot_id>=0) && (slot_id<=21)) {
-		const ItemInst* inst = c->GetInv().GetItem(SLOT_CURSOR);
-		if (inst && inst->IsType(ItemClassCommon)) {
+		const ItemInst* from_inst = c->GetInv().GetItem(SLOT_CURSOR);
+		const ItemInst* to_inst = c->GetInv().GetItem(slot_id); // added (desync issue when forcing stack to stack)
+		bool partialmove = false;
+		sint16 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		= SLOT_CURSOR;
 			mi->to_slot			= slot_id;
-			mi->number_in_stack	= inst->GetCharges();
+			// 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
-			c->SwapItem(mi);
-			c->FastQueuePacket(&outapp);
-			
+			// 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);
+
+				// 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 (sint16 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);
+
 			// @merth: also send out a wear change packet?
 		}
-		else if (inst == NULL)
+		else if (from_inst == NULL)
 			c->Message(13, "Error: There is no item on your cursor");
 		else
 			c->Message(13, "Error: Item on your cursor cannot be equipped");
@@ -3727,6 +3817,12 @@
 		else
 			c->Message(0, "Insufficient status to modify player corpse.");
 	}
+	else if (strcasecmp(sep->arg[1], "InspectLoot") == 0) {
+		if (target == 0 || !target->IsCorpse())
+			c->Message(0, "Error: Target must be a corpse.");
+		else
+			target->CastToCorpse()->QueryLoot(c);
+	}
 	else if (strcasecmp(sep->arg[1], "lock") == 0) {
 		if (target == 0 || !target->IsCorpse())
 			c->Message(0, "Error: Target must be a corpse.");
@@ -3777,6 +3873,7 @@
 		c->Message(0, "  Lock - GM locks the corpse - cannot be looted by non-GM");
 		c->Message(0, "  UnLock");
 		c->Message(0, "  RemoveCash");
+		c->Message(0, "  InspectLoot");
 		c->Message(0, "  [to remove items from corpses, loot them]");
 		c->Message(0, "Lead-GM status required to delete/modify player corpses");
 		c->Message(0, "  DeletePlayerCorpses");
@@ -11529,3 +11626,51 @@
 	else
 		t->ShowXTargets(c);
 }
+
+void command_zopp(Client *c, const Seperator *sep)
+{ // - Owner only command..non-targetable to eliminate malicious or mischievious activities.
+	if (!c)
+		return;
+	else if (sep->argnum < 3 || sep->argnum > 4)
+		c->Message(0, "Usage: #zopp [trade/summon] [slot id] [item id] [*charges]");
+	else if (!strcasecmp(sep->arg[1], "trade") == 0 && !strcasecmp(sep->arg[1], "t") == 0 && !strcasecmp(sep->arg[1], "summon") == 0 && !strcasecmp(sep->arg[1], "s") == 0)
+		c->Message(0, "Usage: #zopp [trade/summon] [slot id] [item id] [*charges]");
+	else if (!sep->IsNumber(2) || !sep->IsNumber(3) || (sep->argnum == 4 && !sep->IsNumber(4)))
+		c->Message(0, "Usage: #zopp [trade/summon] [slot id] [item id] [*charges]");
+	else {
+		ItemPacketType packettype;
+
+		if (strcasecmp(sep->arg[1], "trade") == 0 || strcasecmp(sep->arg[1], "t") == 0) {
+			packettype = ItemPacketTrade;
+		}
+		else {
+			packettype = ItemPacketSummonItem;
+		}
+
+		sint16 slotid = atoi(sep->arg[2]);
+		uint32 itemid = atoi(sep->arg[3]);
+		sint16 charges = sep->argnum == 4 ? atoi(sep->arg[4]) : 1; // defaults to 1 charge if not specified
+
+		const Item_Struct* FakeItem = database.GetItem(itemid);
+		
+		if (!FakeItem) {
+			c->Message(13, "Error: Item [%u] is not a valid item id.", itemid);
+			return;
+		}
+				
+		if (database.GetItemStatus(itemid) > c->Admin()) {
+			c->Message(13, "Error: Insufficient status to use this command.");
+			return;
+		}
+
+		if (charges < 0 || charges > FakeItem->StackSize) {
+			c->Message(13, "Warning: The specified charge count does not meet expected criteria!");
+			c->Message(0, "Processing request..results may cause unpredictable behavior.");
+		}
+
+		ItemInst* FakeItemInst = database.CreateItem(FakeItem, charges);
+		c->SendItemPacket(slotid, FakeItemInst, packettype);
+		c->Message(0, "Sending zephyr op packet to client - [%s] %s (%u) with %i %s to slot %i.", packettype==ItemPacketTrade?"Trade":"Summon", FakeItem->Name, itemid, charges, abs(charges==1)?"charge":"charges", slotid);
+		safe_delete(FakeItemInst);
+	}
+}
\ No newline at end of file
Index: zone/command.h
===================================================================
--- zone/command.h	(revision 2193)
+++ zone/command.h	(working copy)
@@ -320,6 +320,7 @@
 void command_qtest(Client *c, const Seperator *sep);
 void command_mysql(Client *c, const Seperator *sep);
 void command_xtargets(Client *c, const Seperator *sep);
+void command_zopp(Client *c, const Seperator *sep);
 
 #ifdef EMBPERL
 void command_embperl_plugin(Client *c, const Seperator *sep);
Index: zone/forage.cpp
===================================================================
--- zone/forage.cpp	(revision 2193)
+++ zone/forage.cpp	(working copy)
@@ -358,7 +358,7 @@
 			}
 			else
 			{
-				PutItemInInventory(SLOT_CURSOR, *inst);
+				PushItemOnCursor(*inst); // changed from PutItemInInventory(SLOT_CURSOR, *inst); - was additional overhead
 				SendItemPacket(SLOT_CURSOR,inst,ItemPacketSummonItem);
 				if(RuleB(TaskSystem, EnableTaskSystem))
 					UpdateTasksForItem(ActivityFish, food_id);
Index: zone/inventory.cpp
===================================================================
--- zone/inventory.cpp	(revision 2193)
+++ zone/inventory.cpp	(working copy)
@@ -222,6 +222,14 @@
 				inst->SetCharges(1);
 			if ((inst->GetCharges()>0))
 				inst->SetCharges(inst->GetCharges());
+
+			// Added reduction of overcharged items to maximum stacksize
+			if ((inst->GetCharges()>inst->GetItem()->StackSize)) {
+				inst->SetCharges(inst->GetItem()->StackSize);
+				Message(0, "Your summoned item is charged beyond maximum allowable - adjusting to %i charges.", inst->GetCharges());
+			}
+
+			// Corrected the augment references to reflect augment name/id instead of base item name/id
 			if (aug1) {
 				const Item_Struct* augitem1 = database.GetItem(aug1);
 				if (augitem1) {
@@ -229,7 +237,7 @@
 						inst->PutAugment(&database, 0, aug1);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem1->Name, aug1);
 					}
 				}
 			}
@@ -240,7 +248,7 @@
 						inst->PutAugment(&database, 1, aug2);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem2->Name, aug2);
 					}
 				}
 			}
@@ -251,7 +259,7 @@
 						inst->PutAugment(&database, 2, aug3);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem3->Name, aug3);
 					}
 				}
 			}
@@ -262,7 +270,7 @@
 						inst->PutAugment(&database, 3, aug4);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem4->Name, aug4);
 					}
 				}
 			}
@@ -273,7 +281,7 @@
 						inst->PutAugment(&database, 4, aug5);
 					}
 					else {
-						Message(0, "You already have a %s (%i) in your inventory!", item->Name, item_id);
+						Message(0, "You already have a %s (%u) in your inventory - Augment not added!", augitem5->Name, aug5);
 					}
 				}
 			}
@@ -397,9 +405,11 @@
 		LogFile->write(EQEMuLog::Debug, "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) {
+		if(client_update && IsValidSlot(slot_id)) {
 			EQApplicationPacket* outapp;
 			outapp = new EQApplicationPacket(OP_DeleteItem, sizeof(DeleteItem_Struct));
 			DeleteItem_Struct* delitem	= (DeleteItem_Struct*)outapp->pBuffer;
@@ -427,23 +437,29 @@
 		    database.SaveInventory(character_id, inst, slot_id);
 	}
 
-	if(client_update) {
+	if(client_update && IsValidSlot(slot_id)) {
 		EQApplicationPacket* outapp;
 		if(inst) {
-			if(!inst->IsStackable() && !isDeleted) 
+			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);
+				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);
+
+				if (slot_id == SLOT_CURSOR) {
+					Message(13, "Server Warning! If you just received a MOVE ITEM FAILED IN CLIENT APPLICATION");
+					Message(13, "error message, then you will need to zone or relog to clear this problem.");
+					Message(0, "Do not perform any inventory actions until you do so or permanent item loss is possible.");
+				}
 		}
 		else {
 			outapp = new EQApplicationPacket(OP_MoveItem, sizeof(MoveItem_Struct));
@@ -455,7 +471,6 @@
 			safe_delete(outapp);
 		}
 	}
-
 }
 
 // Puts an item into the person's inventory
@@ -1011,7 +1026,8 @@
 			move_in->from_slot = dst_slot_check;
 			move_in->to_slot = src_slot_check;
 			move_in->number_in_stack = dst_inst->GetCharges();
-			SwapItem(move_in);
+			if (!SwapItem(move_in)) // shouldn't fail because call wouldn't exist otherwise, but just in case...
+				this->Message(13, "Error: Internal SwapItem call returned a failure!");
 		}
 		Message(13, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
 		LogFile->write(EQEMuLog::Debug, "Error: Server found no item in slot %i (->%i), Deleting Item!", src_slot_id, dst_slot_id);
@@ -1188,7 +1204,13 @@
 					mlog(INVENTORY__SLOTS, "Dest (%d) now has %d charges, source (%d) has %d (%d moved)", dst_slot_id, dst_inst->GetCharges(), src_slot_id, src_inst->GetCharges(), usedcharges);
 				}
 			} else {
-				//stack is full, so 
+				//stack is full, so
+
+				// there was no action taken here previously. any moveitem action would cause server to fail swapitem request, but
+				// the calling method still processed a success by continuing on to the end of the procedure. affected methods have
+				// been changed to conditional calls. needed to add this:
+				mlog(INVENTORY__ERROR, "Move from %d to %d with stack size %d. Exceeds dest maximum stack size: %d/%d", src_slot_id, dst_slot_id, move_in->number_in_stack, (src_inst->GetCharges()+dst_inst->GetCharges()), dst_inst->GetItem()->StackSize);
+				return false;
 			}
 		}
 		else {
@@ -1679,7 +1701,7 @@
 	Save();
 }
 
-void	Client::RemoveBandolier(const EQApplicationPacket *app) {
+void Client::RemoveBandolier(const EQApplicationPacket *app) {
 
 	// Delete bandolier with the specified number
 
@@ -1693,7 +1715,7 @@
 	Save();
 }
 
-void	Client::SetBandolier(const EQApplicationPacket *app) {
+void Client::SetBandolier(const EQApplicationPacket *app) {
 
 	// Swap the weapons in the given bandolier set into the character's weapon slots and return
 	// any items currently in the weapon slots to inventory.
@@ -1714,7 +1736,28 @@
 			// Check if the player has the item specified in the bandolier set on them.
 			//
 			slot = m_inv.HasItem(m_pp.bandoliers[bss->number].items[BandolierSlot].item_id, 1, 
-					     invWhereWorn|invWherePersonal|invWhereCursor);
+					     invWhereWorn|invWherePersonal);
+
+			// removed 'invWhereCursor' argument from above and implemented slots 30, 331-340 checks here 
+			if (slot == SLOT_INVALID) {
+				if (m_inv.GetItem(SLOT_CURSOR)) {
+					if (m_inv.GetItem(SLOT_CURSOR)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
+						m_inv.GetItem(SLOT_CURSOR)->GetCharges() >= 1) // '> 0' the same, but this matches Inventory::_HasItem conditional check
+							slot = SLOT_CURSOR;
+					else if (m_inv.GetItem(SLOT_CURSOR)->GetItem()->ItemClass == 1) {
+						for(sint16 CursorBagSlot = 331; CursorBagSlot <= 340; CursorBagSlot++) {
+							if (m_inv.GetItem(CursorBagSlot)) {
+								if (m_inv.GetItem(CursorBagSlot)->GetItem()->ID == m_pp.bandoliers[bss->number].items[BandolierSlot].item_id &&
+									m_inv.GetItem(CursorBagSlot)->GetCharges() >= 1) { // ditto
+										slot = CursorBagSlot;
+										break;
+								}
+							}
+						}
+					}
+				}
+			}
+
 			// if the player has this item in their inventory,
 			if(slot != SLOT_INVALID) {
 				// Pull the item out of the inventory
@@ -1842,7 +1885,7 @@
 	//
 	if(ItemToReturn->IsStackable()) {
 
-		for (sint16 i=22; i<=29; i++) {
+		for (sint16 i=22; i<=30; i++) { // changed slot max to 30 from 29. client will stack into slot 30 (bags too) before moving.
 
 			ItemInst* InvItem = m_inv.GetItem(i);
 
@@ -1905,7 +1948,7 @@
 
 	// We have tried stacking items, now just try and find an empty slot.
 
-	for (sint16 i=22; i<=29; i++) {
+	for (sint16 i=22; i<=30; i++) { // changed slot max to 30 from 29. client will move into slot 30 (bags too) before pushing onto cursor.
 
 		ItemInst* InvItem = m_inv.GetItem(i);
 
Index: zone/PlayerCorpse.cpp
===================================================================
--- zone/PlayerCorpse.cpp	(revision 2193)
+++ zone/PlayerCorpse.cpp	(working copy)
@@ -347,11 +347,15 @@
 
 	if(!RuleB(Character, LeaveNakedCorpses) || RuleB(Character, LeaveCorpses) && GetLevel() >= RuleI(Character, DeathItemLossLevel)) {
 		// cash
-		SetCash(pp->copper, pp->silver, pp->gold, pp->platinum);
-		pp->copper = 0;
-		pp->silver = 0;
-		pp->gold = 0;
-		pp->platinum = 0;
+		// Let's not move the cash when 'RespawnFromHover = true' && 'client->GetClientVersion() >= EQClientSoF' since the client doesn't.
+		// (change to first client that supports 'death hover' mode, if not SoF.)
+		if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) {
+			SetCash(pp->copper, pp->silver, pp->gold, pp->platinum);
+			pp->copper = 0;
+			pp->silver = 0;
+			pp->gold = 0;
+			pp->platinum = 0;
+		}
 	
 		// get their tints
 		memcpy(item_tint, &client->GetPP().item_tint, sizeof(item_tint));
@@ -367,23 +371,30 @@
 			item = client->GetInv().GetItem(i);
 			if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
 			{
-				MoveItemToCorpse(client, item, i);
-                removed_list.push_back(i);
+				std::list<uint32> slot_list = MoveItemToCorpse(client, item, i);
+				removed_list.merge(slot_list);  
 			}
 		}
 
-		// cursor queue
-		iter_queue it;
-		for(it=client->GetInv().cursor_begin(),i=8000; it!=client->GetInv().cursor_end(); it++,i++) {
-			item = *it;
-			if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
-			{
-				MoveItemToCorpse(client, item, i);
-                cursor = true;
+		// cursor queue // (change to first client that supports 'death hover' mode, if not SoF.)
+		if (!RuleB(Character, RespawnFromHover) || client->GetClientVersion() < EQClientSoF) {
+
+			// bumped starting assignment to 8001 because any in-memory 'slot 8000' item was moved above as 'slot 30'
+			// this was mainly for client profile state reflection..should match db player inventory entries now.
+			
+			iter_queue it;
+			for(it=client->GetInv().cursor_begin(),i=8001; it!=client->GetInv().cursor_end(); it++,i++) {
+				item = *it;
+				if((item && (!client->IsBecomeNPC())) || (item && client->IsBecomeNPC() && !item->GetItem()->NoRent))
+				{
+					std::list<uint32> slot_list = MoveItemToCorpse(client, item, i);
+					removed_list.merge(slot_list);
+			        cursor = true;
+				}
 			}
 		}
 		
-        if(removed_list.size() != 0) {
+		if(removed_list.size() != 0) {
             std::stringstream ss("");
             ss << "DELETE FROM inventory WHERE charid=" << client->CharacterID();
             ss << " AND (";
@@ -401,14 +412,18 @@
             ss << ")";
             database.RunQuery(ss.str().c_str(), ss.str().length());
         }
-        
-        if(cursor) {
-            std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
-            std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
-            database.SaveCursor(client->CharacterID(), 
-                start, finish);
+
+        if(cursor) { // all cursor items should be on corpse (client < SoF or RespawnFromHover = false)
+			while(!client->GetInv().CursorEmpty())
+					client->DeleteItemInInventory(SLOT_CURSOR, 0, false, false);           
         }
+		else { // only visible cursor made it to corpse (client >= Sof and RespawnFromHover = true)
+			std::list<ItemInst*>::const_iterator start = client->GetInv().cursor_begin();
+			std::list<ItemInst*>::const_iterator finish = client->GetInv().cursor_end();
+			database.SaveCursor(client->CharacterID(), start, finish);
+		}
 
+		// client->CalcBonuses(); // will only affect offline profile viewing of dead characters..unneeded overhead
 		client->Save();
 	} //end "not leaving naked corpses"
 	
@@ -417,28 +432,35 @@
 }
 
 // solar: helper function for client corpse constructor
-void Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
+std::list<uint32> Corpse::MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot)
 {
 	int bagindex;
 	sint16 interior_slot;
 	ItemInst *interior_item;
+	std::list<uint32> returnlist;
 
 	AddItem(item->GetItem()->ID, item->GetCharges(), equipslot, item->GetAugmentItemID(0), item->GetAugmentItemID(1), item->GetAugmentItemID(2), item->GetAugmentItemID(3), item->GetAugmentItemID(4));
-	if(item->IsType(ItemClassContainer))
+	returnlist.push_back(equipslot);
+
+	// Qualified bag slot iterations. processing bag slots that don't exist is probably not a good idea.
+	if(item->IsType(ItemClassContainer) && ((equipslot >= 22 && equipslot <=30))) // Limit the bag check to inventory and cursor slots.
 	{
 		for(bagindex = 0; bagindex <= 10; bagindex++)
 		{
+			// For empty bags in cursor queue, slot was previously being resolved as SLOT_INVALID (-1)
 			interior_slot = Inventory::CalcSlotId(equipslot, bagindex);
 			interior_item = client->GetInv().GetItem(interior_slot);
 
 			if(interior_item)
 			{
 				AddItem(interior_item->GetItem()->ID, interior_item->GetCharges(), interior_slot, interior_item->GetAugmentItemID(0), interior_item->GetAugmentItemID(1), interior_item->GetAugmentItemID(2), interior_item->GetAugmentItemID(3), interior_item->GetAugmentItemID(4));
+				returnlist.push_back(Inventory::CalcSlotId(equipslot, bagindex));
 				client->DeleteItemInInventory(interior_slot, 0, true, false);
 			}
 		}
 	}
 	client->DeleteItemInInventory(equipslot, 0, true, false);
+	return returnlist;
 }
 
 // To be called from LoadFromDBData
@@ -981,19 +1003,41 @@
 		ItemList::iterator cur,end;
 		cur = itemlist.begin();
 		end = itemlist.end();
+
+		int corpselootlimit = 30; // 30 is the original value // con check value in QueryLoot needs to reflect this value
+		
+		/* need actual corpse limit values per client (or client range)..if always 30, then these con checks are unneeded
+		// enumeration shouldn't be needed unless someone finds a use for this info elsewhere
+		
+		if (client->GetClientVersion()>=EQClientVoA)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientHoT)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientUnderfoot)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientSoD)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientSoF) // SoF has 32 visible slots..change untested
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClientTitanium)
+			corpselootlimit=30;
+		else if (client->GetClientVersion()>=EQClient62)
+			corpselootlimit=30;
+		else
+			corpselootlimit=30; // */
+
 		for(; cur != end; cur++) {
 			ServerLootItem_Struct* item_data = *cur;
 			item_data->lootslot = 0xFFFF;
+			
+			// Dont display the item if it's in a bag
 
-			// Dont display the item if it's in a bag
-			if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3)
+			// Added cursor queue slots to corpse item visibility list. Nothing else should be making it to corpse.
+			if(!IsPlayerCorpse() || item_data->equipSlot <= 30 || tCanLoot>=3 ||
+				(item_data->equipSlot >= 8000 && item_data->equipSlot <= 8999))
 			{
-				if (i >= 30)
+				if (i < corpselootlimit) // < 30 (0 - 29) 
 				{
-						Message(13, "Warning: Too many items to display. Loot some then re-loot the corpse to see the rest");
-				}
-				else
-				{
 					item = database.GetItem(item_data->item_id);
 					if (client && item)
 					{
@@ -1006,9 +1050,24 @@
 						item_data->lootslot = i;
 					}
 				}
+				else if (i == corpselootlimit) // = 30
+				{
+					client->Message(13, "*** This corpse contains more items than can be displayed! ***");
+					client->Message(0, "Remove items and re-loot corpse to access remaining inventory.");
+				}
 				i++;
 			}
 		}
+		if (i > corpselootlimit) // > 30 (remember 'i' is increased again after the last iteration, so no '=')
+			client->Message(0, "(%s contains %i additional %s.)", GetName(), (i-corpselootlimit), (i-corpselootlimit)==1?"item":"items");
+
+		if (IsPlayerCorpse() && i == 0 && itemlist.size() > 0) { // somehow, corpse contains items, but client doesn't see them...
+			client->Message(13, "This corpse contains items that you do not have permission to access!");
+			client->Message(0, "Contact a GM for assistance to see if item replacement is necessary.");
+			client->Message(0, "BUGGED CORPSE [DBID: %i, Name: %s, Item Count: %i]", GetDBID(), GetName(), itemlist.size());
+			// if needed/wanted - create log dump->iterate corpse list..need pointer to log file
+			// could add code to check for owning client and give list of bugged items on corpse
+		}
 	}
 	
 	// Disgrace: Client seems to require that we send the packet back...
@@ -1296,7 +1355,7 @@
 }
 
 void Corpse::QueryLoot(Client* to) {
-	int x = 0;
+	int x = 0, y = 0; // x = visible items, y = total items
 	to->Message(0, "Coin: %ip %ig %is %ic", platinum, gold, silver, copper);
 
 	ItemList::iterator cur,end;
@@ -1304,14 +1363,44 @@
 	end = itemlist.end();
 	for(; cur != end; cur++) {
 		ServerLootItem_Struct* sitem = *cur;
-		const Item_Struct* item = database.GetItem(sitem->item_id);
-		if (item)
-			to->Message(0, "  %d: %s", item->ID, item->Name);
-		else
-			to->Message(0, "  Error: 0x%04x", sitem->item_id);
-		x++;
+
+		if (IsPlayerCorpse()) {
+			if (sitem->equipSlot >= 251 && sitem->equipSlot <= 340)
+				sitem->lootslot = 0xFFFF;
+			else
+				x < 30 ? sitem->lootslot = x : sitem->lootslot = 0xFFFF; // this con value needs to reflect corpselootlimit in MakeLootRequestPackets
+			
+			const Item_Struct* item = database.GetItem(sitem->item_id);
+
+			if (item)
+				to->Message((sitem->lootslot == 0xFFFF), "  LootSlot: %i (EquipSlot: %i) Item: %s (%d) with %i %s", sitem->lootslot, sitem->equipSlot, item->Name, item->ID, sitem->charges, sitem->charges==1?"charge":"charges");
+			else
+				to->Message((sitem->lootslot == 0xFFFF), "  Error: 0x%04x", sitem->item_id);
+			
+			if (sitem->lootslot != 0xFFFF)
+				x++;
+
+			y++;
+		}
+		else {
+			sitem->lootslot=y;
+			const Item_Struct* item = database.GetItem(sitem->item_id);
+			
+			if (item)
+				to->Message(0, "  LootSlot: %i Item: %s (%d) with %i %s", sitem->lootslot, item->Name, item->ID, sitem->charges, sitem->charges==1?"charge":"charges");
+			else
+				to->Message(0, "  Error: 0x%04x", sitem->item_id);
+
+			y++;
+		}
 	}
-	to->Message(0, "%i items on %s.", x, this->GetName());
+
+	if (IsPlayerCorpse()) {
+		to->Message(0, "%i visible %s (%i total) on %s (DBID: %i).", x, x==1?"item":"items", y, this->GetName(), this->GetDBID());
+	}
+	else {
+		to->Message(0, "%i %s on %s.", y, y==1?"item":"items", this->GetName());
+	}
 }
 
 bool Corpse::Summon(Client* client, bool spell, bool CheckDistance)
Index: zone/PlayerCorpse.h
===================================================================
--- zone/PlayerCorpse.h	(revision 2193)
+++ zone/PlayerCorpse.h	(working copy)
@@ -111,7 +111,7 @@
 	inline int GetRezzExp() { return rezzexp; }
 
 protected:
-	void MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot);
+	std::list<uint32> MoveItemToCorpse(Client *client, ItemInst *item, sint16 equipslot);
 
 private:
 	bool		p_PlayerCorpse;
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #12  
Old 10-30-2012, 08:58 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Heys guys! I haven't seen anything, good or bad, regarding this patch.

I was wondering if anyone has actually tried using the bandolier function since this patch went live.


I'm not looking for kudos or atta-boys, but if you have had any experience that warrants looking into the code, please let me know. (Try to include any actions
that you were doing prior to negative experiences.)

Thanks!
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 04:24 PM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3