diff --git a/common/races.h b/common/races.h index 2c360e908..68add5cca 100644 --- a/common/races.h +++ b/common/races.h @@ -47,6 +47,8 @@ #define IKSAR 128 #define VAHSHIR 130 #define CONTROLLED_BOAT 141 +#define MINOR_ILL_OBJ 142 +#define TREE 143 #define IKSAR_SKELETON 161 #define FROGLOK 330 #define FROGLOK2 74 // Not sure why /who all reports race as 74 for frogloks diff --git a/zone/entity.cpp b/zone/entity.cpp index a28a4b846..c6de7b33e 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -618,6 +618,7 @@ void EntityList::AddNPC(NPC *npc, bool SendSpawnPacket, bool dontqueue) EQApplicationPacket *app = new EQApplicationPacket; npc->CreateSpawnPacket(app, npc); QueueClients(npc, app); + npc->SendArmorAppearance(); safe_delete(app); } else { NewSpawn_Struct *ns = new NewSpawn_Struct; @@ -726,10 +727,16 @@ void EntityList::CheckSpawnQueue() EQApplicationPacket *outapp = 0; iterator.Reset(); + NewSpawn_Struct *ns; + while(iterator.MoreElements()) { outapp = new EQApplicationPacket; - Mob::CreateSpawnPacket(outapp, iterator.GetData()); + ns = iterator.GetData(); + Mob::CreateSpawnPacket(outapp, ns); QueueClients(0, outapp); + auto it = npc_list.find(ns->spawn.spawnId); + NPC *pnpc = it->second; + pnpc->SendArmorAppearance(); safe_delete(outapp); iterator.RemoveCurrent(); } @@ -1149,19 +1156,39 @@ void EntityList::SendZoneSpawnsBulk(Client *client) NewSpawn_Struct ns; Mob *spawn; uint32 maxspawns = 100; + EQApplicationPacket *app; if (maxspawns > mob_list.size()) maxspawns = mob_list.size(); BulkZoneSpawnPacket *bzsp = new BulkZoneSpawnPacket(client, maxspawns); + + int32 race=-1; for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { spawn = it->second; if (spawn && spawn->InZone()) { if (spawn->IsClient() && (spawn->CastToClient()->GMHideMe(client) || spawn->CastToClient()->IsHoveringForRespawn())) continue; - memset(&ns, 0, sizeof(NewSpawn_Struct)); - spawn->FillSpawnStruct(&ns, client); - bzsp->AddSpawn(&ns); + + race = spawn->GetRace(); + + // Illusion races on PCs don't work as a mass spawn + // But they will work as an add_spawn AFTER CLIENT_CONNECTED. + if (spawn->IsClient() && (race == MINOR_ILL_OBJ || race == TREE)) { + app = new EQApplicationPacket; + spawn->CreateSpawnPacket(app); + client->QueuePacket(app, true, Client::CLIENT_CONNECTED); + safe_delete(app); + } + else { + memset(&ns, 0, sizeof(NewSpawn_Struct)); + spawn->FillSpawnStruct(&ns, client); + bzsp->AddSpawn(&ns); + } + + // Despite being sent in the OP_ZoneSpawns packet, the client + // does not display worn armor correctly so display it. + spawn->SendArmorAppearance(client); } } safe_delete(bzsp); diff --git a/zone/mob.cpp b/zone/mob.cpp index d47be1957..11d82dbd1 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2552,7 +2552,35 @@ uint32 NPC::GetEquipment(uint8 material_slot) const return equipment[invslot]; } -void Mob::SendWearChange(uint8 material_slot) +void Mob::SendArmorAppearance(Client *one_client) +{ + // one_client of 0 means sent to all clients + // + // Despite the fact that OP_NewSpawn and OP_ZoneSpawns include the + // armor being worn and its mats, the client doesn't update the display + // on arrival of these packets reliably. + // + // Send Wear changes if mob is a PC race and item is an armor slot. + // The other packets work for primary/secondary. + + if (IsPlayerRace(race)) + { + if (!IsClient()) + { + const Item_Struct *item; + for (int i=0; i< 7 ; ++i) + { + item=database.GetItem(GetEquipment(i)); + if (item != 0) + { + SendWearChange(i,one_client); + } + } + } + } +} + +void Mob::SendWearChange(uint8 material_slot, Client *one_client) { EQApplicationPacket* outapp = new EQApplicationPacket(OP_WearChange, sizeof(WearChange_Struct)); WearChange_Struct* wc = (WearChange_Struct*)outapp->pBuffer; @@ -2564,7 +2592,15 @@ void Mob::SendWearChange(uint8 material_slot) wc->color.Color = GetEquipmentColor(material_slot); wc->wear_slot_id = material_slot; - entity_list.QueueClients(this, outapp); + if (!one_client) + { + entity_list.QueueClients(this, outapp); + } + else + { + one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED); + } + safe_delete(outapp); } diff --git a/zone/mob.h b/zone/mob.h index 5bbd1ea0b..ada2c56dd 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -171,7 +171,8 @@ public: void SendAppearanceEffect(uint32 parm1, uint32 parm2, uint32 parm3, uint32 parm4, uint32 parm5, Client *specific_target=nullptr); void SendTargetable(bool on, Client *specific_target = nullptr); - virtual void SendWearChange(uint8 material_slot); + virtual void SendArmorAppearance(Client *one_client = nullptr); + virtual void SendWearChange(uint8 material_slot, Client *one_client = nullptr); virtual void SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model = 0, uint32 elite_material = 0, uint32 unknown06 = 0, uint32 unknown18 = 0); virtual void SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uint8 blue_tint);