Browse Source

- Fix #537 - DoF client health, power, concentration display on items correctly, AoM and DoF client no longer have issues with hide hood/helm in options impacting self and other options
- Fix #434 - AttackAllowed now checks for attackable against NPCs. Added more AttackAllowed checks around AE/Enemy target to avoid non-attackable npcs
- Fix #531 - DoF house support, AoM client also fixed inside house for door widget
- Fix #543 - Addressed AE/other spells including unattackable spawns
- Support for LUA Function InFront(Spawn, Target)
- Fix AE max targets exceeding cap

Emagi 7 months ago
parent
commit
ace2e20281

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

@@ -96,6 +96,10 @@ bool Entity::AttackAllowed(Entity* target, float distance, bool range_attack) {
 		LogWrite(COMBAT__DEBUG, 3, "AttackAllowed", "Failed to attack: no target, mezzed, stunned or dazed");
 		return false;
 	}
+	
+	if((!target->IsPlayer() && !target->GetAttackable()) || (!IsPlayer() && !GetAttackable())) {
+		return false;
+	}
 
 	if (IsPlayer())
 		client = GetZone()->GetClientBySpawn(this);

+ 48 - 20
EQ2/source/WorldServer/Commands/Commands.cpp

@@ -3741,10 +3741,19 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 		case COMMAND_HOUSE_DEPOSIT:
 		{
 			PrintSep(sep, "COMMAND_HOUSE_DEPOSIT");
-			// arg0 = ??? (set to 3)
+			// arg0 = spawn_id for DoF, could also be house_id for newer clients
 			// arg1 = coin (in copper)
 			// arg2 = status? (not implemented yet)
-			PlayerHouse* ph = world.GetPlayerHouseByInstanceID(client->GetCurrentZone()->GetInstanceID());
+			PlayerHouse* ph = nullptr;
+			int32 spawn_id = 0;
+			if(sep && sep->arg[0]) {
+				spawn_id = atoul(sep->arg[0]);
+				ph = world.GetPlayerHouse(client, spawn_id, client->GetVersion() > 546 ? spawn_id : 0, nullptr);
+			}
+			
+			if(!ph) {
+				ph = world.GetPlayerHouseByInstanceID(client->GetCurrentZone()->GetInstanceID());
+			}
 			if (ph && sep && sep->IsNumber(1))
 			{
 				int64 outValCoin = strtoull(sep->arg[1], NULL, 0);
@@ -3779,7 +3788,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 						database.LoadDeposits(ph);
 						client->PlaySound("coin_cha_ching");
 						HouseZone* hz = world.GetHouseZone(ph->house_id);
-						ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetPlayer()->GetID());
+						ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetVersion() <= 546 ? spawn_id : client->GetPlayer()->GetID());
 					}
 					else
 					{
@@ -3796,16 +3805,21 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 		}
 		case COMMAND_HOUSE:
 		{
+			int32 spawn_id = 0;
 			if (sep && sep->IsNumber(0))
 			{
-				int32 unique_id = atoi(sep->arg[0]);
-				PlayerHouse* ph = world.GetPlayerHouseByUniqueID(unique_id);
+				PlayerHouse* ph = nullptr;
+				if(!ph && sep && sep->arg[0]) {
+					spawn_id = atoul(sep->arg[0]);
+					ph = world.GetPlayerHouse(client, spawn_id, spawn_id, nullptr);
+				}
+				
 				HouseZone* hz = 0;
 					
 				if (ph)
 					hz = world.GetHouseZone(ph->house_id);
 				// there is a arg[1] that is true/false, but not sure what it is for investigate more later
-				ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetPlayer()->GetID());
+				ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetVersion() <= 546 ? spawn_id : client->GetPlayer()->GetID());
 			}
 			else if (client->GetCurrentZone()->GetInstanceType() != 0)
 			{
@@ -3816,7 +3830,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie
 				if ( ph )
 					hz = world.GetHouseZone(ph->house_id);
 
-				ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetPlayer()->GetID());
+				ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetVersion() <= 546 ? spawn_id : client->GetPlayer()->GetID());
 				client->GetCurrentZone()->SendHouseItems(client);
 			}
 			break;
