Forráskód Böngészése

Fix #524 - DoF client part #3, plus crash fixes (reload spells, entering zone shutting down)
- Addressed DoF inventory causing items to be put in the wrong slot or disappearing
- Fixed instances serving a client a zone currently shutting down
- Added more enforcement of the client count for a zone so it does not prematurely shutdown when a client is entering the zone
- Addressed NPCs in DoF client "looking at" them when they should not. "interaction_flag" in SetInfoStructUInt(Spawn, "interaction_flag", 255) will now enforce not looking at a player.
- resolved /reload spells crash
- Control Effects now work for DoF client
- /flymode now supports values 1 and 2. 1 = flymode, 2 = noclip + flymode. DoF client flymode is not the same as AOM, it doesn't support up/down/jump
- added /gm controleffects (select entity target) will display their active control effects
- DoF client: can now right-click examine items in base inventory and inside bags of inventory
- can no longer put bags inside of other bags
- fixed the classic icons for collecting, fishing, gathering, foresting, mining, trapping, tracking put in temp icon until we determine right one.

Emagi 8 hónapja
szülő
commit
5cc42192a5

+ 49 - 12
EQ2/source/WorldServer/ClientPacketFunctions.cpp

@@ -241,9 +241,22 @@ void ClientPacketFunctions::SendUpdateSpellBook ( Client* client ){
 	client->GetPlayer()->UnlockAllSpells(true);
 	client->GetPlayer()->UnlockAllSpells(true);
 }
 }
 
 
+void ClientPacketFunctions::SendServerControlFlagsClassic(Client* client, int32 param, int32 value) {
+	PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", client->GetVersion());
+	if(packet) {
+		packet->setDataByName("parameter", param);
+		packet->setDataByName("value", value);
+		client->QueuePacket(packet->serialize());
+	}
+	safe_delete(packet);
+}
 void ClientPacketFunctions::SendServerControlFlags(Client* client, int8 param, int8 param_val, int8 value) {
 void ClientPacketFunctions::SendServerControlFlags(Client* client, int8 param, int8 param_val, int8 value) {
 	PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", client->GetVersion());
 	PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", client->GetVersion());
 	if(packet) {
 	if(packet) {
+		
+		if(client->GetVersion() <= 546 && param == 1 && !value) {
+			param_val = 0;
+		}
 		if (param == 1)
 		if (param == 1)
 			packet->setDataByName("parameter1", param_val);
 			packet->setDataByName("parameter1", param_val);
 		else if (param == 2)
 		else if (param == 2)
@@ -258,7 +271,6 @@ void ClientPacketFunctions::SendServerControlFlags(Client* client, int8 param, i
 			safe_delete(packet);
 			safe_delete(packet);
 			return;
 			return;
 		}
 		}
-
 		packet->setDataByName("value", value);
 		packet->setDataByName("value", value);
 		client->QueuePacket(packet->serialize());
 		client->QueuePacket(packet->serialize());
 		/*
 		/*
@@ -395,18 +407,44 @@ void ClientPacketFunctions::SendStateCommand(Client* client, int32 spawn_id, int
 
 
 void ClientPacketFunctions::SendFlyMode(Client* client, int8 flymode, bool updateCharProperty)
 void ClientPacketFunctions::SendFlyMode(Client* client, int8 flymode, bool updateCharProperty)
 {
 {
-	PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", client->GetVersion());
-
 	if (updateCharProperty)
 	if (updateCharProperty)
 		database.insertCharacterProperty(client, CHAR_PROPERTY_FLYMODE, (char*)std::to_string(flymode).c_str());
 		database.insertCharacterProperty(client, CHAR_PROPERTY_FLYMODE, (char*)std::to_string(flymode).c_str());
-
-	if (packet) {
-		packet->setDataByName("parameter5", 32);
-		packet->setDataByName("value", flymode);
-		client->QueuePacket(packet->serialize());
-
-		client->Message(CHANNEL_STATUS, "Flymode %s", flymode == 1 ? "on" : "off");
+	if(client->GetVersion() <= 546) {
+		if(flymode) {
+			// old flymode
+			SendServerControlFlagsClassic(client, flymode, 1);
+			if(flymode == 1) {
+				// disable noclip
+				SendServerControlFlagsClassic(client, 2, 0);
+			}
+		}
+		else {
+			// disable flymode and noclip
+			SendServerControlFlagsClassic(client, 2, 0);
+			SendServerControlFlagsClassic(client, 1, 0);
+		}
+	}
+	else {	
+		if(flymode == 2) {
+			// new flymode + noclip
+			SendServerControlFlags(client, 5, 32, 1);
+			SendServerControlFlags(client, 1, 2, 1);
+		}
+		else if(flymode == 1) {
+			// new flymode
+			SendServerControlFlags(client, 5, 32, 1);
+			SendServerControlFlags(client, 1, 2, 0);
+		}
+		else {
+			// disable flymode and noclip
+			SendServerControlFlags(client, 5, 32, 0);
+			SendServerControlFlags(client, 1, 2, 0);
+		}
+	}
+		
+		client->Message(CHANNEL_STATUS, "Flymode %s, No Clip %s", flymode > 0 ? "on" : "off", flymode > 1 ? "on" : "off");
 		/*
 		/*
+		CLASSIC/DOF ONLY HAS THE FIRST SET OF FLAGS
 		Some other values for this packet
 		Some other values for this packet
 		first param:
 		first param:
 		01 flymode
 		01 flymode
@@ -417,6 +455,7 @@ void ClientPacketFunctions::SendFlyMode(Client* client, int8 flymode, bool updat
 		32 low gravity
 		32 low gravity
 		64 sit
 		64 sit
 
 
+		EVERYTHING BELOW NOT SUPPORTED BY CLASSIC/DOF
 		second
 		second
 		2 crouch
 		2 crouch
 
 
@@ -437,6 +476,4 @@ void ClientPacketFunctions::SendFlyMode(Client* client, int8 flymode, bool updat
 		32 flymode2?
 		32 flymode2?
 
 
 		*/
 		*/
-		safe_delete(packet);
-	}
 }
 }

+ 2 - 0
EQ2/source/WorldServer/ClientPacketFunctions.h

@@ -58,6 +58,8 @@ public:
 
 
 	static void SendServerControlFlags(Client* client, int8 param, int8 param_val, int8 value);
 	static void SendServerControlFlags(Client* client, int8 param, int8 param_val, int8 value);
 
 
+	static void SendServerControlFlagsClassic(Client* client, int32 param, int32 value);
+
 	static void SendInstanceList(Client* client);
 	static void SendInstanceList(Client* client);
 
 
 	static void SendZoneChange(Client* client, char* zone_ip, int16 zone_port, int32 key);
 	static void SendZoneChange(Client* client, char* zone_ip, int16 zone_port, int32 key);

+ 41 - 12
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -2095,6 +2095,11 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 			if(sep && sep->arg[1][0] && sep->IsNumber(1)){
 			if(sep && sep->arg[1][0] && sep->IsNumber(1)){
 				if(strcmp(sep->arg[0], "inventory") == 0){
 				if(strcmp(sep->arg[0], "inventory") == 0){
 					int32 item_index = atol(sep->arg[1]);
 					int32 item_index = atol(sep->arg[1]);
+					
+					if(client->GetVersion() <= 546) {
+						item_index = (uint32)-(sint32)item_index & 0xFFFFFFFF;
+						item_index -= 1;
+					}
 					Item* item = client->GetPlayer()->item_list.GetItemFromIndex(item_index);
 					Item* item = client->GetPlayer()->item_list.GetItemFromIndex(item_index);
 					if(item){
 					if(item){
 						if (item->IsCollectable() && client->SendCollectionsForItem(item))
 						if (item->IsCollectable() && client->SendCollectionsForItem(item))
@@ -2812,11 +2817,11 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 		case COMMAND_FLYMODE:{
 		case COMMAND_FLYMODE:{
 			if(sep && sep->arg[0] && sep->IsNumber(0)){
 			if(sep && sep->arg[0] && sep->IsNumber(0)){
 				PrintSep(sep, "COMMAND_FLYMODE");
 				PrintSep(sep, "COMMAND_FLYMODE");
-				int8 val = atoi(sep->arg[0]);
+				int8 val = atoul(sep->arg[0]);
 				ClientPacketFunctions::SendFlyMode(client, val);
 				ClientPacketFunctions::SendFlyMode(client, val);
 			}
 			}
 			else{
 			else{
-				client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Usage ON: /flymode 1");
+				client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Usage ON: /flymode [1|2] 1 = fly, 2 = no clip");
 				client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Usage OFF: /flymode 0");
 				client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Usage OFF: /flymode 0");
 			}
 			}
 			break;
 			break;
@@ -3476,9 +3481,9 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 					PrintSep(sep, "ZONE LOCK");
 					PrintSep(sep, "ZONE LOCK");
 
 
 					if(sep->IsNumber(1))
 					if(sep->IsNumber(1))
-						zsZone = zone_list.Get(atoul(sep->arg[1]), false);
+						zsZone = zone_list.Get(atoul(sep->arg[1]), false, false, false);
 					else
 					else
-						zsZone = zone_list.Get(sep->arg[1], false);
+						zsZone = zone_list.Get(sep->arg[1], false, false, false);
 
 
 					if( zsZone )
 					if( zsZone )
 					{
 					{
@@ -3495,9 +3500,9 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 					PrintSep(sep, "ZONE UNLOCK");
 					PrintSep(sep, "ZONE UNLOCK");
 
 
 					if(sep->IsNumber(1))
 					if(sep->IsNumber(1))
-						zsZone = zone_list.Get(atoul(sep->arg[1]), false);
+						zsZone = zone_list.Get(atoul(sep->arg[1]), false, false, false);
 					else
 					else
-						zsZone = zone_list.Get(sep->arg[1], false);
+						zsZone = zone_list.Get(sep->arg[1], false, false, false);
 
 
 					if( zsZone )
 					if( zsZone )
 					{
 					{
@@ -4022,6 +4027,15 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 					else
 					else
 						client->SetPlayerPOVGhost(nullptr);
 						client->SetPlayerPOVGhost(nullptr);
 				}
 				}
+				else if (strcmp(sep->arg[0], "controleffects") == 0)
+				{
+					if(cmdTarget && cmdTarget->IsEntity()) {
+						((Entity*)cmdTarget)->SendControlEffectDetailsToClient(client);
+					}
+					else {
+						client->GetPlayer()->SendControlEffectDetailsToClient(client);
+					}
+				}
 				else if (strcmp(sep->arg[0], "luadebug") == 0)
 				else if (strcmp(sep->arg[0], "luadebug") == 0)
 				{
 				{
 					client->SetLuaDebugClient(onOff);
 					client->SetLuaDebugClient(onOff);
@@ -6737,7 +6751,7 @@ void Commands::Command_Inventory(Client* client, Seperator* sep, EQ2_RemoteComma
 		else if(sep->arg[4][0] && strncasecmp("move", sep->arg[0], 4) == 0 && sep->IsNumber(1) && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4))
 		else if(sep->arg[4][0] && strncasecmp("move", sep->arg[0], 4) == 0 && sep->IsNumber(1) && sep->IsNumber(2) && sep->IsNumber(3) && sep->IsNumber(4))
 		{
 		{
 			int16 from_index = atoi(sep->arg[1]);
 			int16 from_index = atoi(sep->arg[1]);
-			sint16 to_slot = player->ConvertSlotFromClient(atoi(sep->arg[2]), client->GetVersion());
+			sint16 to_slot = atoi(sep->arg[2]); // don't convert slot since this is inventory not equipment
 			sint32 bag_id = atol(sep->arg[3]);
 			sint32 bag_id = atol(sep->arg[3]);
 			int8 charges = atoi(sep->arg[4]);
 			int8 charges = atoi(sep->arg[4]);
 			Item* item = client->GetPlayer()->item_list.GetItemFromIndex(from_index);
 			Item* item = client->GetPlayer()->item_list.GetItemFromIndex(from_index);
@@ -6889,7 +6903,7 @@ void Commands::Command_Inventory(Client* client, Seperator* sep, EQ2_RemoteComma
 						bag_id = atol(sep->arg[2]);
 						bag_id = atol(sep->arg[2]);
 
 
 					if(sep->IsNumber(3))
 					if(sep->IsNumber(3))
-						to_slot = player->ConvertSlotFromClient(atoi(sep->arg[3]), client->GetVersion());
+						to_slot = atoi(sep->arg[3]);
 				}
 				}
 
 
 				sint8 unk4 = 0;
 				sint8 unk4 = 0;
@@ -6938,7 +6952,7 @@ void Commands::Command_Inventory(Client* client, Seperator* sep, EQ2_RemoteComma
 		}
 		}
 		else if (sep->arg[2][0] && strncasecmp("pop", sep->arg[0], 3) == 0 && sep->IsNumber(1) && sep->IsNumber(2)) 
 		else if (sep->arg[2][0] && strncasecmp("pop", sep->arg[0], 3) == 0 && sep->IsNumber(1) && sep->IsNumber(2)) 
 		{
 		{
-			sint16 to_slot = player->ConvertSlotFromClient(atoi(sep->arg[1]), client->GetVersion());
+			sint16 to_slot = atoi(sep->arg[1]);
 			sint32 bag_id = atoi(sep->arg[2]);
 			sint32 bag_id = atoi(sep->arg[2]);
 			Item* item = client->GetPlayer()->item_list.GetOverflowItem();
 			Item* item = client->GetPlayer()->item_list.GetOverflowItem();
 			if (item) {
 			if (item) {
@@ -10619,6 +10633,21 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 		else if (atoi(sep->arg[0]) == 31) {
 		else if (atoi(sep->arg[0]) == 31) {
 			client->SendRecipeList();
 			client->SendRecipeList();
 		}
 		}
+		else if (atoi(sep->arg[0]) == 32 && sep->IsNumber(1) && sep->IsNumber(2)) {
+			if(client->GetVersion() <= 546) {
+				int32 param = atoul(sep->arg[1]);
+				int32 paramvalue = atoul(sep->arg[2]);
+				client->Message(CHANNEL_COLOR_YELLOW, "Send control flag param %u param value %u", param, paramvalue);
+				ClientPacketFunctions::SendServerControlFlagsClassic(client, param, paramvalue);
+			}
+			else if(sep->IsNumber(3)) {
+				int8 param1 = atoul(sep->arg[1]);
+				int8 param2 = atoul(sep->arg[2]);
+				int8 paramval = atoul(sep->arg[3]);
+				client->Message(CHANNEL_COLOR_YELLOW, "Send control flag param1 %u param2 %u param value %u", param1, param2, paramval);
+				ClientPacketFunctions::SendServerControlFlags(client, param1, param2, paramval);
+			}
+		}
 	}
 	}
 	else {
 	else {
 			PacketStruct* packet2 = configReader.getStruct("WS_ExamineSpellInfo", client->GetVersion());
 			PacketStruct* packet2 = configReader.getStruct("WS_ExamineSpellInfo", client->GetVersion());
@@ -10931,7 +10960,7 @@ void Commands::Command_ZoneSafeCoords(Client *client, Seperator *sep)
 
 
 	if (zone_id > 0)
 	if (zone_id > 0)
 	{
 	{
-		zone = zone_list.Get(zone_id, false);
+		zone = zone_list.Get(zone_id, false, false, false);
 		if (zone)
 		if (zone)
 		{
 		{
 			zone->SetSafeX(client->GetPlayer()->GetX());
 			zone->SetSafeX(client->GetPlayer()->GetX());
@@ -11004,14 +11033,14 @@ void Commands::Command_ZoneSet(Client* client, Seperator* sep)
 		if (sep->IsNumber(0) && atoi(sep->arg[0]) > 0) 
 		if (sep->IsNumber(0) && atoi(sep->arg[0]) > 0) 
 		{
 		{
 			zone_id = atoi(sep->arg[0]);
 			zone_id = atoi(sep->arg[0]);
-			zone = zone_list.Get(atoi(sep->arg[0]), false);
+			zone = zone_list.Get(atoi(sep->arg[0]), false, false, false);
 		}
 		}
 		else 
 		else 
 		{
 		{
 			zone_id = database.GetZoneID(sep->arg[0]);
 			zone_id = database.GetZoneID(sep->arg[0]);
 
 
 			if (zone_id > 0)
 			if (zone_id > 0)
-				zone = zone_list.Get(sep->arg[0], false);
+				zone = zone_list.Get(sep->arg[0], false, false, false);
 		}
 		}
 
 
 		if (zone_id > 0) 
 		if (zone_id > 0) 

+ 1 - 1
EQ2/source/WorldServer/Commands/ConsoleCommands.cpp

@@ -359,7 +359,7 @@ bool ConsoleZoneCommand(Seperator *sep)
 		{
 		{
 			if( sep->IsNumber(2) )
 			if( sep->IsNumber(2) )
 			{
 			{
-				zone = zone_list.Get(atoi(sep->arg[2]), false);
+				zone = zone_list.Get(atoi(sep->arg[2]), false, false, false);
 				if( zone )
 				if( zone )
 				{
 				{
 					printf("> Zone status for zone ID %i...\n", atoi(sep->arg[2]));
 					printf("> Zone status for zone ID %i...\n", atoi(sep->arg[2]));

+ 20 - 0
EQ2/source/WorldServer/Entity.cpp

@@ -3739,4 +3739,24 @@ bool Entity::IsEngagedBySpawnID(int32 id) {
 	}
 	}
 	
 	
 	return ret;
 	return ret;
+}
+
+void Entity::SendControlEffectDetailsToClient(Client* client) {
+	client->Message(CHANNEL_COLOR_YELLOW, "Current control effects on %s", GetName());
+	client->Message(CHANNEL_COLOR_YELLOW, "-------------------------------");
+	for (int i = 0; i < CONTROL_MAX_EFFECTS; i++) {
+		if(control_effects[i]) {
+			MutexList<LuaSpell*>* spells = control_effects[i];
+			if(spells->size() > 0) {
+				MutexList<LuaSpell*>::iterator itr = spells->begin();		
+				while(itr.Next()){
+					LuaSpell* spell = itr->value;
+					if(spell && spell->spell && spell->spell->GetSpellData()) {
+						client->Message(CHANNEL_COLOR_YELLOW, "Spell %s (%u) control effect %s", spell->spell->GetName(), spell->spell->GetSpellData()->id, GetControlEffectName(i).c_str());
+					}
+				}
+			}
+		}
+	}
+	client->Message(CHANNEL_COLOR_YELLOW, "-------------------------------");
 }
 }

+ 65 - 0
EQ2/source/WorldServer/Entity.h

@@ -1888,7 +1888,72 @@ public:
 	
 	
 	bool IsEngagedInEncounter(Spawn** res = nullptr);
 	bool IsEngagedInEncounter(Spawn** res = nullptr);
 	bool IsEngagedBySpawnID(int32 id);
 	bool IsEngagedBySpawnID(int32 id);
+	void SendControlEffectDetailsToClient(Client* client);
 		
 		
+	std::string GetControlEffectName(int8 control_effect_type) {
+		switch(control_effect_type) {
+			case CONTROL_EFFECT_TYPE_MEZ: {
+				return "Mesmerize";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_STIFLE:{
+				return "Stifle";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_DAZE:{
+				return "Daze";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_STUN:{
+				return "Stun";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_ROOT:{
+				return "Root";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_FEAR:{
+				return "Fear";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_WALKUNDERWATER:{
+				return "WalkUnderwater";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_JUMPUNDERWATER:{
+				return "JumpUnderwater";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_INVIS:{
+				return "Invisible";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_STEALTH:{
+				return "Stealth";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_SNARE:{
+				return "Snare";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_FLIGHT:{
+				return "Flight";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_GLIDE:{
+				return "Glide";
+				break;
+			}
+			case CONTROL_EFFECT_TYPE_SAFEFALL:{
+				return "SafeFall";
+				break;
+			}
+			default: {
+				return "Undefined";
+				break;
+			}
+		}
+	}
 	// when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock
 	// when PacketStruct is fixed for C++17 this should become a shared_mutex and handle read/write lock
 	std::mutex		MEquipment;
 	std::mutex		MEquipment;
 	std::mutex		MStats;
 	std::mutex		MStats;

+ 21 - 5
EQ2/source/WorldServer/Items/Items.cpp

@@ -3330,15 +3330,20 @@ bool PlayerItemList::MoveItem(sint32 to_bag_id, int16 from_index, sint8 to, int8
 	if(item_from){
 	if(item_from){
 		if(to_bag_id > 0){  //bag item
 		if(to_bag_id > 0){  //bag item
 			Item* bag = GetItemFromUniqueID(to_bag_id, true, false);
 			Item* bag = GetItemFromUniqueID(to_bag_id, true, false);
-			if(bag && bag->details.num_slots > to)
+			if(bag && bag->details.num_slots > to && (!item_from || !item_from->IsBag()))
 				item_to = items[to_bag_id][BASE_EQUIPMENT][to];
 				item_to = items[to_bag_id][BASE_EQUIPMENT][to];
 			else{
 			else{
 				MPlayerItems.releasewritelock(__FUNCTION__, __LINE__);
 				MPlayerItems.releasewritelock(__FUNCTION__, __LINE__);
 				return false;
 				return false;
 			}
 			}
 		}
 		}
-		else
+		else {
 			item_to = items[to_bag_id][BASE_EQUIPMENT][to];
 			item_to = items[to_bag_id][BASE_EQUIPMENT][to];
+			if(item_to && item_to->IsBag() && item_from && item_from->IsBag()) {
+				MPlayerItems.releasewritelock(__FUNCTION__, __LINE__);
+				return false;
+			}
+		}
 		if(charges > 0) {
 		if(charges > 0) {
 			if (item_to && item_from->details.item_id == item_to->details.item_id){
 			if (item_to && item_from->details.item_id == item_to->details.item_id){
 				if(item_to->details.count > 0 && item_to->details.count < item_to->stack_count){
 				if(item_to->details.count > 0 && item_to->details.count < item_to->stack_count){
@@ -3614,17 +3619,28 @@ void PlayerItemList::AddItemToPacket(PacketStruct* packet, Player* player, Item*
 		packet->setSubstructArrayDataByName("items", "unique_id", item->details.item_id, 0, i);
 		packet->setSubstructArrayDataByName("items", "unique_id", item->details.item_id, 0, i);
 	else
 	else
 		packet->setSubstructArrayDataByName("items", "unique_id", item->details.unique_id, 0, i);
 		packet->setSubstructArrayDataByName("items", "unique_id", item->details.unique_id, 0, i);
-	packet->setSubstructArrayDataByName("items", "bag_id", item->details.bag_id, 0, i);
 	packet->setSubstructArrayDataByName("items", "inv_slot_id", item->details.inv_slot_id, 0, i);
 	packet->setSubstructArrayDataByName("items", "inv_slot_id", item->details.inv_slot_id, 0, i);
 	packet->setSubstructArrayDataByName("items", "menu_type", menu_data, 0, i);
 	packet->setSubstructArrayDataByName("items", "menu_type", menu_data, 0, i);
-	if (overflow)
+	if (overflow) {
 		packet->setSubstructArrayDataByName("items", "index", 0xFFFF, 0, i);
 		packet->setSubstructArrayDataByName("items", "index", 0xFFFF, 0, i);
+	}
+	else if(client->GetVersion() <= 546) {
+		if(item->details.inv_slot_id == 0 && item->details.slot_id < 6) {
+			packet->setSubstructArrayDataByName("items", "bag_id", item->details.bag_id, 0, i);
+		}
+		else {
+			packet->setSubstructArrayDataByName("items", "bag_id", i, 0, i);
+		}
+		packet->setSubstructArrayDataByName("items", "index", 0xFFFF, 0, i);
+		item->details.index = i;
+	}
 	else {
 	else {
+		packet->setSubstructArrayDataByName("items", "bag_id", item->details.bag_id, 0, i);
 		packet->setSubstructArrayDataByName("items", "index", i, 0, i);
 		packet->setSubstructArrayDataByName("items", "index", i, 0, i);
 		item->details.index = i;
 		item->details.index = i;
 	}
 	}
 	packet->setSubstructArrayDataByName("items", "icon", item->details.icon, 0, i);
 	packet->setSubstructArrayDataByName("items", "icon", item->details.icon, 0, i);
-	packet->setSubstructArrayDataByName("items", "slot_id", player->ConvertSlotToClient(item->details.slot_id, client->GetVersion()), 0, i);
+	packet->setSubstructArrayDataByName("items", "slot_id", item->details.slot_id, 0, i); // inventory doesn't convert slots
 	if (client->GetVersion() <= 1208) {
 	if (client->GetVersion() <= 1208) {
 		packet->setSubstructArrayDataByName("items", "count", (std::min)(item->details.count, (int16)255), 0, i);
 		packet->setSubstructArrayDataByName("items", "count", (std::min)(item->details.count, (int16)255), 0, i);
 	}
 	}

+ 2 - 2
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -1698,11 +1698,11 @@ int EQ2Emu_lua_GetZone(lua_State* state) {
 	int32 zone_id = lua_interface->GetInt32Value(state);
 	int32 zone_id = lua_interface->GetInt32Value(state);
 	ZoneServer* zone = 0;
 	ZoneServer* zone = 0;
 	if (zone_id > 0)
 	if (zone_id > 0)
-		zone = zone_list.Get(zone_id);
+		zone = zone_list.Get(zone_id, true, false, false);
 	else {
 	else {
 		string zone_name = lua_interface->GetStringValue(state);
 		string zone_name = lua_interface->GetStringValue(state);
 		if (zone_name.length() > 0) {
 		if (zone_name.length() > 0) {
-			zone = zone_list.Get(zone_name.c_str());
+			zone = zone_list.Get(zone_name.c_str(), true, false, false);
 		}
 		}
 		else {
 		else {
 			Spawn* spawn = lua_interface->GetSpawn(state);
 			Spawn* spawn = lua_interface->GetSpawn(state);

+ 19 - 4
EQ2/source/WorldServer/Player.cpp

@@ -2865,7 +2865,7 @@ EQ2Packet* Player::GetSpellBookUpdatePacket(int16 version) {
 					packet->setSubstructArrayDataByName("spells", "recast_available", spell_entry->recast_available, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "recast_available", spell_entry->recast_available, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "recast_time", spell_entry->recast, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "recast_time", spell_entry->recast, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "status", spell_entry->status, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "status", spell_entry->status, 0, ptr);
-					packet->setSubstructArrayDataByName("spells", "icon", (spell->GetSpellIcon() * -1) - 1, 0, ptr);
+					packet->setSubstructArrayDataByName("spells", "icon", (spell->TranslateClientSpellIcon(version) * -1) - 1, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "icon_type", spell->GetSpellIconBackdrop(), 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "icon_type", spell->GetSpellIconBackdrop(), 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "icon2", spell->GetSpellIconHeroicOp(), 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "icon2", spell->GetSpellIconHeroicOp(), 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "unique_id", (spell_entry->tier + 1) * -1, 0, ptr); //this is actually GetSpellNameCrc(spell->GetName()), but hijacking it for spell tier
 					packet->setSubstructArrayDataByName("spells", "unique_id", (spell_entry->tier + 1) * -1, 0, ptr); //this is actually GetSpellNameCrc(spell->GetName()), but hijacking it for spell tier
@@ -6589,7 +6589,22 @@ void PlayerControlFlags::SendControlFlagUpdates(Client* client){
 	for (itr = flag_changes.begin(); itr != flag_changes.end(); itr++){
 	for (itr = flag_changes.begin(); itr != flag_changes.end(); itr++){
 		ptr = &itr->second;
 		ptr = &itr->second;
 		for (itr2 = ptr->begin(); itr2 != ptr->end(); itr2++){
 		for (itr2 = ptr->begin(); itr2 != ptr->end(); itr2++){
-			ClientPacketFunctions::SendServerControlFlags(client, itr->first, itr2->first, itr2->second);
+			int32 param = itr2->first;
+			if(client->GetVersion() <= 546) {
+				switch(itr->first) {
+					case 4: {
+						if(itr2->first == 64) { // stun
+							ClientPacketFunctions::SendServerControlFlagsClassic(client, 8, itr2->second);
+							param = 16;
+						}
+						break;
+					}
+				}
+				ClientPacketFunctions::SendServerControlFlagsClassic(client, itr2->first, itr2->second);
+			}
+			else {
+				ClientPacketFunctions::SendServerControlFlags(client, itr->first, itr2->first, itr2->second);
+			}
 		}
 		}
 	}
 	}
 	flag_changes.clear();
 	flag_changes.clear();
@@ -6899,7 +6914,7 @@ void Player::SaveSpellEffects()
 				target_char_id = ((Player*)spawn)->GetCharacterID();
 				target_char_id = ((Player*)spawn)->GetCharacterID();
 
 
 			int32 timestamp = 0xFFFFFFFF;
 			int32 timestamp = 0xFFFFFFFF;
-			if(!info->spell_effects[i].spell->spell->GetSpellData()->duration_until_cancel)
+			if(info->spell_effects[i].spell->spell->GetSpellData() && !info->spell_effects[i].spell->spell->GetSpellData()->duration_until_cancel)
 				timestamp = info->spell_effects[i].expire_timestamp - Timer::GetCurrentTime2();
 				timestamp = info->spell_effects[i].expire_timestamp - Timer::GetCurrentTime2();
 			
 			
 			int32 caster_char_id = info->spell_effects[i].spell->initial_caster_char_id;
 			int32 caster_char_id = info->spell_effects[i].spell->initial_caster_char_id;
@@ -6933,7 +6948,7 @@ void Player::SaveSpellEffects()
 			int32 caster_char_id = (info->maintained_effects[i].spell->caster && info->maintained_effects[i].spell->caster->IsPlayer()) ? ((Player*)info->maintained_effects[i].spell->caster)->GetCharacterID() : 0;
 			int32 caster_char_id = (info->maintained_effects[i].spell->caster && info->maintained_effects[i].spell->caster->IsPlayer()) ? ((Player*)info->maintained_effects[i].spell->caster)->GetCharacterID() : 0;
 			
 			
 			int32 timestamp = 0xFFFFFFFF;
 			int32 timestamp = 0xFFFFFFFF;
-			if(!info->maintained_effects[i].spell->spell->GetSpellData()->duration_until_cancel)
+			if(info->maintained_effects[i].spell->spell->GetSpellData() && !info->maintained_effects[i].spell->spell->GetSpellData()->duration_until_cancel)
 				timestamp = info->maintained_effects[i].expire_timestamp - Timer::GetCurrentTime2();
 				timestamp = info->maintained_effects[i].expire_timestamp - Timer::GetCurrentTime2();
 			savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, 
 			savedEffects.AddQueryAsync(GetCharacterID(), &database, Q_INSERT, 
 			"insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, custom_function) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s')", 
 			"insert into character_spell_effects (name, caster_char_id, target_char_id, target_type, db_effect_type, spell_id, effect_slot, slot_pos, icon, icon_backdrop, conc_used, tier, total_time, expire_timestamp, lua_file, custom_spell, charid, damage_remaining, effect_bitmask, num_triggers, had_triggers, cancel_after_triggers, crit, last_spellattack_hit, interrupted, resisted, custom_function) values ('%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %f, %u, '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, '%s')", 

+ 35 - 10
EQ2/source/WorldServer/Spawn.cpp

@@ -2322,6 +2322,7 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 
 
 	bool spawnHiddenFromClient = false;
 	bool spawnHiddenFromClient = false;
 
 
+	int8 classicFlags = 0;
 	// radius of 0 is always seen, -1 is never seen (unless items/spells override), larger than 0 is a defined radius to restrict visibility
 	// radius of 0 is always seen, -1 is never seen (unless items/spells override), larger than 0 is a defined radius to restrict visibility
 	sint32 radius = rule_manager.GetGlobalRule(R_PVP, InvisPlayerDiscoveryRange)->GetSInt32();
 	sint32 radius = rule_manager.GetGlobalRule(R_PVP, InvisPlayerDiscoveryRange)->GetSInt32();
 	if (radius != 0 && (Spawn*)spawn != this && this->IsPlayer() && !spawn->CanSeeInvis((Entity*)this))
 	if (radius != 0 && (Spawn*)spawn != this && this->IsPlayer() && !spawn->CanSeeInvis((Entity*)this))
@@ -2435,12 +2436,19 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 	
 	
 	if (IsNPC() && !IsPet() && !scaredOfPlayer)
 	if (IsNPC() && !IsPet() && !scaredOfPlayer)
 	{
 	{
-		if(((Entity*)this)->GetInfoStruct()->get_interaction_flag())
-			packet->setDataByName("interaction_flag", ((Entity*)this)->GetInfoStruct()->get_interaction_flag()); //this makes NPCs head turn to look at you (12)
-		else
+		if(((Entity*)this)->GetInfoStruct()->get_interaction_flag()) {
+			if(((Entity*)this)->GetInfoStruct()->get_interaction_flag() == 255) { 
+				packet->setDataByName("interaction_flag", 0);
+				classicFlags += INFO_CLASSIC_FLAG_NOLOOK;
+			}
+			else {
+				packet->setDataByName("interaction_flag", ((Entity*)this)->GetInfoStruct()->get_interaction_flag()); //this makes NPCs head turn to look at you (12)
+			}
+		}
+		else {
 			packet->setDataByName("interaction_flag", 12); //turn head since no other value is set
 			packet->setDataByName("interaction_flag", 12); //turn head since no other value is set
+		}
 	}
 	}
-	
 	packet->setDataByName("emote_state", appearance.emote_state);
 	packet->setDataByName("emote_state", appearance.emote_state);
 	packet->setDataByName("mood_state", appearance.mood_state);
 	packet->setDataByName("mood_state", appearance.mood_state);
 	packet->setDataByName("gender", appearance.gender);
 	packet->setDataByName("gender", appearance.gender);
@@ -2499,18 +2507,36 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 		// find the visual flags
 		// find the visual flags
 		int8 vis_flag = 0;
 		int8 vis_flag = 0;
 		//Invis + crouch flag check
 		//Invis + crouch flag check
-		if (entity->IsStealthed())
+		if (entity->IsStealthed()) {
 			vis_flag += (INFO_VIS_FLAG_INVIS + INFO_VIS_FLAG_CROUCH);
 			vis_flag += (INFO_VIS_FLAG_INVIS + INFO_VIS_FLAG_CROUCH);
+			classicFlags += INFO_VIS_FLAG_INVIS + INFO_VIS_FLAG_CROUCH;
+		}
 		//Invis flag check
 		//Invis flag check
-		else if (entity->IsInvis())
+		else if (entity->IsInvis()) {
 			vis_flag += INFO_VIS_FLAG_INVIS;
 			vis_flag += INFO_VIS_FLAG_INVIS;
+			classicFlags += INFO_VIS_FLAG_INVIS;
+		}
+		
 		//Mount flag check
 		//Mount flag check
-		if (entity->GetMount() > 0)
+		if (entity->GetMount() > 0) {
 			vis_flag += INFO_VIS_FLAG_MOUNTED;
 			vis_flag += INFO_VIS_FLAG_MOUNTED;
+		}
+		
 		//Hide hood check
 		//Hide hood check
-		if ((IsPlayer() && ((Player*)this)->get_character_flag(CF_HIDE_HOOD)) || appearance.hide_hood)
+		if (IsPlayer() && ((Player*)this)->get_character_flag(CF_HIDE_HOOD)) {
 			vis_flag += INFO_VIS_FLAG_HIDE_HOOD;
 			vis_flag += INFO_VIS_FLAG_HIDE_HOOD;
-
+		}
+		else if(IsPlayer()) {
+			classicFlags += INFO_CLASSIC_FLAG_SHOW_HOOD;
+		}
+		
+		if(appearance.hide_hood) {
+			vis_flag += INFO_VIS_FLAG_HIDE_HOOD;
+		}
+			
+		if(version <= 546) {
+			packet->setDataByName("flags", classicFlags);
+		}
 		packet->setDataByName("visual_flag", vis_flag);
 		packet->setDataByName("visual_flag", vis_flag);
 		packet->setColorByName("mount_saddle_color", entity->GetMountSaddleColor());
 		packet->setColorByName("mount_saddle_color", entity->GetMountSaddleColor());
 		packet->setColorByName("mount_color", entity->GetMountColor());
 		packet->setColorByName("mount_color", entity->GetMountColor());
@@ -2716,7 +2742,6 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 	}
 	}
 
 
 	packet->setDataByName("activity_status", temp_activity_status); //appearance.activity_status);
 	packet->setDataByName("activity_status", temp_activity_status); //appearance.activity_status);
-
 	// If player and player has a follow target
 	// If player and player has a follow target
 	/* Jan 2021 Note!! Setting follow_target 0xFFFFFFFF has the result in causing strange behavior in swimming.  Targetting a mob makes you focus down to its swim level, unable to swim above it.
 	/* Jan 2021 Note!! Setting follow_target 0xFFFFFFFF has the result in causing strange behavior in swimming.  Targetting a mob makes you focus down to its swim level, unable to swim above it.
 	** in the same respect the player will drop like a rock to the bottom of the ocean (seems to be when self set to that flag?)
 	** in the same respect the player will drop like a rock to the bottom of the ocean (seems to be when self set to that flag?)

+ 5 - 0
EQ2/source/WorldServer/Spawn.h

@@ -173,6 +173,11 @@
 #define VISUAL_STATE_COLLECTION_TURN_IN		6674
 #define VISUAL_STATE_COLLECTION_TURN_IN		6674
 #define VISUAL_STATE_IDLE_AFRAID			17953
 #define VISUAL_STATE_IDLE_AFRAID			17953
 
 
+#define INFO_CLASSIC_FLAG_INVIS                 1
+#define INFO_CLASSIC_FLAG_SHOW_HOOD             2
+#define INFO_CLASSIC_FLAG_NOLOOK                4
+#define INFO_CLASSIC_FLAG_CROUCH                8
+
 using namespace std;
 using namespace std;
 class Spell;
 class Spell;
 class ZoneServer;
 class ZoneServer;

+ 2 - 2
EQ2/source/WorldServer/SpellProcess.cpp

@@ -43,12 +43,12 @@ SpellProcess::~SpellProcess(){
 	RemoveAllSpells();
 	RemoveAllSpells();
 }
 }
 
 
-void SpellProcess::RemoveAllSpells(){
+void SpellProcess::RemoveAllSpells(bool reload_spells){
 	ClearSpellScriptTimerList();
 	ClearSpellScriptTimerList();
 
 
 	MutexList<LuaSpell*>::iterator active_spells_itr = active_spells.begin();
 	MutexList<LuaSpell*>::iterator active_spells_itr = active_spells.begin();
 	while(active_spells_itr.Next()){
 	while(active_spells_itr.Next()){
-		DeleteCasterSpell(active_spells_itr->value, "", true, 0, true);
+		DeleteCasterSpell(active_spells_itr->value, "", true, 0, !reload_spells);
 	}
 	}
 
 
 	MSpellProcess.lock();
 	MSpellProcess.lock();

+ 1 - 1
EQ2/source/WorldServer/SpellProcess.h

@@ -159,7 +159,7 @@ public:
 	~SpellProcess();
 	~SpellProcess();
 
 
 	/// <summary>Remove all spells from the SpellProcess </summary>
 	/// <summary>Remove all spells from the SpellProcess </summary>
-	void RemoveAllSpells();
+	void RemoveAllSpells(bool reload_spells = false);
 
 
 	/// <summary>Main loop, handles everything (interupts, cast time, recast, ...) </summary>
 	/// <summary>Main loop, handles everything (interupts, cast time, recast, ...) </summary>
 	void Process();
 	void Process();

+ 32 - 1
EQ2/source/WorldServer/Spells.cpp

@@ -697,9 +697,40 @@ void Spell::SetAAPacketInformation(PacketStruct* packet, AltAdvanceData* data, C
 
 
 	}
 	}
 }
 }
+
+sint16 Spell::TranslateClientSpellIcon(int16 version) {
+	sint16 spell_icon = GetSpellIcon();
+	if(version <= 546) {
+		switch(spell_icon) {
+			case 772: // tracking
+				spell_icon = 32; // ??
+				break;
+			case 773: // mining
+				spell_icon = 33; // OK
+				break;
+			case 774: // gathering
+				spell_icon = 56; // OK
+				break;
+			case 775: // fishing
+				spell_icon = 55; // OK
+				break;
+			case 776: // trapping
+				spell_icon = 46; // OK
+				break;
+			case 777: // foresting
+				spell_icon = 125; // OK
+				break;
+			case 778: // collecting
+				spell_icon = 167; // OK
+				break;
+		}
+	}
+	return spell_icon;
+}
+
 void Spell::SetPacketInformation(PacketStruct* packet, Client* client, bool display_tier) {
 void Spell::SetPacketInformation(PacketStruct* packet, Client* client, bool display_tier) {
 	packet->setSubstructDataByName("spell_info", "id", spell->id);
 	packet->setSubstructDataByName("spell_info", "id", spell->id);
-	packet->setSubstructDataByName("spell_info", "icon", spell->icon);
+	packet->setSubstructDataByName("spell_info", "icon", TranslateClientSpellIcon(client->GetVersion()));
 	packet->setSubstructDataByName("spell_info", "icon2", spell->icon_heroic_op);	// fix struct element name eventually
 	packet->setSubstructDataByName("spell_info", "icon2", spell->icon_heroic_op);	// fix struct element name eventually
 	packet->setSubstructDataByName("spell_info", "icontype", spell->icon_backdrop);	// fix struct element name eventually
 	packet->setSubstructDataByName("spell_info", "icontype", spell->icon_backdrop);	// fix struct element name eventually
 
 

+ 1 - 0
EQ2/source/WorldServer/Spells.h

@@ -335,6 +335,7 @@ public:
 	void AddSpellLuaDataBool(bool value, string helper);
 	void AddSpellLuaDataBool(bool value, string helper);
 	void AddSpellLuaDataString(string value, string value2, string helper);
 	void AddSpellLuaDataString(string value, string value2, string helper);
 	int32 GetSpellID();
 	int32 GetSpellID();
+	sint16 TranslateClientSpellIcon(int16 version);
 	void SetPacketInformation(PacketStruct* packet, Client* client = 0, bool display_tier = false);
 	void SetPacketInformation(PacketStruct* packet, Client* client = 0, bool display_tier = false);
 	void SetAAPacketInformation(PacketStruct* packet, AltAdvanceData* data, Client* client = 0, bool display_tier = false);
 	void SetAAPacketInformation(PacketStruct* packet, AltAdvanceData* data, Client* client = 0, bool display_tier = false);
 	int8 GetSpellTier();
 	int8 GetSpellTier();

+ 26 - 16
EQ2/source/WorldServer/World.cpp

@@ -549,7 +549,7 @@ void ZoneList::Remove(ZoneServer* zone) {
 		world.RemoveMaps(std::string(zoneName));
 		world.RemoveMaps(std::string(zoneName));
 	}
 	}
 }
 }
-ZoneServer* ZoneList::Get(const char* zone_name, bool loadZone, bool skip_existing_zones) {
+ZoneServer* ZoneList::Get(const char* zone_name, bool loadZone, bool skip_existing_zones, bool increment_zone) {
 	list<ZoneServer*>::iterator zone_iter;
 	list<ZoneServer*>::iterator zone_iter;
 	ZoneServer* tmp = 0;
 	ZoneServer* tmp = 0;
 	ZoneServer* ret = 0;
 	ZoneServer* ret = 0;
@@ -560,9 +560,13 @@ ZoneServer* ZoneList::Get(const char* zone_name, bool loadZone, bool skip_existi
 			tmp = *zone_iter;
 			tmp = *zone_iter;
 			if (!tmp->isZoneShuttingDown() && !tmp->IsInstanceZone() && strlen(zone_name) == strlen(tmp->GetZoneName()) && 
 			if (!tmp->isZoneShuttingDown() && !tmp->IsInstanceZone() && strlen(zone_name) == strlen(tmp->GetZoneName()) && 
 				strncasecmp(tmp->GetZoneName(), zone_name, strlen(zone_name))==0){
 				strncasecmp(tmp->GetZoneName(), zone_name, strlen(zone_name))==0){
-				if(tmp->NumPlayers() < 30 || tmp->IsCityZone())
+				if(tmp->NumPlayers() < 30 || tmp->IsCityZone()) {
 					ret = tmp;
 					ret = tmp;
-				break;
+					if(increment_zone) {
+						ret->IncrementIncomingClients();
+					}
+					break;
+				}
 			}
 			}
 		}
 		}
 
 
@@ -573,18 +577,15 @@ ZoneServer* ZoneList::Get(const char* zone_name, bool loadZone, bool skip_existi
 	{
 	{
 		if ( loadZone )
 		if ( loadZone )
 		{
 		{
-			ret = new ZoneServer(zone_name, true);
+			ret = new ZoneServer(zone_name);
 			database.LoadZoneInfo(ret);
 			database.LoadZoneInfo(ret);
 			ret->Init();
 			ret->Init();
 		}
 		}
 	}
 	}
-	else if(ret && loadZone) {
-		ret->IncrementIncomingClients();
-	}
 	return ret;
 	return ret;
 }
 }
 
 
-ZoneServer* ZoneList::Get(int32 id, bool loadZone, bool skip_existing_zones) {
+ZoneServer* ZoneList::Get(int32 id, bool loadZone, bool skip_existing_zones, bool increment_zone) {
 	list<ZoneServer*>::iterator zone_iter;
 	list<ZoneServer*>::iterator zone_iter;
 	ZoneServer* tmp = 0;
 	ZoneServer* tmp = 0;
 	ZoneServer* ret = 0;
 	ZoneServer* ret = 0;
@@ -593,16 +594,21 @@ ZoneServer* ZoneList::Get(int32 id, bool loadZone, bool skip_existing_zones) {
 		for(zone_iter=zlist.begin(); zone_iter!=zlist.end(); zone_iter++){
 		for(zone_iter=zlist.begin(); zone_iter!=zlist.end(); zone_iter++){
 			tmp = *zone_iter;
 			tmp = *zone_iter;
 			if(!tmp->isZoneShuttingDown() && !tmp->IsInstanceZone() && tmp->GetZoneID() == id){
 			if(!tmp->isZoneShuttingDown() && !tmp->IsInstanceZone() && tmp->GetZoneID() == id){
-				if(tmp->NumPlayers() < 30 || tmp->IsCityZone())
+				if(tmp->NumPlayers() < 30 || tmp->IsCityZone()) {
 					ret = tmp;
 					ret = tmp;
-				break;
+					if(increment_zone) {
+						ret->IncrementIncomingClients();
+					}
+					break;
+				}
 			}
 			}
 		}
 		}
 		MZoneList.releasereadlock(__FUNCTION__, __LINE__);
 		MZoneList.releasereadlock(__FUNCTION__, __LINE__);
 	}
 	}
 
 
-	if(ret)
+	if(ret) {
 		tmp = ret;
 		tmp = ret;
+	}
 	else if (loadZone) {
 	else if (loadZone) {
 		string zonename = database.GetZoneName(id);
 		string zonename = database.GetZoneName(id);
 		if(zonename.length() >0){
 		if(zonename.length() >0){
@@ -634,7 +640,7 @@ void ZoneList::SendZoneList(Client* client) {
 	MZoneList.releasereadlock(__FUNCTION__, __LINE__);
 	MZoneList.releasereadlock(__FUNCTION__, __LINE__);
 }
 }
 
 
-ZoneServer* ZoneList::GetByInstanceID(int32 id, int32 zone_id, bool skip_existing_zones) {
+ZoneServer* ZoneList::GetByInstanceID(int32 id, int32 zone_id, bool skip_existing_zones, bool increment_zone) {
 	list<ZoneServer*>::iterator zone_iter;
 	list<ZoneServer*>::iterator zone_iter;
 	ZoneServer* tmp = 0;
 	ZoneServer* tmp = 0;
 	ZoneServer* ret = 0;
 	ZoneServer* ret = 0;
@@ -644,17 +650,21 @@ ZoneServer* ZoneList::GetByInstanceID(int32 id, int32 zone_id, bool skip_existin
 		{
 		{
 			for(zone_iter=zlist.begin(); zone_iter!=zlist.end(); zone_iter++){
 			for(zone_iter=zlist.begin(); zone_iter!=zlist.end(); zone_iter++){
 				tmp = *zone_iter;
 				tmp = *zone_iter;
-				if(tmp->GetInstanceID() == id){
-						ret = tmp;
-						break;
+				if(!tmp->isZoneShuttingDown() && tmp->GetInstanceID() == id){
+					ret = tmp;
+					if(increment_zone) {
+						ret->IncrementIncomingClients();
+					}
+					break;
 				}
 				}
 			}
 			}
 		}
 		}
 		MZoneList.releasereadlock(__FUNCTION__, __LINE__);
 		MZoneList.releasereadlock(__FUNCTION__, __LINE__);
 	}
 	}
 
 
-	if(ret)
+	if(ret) {
 		tmp = ret;
 		tmp = ret;
+	}
 	else if ( zone_id > 0 ){
 	else if ( zone_id > 0 ){
 		string zonename = database.GetZoneName(zone_id);
 		string zonename = database.GetZoneName(zone_id);
 		if(zonename.length() > 0){
 		if(zonename.length() > 0){

+ 3 - 3
EQ2/source/WorldServer/World.h

@@ -386,9 +386,9 @@ class ZoneList {
 	
 	
 	void Add(ZoneServer* zone);
 	void Add(ZoneServer* zone);
 	void Remove(ZoneServer* zone);
 	void Remove(ZoneServer* zone);
-	ZoneServer*	Get(int32 id, bool loadZone = true, bool skip_existing_zones = false);
-	ZoneServer* Get(const char* zone_name, bool loadZone=true, bool skip_existing_zones = false);
-	ZoneServer* GetByInstanceID(int32 id, int32 zone_id=0, bool skip_existing_zones = false);
+	ZoneServer*	Get(int32 id, bool loadZone = true, bool skip_existing_zones = false, bool increment_zone = true);
+	ZoneServer* Get(const char* zone_name, bool loadZone=true, bool skip_existing_zones = false, bool increment_zone = true);
+	ZoneServer* GetByInstanceID(int32 id, int32 zone_id=0, bool skip_existing_zones = false, bool increment_zone = true);
 
 
 	/// <summary>Get the instance for the given zone id with the lowest population</summary>
 	/// <summary>Get the instance for the given zone id with the lowest population</summary>
 	/// <param name='zone_id'>The id of the zone to look up</param>
 	/// <param name='zone_id'>The id of the zone to look up</param>

+ 5 - 5
EQ2/source/WorldServer/WorldDatabase.cpp

@@ -2050,20 +2050,20 @@ bool WorldDatabase::loadCharacterProperties(Client* client) {
 		}
 		}
 		else if (!stricmp(prop_name, CHAR_PROPERTY_FLYMODE))
 		else if (!stricmp(prop_name, CHAR_PROPERTY_FLYMODE))
 		{
 		{
-			int8 flymode = atoi(prop_value);
+			int8 flymode = atoul(prop_value);
 			if (flymode) // avoid fly mode notification unless enabled
 			if (flymode) // avoid fly mode notification unless enabled
 				ClientPacketFunctions::SendFlyMode(client, flymode, false);
 				ClientPacketFunctions::SendFlyMode(client, flymode, false);
 		}
 		}
 		else if (!stricmp(prop_name, CHAR_PROPERTY_INVUL))
 		else if (!stricmp(prop_name, CHAR_PROPERTY_INVUL))
 		{
 		{
-			int8 invul = atoi(prop_value);
+			int8 invul = atoul(prop_value);
 			client->GetPlayer()->SetInvulnerable(invul == 1);
 			client->GetPlayer()->SetInvulnerable(invul == 1);
 			if (client->GetPlayer()->GetInvulnerable())
 			if (client->GetPlayer()->GetInvulnerable())
 				client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are now invulnerable!");
 				client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are now invulnerable!");
 		}
 		}
 		else if (!stricmp(prop_name, CHAR_PROPERTY_GMVISION))
 		else if (!stricmp(prop_name, CHAR_PROPERTY_GMVISION))
 		{
 		{
-			int8 val = atoi(prop_value);
+			int8 val = atoul(prop_value);
 			client->GetPlayer()->SetGMVision(val == 1);
 			client->GetPlayer()->SetGMVision(val == 1);
 			client->GetCurrentZone()->SendAllSpawnsForVisChange(client, false);
 			client->GetCurrentZone()->SendAllSpawnsForVisChange(client, false);
 			if (val)
 			if (val)
@@ -2071,7 +2071,7 @@ bool WorldDatabase::loadCharacterProperties(Client* client) {
 		}
 		}
 		else if (!stricmp(prop_name, CHAR_PROPERTY_REGIONDEBUG))
 		else if (!stricmp(prop_name, CHAR_PROPERTY_REGIONDEBUG))
 		{
 		{
-			int8 val = atoi(prop_value);
+			int8 val = atoul(prop_value);
 			
 			
 			client->SetRegionDebug(val == 1);
 			client->SetRegionDebug(val == 1);
 			if (val)
 			if (val)
@@ -2079,7 +2079,7 @@ bool WorldDatabase::loadCharacterProperties(Client* client) {
 		}
 		}
 		else if (!stricmp(prop_name, CHAR_PROPERTY_LUADEBUG))
 		else if (!stricmp(prop_name, CHAR_PROPERTY_LUADEBUG))
 		{
 		{
-			int8 val = atoi(prop_value);
+			int8 val = atoul(prop_value);
 			if (val)
 			if (val)
 			{
 			{
 				client->SetLuaDebugClient(true);
 				client->SetLuaDebugClient(true);

+ 6 - 6
EQ2/source/WorldServer/client.cpp

@@ -2180,7 +2180,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 
 
 				{
 				{
 					player->GetInfoStruct()->subtract_status_points(status_req);
 					player->GetInfoStruct()->subtract_status_points(status_req);
-					ZoneServer* instance_zone = zone_list.GetByInstanceID(0, hz->zone_id);
+					ZoneServer* instance_zone = zone_list.GetByInstanceID(0, hz->zone_id, false, false);
 					int32 upkeep_due = Timer::GetUnixTimeStamp() + 604800; // 604800 = 7 days
 					int32 upkeep_due = Timer::GetUnixTimeStamp() + 604800; // 604800 = 7 days
 					int64 unique_id = database.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, instance_zone->GetInstanceID(), upkeep_due);
 					int64 unique_id = database.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, instance_zone->GetInstanceID(), upkeep_due);
 					world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
 					world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
@@ -2201,7 +2201,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 							break;
 							break;
 						}
 						}
 
 
-						ZoneServer* instance_zone = zone_list.GetByInstanceID(0, hz->zone_id);
+						ZoneServer* instance_zone = zone_list.GetByInstanceID(0, hz->zone_id, false, false);
 						int32 upkeep_due = Timer::GetUnixTimeStamp() + 604800; // 604800 = 7 days
 						int32 upkeep_due = Timer::GetUnixTimeStamp() + 604800; // 604800 = 7 days
 						int64 unique_id = database.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, instance_zone->GetInstanceID(), upkeep_due);
 						int64 unique_id = database.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, instance_zone->GetInstanceID(), upkeep_due);
 						world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
 						world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
@@ -2230,7 +2230,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 			if (ph) {
 			if (ph) {
 				HouseZone* hz = world.GetHouseZone(ph->house_id);
 				HouseZone* hz = world.GetHouseZone(ph->house_id);
 				if (hz) {
 				if (hz) {
-					ZoneServer* house = zone_list.GetByInstanceID(ph->instance_id, hz->zone_id);
+					ZoneServer* house = zone_list.GetByInstanceID(ph->instance_id, hz->zone_id, false, true);
 					if (house) {
 					if (house) {
 						Zone(house, true);
 						Zone(house, true);
 					}
 					}
@@ -4127,7 +4127,7 @@ ZoneServer* Client::IdentifyInstance(int32 zoneID) {
 			}
 			}
 
 
 			// Need to update `character_instances` table with new timestamps (for persistent) and instance id's
 			// Need to update `character_instances` table with new timestamps (for persistent) and instance id's
-			instance_zone = zone_list.GetByInstanceID(data->instance_id, zoneID);
+			instance_zone = zone_list.GetByInstanceID(data->instance_id, zoneID, false, false);
 
 
 			// if we got an instance_zone and the instance_id from the data is 0 or data instance id is not the same as the zone instance id then update values
 			// if we got an instance_zone and the instance_id from the data is 0 or data instance id is not the same as the zone instance id then update values
 			if (instance_zone && (data->instance_id == 0 || data->instance_id != instance_zone->GetInstanceID())) {
 			if (instance_zone && (data->instance_id == 0 || data->instance_id != instance_zone->GetInstanceID())) {
@@ -4287,7 +4287,7 @@ bool Client::CheckZoneAccess(const char* zoneName) {
 
 
 	LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone access check for %s (%u), client: %u", zoneName, database.GetZoneID(zoneName), GetVersion());
 	LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone access check for %s (%u), client: %u", zoneName, database.GetZoneID(zoneName), GetVersion());
 
 
-	ZoneServer* zone = zone_list.Get(zoneName, false);
+	ZoneServer* zone = zone_list.Get(zoneName, false, false, false);
 
 
 	// JA: implemented /zone lock|unlock commands (2012.07.28)
 	// JA: implemented /zone lock|unlock commands (2012.07.28)
 	if (zone && zone->GetZoneLockState())
 	if (zone && zone->GetZoneLockState())
@@ -4368,7 +4368,7 @@ bool Client::CheckZoneAccess(const char* zoneName) {
 }
 }
 
 
 void Client::Zone(int32 instanceid, bool set_coords, bool byInstanceID, bool is_spell) {
 void Client::Zone(int32 instanceid, bool set_coords, bool byInstanceID, bool is_spell) {
-	Zone(zone_list.GetByInstanceID(instanceid), set_coords, is_spell);
+	Zone(zone_list.GetByInstanceID(instanceid, 0, false, true), set_coords, is_spell);
 
 
 }
 }
 
 

+ 15 - 9
EQ2/source/WorldServer/zoneserver.cpp

@@ -119,12 +119,9 @@ extern MasterSkillList master_skill_list;
 int32 MinInstanceID = 1000;
 int32 MinInstanceID = 1000;
 
 
 // JA: Moved most default values to Rules and risky initializers to ZoneServer::Init() - 2012.12.07
 // JA: Moved most default values to Rules and risky initializers to ZoneServer::Init() - 2012.12.07
-ZoneServer::ZoneServer(const char* name, bool incoming_client) {
+ZoneServer::ZoneServer(const char* name) {
 	incoming_clients = 0;
 	incoming_clients = 0;
 	
 	
-	if(incoming_client)
-		IncrementIncomingClients();
-	
 	MIncomingClients.SetName("ZoneServer::MIncomingClients");
 	MIncomingClients.SetName("ZoneServer::MIncomingClients");
 
 
 	depop_zone = false;
 	depop_zone = false;
@@ -258,13 +255,18 @@ ZoneServer::~ZoneServer() {
 void ZoneServer::IncrementIncomingClients() { 
 void ZoneServer::IncrementIncomingClients() { 
 	MIncomingClients.writelock(__FUNCTION__, __LINE__);
 	MIncomingClients.writelock(__FUNCTION__, __LINE__);
 	incoming_clients++;
 	incoming_clients++;
+	LogWrite(ZONE__INFO, 0, "Zone", "Increment incoming clients of '%s' zoneid %u (instance id: %u).  Current incoming client count: %u", zone_name, zoneID, instanceID, incoming_clients);
 	MIncomingClients.releasewritelock(__FUNCTION__, __LINE__);
 	MIncomingClients.releasewritelock(__FUNCTION__, __LINE__);
 }
 }
 
 
 void ZoneServer::DecrementIncomingClients() { 
 void ZoneServer::DecrementIncomingClients() { 
 	MIncomingClients.writelock(__FUNCTION__, __LINE__);
 	MIncomingClients.writelock(__FUNCTION__, __LINE__);
+	bool zeroed = false;
 	if(incoming_clients)
 	if(incoming_clients)
 		incoming_clients--;
 		incoming_clients--;
+	else
+		zeroed = true;
+	LogWrite(ZONE__INFO, 0, "Zone", "Decrement incoming clients of '%s' zoneid %u (instance id: %u).  Current incoming client count: %u (was client count previously zero: %u)", zone_name, zoneID, instanceID, incoming_clients, zeroed);
 	MIncomingClients.releasewritelock(__FUNCTION__, __LINE__);
 	MIncomingClients.releasewritelock(__FUNCTION__, __LINE__);
 }
 }
 
 
@@ -282,7 +284,6 @@ void ZoneServer::Init()
 	shutdownTimer.Disable();
 	shutdownTimer.Disable();
 	spawn_range.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackPlayer)->GetInt32());
 	spawn_range.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackPlayer)->GetInt32());
 	aggro_timer.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackNPC)->GetInt32());
 	aggro_timer.Start(rule_manager.GetGlobalRule(R_Zone, CheckAttackNPC)->GetInt32());
-
 	/* Weather stuff */
 	/* Weather stuff */
 	InitWeather();
 	InitWeather();
 
 
@@ -450,6 +451,7 @@ void ZoneServer::DeleteSpellProcess(){
 	MMasterZoneLock->unlock();
 	MMasterZoneLock->unlock();
 	MMasterSpawnLock.releasewritelock(__FUNCTION__, __LINE__);
 	MMasterSpawnLock.releasewritelock(__FUNCTION__, __LINE__);
 	DismissAllPets();
 	DismissAllPets();
+	spellProcess->RemoveAllSpells(true);
 	safe_delete(spellProcess);
 	safe_delete(spellProcess);
 }
 }
 
 
@@ -1452,7 +1454,7 @@ bool ZoneServer::Process()
 			{
 			{
 				SetWatchdogTime(Timer::GetCurrentTime2());
 				SetWatchdogTime(Timer::GetCurrentTime2());
 				// Client loop
 				// Client loop
-				ClientProcess();
+				ClientProcess(true);
 				Sleep(10);
 				Sleep(10);
 			}
 			}
 
 
@@ -1488,6 +1490,8 @@ bool ZoneServer::Process()
 					break;
 					break;
 			}
 			}
 	
 	
+			startupDelayTimer.Start(60000); // this is hard coded for 60 seconds after the zone is loaded to allow a client to at least add itself to the list before we start zone shutdown timer
+			
 			MMasterZoneLock->lock();
 			MMasterZoneLock->lock();
 			
 			
 			LoadingData = false;
 			LoadingData = false;
@@ -1522,7 +1526,9 @@ bool ZoneServer::Process()
 			SendCharSheetChanges();
 			SendCharSheetChanges();
 
 
 		// Client loop
 		// Client loop
-		ClientProcess();
+		ClientProcess(startupDelayTimer.Enabled());
+		if(startupDelayTimer.Check())
+			startupDelayTimer.Disable();
 
 
 		if(spellProcess)
 		if(spellProcess)
 			spellProcess->Process();
 			spellProcess->Process();
@@ -3391,9 +3397,9 @@ void ZoneServer::RemoveClientImmediately(Client* client) {
 	}
 	}
 }
 }
 
 
-void ZoneServer::ClientProcess()
+void ZoneServer::ClientProcess(bool ignore_shutdown_timer)
 {
 {
-	if(connected_clients.size(true) == 0)
+	if(!ignore_shutdown_timer && connected_clients.size(true) == 0)
 	{
 	{
 		MIncomingClients.readlock(__FUNCTION__, __LINE__);
 		MIncomingClients.readlock(__FUNCTION__, __LINE__);
 		bool shutdownDelayCheck = shutdownDelayTimer.Check();
 		bool shutdownDelayCheck = shutdownDelayTimer.Check();

+ 5 - 4
EQ2/source/WorldServer/zoneserver.h

@@ -276,7 +276,7 @@ enum SUBSPAWN_TYPES {
 // need to attempt to clean this up and add xml comments, remove unused code, find a logical way to sort the functions maybe by get/set/process/add etc...
 // need to attempt to clean this up and add xml comments, remove unused code, find a logical way to sort the functions maybe by get/set/process/add etc...
 class ZoneServer {
 class ZoneServer {
 public:
 public:
-	ZoneServer(const char* file, bool incoming_client=false);
+	ZoneServer(const char* file);
     ~ZoneServer();
     ~ZoneServer();
 	
 	
 	void		IncrementIncomingClients();
 	void		IncrementIncomingClients();
@@ -735,7 +735,7 @@ private:
 	/*
 	/*
 	Following functions were public but never used outside the zone server so moved them to private
 	Following functions were public but never used outside the zone server so moved them to private
 	*/
 	*/
-	void	ClientProcess();																					// never used outside zone server
+	void	ClientProcess(bool ignore_shutdown_timer = false);													// never used outside zone server
 	void	RemoveClient(Client* client);																		// never used outside zone server
 	void	RemoveClient(Client* client);																		// never used outside zone server
 	void	DeterminePosition(SpawnLocation* spawnlocation, Spawn* spawn);										// never used outside zone server
 	void	DeterminePosition(SpawnLocation* spawnlocation, Spawn* spawn);										// never used outside zone server
 	void	AddDeadSpawn(Spawn* spawn, int32 timer = 0xFFFFFFFF);												// never used outside zone server
 	void	AddDeadSpawn(Spawn* spawn, int32 timer = 0xFFFFFFFF);												// never used outside zone server
@@ -893,6 +893,7 @@ private:
 	Timer	regenTimer;
 	Timer	regenTimer;
 	Timer	respawn_timer;
 	Timer	respawn_timer;
 	Timer	shutdownTimer;
 	Timer	shutdownTimer;
+	Timer	startupDelayTimer;
 	Timer	spawn_check_add;
 	Timer	spawn_check_add;
 	Timer	spawn_check_remove;
 	Timer	spawn_check_remove;
 	Timer	spawn_expire_timer;
 	Timer	spawn_expire_timer;
@@ -914,8 +915,8 @@ private:
 	volatile bool	repop_zone;
 	volatile bool	repop_zone;
 	volatile bool	respawns_allowed;
 	volatile bool	respawns_allowed;
 	volatile bool	LoadingData;
 	volatile bool	LoadingData;
-	bool    reloading_spellprocess;
-	bool	zoneShuttingDown;
+	std::atomic<bool> reloading_spellprocess;
+	std::atomic<bool> zoneShuttingDown;
 	bool	cityzone;
 	bool	cityzone;
 	bool	always_loaded;
 	bool	always_loaded;
 	bool	isInstance;	
 	bool	isInstance;	

+ 11 - 9
server/WorldStructs.xml

@@ -6461,11 +6461,14 @@ to zero and treated like placeholders." />
 <Data ElementName="size_unknown" Type="float" />
 <Data ElementName="size_unknown" Type="float" />
 <Data ElementName="unknown4" Type="int8" />
 <Data ElementName="unknown4" Type="int8" />
 </Struct>
 </Struct>
-<Struct Name="WS_ServerControlFlags" ClientVersion="1" OpcodeName="OP_ChangeServerControlFlagMsg" >
-<Data ElementName="parameter1" Type="int8" />
-<Data ElementName="parameter2" Type="int8" />
-<Data ElementName="parameter3" Type="int8" />
-<Data ElementName="value" Type="int8" />
+<!-- classic uses opcode OP_UpdateClientPredFlagsMsg instead of OP_ChangeServerControlFlagMsg -->
+<Struct Name="WS_ServerControlFlags" ClientVersion="1" OpcodeName="OP_UpdateClientPredFlagsMsg" >
+<Data ElementName="parameter" Type="int32" />
+<Data ElementName="value" Type="int32" />
+</Struct>
+<Struct Name="WS_ServerControlFlags" ClientVersion="546" OpcodeName="OP_UpdateClientPredFlagsMsg" >
+<Data ElementName="parameter" Type="int32" />
+<Data ElementName="value" Type="int32" />
 </Struct>
 </Struct>
 <Struct Name="WS_ServerControlFlags" ClientVersion="547" OpcodeName="OP_ChangeServerControlFlagMsg" >
 <Struct Name="WS_ServerControlFlags" ClientVersion="547" OpcodeName="OP_ChangeServerControlFlagMsg" >
 <Data ElementName="parameter1" Type="int8" />
 <Data ElementName="parameter1" Type="int8" />
@@ -15936,12 +15939,11 @@ to zero and treated like placeholders." />
 <Data ElementName="skill_id" Type="int32" Size="6"/>
 <Data ElementName="skill_id" Type="int32" Size="6"/>
 </Struct>
 </Struct>
 <Struct Name="WS_ShowItemCreation" ClientVersion="546" OpcodeName="OP_ShowItemCreationProcessUIMsg">
 <Struct Name="WS_ShowItemCreation" ClientVersion="546" OpcodeName="OP_ShowItemCreationProcessUIMsg">
-<!-- starting durability maybe?-->
 <Data ElementName="max_possible_durability" Type="int32" Size="1" />
 <Data ElementName="max_possible_durability" Type="int32" Size="1" />
 <Data ElementName="max_possible_progress" Type="int32" Size="1" />
 <Data ElementName="max_possible_progress" Type="int32" Size="1" />
 <Data ElementName="unknown2" Type="int32" Size="2" />
 <Data ElementName="unknown2" Type="int32" Size="2" />
 <Data ElementName="progress_levels_known" Type="int8" Size="1" />
 <Data ElementName="progress_levels_known" Type="int8" Size="1" />
-<Data ElementName="num_process" Type="int8" Size="1" />
+<Data ElementName="num_process" Type="int16" Size="1" />
 <Data ElementName="process_array" Type="Array" ArraySizeVariable="num_process">
 <Data ElementName="process_array" Type="Array" ArraySizeVariable="num_process">
   <Data ElementName="progress_needed" Type="int32" Size="1" />
   <Data ElementName="progress_needed" Type="int32" Size="1" />
   <Data ElementName="unknown3" Type="int8" Size="1" IfVariableNotSet="progress_needed"/>
   <Data ElementName="unknown3" Type="int8" Size="1" IfVariableNotSet="progress_needed"/>
@@ -15952,7 +15954,7 @@ to zero and treated like placeholders." />
   <Data ElementName="item_byproduct_icon" Type="int16" />
   <Data ElementName="item_byproduct_icon" Type="int16" />
   <!-- Another EQ2_Item? Does subtype set to FF prevent the rest of the packet?-->
   <!-- Another EQ2_Item? Does subtype set to FF prevent the rest of the packet?-->
   <!-- If not an EQ2_item this unknown *might* be quantity-->
   <!-- If not an EQ2_item this unknown *might* be quantity-->
-  <Data ElementName="item_byproduct_unknown" Type="int8" />
+  <Data ElementName="item_byproduct_unknown" Type="int16" />
   <Data ElementName="packettype" Type="int16" />
   <Data ElementName="packettype" Type="int16" />
   <Data ElementName="packetsubtype" Type="int8" />
   <Data ElementName="packetsubtype" Type="int8" />
 </Data>
 </Data>
@@ -15962,7 +15964,7 @@ to zero and treated like placeholders." />
 <Data ElementName="product_item" Type="EQ2_Item" />
 <Data ElementName="product_item" Type="EQ2_Item" />
 <Data ElementName="product_byproduct_name" Type="EQ2_16Bit_String" />
 <Data ElementName="product_byproduct_name" Type="EQ2_16Bit_String" />
 <Data ElementName="product_byproduct_icon" Type="int16" />
 <Data ElementName="product_byproduct_icon" Type="int16" />
-<Data ElementName="product_byproduct_unknown" Type="int8" />
+<Data ElementName="product_byproduct_unknown" Type="int16" />
 <Data ElementName="packettype" Type="int16" />
 <Data ElementName="packettype" Type="int16" />
 <Data ElementName="packetsubtype" Type="int8" />
 <Data ElementName="packetsubtype" Type="int8" />
 <Data ElementName="skill_id" Type="int32" Size="6"/>
 <Data ElementName="skill_id" Type="int32" Size="6"/>