diff --git a/zone/entity.cpp b/zone/entity.cpp index a2fb2657d..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(); } @@ -1179,20 +1186,9 @@ void EntityList::SendZoneSpawnsBulk(Client *client) bzsp->AddSpawn(&ns); } - // On NPCs wearing gear from loottable or previously traded - // to them, mass spawn does not properly update the visual look. - // (Bulk packet sends the same info - client just doesn't use it. - // except on primary/secondary - tested on multiple client types) - // Do that using a Wear Change now. - if (!spawn->IsClient()) { - const Item_Struct *item; - for (int i=0; i< 7 ; ++i) { - item=database.GetItem(spawn->GetEquipment(i)); - if (item != 0) { - spawn->SendWearChange(i,client); - } - } - } + // 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 9e9bcbd5d..9b4c2f88e 100644 --- a/zone/mob.cpp +++ b/zone/mob.cpp @@ -2552,6 +2552,34 @@ uint32 NPC::GetEquipment(uint8 material_slot) const return equipment[invslot]; } +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)); diff --git a/zone/mob.h b/zone/mob.h index 22f9cb5f1..ada2c56dd 100644 --- a/zone/mob.h +++ b/zone/mob.h @@ -171,6 +171,7 @@ 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 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);