View Single Post
  #10  
Old 08-14-2012, 05:49 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

Ok, here is everything so far diff'd off of rev 2185.


Code:
Index: client_packet.cpp
===================================================================
--- client_packet.cpp	(revision 2185)
+++ client_packet.cpp	(working copy)
@@ -3310,6 +3310,55 @@
 			return;
 		}
 	}
+
+	// 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 lose items to bugged corpses at some point.
+	//* 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 */
+
 	SwapItem(mi);
 	return;
 }
Index: command.cpp
===================================================================
--- command.cpp	(revision 2185)
+++ 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) { // 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!");
 	}
 }
@@ -3727,6 +3771,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 +3827,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 +11580,40 @@
 	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;
+	if (sep->argnum < 2 || sep->argnum > 3)
+		c->Message(0, "Usage: #zopp [slot id] [item id] [*charges]");
+	else if (!sep->IsNumber(1) || !sep->IsNumber(2) || (sep->argnum == 3 && !sep->IsNumber(3)))
+		c->Message(0, "Usage: #zopp [slot id] [item id] [*charges]");
+	else {
+		sint16 slotid = atoi(sep->arg[1]);
+		int32 itemid = atoi(sep->arg[2]);
+		sint16 charges = sep->argnum == 3 ? atoi(sep->arg[3]) : 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, ItemPacketTrade);
+		c->Message(0, "Sending zephyr op packet to client - %s (%u) with %i %s to slot %i.", FakeItem->Name, itemid, charges, abs(charges==1)?"charge":"charges", slotid);
+		safe_delete(FakeItemInst);
+	}
+}
\ No newline at end of file
Index: command.h
===================================================================
--- command.h	(revision 2185)
+++ 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: inventory.cpp
===================================================================
--- inventory.cpp	(revision 2185)
+++ 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,7 +437,7 @@
 		    database.SaveInventory(character_id, inst, slot_id);
 	}
 
-	if(client_update) {
+	if(client_update && IsValidSlot(slot_id)) {
 		EQApplicationPacket* outapp;
 		if(inst) {
 			if(!inst->IsStackable() && !isDeleted) 
Index: PlayerCorpse.cpp
===================================================================
--- PlayerCorpse.cpp	(revision 2185)
+++ 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: PlayerCorpse.h
===================================================================
--- PlayerCorpse.h	(revision 2185)
+++ 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;

No more updates to this portion of code unless I, or someone else, finds a major flaw in it.

I can post test procedures if anyone needs specific criteria.
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote