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

Reply
 
Thread Tools Display Modes
  #1  
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
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 05:38 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 - 2025, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3