@@ -8481,17 +8495,22 @@ void Commands::Command_ShowCloak(Client* client, Seperator* sep)
 void Commands::Command_ShowHelm(Client* client, Seperator* sep)
 {
 	Player* player = client->GetPlayer();
-
+	
+	if(client->GetVersion() <= 546) {
+		return; // not allowed/supported
+	}
+	
 	if (sep && sep->arg[0])
 	{
+		PrintSep(sep, "Command_ShowHelm");
 		const char* value = sep->arg[0];
 		if (strncasecmp(value, "true", strlen(value)) == 0) 
 		{
-			player->reset_character_flag(CF_HIDE_HELM);
-			player->set_character_flag(CF_HIDE_HOOD);
+			player->toggle_character_flag(CF_HIDE_HELM);
+			player->toggle_character_flag(CF_HIDE_HOOD);
 		}
 		else if (strncasecmp(value, "false", strlen(value)) == 0) 
-			player->set_character_flag(CF_HIDE_HELM);
+			player->toggle_character_flag(CF_HIDE_HELM);
 		else
 		{
 			client->Message(CHANNEL_COLOR_YELLOW, "Not supposed to be here! Please /bug this: Error in %s (%u)", __FUNCTION__, __LINE__);
@@ -8513,15 +8532,19 @@ void Commands::Command_ShowHood(Client* client, Seperator* sep)
 
 	if (sep && sep->arg[0])
 	{
+		PrintSep(sep, "Command_ShowHood");
 		const char* value = sep->arg[0];
 
 		if (strncasecmp(value, "true", strlen(value)) == 0) 
 		{
-			player->reset_character_flag(CF_HIDE_HOOD);
-			player->set_character_flag(CF_HIDE_HELM);
+			player->toggle_character_flag(CF_HIDE_HOOD);
+			if(client->GetVersion() > 546) { // no hide helm support in DoF
+				player->toggle_character_flag(CF_HIDE_HELM);
+			}
+		}
+		else if (strncasecmp(value, "false", strlen(value)) == 0) {
+			player->toggle_character_flag(CF_HIDE_HOOD);
 		}
-		else if (strncasecmp(value, "false", strlen(value)) == 0) 
-			player->set_character_flag(CF_HIDE_HOOD);
 		else
 		{
 			client->Message(CHANNEL_COLOR_YELLOW, "Not supposed to be here! Please /bug this: Error in %s (%u)", __FUNCTION__, __LINE__);
@@ -8540,20 +8563,25 @@ void Commands::Command_ShowHood(Client* client, Seperator* sep)
 void Commands::Command_ShowHoodHelm(Client* client, Seperator* sep)
 {
 	Player* player = client->GetPlayer();
-
+	
+	if(client->GetVersion() <= 546) {
+		return; // not allowed/supported
+	}
+	
 	if (sep && sep->arg[0])
 	{
+		PrintSep(sep, "Command_ShowHoodHelm");
 		const char* value = sep->arg[0];
 		if (strncasecmp(value, "true", strlen(value)) == 0) 
 		{
-			player->reset_character_flag(CF_HIDE_HOOD);
-			player->reset_character_flag(CF_HIDE_HELM);
+			player->toggle_character_flag(CF_HIDE_HOOD);
+			player->toggle_character_flag(CF_HIDE_HELM);
 		}
 		else if (strncasecmp(value, "false", strlen(value)) == 0) 
 		{
 			// don't think we ever wind up in here...
-			player->set_character_flag(CF_HIDE_HOOD);
-			player->set_character_flag(CF_HIDE_HELM);
+			player->toggle_character_flag(CF_HIDE_HOOD);
+			player->toggle_character_flag(CF_HIDE_HELM);
 		}
 		else
 		{

+ 52 - 48
EQ2/source/WorldServer/Housing/HousingPackets.cpp

@@ -62,7 +62,7 @@ void ClientPacketFunctions::SendHousePurchase(Client* client, HouseZone* hz, int
 			enable_buy = false;
 
 		packet->setDataByName("enable_buy", enable_buy ? 1 : 0);
-
+		//packet->PrintPacket();
 		client->QueuePacket(packet->serialize());
 	}
 
@@ -70,6 +70,10 @@ void ClientPacketFunctions::SendHousePurchase(Client* client, HouseZone* hz, int
 }
 
 void ClientPacketFunctions::SendHousingList(Client* client) {
+	if(client->GetVersion() <= 546) {
+		return; // not supported
+	}
+	
 	std::vector<PlayerHouse*> houses = world.GetAllPlayerHouses(client->GetCharacterID());
 	// this packet must be sent first otherwise it blocks out the enter house option after paying upkeep
 	PacketStruct* packet = configReader.getStruct("WS_CharacterHousingList", client->GetVersion());
@@ -133,14 +137,16 @@ void ClientPacketFunctions::SendBaseHouseWindow(Client* client, HouseZone* hz, P
 		upkeep_due = ph->upkeep_due - Timer::GetUnixTimeStamp();
 		
 	// need this to enable the "enter house" button
-	PacketStruct* packet = configReader.getStruct("WS_UpdateHouseAccessDataMsg", client->GetVersion());
-	
-	if(!packet) {
-		return;
-	}
+	PacketStruct* packet = nullptr;
+
 
-	if(client->GetCurrentZone()->GetInstanceType() != PERSONAL_HOUSE_INSTANCE
+	if(client->GetVersion() > 546 && client->GetCurrentZone()->GetInstanceType() != PERSONAL_HOUSE_INSTANCE
 			&& client->GetCurrentZone()->GetInstanceType() != GUILD_HOUSE_INSTANCE) {
+		packet = configReader.getStruct("WS_UpdateHouseAccessDataMsg", client->GetVersion());
+		
+		if(!packet) {
+			return; // we need this for these clients or enter house will not work properly
+		}
 		if (packet) {
 			packet->setDataByName("house_id", 0xFFFFFFFFFFFFFFFF);
 			packet->setDataByName("success",  (upkeep_due > 0) ? 0xFFFFFFFF : 0);
@@ -150,7 +156,7 @@ void ClientPacketFunctions::SendBaseHouseWindow(Client* client, HouseZone* hz, P
 		client->QueuePacket(packet->serialize());
 	}
 	safe_delete(packet);
-		
+	
 	packet = configReader.getStruct("WS_PlayerHouseBaseScreen", client->GetVersion());
 	if (packet) {
 		packet->setDataByName("house_id", ph->unique_id);
@@ -169,53 +175,51 @@ void ClientPacketFunctions::SendBaseHouseWindow(Client* client, HouseZone* hz, P
 		packet->setDataByName("privlage_level", 4);
 		// temp - set house type to personal house for now
 		packet->setDataByName("house_type", 0);
-
-		if (client->GetCurrentZone()->GetInstanceType() == PERSONAL_HOUSE_INSTANCE
+			
+		if(client->GetCurrentZone()->GetInstanceType() == PERSONAL_HOUSE_INSTANCE
 			|| client->GetCurrentZone()->GetInstanceType() == GUILD_HOUSE_INSTANCE) {
-				// Inside a house need to set a flag and set the history for the tabs
-
-			packet->setDataByName("inside_house", 1);
-			packet->setDataByName("num_access", 0);
-			packet->setDataByName("public_access_level", 1);
-			packet->setDataByName("num_history", 0);
+				packet->setDataByName("inside_house", 1);
+				packet->setDataByName("public_access_level", 1);
+		}
+		packet->setDataByName("num_access", 0);
+		packet->setDataByName("num_history", 0);
 
-			// allows deposits/history to be seen -- at this point seems plausible supposed to be 'inside_house'..?
-			packet->setDataByName("unknown3", (ph->deposits.size() || ph->history.size()) ? 1 : 0);
+		// allows deposits/history to be seen -- at this point seems plausible supposed to be 'inside_house'..?
+		packet->setDataByName("unknown3", (ph->deposits.size() || ph->history.size()) ? 1 : 0);
 
-			packet->setArrayLengthByName("num_deposit", ph->deposits.size());
-			list<Deposit>::iterator itr;
-			int d = 0;
-			for (itr = ph->deposits.begin(); itr != ph->deposits.end(); itr++)
-			{
-				packet->setArrayDataByName("deposit_name", itr->name.c_str(), d);
-				packet->setArrayDataByName("deposit_total_coin", itr->amount, d);
-				packet->setArrayDataByName("deposit_time_stamp", itr->timestamp, d);
-				packet->setArrayDataByName("deposit_last_coin", itr->last_amount, d);
-				packet->setArrayDataByName("deposit_total_status", itr->status, d);
-				packet->setArrayDataByName("deposit_last_status", itr->last_status, d);
-				d++;
-			}
+		packet->setArrayLengthByName("num_deposit", ph->deposits.size());
+		list<Deposit>::iterator itr;
+		int d = 0;
+		for (itr = ph->deposits.begin(); itr != ph->deposits.end(); itr++)
+		{
+			packet->setArrayDataByName("deposit_name", itr->name.c_str(), d);
+			packet->setArrayDataByName("deposit_total_coin", itr->amount, d);
+			packet->setArrayDataByName("deposit_time_stamp", itr->timestamp, d);
+			packet->setArrayDataByName("deposit_last_coin", itr->last_amount, d);
+			packet->setArrayDataByName("deposit_total_status", itr->status, d);
+			packet->setArrayDataByName("deposit_last_status", itr->last_status, d);
+			d++;
+		}
 
 
-			packet->setArrayLengthByName("num_history", ph->history.size());
-			list<HouseHistory>::iterator hitr;
-			d = 0;
-			for (hitr = ph->history.begin(); hitr != ph->history.end(); hitr++)
-			{
-				packet->setArrayDataByName("history_name", hitr->name.c_str(), d);
-				packet->setArrayDataByName("history_coins", hitr->amount, d);
-				packet->setArrayDataByName("history_status", hitr->status, d);
-				packet->setArrayDataByName("history_time_stamp", hitr->timestamp, d);
-				packet->setArrayDataByName("history_reason", hitr->reason.c_str(), d);
-				packet->setArrayDataByName("history_add_flag", hitr->pos_flag, d);
-				d++;
-			}
+		packet->setArrayLengthByName("num_history", ph->history.size());
+		list<HouseHistory>::iterator hitr;
+		d = 0;
+		for (hitr = ph->history.begin(); hitr != ph->history.end(); hitr++)
+		{
+			packet->setArrayDataByName("history_name", hitr->name.c_str(), d);
+			packet->setArrayDataByName("history_coins", hitr->amount, d);
+			packet->setArrayDataByName("history_status", hitr->status, d);
+			packet->setArrayDataByName("history_time_stamp", hitr->timestamp, d);
+			packet->setArrayDataByName("history_reason", hitr->reason.c_str(), d);
+			packet->setArrayDataByName("history_add_flag", hitr->pos_flag, d);
+			d++;
 		}
-
-		client->QueuePacket(packet->serialize());
-		safe_delete(packet);
+		
+		EQ2Packet* pack = packet->serialize();
+		//DumpPacket(pack);
+		client->QueuePacket(pack);
 	}
-
 	safe_delete(packet);
 }
 

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

@@ -1887,6 +1887,7 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 				}
 			}	
 			
+			bool valueSet = false;
 			if (tmp_subtype == 255 ){
 				
 				dropstat += 1;
@@ -1894,36 +1895,61 @@ void Item::serialize(PacketStruct* packet, bool show_name, Player* player, int16
 			}
 			else {
 				packet->setArrayDataByName("stat_type", stat_type, i-dropstat);
-				packet->setArrayDataByName("stat_subtype", tmp_subtype, i-dropstat);
+				
+				if(client->GetVersion() <= 546 && stat_type == 5) {
+					valueSet = true;
+					// DoF client has to be goofy about this junk, stat_subtype is the stat value, value is always "9" and we set the stat_name to the appropriate stat (but power=mana)
+					packet->setArrayDataByName("stat_subtype", (sint16)statValue , i - dropstat);
+					packet->setArrayDataByName("value", (sint16)9 , i - dropstat);
+					switch(tmp_subtype) {
+						case 0: {
+							packet->setArrayDataByName("stat_name", "health", i - dropstat);
+							break;
+						}
+						case 1: {
+							packet->setArrayDataByName("stat_name", "mana", i - dropstat);
+							break;
+						}
+						case 2: {
+							packet->setArrayDataByName("stat_name", "concentration", i - dropstat);
+							break;
+						}
+					}
+				}
+				else {
+					packet->setArrayDataByName("stat_subtype", tmp_subtype, i-dropstat);
+				}
 			}
 			if (stat->stat_name.length() > 0)
 				packet->setArrayDataByName("stat_name", stat->stat_name.c_str(), i-dropstat);
 			/* SF client */
 
-			if ((client->GetVersion() >= 63119) || client->GetVersion() == 61331) {
-				if (stat->stat_type == 6){
-					packet->setArrayDataByName("value", statValue , i - dropstat);//63119 or when diety started (this is actually the modified stat
-					packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value (this is the unmodified stat
-				}
-				else	{
-					packet->setArrayDataByName("value", (sint16)statValue , i - dropstat, 0U, true);
-					packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value
+			if(!valueSet) {
+				if ((client->GetVersion() >= 63119) || client->GetVersion() == 61331) {
+					if (stat->stat_type == 6){
+						packet->setArrayDataByName("value", statValue , i - dropstat);//63119 or when diety started (this is actually the modified stat
+						packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value (this is the unmodified stat
+					}
+					else	{
+						packet->setArrayDataByName("value", (sint16)statValue , i - dropstat, 0U, true);
+						packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value
+					}
 				}
-			}
-			 else if (client->GetVersion() >= 1028) {
-				if (stat->stat_type == 6){
-					packet->setArrayDataByName("value", statValue , i - dropstat);//63119 or when diety started (this is actually the infused modified stat
-					packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value (this is the unmodified stat
+				 else if (client->GetVersion() >= 1028) {
+					if (stat->stat_type == 6){
+						packet->setArrayDataByName("value", statValue , i - dropstat);//63119 or when diety started (this is actually the infused modified stat
+						packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value (this is the unmodified stat
+					}
+					else {
+						packet->setArrayDataByName("value", (sint16)statValue , i - dropstat, 0U, true);
+						packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value
+					}
+					
 				}
-				else {
-					packet->setArrayDataByName("value", (sint16)statValue , i - dropstat, 0U, true);
+				else{
+					packet->setArrayDataByName("value", (sint16)statValue , i - dropstat);
 					packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value
 				}
-				
-			}
-			else{
-				packet->setArrayDataByName("value", (sint16)statValue , i - dropstat);
-				packet->setArrayDataByName("value2", stat->value, i - dropstat);//63119 temp will be replace by modified value
 			}
 		}
 	}

+ 27 - 0
EQ2/source/WorldServer/LuaFunctions.cpp

@@ -8694,6 +8694,33 @@ int EQ2Emu_lua_IsFlanking(lua_State* state) {
 	return 1;
 }
 
+int EQ2Emu_lua_InFront(lua_State* state) {
+	if (!lua_interface)
+		return 0;
+
+	Spawn* spawn = lua_interface->GetSpawn(state);
+	Spawn* target = lua_interface->GetSpawn(state, 2);
+	lua_interface->ResetFunctionStack(state);
+
+	if (!spawn) {
+		lua_interface->LogError("%s: LUA InFrontSpawn command error: spawn is not valid", lua_interface->GetScriptName(state));
+		return 0;
+	}
+
+	if (!spawn->IsEntity()) {
+		lua_interface->LogError("%s: LUA InFrontSpawn command error: spawn is not an entity", lua_interface->GetScriptName(state));
+		return 0;
+	}
+
+	if (!target) {
+		lua_interface->LogError("%s: LUA InFrontSpawn command error: target is not valid", lua_interface->GetScriptName(state));
+		return 0;
+	}
+
+	lua_interface->SetBooleanValue(state, ((Entity*)spawn)->InFrontSpawn(target, spawn->GetX(), spawn->GetZ()));
+	return 1;
+}
+
 int EQ2Emu_lua_GetItemCount(lua_State* state) {
 	if (!lua_interface)
 		return 0;

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

@@ -415,6 +415,7 @@ int EQ2Emu_lua_LastSpellAttackHit(lua_State* state);
 
 int EQ2Emu_lua_IsBehind(lua_State* state);
 int EQ2Emu_lua_IsFlanking(lua_State* state);
+int EQ2Emu_lua_InFront(lua_State* state);
 int EQ2Emu_lua_AddSpellTimer(lua_State* state);
 int EQ2Emu_lua_SetItemCount(lua_State* state);
 int EQ2Emu_lua_GetItemCount(lua_State* state);

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

@@ -1287,6 +1287,7 @@ void LuaInterface::RegisterFunctions(lua_State* state) {
 	lua_register(state, "LastSpellAttackHit", EQ2Emu_lua_LastSpellAttackHit);
 	lua_register(state, "IsBehind", EQ2Emu_lua_IsBehind);
 	lua_register(state, "IsFlanking", EQ2Emu_lua_IsFlanking);
+	lua_register(state, "InFront", EQ2Emu_lua_InFront);
 	lua_register(state, "AddSpellTimer", EQ2Emu_lua_AddSpellTimer);
 	lua_register(state, "GetItemCount", EQ2Emu_lua_GetItemCount);
 	lua_register(state, "SetItemCount", EQ2Emu_lua_SetItemCount);

+ 4 - 2
EQ2/source/WorldServer/Spawn.cpp

@@ -2525,14 +2525,16 @@ void Spawn::InitializeInfoPacketData(Player* spawn, PacketStruct* packet) {
 		//Hide hood check
 		bool vis_hide_hood = false;
 		if (IsPlayer() && ((Player*)this)->get_character_flag(CF_HIDE_HOOD)) {
-			vis_flag += INFO_VIS_FLAG_HIDE_HOOD;
+			if(version > 546) {
+				vis_flag += INFO_VIS_FLAG_HIDE_HOOD;
+			}
 			vis_hide_hood = true;
 		}
 		else if(IsPlayer()) {
 			classicFlags += INFO_CLASSIC_FLAG_SHOW_HOOD;
 		}
 		
-		if(!vis_hide_hood && appearance.hide_hood) {
+		if(!vis_hide_hood && appearance.hide_hood && version > 546) {
 			vis_flag += INFO_VIS_FLAG_HIDE_HOOD;
 		}
 			

+ 11 - 9
EQ2/source/WorldServer/SpellProcess.cpp

@@ -2164,13 +2164,13 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 
 								// if NPC group member is (still) an NPC (wtf?) and is alive, send the NPC group member back as a successful target of non-friendly spell group_member->Alive()
 								if (group_member->GetZone() == caster->GetZone() && 
-								group_member->IsNPC() && group_member->Alive() && !((Entity*)group_member)->IsAOEImmune() && (!((Entity*)group_member)->IsMezzed() || group_member == target))
+								group_member->IsNPC() && (data->friendly_spell || ((Entity*)caster)->AttackAllowed((Entity*)group_member)) && group_member->Alive() && !((Entity*)group_member)->IsAOEImmune() && (!((Entity*)group_member)->IsMezzed() || group_member == target))
 									AddLuaSpellTarget(luaspell, group_member->GetID());
 
 								// note: this should generate some hate towards the caster
 							}
 						} // end is spawngroup
-						else
+						else if(data->friendly_spell || ((Entity*)caster)->AttackAllowed((Entity*)target))
 							AddLuaSpellTarget(luaspell, target->GetID()); // return single target NPC for non-friendly spell
 					}
 					else if(data->friendly_spell)
@@ -2184,7 +2184,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 					}
 					else if(target && target->IsPlayer())
 					{
-						if(!GetPlayerGroupTargets((Player*)target, caster, luaspell, true, false))
+						if(!GetPlayerGroupTargets((Player*)target, caster, luaspell, true, false) && ((Entity*)caster)->AttackAllowed((Entity*)target))
 							AddSelfAndPet(luaspell, target);
 					}
 				}
@@ -2299,7 +2299,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 						{
 							Spawn* group_member = *itr;
 
-							if (group_member->IsNPC() && group_member->Alive()){
+							if (group_member->IsNPC() && group_member->Alive() && ((Entity*)caster)->AttackAllowed(((Entity*)group_member))){
 								AddLuaSpellTarget(luaspell, group_member->GetID(), false);
 								if (((Entity*)group_member)->HasPet()){
 									Entity* pet = ((Entity*)group_member)->GetPet();
@@ -2397,7 +2397,7 @@ void SpellProcess::GetSpellTargets(LuaSpell* luaspell)
 
 							// if NPC group member is (still) an NPC (wtf?) and is alive, send the NPC group member back as a successful target of non-friendly spell group_member->Alive()
 							if (group_member->GetZone() == caster->GetZone() && 
-							group_member->IsNPC() && group_member->Alive() && !((Entity*)group_member)->IsAOEImmune() && (!((Entity*)group_member)->IsMezzed() || group_member == target))
+							group_member->IsNPC() && group_member->Alive() && ((Entity*)caster)->AttackAllowed((Entity*)group_member) && !((Entity*)group_member)->IsAOEImmune() && (!((Entity*)group_member)->IsMezzed() || group_member == target))
 								AddLuaSpellTarget(luaspell, group_member->GetID(), false);
 
 							// note: this should generate some hate towards the caster
@@ -2547,22 +2547,24 @@ void SpellProcess::GetSpellTargetsTrueAOE(LuaSpell* luaspell) {
 		luaspell->MSpellTargets.writelock(__FUNCTION__, __LINE__);
 		for (int8 i = 0; i < spawns.size(); i++) {
 			if (i == 0){
-				if (luaspell->initial_target && luaspell->caster->GetID() != luaspell->initial_target){
+				Spawn* spawn = luaspell->caster->GetZone()->GetSpawnByID(luaspell->initial_target);
+				if (spawn && luaspell->initial_target && luaspell->caster->GetID() != luaspell->initial_target && luaspell->caster->AttackAllowed((Entity*)spawn)){
 					//this is the "Direct" target and aoe can't be avoided
 					AddLuaSpellTarget(luaspell, luaspell->initial_target, false);
 					ignore_target = luaspell->initial_target;
 				}
-				if (luaspell->targets.size() >= luaspell->spell->GetSpellData()->max_aoe_targets)
-					break;
 			}
 			
+			if (luaspell->targets.size() >= luaspell->spell->GetSpellData()->max_aoe_targets)
+				break;
+			
 			int32 target_id = spawns.at(i);
 			Spawn* spawn = luaspell->caster->GetZone()->GetSpawnByID(target_id);
 			if(!spawn) {
 				LogWrite(SPELL__ERROR, 0, "Spell", "Error: Spell target is NULL!  SpellProcess::ProcessSpell for Spell '%s' target id %u", (luaspell->spell != nullptr) ? luaspell->spell->GetName() : "Unknown", target_id);
 			}
 			//If we have already added this spawn, check the next spawn in the list
-			if (spawn && spawn->GetID() == ignore_target){
+			if (spawn && spawn->GetID() == ignore_target || (spawn->IsEntity() && !luaspell->caster->AttackAllowed((Entity*)spawn))){
 				continue;
 			}
 			if (spawn){

+ 50 - 27
EQ2/source/WorldServer/Widget.cpp

@@ -18,6 +18,9 @@
     along with EQ2Emulator.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string.hpp>
+
 #include "Widget.h"
 #include "../common/ConfigReader.h"
 #include "Spells.h"
@@ -363,15 +366,18 @@ void Widget::HandleUse(Client* client, string command, int8 overrideWidgetType){
 		else if (meets_quest_reqs && appearance.show_command_icon != 1)
 			return;
 	}
-
+	std::string cmdlower(command);
+	boost::algorithm::to_lower(cmdlower);
+	
 	if (client && GetTransporterID() > 0)
 	{
 		client->SetTemporaryTransportID(0);
 		GetZone()->GetTransporters(&destinations, client, GetTransporterID());
 	}
-	if (destinations.size() && client)
+	bool skipHouseCommands = (cmdlower == "access" || cmdlower == "visit");
+	if (!skipHouseCommands && destinations.size() && client)
 		client->ProcessTeleport(this, &destinations, GetTransporterID());
-	else if (overrideWidgetType == WIDGET_TYPE_DOOR || overrideWidgetType == WIDGET_TYPE_LIFT){
+	else if (!skipHouseCommands && (overrideWidgetType == WIDGET_TYPE_DOOR || overrideWidgetType == WIDGET_TYPE_LIFT)){
 		Widget* widget = this;
 		if (!action_spawn && action_spawn_id > 0){
 			Spawn* spawn = GetZone()->GetSpawnByDatabaseID(action_spawn_id);
@@ -400,42 +406,59 @@ void Widget::HandleUse(Client* client, string command, int8 overrideWidgetType){
 		}
 		widget->ProcessUse(client ? client->GetPlayer() : nullptr);
 	}
-	else if (client && m_houseID > 0 && strncasecmp("access", command.c_str(), 6) == 0) {
-		// Used a door to enter a house
-		HouseZone* hz = world.GetHouseZone(m_houseID);
-		PlayerHouse* ph = 0;
-		if (hz)
-			ph = world.GetPlayerHouseByHouseID(client->GetPlayer()->GetCharacterID(), hz->id);
-		if (ph) {
-			// if we aren't in our own house we should get the full list of houses we can visit
-			if ( m_houseID && client->GetCurrentZone()->GetInstanceType() != Instance_Type::PERSONAL_HOUSE_INSTANCE )
-				ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(m_houseID));
-
-			ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, client->GetPlayer()->GetID());
-			client->GetCurrentZone()->SendHouseItems(client);
-		}
-		else {
-			if (hz)
-				ClientPacketFunctions::SendHousePurchase(client, hz, 0);
-		}
-	}
-	else if (client && strncasecmp("access", command.c_str(), 6) == 0 && GetZone()->GetInstanceType() > 0) {
+	else if (client && cmdlower == "access" && GetZone()->GetInstanceID() && 
+					(GetZone()->GetInstanceType() == PERSONAL_HOUSE_INSTANCE || GetZone()->GetInstanceType() == GUILD_HOUSE_INSTANCE)) {
 		// Used a door within a house
 		PlayerHouse* ph = world.GetPlayerHouseByInstanceID(GetZone()->GetInstanceID());
 		if (ph) {
 			HouseZone* hz = world.GetHouseZone(ph->house_id);
 			if (hz) {
 				int32 id = client->GetPlayer()->GetIDWithPlayerSpawn(this);
-				if (m_houseID)
-					ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(m_houseID));
+				ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(hz->id));
 
 				ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, id);
 			}
 		}
 	}
-	else if (client && m_houseID > 0 && strncasecmp("visit", command.c_str(), 6) == 0) {
+	else if (client && m_houseID > 0 && cmdlower == "access") {
+		// Used a door to enter a house
+		HouseZone* hz = nullptr;
+		PlayerHouse* ph = nullptr;
+		
+		int32 id = 0;
+		if(client->GetVersion() <= 546) {
+			id = client->GetPlayer()->GetIDWithPlayerSpawn(this);
+			ph = world.GetPlayerHouse(client, id, 0, &hz);
+		}
+		else {
+			hz = world.GetHouseZone(m_houseID);
+			if(hz) {
+				ph = world.GetPlayerHouseByHouseID(client->GetPlayer()->GetCharacterID(), hz->id);
+			}
+			id = client->GetPlayer()->GetID();// reconsider?
+		}
+		
+		if (ph && hz) {
+			// if we aren't in our own house we should get the full list of houses we can visit
+			if ( client->GetCurrentZone()->GetInstanceType() != Instance_Type::PERSONAL_HOUSE_INSTANCE && client->GetVersion() > 546 )
+				ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(hz->id));
+
+			ClientPacketFunctions::SendBaseHouseWindow(client, hz, ph, id);
+			client->GetCurrentZone()->SendHouseItems(client);
+		}
+		else {
+			if (hz)
+				ClientPacketFunctions::SendHousePurchase(client, hz, 0);
+		}
+	}
+	else if (client && m_houseID > 0 && cmdlower == "visit") {
+		HouseZone* hz = nullptr;
+		int32 id = client->GetPlayer()->GetIDWithPlayerSpawn(this);
+		PlayerHouse* ph = world.GetPlayerHouse(client, id, 0, &hz);
 		ClientPacketFunctions::SendHousingList(client);
-		ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(m_houseID));
+		if(hz != nullptr) {
+			ClientPacketFunctions::SendHouseVisitWindow(client, world.GetAllPlayerHousesByHouseID(hz->id));
+		}
 	}
 	else if (client && command.length() > 0) {
 		EntityCommand* entity_command = FindEntityCommand(command);

+ 32 - 0
EQ2/source/WorldServer/World.cpp

@@ -2060,6 +2060,38 @@ vector<PlayerHouse*> World::GetAllPlayerHousesByHouseID(int32 house_id) {
 	return ret;
 }
 
+PlayerHouse* World::GetPlayerHouse(Client* client, int32 spawn_id, int64 unique_house_id, HouseZone** set_house_zone) {
+	PlayerHouse* ph = nullptr;
+	HouseZone* hz = nullptr;
+	
+	if(spawn_id) {
+		Spawn* houseWidget = client->GetPlayer()->GetSpawnByIndex(spawn_id);
+		if(houseWidget && houseWidget->IsWidget() && ((Widget*)houseWidget)->GetHouseID()) {
+			hz = world.GetHouseZone(((Widget*)houseWidget)->GetHouseID());
+			if (hz) {
+				ph = world.GetPlayerHouseByHouseID(client->GetPlayer()->GetCharacterID(), hz->id);
+			}
+		}
+	}
+	
+	if(!ph && client->GetCurrentZone()->GetInstanceID()) {
+		ph = world.GetPlayerHouseByInstanceID(client->GetCurrentZone()->GetInstanceID());
+	}
+	
+	if(!ph && unique_house_id) {
+		ph = world.GetPlayerHouseByUniqueID(unique_house_id);
+	}
+	
+	if (ph && !hz) {
+		hz = world.GetHouseZone(ph->house_id);
+	}
+	
+	if(set_house_zone)
+		*set_house_zone = hz;
+	
+	return ph;
+}
+
 void World::PopulateTOVStatMap() {
 	//This function populates a map that converts changed CoE to ToV stats
 	tov_itemstat_conversion[0] = TOV_ITEM_STAT_HPREGEN;

+ 2 - 1
EQ2/source/WorldServer/World.h

@@ -590,7 +590,8 @@ public:
 	PlayerHouse* GetPlayerHouseByInstanceID(int32 instance_id);
 	vector<PlayerHouse*> GetAllPlayerHouses(int32 char_id);
 	vector<PlayerHouse*> GetAllPlayerHousesByHouseID(int32 house_id);
-
+	PlayerHouse* GetPlayerHouse(Client* client, int32 spawn_id, int64 unique_house_id, HouseZone** set_house_zone);
+	
 	void ReloadHouseData(PlayerHouse* ph);
 
 	PlayerGroupManager* GetGroupManager() { return &m_playerGroupManager; }

+ 70 - 19
EQ2/source/WorldServer/client.cpp

@@ -2161,11 +2161,19 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 	}
 	case OP_BuyPlayerHouseMsg: {
 		LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_BuyPlayerHouseMsg", opcode, opcode);
+		DumpPacket(app);
 		int64 bank_money = GetPlayer()->GetBankCoinsPlat();
 		PacketStruct* packet = configReader.getStruct("WS_BuyHouse", GetVersion());
 		if (packet) {
 			if(packet->LoadPacketData(app->pBuffer, app->size)) {
-				HouseZone* hz = world.GetHouseZone(packet->getType_int64_ByName("house_id"));
+				int64 house_id = 0;
+				if(GetVersion() <= 546) {
+					house_id = packet->getType_int32_ByName("house_id");
+				}
+				else {
+					house_id = packet->getType_int64_ByName("house_id");
+				}
+				HouseZone* hz = world.GetHouseZone(house_id);
 				if (hz) {
 					bool got_bank_money = BankHasCoin(hz->cost_coin);
 					int8 disable_alignment_req = rule_manager.GetGlobalRule(R_Player, DisableHouseAlignmentRequirement)->GetInt8();
@@ -2200,7 +2208,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 						world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
 						//ClientPacketFunctions::SendHousingList(this);
 						PlayerHouse* ph = world.GetPlayerHouseByUniqueID(unique_id);
-						ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, this->GetPlayer()->GetID());
+						ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, GetVersion() <= 546 ? house_id : this->GetPlayer()->GetID());
 						PlaySound("coin_cha_ching");
 					}
 					else if (status_req <= available_status && got_bank_money == 1) {
@@ -2220,7 +2228,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 							int64 unique_id = database.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, instance_zone->GetInstanceID(), upkeep_due);
 							world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
 							PlayerHouse* ph = world.GetPlayerHouseByUniqueID(unique_id);
-							ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, this->GetPlayer()->GetID());
+							ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, GetVersion() <= 546 ? house_id : this->GetPlayer()->GetID());
 							PlaySound("coin_cha_ching");
 					}
 					else
@@ -2237,19 +2245,25 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 	}
 	case OP_EnterHouseMsg: {
 		LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_EnterHouseMsg", opcode, opcode);
-		
+		DumpPacket(app);
 		PacketStruct* packet = configReader.getStruct("WS_EnterHouse", GetVersion());
 		if (packet) {
 			if(packet->LoadPacketData(app->pBuffer, app->size)) {
-				PlayerHouse* ph = world.GetPlayerHouseByUniqueID(packet->getType_int64_ByName("house_id"));
-				if (ph) {
-					HouseZone* hz = world.GetHouseZone(ph->house_id);
-					if (hz) {
-						ZoneServer* house = zone_list.GetByInstanceID(ph->instance_id, hz->zone_id, false, true);
-						if (house) {
-							Zone(house, true);
-						}
-					}
+				PlayerHouse* ph = nullptr;
+				HouseZone* hz = nullptr;
+				int64 house_id = 0;
+				int32 spawn_index = 0;
+				
+				if(GetVersion() <= 546) {
+					spawn_index = packet->getType_int32_ByName("house_id");
+				}
+				else {
+					house_id = packet->getType_int64_ByName("house_id");
+				}
+				
+				ZoneServer* house = GetHouseZoneServer(spawn_index, house_id);
+				if (house) {
+					Zone(house, true);
 				}
 			}
 		}
@@ -2264,11 +2278,18 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 
 		if (packet) {
 			if(packet->LoadPacketData(app->pBuffer, app->size)) {
-				int64 houseID = packet->getType_int64_ByName("house_id");
-				PlayerHouse* ph = world.GetPlayerHouseByUniqueID(houseID);
+				int64 house_id = 0;
+				
+				if(GetVersion() <= 546) {
+					house_id = packet->getType_int32_ByName("house_id");
+				}
+				else {
+					house_id = packet->getType_int64_ByName("house_id");
+				}
+				HouseZone* hz = nullptr;
+				PlayerHouse* ph = world.GetPlayerHouse(this, GetVersion() <= 546 ? house_id : 0, GetVersion() > 546 ? house_id : 0, &hz);
 				if (ph)
 				{
-					HouseZone* hz = world.GetHouseZone(ph->house_id);
 					if (!hz)
 					{
 						Message(CHANNEL_COLOR_YELLOW, "HouseZone ID %u does NOT exist!", ph->house_id);
@@ -2345,7 +2366,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 						ph->upkeep_due = upkeep_due;
 						database.SetHouseUpkeepDue(GetCharacterID(), ph->house_id, ph->instance_id, ph->upkeep_due);
 						//ClientPacketFunctions::SendHousingList(this);
-						ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, this->GetPlayer()->GetID());
+						ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, GetVersion() <= 546 ? house_id : this->GetPlayer()->GetID());
 						PlaySound("coin_cha_ching");
 					}
 					else if (!statusReq && got_bank_money == 1) {
@@ -2366,7 +2387,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 
 						ph->upkeep_due = upkeep_due;
 						database.SetHouseUpkeepDue(GetCharacterID(), ph->house_id, ph->instance_id, ph->upkeep_due);
-						ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, this->GetPlayer()->GetID());
+						ClientPacketFunctions::SendBaseHouseWindow(this, hz, ph, GetVersion() <= 546 ? house_id : this->GetPlayer()->GetID());
 						PlaySound("coin_cha_ching");
 					}
 					else
@@ -2382,7 +2403,7 @@ bool Client::HandlePacket(EQApplicationPacket* app) {
 					}
 				}
 				else
-					Message(CHANNEL_COLOR_YELLOW, "PlayerHouse ID %u does NOT exist!", houseID);
+					Message(CHANNEL_COLOR_YELLOW, "PlayerHouse ID %u does NOT exist!", house_id);
 			}
 		}
 
@@ -12371,4 +12392,34 @@ void Client::SendRecipeDetails(vector<int32>* recipes) {
 	
 	QueuePacket(packet->serialize());
 	safe_delete(packet);
+}
+
+ZoneServer* Client::GetHouseZoneServer(int32 spawn_id, int64 house_id) {
+	PlayerHouse* ph = nullptr;
+	HouseZone* hz = nullptr;
+	if(spawn_id) {
+		Spawn* houseWidget = GetPlayer()->GetSpawnByIndex(spawn_id);
+		if(houseWidget && houseWidget->IsWidget() && ((Widget*)houseWidget)->GetHouseID()) {
+			hz = world.GetHouseZone(((Widget*)houseWidget)->GetHouseID());
+			if (hz) {
+				ph = world.GetPlayerHouseByHouseID(GetPlayer()->GetCharacterID(), hz->id);
+			} else {
+				Message(CHANNEL_COLOR_YELLOW, "HouseWidget spawn index %u house zone could not be found.", spawn_id);
+			}
+		}
+	}
+	
+	if(!ph && house_id) {
+		ph = world.GetPlayerHouseByUniqueID(house_id);
+		if (ph) {
+			hz = world.GetHouseZone(ph->house_id);
+		}
+	}
+	
+	if (ph && hz) {
+		ZoneServer* house = zone_list.GetByInstanceID(ph->instance_id, hz->zone_id, false, true);
+		return house;
+	}
+	
+	return nullptr;
 }

+ 2 - 1
EQ2/source/WorldServer/client.h

@@ -685,7 +685,8 @@ private:
 	string* pending_last_name;
 	IncomingPaperdollImage incoming_paperdoll;
 	int32 transmuteID;
-
+	ZoneServer* GetHouseZoneServer(int32 spawn_id, int64 house_id);
+	
 	std::atomic<bool> m_recipeListSent;
 	bool initial_spawns_sent;
 	bool should_load_spells;

+ 4 - 0
EQ2/source/WorldServer/zoneserver.cpp

@@ -8392,6 +8392,10 @@ void ZoneServer::SendHouseItems(Client* client)
 
 	PacketStruct* packet = configReader.getStruct("WS_HouseItemsList", client->GetVersion());
 
+	if(!packet) {
+		return;
+	}
+	
 	std::vector<HouseItem> items = GetHouseItems(client);
 
 	// setting this to 1 puts it on the door widget

+ 6 - 6
server/ItemStructs.xml

@@ -40,12 +40,12 @@
     <Data ElementName="flags" Type="int32" Size="1" />
     <Data ElementName="unknown8_1" Type="int8" Size="15" />
     <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_array" Type="Array" ArraySizeVariable="stat_count">
+	  <Data ElementName="stat_type" Type="int8" Size="1"/> <!-- v138 -->
+	  <Data ElementName="stat_subtype" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" /> <!-- v139 -->
+	  <Data ElementName="value" Type="sint16" OversizedValue="127" OversizedByte="127" Size="1" /> <!-- v140 -->
+	  <Data ElementName="stat_name" Type="EQ2_8Bit_String" Size="1" /> <!-- v141? -->
+	</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" />

+ 98 - 6
server/WorldStructs.xml

@@ -15725,6 +15725,18 @@ to zero and treated like placeholders." />
 	<Data ElementName="claimed_on_this_char" Type="int8" Size="1" />		
 </Data>
 </Struct>
+<Struct Name="WS_PromoFlagsDetails" ClientVersion="546" OpcodeName="OP_PromoFlagsDetailsMsg">
+<Data ElementName="num_claim_items" Type="int32" Size="1" />
+<Data ElementName="claim_items_array" Type="Array" ArraySizeVariable="num_claim_items">		
+	<Data ElementName="id" Type="int32" Size="1" />	
+	<Data ElementName="not_yet_claimed" Type="int8" Size="1" />		
+	<Data ElementName="num_remaining" Type="int32" Size="1" />
+	<Data ElementName="one_per_character" Type="int8" Size="1" />
+	<Data ElementName="item_name" Type="EQ2_16Bit_String" Size="1" />	
+	<Data ElementName="text" Type="EQ2_16Bit_String" Size="1" />
+	<Data ElementName="claimed_on_this_char" Type="int8" Size="1" />		
+</Data>
+</Struct>
 <Struct Name="WS_PromoFlagsDetails" ClientVersion="547" OpcodeName="OP_PromoFlagsDetailsMsg">
 <Data ElementName="num_claim_items" Type="int32" Size="1" />
 <Data ElementName="claim_items_array" Type="Array" ArraySizeVariable="num_claim_items">
@@ -16726,17 +16738,16 @@ to zero and treated like placeholders." />
 <Struct Name="WS_DisplayVisitScreen" ClientVersion="1" OpcodeName="OP_DisplayInnVisitScreenMsg">
 <Data ElementName="num_houses" Type="int32" Size="1" />
 <Data ElementName="visithouse_array" Type="Array" ArraySizeVariable="num_houses">
-  <Data ElementName="unknown1" Type="int32" Size="1" />
+  <Data ElementName="house_id" Type="int32" Size="1" />
   <Data ElementName="house_owner" Type="EQ2_16Bit_String" />
+  <Data ElementName="access_level" Type="int8" Size="1" />
   <Data ElementName="unknown2" Type="int32" Size="1" />
-  <Data ElementName="unknown3" Type="int8" Size="1" />
 </Data>
 </Struct>
 <Struct Name="WS_DisplayVisitScreen" ClientVersion="1096" OpcodeName="OP_DisplayInnVisitScreenMsg">
 <Data ElementName="num_houses" Type="int32" Size="1" />
 <Data ElementName="visithouse_array" Type="Array" ArraySizeVariable="num_houses">
-  <Data ElementName="unknown1" Type="int32" Size="1" />
-  <Data ElementName="unknown2" Type="int32" Size="1" />
+  <Data ElementName="house_id" Type="int64" Size="1" />
   <Data ElementName="house_owner" Type="EQ2_16Bit_String" />
   <Data ElementName="house_location" Type="EQ2_16Bit_string" />
   <Data ElementName="access_level" Type="int8" Size="1" />
@@ -17954,6 +17965,19 @@ to zero and treated like placeholders." />
 </Struct>
 <Struct Name="WS_PlayerHousePurchase" ClientVersion="1" OpcodeName="OP_PlayerHousePurchaseScreenMsg">
 <Data ElementName="house_name" Type="EQ2_16Bit_String" />
+<Data ElementName="house_id" Type="int32" />
+<Data ElementName="spawn_id" Type="int32" />
+<Data ElementName="unknown1" Type="int32" />
+<Data ElementName="purchase_coins" Type="int32" OversizedValue="127" OversizedByte="127"/>
+<Data ElementName="purchase_status" Type="int32" OversizedValue="127" OversizedByte="127"/>
+<Data ElementName="upkeep_coins" Type="sint32" OversizedValue="127" OversizedByte="127"/>
+<Data ElementName="unknown" Type="sint32"/>
+<Data ElementName="upkeep_status" Type="sint32" OversizedValue="127" OversizedByte="127"/>
+<Data ElementName="unknown1" Type="int8" Size="2"/>
+<Data ElementName="enable_buy" Type="int8" />
+</Struct>
+<Struct Name="WS_PlayerHousePurchase" ClientVersion="547" OpcodeName="OP_PlayerHousePurchaseScreenMsg">
+<Data ElementName="house_name" Type="EQ2_16Bit_String" />
 <Data ElementName="house_id" Type="int64" />
 <Data ElementName="spawn_id" Type="int32" />
 <Data ElementName="purchase_coins" Type="int64" />
@@ -17965,9 +17989,64 @@ to zero and treated like placeholders." />
 <Data ElementName="enable_buy" Type="int8" />
 </Struct>
 <Struct Name="WS_BuyHouse" ClientVersion="1" OpcodeName="OP_BuyPlayerHouseMsg">
+<Data ElementName="house_id" Type="int32" />
+</Struct>
+<Struct Name="WS_BuyHouse" ClientVersion="547" OpcodeName="OP_BuyPlayerHouseMsg">
 <Data ElementName="house_id" Type="int64" />
 </Struct>
 <Struct Name="WS_PlayerHouseBaseScreen" ClientVersion="1" OpcodeName="OP_PlayerHouseBaseScreenMsg">
+<Data ElementName="spawn_id" Type="int32" />
+<Data ElementName="house_name" Type="EQ2_16Bit_String" />
+<Data ElementName="upkeep_cost_coins" Type="int64"/>
+<Data ElementName="upkeep_cost_status" Type="sint32"/>
+<Data ElementName="escrow_balance_coins" Type="int32"/>
+<Data ElementName="escrow_balance_status" Type="int32"/>
+<Data ElementName="unknownx" Type="int32" Size="1"/>
+<Data ElementName="upkeep_due" Type="int32" />
+<Data ElementName="privlage_level" Type="int8" />
+<Data ElementName="house_type" Type="int8" />
+<Data ElementName="inside_house" Type="int8" />
+<Data ElementName="unknown3" Type="int8" />
+<Data ElementName="num_access" Type="int8" />
+<Data ElementName="access_array" Type="Array" ArraySizeVariable="num_access">
+  <Data ElementName="access_unknown1" Type="int8" Size="8" />
+  <Data ElementName="access_name" Type="EQ2_16Bit_String" />
+  <Data ElementName="access_level" Type="int8" />
+</Data>
+<Data ElementName="public_access_level" Type="int8" />
+<Data ElementName="num_deposit" Type="int8" />
+<Data ElementName="deposit_array" Type="Array" ArraySizeVariable="num_deposit">
+  <Data ElementName="unknownx" Type="int8" Size="4"/>
+  <Data ElementName="deposit_name" Type="EQ2_16Bit_String" />
+  <Data ElementName="deposit_total_coin" Type="int64" />
+  <Data ElementName="deposit_total_status" Type="int32" />
+  <Data ElementName="deposit_last_coin" Type="int64" />
+  <Data ElementName="deposit_last_status" Type="int32" />
+  <Data ElementName="deposit_time_stamp" Type="int32" />
+</Data>
+<Data ElementName="num_history" Type="int8" />
+<Data ElementName="history_array" Type="Array" ArraySizeVariable="num_history">
+  <Data ElementName="unknown_history" Type="int8" Size="4"/>
+  <Data ElementName="history_name" Type="EQ2_16Bit_String" />
+  <Data ElementName="history_coins" Type="int64" />
+  <Data ElementName="history_status" Type="int32" />
+  <Data ElementName="history_time_stamp" Type="int32" />
+</Data>
+<Data ElementName="allow_item_collection" Type="int8" />
+<Data ElementName="unknown4" Type="int8" />
+<Data ElementName="placed_item_count" Type="int16" />
+<Data ElementName="max_placed_items" Type="int16" />
+<Data ElementName="actual_item_count" Type="int16" />
+<Data ElementName="moving_crate_item_count" Type="int16" />
+<Data ElementName="status_reduction" Type="int32" />
+<Data ElementName="coin_reduction" Type="float" />
+<Data ElementName="additional_slots" Type="int32" />
+<Data ElementName="allowed_amenities" Type="int32" />
+<Data ElementName="total_amenities" Type="int32" />
+<Data ElementName="get_portal_flag" Type="int8" />
+<Data ElementName="unknown6" Type="int8" />
+</Struct>
+<Struct Name="WS_PlayerHouseBaseScreen" ClientVersion="547" OpcodeName="OP_PlayerHouseBaseScreenMsg">
 <Data ElementName="house_id" Type="int64" />
 <Data ElementName="spawn_id" Type="int32" /><!-- spawn id of the door -->
 <Data ElementName="house_name" Type="EQ2_16Bit_String" />
@@ -18269,10 +18348,17 @@ to zero and treated like placeholders." />
 <Data ElementName="house_id2" Type="int64" />
 </Struct>
 <Struct Name="WS_EnterHouse" ClientVersion="1" OpcodeName="OP_EnterHouseMsg">
+<Data ElementName="house_id" Type="int32" />
+</Struct>
+<Struct Name="WS_EnterHouse" ClientVersion="547" OpcodeName="OP_EnterHouseMsg">
 <Data ElementName="house_id" Type="int64" />
 <Data ElementName="spawn_id" Type="int32" />
 </Struct>
 <Struct Name="WS_PayUpkeep" ClientVersion="1" OpcodeName="OP_PayHouseUpkeepMsg">
+<Data ElementName="house_id" Type="int32" />
+<Data ElementName="unknown" Type="int8" Size="3" />
+</Struct>
+<Struct Name="WS_PayUpkeep" ClientVersion="547" OpcodeName="OP_PayHouseUpkeepMsg">
 <Data ElementName="house_id" Type="int64" />
 <Data ElementName="unknown" Type="int8" Size="3" />
 </Struct>
@@ -18291,7 +18377,7 @@ to zero and treated like placeholders." />
   <Data ElementName="location" Type="int8" />
   <Data ElementName="unknown6" Type="int32" />
 </Data>
-<Data ElementName="unknown7" Type="int16" />
+<Data ElementName="is_widget_door" Type="int16" />
 </Struct>
 <Struct Name="WS_HouseItemsList" ClientVersion="57048" OpcodeName="OP_HouseItemsList">
 <Data ElementName="num_items" Type="int32" />
@@ -18308,7 +18394,7 @@ to zero and treated like placeholders." />
   <Data ElementName="location" Type="int8" />
   <Data ElementName="unknown6" Type="int32" />
 </Data>
-<Data ElementName="unknown7" Type="int16" />
+<Data ElementName="is_widget_door" Type="int16" />
 </Struct>
 <Struct Name="WS_HouseItemsList" ClientVersion="60114" OpcodeName="OP_HouseItemsList">
 <Data ElementName="num_items" Type="int32" />
@@ -18812,6 +18898,12 @@ to zero and treated like placeholders." />
  </Data> 
 </Struct>
 <Struct Name="WS_UpdateHouseAccessDataMsg" ClientVersion="1" OpcodeName="OP_UpdateHouseAccessDataMsg">
+  <Data ElementName="success" Type="int32"/>
+  <Data ElementName="house_id" Type="int32" />
+  <Data ElementName="unknown2" Type="int32" />
+  <Data ElementName="unknown3" Type="int32" />
+</Struct>
+<Struct Name="WS_UpdateHouseAccessDataMsg" ClientVersion="547" OpcodeName="OP_UpdateHouseAccessDataMsg">
   <Data ElementName="success" Type="int32"/>
   <Data ElementName="house_id" Type="int64" />
   <Data ElementName="unknown2" Type="int32" />