Browse Source

Isle of Refuge March 2005 Client **BETA** Support!!

Isle of Refuge/Classic CD Release updates:
- Fixed loading ui timeout for spells with higher tiers (And we have no default 0 tier).
  *To note there is one outstanding timeout observed with spell serialization in DoF/KoS client https://git.eq2emu.com/devn00b/EQ2EMu/issues/568 put "cl_load_ui_resources_timeout 0" in eq2_default.ini as workaround.
- Fixed pet commands for older clients, stayhere, followme, guardme, guardhere (not sure this is the proper logic for this command did it change in later clients?)
- Beta on EQ2 Release CD Disc fixed to no longer warp constantly while moving around.  This client does not like receiving self position updates in bulk.
- Fixed other player position updates when on isle of refuge/cd release of EQ2.  Previously they would just throw the player all over the place no rhyme or reason.  Apparently these clients only like the bulk changes from Client::SendSpawnChanges

Caveats to Isle of Refuge Client:
- NOTE UNEXPECTED BEHAVIOR WITH IOR/BETA CD: Isle of Refuge/Beta Release CD still has an outstanding issue in that it receives a spawn update, it pauses sending position updates to the server causing a hiccup of updates.  It is also inconsistent with how it updates so there is more a "step step" movement from those players to other clients.
See issue https://git.eq2emu.com/devn00b/EQ2EMu/issues/566
- Collections are not supported right now on Isle of Refuge/Classic CD Release as no collections tab exists, see https://git.eq2emu.com/devn00b/EQ2EMu/issues/567
- Zones are limited to the Boat (farjourneyfreeport/boat_06p_tutorial02) and Isle of Refuge (islerefuge1/tutorial_island02).  Client does not have any other zone files available at this time.  Admins can bypass at your own risk.

Multi client updates:
- Fixed Waypoint structure for button in the journal menu for KoS/DoF/Classic clients (still need to support waypoints in quests, no design for that implemented yet)
- Fixed some misc structure sizing for DoF/KoS
- No longer consume food/drink that does not have an item script applied since we cannot properly track duration (via the item script + spell)
- Regression fix for https://git.eq2emu.com/devn00b/EQ2EMu/commit/02f6f2a1af6cde44a16a340b1ccac13d96dc7d67 - fixed levelling not properly setting HP/Power (it would show a strange character sheet update where stats turn red instead).
- Fixed NPC spawns overrunning their target in combat and continuing to run past (as if delta'ing forever).
- Fixed DoF/KoS client showing players continuing to run when they are at a stop (position updates were not being sent due to a xor flag check).  Isle of Refuge/Beta Disc still seem to suffer this problem, if you move your heading left/right it will reset your position correctly with other clients.
- (Workaround KoS and earlier clients, not AoM) Player position updates will not be providing pos_dest_loc_offset or pos_dest_loc_offset2 due to warping (all over the place).  NPCs function fine with these properties.

KoS client updates:
- Fixed KoS client merchants working fully now
- Fixed underworld (dying sound) for KoS client
- Fixed character sheet, bind and house zone now properly set, no compression error in client alert log.

New Server Features:
- New LUA Function: GetSpellInitialTarget() inside spell script, GetSpellInitialTarget(Spell) outside of spell script.  Returns Spawn pointer of initial target for spell.

Server Combat Changes:
- Hard coded minimum parry chance of 10%
- Hard coded minimum block chance of 30%
Emagi 3 months ago
parent
commit
41738ba225
38 changed files with 2014 additions and 296 deletions
  1. 42 0
      DB/updates/latest_login_opcodes_june6_2024.sql
  2. 42 0
      DB/updates/latest_opcodes_june6_2024.sql
  3. 41 0
      DB/updates/latest_spell_error_versions_june6_2024.sql
  4. 2 0
      EQ2/source/LoginServer/PacketHeaders.h
  5. 11 5
      EQ2/source/LoginServer/client.cpp
  6. 1 0
      EQ2/source/LoginServer/client.h
  7. 2 2
      EQ2/source/LoginServer/login_structs.h
  8. 1 1
      EQ2/source/WorldServer/ClientPacketFunctions.cpp
  9. 8 0
      EQ2/source/WorldServer/Combat.cpp
  10. 55 27
      EQ2/source/WorldServer/Commands/Commands.cpp
  11. 46 34
      EQ2/source/WorldServer/Items/Items.cpp
  12. 3 3
      EQ2/source/WorldServer/Items/Items.h
  13. 30 1
      EQ2/source/WorldServer/LuaFunctions.cpp
  14. 2 0
      EQ2/source/WorldServer/LuaFunctions.h
  15. 2 0
      EQ2/source/WorldServer/LuaInterface.cpp
  16. 60 20
      EQ2/source/WorldServer/Player.cpp
  17. 28 0
      EQ2/source/WorldServer/Player.h
  18. 9 3
      EQ2/source/WorldServer/Quests.cpp
  19. 1 0
      EQ2/source/WorldServer/Quests.h
  20. 5 2
      EQ2/source/WorldServer/Skills.cpp
  21. 50 35
      EQ2/source/WorldServer/Spawn.cpp
  22. 2 2
      EQ2/source/WorldServer/Spawn.h
  23. 2 2
      EQ2/source/WorldServer/Spells.cpp
  24. 1 1
      EQ2/source/WorldServer/Tradeskills/TradeskillsPackets.cpp
  25. 1 1
      EQ2/source/WorldServer/Traits/Traits.cpp
  26. 255 67
      EQ2/source/WorldServer/client.cpp
  27. 5 0
      EQ2/source/WorldServer/client.h
  28. 9 5
      EQ2/source/WorldServer/zoneserver.cpp
  29. 7 3
      EQ2/source/common/EQ2_Common_Structs.h
  30. 4 0
      EQ2/source/common/EQPacket.cpp
  31. 1 1
      EQ2/source/common/MiscFunctions.cpp
  32. 22 14
      EQ2/source/common/PacketStruct.cpp
  33. 3 3
      EQ2/source/common/PacketStruct.h
  34. 42 0
      server/CommonStructs.xml
  35. 289 7
      server/ItemStructs.xml
  36. 66 1
      server/LoginStructs.xml
  37. 176 7
      server/SpawnStructs.xml
  38. 688 49
      server/WorldStructs.xml

File diff suppressed because it is too large
+ 42 - 0
DB/updates/latest_login_opcodes_june6_2024.sql


File diff suppressed because it is too large
+ 42 - 0
DB/updates/latest_opcodes_june6_2024.sql


File diff suppressed because it is too large
+ 41 - 0
DB/updates/latest_spell_error_versions_june6_2024.sql


+ 2 - 0
EQ2/source/LoginServer/PacketHeaders.h

@@ -21,6 +21,7 @@ extern ConfigReader configReader;
 class CharSelectProfile : public DataBuffer{
 public:
 	CharSelectProfile(int16 version){
+		deleted = false;
 		packet = configReader.getStruct("CharSelectProfile",version);
 		for(int8 i=0;i<24;i++){
 			packet->setEquipmentByName("equip",0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,i);
@@ -35,6 +36,7 @@ public:
 	void				SaveData(int16 in_version);
 	void				Data();
 	int16				size;
+	bool				deleted;
 };
 
 class LS_CharSelectList : public DataBuffer {

+ 11 - 5
EQ2/source/LoginServer/client.cpp

@@ -74,6 +74,7 @@ Client::Client(EQStream* ieqnc) {
 	update_position = 0;
 	update_packets = 0;
 	needs_world_list = true;
+	sent_character_list = false;
 }
 
 Client::~Client() {
@@ -243,7 +244,10 @@ bool Client::Process() {
 			case OP_AllWSDescRequestMsg:{				
 				SendWorldList();
 				needs_world_list = false;
-				database.LoadCharacters(GetLoginAccount(), GetVersion());				
+				if(!sent_character_list) {
+					database.LoadCharacters(GetLoginAccount(), GetVersion());
+					sent_character_list = true;
+				}				
 				SendCharList();				
 				break;
 										}
@@ -290,6 +294,7 @@ bool Client::Process() {
 					}
 					else
 					{
+						createRequest = packet;
 						ServerPacket* outpack = new ServerPacket(ServerOP_CharacterCreate, app->size+sizeof(int16));
 						int16 out_version = GetVersion();
 						memcpy(outpack->pBuffer, &out_version, sizeof(int16));
@@ -298,14 +303,16 @@ bool Client::Process() {
 						
 						if(out_version<=283)	
 							tmp+=2;	
-						else	
+						else if(out_version == 373) {
+							tmp += 6;
+						}
+						else
 							tmp += 7;
 						
 						int32 account_id = GetAccountID();
 						memcpy(tmp, &account_id, sizeof(int32));
 						world_server->SendPacket(outpack);
 						safe_delete(outpack);
-						createRequest = packet;
 					}
 				}
 				else{
@@ -319,7 +326,6 @@ bool Client::Process() {
 				int32 char_id = 0;
 				int32 server_id = 0;
 				PacketStruct* request = configReader.getStruct("LS_PlayRequest",GetVersion());
-
 				if(request && request->LoadPacketData(app->pBuffer,app->size)){
 					char_id = request->getType_int32_ByName("char_id");
 					if (GetVersion() <= 283) {	
@@ -412,7 +418,7 @@ bool Client::Process() {
 void Client::SaveErrorsToDB(EQApplicationPacket* app, char* type, int32 version){
 	int32 size = 0;
 	z_stream zstream;
-	if (version >= 284) {
+	if (version >= 546) {
 		memcpy(&size, app->pBuffer + sizeof(int32), sizeof(int32));
 		zstream.next_in = app->pBuffer + 8;
 		zstream.avail_in = app->size - 8;

+ 1 - 0
EQ2/source/LoginServer/client.h

@@ -97,6 +97,7 @@ private:
 	bool	needs_world_list;
 	int16	version;
 	char	bannedreason[30];
+	bool	sent_character_list;
 	eLoginMode LoginMode;
 	PacketStruct* createRequest;
 	Timer* playWaitTimer;

+ 2 - 2
EQ2/source/LoginServer/login_structs.h

@@ -41,7 +41,7 @@ struct LS_CharListAccountInfoEarlyClient {
 	int32	unknown1;	
 	int16	unknown2;	
 	int32   maxchars;	
-	int8	unknown4;	
+	int8	unknown4; // 15 bytes total	
 	//	int8	unknown7; // adds 'free' option..	
 };
 	
@@ -55,7 +55,7 @@ struct LS_CharListAccountInfo{
 	int32	unknown5[4];
 	int8	vet_adv_bonus;  // sets Veteran Bonus under 'Select Character' yellow (vs greyed out), adventure/tradeskill bonus 200%
 	int8	vet_trade_bonus;  // when 1 (count?) provides free upgrade option for character to lvl 90 (heroic character) -- its a green 'Free' up arrow next to the character that is selected in char select
-};
+}; // 33 bytes
 #pragma pack()
 
 #endif

+ 1 - 1
EQ2/source/WorldServer/ClientPacketFunctions.cpp

@@ -180,7 +180,7 @@ void ClientPacketFunctions::SendCharacterMacros(Client* client) {
 					LogWrite(PACKET__DEBUG, 5, "Packet", "Loading Macro %i, name: %s", itr->first, itr->second[0]->name.c_str());
 					macro_packet->setArrayDataByName("name", itr->second[0]->name.c_str(), x);
 				}
-				if (client->GetVersion() > 283) {
+				if (client->GetVersion() > 373) {
 					char tmp_details_count[25] = { 0 };
 					sprintf(tmp_details_count, "macro_details_count_%i", x);
 					macro_packet->setArrayLengthByName(tmp_details_count, itr->second.size());

+ 8 - 0
EQ2/source/WorldServer/Combat.cpp

@@ -823,6 +823,10 @@ int8 Entity::DetermineHit(Spawn* victim, int8 type, int8 damage_type, float ToHi
 			float parryChance = entity_victim->GetInfoStruct()->get_parry();
 			float chanceValue = (100.0f - parryChance);
 
+			if(chanceValue < 10.0f) { // min default per https://eq2.fandom.com/wiki/Update:29
+				chanceValue = 10.0f; // this becomes 5.0f at EoF
+			}
+			
 			if(rand()%roll_chance >= chanceValue){ //successful parry
 				/* You may only riposte things in the front quadrant.
 				Riposte is based off of parry: a certain % of parries turn into ripostes.
@@ -852,6 +856,10 @@ int8 Entity::DetermineHit(Spawn* victim, int8 type, int8 damage_type, float ToHi
 		{
 			blockChance += (blockChance*(entity_victim->GetInfoStruct()->get_block_chance()/100.0f));
 			float chanceValue = (100.0f - blockChance);
+			\
+			if(chanceValue < 30.0f) { // min default per https://eq2.fandom.com/wiki/Update:29
+				chanceValue = 30.0f; // this becomes 25.0f at EoF
+			}
 			/* Non-brawlers may only block things in the front quadrant.
 			Riposte is based off of parry: a certain % of parries turn into ripostes.
 			*/

+ 55 - 27
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -8172,7 +8172,7 @@ void Commands::Command_Pet(Client* client, Seperator* sep)
 		return;
 	}
 	
-	if (strcmp(sep->arg[0], "stay") == 0) {
+	if (strcmp(sep->arg[0], "stay") == 0 || strcmp(sep->arg[0], "stayhere") == 0) {
 		client->Message(CHANNEL_COLOR_YELLOW, "You command your pet to stay.");
 		client->GetPlayer()->GetInfoStruct()->set_pet_movement(1);
 		client->GetPlayer()->SetCharSheetChanged(true);
@@ -8181,12 +8181,12 @@ void Commands::Command_Pet(Client* client, Seperator* sep)
 		if (client->GetPlayer()->GetCharmedPet())
 			client->GetPlayer()->GetCharmedPet()->following = false;
 	}
-	else if (strcmp(sep->arg[0], "follow") == 0) {
+	else if (strcmp(sep->arg[0], "follow") == 0 || strcmp(sep->arg[0], "followme") == 0) {
 		client->Message(CHANNEL_COLOR_YELLOW, "You command your pet to follow.");
 		client->GetPlayer()->GetInfoStruct()->set_pet_movement(2);
 		client->GetPlayer()->SetCharSheetChanged(true);
 	}
-	else if (strcmp(sep->arg[0], "preserve_master") == 0) {
+	else if (strcmp(sep->arg[0], "preserve_master") == 0 || strcmp(sep->arg[0], "guardme") == 0) {
 		if (client->GetPlayer()->GetInfoStruct()->get_pet_behavior() & 1) {
 			client->Message(CHANNEL_COLOR_YELLOW, "Your pet will no longer protect you.");
 			client->GetPlayer()->GetInfoStruct()->set_pet_behavior(client->GetPlayer()->GetInfoStruct()->get_pet_behavior()-1);
@@ -8197,7 +8197,7 @@ void Commands::Command_Pet(Client* client, Seperator* sep)
 		}
 		client->GetPlayer()->SetCharSheetChanged(true);
 	}
-	else if (strcmp(sep->arg[0], "preserve_self") == 0) {
+	else if (strcmp(sep->arg[0], "preserve_self") == 0 || strcmp(sep->arg[0], "guardhere") == 0) { // guardhere might be accurate, diff logic
 		if (client->GetPlayer()->GetInfoStruct()->get_pet_behavior() & 2) {
 			client->Message(CHANNEL_COLOR_YELLOW, "Your pet will no longer protect itself.");
 			client->GetPlayer()->GetInfoStruct()->set_pet_behavior(client->GetPlayer()->GetInfoStruct()->get_pet_behavior()-2);
@@ -8240,7 +8240,7 @@ void Commands::Command_Pet(Client* client, Seperator* sep)
 		client->Message(CHANNEL_COLOR_YELLOW, "You tell your pet to get lost.");
 	}
 	else
-		client->Message(CHANNEL_COLOR_YELLOW, "Unknown pet command.");
+		client->Message(CHANNEL_COLOR_YELLOW, "Unknown pet command %s.", sep->arg[0]);
 	
 }
 
@@ -9205,7 +9205,7 @@ void Commands::Command_Toggle_AutoConsume(Client* client, Seperator* sep)
 	{
 		int8 slot = atoi(sep->arg[0]);
 		int8 flag = atoi(sep->arg[1]);
-		if (client->GetVersion() <= 283) {
+		if (client->GetVersion() <= 373) {
 			slot += 4;
 		}
 		else if (client->GetVersion() <= 561) {
@@ -10173,7 +10173,7 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 		else if (atoi(sep->arg[0]) == 12) {
 			PacketStruct* packet2 = configReader.getStruct("WS_QuestJournalReply", client->GetVersion());
 			if (packet2) {
-				packet2->setDataByName("quest_id", 524);
+				packet2->setDataByName("quest_id", 5725);
 				packet2->setDataByName("player_crc", 2900677088);
 				packet2->setDataByName("name", "Archetype Selection");
 				packet2->setDataByName("description", "I have reported my profession to Garven Tralk.");
@@ -10211,7 +10211,7 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 				packet2->setSubstructArrayDataByName("reward_data", "reward_id", 123);
 				Item* item = master_item_list.GetItem(152755);
 				packet2->setArrayDataByName("reward_id", item->details.item_id);
-				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, -1);
+				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, client->GetClientItemPacketOffset());
 				/*packet2->setSubstructDataByName("item", "unique_id", 567);
 				packet2->setSubstructDataByName("item", "broker_item_id", 0xFFFFFFFFFFFFFFFF);
 				packet2->setSubstructDataByName("item", "icon", 0xe7);
@@ -10331,9 +10331,9 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 				Spawn* spawn = client->GetPlayer()->GetTarget();
 				if (spawn)
 					packet2->setDataByName("object_id", client->GetPlayer()->GetIDWithPlayerSpawn(spawn));
-				packet2->setDataByName("unknown3", 1);
-				packet2->setDataByName("unknown4", 1);
-				packet2->setDataByName("unknown5", 60);
+				packet2->setDataByName("display", 1);
+				packet2->setDataByName("loot_type", 1);
+				packet2->setDataByName("lotto_timeout", 60);
 				EQ2Packet* app = packet2->serialize();
 				DumpPacket(app);
 				client->QueuePacket(app);
@@ -10362,13 +10362,13 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 				packet2->setSubstructDataByName("reward_data", "reward", "Quest Reward!");
 				packet2->setSubstructDataByName("reward_data", "max_coin", 0);
 				packet2->setSubstructDataByName("reward_data", "text", "Some custom text to mess things up?");
-				//packet2->setSubstructDataByName("reward_data", "status_points", 5);
+				packet2->setSubstructDataByName("reward_data", "status_points", 5);
 				//packet2->setSubstructDataByName("reward_data", "exp_bonus", 10);
 				packet2->setSubstructArrayLengthByName("reward_data", "num_rewards", 1);
 				Item* item = new Item(master_item_list.GetItem(9357));
 				packet2->setArrayDataByName("reward_id", item->details.item_id);
 				//item->stack_count = 20;
-				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, -1);
+				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, client->GetClientItemPacketOffset());
 				safe_delete(item);
 				/*item = new Item(master_item_list.GetItem(36685));
 				item->stack_count = 20;
@@ -10505,7 +10505,7 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 				Item* item = new Item(master_item_list.GetItem(36212));
 				packet2->setArrayDataByName("reward_id", item->details.item_id);
 				item->stack_count = 20;
-				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, -1);
+				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, client->GetClientItemPacketOffset());
 				safe_delete(item);
 				char accept[35] = { 0 };
 				char decline[35] = { 0 };
@@ -10550,7 +10550,7 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 				Item* item = new Item(master_item_list.GetItem(36212));
 				packet2->setArrayDataByName("reward_id", item->details.item_id);
 				item->stack_count = 20;
-				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, -1);
+				packet2->setItemArrayDataByName("item", item, client->GetPlayer(), 0, 0, client->GetClientItemPacketOffset());
 				safe_delete(item);
 				char accept[35] = { 0 };
 				char decline[35] = { 0 };
@@ -10747,7 +10747,7 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 			if(item) {
 				packet->setSubstructArrayLengthByName("reward_data", "num_select_rewards", 1);
 				packet->setArrayDataByName("select_reward_id", item->details.item_id, 0);
-				packet->setItemArrayDataByName("select_item", item, client->GetPlayer(), 0, 0, -1);
+				packet->setItemArrayDataByName("select_item", item, client->GetPlayer(), 0, 0, World::newValue - 2);
 			}
 
 			client->QueuePacket(packet->serialize());
@@ -10755,7 +10755,7 @@ void Commands::Command_Test(Client* client, EQ2_16BitString* command_parms) {
 		}
 	}
 	else {
-			PacketStruct* packet2 = configReader.getStruct("WS_ExamineSpellInfo", client->GetVersion());
+			PacketStruct* packet2 = configReader.getStruct("WS_ExaminePartialSpellInfo", client->GetVersion());
 			if (packet2) {
 				packet2->setSubstructDataByName("info_header", "show_name", 1);
 				packet2->setSubstructDataByName("info_header", "unknown", 7);
@@ -11192,7 +11192,7 @@ void Commands::Command_Wind(Client* client, Seperator* sep) {
 
 void Commands::Command_SendMerchantWindow(Client* client, Seperator* sep, bool sell) {
 	Spawn* spawn = client->GetPlayer()->GetTarget();
-	if(client->GetVersion() <= 561) {
+	if(client->GetVersion() < 561) {
 		sell = false; // doesn't support in the same way as AoM just open the normal buy/sell window
 	}
 	if(spawn) {
@@ -11320,17 +11320,45 @@ void Commands::Command_ConsumeFood(Client* client, Seperator* sep) {
 	if (sep && sep->arg[0] && sep->IsNumber(0))
 	{
 		Player* player = client->GetPlayer();
-		int8 slot = atoi(sep->arg[0]);
-		if (client->GetVersion() <= 283) {
-			slot += 4;
-		}
-		else if (client->GetVersion() <= 561) {
-			slot += 2;
+		int32 slot = atoul(sep->arg[0]);
+		if (client->GetVersion() <= 373) {
+			if(client->GetVersion() <= 561) {
+				if(slot <= 255) {
+					slot = 255 - slot;
+				}
+				else {
+					if(slot == 256) { // first "new" item to inventory is assigned index 256 by client
+						slot = client->GetPlayer()->item_list.GetFirstNewItem();
+					}
+					else {
+						// otherwise the slot has to be mapped out depending on the amount of new items + index sent in
+						slot = client->GetPlayer()->item_list.GetNewItemByIndex((int16)slot - 255);
+					}
+				}
+			}
+			Item* item = client->GetPlayer()->item_list.GetItemFromIndex(slot);
+			if(item && item->IsFood()) {
+				if(client->CheckConsumptionAllowed(slot)) {
+					if(item->IsFoodFood())
+						slot = EQ2_FOOD_SLOT;
+					else if(item->IsFoodDrink())
+						slot = EQ2_DRINK_SLOT;
+					else
+						return; // not valid item
+					
+					client->ConsumeFoodDrink(item, slot);
+				}
+			}
 		}
-		Item* item = player->GetEquipmentList()->GetItem(slot);
+		else {
+				if (client->GetVersion() > 373 && client->GetVersion() <= 561) {
+					slot += 2;
+				}
+				Item* item = player->GetEquipmentList()->GetItem(slot);
 
-		if(client->CheckConsumptionAllowed(slot)) {
-			client->ConsumeFoodDrink(item, slot);
+				if(client->CheckConsumptionAllowed(slot)) {
+					client->ConsumeFoodDrink(item, slot);
+				}
 		}
 	}
 }

+ 46 - 34
EQ2/source/WorldServer/Items/Items.cpp

@@ -1795,7 +1795,7 @@ int16 Item::GetOverrideLevel(int8 adventure_class, int8 tradeskill_class){
 	return ret;
 }
 
-void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16 packet_type, int8 subtype, bool loot_item){
+void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16 packet_type, int8 subtype, bool loot_item, bool inspect){
 	int64 classes = 0;
 	Client *client;
 	int8 tmp_subtype = 0;
@@ -2023,7 +2023,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 	packet->setSubstructDataByName("header_info", "unknown21", 0x00000000);
 	packet->setSubstructDataByName("header_info", "condition", generic_info.condition);
 	packet->setSubstructDataByName("header_info", "weight", generic_info.weight);
-	if (packet->GetVersion() <= 283) { //orig client only has one skill
+	if (packet->GetVersion() <= 373) { //orig client only has one skill
 		if (generic_info.skill_req1 == 0 || generic_info.skill_req1 == 0xFFFFFFFF) {
 			if (generic_info.skill_req2 != 0 && generic_info.skill_req2 != 0xFFFFFFFF) {
 				packet->setSubstructDataByName("header_info", "skill_req1", generic_info.skill_req2);
@@ -2048,7 +2048,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 	}
 	if(generic_info.skill_min != 0)
 		packet->setSubstructDataByName("header_info", "skill_min", generic_info.skill_min);
-	if (client->GetVersion() <= 283) {
+	if (client->GetVersion() <= 373) {
 		string flags;
 		if (CheckFlag(NO_TRADE))
 			flags += "NO-TRADE   ";
@@ -2194,7 +2194,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			classes = 36024082983773912;
 		
 	}
-	if (client->GetVersion() <= 283 && generic_info.adventure_default_level > 0) {
+	if (client->GetVersion() <= 373 && generic_info.adventure_default_level > 0) {
 		packet->setSubstructDataByName("header_info", "skill_min", (generic_info.adventure_default_level-1)*5+1);
 		packet->setSubstructDataByName("header_info", "skill_recommended", details.recommended_level * 5);
 	}
@@ -2211,7 +2211,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 		packet->setSubstructArrayLengthByName("header_info", "slot_count", slot_data.size());
 		for(int32 i=0;i<slot_data.size();i++){
 			int8 slot = slot_data[i];
-			if (client->GetVersion() <= 283) {
+			if (client->GetVersion() <= 373) {
 				if (slot > EQ2_EARS_SLOT_1 && slot <= EQ2_WAIST_SLOT) //they added a second ear slot later, adjust for only 1 original slot
 					slot -= 1;
 				else if (slot == EQ2_FOOD_SLOT)
@@ -2230,12 +2230,12 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			packet->setArrayDataByName("slot", slot, i);
 		}
 	}
-	if(!loot_item){
+	if(!loot_item && !inspect){
 		if (adornment_info)
 			LogWrite(ITEM__DEBUG, 0, "Items", "\ttype: %i, Duration: %i, item_types_: %i, slot_type: %i", generic_info.item_type, adornment_info->duration, adornment_info->item_types, adornment_info->slot_type);
 
 		int8 tmpType = generic_info.item_type;
-		if (client->GetVersion() <= 283 && generic_info.item_type > ITEM_TYPE_RECIPE)
+		if (client->GetVersion() <= 373 && generic_info.item_type > ITEM_TYPE_RECIPE)
 			tmpType = 0;
 		else if(client->GetVersion() <= 561 && (generic_info.item_type > ITEM_TYPE_HOUSE || generic_info.item_type == ITEM_TYPE_BAUBLE))
 			tmpType = 0;
@@ -2244,7 +2244,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 		switch(generic_info.item_type){
 			case ITEM_TYPE_WEAPON:{
 				if(weapon_info){
-					if (client->GetVersion() <= 283) {
+					if (client->GetVersion() < 373) {
 						packet->setSubstructDataByName("details", "wield_type", weapon_info->wield_type);
 						packet->setSubstructDataByName("details", "damage_low1", weapon_info->damage_low1);
 						packet->setSubstructDataByName("details", "damage_high1", weapon_info->damage_high1);
@@ -2270,7 +2270,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			}
 			case ITEM_TYPE_RANGED:{
 				if(ranged_info){
-					if (client->GetVersion() <= 283) {
+					if (client->GetVersion() < 373) {
 						packet->setSubstructDataByName("details", "damage_low1", ranged_info->weapon_info.damage_low1);
 						packet->setSubstructDataByName("details", "damage_high1", ranged_info->weapon_info.damage_high1);
 						packet->setSubstructDataByName("details", "damage_low2", ranged_info->weapon_info.damage_low2);
@@ -2297,7 +2297,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			case ITEM_TYPE_SHIELD:
 			case ITEM_TYPE_ARMOR:{
 				if(armor_info){
-					if (client->GetVersion() <= 283) {
+					if (client->GetVersion() < 373) {
 						packet->setSubstructDataByName("details", "mitigation_low", armor_info->mitigation_low);
 						packet->setSubstructDataByName("details", "mitigation_high", armor_info->mitigation_high);
 					}
@@ -2364,7 +2364,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 				break;
 			}
 			case ITEM_TYPE_FOOD:{
-				if(food_info && client->GetVersion() >=284){
+				if(food_info && client->GetVersion() >=374){
 					packet->setDataByName("food_type", food_info->type);
 					packet->setDataByName("level", food_info->level);
 					packet->setDataByName("duration", food_info->duration);
@@ -2376,7 +2376,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 				if(skill_info->spell_id > 0){
 					Spell* spell = master_spell_list.GetSpell(skill_info->spell_id, skill_info->spell_tier);
 					if(spell){
-						if(player && client->GetVersion() >= 284) {
+						if(player && client->GetVersion() >= 374) {
 							packet->setSubstructDataByName("header_info", "footer_type", 0);
 							
 							spell->SetPacketInformation(packet, client);
@@ -2425,7 +2425,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 				break;
 			}
 			case ITEM_TYPE_THROWN:{
-				if(thrown_info && client->GetVersion() >= 284){
+				if(thrown_info && client->GetVersion() >= 374){
 					packet->setDataByName("range", thrown_info->range);
 					packet->setDataByName("damage_modifier", thrown_info->damage_modifier);
 					packet->setDataByName("hit_bonus", thrown_info->hit_bonus);
@@ -2434,7 +2434,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 				break;
 			}
 			case ITEM_TYPE_HOUSE:{
-				if(houseitem_info && client->GetVersion() >= 284){
+				if(houseitem_info && client->GetVersion() >= 374){
 					packet->setDataByName("status_rent_reduction", houseitem_info->status_rent_reduction);
 					packet->setDataByName("coin_rent_reduction", houseitem_info->coin_rent_reduction);
 					packet->setDataByName("house_only", houseitem_info->house_only);
@@ -2442,7 +2442,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 				break;
 			}
 			case ITEM_TYPE_BOOK:{
-				if(book_info && client->GetVersion() >= 284){
+				if(book_info && client->GetVersion() >= 374){
 					packet->setDataByName("language", book_info->language);
 					packet->setMediumStringByName("author", book_info->author.data.c_str());
 					packet->setMediumStringByName("title", book_info->title.data.c_str());
@@ -2473,7 +2473,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			}
 			case ITEM_TYPE_ADORNMENT:{
 				//Adornements
-				if (client->GetVersion() >= 284) {
+				if (client->GetVersion() >= 374) {
 					packet->setDataByName("item_types", adornment_info->item_types);
 					packet->setDataByName("duration", adornment_info->duration); // need to calcualte for remaining duration
 					packet->setDataByName("slot_type", adornment_info->slot_type);
@@ -2489,7 +2489,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			}			
 			case ITEM_TYPE_HOUSE_CONTAINER:{
 				//House Containers
-				if(housecontainer_info && client->GetVersion() >= 284){
+				if(housecontainer_info && client->GetVersion() >= 374){
 					packet->setDataByName("allowed_types", housecontainer_info->allowed_types);
 					packet->setDataByName("num_slots", housecontainer_info->num_slots);
 					packet->setDataByName("broker_commission", housecontainer_info->broker_commission);
@@ -2589,20 +2589,24 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 
 }
 
-PacketStruct* Item::PrepareItem(int16 version, bool merchant_item, bool loot_item){
+PacketStruct* Item::PrepareItem(int16 version, bool merchant_item, bool loot_item, bool inspection){
 	PacketStruct* packet = 0;
+
 	if(loot_item && version > 561)
 		packet = configReader.getStruct("WS_LootItemGeneric", version);
-	else if(loot_item && version <= 561) {
+	else if(!inspection && loot_item && version <= 561) {
 		packet = configReader.getStruct("WS_ItemGeneric", version);
 		packet->AddFlag("loot");
 	}
+	else if(inspection && version <= 373) {
+			packet = configReader.getStruct("WS_ItemInspect", version);
+	} 
 	else if(version <= 561 && (generic_info.item_type > ITEM_TYPE_HOUSE || generic_info.item_type == ITEM_TYPE_BAUBLE)) {
-		packet = configReader.getStruct("WS_ItemGeneric", version);
+			packet = configReader.getStruct("WS_ItemGeneric", version);
 	}
 	else{
 		int8 tmpType = generic_info.item_type;
-		if (version <= 283 && generic_info.item_type > ITEM_TYPE_RECIPE)
+		if (version <= 373 && generic_info.item_type > ITEM_TYPE_RECIPE)
 			tmpType = 0;
 		else if(version <= 561 && (generic_info.item_type > ITEM_TYPE_HOUSE || generic_info.item_type == ITEM_TYPE_BAUBLE))
 			tmpType = 0;
@@ -2730,8 +2734,8 @@ PacketStruct* Item::PrepareItem(int16 version, bool merchant_item, bool loot_ite
 	return packet;
 }
 
-EQ2Packet* Item::serialize(int16 version, bool show_name, Player* player, bool include_twice, int16 packet_type, int8 subtype, bool merchant_item, bool loot_item){
-	PacketStruct* packet = PrepareItem(version, merchant_item, loot_item);
+EQ2Packet* Item::serialize(int16 version, bool show_name, Player* player, bool include_twice, int16 packet_type, int8 subtype, bool merchant_item, bool loot_item, bool inspect){
+	PacketStruct* packet = PrepareItem(version, merchant_item, loot_item, inspect);
 	if(!packet)
 		return 0;
 	if (version <= 561) {
@@ -2739,9 +2743,9 @@ EQ2Packet* Item::serialize(int16 version, bool show_name, Player* player, bool i
 		packet_type = 0;
 	}
 	if(include_twice && IsBag() == false && IsBauble() == false && IsFood() == false)
-		serialize(packet, show_name, player, packet_type, 0x80, loot_item);
+		serialize(packet, show_name, player, packet_type, 0x80, loot_item, inspect);
 	else
-		serialize(packet, show_name, player, packet_type, 0, loot_item);
+		serialize(packet, show_name, player, packet_type, 0, loot_item, inspect);
 	if(merchant_item)
 		packet->setSubstructDataByName("header_info", "unique_id", 0xFFFFFFFF);
 	string* generic_string_data = packet->serializeString();
@@ -2761,7 +2765,7 @@ EQ2Packet* Item::serialize(int16 version, bool show_name, Player* player, bool i
 		memcpy(out_ptr, (uchar*)generic_string_data->c_str() + 13, generic_string_data->length() -13);
 	}
 	int32 size2 = size;
-	if (version <= 283) {
+	if (version <= 373) {
 		uchar* out_ptr2 = out_data;
 		if (size2 >= 0xFF) {
 			size2 -= 3;			
@@ -3721,7 +3725,7 @@ void PlayerItemList::AddItemToPacket(PacketStruct* packet, Player* player, Item*
 
 	if(item->generic_info.condition == 0)
 		menu_data += ITEM_MENU_TYPE_BROKEN;
-	if (client->GetVersion() <= 283){
+	if (client->GetVersion() <= 373){
 		string flags;
 		if (item->CheckFlag(NO_TRADE))
 			flags += "NO-TRADE   ";
@@ -3732,13 +3736,13 @@ void PlayerItemList::AddItemToPacket(PacketStruct* packet, Player* player, Item*
 	}
 
 	if (item->CheckFlag(ATTUNED) || item->CheckFlag(NO_TRADE)) {
-		if (client->GetVersion() <= 283)
+		if (client->GetVersion() <= 373)
 			menu_data += ORIG_ITEM_MENU_TYPE_ATTUNED;
 		else
 			menu_data += ITEM_MENU_TYPE_ATTUNED;
 	}
 	else if (item->CheckFlag(ATTUNEABLE)) {
-		if (client->GetVersion() <= 283)
+		if (client->GetVersion() <= 373)
 			menu_data += ORIG_ITEM_MENU_TYPE_ATTUNEABLE;
 		else
 			menu_data += ITEM_MENU_TYPE_ATTUNEABLE;
@@ -3746,11 +3750,19 @@ void PlayerItemList::AddItemToPacket(PacketStruct* packet, Player* player, Item*
 	if (item->generic_info.usable == 1)
 		menu_data += ITEM_MENU_TYPE_USE;
 	if (item->details.count > 0 && item->stack_count > 1) {
-		if (client->GetVersion() <= 283)
+		if (client->GetVersion() <= 373)
 			menu_data += ORIG_ITEM_MENU_TYPE_STACKABLE;
 		else
 			menu_data += ITEM_MENU_TYPE_DISPLAY_CHARGES;
 	}
+	if(item->IsFood()) {
+		if (client->GetVersion() <= 373) {						
+			if (item->IsFoodDrink())
+				menu_data += ORIG_ITEM_MENU_TYPE_DRINK;
+			else if(item->IsFoodFood())
+				menu_data += ORIG_ITEM_MENU_TYPE_FOOD;
+		}
+	}
 	if(item->details.item_locked) {
 		menu_data += ITEM_MENU_TYPE_BROKEN; // broken is also used to lock item during crafting
 	}
@@ -4307,13 +4319,13 @@ EQ2Packet* EquipmentItemList::serialize(int16 version, Player* player){
 				else if (item->generic_info.condition <= 20)
 					menu_data += ITEM_MENU_TYPE_DAMAGED;
 				if (item->CheckFlag(ATTUNED) || item->CheckFlag(NO_TRADE)) {
-					if (version <= 283)
+					if (version <= 373)
 						menu_data += ORIG_ITEM_MENU_TYPE_ATTUNED;
 					else
 						menu_data += ITEM_MENU_TYPE_ATTUNED;
 				}
 				else if (item->CheckFlag(ATTUNEABLE)) {
-					if (version <= 283)
+					if (version <= 373)
 						menu_data += ORIG_ITEM_MENU_TYPE_ATTUNEABLE;
 					else
 						menu_data += ITEM_MENU_TYPE_ATTUNEABLE;
@@ -4322,7 +4334,7 @@ EQ2Packet* EquipmentItemList::serialize(int16 version, Player* player){
 					menu_data += ITEM_MENU_TYPE_USE;
 				if (item->IsFood())
 				{
-					if (version <= 283) {						
+					if (version <= 373) {						
 						if (item->IsFoodDrink())
 							menu_data += ORIG_ITEM_MENU_TYPE_DRINK;
 						else
@@ -4343,7 +4355,7 @@ EQ2Packet* EquipmentItemList::serialize(int16 version, Player* player){
 				packet->setSubstructArrayDataByName("items", "bag_id", item->details.bag_id, 0, i);
 				packet->setSubstructArrayDataByName("items", "inv_slot_id", item->details.inv_slot_id, 0, i);
 				if (item->details.count > 0 && item->stack_count > 1) {
-					if (version <= 283)
+					if (version <= 373)
 						menu_data += ORIG_ITEM_MENU_TYPE_STACKABLE;
 					else
 						menu_data += ITEM_MENU_TYPE_DISPLAY_CHARGES;

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

@@ -1050,9 +1050,9 @@ public:
 	string CreateItemLink(int16 client_Version, bool bUseUniqueID=false);
 
 	void SetItemType(int8 in_type);
-	void serialize(PacketStruct* packet, bool show_name = false, Player* player = 0, int16 packet_type = 0, int8 subtype = 0, bool loot_item = false);
-	EQ2Packet* serialize(int16 version, bool show_name = false, Player* player = 0, bool include_twice = true, int16 packet_type = 0, int8 subtype = 0, bool merchant_item = false, bool loot_item = false);
-	PacketStruct* PrepareItem(int16 version, bool merchant_item = false, bool loot_item = false);
+	void serialize(PacketStruct* packet, bool show_name = false, Player* player = 0, int16 packet_type = 0, int8 subtype = 0, bool loot_item = false, bool inspect = false);
+	EQ2Packet* serialize(int16 version, bool show_name = false, Player* player = 0, bool include_twice = true, int16 packet_type = 0, int8 subtype = 0, bool merchant_item = false, bool loot_item = false, bool inspect = false);
+	PacketStruct* PrepareItem(int16 version, bool merchant_item = false, bool loot_item = false, bool inspection = false);
 	bool CheckFlag(int32 flag);
 	bool CheckFlag2(int32 flag);
 	void AddSlot(int8 slot_id);

+ 30 - 1
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -11425,7 +11425,7 @@ int EQ2Emu_lua_InstructionWindowClose(lua_State* state) {
 		lua_interface->LogError("LUA InstructionWindowClose command error: player is not valid");
 		return 0;
 	}
-	if (client) {
+	if (client && client->GetVersion() >= 374) {
 		client->QueuePacket(new EQ2Packet(OP_EqInstructionWindowCloseCmd, 0, 0));
 	}
 	return 0;
@@ -14064,3 +14064,32 @@ int EQ2Emu_lua_ToggleCharacterFlag(lua_State* state) {
 	((Player*)player)->toggle_character_flag(flag_id);
 	return 0;
 }
+
+int EQ2Emu_lua_GetSpellInitialTarget(lua_State* state) {
+	LuaSpell* spell = lua_interface->GetSpell(state);
+	
+	if(!spell) {
+		spell = lua_interface->GetCurrentSpell(state);
+	}
+	
+	lua_interface->ResetFunctionStack(state);
+	if (spell) {
+		if(!spell->caster) {
+			lua_interface->LogError("%s: LUA GetSpellTarget command error, caster does not exist.", lua_interface->GetScriptName(state));
+			return 0;
+		}
+		if(!spell->caster->GetZone()) {
+			lua_interface->LogError("%s: LUA GetSpellTarget command error, zone does not exist.", lua_interface->GetScriptName(state));
+			return 0;
+		}
+		Spawn* spawn = spell->caster->GetZone()->GetSpawnByID(spell->initial_target);
+		if (spawn) {
+			lua_interface->SetSpawnValue(state, spawn);
+			return 1;
+		}
+		else {
+			lua_interface->LogError("%s: LUA GetSpellTarget command error, could not find initial target %u to map to spawn.", lua_interface->GetScriptName(state), spell->initial_target);
+		}
+	}
+	return 0;
+}

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

@@ -654,4 +654,6 @@ int EQ2Emu_lua_SendHearCast(lua_State* state);
 
 int EQ2Emu_lua_GetCharacterFlag(lua_State* state);
 int EQ2Emu_lua_ToggleCharacterFlag(lua_State* state);
+
+int EQ2Emu_lua_GetSpellInitialTarget(lua_State* state);
 #endif

+ 2 - 0
EQ2/source/WorldServer/LuaInterface.cpp

@@ -1566,6 +1566,8 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
 	
 	lua_register(state, "GetCharacterFlag", EQ2Emu_lua_GetCharacterFlag);
 	lua_register(state, "ToggleCharacterFlag", EQ2Emu_lua_ToggleCharacterFlag);
+	
+	lua_register(state, "GetSpellInitialTarget", EQ2Emu_lua_GetSpellInitialTarget);
 }
 
 void LuaInterface::LogError(const char* error, ...)  {

+ 60 - 20
EQ2/source/WorldServer/Player.cpp

@@ -472,7 +472,7 @@ PacketStruct* PlayerInfo::serialize2(int16 version){
 		
 		if(info_struct->get_pet_id() != 0xFFFFFFFF) {
 			char pet_name[32];
-			strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
+			strncpy(pet_name, info_struct->get_pet_name().c_str(), version <= 373 ? 16 : 32);
 			packet->setDataByName("pet_name", pet_name);
 		}
 		else {
@@ -923,12 +923,12 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
 		packet->setDataByName("crit_success_mod", player->stats[ITEM_STAT_CRIT_SUCCESS_MOD]);// dov confirmed
 		((Entity*)player)->MStats.unlock();
 
-		if (version <= 283 && info_struct->get_pet_id() == 0xFFFFFFFF)
+		if (version <= 373 && info_struct->get_pet_id() == 0xFFFFFFFF)
 			packet->setDataByName("pet_id", 0);
 		else {
 			packet->setDataByName("pet_id", info_struct->get_pet_id());
 			char pet_name[32];
-			strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
+			strncpy(pet_name, info_struct->get_pet_name().c_str(), version <= 373 ? 16 : 32);
 			packet->setDataByName("pet_name", pet_name);
 		}
 
@@ -1181,10 +1181,11 @@ EQ2Packet* PlayerInfo::serialize(int16 version, int16 modifyPos, int32 modifyVal
 		string* data = packet->serializeString();
 		int32 size = data->length();
 
+		printf("CharSheet size: %u for version %u\n", size, version);
 		//DumpPacket((uchar*)data->c_str(), data->size());
 		//packet->PrintPacket();
 		uchar* tmp = new uchar[size];
-		bool reverse = version > 283;
+		bool reverse = version > 373;
 		if (!changes) {
 			orig_packet = new uchar[size];
 			changes = new uchar[size];
@@ -1250,6 +1251,7 @@ EQ2Packet* PlayerInfo::serializePet(int16 version) {
 			packet->setDataByName("spawn_id2", info_struct->get_pet_id());
 			
 			if(info_struct->get_pet_id() != 0xFFFFFFFF) {
+				packet->setDataByName("pet_id", info_struct->get_pet_id());
 				char pet_name[32];
 				strncpy(pet_name, info_struct->get_pet_name().c_str(), 32);
 				packet->setDataByName("name", pet_name);
@@ -1358,7 +1360,7 @@ bool Player::DamageEquippedItems(int8 amount, Client* client) {
 }
 
 int16 Player::ConvertSlotToClient(int8 slot, int16 version) {
-	if (version <= 283) {
+	if (version <= 373) {
 		if (slot == EQ2_FOOD_SLOT)
 			slot = EQ2_ORIG_FOOD_SLOT;
 		else if (slot == EQ2_DRINK_SLOT)
@@ -1378,7 +1380,7 @@ int16 Player::ConvertSlotToClient(int8 slot, int16 version) {
 }
 
 int16 Player::ConvertSlotFromClient(int8 slot, int16 version) {
-	if (version <= 283) {
+	if (version <= 373) {
 		if (slot == EQ2_ORIG_FOOD_SLOT)
 			slot = EQ2_FOOD_SLOT;
 		else if (slot == EQ2_ORIG_DRINK_SLOT)
@@ -1406,7 +1408,7 @@ int16 Player::GetNumSlotsEquip(int16 version) {
 }
 
 int8 Player::GetMaxBagSlots(int16 version) {
-	if(version <= 283) {
+	if(version <= 373) {
 		return CLASSIC_EQ_MAX_BAG_SLOTS;
 	}
 	else if(version <= 561) {
@@ -1804,6 +1806,7 @@ vector<EQ2Packet*> Player::EquipItem(int16 index, int16 version, int8 appearance
 	}
 	Item* item = item_list.indexed_items[index];
 	int8 orig_slot_id = slot_id;
+	int8 slot = 255;
 	if (item) {
 		if(orig_slot_id == 255 && item->CheckFlag2(APPEARANCE_ONLY)) {
 			appearance_type = 1;
@@ -1813,7 +1816,7 @@ vector<EQ2Packet*> Player::EquipItem(int16 index, int16 version, int8 appearance
 			item_list.MPlayerItems.releasereadlock(__FUNCTION__, __LINE__);
 			return packets;
 		}
-		int8 slot = equipList->GetFreeSlot(item, slot_id, version);
+		slot = equipList->GetFreeSlot(item, slot_id, version);
 		
 		bool canEquip = CanEquipItem(item,slot);
 		int32 conflictSlot = 0;
@@ -1963,6 +1966,19 @@ vector<EQ2Packet*> Player::EquipItem(int16 index, int16 version, int8 appearance
 			item_list.MPlayerItems.releasereadlock(__FUNCTION__, __LINE__);
 	}
 	
+	if(slot < 255) {
+		if (slot == EQ2_FOOD_SLOT && item->IsFoodFood() && get_character_flag(CF_FOOD_AUTO_CONSUME)) {
+			Item* item = GetEquipmentList()->GetItem(EQ2_FOOD_SLOT);
+			if(item && GetClient())
+				GetClient()->ConsumeFoodDrink(item, EQ2_FOOD_SLOT);
+		}
+		else if (slot == EQ2_DRINK_SLOT && item->IsFoodDrink() && get_character_flag(CF_DRINK_AUTO_CONSUME)) {
+			Item* item = GetEquipmentList()->GetItem(EQ2_DRINK_SLOT);
+			if(item && GetClient())
+				GetClient()->ConsumeFoodDrink(item, EQ2_DRINK_SLOT);
+		}
+	}
+	
 	client->UpdateSentSpellList();
 	client->ClearSentSpellList();
 
@@ -2896,6 +2912,9 @@ EQ2Packet* Player::GetSpellBookUpdatePacket(int16 version) {
 		int32 total_bytes = packet2->GetTotalPacketSize();
 		safe_delete(packet2);
 		packet->setArrayLengthByName("spell_count", count);
+		
+		LogWrite(PLAYER__DEBUG, 5, "Player", "%s: GetSpellBookUpdatePacket Spell Count: %u, Spell Entry Book Size: %u", GetName(), count, total_bytes);
+
 		if (count > 0) {
 			if (count > spell_count) {
 				uchar* tmp = 0;
@@ -2925,7 +2944,7 @@ EQ2Packet* Player::GetSpellBookUpdatePacket(int16 version) {
 					if (spell_entry->recast_available == 0 || Timer::GetCurrentTime2() > spell_entry->recast_available) {
 						packet->setSubstructArrayDataByName("spells", "available", 1, 0, ptr);
 					}
-										
+					LogWrite(PLAYER__DEBUG, 9, "Player", "%s: GetSpellBookUpdatePacket Send Spell %u in position %u\n",GetName(), spell_entry->spell_id, ptr);
 					packet->setSubstructArrayDataByName("spells", "spell_id", spell_entry->spell_id, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "type", spell_entry->type, 0, ptr);
 					packet->setSubstructArrayDataByName("spells", "recast_available", spell_entry->recast_available, 0, ptr);
@@ -3318,7 +3337,7 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		old_movement_packet = new uchar[total_bytes];
 	if (movement_packet && old_movement_packet)
 		memcpy(old_movement_packet, movement_packet, total_bytes);
-	bool reverse = version > 283;
+	bool reverse = version > 373;
 	Unpack(len, data, movement_packet, total_bytes, 0, reverse);
 	if (!movement_packet || !old_movement_packet)
 		return;
@@ -3332,12 +3351,14 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 	float direction2;	// = update->getType_float_ByName("direction2");;
 	float speed;		// = update->getType_float_ByName("speed");;
 	float side_speed;
+	float vert_speed;
 	float x;			// = update->getType_float_ByName("x");;
 	float y;			// = update->getType_float_ByName("y");;
 	float z;			// = update->getType_float_ByName("z");;
 	float x_speed;
 	float y_speed;
 	float z_speed;
+	float client_pitch;
 
 	// comment out this if/else if/else block if you use xml structs
 	if (version >= 1144) {
@@ -3348,13 +3369,15 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		direction2 = update->direction2;
 		speed = update->speed;
 		side_speed = update->side_speed;
+		vert_speed = update->vert_speed;
 		x = update->x;
 		y = update->y;
 		z = update->z;
 		x_speed = update->speed_x;
 		y_speed = update->speed_y;
 		z_speed = update->speed_z;
-
+		client_pitch = update->pitch;
+		
 		SetPitch(180 + update->pitch);
 	}
 	else if (version >= 1096) {
@@ -3365,16 +3388,18 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		direction2 = update->direction2;
 		speed = update->speed;
 		side_speed = update->side_speed;
+		vert_speed = update->vert_speed;
 		x = update->x;
 		y = update->y;
 		z = update->z;
 		x_speed = update->speed_x;
 		y_speed = update->speed_y;
 		z_speed = update->speed_z;
-
+		client_pitch = update->pitch;
+		
 		SetPitch(180 + update->pitch);
 	}
-	else if (version <= 283) {
+	else if (version <= 373) {
 		Player_Update283* update = (Player_Update283*)movement_packet;
 		activity = update->activity;
 		grid_id = update->grid_location;
@@ -3382,6 +3407,9 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		direction2 = update->direction2;
 		speed = update->speed;
 		side_speed = update->side_speed;
+		vert_speed = update->vert_speed;
+		client_pitch = update->pitch;
+		
 		x = update->x;
 		y = update->y;
 		z = update->z;
@@ -3399,6 +3427,7 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		direction2 = update->direction2;
 		speed = update->speed;
 		side_speed = update->side_speed;
+		vert_speed = update->vert_speed;
 		x = update->x;
 		y = update->y;
 		z = update->z;
@@ -3411,9 +3440,11 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 		appearance.pos.X3 = update->orig_x2;
 		appearance.pos.Y3 = update->orig_y2;
 		appearance.pos.Z3 = update->orig_z2;
+		client_pitch = update->pitch;
+		
 		SetPitch(180 + update->pitch);
 	}
-
+	
 	SetHeading((sint16)(direction1 * 64), (sint16)(direction2 * 64));
 	if (activity != last_movement_activity) {
 		switch(activity) {
@@ -3527,13 +3558,23 @@ void Player::PrepareIncomingMovementPacket(int32 len, uchar* data, int16 version
 			SetSpeedY(y_speed);
 			SetSpeedZ(z_speed);
 			SetSideSpeed(side_speed);
-			pos_packet_speed = speed;
+			SetVertSpeed(vert_speed);
+			SetClientHeading1(direction1);
+			SetClientHeading2(direction2);
+			SetClientPitch(client_pitch);
+			if(version > 373) {
+				pos_packet_speed = speed;
+			}
 		}
 		else {
-			SetSpeedX(0);
-			SetSpeedY(0);
-			SetSpeedZ(0);
-			SetSideSpeed(0);
+			SetSpeedX(0.0f);
+			SetSpeedY(0.0f);
+			SetSpeedZ(0.0f);
+			SetSideSpeed(0.0f);
+			SetVertSpeed(0.0f);
+			SetClientHeading1(direction1);
+			SetClientHeading2(direction2);
+			SetClientPitch(client_pitch);
 			pos_packet_speed = 0;
 		}
 	}
@@ -4571,7 +4612,6 @@ PacketStruct* Player::GetQuestJournalPacket(bool all_quests, int16 version, int3
 #if EQDEBUG >= 9
 		packet->PrintPacket();
 #endif
-
 	}
 	return packet;
 }

+ 28 - 0
EQ2/source/WorldServer/Player.h

@@ -470,6 +470,34 @@ public:
 	float GetSideSpeed() {
 		return appearance.pos.SideSpeed;
 	}
+	void SetVertSpeed(float vert_speed, bool updateFlags = true) {
+		SetPos(&appearance.pos.VertSpeed, vert_speed, updateFlags);
+	}
+	float GetVertSpeed() {
+		return appearance.pos.VertSpeed;
+	}
+	
+	void SetClientHeading1(float heading, bool updateFlags = true) {
+		SetPos(&appearance.pos.ClientHeading1, heading, updateFlags);
+	}
+	float GetClientHeading1() {
+		return appearance.pos.ClientHeading1;
+	}
+	
+	void SetClientHeading2(float heading, bool updateFlags = true) {
+		SetPos(&appearance.pos.ClientHeading2, heading, updateFlags);
+	}
+	float GetClientHeading2() {
+		return appearance.pos.ClientHeading2;
+	}
+	
+	void SetClientPitch(float pitch, bool updateFlags = true) {
+		SetPos(&appearance.pos.ClientPitch, pitch, updateFlags);
+	}
+	float GetClientPitch() {
+		return appearance.pos.ClientPitch;
+	}
+	
 	int8 GetTutorialStep() {
 		return tutorial_step;
 	}

+ 9 - 3
EQ2/source/WorldServer/Quests.cpp

@@ -881,7 +881,13 @@ EQ2Packet* Quest::OfferQuest(int16 version, Player* player){
 	PacketStruct* packet = configReader.getStruct("WS_OfferQuest", version);
 	if(packet){	
 		packet->setDataByName("reward", "Quest Reward!");
-		packet->setDataByName("title", name.c_str());
+		if(packet->GetVersion() <= 373) {
+				std::string quotedName = std::string("\"" + name + "\"");
+			packet->setDataByName("title", quotedName.c_str());
+		}
+		else {
+			packet->setDataByName("title", name.c_str());
+		}
 		packet->setDataByName("description", description.c_str());
 		if(type == "Tradeskill")
 			packet->setDataByName("quest_difficulty", player->GetTSArrowColor(level));
@@ -1270,7 +1276,7 @@ EQ2Packet* Quest::QuestJournalReply(int16 version, int32 player_crc, Player* pla
 				item = reward_items[i];
 				packet->setArrayDataByName("reward_id", item->details.item_id, i);
 				if (version < 860)
-					packet->setItemArrayDataByName("item", item, player, i, 0, -1);
+					packet->setItemArrayDataByName("item", item, player, i, 0, version <= 373 ? -2 : -1);
 				else if (version < 1193)
 					packet->setItemArrayDataByName("item", item, player, i);
 				else
@@ -1285,7 +1291,7 @@ EQ2Packet* Quest::QuestJournalReply(int16 version, int32 player_crc, Player* pla
 				item = selectable_reward_items[i];
 				packet->setArrayDataByName("select_reward_id", item->details.item_id, i);
 				if (version < 860)
-					packet->setItemArrayDataByName("select_item", item, player, i, 0, -1);
+					packet->setItemArrayDataByName("select_item", item, player, i, 0, version <= 373 ? -2 : -1);
 				else if (version < 1193)
 					packet->setItemArrayDataByName("select_item", item, player, i);
 				else

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

@@ -260,6 +260,7 @@ public:
 	bool				IsRepeatable() { return m_repeatable; }
 	
 	void				SetTracked(bool val) { m_tracked = val; }
+	bool				GetTracked() { return m_tracked; }
 	bool				IsTracked() { return m_tracked && !m_hidden; }
 	void                SetCompletedFlag(bool val);
 	bool                GetCompletedFlag() {return completed_flag;}

+ 5 - 2
EQ2/source/WorldServer/Skills.cpp

@@ -358,9 +358,12 @@ EQ2Packet* PlayerSkillList::GetSkillPacket(int16 version){
 			if (version > 561) {
 				size = 21 * skill_count + 8;
 			}
-			else if (version <= 283) {
+			else if (version < 373) {
 				size = 12 * skill_count + 6;
 			}
+			else if (version <= 373) {
+				size = 15 * skill_count + 6;
+			}
 			else if (version <= 561) {
 				size = 21 * skill_count + 7;
 			}
@@ -424,7 +427,7 @@ EQ2Packet* PlayerSkillList::GetSkillPacket(int16 version){
 			}
 		}
 		int8 offset = 1;
-		if (version <= 283)
+		if (version <= 373)
 			offset = 0;
 		EQ2Packet* ret = packet->serializeCountPacket(version, offset, orig_packet, xor_packet);
 		//packet->PrintPacket();

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

@@ -313,7 +313,7 @@ void Spawn::InitializeVisPacketData(Player* player, PacketStruct* vis_packet) {
 
 			if (appearance.attackable == 1)
 				arrow_color = player->GetArrowColor(GetLevel());
-			if (version <= 283) {
+			if (version <= 373) {
 				if (GetMerchantID() > 0)
 					arrow_color += 7;
 				else {
@@ -654,14 +654,14 @@ EQ2Packet* Spawn::spawn_serialize(Player* player, int16 version, int16 offset, i
 	//	DumpPacket(part2, part2_size);
 
 	uchar tmp[4000];
-	bool reverse = (version > 283);
+	bool reverse = (version > 373);
 	part2_size = Pack(tmp, part2, part2_size, 4000, version, reverse);
 	int32 total_size = part1->length() + part2_size + 3;
 	if (part3)
 		total_size += part3->length();
 	int32 final_packet_size = total_size + 1;
 
-	if (version > 283)
+	if (version > 373)
 		final_packet_size += 3;
 	else {
 		if (final_packet_size >= 255) {
@@ -670,7 +670,7 @@ EQ2Packet* Spawn::spawn_serialize(Player* player, int16 version, int16 offset, i
 	}
 	uchar* final_packet = new uchar[final_packet_size];
 	ptr = final_packet;
-	if (version <= 283) {
+	if (version <= 373) {
 		if ((final_packet_size - total_size) > 1) {
 			memcpy(ptr, &oversized_packet, sizeof(oversized_packet));
 			ptr += sizeof(oversized_packet);
@@ -831,7 +831,7 @@ uchar* Spawn::spawn_vis_changes(Player* player, int16 version, int16* vis_packet
 	return tmp2;
 }
 
-uchar* Spawn::spawn_pos_changes(Player* player, int16 version, int16* pos_packet_size) {
+uchar* Spawn::spawn_pos_changes(Player* player, int16 version, int16* pos_packet_size, bool override_) {
 	int16 index = player->GetIndexForSpawn(this);
 
 	PacketStruct* packet = player->GetSpawnPosStruct();
@@ -862,7 +862,7 @@ uchar* Spawn::spawn_pos_changes(Player* player, int16 version, int16* pos_packet
 		}
 	}
 
-	if (!changed) {
+	if (!changed && !override_) {
 		player->pos_mutex.releasewritelock(__FUNCTION__, __LINE__);
 		return nullptr;
 	}
@@ -911,7 +911,7 @@ uchar* Spawn::spawn_pos_changes(Player* player, int16 version, int16* pos_packet
 	return tmp2;
 }
 
-EQ2Packet* Spawn::player_position_update_packet(Player* player, int16 version){
+EQ2Packet* Spawn::player_position_update_packet(Player* player, int16 version, bool override_){
 	if(!player || player->IsPlayer() == false){
 		LogWrite(SPAWN__ERROR, 0, "Spawn", "Error: Called player_position_update_packet without player!");
 		return 0;
@@ -925,17 +925,18 @@ EQ2Packet* Spawn::player_position_update_packet(Player* player, int16 version){
 	static const int8 vis_size = 1;
 	int16 pos_packet_size = 0;
 	m_Update.writelock(__FUNCTION__, __LINE__);
-	uchar* pos_changes = spawn_pos_changes(player, version, &pos_packet_size);
-	if (pos_changes == NULL )
+	uchar* pos_changes = spawn_pos_changes(player, version, &pos_packet_size, override_);
+	if (pos_changes == NULL)
 	{
+		printf("%s returned null for pos changes\n", GetName());
 		m_Update.releasewritelock(__FUNCTION__, __LINE__);
 		return NULL;
 	}
 
 	int32 size = info_size + pos_packet_size + vis_size + 8;
-	if (version >= 284)
+	if (version >= 374)
 		size += 3;
-	else if (version <= 283 && size >= 255) {//1 byte to 3 for overloaded val
+	else if (version <= 373 && size >= 255) {//1 byte to 3 for overloaded val
 		size += 2;
 	}
 	static const int8 oversized = 255;
@@ -949,7 +950,7 @@ EQ2Packet* Spawn::player_position_update_packet(Player* player, int16 version){
 	uchar* tmp = new uchar[size];
 	memset(tmp, 0, size);
 	uchar* ptr = tmp;
-	if (version >= 284) {
+	if (version >= 374) {
 		size -= 4;
 		memcpy(ptr, &size, sizeof(int32));
 		size += 4;
@@ -976,7 +977,7 @@ EQ2Packet* Spawn::player_position_update_packet(Player* player, int16 version){
 	ptr += sizeof(int8);
 	memcpy(ptr, &opcode_val, sizeof(int16));
 	ptr += sizeof(int16);
-	if (version <= 283) {
+	if (version <= 373) {
 		int32 timestamp = Timer::GetCurrentTime2();
 		memcpy(ptr, &timestamp, sizeof(int32));
 	}
@@ -1026,15 +1027,15 @@ EQ2Packet* Spawn::spawn_update_packet(Player* player, int16 version, bool overri
 		vis_changes = spawn_vis_changes(player, version, &vis_packet_size);
 
 	int32 size = info_packet_size + pos_packet_size + vis_packet_size + 8;
-	if (version >= 284)
+	if (version >= 374)
 		size += 3;
-	else if (version <= 283 && size >= 255) {//1 byte to 3 for overloaded val
+	else if (version <= 373 && size >= 255) {//1 byte to 3 for overloaded val
 		size += 2;
 	}
 	uchar* tmp = new uchar[size];
 	memset(tmp, 0, size);
 	uchar* ptr = tmp;
-	if (version >= 284) {
+	if (version >= 374) {
 		size -= 4;
 		memcpy(ptr, &size, sizeof(int32));
 		size += 4;
@@ -1256,7 +1257,7 @@ uchar* Spawn::spawn_pos_changes_ex(Player* player, int16 version, int16* pos_pac
 		}
 	}
 
-	if (!changed) {
+	if (!changed && version > 561) {
 		player->pos_mutex.releasewritelock(__FUNCTION__, __LINE__);
 		return nullptr;
 	}
@@ -2210,15 +2211,17 @@ void Spawn::InitializePosPacketData(Player* player, PacketStruct* packet, bool b
 	//pos_size: 5
 	//actor_stop_range: 5
 	//this is for original box client, destinations used to be offsets
-	if (appearance.pos.X2 != 0 || appearance.pos.Y2 != 0 || appearance.pos.Z2 != 0) {
-		packet->setDataByName("pos_dest_loc_offset", TransformFromFloat(appearance.pos.X2 - appearance.pos.X, 5));
-		packet->setDataByName("pos_dest_loc_offset", TransformFromFloat(appearance.pos.Y2 - appearance.pos.Y, 5), 1);
-		packet->setDataByName("pos_dest_loc_offset", TransformFromFloat(appearance.pos.Z2 - appearance.pos.Z, 5), 2);
-	}
-	if (appearance.pos.X3 != 0 || appearance.pos.Y3 != 0 || appearance.pos.Z3 != 0) {
-		packet->setDataByName("pos_dest_loc_offset2", TransformFromFloat(appearance.pos.X3 - appearance.pos.X, 5));
-		packet->setDataByName("pos_dest_loc_offset2", TransformFromFloat(appearance.pos.Y3 - appearance.pos.Y, 5), 1);
-		packet->setDataByName("pos_dest_loc_offset2", TransformFromFloat(appearance.pos.Z3 - appearance.pos.Z, 5), 2);
+	if(version <= 373 || version > 561 || !IsPlayer()) {
+		if (appearance.pos.X2 != 0 || appearance.pos.Y2 != 0 || appearance.pos.Z2 != 0) {
+			packet->setDataByName("pos_dest_loc_offset", TransformFromFloat(appearance.pos.X2 - appearance.pos.X, 5));
+			packet->setDataByName("pos_dest_loc_offset", TransformFromFloat(appearance.pos.Y2 - appearance.pos.Y, 5), 1);
+			packet->setDataByName("pos_dest_loc_offset", TransformFromFloat(appearance.pos.Z2 - appearance.pos.Z, 5), 2);
+		}
+		if (appearance.pos.X3 != 0 || appearance.pos.Y3 != 0 || appearance.pos.Z3 != 0) {
+			packet->setDataByName("pos_dest_loc_offset2", TransformFromFloat(appearance.pos.X3 - appearance.pos.X, 5));
+			packet->setDataByName("pos_dest_loc_offset2", TransformFromFloat(appearance.pos.Y3 - appearance.pos.Y, 5), 1);
+			packet->setDataByName("pos_dest_loc_offset2", TransformFromFloat(appearance.pos.Z3 - appearance.pos.Z, 5), 2);
+		}
 	}
 
 	bool bSendSpeed = true;
@@ -2267,20 +2270,28 @@ void Spawn::InitializePosPacketData(Player* player, PacketStruct* packet, bool b
 	//packet->setDataByName("pos_unknown2", 4, 2);
 
 	int16 speed_multiplier = rule_manager.GetGlobalRule(R_Spawn, SpeedMultiplier)->GetInt16(); // was 1280, 600 and now 300... investigating why
-
+	int8 movement_mode = 0;
 	if (IsPlayer()) {
 		Player* player = static_cast<Player*>(this);
-
-		packet->setDataByName("pos_speed", player->GetPosPacketSpeed() * speed_multiplier);
-		packet->setDataByName("pos_side_speed", player->GetSideSpeed() * speed_multiplier);
+		sint16 pos_packet_speed = player->GetPosPacketSpeed() * speed_multiplier;
+		sint16 side_speed = player->GetSideSpeed() * speed_multiplier;
+		packet->setDataByName("pos_speed", pos_packet_speed);
+		packet->setDataByName("pos_side_speed", side_speed);
+		if(pos_packet_speed != 0 || side_speed != 0) {
+			movement_mode = 2;
+		}
 	}
 	else if (bSendSpeed) {
-		packet->setDataByName("pos_speed", GetSpeed() * speed_multiplier);
+		sint16 side_speed = GetSpeed() * speed_multiplier;
+		packet->setDataByName("pos_speed", side_speed);
+		if(side_speed != 0) {
+			movement_mode = 2;
+		}
 	}
 	
 	
 	if (IsNPC() || IsPlayer()) {
-		packet->setDataByName("pos_move_type", 25);
+		packet->setDataByName("pos_move_type", World::newValue);
 	}
 	else if (IsWidget() || IsSign()) {
 		packet->setDataByName("pos_move_type", 11);
@@ -2289,8 +2300,9 @@ void Spawn::InitializePosPacketData(Player* player, PacketStruct* packet, bool b
 		packet->setDataByName("pos_move_type", 16);
 	}
 	
-	if (!IsPlayer()) // has to be 2 or NPC's warp around when moving
-		packet->setDataByName("pos_movement_mode", 2);
+	if (!IsPlayer()) { // has to be 2 or NPC's warp around when moving
+		packet->setDataByName("pos_movement_mode", movement_mode);
+	}
 	
 	packet->setDataByName("face_actor_id", 0xFFFFFFFF);
 
@@ -2316,7 +2328,7 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 			if (GetHP() > 0)
 				percent = (int8)(((float)GetHP() / GetTotalHP()) * 100);
 			
-			if (version >= 284) {
+			if (version >= 373) {
 				if (percent < 100) {
 					packet->setDataByName("hp_remaining", 100 ^ percent);
 				}
@@ -2381,6 +2393,9 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 		sogaModelType = 0;
 	}
 
+	if(version <= 373 && (model_type == 5864 || model_type == 5865 || model_type == 4015)) {
+		model_type = 4034;
+	}
 	packet->setDataByName("model_type", model_type);
 	if (appearance.soga_model_type == 0)
 		packet->setDataByName("soga_model_type", model_type);

+ 2 - 2
EQ2/source/WorldServer/Spawn.h

@@ -874,9 +874,9 @@ public:
 	virtual EQ2Packet* serialize(Player* player, int16 version);
 	EQ2Packet* spawn_serialize(Player* player, int16 version, int16 offset = 0, int32 value = 0, int16 offset2 = 0, int16 offset3 = 0, int16 offset4 = 0, int32 value2 = 0);
 	EQ2Packet* spawn_update_packet(Player* player, int16 version, bool override_changes = false, bool override_vis_changes = false);
-	EQ2Packet* player_position_update_packet(Player* player, int16 version);
+	EQ2Packet* player_position_update_packet(Player* player, int16 version, bool override_ = false);
 	uchar* spawn_info_changes(Player* spawn, int16 version, int16* info_packet_size);
-	uchar* spawn_pos_changes(Player* spawn, int16 version, int16* pos_packet_size);
+	uchar* spawn_pos_changes(Player* spawn, int16 version, int16* pos_packet_size, bool override_ = false);
 	uchar* spawn_vis_changes(Player* spawn, int16 version, int16* vis_packet_size);
 
 	uchar* spawn_info_changes_ex(Player* spawn, int16 version, int16* info_packet_size);

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

@@ -976,7 +976,7 @@ void Spell::SetPacketInformation(PacketStruct* packet, Client* client, bool disp
 	//packet->PrintPacket();
 }
 EQ2Packet* Spell::SerializeSpecialSpell(Client* client, bool display, int8 packet_type, int8 sub_packet_type) {
-	if (client->GetVersion() <= 283)
+	if (client->GetVersion() <= 373)
 		return SerializeSpell(client, display, false, packet_type, 0, "WS_ExaminePartialSpellInfo");
 	return SerializeSpell(client, display, false, packet_type, sub_packet_type, "WS_ExamineSpecialSpellInfo");
 }
@@ -1064,7 +1064,7 @@ EQ2Packet* Spell::SerializeSpell(Client* client, bool display, bool trait_displa
 	if (version <= 561) {
 		if (packet_type == 1)
 			struct_name = "WS_ExamineEffectInfo";
-		else if (!display && (version<=283 || send_partial_packet))
+		else if (!display && (version<=373 || send_partial_packet))
 			struct_name = "WS_ExaminePartialSpellInfo";
 		else
 			struct_name = "WS_ExamineSpellInfo";

+ 1 - 1
EQ2/source/WorldServer/Tradeskills/TradeskillsPackets.cpp

@@ -542,7 +542,7 @@ void ClientPacketFunctions::SendItemCreationUI(Client* client, Recipe* recipe) {
 	packet->setDataByName("product_item_icon", item->details.icon);
 
 	if(client->GetVersion() < 860)
-		packet->setItemByName("product_item", item, client->GetPlayer(), 0, -1);
+		packet->setItemByName("product_item", item, client->GetPlayer(), 0, client->GetClientItemPacketOffset());
 	else if (client->GetVersion() < 1193)
 		packet->setItemByName("product_item", item, client->GetPlayer());
 	else

+ 1 - 1
EQ2/source/WorldServer/Traits/Traits.cpp

@@ -292,7 +292,7 @@ bool MasterTraitList::ChooseNextTrait(Client* client) {
 						if(item) {
 							//LogWrite(SPELL__INFO, 0, "Traits", "Item found %s to be sent", item->name.c_str());
 							packet->setArrayDataByName("select_reward_id", (*itr3)->item_id, item_count);
-							packet->setItemArrayDataByName("select_item", item, client->GetPlayer(), item_count, 0, -1);
+							packet->setItemArrayDataByName("select_item", item, client->GetPlayer(), item_count, 0, client->GetClientItemPacketOffset());
 							item_count++;
 						}
 					}

+ 255 - 67
EQ2/source/WorldServer/client.cpp

@@ -159,6 +159,8 @@ Client::Client(EQStream* ieqs) : underworld_cooldown_timer(5000), pos_update(125
 	zoning_z = 0;
 	zoning_instance_id = 0;
 	player_pos_changed = false;
+	player_pos_timer = Timer::GetCurrentTime2()+1000;
+	enabled_player_pos_timer = true;
 	++numclients;
 	if (world.GetServerStatisticValue(STAT_SERVER_MOST_CONNECTIONS) < numclients)
 		world.UpdateServerStatistic(STAT_SERVER_MOST_CONNECTIONS, numclients, true);
@@ -408,7 +410,7 @@ void Client::SendLoginInfo() {
 	if (version > 561) // right version? possibly not!
 		master_aa_list.DisplayAA(this, 0, 3);
 
-	if (version > 283)
+	if (version > 373)
 		SendCollectionList();
 	SendBiography();
 
@@ -440,7 +442,7 @@ void Client::SendLoginInfo() {
 		guild->SendAllGuildEvents(this);
 		guild->SendGuildMemberList(this);
 	}*/
-	if (version > 283) {
+	if (version > 373) {
 		LogWrite(CCLIENT__DEBUG, 0, "Client", "Loading Faction Updates...");
 		EQ2Packet* outapp = player->GetFactions()->FactionUpdate(GetVersion());
 		if (outapp) {
@@ -653,7 +655,7 @@ void Client::HandlePlayerRevive(int32 point_id)
 	zone_desc = GetCurrentZone()->GetZoneDescription();
 	Message(CHANNEL_NARRATIVE, "Reviving in %s at %s.", zone_desc.c_str(), location_name);
 	player->SetSpawnType(4);
-	if (version > 283) {
+	if (version > 373) {
 		packet = configReader.getStruct("WS_CancelMoveObjectMode", GetVersion());
 		if (packet)
 		{
@@ -798,7 +800,7 @@ void Client::SendCharInfo() {
 			QueuePacket(items->at(i)->serialize(GetVersion(), false, GetPlayer()));
 	}
 	safe_delete(items);
-	if (version > 283) {
+	if (version >= 373) {
 		SendTitleUpdate();
 	}
 
@@ -904,7 +906,7 @@ void Client::SendCharInfo() {
 
 void Client::SendZoneSpawns() {
 	//Allows us to place spawns almost anywhere
-	if (version > 283) {
+	if (version > 373) {
 		uchar blah[] = { 0x00,0x3C,0x1C,0x46,0x00,0x3C,0x1C,0x46,0x00,0x3C,0x1C,0x46 };
 		EQ2Packet* app = new EQ2Packet(OP_MoveableObjectPlacementCriteri, blah, sizeof(blah));
 		QueuePacket(app);
@@ -1362,7 +1364,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 				string name = macro_update->getType_EQ2_8BitString_ByName("name").data;
 				int8 count = macro_update->getType_int8_ByName("macro_count");
 
-				if (GetVersion() <= 283) {
+				if (GetVersion() <= 373) {
 					update->push_back(macro_update->getType_EQ2_8BitString_ByName("command").data);
 				}
 				else {
@@ -2020,7 +2022,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 		break;
 	}
 	case OP_PredictionUpdateMsg: {
-		LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_PredictionUpdateMsg", opcode, opcode);
+		LogWrite(OPCODE__DEBUG, 7, "Opcode", "Opcode 0x%X (%i): OP_PredictionUpdateMsg from %s", opcode, opcode, GetPlayer()->GetName());
 		if (version <= 561) {
 			int8 offset = 9;
 			if (app->pBuffer[0] == 0xFF)
@@ -2039,6 +2041,11 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 				else
 					player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version);
 				player_pos_changed = true;
+				
+				GetPlayer()->changed = true;
+				GetPlayer()->info_changed = true;
+				GetPlayer()->vis_changed = true;
+				GetPlayer()->AddChangedZoneSpawn();
 				//DumpPacket(app);
 			}
 		}
@@ -2071,7 +2078,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 		break;
 	}
 	case OP_UpdatePositionMsg: {
-		LogWrite(OPCODE__DEBUG, 7, "Opcode", "Opcode 0x%X (%i): OP_UpdatePositionMsg", opcode, opcode);
+		LogWrite(OPCODE__DEBUG, 7, "Opcode", "Opcode 0x%X (%i): OP_UpdatePositionMsg from %s", opcode, opcode, GetPlayer()->GetName());
 		int8 offset = 13;
 		if (app->pBuffer[0] == 0xFF)
 			offset += 2;
@@ -2089,6 +2096,11 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 			else
 				player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version);
 			player_pos_changed = true;
+			
+			GetPlayer()->changed = true;
+			GetPlayer()->info_changed = true;
+			GetPlayer()->vis_changed = true;
+			GetPlayer()->AddChangedZoneSpawn();
 			LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
 			//DumpPacket(app);
 		}
@@ -2542,28 +2554,43 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 		PacketStruct* packet = configReader.getStruct("WS_QuestJournalWaypoint", GetVersion());
 		if (packet) {
 			if(packet->LoadPacketData(app->pBuffer, app->size)) {
-				int32 quests = packet->getType_int32_ByName("num_quests");
-
-				if (quests > 100) // just picking a number higher than max allowed
-				{
-					LogWrite(CCLIENT__ERROR, 0, "Client", "num_quests = %u - quantity too high, aborting load.", quests);
-					break;
+				if(GetVersion() <= 561) {
+					int32 quest_id = packet->getType_int32_ByName("quest_id");
+					GetPlayer()->MPlayerQuests.writelock(__FUNCTION__, __LINE__);
+					if (player->player_quests.count(quest_id) > 0 && player->player_quests[quest_id]) {
+						if(player->player_quests[quest_id]->GetTracked())
+							player->player_quests[quest_id]->SetTracked(false);
+						else
+							player->player_quests[quest_id]->SetTracked(true);
+					
+						player->player_quests[quest_id]->SetSaveNeeded(true);
+					}
+					GetPlayer()->MPlayerQuests.releasewritelock(__FUNCTION__, __LINE__);
 				}
+				else {
+					int32 quests = packet->getType_int32_ByName("num_quests");
 
-				LogWrite(CCLIENT__DEBUG, 0, "Client", "num_quests = %u", quests);
+					if (quests > 100) // just picking a number higher than max allowed
+					{
+						LogWrite(CCLIENT__ERROR, 0, "Client", "num_quests = %u - quantity too high, aborting load.", quests);
+						break;
+					}
 
-				for (int32 i = 0; i < quests; i++) {
-					int32 id = packet->getType_int32_ByName("quest_id_0", i);
-					if (id == 0)
-						continue;
-					LogWrite(CCLIENT__DEBUG, 5, "Client", "quest_id = %u", id);
-					bool tracked = packet->getType_int8_ByName("quest_tracked_0", i) == 1 ? true : false;
-					GetPlayer()->MPlayerQuests.writelock(__FUNCTION__, __LINE__);
-					if (player->player_quests.count(id) > 0 && player->player_quests[id]) {
-						player->player_quests[id]->SetTracked(tracked);
-						player->player_quests[id]->SetSaveNeeded(true);
+					LogWrite(CCLIENT__DEBUG, 0, "Client", "num_quests = %u", quests);
+
+					for (int32 i = 0; i < quests; i++) {
+						int32 id = packet->getType_int32_ByName("quest_id_0", i);
+						if (id == 0)
+							continue;
+						LogWrite(CCLIENT__DEBUG, 5, "Client", "quest_id = %u", id);
+						bool tracked = packet->getType_int8_ByName("quest_tracked_0", i) == 1 ? true : false;
+						GetPlayer()->MPlayerQuests.writelock(__FUNCTION__, __LINE__);
+						if (player->player_quests.count(id) > 0 && player->player_quests[id]) {
+							player->player_quests[id]->SetTracked(tracked);
+							player->player_quests[id]->SetSaveNeeded(true);
+						}
+						GetPlayer()->MPlayerQuests.releasewritelock(__FUNCTION__, __LINE__);
 					}
-					GetPlayer()->MPlayerQuests.releasewritelock(__FUNCTION__, __LINE__);
 				}
 			}
 			safe_delete(packet);
@@ -3146,11 +3173,11 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 	if (!app || app->size == 0)
 		return;
 	//LogWrite(CCLIENT__DEBUG, 0, "Client", "Request2:");
-	//DumpPacket(app);
 
 	int8 type = app->pBuffer[0];
+	DumpPacket(app->pBuffer,app->size);
 	//283: item: 0, effect: 1, recipe: 2, spell: 3
-	if (version <= 283) {
+	if (version <= 373) {
 		if (type == 1)
 			type = 4;
 		else if (type == 2)
@@ -3160,7 +3187,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		Spell* spell = 0;
 		bool trait_display;
 		
-		request = configReader.getStruct((GetVersion() <= 283) ? "WS_ExamineInfoRequest" : "WS_ExamineInfoRequestMsg", GetVersion());
+		request = configReader.getStruct((GetVersion() <= 373) ? "WS_ExamineInfoRequest" : "WS_ExamineInfoRequestMsg", GetVersion());
 		if (!request) {
 			return;
 		}
@@ -3173,14 +3200,14 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		int32 tier = request->getType_int32_ByName("tier");
 		int32 trait_tier = request->getType_int32_ByName("unknown_id");
 		bool display = true;
-		if (version <= 283 && request->getType_int8_ByName("display") == 1) // this is really requesting a partial packet
+		if (version <= 373 && request->getType_int8_ByName("display") == 1) // this is really requesting a partial packet
 			display = false;
 		else if (version <= 561)
 			display = request->getType_int8_ByName("display");
 		else if (version > 561)
 			display = false; // clients default is false otherwise it pops up a window when hovering over the knowledge book abilities
-
-		//printf("Type: (%i) Tier: (%u) Unknown ID: (%u) Item ID: (%u)\n",type,tier,trait_tier,id);
+		
+		LogWrite(CCLIENT__DEBUG, 5, "Client", "Client::HandleExamineInfoRequest from %s: Type: (%i) Tier: (%u) Unknown ID: (%u) Item ID: (%u)",GetPlayer()->GetName(),type,tier,trait_tier,id);
 
 		if (trait_tier != 0xFFFFFFFF) {
 			spell = master_spell_list.GetSpell(id, trait_tier);
@@ -3204,6 +3231,12 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 			lua_interface->FindCustomSpellUnlock();
 		}
 		
+		if(!spell) { // fix ui timeout for classic, isle of refuge, dof, kos clients
+			int8 playerTier = GetPlayer()->GetSpellTier(id);
+			spell = master_spell_list.GetSpell(id, playerTier);
+			LogWrite(CCLIENT__WARNING, 0, "Client", "Client::HandleExamineInfoRequest from %s: Failed to find tier 1 spell.  Last resort try to get the spell from the player book, spell %u, tier %u", GetPlayer()->GetName(),id,playerTier);
+		}
+		
 		if (spell && !CountSentSpell(spell->GetSpellID(), spell->GetSpellTier())) {
 			if (!spell->IsCopiedSpell())
 				SetSentSpell(spell->GetSpellID(), spell->GetSpellTier());
@@ -3217,6 +3250,9 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 			//DumpPacket(app);
 			QueuePacket(app);
 		}
+		else {
+				LogWrite(CCLIENT__ERROR, 0, "Client", "Client::HandleExamineInfoRequest from %s: Failed to successfully send Type: (%i) Tier: (%u) Unknown ID: (%u) Item ID: (%u)",GetPlayer()->GetName(),type,tier,trait_tier,id);
+		}
 	}
 	else if (type == 0) {
 		request = configReader.getStruct("WS_ExamineInfoItemRequest", GetVersion());
@@ -3312,6 +3348,8 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 			return;
 		}
 		int32 id = request->getType_int32_ByName("item_id");
+
+		LogWrite(CCLIENT__DEBUG, 5, "Client", "Client::HandleExamineInfoRequest from %s: Found Type: (%i) Item ID: (%u)",GetPlayer()->GetName(),type,id);
 		//int32 unknown_0 = request->getType_int32_ByName("unknown",0);
 		//int32 unknown_1 = request->getType_int32_ByName("unknown",1);
 		//int8 unknown2 = request->getType_int8_ByName("unknown2");
@@ -3344,6 +3382,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		SpellEffects* effect = player->GetSpellEffect(id);
 		//printf("Type: (%i) Unknown5: (%i) Item ID: (%u)\n",type,unknown5,id);
 		if (effect) {
+			LogWrite(CCLIENT__DEBUG, 5, "Client", "Client::HandleExamineInfoRequest from %s: Found Type: (%i) Item ID: (%u)",GetPlayer()->GetName(),type,id);
 			int8 tier = effect->tier;
 			Spell* spell = master_spell_list.GetSpell(id, tier);
 
@@ -3358,20 +3397,23 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 				lua_interface->FindCustomSpellUnlock();
 			}
 
-			if (spell && !CountSentSpell(id, tier)) {
+			if (spell && (version <= 561 || !CountSentSpell(id, tier))) { // fix DoF and KoS clients UI Timeout
 				if (!spell->IsCopiedSpell())
 					SetSentSpell(spell->GetSpellID(), spell->GetSpellTier());
 				int8 type = 0;
-				if (version <= 283)
+				if (version <= 373)
 					type = 1;
 				EQ2Packet* app = spell->SerializeSpecialSpell(this, false, type, 0x81);
 				//DumpPacket(app);
 				QueuePacket(app);
 			}
 		}
+		else {
+			LogWrite(CCLIENT__ERROR, 0, "Client", "Client::HandleExamineInfoRequest from %s: Cannot Find Type: (%i) Item ID: (%u)",GetPlayer()->GetName(),type,id);
+		}
 	}
 	else if (type == 5) { // recipe info
-	request = configReader.getStruct((GetVersion() <= 283) ? "WS_ExamineInfoRequest" : "WS_ExamineInfoRequestMsg", GetVersion());
+	request = configReader.getStruct((GetVersion() <= 373) ? "WS_ExamineInfoRequest" : "WS_ExamineInfoRequestMsg", GetVersion());
 		if (!request)
 			return;
 		if(!request->LoadPacketData(app->pBuffer, app->size)) {
@@ -3401,7 +3443,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		Spell* spell = 0;
 		//Spell* spell2 = 0;
 		//AltAdvanceData* data = 0;
-		request = configReader.getStruct((GetVersion() <= 283) ? "WS_ExamineInfoRequest" : "WS_ExamineInfoRequestMsg", GetVersion());
+		request = configReader.getStruct((GetVersion() <= 373) ? "WS_ExamineInfoRequest" : "WS_ExamineInfoRequestMsg", GetVersion());
 		if (!request)
 			return;
 		if(!request->LoadPacketData(app->pBuffer, app->size)) {
@@ -3430,7 +3472,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 
 		if (!spell)
 		{
-			LogWrite(WORLD__ERROR, 0, "WORLD", "FAILED Examine Info Request-> Spell ID: %u, tier: %i", id, tier);
+			LogWrite(CCLIENT__ERROR, 0, "Client", "WORLD", "Client::HandleExamineInfoRequest from %s: FAILED Examine Info Request-> Spell ID: %u, tier: %i", GetPlayer()->GetName(), id, tier);
 			return;
 		}
 
@@ -3448,7 +3490,7 @@ void Client::HandleExamineInfoRequest(EQApplicationPacket* app) {
 		//}
 	}
 	else {
-		LogWrite(WORLD__ERROR, 0, "World", "Unknown examine request: %i", (int)type);
+		LogWrite(CCLIENT__ERROR, 0, "World", "Client::HandleExamineInfoRequest from %s: Unknown examine request: %i", GetPlayer()->GetName(), (int)type);
 		DumpPacket(app);
 	}
 	safe_delete(request);
@@ -3658,7 +3700,20 @@ bool Client::Process(bool zone_process) {
 		if(GetPlayer()->GetRegionMap())
 			GetPlayer()->GetRegionMap()->TicRegionsNearSpawn(this->GetPlayer(), regionDebugMessaging ? this : nullptr);
 		
+		if(!player_pos_changed && IsReadyForUpdates() && player_pos_timer < Timer::GetCurrentTime2() && enabled_player_pos_timer) {
+			if(version > 373) {
+			GetPlayer()->info_changed = true;
+			GetPlayer()->vis_changed = true;
+			GetPlayer()->position_changed = true;
+			GetPlayer()->changed = true;
+			GetPlayer()->AddChangedZoneSpawn();
+			}
+			player_pos_timer = Timer::GetCurrentTime2()+5000;
+			enabled_player_pos_timer = false;
+		}
 		if(player_pos_changed && IsReadyForUpdates()) {
+			player_pos_timer = Timer::GetCurrentTime2()+500;
+			enabled_player_pos_timer = true;
 			if(!underworld_cooldown_timer.Enabled() || (underworld_cooldown_timer.Enabled() && underworld_cooldown_timer.Check())) {
 				bool underworld = false;
 				if(rule_manager.GetGlobalRule(R_Zone, UseMapUnderworldCoords)->GetBool()) {
@@ -3688,7 +3743,6 @@ bool Client::Process(bool zone_process) {
 			}
 			//GetPlayer()->CalculateLocation();
 			client_list.CheckPlayersInvisStatus(this);
-			GetCurrentZone()->SendPlayerPositionChanges(GetPlayer());
 			
 			player_pos_changed = false;
 			
@@ -4094,6 +4148,79 @@ int8 Client::GetMessageChannelColor(int8 channel_type) {
 			}
 		}
 	}
+	else if (GetVersion() <= 373) {
+		if (channel_type <=18)
+			return channel_type;
+		switch (channel_type) {
+			case CHANNEL_PRIVATE_CHAT:
+			case CHANNEL_NONPLAYER_TELL:
+				return 22;
+			case CHANNEL_PRIVATE_TELL:
+			case CHANNEL_TELL_FROM_CS:
+				return 23;
+			case CHANNEL_CHAT_CHANNEL_TEXT:
+			case CHANNEL_OUT_OF_CHARACTER:
+			case CHANNEL_CUSTOM_CHANNEL:
+			case CHANNEL_CHARACTER_TEXT:
+			case CHANNEL_REWARD:
+			case CHANNEL_DEATH:
+			case CHANNEL_PET_CHAT:
+			case CHANNEL_SKILL:
+				return 26;
+			case CHANNEL_AUCTION:
+				return 27;
+			case CHANNEL_SPELLS:
+			case CHANNEL_YOU_CAST:
+			case CHANNEL_YOU_FAIL:
+				return channel_type - 8;
+			case CHANNEL_FRIENDLY_CAST:
+			case CHANNEL_FRIENDLY_FAIL:
+			case CHANNEL_OTHER_CAST:
+			case CHANNEL_OTHER_FAIL:
+			case CHANNEL_HOSTILE_CAST:
+			case CHANNEL_HOSTILE_FAIL:
+			case CHANNEL_WORN_OFF:
+			case CHANNEL_SPELLS_OTHER:
+				return channel_type - 9;
+			case CHANNEL_COMBAT:
+				return channel_type - 15;
+			case CHANNEL_HEROIC_OPPORTUNITY:
+			case CHANNEL_NON_MELEE_DAMAGE:
+			case CHANNEL_DAMAGE_SHIELD:
+				return channel_type - 16;
+			case CHANNEL_MELEE_COMBAT:
+			case CHANNEL_WARNINGS:
+			case CHANNEL_YOU_HIT:
+			case CHANNEL_YOU_MISS:
+			case CHANNEL_ATTACKER_HITS:
+			case CHANNEL_ATTACKER_MISSES:
+				return channel_type - 18;
+			case CHANNEL_OTHER_HIT:
+			case CHANNEL_OTHER_MISSES:
+			case CHANNEL_CRITICAL_HIT:
+				return channel_type - 22;
+			case CHANNEL_OTHER:
+			case CHANNEL_MONEY_SPLIT:
+			case CHANNEL_LOOT:
+				return channel_type - 30;
+			case CHANNEL_COMMAND_TEXT:
+			case CHANNEL_BROADCAST:
+			case CHANNEL_WHO:
+			case CHANNEL_COMMANDS:
+			case CHANNEL_MERCHANT:
+			case CHANNEL_MERCHANT_BUY_SELL:
+			case CHANNEL_CONSIDER_MESSAGE:
+			case CHANNEL_CON_MINUS_2:
+			case CHANNEL_CON_MINUS_1:
+			case CHANNEL_CON_0:
+			case CHANNEL_CON_1:
+			case CHANNEL_CON_2:
+				return 68;
+			default: {
+				return CHANNEL_DEFAULT;
+			}
+		}
+	}
 	else if (GetVersion() <= 561) {
 		if (channel_type < 20)
 			return channel_type;
@@ -4674,6 +4801,13 @@ void Client::Zone(ZoneServer* new_zone, bool set_coords, bool is_spell) {
 		return;
 	}
 	
+	if(GetVersion() == 373 && GetAdminStatus() == 0) {
+		if(strncasecmp(new_zone->GetZoneFile(),"boat_06p_tutorial02",19) && strncasecmp(new_zone->GetZoneFile(),"tutorial_island02",17)) {
+			SimpleMessage(CHANNEL_COLOR_RED, "This client does not currently support beyond the boat tutorial (farjourneyfreeport) or island of refuge (islerefuge1)");
+			return;
+		}
+	}
+	
 	client_zoning = true;
 	zoning_id = new_zone->GetZoneID();
 	zoning_instance_id = new_zone->GetInstanceID();
@@ -4748,7 +4882,7 @@ void Client::Zone(ZoneServer* new_zone, bool set_coords, bool is_spell) {
 
 	LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Sending to zone_auth.AddAuth...", __FUNCTION__);
 	zone_auth.AddAuth(new ZoneAuthRequest(GetAccountID(), player->GetName(), key));
-	if (version > 283) {
+	if (version > 373) {
 		PacketStruct* packet = configReader.getStruct("WS_CancelMoveObjectMode", version);
 		if (packet)
 		{
@@ -5074,9 +5208,9 @@ void Client::ChangeLevel(int16 old_level, int16 new_level) {
 	LogWrite(MISC__TODO, 1, "TODO", "Get new HP/POWER/stat based on default values from DB\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
 
 	GetPlayer()->SetTotalHPBase(new_level * new_level * 2 + 40);
-	GetPlayer()->SetTotalHPBaseInstance(GetPlayer()->GetTotalHPBaseInstance());
+	GetPlayer()->SetTotalHPBaseInstance(GetPlayer()->GetTotalHPBase()); // we need the hp base to override the instance as the new default
 	GetPlayer()->SetTotalPowerBase((sint32)(new_level * new_level * 2.1 + 45));
-	GetPlayer()->SetTotalPowerBaseInstance(GetPlayer()->GetTotalPowerBaseInstance());
+	GetPlayer()->SetTotalPowerBaseInstance(GetPlayer()->GetTotalPowerBase()); // we need the hp base to override the instance as the new default
 	GetPlayer()->CalculateBonuses();
 	GetPlayer()->SetHP(GetPlayer()->GetTotalHP());
 	GetPlayer()->SetPower(GetPlayer()->GetTotalPower());
@@ -5518,7 +5652,7 @@ void Client::SendLootResponsePacket(int32 total_coins, vector<Item*>* items, Spa
 				}
 			}
 		}
-		if (GetVersion() >= 284) {
+		if (GetVersion() >= 374) {
 			if (GetVersion() > 561) {
 				if (send_items.size() > 0) {
 					packet->setDataByName("loot_count", send_items.size());
@@ -5617,10 +5751,10 @@ void Client::SendLootResponsePacket(int32 total_coins, vector<Item*>* items, Spa
 						packet->setArrayDataByName("ability_id", 0xFFFFFFFF, i);
 				}
 			}
+			packet->setDataByName("display", 1);
+			packet->setDataByName("loot_type", entity->GetLootMethod()); // normal
+			packet->setDataByName("lotto_timeout", entity->GetLootTimeRemaining() / 1000); // 60 seconds
 			packet->setDataByName("object_id", entity->GetID());
-			packet->setDataByName("unknown3", 1);
-			packet->setDataByName("unknown4", 1);
-			packet->setDataByName("unknown5", 60);
 			outapp = packet->serialize();
 		}
 		if (outapp) {
@@ -6525,7 +6659,7 @@ void Client::CheckPlayerQuestsSpellUpdate(Spell* spell) {
 }
 
 void Client::AddPendingQuest(Quest* quest, bool forced) {
-	if (version <= 283 || forced) { //this client doesn't ask if you want the quest, so auto accept
+	if (version <= 372 || forced) { //this client doesn't ask if you want the quest, so auto accept
 		MPendingQuestAccept.lock();
 		player->pending_quests[quest->GetQuestID()] = quest;
 		MPendingQuestAccept.unlock();
@@ -6972,7 +7106,7 @@ void Client::DisplayQuestRewards(Quest* quest, int64 coin, vector<Item*>* reward
 					Item* item = rewards->at(i);
 					if (item) {
 						packet2->setArrayDataByName("reward_id", item->details.item_id, i);
-						packet2->setItemArrayDataByName("item", item, player, i, 0, -1);
+						packet2->setItemArrayDataByName("item", item, player, i, 0, GetClientItemPacketOffset());
 					}
 					if(!quest) //this entire function is either for version <=561 or for quest rewards in middle of quest, so quest should be 0, otherwise quest will handle the rewards
 						player->AddPendingItemReward(item); //item reference will be deleted after the player accepts it
@@ -6983,7 +7117,7 @@ void Client::DisplayQuestRewards(Quest* quest, int64 coin, vector<Item*>* reward
 				Item* item = items.at(j);
 				if (item) {
 					packet2->setArrayDataByName("reward_id", item->details.item_id, i);
-					packet2->setItemArrayDataByName("item", item, player, i, 0, -1);
+					packet2->setItemArrayDataByName("item", item, player, i, 0, GetClientItemPacketOffset());
 				}
 				if(!quest) //this entire function is either for version <=561 or for quest rewards in middle of quest, so quest should be 0, otherwise quest will handle the rewards
 					player->AddPendingItemReward(item); //item reference will be deleted after the player accepts it
@@ -6997,7 +7131,7 @@ void Client::DisplayQuestRewards(Quest* quest, int64 coin, vector<Item*>* reward
 				Item* item = selectable_rewards->at(i);
 				if (item) {
 					packet2->setArrayDataByName("select_reward_id", item->details.item_id, i);
-					packet2->setItemArrayDataByName("select_item", item, player, i, 0, -1);
+					packet2->setItemArrayDataByName("select_item", item, player, i, 0, GetClientItemPacketOffset());
 					if (!quest) //this entire function is either for version <=561 or for quest rewards in middle of quest, so quest should be 0, otherwise quest will handle the rewards
 						player->AddPendingSelectableItemReward(source_id, item); //item reference will be deleted after the player selects one
 				}
@@ -7056,7 +7190,7 @@ void Client::PopulateQuestRewardItems(vector <Item*>* items, PacketStruct* packe
 		for (int32 i = 0; i < items->size();) {
 			packet->setArrayDataByName(reward_id_str.c_str(), items->at(i)->details.item_id, pos);
 			if (version < 860)
-				packet->setItemArrayDataByName(item_str.c_str(), items->at(i), player, pos, 0, -1);
+				packet->setItemArrayDataByName(item_str.c_str(), items->at(i), player, pos, 0, GetClientItemPacketOffset());
 			else if (version < 1193)
 				packet->setItemArrayDataByName(item_str.c_str(), items->at(i), player, pos);
 			else
@@ -8361,11 +8495,14 @@ void Client::SendBuyMerchantList(bool sell) {
 						packet->setArrayDataByName("station_cash", ItemInfo.price_stationcash, i);
 					}
 				}
-				if (GetVersion() <= 561) {
+				if (GetVersion() < 561) {
 					//buy is 0 so dont need to set it
 					if (sell)
 						packet->setDataByName("type", 1);
 				}
+				else if (GetVersion() == 561) {
+					packet->setDataByName("type", 2);
+				}
 				else {
 					if (sell)
 						packet->setDataByName("type", 130);
@@ -8508,9 +8645,12 @@ void Client::SendSellMerchantList(bool sell) {
 					if (GetVersion() <= 1096)
 						packet->setArrayDataByName("description", item->description.c_str(), i);
 				}
-				if (GetVersion() <= 561) {
+				if (GetVersion() < 561) {
 					packet->setDataByName("type", 1);
 				}
+				else if(GetVersion() == 561) {
+						packet->setDataByName("type", 1);
+				}
 				else {
 					if (sell)
 						packet->setDataByName("type", 129);
@@ -8974,7 +9114,7 @@ void Client::SendMailList() {
 					{
 						item->stack_count = mail->stack > 1 ? mail->stack : 0;
 						if (version < 860)
-							p->setItemArrayDataByName("item", item, player, i, 0, -1);
+							p->setItemArrayDataByName("item", item, player, i, 0, GetClientItemPacketOffset());
 						else if (version < 1193)
 							p->setItemArrayDataByName("item", item, player, i);
 						else
@@ -9055,7 +9195,7 @@ void Client::DisplayMailMessage(int32 mail_id) {
 					Item* item = master_item_list.GetItem(mail->char_item_id);
 					item->stack_count = mail->stack > 1 ? mail->stack : 0;
 					if (version < 860)
-						packet->setItemByName("item", item, player, 0, -1);
+						packet->setItemByName("item", item, player, 0, version <= 373 ? -2 : -1);
 					else if (version < 1193)
 						packet->setItemByName("item", item, player, 0, 0);
 					else
@@ -9217,7 +9357,7 @@ bool Client::AddMailItem(Item* item)
 				packet->setDataByName("stack", mail_window.stack);
 				item->stack_count = mail_window.stack;
 				if (version < 860)
-					packet->setItemByName("item", item, player, 0, -1);
+					packet->setItemByName("item", item, player, 0, version <= 373 ? -2 : -1);
 				else if (version < 1193)
 					packet->setItemByName("item", item, player, 0, 0);
 				else
@@ -9280,7 +9420,7 @@ bool Client::AddMailCoin(int32 copper, int32 silver, int32 gold, int32 plat) {
 					packet->setDataByName("stack", mail_window.stack);
 					item->stack_count = mail_window.stack;
 					if (version < 860)
-						packet->setItemByName("item", item, player, 0, -1);
+						packet->setItemByName("item", item, player, 0, version <= 373 ? -2 : -1);
 					else if (version < 1193)
 						packet->setItemByName("item", item, player, 0, 0);
 					else
@@ -10114,7 +10254,17 @@ void Client::InspectPlayer(Player* player_to_inspect) {
 			for (size_t i = 0; i < biography.length(); i++)
 				packet->setArrayDataByName("biography_char", biography[i], i);
 			
-			if(GetVersion() <= 561) {
+			if(GetVersion() <= 373) {
+				for(int32 s=0;s<20;s++) {
+					int32 slot = s;
+					
+					char item_slot_name[64], item_slot_name_appearance[64];
+					_snprintf(item_slot_name,64,"slot_%u",slot);
+					Item* pw = player_to_inspect->GetEquipmentList()->GetItem(GetPlayer()->ConvertSlotFromClient(s, GetVersion()));
+					packet->setItemByName(item_slot_name, pw, this->GetPlayer(), 0, 7, true, true, true);
+				}
+			}
+			else if(GetVersion() <= 561) {
 				for(int32 s=0;s<22;s++) {
 					int32 slot = s;
 					
@@ -10546,7 +10696,7 @@ void Client::DisplayCollectionComplete(Collection* collection) {
 							Item* item = reward_items->at(i)->item;
 							if (item) {
 								packet2->setArrayDataByName("reward_id", item->details.item_id, i);
-								packet2->setItemArrayDataByName("item", item, player, i, 0, -1);
+								packet2->setItemArrayDataByName("item", item, player, i, 0, GetClientItemPacketOffset());
 							}
 						}
 					}
@@ -10557,7 +10707,7 @@ void Client::DisplayCollectionComplete(Collection* collection) {
 						Item* item = selectable_reward_items->at(i)->item;
 						if (item) {
 							packet2->setArrayDataByName("select_reward_id", item->details.item_id, i);
-							packet2->setItemArrayDataByName("select_item", item, player, i, 0, -1);
+							packet2->setItemArrayDataByName("select_item", item, player, i, 0, GetClientItemPacketOffset());
 						}
 					}
 				}
@@ -10592,7 +10742,7 @@ void Client::DisplayCollectionComplete(Collection* collection) {
 
 		packet->setArrayDataByName("reward_id", reward_item->item->details.item_id, i);
 		if (version < 860)
-			packet->setItemArrayDataByName("item", reward_item->item, player, i, 0, -1);
+			packet->setItemArrayDataByName("item", reward_item->item, player, i, 0, GetClientItemPacketOffset());
 		else if (version < 1193)
 			packet->setItemArrayDataByName("item", reward_item->item, player, i);
 		else
@@ -10610,7 +10760,7 @@ void Client::DisplayCollectionComplete(Collection* collection) {
 
 		packet->setArrayDataByName("select_reward_id", reward_item->item->details.item_id, i);
 		if (version < 860)
-			packet->setItemArrayDataByName("select_item", reward_item->item, player, i, 0, -1);
+			packet->setItemArrayDataByName("select_item", reward_item->item, player, i, 0, GetClientItemPacketOffset());
 		else if (version < 1193)
 			packet->setItemArrayDataByName("select_item", reward_item->item, player, i);
 		else
@@ -11344,6 +11494,10 @@ void Client::SendSpawnChanges(set<Spawn*>& spawns) {
 		if (index == 0 || !GetPlayer()->WasSentSpawn(spawn->GetID()))
 			continue;
 
+		if(GetPlayer() == spawn && GetVersion() <= 284) { // stopped self client/player warping in the EQ2 release disc (Beta), don't send yourself in bulk spawn updates
+			continue;
+		}
+		
 		int16 tmp_info_size = 0;
 		int16 tmp_pos_size = 0;
 		int16 tmp_vis_size = 0;
@@ -11476,19 +11630,19 @@ void Client::MakeSpawnChangePacket(map<int32, SpawnData> info_changes, map<int32
 		opcode_val = EQOpcodeManager[GetOpcodeVersion(version)]->EmuToEQ(OP_EqUpdateGhostCmd);
 	}
 	int32 size = info_size + pos_size + vis_size + 8;
-	if (version > 283) //version 283 and below uses an overload for size, not always 4 bytes
-		size += 3;
 	size += CheckOverLoadSize(info_size);
 	size += CheckOverLoadSize(pos_size);
 	size += CheckOverLoadSize(vis_size);
-	if (version <= 283 && size >= 255) {//1 byte to 3 for overloaded val
+	if (version <= 373 && size >= 255) {//1 byte to 3 for overloaded val
 		size += 2;
 	}
+	else if (version >= 374)
+		size += 3;
 	uchar* tmp = new uchar[size];
 	uchar* ptr = tmp;
 
 	memset(tmp, 0, size);
-	if (version <= 283) {
+	if (version <= 373) {
 		if (size >= 255) {
 			size -= 3;
 			memcpy(ptr, &oversized, sizeof(int8));
@@ -11779,6 +11933,7 @@ void Client::SendShowBook(Spawn* sender, string title, int8 language, int8 num_p
 		{
 			// release client
 			case 283:
+			case 373: // trial isle client
 			{
 				endString.append(page);
 				break;
@@ -11802,7 +11957,7 @@ void Client::SendShowBook(Spawn* sender, string title, int8 language, int8 num_p
 		}
 	}
 
-	if (GetVersion() == 283)
+	if (GetVersion() <= 373)
 	{
 		packet->setDataByName("page_text", endString.c_str());
 	}
@@ -11848,6 +12003,7 @@ void Client::SendShowBook(Spawn* sender, string title, int8 language, vector<Ite
 		{
 			// release client
 		case 283:
+		case 373: // trial isle client
 		{
 			endString.append(pageText);
 			break;
@@ -12065,6 +12221,10 @@ void Client::ConsumeFoodDrink(Item* item, int32 slot)
 				else
 					Message(CHANNEL_NARRATIVE, "You drink a %s.", item->name.c_str());
 			}
+			else {
+					Message(CHANNEL_NARRATIVE, "SERVER BUG! Item Script not assigned for consuming '%s'.", item->name.c_str());
+					return;
+			}
 
 		if (item->details.count > 1) {
 			item->details.count -= 1;
@@ -12077,6 +12237,10 @@ void Client::ConsumeFoodDrink(Item* item, int32 slot)
 		}
 		GetPlayer()->SetCharSheetChanged(true);
 		QueuePacket(player->GetEquipmentList()->serialize(GetVersion(), player));
+		if(GetVersion() <= 373) {
+			EQ2Packet* outapp = GetPlayer()->SendInventoryUpdate(GetVersion());
+			QueuePacket(outapp);
+		}
 	}
 }
 
@@ -12466,6 +12630,30 @@ bool Client::CheckConsumptionAllowed(int16 slot, bool send_message) {
 			break;
 		}
 		default: {
+			if (GetVersion() <= 373) {
+				Item* item = GetPlayer()->item_list.GetItemFromIndex(slot);
+				if(item->IsFood()) {
+					if(item->IsFoodFood()) {
+						if(GetPlayer()->GetSpellEffectBySpellType(SPELL_TYPE_FOOD)) {
+							if(send_message) {
+								Message(CHANNEL_NARRATIVE, "If you ate anymore you would explode!");
+							}
+							return false;
+						}
+						return true;
+					}
+					else if(item->IsFoodDrink()) {
+						if (GetPlayer()->GetSpellEffectBySpellType(SPELL_TYPE_DRINK))
+						{
+							if(send_message) {
+								Message(CHANNEL_NARRATIVE, "If you drank anymore you would explode!");
+							}
+							return false;
+						}
+						return true;
+					}
+				}
+			}
 			return false;
 			break;
 		}

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

@@ -585,6 +585,9 @@ public:
 	
 	void	SendHearCast(Spawn* caster, Spawn* target, int32 spell_visual, int16 cast_time);
 	int32	GetSpellVisualOverride(int32 spell_visual);
+	
+	sint16	GetClientItemPacketOffset() { sint16 offset = -1; if(GetVersion() <= 373) { offset = -2; } return offset; }
+	
 private:
 	void	AddRecipeToPlayerPack(Recipe* recipe, PacketStruct* packet, int16* i);
 	void    SavePlayerImages();
@@ -673,6 +676,8 @@ private:
 	Timer	spawn_removal_timer;
 	std::atomic<bool> player_pos_changed;
 	std::atomic<int8> player_pos_change_count;
+	int32 player_pos_timer;
+	bool enabled_player_pos_timer;
 	bool HandlePacket(EQApplicationPacket *app);
 	EQStream* eqs;
 	bool quickbar_changed;

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

@@ -2276,9 +2276,11 @@ void ZoneServer::SendPlayerPositionChanges(Player* player){
 		for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
 			client = *client_itr;
 			if(player != client->GetPlayer() && client->GetPlayer()->WasSentSpawn(player->GetID())){
-				EQ2Packet* outapp = player->player_position_update_packet(client->GetPlayer(), client->GetVersion());
-				if(outapp)
-					client->QueuePacket(outapp);
+				if(client->GetVersion() > 373) {
+					EQ2Packet* outapp = player->player_position_update_packet(client->GetPlayer(), client->GetVersion(), true);
+					if(outapp)
+						client->QueuePacket(outapp);
+				}
 			}
 		}
 		MClientList.releasereadlock(__FUNCTION__, __LINE__);
@@ -3718,6 +3720,7 @@ void ZoneServer::HandleChatMessage(Client* client, Spawn* from, const char* to,
 				packet->setMediumStringByName("from", from->GetName());
 			if (client->GetPlayer() != from)
 				packet->setMediumStringByName("to", client->GetPlayer()->GetName());
+			int8 clientchannel = client->GetMessageChannelColor(channel);
 			packet->setDataByName("channel", client->GetMessageChannelColor(channel));
 			if (from && ((from == client->GetPlayer()) || (client->GetPlayer()->WasSentSpawn(from->GetID()))))
 				packet->setDataByName("from_spawn_id", client->GetPlayer()->GetIDWithPlayerSpawn(from));
@@ -4500,7 +4503,7 @@ void ZoneServer::RemoveSpawn(Spawn* spawn, bool delete_spawn, bool respawn, bool
 	for (client_itr = clients.begin(); client_itr != clients.end(); client_itr++) {
 		client = *client_itr;
 
-		if (client && (client->GetVersion() > 283 || !client->IsZoning() || client->GetPlayer() != spawn)) { //don't send destroy ghost of 283 client when zoning
+		if (client && (client->GetVersion() > 373 || !client->IsZoning() || client->GetPlayer() != spawn)) { //don't send destroy ghost of 283 client when zoning
 			if (client->GetPlayer()->HasTarget() && client->GetPlayer()->GetTarget() == spawn)
 				client->GetPlayer()->SetTarget(0);
 			if(client->GetPlayer()->WasSentSpawn(spawn->GetID()) || client->GetPlayer()->IsSendingSpawn(spawn->GetID()))
@@ -5427,9 +5430,10 @@ void ZoneServer::SendSpellFailedPacket(Client* client, int16 error){
 		/*		Temp solution, need to modify the error code before this function and while we still have access to the spell/combat art		*/
 		error = master_spell_list.GetSpellErrorValue(client->GetVersion(), error);
 
-		if(client->GetVersion() <= 561 && error) {
+		if(client->GetVersion() > 373 && client->GetVersion() <= 561 && error) {
 			error += 1;
 		}
+		
 		packet->setDataByName("error_code", error);
 		//packet->PrintPacket();
 		client->QueuePacket(packet->serialize());

+ 7 - 3
EQ2/source/common/EQ2_Common_Structs.h

@@ -182,6 +182,10 @@ struct PositionData{
 	float			SpeedY;
 	float			SpeedZ;
 	float			SideSpeed;
+	float			VertSpeed;
+	float			ClientHeading1;
+	float			ClientHeading2;
+	float			ClientPitch;
 	int16			collision_radius;
 	int16			state;
 };
@@ -234,7 +238,7 @@ struct Player_Update{
 /*0012*/	float	unknown3[8];
 /*0044*/	float	speed;
 /*0048*/	float	side_speed;
-/*0052*/	float	unknown4;
+/*0052*/	float	vert_speed;
 /*0056*/	float	orig_x;
 /*0060*/	float	orig_y;
 /*0064*/	float	orig_z;
@@ -298,7 +302,7 @@ struct Player_Update1096{
 /*0044*/	float	unk_speed;
 /*0048*/	float	speed;
 /*0052*/	float	side_speed;
-/*0056*/	float	unknown4;
+/*0056*/	float	vert_speed;
 /*0060*/	float	orig_x;
 /*0064*/	float	orig_y;
 /*0068*/	float	orig_z;
@@ -329,7 +333,7 @@ struct Player_Update1144{
 /*0044*/    float    unk_speed;
 /*0048*/    float    speed;
 /*0052*/    float    side_speed;
-/*0056*/    float    unknown4;
+/*0056*/    float    vert_speed;
 /*0060*/    float    orig_x;
 /*0064*/    float    orig_y;
 /*0068*/    float    orig_z;

+ 4 - 0
EQ2/source/common/EQPacket.cpp

@@ -81,6 +81,8 @@ int8 EQ2Packet::PreparePacket(int16 MaxLen) {
 		LogWrite(PACKET__ERROR, 0, "Packet", "Version %i is not listed in the opcodes table for opcode %s", version, EQOpcodeManager[OpcodeVersion]->EmuToName(login_op));
 		return -1;
 	}
+	
+	int16 orig_opcode = login_opcode;
 	int8 offset = 0;
 	//one of the int16s is for the seq, other is for the EQ2 opcode and compressed flag (OP_Packet is the header, not the opcode)
 	int32 new_size = size + sizeof(int16) + sizeof(int8);
@@ -112,10 +114,12 @@ int8 EQ2Packet::PreparePacket(int16 MaxLen) {
 		ptr += sizeof(int8);
 	}
 	memcpy(ptr, pBuffer, size);
+	
 	safe_delete_array(pBuffer);
 	pBuffer = new_buffer;
 	offset = new_size - size - 1;
 	size = new_size;
+	
 	return offset;
 }
 

+ 1 - 1
EQ2/source/common/MiscFunctions.cpp

@@ -430,7 +430,7 @@ int32 Pack(uchar* data, uchar* src, int16 srcLen, int16 dstLen, int16 version, b
     int		codeLen = 0;
     int8	zeroLen = 0;
 	memset(data,0,dstLen);
-	if (version > 1 && version <= 283)
+	if (version > 1 && version <= 374)
 		reverse = false;
     while(pos < srcLen) {
         if(src[pos] || codeLen) {

+ 22 - 14
EQ2/source/common/PacketStruct.cpp

@@ -1790,14 +1790,14 @@ void PacketStruct::serializePacket(bool clear) {
 	}
 #ifndef LOGIN
 	if (client_cmd) {
-		int16 opcode_val = GetOpcodeValue(client_version);			
+		int16 opcode_val = GetOpcodeValue(client_version);
 		Clear();
 		int32 size = client_data.length() + 3; //gotta add the opcode and oversized
 		int8 oversized = 0xFF;
 		int16 OpcodeVersion = GetOpcodeVersion(client_version);
 		if (opcode_val == EQOpcodeManager[OpcodeVersion]->EmuToEQ(OP_EqExamineInfoCmd) && client_version > 561)
 			size += (size - 9);
-		if (client_version <= 283) {
+		if (client_version <= 374) {
 			if (size >= 255) {
 				StructAddData(oversized, sizeof(int8), 0);
 				StructAddData(size, sizeof(int16), 0);
@@ -2232,6 +2232,7 @@ bool PacketStruct::SetOpcode(const char* new_opcode) {
 
 EQ2Packet* PacketStruct::serialize() {
 	serializePacket();
+	
 	if (GetOpcode() != OP_Unknown)
 		return new EQ2Packet(GetOpcode(), getData(), getDataSize());
 	else {
@@ -2554,17 +2555,23 @@ void PacketStruct::LoadFromPacketStruct(PacketStruct* packet, char* substruct_na
 }
 
 #ifdef WORLD
-void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 index, sint8 offset, bool loot_item, bool make_empty_item_packet) {
+void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 index, sint8 offset, bool loot_item, bool make_empty_item_packet, bool inspect) {
 	if (!ds)
 		return;
 	uchar* ptr = (uchar*)GetStructPointer(ds);
 	
 	if(!item) {
 		if(make_empty_item_packet) {
-			if(client_version <= 561) {
+			if(client_version <= 373) {
+				// for player inspection this will offset the parts of the packet that have no items
+				uchar bogusItemBuffer[] = {0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x64,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+				int sizeOfArray = sizeof(bogusItemBuffer) / sizeof(bogusItemBuffer[0]);
+				ds->SetItemSize(sizeOfArray);
+				memcpy(ptr, bogusItemBuffer, sizeOfArray);	
+			}
+			else if(client_version <= 561) {
 				// for player inspection this will offset the parts of the packet that have no items
 				uchar bogusItemBuffer[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x8C,0x5A,0xF1,0xD2,0x8C,0x5A,0xF1,0xD2,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00};
-				bogusItemBuffer[World::newValue] = 0x00;
 				int sizeOfArray = sizeof(bogusItemBuffer) / sizeof(bogusItemBuffer[0]);
 				ds->SetItemSize(sizeOfArray);
 				memcpy(ptr, bogusItemBuffer, sizeOfArray);	
@@ -2579,17 +2586,20 @@ void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 ind
 		}
 		return;
 	}
-	PacketStruct* packet = item->PrepareItem(client_version, false, loot_item);
+	PacketStruct* packet = item->PrepareItem(client_version, false, loot_item, inspect);
 	if (packet) {
 		int16 item_version = GetItemPacketType(packet->GetVersion());
 		// newer clients can handle the item structure without the loot_item flag set to true, older clients like DoF need a smaller subpacket of item
-		item->serialize(packet, true, player, item_version, 0, (packet->GetVersion() <= 561) ? loot_item : false);
+		item->serialize(packet, true, player, item_version, 0, (packet->GetVersion() <= 561) ? loot_item : false, inspect);
 
 		string* generic_string_data = packet->serializeString();
 		int32 size = generic_string_data->length(); // had to set to 81
 		int32 actual_length = size;
 
-		if(offset > 12) {
+		if(client_version <= 373 && make_empty_item_packet && inspect) {
+			size += 2; // end padding for the specialized item (used for player inspection)
+		}
+		else if(offset > 12) {
 			size += 6; // end padding for the specialized item (used for player inspection)
 		}
 		//DumpPacket((uchar*)generic_string_data->c_str(), size);
@@ -2620,22 +2630,20 @@ void PacketStruct::setItem(DataStruct* ds, Item* item, Player* player, int32 ind
 			memcpy(out_ptr, (uchar*)generic_string_data->c_str() + (13 + offset), generic_string_data->length() - (13 + offset));
 		}
 		ds->SetItemSize(size);
-	//	printf("Item Name: %s\n",item->name.c_str());
-	//	DumpPacket(out_data, size);
 		memcpy(ptr, out_data, size);
 		safe_delete_array(out_data);
 		delete packet;
 	}
 	//DumpPacket(ptr2, ds->GetItemSize());
 }
-void PacketStruct::setItemByName(const char* name, Item* item, Player* player, int32 index, sint8 offset, bool loot_item, bool make_empty_item_packet) {
-	setItem(findStruct(name, index), item, player, index, offset, loot_item, make_empty_item_packet);
+void PacketStruct::setItemByName(const char* name, Item* item, Player* player, int32 index, sint8 offset, bool loot_item, bool make_empty_item_packet, bool inspect) {
+	setItem(findStruct(name, index), item, player, index, offset, loot_item, make_empty_item_packet, inspect);
 }
-void PacketStruct::setItemArrayDataByName(const char* name, Item* item, Player* player, int32 index1, int32 index2, sint8 offset, bool loot_item, bool make_empty_item_packet) {
+void PacketStruct::setItemArrayDataByName(const char* name, Item* item, Player* player, int32 index1, int32 index2, sint8 offset, bool loot_item, bool make_empty_item_packet, bool inspect) {
 	char tmp[10] = { 0 };
 	sprintf(tmp, "_%i", index1);
 	string name2 = string(name).append(tmp);
-	setItem(findStruct(name2.c_str(), index1, index2), item, player, index2, offset, loot_item, make_empty_item_packet);
+	setItem(findStruct(name2.c_str(), index1, index2), item, player, index2, offset, loot_item, make_empty_item_packet, inspect);
 }
 
 void PacketStruct::ResetData() {

+ 3 - 3
EQ2/source/common/PacketStruct.h

@@ -441,9 +441,9 @@ public:
 		}
 	}
 #ifdef WORLD	
-	void setItem(DataStruct* ds, Item* item, Player* player, int32 index, sint8 offset = 0, bool loot_item = false, bool make_empty_item_packet = false);
-	void setItemByName(const char* name, Item* item, Player* player, int32 index = 0, sint8 offset = 0, bool loot_item = false, bool make_empty_item_packet = false);
-	void setItemArrayDataByName(const char* name, Item* item, Player* player, int32 index1 = 0, int32 index2 = 0, sint8 offset = 0, bool loot_item = false, bool make_empty_item_packet = false);
+	void setItem(DataStruct* ds, Item* item, Player* player, int32 index, sint8 offset = 0, bool loot_item = false, bool make_empty_item_packet = false, bool inspect = false);
+	void setItemByName(const char* name, Item* item, Player* player, int32 index = 0, sint8 offset = 0, bool loot_item = false, bool make_empty_item_packet = false, bool inspect = false);
+	void setItemArrayDataByName(const char* name, Item* item, Player* player, int32 index1 = 0, int32 index2 = 0, sint8 offset = 0, bool loot_item = false, bool make_empty_item_packet = false, bool inspect = false);
 #endif
 	void setEquipmentByName(const char* name, EQ2_EquipmentItem data, int32 index = 0) {
 		setEquipmentByName(findStruct(name, index), data, index);

+ 42 - 0
server/CommonStructs.xml

@@ -43,6 +43,48 @@ to zero and treated like placeholders." />
 <Data ElementName="body_size" Type="float" Size="1" />
 <Data ElementName="body_age" Type="float" Size="1" />
 </Struct>
+<Struct Name="CreateCharacter" ClientVersion="373" OpcodeName="OP_CreateCharacterRequestMsg">
+<Data ElementName="unknown0" Type="int32" />
+<Data ElementName="account_id" Type="int32"  />
+<Data ElementName="server_id" Type="int32" />
+<Data ElementName="name" Type="EQ2_16Bit_String" />
+<Data ElementName="race" Type="int8" />
+<Data ElementName="gender" Type="int8" />
+<Data ElementName="deity" Type="int8" />
+<Data ElementName="class" Type="int8" />
+<Data ElementName="level" Type="int8" />
+<Data ElementName="starting_zone" Type="int8" />
+<Data ElementName="unknown1" Type="int8" Size="2" />
+<Data ElementName="race_file" Type="EQ2_16Bit_String" />
+<Data ElementName="skin_color" Type="float" Size="3" />
+<Data ElementName="eye_color" Type="float" Size="3" />
+<Data ElementName="hair_color1" Type="float" Size="3" />
+<Data ElementName="hair_color2" Type="float" Size="3" />
+<Data ElementName="hair_highlight" Type="float" Size="3" />
+<Data ElementName="unknown2" Type="int8" Size="26" />
+<Data ElementName="hair_file" Type="EQ2_16Bit_String" />
+<Data ElementName="hair_type_color" Type="float" Size="3" />
+<Data ElementName="hair_type_highlight_color" Type="float" Size="3" />
+<Data ElementName="face_file" Type="EQ2_16Bit_String" />
+<Data ElementName="hair_face_color" Type="float" Size="3" />
+<Data ElementName="hair_face_highlight_color" Type="float" Size="3" />
+<Data ElementName="chest_file" Type="EQ2_16Bit_String" />
+<Data ElementName="shirt_color" Type="float" Size="3" />
+<Data ElementName="unknown_chest_color" Type="float" Size="3" />
+<Data ElementName="legs_file" Type="EQ2_16Bit_String" />
+<Data ElementName="pants_color" Type="float" Size="3" />
+<Data ElementName="unknown_legs_color" Type="float" Size="3" />
+<Data ElementName="unknown9" Type="float" Size="3" />
+<Data ElementName="eyes2" Type="float" Size="3" />
+<Data ElementName="ears" Type="float" Size="3" />
+<Data ElementName="eye_brows" Type="float" Size="3" />
+<Data ElementName="cheeks" Type="float" Size="3" />
+<Data ElementName="lips" Type="float" Size="3" />
+<Data ElementName="chin" Type="float" Size="3" />
+<Data ElementName="nose" Type="float" Size="3" />
+<Data ElementName="body_size" Type="float" Size="1" />
+<Data ElementName="body_age" Type="float" Size="1" />
+</Struct>
 <Struct Name="CreateCharacter" ClientVersion="546" OpcodeName="OP_CreateCharacterRequestMsg">
 <Data ElementName="unknown0" Type="int8" />
 <Data ElementName="unknown1" Type="int32" />

+ 289 - 7
server/ItemStructs.xml

@@ -31,6 +31,102 @@
       <Data ElementName="slot" Type="int8" Size="1" />
     </Data>
   </Struct>
+
+  <Struct Name="Substruct_BaseItemDescriptionInspect" ClientVersion="373" >
+	<Data ElementName="unknownblah" Type="int8" Size="3" />
+    <Data ElementName="unique_id" Type="int32" Size="1" />
+    <Data ElementName="icon" Type="int16" Size="1" />
+    <Data ElementName="tier" Type="int8" Size="1" />
+    <Data ElementName="flag_names" Type="EQ2_8Bit_String" Size="1" />
+    <Data ElementName="unknown8_1" Type="int8" Size="17" />
+    <Data ElementName="stat_count" Type="int8" />
+    <Data ElementName="stat_array" Type="Array" ArraySizeVariable="stat_count">
+      <Data ElementName="stat_type" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="stat_subtype" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="value" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="stat_name" Type="EQ2_8Bit_String" Size="1" />
+    </Data>
+    <Data ElementName="stat_string_count" Type="int8" />
+    <Data ElementName="stat_string_array" Type="Array" ArraySizeVariable="stat_string_count">
+      <Data ElementName="stat_string" Type="EQ2_8Bit_String" Size="1" />
+      <Data ElementName="adornment_flag" Type="int8" Size="1" />
+      <Data ElementName="adornment_array" Type="Array" ArraySizeVariable="adornment_flag">
+        <Data ElementName="adornment_unknown" Type="int8" Size="1" />
+      </Data>
+      <Data ElementName="stat_description" Type="EQ2_16Bit_String" Size="1" />
+    </Data>
+    <Data ElementName="condition" Type="int8" Size="1" />   
+	<Data ElementName="weight" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+	<Data ElementName="unknown" Type="int8" Size="9" />
+  </Struct>
+  <Struct Name="Substruct_BaseItemDescriptionGeneric" ClientVersion="373" >
+	<Data ElementName="unknownblah" Type="int8" Size="3" />
+    <Data ElementName="unique_id" Type="int32" Size="1" />
+    <Data ElementName="icon" Type="int16" Size="1" />
+    <Data ElementName="tier" Type="int8" Size="1" />
+    <Data ElementName="flag_names" Type="EQ2_8Bit_String" Size="1" />
+    <Data ElementName="unknown8_1" Type="int8" Size="17" />
+    <Data ElementName="stat_count" Type="int8" />
+    <Data ElementName="stat_array" Type="Array" ArraySizeVariable="stat_count">
+      <Data ElementName="stat_type" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="stat_subtype" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="value" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="stat_name" Type="EQ2_8Bit_String" Size="1" />
+    </Data>
+    <Data ElementName="stat_string_count" Type="int8" />
+    <Data ElementName="stat_string_array" Type="Array" ArraySizeVariable="stat_string_count">
+      <Data ElementName="stat_string" Type="EQ2_8Bit_String" Size="1" />
+      <Data ElementName="adornment_flag" Type="int8" Size="1" />
+      <Data ElementName="adornment_array" Type="Array" ArraySizeVariable="adornment_flag">
+        <Data ElementName="adornment_unknown" Type="int8" Size="1" />
+      </Data>
+      <Data ElementName="stat_description" Type="EQ2_16Bit_String" Size="1" />
+    </Data>
+    <Data ElementName="condition" Type="int8" Size="1" />   
+	<Data ElementName="weight" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+	<Data ElementName="skill_req1" Type="int32" Size="1" />
+	<Data ElementName="skill_req2" Type="int32" Size="1" />
+    <Data ElementName="skill_min" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+	<Data ElementName="skill_recommended" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />	
+    <Data ElementName="slot_count" Type="int8" />
+    <Data ElementName="slot_array" Type="Array" ArraySizeVariable="slot_count">
+      <Data ElementName="slot" Type="int8" Size="1" />
+    </Data>
+  </Struct>
+<Struct Name="Substruct_BaseItemDescription" ClientVersion="373" >
+	<Data ElementName="unknownblah" Type="int8" Size="3" />
+    <Data ElementName="unique_id" Type="int32" Size="1" />
+    <Data ElementName="icon" Type="int16" Size="1" />
+    <Data ElementName="tier" Type="int8" Size="1" />
+    <Data ElementName="flag_names" Type="EQ2_8Bit_String" Size="1" />
+    <Data ElementName="unknown8_1" Type="int8" Size="17" />
+    <Data ElementName="stat_count" Type="int8" />
+    <Data ElementName="stat_array" Type="Array" ArraySizeVariable="stat_count">
+      <Data ElementName="stat_type" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="stat_subtype" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="value" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" />
+      <Data ElementName="stat_name" Type="EQ2_8Bit_String" Size="1" />
+    </Data>
+    <Data ElementName="stat_string_count" Type="int8" />
+    <Data ElementName="stat_string_array" Type="Array" ArraySizeVariable="stat_string_count">
+      <Data ElementName="stat_string" Type="EQ2_8Bit_String" Size="1" />
+      <Data ElementName="adornment_flag" Type="int8" Size="1" />
+      <Data ElementName="adornment_array" Type="Array" ArraySizeVariable="adornment_flag">
+        <Data ElementName="adornment_unknown" Type="int8" Size="1" />
+      </Data>
+      <Data ElementName="stat_description" Type="EQ2_16Bit_String" Size="1" />
+    </Data>
+    <Data ElementName="condition" Type="int8" Size="1" />   
+	<Data ElementName="weight" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+	<Data ElementName="skill_req1" Type="int32" Size="1" />
+	<Data ElementName="skill_req2" Type="int32" Size="1" />
+    <Data ElementName="skill_min" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+	<Data ElementName="skill_recommended" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />	
+    <Data ElementName="slot_count" Type="int8" />
+    <Data ElementName="slot_array" Type="Array" ArraySizeVariable="slot_count">
+      <Data ElementName="slot" Type="int8" Size="1" />
+    </Data>
+  </Struct>
 <Struct Name="Substruct_BaseItemDescription" ClientVersion="546" >
     <Data ElementName="unknown" Type="int8" Size="1" />
     <Data ElementName="unique_id" Type="int32" Size="1" />
@@ -1036,6 +1132,22 @@
 <Data ElementName="item_id" Type="sint32" Size="1" />
 <Data ElementName="name" Type="char" Size="81" />
 </Struct>
+<Struct Name="Substruct_Item" ClientVersion="373" >
+<Data ElementName="unique_id" Type="int32" Size="1" /><!-- 4 -->
+<Data ElementName="bag_id" Type="int32" Size="1" /><!-- 8 -->
+<Data ElementName="inv_slot_id" Type="int32" Size="1" /><!-- 12 -->
+<Data ElementName="menu_type" Type="int32" Size="1" /><!-- 16 -->
+<Data ElementName="slot_id" Type="int8" Size="1" /><!-- 17 -->
+<Data ElementName="index" Type="int16" Size="1" /><!-- 19 -->
+<Data ElementName="icon" Type="int16" Size="1" /> <!-- 21 -->
+<Data ElementName="count" Type="int8" Size="1" /> <!-- 23 -->
+<Data ElementName="level" Type="int8" Size="1" /> <!-- 24 -->
+<Data ElementName="tier" Type="int8" Size="1" /> <!-- 25 -->
+<Data ElementName="num_slots" Type="int8" Size="1" /> <!-- 26 -->
+<Data ElementName="item_id" Type="sint32" Size="1" /> <!-- 27 -->
+<Data ElementName="name" Type="char" Size="64" />
+<Data ElementName="unknown6" Type="int8" Size="17" />
+</Struct>
 <Struct Name="Substruct_Item" ClientVersion="546" >
 <Data ElementName="unique_id" Type="int32" Size="1" /><!-- 4 -->
 <Data ElementName="bag_id" Type="int32" Size="1" /><!-- 8 -->
@@ -1311,6 +1423,18 @@
 <Data ElementName="name" Type="EQ2_8Bit_String" Size="1" />
 <Data ElementName="description" Type="EQ2_16Bit_String" Size="1" />
 </Struct>
+<Struct Name="Substruct_ItemFooterInspect" ClientVersion="373" >
+<Data ElementName="name" Type="EQ2_8Bit_String" Size="1" />
+</Struct>
+<Struct Name="Substruct_ItemFooter" ClientVersion="373" >
+<Data ElementName="num_effects" Type="int8" Size="1"  IfFlagNotSet="loot" /> 
+<Data ElementName="effect_array" Type="Array" ArraySizeVariable="num_effects" IfFlagNotSet="loot">
+	<Data ElementName="subbulletflag" Type="int8" Size = "1" />
+	<Data ElementName="effect" Type="EQ2_16Bit_String" Size="1" />
+</Data>
+<Data ElementName="name" Type="EQ2_8Bit_String" Size="1" />
+<Data ElementName="description" Type="EQ2_16Bit_String" Size="1" />
+</Struct>
 <Struct Name="Substruct_ItemFooter" ClientVersion="546" >
 <Data ElementName="num_effects" Type="int8" Size="1"  IfFlagNotSet="loot" /> 
 <Data ElementName="effect_array" Type="Array" ArraySizeVariable="num_effects" IfFlagNotSet="loot">
@@ -3804,6 +3928,21 @@
 <Data ElementName="info" Substruct="Substruct_BaseItemDescription" Size="1" />
 <Data ElementName="item_type" Type="int8" Size="1" />
 </Struct>
+<Struct Name="Substruct_ItemDescriptionInspect" ClientVersion="373" >
+<Data ElementName="info_header" Substruct="WS_ExamineInfoHeader" Size="1" />
+<Data ElementName="info" Substruct="Substruct_BaseItemDescriptionInspect" Size="1" />
+<Data ElementName="item_type" Type="int8" Size="1" />
+</Struct>
+<Struct Name="Substruct_ItemDescriptionGeneric" ClientVersion="373" >
+<Data ElementName="info_header" Substruct="WS_ExamineInfoHeader" Size="1" />
+<Data ElementName="info" Substruct="Substruct_BaseItemDescriptionGeneric" Size="1" />
+<Data ElementName="item_type" Type="int8" Size="1" />
+</Struct>
+<Struct Name="Substruct_ItemDescription" ClientVersion="373" >
+<Data ElementName="info_header" Substruct="WS_ExamineInfoHeader" Size="1" />
+<Data ElementName="info" Substruct="Substruct_BaseItemDescription" Size="1" />
+<Data ElementName="item_type" Type="int8" Size="1" />
+</Struct>
 <Struct Name="Substruct_ItemDescription" ClientVersion="546" >
 <Data ElementName="info_header" Substruct="WS_ExamineInfoHeader" Size="1" />
 <Data ElementName="info" Substruct="Substruct_BaseItemDescription" Size="1" />
@@ -4085,6 +4224,14 @@
 </Data>
 <Data ElementName="equip_flag" Type="int8" Size="1" />
 </Struct>
+<Struct Name="WS_UpdateInventory" ClientVersion="373" OpcodeName="OP_UpdateInventoryMsg" >
+<Data ElementName="item_count" Type="int16" />
+<Data ElementName="packed_size" Type="int32" />
+<Data ElementName="item_array" Type="Array" ArraySizeVariable="item_count">
+  <Data ElementName="items" Substruct="Substruct_Item" Size="1" />
+</Data>
+<Data ElementName="equip_flag" Type="int8" Size="1" />
+</Struct>
 <Struct Name="WS_UpdateInventory" ClientVersion="546" OpcodeName="OP_UpdateInventoryMsg" >
 <Data ElementName="item_count" Type="int16" />
 <Data ElementName="packed_size" Type="int32" />
@@ -4193,6 +4340,14 @@
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemGeneric" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescriptionGeneric" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemInspect" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescriptionInspect" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooterInspect" Size="1" />
+</Struct>
 <Struct Name="WS_ItemGeneric" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
@@ -4201,6 +4356,34 @@
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemRange" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="damage_low1" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_high1" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_low2" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_high2" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_low3" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_high3" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="delay" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="range_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="range_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="rating" Type="float" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemRange" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="damage_low1" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_high1" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_low2" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_high2" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_low3" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="damage_high3" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="delay" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="range_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="range_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="rating" Type="float" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemRange" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="damage_low1" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
@@ -4238,6 +4421,14 @@
 <Data ElementName="damage_type" Type="int32" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemThrown" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="range" Type="sint32" Size="1" />
+<Data ElementName="damage_modifier" Type="sint32" Size="1" />
+<Data ElementName="hit_bonus" Type="float" Size="1" />
+<Data ElementName="damage_type" Type="int32" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemThrown" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="range" Type="sint32" Size="1" />
@@ -4246,7 +4437,7 @@
 <Data ElementName="damage_type" Type="int32" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
-<Struct Name="WS_ItemWeapon" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Struct Name="WS_ItemWeapon" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="wield_type" Type="int8" Size="1" />
 <Data ElementName="damage_low1" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
@@ -4260,16 +4451,32 @@
 <Data ElementName="rating" Type="float" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
-<Struct Name="WS_ItemArmor" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Struct Name="WS_ItemWeapon" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
-<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
-<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="wield_type" Type="int8" Size="1" />
+<Data ElementName="damage_low1" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_high1" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_low2" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_high2" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_low3" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_high3" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="delay" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_type" Type="int8" Size="1" />
+<Data ElementName="rating" Type="float" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
-<Struct Name="WS_ItemShield" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Struct Name="WS_ItemWeapon" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
-<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
-<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="wield_type" Type="int8" Size="1" />
+<Data ElementName="damage_low1" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_high1" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_low2" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_high2" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_low3" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_high3" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="delay" Type="int16" OversizedValue="127" OversizedByte="127" Size="1" />
+<Data ElementName="damage_type" Type="int8" Size="1" />
+<Data ElementName="rating" Type="float" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
 <Struct Name="WS_ItemWeapon" ClientVersion="562" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
@@ -4286,12 +4493,48 @@
 <Data ElementName="rating" Type="float" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemArmor" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemArmor" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemArmor" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemArmor" ClientVersion="562" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
 <Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemShield" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemShield" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemShield" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="mitigation_high" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemShield" ClientVersion="562" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="mitigation_low" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
@@ -4413,6 +4656,12 @@
 <Data ElementName="recipe_filler" Substruct="WS_ItemRecipeBookDetails" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemBag" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="details" Substruct="WS_ItemBagDetails" Size="1" />
+<Data ElementName="filler" Type="int8" Size="1"/>
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemSkill" ClientVersion="1" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="spell_info" Substruct="WS_SpellInfo" Size="1" />
@@ -4452,6 +4701,13 @@
 <Data ElementName="food_type" Type="int8" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemFood" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="food_type" Type="int8" Size="1" />
+<Data ElementName="level" Type="int8" Size="1" />
+<Data ElementName="duration" Type="float" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemFood" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="food_type" Type="int8" Size="1" />
@@ -4479,6 +4735,32 @@
 <Data ElementName="display_until_cancelled" Type="int8" Size="1" />
 <Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
 </Struct>
+<Struct Name="WS_ItemBauble" ClientVersion="373" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="cast" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="recovery" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="duration" Type="int32" Size="1" />
+<Data ElementName="recast" Type="float" Size="1" />
+<Data ElementName="display_cast_time" Type="int8" Size="1" />
+<Data ElementName="display_bauble_type" Type="int8" Size="1" />
+<Data ElementName="effect_radius" Type="float" Size="1" />
+<Data ElementName="max_aoe_targets" Type="int32" Size="1" />
+<Data ElementName="display_until_cancelled" Type="int8" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
+<Struct Name="WS_ItemBauble" ClientVersion="546" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
+<Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
+<Data ElementName="cast" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="recovery" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />
+<Data ElementName="duration" Type="int32" Size="1" />
+<Data ElementName="recast" Type="float" Size="1" />
+<Data ElementName="display_cast_time" Type="int8" Size="1" />
+<Data ElementName="display_bauble_type" Type="int8" Size="1" />
+<Data ElementName="effect_radius" Type="float" Size="1" />
+<Data ElementName="max_aoe_targets" Type="int32" Size="1" />
+<Data ElementName="display_until_cancelled" Type="int8" Size="1" />
+<Data ElementName="footer" Substruct="Substruct_ItemFooter" Size="1" />
+</Struct>
 <Struct Name="WS_ItemBauble" ClientVersion="562" OpcodeName="OP_ClientCmdMsg" OpcodeType="OP_EqExamineInfoCmd">
 <Data ElementName="header" Substruct="Substruct_ItemDescription" Size="1" />
 <Data ElementName="cast" Type="int16" Size="1" OversizedValue="127" OversizedByte="127" />

+ 66 - 1
server/LoginStructs.xml

@@ -78,6 +78,21 @@ to zero and treated like placeholders." />
   <Data ElementName="load" Type="int8" Size="1" />
 </Data>
 </Struct>
+<Struct Name="LS_WorldList" ClientVersion="373" OpcodeName="OP_WorldListMsg">
+<Data ElementName="num_worlds" Type="int8" />
+<Data ElementName="world_list" Type="Array" ArraySizeVariable="num_worlds">
+  <Data ElementName="id" Type="int32" Size="1" />
+  <Data ElementName="name" Type="EQ2_16Bit_String" />
+  <Data ElementName="tag" Type="int8" Size="1" />
+  <Data ElementName="locked" Type="int8" Size="1" />
+  <Data ElementName="hidden" Type="int8" Size="1" />
+  <Data ElementName="unknown" Type="int8" Size="1" />
+  <Data ElementName="num_players" Type="int16" Size="1" />
+  <Data ElementName="load" Type="int8" Size="1" />
+  <Data ElementName="number_online_flag" Type="int8" Size="1" />
+  <Data ElementName="allowed_races" Type="int32" Size="1" />
+</Data>
+</Struct>
 <Struct Name="LS_WorldList" ClientVersion="546" OpcodeName="OP_WorldListMsg">
 <Data ElementName="num_worlds" Type="int8" />
 <Data ElementName="world_list" Type="Array" ArraySizeVariable="num_worlds">
@@ -246,7 +261,57 @@ to zero and treated like placeholders." />
 <Data ElementName="hair_color2" Type="sint8" Size="3" />
 <Data ElementName="hair_color3" Type="sint8" Size="3" />
 <Data ElementName="flags" Type="int8" Size="1" />
-<Data ElementName="unknown11" Type="int8" Size="14" />
+</Struct>
+<Struct Name="CharSelectProfile" ClientVersion="373"> 
+<Data ElementName="charid" Type="int32" Size="1" />
+<Data ElementName="server_id" Type="int32" Size="1" />
+<Data ElementName="name" Type="EQ2_16BitString" Size="1" />
+<Data ElementName="race" Type="int8" Size="1" />
+<Data ElementName="class" Type="int8" Size="1" />
+<Data ElementName="level" Type="int32" Size="1" />
+<Data ElementName="zone" Type="EQ2_16BitString" Size="1" />
+<Data ElementName="unknown1" Type="int32" Size="1" />
+<Data ElementName="unknown2" Type="int32" Size="1" />
+<Data ElementName="created_date" Type="int32" Size="1" />
+<Data ElementName="last_played" Type="int32" Size="1" />
+<Data ElementName="unknown3" Type="int32" Size="1" />
+<Data ElementName="unknown4" Type="int32" Size="1" />
+<Data ElementName="zonename2" Type="EQ2_16BitString" Size="1" />
+<Data ElementName="zonedesc" Type="EQ2_16BitString" Size="1" />
+<Data ElementName="version" Type="int8" Size="1" />
+<Data ElementName="race_type" Type="int16" Size="1" />
+<Data ElementName="skin_color" Type="sint8" Size="3" />
+<Data ElementName="eye_color" Type="sint8" Size="3" />
+<Data ElementName="equip" Type="EQ2_EquipmentItem" Size="21" />
+<Data ElementName="hair_type" Type="int16" Size="1" />
+<Data ElementName="hair_type_color" Type="sint8" Size="3" />
+<Data ElementName="hair_type_highlight_color" Type="sint8" Size="3" />
+<Data ElementName="hair_face_type" Type="int16" Size="1" />
+<Data ElementName="hair_face_color" Type="sint8" Size="3" />
+<Data ElementName="hair_face_highlight_color" Type="sint8" Size="3" />
+<Data ElementName="chest_type" Type="int16" Size="1" />
+<Data ElementName="shirt_color" Type="sint8" Size="3" />
+<Data ElementName="unknown_chest_color" Type="sint8" Size="3" />
+<Data ElementName="legs_type" Type="int16" Size="1" />
+<Data ElementName="pants_color" Type="sint8" Size="3" />
+<Data ElementName="unknown_legs_color" Type="sint8" Size="3" />
+<Data ElementName="unknown9" Type="sint8" Size="3" />
+<Data ElementName="eye_type" Type="sint8" Size="3" />
+<Data ElementName="ear_type" Type="sint8" Size="3" />
+<Data ElementName="eye_brow_type" Type="sint8" Size="3" />
+<Data ElementName="cheek_type" Type="sint8" Size="3" />
+<Data ElementName="lip_type" Type="sint8" Size="3" />
+<Data ElementName="chin_type" Type="sint8" Size="3" />
+<Data ElementName="nose_type" Type="sint8" Size="3" />
+<Data ElementName="body_size" Type="sint8" Size="1" />
+<Data ElementName="bump_scale" Type="sint8" Size="1" />
+<Data ElementName="mount" Type="int16" Size="1" />
+<Data ElementName="mount_color1" Type="sint8" Size="3" />
+<Data ElementName="mount_color2" Type="sint8" Size="3" />
+<Data ElementName="hair_color1" Type="sint8" Size="3" />
+<Data ElementName="hair_color2" Type="sint8" Size="3" />
+<Data ElementName="hair_color3" Type="sint8" Size="3" />
+<Data ElementName="flags" Type="int8" Size="1" />
 </Struct>
 <Struct Name="CharSelectProfile" ClientVersion="546">
 <Data ElementName="charid" Type="int32" Size="1" />

+ 176 - 7
server/SpawnStructs.xml

@@ -17,6 +17,25 @@
 </Data>
 <Data ElementName="time_stamp" Type="int32" Size="1" />
 </Struct>
+<Struct Name="WS_SpawnStruct_Header" ClientVersion="373">
+<Data ElementName="index" Type="int16" Size="1" OversizedValue="255" />
+<Data ElementName="spawn_id" Type="int32" Size="1" />
+<Data ElementName="spawn_anim" Type="int16" Size="1" />
+<Data ElementName="command_list" Type="int8" Size="1" />
+<Data ElementName="command_list_array" Type="Array" ArraySizeVariable="command_list">
+	<Data ElementName="command_list_name" Type="EQ2_16Bit_String" />
+	<Data ElementName="command_list_max_distance" Type="float" Size="1" />
+	<Data ElementName="command_list_error" Type="EQ2_16Bit_String" Size="1" />
+	<Data ElementName="command_list_command" Type="EQ2_16Bit_String" />
+</Data>
+<Data ElementName="default_command" Type="EQ2_16Bit_String" Size="1" />
+<Data ElementName="max_distance" Type="float" Size="1" />
+<Data ElementName="group_size" Type="int8" Size="1" />
+<Data ElementName="group_array" Type="Array" ArraySizeVariable="group_size">
+	<Data ElementName="group_spawn_id" Type="int32" />
+</Data>
+<Data ElementName="time_stamp" Type="int32" Size="1" />
+</Struct>
 <Struct Name="WS_SpawnStruct_Header" ClientVersion="546">
 <Data ElementName="index" Type="int16" Size="1" OversizedValue="255" />
 <Data ElementName="spawn_id" Type="int32" Size="1" />
@@ -105,12 +124,41 @@
 <Data ElementName="pos_x" Type="float" Size="1" /> <!-- 0x35 -->
 <Data ElementName="pos_y" Type="float" Size="1" /> <!-- 0x39 -->
 <Data ElementName="pos_z" Type="float" Size="1" /> <!-- 0x3d -->
-<Data ElementName="pos_pitch" Type="sint16" Size="1" /> <!-- 0x41 -->
+<Data ElementName="pos_pitch2" Type="sint16" Size="1" /> <!-- 0x41 -->
 <Data ElementName="pos_collision_radius" Type="sint16" Size="1" /> <!-- 0x43 -->
 <Data ElementName="pos_size" Type="sint16" Size="1" /> <!-- 0x45 -->
 <Data ElementName="face_actor_id" Type="int32" Size="1" /> <!-- 0x47 -->
 <Data ElementName="actor_stop_range" Type="sint16" Size="1" /> <!-- 0x4b -->
 </Struct>
+<Struct Name="Substruct_SpawnPositionStruct" ClientVersion="373" Comment="77 bytes">
+<Data ElementName="pos_grid_id" Type="int32" Size="1" />      <!-- 4 -->
+<Data ElementName="pos_loc_offset" Type="sint16" Size="3" />  <!-- 10 -->
+<Data ElementName="pos_x_velocity" Type="sint16" Size="1" /> <!-- 12 -->
+<Data ElementName="pos_y_velocity" Type="sint16" Size="1" /> <!-- 14 -->
+<Data ElementName="pos_z_velocity" Type="sint16" Size="1" />   <!-- 16 -->
+<Data ElementName="pos_heading1" Type="sint16" Size="1" />    <!-- 18 -->
+<Data ElementName="pos_heading2" Type="sint16" Size="1" />    <!-- 20 -->
+<Data ElementName="pos_speed" Type="sint16" Size="1" />        <!-- 22 -->
+<Data ElementName="pos_state" Type="int32" Size="1" />        <!-- 26 -->
+<Data ElementName="pos_movement_mode" Type="int8" Size="1" /> <!-- 27 -->
+<Data ElementName="pos_dest_loc_offset" Type="sint16" Size="3" /> <!-- 33 -->
+<Data ElementName="pos_dest_loc_offset2" Type="sint16" Size="3" /> <!-- 39 -->
+<Data ElementName="pos_heading_speed" Type="sint16" Size="1" /> <!-- 41 -->
+<Data ElementName="pos_move_type" Type="sint16" Size="1" /> <!-- 43 -->
+<Data ElementName="pos_swim_speed_modifier" Type="sint16" Size="1" /> <!-- 45 -->
+<Data ElementName="pos_side_speed" Type="sint16" Size="1" /> <!-- 47 -->
+<Data ElementName="pos_vert_speed" Type="sint16" Size="1" /> <!-- 49 -->
+<Data ElementName="pos_pitch1" Type="sint16" Size="1" /> <!-- 51 -->
+<Data ElementName="pos_requested_pitch_speed" Type="sint16" Size="1" /> <!-- 53 -->
+<Data ElementName="pos_x" Type="float" Size="1" /> <!-- 57 -->
+<Data ElementName="pos_y" Type="float" Size="1" /> <!-- 61 -->
+<Data ElementName="pos_z" Type="float" Size="1" /> <!-- 65 -->
+<Data ElementName="pos_pitch2" Type="sint16" Size="1" /> <!-- 67 -->
+<Data ElementName="pos_collision_radius" Type="sint16" Size="1" /> <!-- 69 -->
+<Data ElementName="pos_size" Type="sint16" Size="1" /> <!-- 71 -->
+<Data ElementName="face_actor_id" Type="int32" Size="1" /> <!-- 73 -->
+<Data ElementName="actor_stop_range" Type="sint16" Size="1" /> <!-- 75 -->
+</Struct>
 <Struct Name="Substruct_SpawnPositionStruct" ClientVersion="546" Comment="88 bytes">
 <Data ElementName="pos_grid_id" Type="int32" Size="1" />      
 <Data ElementName="pos_loc_offset" Type="sint16" Size="3" />  <!-- 0x4 -->
@@ -130,7 +178,7 @@
 <Data ElementName="pos_swim_speed_modifier" Type="sint16" Size="1" /> <!-- 0x2c -->
 <Data ElementName="pos_side_speed" Type="sint16" Size="1" /> <!-- 0x2e -->
 <Data ElementName="pos_vert_speed" Type="sint16" Size="1" /> <!-- 0x30 -->
-<Data ElementName="pos_requested_pitch" Type="sint16" Size="1" /> <!-- 0x32 -->
+<Data ElementName="pos_pitch1" Type="sint16" Size="1" /> <!-- 0x32 -->
 <Data ElementName="pos_requested_pitch_speed" Type="sint16" Size="1" /> <!-- 0x34 -->
 <Data ElementName="pos_unknown2" Type="int8" Size="6" /> <!-- 0x36 -->
 <Data ElementName="pos_x" Type="float" Size="1" /> <!-- 0x3c -->
@@ -163,7 +211,7 @@
 <Data ElementName="pos_swim_speed_modifier" Type="sint16" Size="1" /> <!-- 0x2c -->
 <Data ElementName="pos_side_speed" Type="sint16" Size="1" /> <!-- 0x2e -->
 <Data ElementName="pos_vert_speed" Type="sint16" Size="1" /> <!-- 0x30 -->
-<Data ElementName="pos_requested_pitch" Type="sint16" Size="1" /> <!-- 0x32 -->
+<Data ElementName="pos_pitch1" Type="sint16" Size="1" /> <!-- 0x32 -->
 <Data ElementName="pos_requested_pitch_speed" Type="sint16" Size="1" /> <!-- 0x34 -->
 <Data ElementName="pos_unknown2" Type="int8" Size="6" /> <!-- 0x36 -->
 <Data ElementName="pos_x" Type="float" Size="1" /> <!-- 0x3c -->
@@ -440,6 +488,96 @@
 <Data ElementName="race" Type="int8" Size="1" /> <!-- 794 -->
 <Data ElementName="gender" Type="int8" Size="1" /> <!-- 795 -->
 </Struct>
+<Struct Name="Substruct_SpawnInfoStruct" ClientVersion="373" Comment="796 bytes">
+<Data ElementName="hp_remaining" Type="int32" Size="1" /> <!-- 4 -->
+<Data ElementName="power_percent" Type="int32" Size="1" /> <!-- 12 -->
+<Data ElementName="follow_target" Type="int32" Size="1" /> <!-- 8 -->
+<Data ElementName="target_id" Type="int32" Size="1" /> <!-- 8 -->
+<Data ElementName="corpse" Type="int8" Size="1" /> <!-- 24 -->
+<Data ElementName="class" Type="int8" Size="1" /> <!-- 25 -->
+<Data ElementName="unknown_maybe_effective_level" Type="int8" Size="1" /> <!-- 26 -->
+<Data ElementName="level" Type="int8" Size="1" /> <!-- 26 -->
+<Data ElementName="difficulty" Type="int8" Size="1" /> <!-- 27 -->
+<Data ElementName="unknown6" Type="int8" Size="1" /> <!-- 28 -->
+<Data ElementName="heroic_flag" Type="int8" Size="1" /> <!-- 29 -->
+<Data ElementName="npc" Type="int8" Size="1" /> <!-- 301 -->
+<Data ElementName="unknown7" Type="int8" Size="1" /> <!-- 302 -->
+<Data ElementName="unknown8" Type="int8" Size="1" /> <!-- 303 -->
+<Data ElementName="merchant" Type="int8" Size="1" /> <!-- 304 -->
+<Data ElementName="unknown9" Type="int8" Size="1" /> <!-- 305 -->
+<Data ElementName="unknown10" Type="int8" Size="1" /> <!-- 306 -->
+<Data ElementName="no_arrow_color_or_highlight" Type="int8" Size="1" /> <!-- 36 -->
+<Data ElementName="no_arrow_color_or_healthbar" Type="int8" Size="1" /> <!-- 37 -->
+<Data ElementName="hand_icon" Type="int8" Size="1" /> <!-- 309 -->
+<Data ElementName="hide_health" Type="int8" Size="1" /> <!-- 310 -->
+<Data ElementName="is_transport" Type="int8" Size="1" /> <!-- 311 -->
+<Data ElementName="house_icon" Type="int8" Size="1" /> <!-- 312 -->
+<Data ElementName="loot_icon" Type="int8" Size="1" /> <!-- 313 -->
+<Data ElementName="auto_attack" Type="int8" Size="1" /> <!-- 314 -->
+<Data ElementName="afk" Type="int8" Size="1" /> <!-- 315 -->
+<Data ElementName="roleplaying" Type="int8" Size="1" /> <!-- 316 -->
+<Data ElementName="anonymous" Type="int8" Size="1" /> <!-- 317 -->
+<Data ElementName="linkdead" Type="int8" Size="1" /> <!-- 318 -->
+<Data ElementName="camping" Type="int8" Size="1" /> <!-- 319 -->
+<Data ElementName="unknown12" Type="int8" Size="1" /> <!-- 320 --> <!-- looking for group? -->
+<Data ElementName="unknown13" Type="int8" Size="1" /> <!-- 321 --> <!-- looking for work? -->
+<Data ElementName="solid_object" Type="int8" Size="1" /> <!-- 322 -->
+<Data ElementName="unknown14" Type="int8" Size="1" /> <!-- 323 -->
+<Data ElementName="unknown15" Type="int8" Size="1" /> <!-- 324 -->
+<Data ElementName="unknown16" Type="int8" Size="1" /> <!-- 325 -->
+<Data ElementName="unknown17" Type="int8" Size="1" /> <!-- 326 -->
+<Data ElementName="activity_status" Type="int32" Size="1" /> <!-- 54, not really used in this version -->
+<Data ElementName="model_type" Type="int16" Size="1" /> <!-- 58 -->
+<Data ElementName="skin_color" Type="EQ2_Color" Size="1" /> <!-- 60 -->
+<Data ElementName="eye_color" Type="EQ2_Color" Size="1" /> <!-- 63 -->
+<Data ElementName="equipment_types" Type="int16" Size="21" /> <!-- 66 -->
+<Data ElementName="hair_type_id" Type="int16" Size="1" />
+<Data ElementName="facial_hair_type_id" Type="int16" Size="1" />
+<Data ElementName="chest_type_id" Type="int16" Size="1" />
+<Data ElementName="legs_type_id" Type="int16" Size="1" />
+<Data ElementName="equipment_colors" Type="EQ2_Color" Size="21" /> <!-- 116 -->
+<Data ElementName="hair_type_color" Type="EQ2_Color" />
+<Data ElementName="hair_face_color" Type="EQ2_Color" />
+<Data ElementName="chest_type_color" Type="EQ2_Color" Size="1" />
+<Data ElementName="legs_type_color" Type="EQ2_Color" Size="1" />
+<Data ElementName="equipment_highlights" Type="EQ2_Color" Size="21" /> <!-- 191 -->
+<Data ElementName="hair_type_highlight_color" Type="EQ2_Color" />
+<Data ElementName="hair_face_highlight_color" Type="EQ2_Color" />
+<Data ElementName="chest_type_highlight_color" Type="EQ2_Color" Size="1" />
+<Data ElementName="legs_type_highlight_color" Type="EQ2_Color" Size="1" />
+<Data ElementName="skull_type" Type="sint8" Size="3" /> <!-- 266 -->
+<Data ElementName="eye_type" Type="sint8" Size="3" /> <!-- 269 -->
+<Data ElementName="ear_type" Type="sint8" Size="3" /> <!-- 272 -->
+<Data ElementName="eye_brow_type" Type="sint8" Size="3" /> <!-- 275 -->
+<Data ElementName="cheek_type" Type="sint8" Size="3" /> <!-- 278 -->
+<Data ElementName="lip_type" Type="sint8" Size="3" /> <!-- 281 -->
+<Data ElementName="chin_type" Type="sint8" Size="3" /> <!-- 284 -->
+<Data ElementName="nose_type" Type="sint8" Size="3" /> <!-- 287 -->
+<Data ElementName="body_size" Type="sint8" Size="1" /> <!-- 290 -->
+<Data ElementName="bump_size" Type="sint8" Size="1" /> <!-- 291 -->
+<Data ElementName="mount_type" Type="int16" Size="1" /> <!-- 292 -->
+<Data ElementName="mount_color" Type="EQ2_Color" /> <!-- 294 -->
+<Data ElementName="mount_saddle_color" Type="EQ2_Color" /> <!-- 297 -->
+<Data ElementName="hair_color1" Type="EQ2_Color" /> <!-- 300 -->
+<Data ElementName="hair_color2" Type="EQ2_Color" /> <!-- 303 -->
+<Data ElementName="hair_highlight" Type="EQ2_Color" /> <!-- 306 -->
+<Data ElementName="flags" Type="int8" Size="1" /><!-- 309 1 == invisible, 2 == show_hood, 8 == crouch -->
+<Data ElementName="temporary_scale" Type="float" Size="1" /> <!-- 310 -->
+<Data ElementName="name" Type="char" Size="64" /> <!-- 314 -->
+<Data ElementName="last_name" Type="char" Size="64" /> <!-- 378 -->
+<Data ElementName="name_suffix" Type="char" Size="64" /> <!-- 442 -->
+<Data ElementName="name_prefix" Type="char" Size="64" /> <!-- 506 -->
+<Data ElementName="unknown31" Type="char" Size="64" /> <!-- 570 -->
+<Data ElementName="second_suffix" Type="char" Size="64" /> <!-- 634 -->
+<Data ElementName="persistent_spell_visuals" Type="int16" Size="8" /> <!-- 698 -->
+<Data ElementName="persistent_spell_levels" Type="int8" Size="8" /> <!-- 714 -->
+<Data ElementName="action_state" Type="int16" Size="1" /> <!-- 786 -->
+<Data ElementName="visual_statex" Type="int16" Size="1" /> <!-- 788 -->
+<Data ElementName="mood_state" Type="int16" Size="1" /> <!-- 790 -->
+<Data ElementName="emote_state" Type="int16" Size="1" /> <!-- 792 -->
+<Data ElementName="race" Type="int8" Size="1" /> <!-- 794 -->
+<Data ElementName="gender" Type="int8" Size="1" /> <!-- 795 -->
+</Struct>
 <Struct Name="Substruct_SpawnInfoStruct" ClientVersion="546" >
 <Data ElementName="hp_remaining" Type="int32" Size="1" /> <!-- 0 -->
 <Data ElementName="power_percent" Type="int32" Size="1" /> <!-- 4 -->
@@ -2470,6 +2608,17 @@
 <Data ElementName="sign_distance" Type="float" Size="1" />
 <Data ElementName="show" Type="int16" Size="1" />
 </Struct>
+<Struct Name="WS_SignWidgetSpawnStruct_Footer" ClientVersion="373">
+<Data ElementName="widget_id" Type="int32" Size="1" />
+<Data ElementName="widget_x" Type="float" Size="1" />
+<Data ElementName="widget_y" Type="float" Size="1" />
+<Data ElementName="widget_z" Type="float" Size="1" />
+<Data ElementName="title" Type="EQ2_16Bit_String" Size="1" />
+<Data ElementName="description" Type="EQ2_16Bit_String" Size="1" />
+<Data ElementName="sign_distance" Type="float" Size="1" />
+<Data ElementName="show" Type="int16" Size="1" />
+<Data ElementName="language" Type="int8" Size="1" />
+</Struct>
 <Struct Name="WS_SignWidgetSpawnStruct_Footer" ClientVersion="546">
 <Data ElementName="widget_id" Type="int32" Size="1" />
 <Data ElementName="widget_x" Type="float" Size="1" />
@@ -2538,18 +2687,33 @@
 </Data>
 </Struct>
 <Struct Name="Substruct_SpawnVisualizationInfoStruct" ClientVersion="1" Comment="12 bytes">
-<Data ElementName="arrow_color" Type="int8" Size="1" /> <!-- 1-6 arrow colors, 7-13 merchant, 14-20 bank, 21-28 hail, 29-34 attack, 35-43 window icons, 46 saw, 47 house -->
+<Data ElementName="arrow_colorx" Type="int8" Size="1" /> <!-- classic clients hate this one trick, crashes due to cursor index hovering over mob if setting arrow color on mobs -->
+<Data ElementName="locked_no_loot" Type="int8" Size="1" />
+<Data ElementName="npc_con" Type="sint8" Size="1" />
+<Data ElementName="quest_flag" Type="int8" Size="1" />
+<Data ElementName="vis_flags" Type="int8" Size="1" />
+<Data ElementName="targetable" Type="int8" Size="1" />
+<Data ElementName="red_glow" Type="int8" Size="1" />
+<Data ElementName="show_name" Type="int8" Size="1" />
+<Data ElementName="attackable" Type="int8" Size="1" />
+<Data ElementName="attackable_icon" Type="int8" Size="1" />
+<Data ElementName="unknown3" Type="int8" Size="1" />
+<Data ElementName="unknown4" Type="int8" Size="1" />
+</Struct>
+<Struct Name="Substruct_SpawnVisualizationInfoStruct" ClientVersion="373" Comment="78 bytes">
+<Data ElementName="arrow_colorx" Type="int8" Size="1" /> <!-- classic clients hate this one trick, crashes due to cursor index hovering over mob if setting arrow color on mobs -->
 <Data ElementName="locked_no_loot" Type="int8" Size="1" />
 <Data ElementName="npc_con" Type="sint8" Size="1" />
-<Data ElementName="group_member" Type="int8" Size="1" />
+<Data ElementName="quest_flag" Type="int8" Size="1" />
 <Data ElementName="vis_flags" Type="int8" Size="1" />
 <Data ElementName="targetable" Type="int8" Size="1" />
 <Data ElementName="red_glow" Type="int8" Size="1" />
 <Data ElementName="show_name" Type="int8" Size="1" />
 <Data ElementName="attackable" Type="int8" Size="1" />
 <Data ElementName="attackable_icon" Type="int8" Size="1" />
-<Data ElementName="unknown11" Type="int8" Size="1" />
-<Data ElementName="unknown12" Type="int8" Size="1" />
+<Data ElementName="unknown3" Type="int8" Size="1" />
+<Data ElementName="unknown4" Type="int8" Size="1" />
+<Data ElementName="guild" Type="char" Size="64" />
 </Struct>
 <Struct Name="Substruct_SpawnVisualizationInfoStruct" ClientVersion="546" Comment="78 bytes">
 <Data ElementName="arrow_color" Type="int8" Size="1" />
@@ -2667,6 +2831,11 @@
 <Data ElementName="vis" Substruct="Substruct_SpawnVisualizationInfoStruct" Size="1" />
 <Data ElementName="info" Substruct="Substruct_SpawnInfoStruct" Size="1" />
 </Struct>
+<Struct Name="WS_SpawnStruct" ClientVersion="373">
+<Data ElementName="position" Substruct="Substruct_SpawnPositionStruct" Size="1" />
+<Data ElementName="vis" Substruct="Substruct_SpawnVisualizationInfoStruct" Size="1" />
+<Data ElementName="info" Substruct="Substruct_SpawnInfoStruct" Size="1" />
+</Struct>
 <Struct Name="WS_SpawnStruct" ClientVersion="546">
 <Data ElementName="position" Substruct="Substruct_SpawnPositionStruct" Size="1" />
 <Data ElementName="vis" Substruct="Substruct_SpawnVisualizationInfoStruct" Size="1" />

File diff suppressed because it is too large
+ 688 - 49
server/WorldStructs.xml


Some files were not shown because too many files changed in this diff