Dress NPCs

It does sound quite nice! I’m assuming that method would prevent the model from randomizing with each refresh (like a relog/zoning)?

I do have another question - with how the outfits are loaded, might it be possible to change something to prevent a crash/freeze when trying to reload a creature template? I tried fiddling around with the code and cleared out the outfitStore before reloading creature_template as a test, but of course that didn’t work. Any potential ideas?

Yes

Hmm, should see why it is crashing.

… debug some … hmm I may look into that

Major update!
Implemented all things suggested by +Kretol.

Moved to github

Updated to newer TC version

Basically in the current version:
You create the row in creature_template_outfits
negative item entries are displayIDs and positive are item entries.

The entry column just holds an unique ID.

Then you place the unique ID (entry) from creature_template_outfits to modelid column in creature_template for your creature, but you make it negative (so 123 will be -123).

You should be able to use up to 4 displays as normal and you should be able to mix normal displays and outfits.

Just noticed this update! Thank you for considering and implementing my suggestions! /emoticons/default_smile.png

Thanks to Valkryst, DressNPCs is now updated to work with multiple outfits on same NPC properly.

Before using multiple outfits on one NPC with same race would only use the first one. (IE use four human outfits but different facial features or items would show only the first one always)

Now having a 6.x branch version:
https://github.com/Rochet2/TrinityCore/tree/dressnpcs_6.x

Note that in addition to normal races you can dress any other race like naga, tuskarr … (image below from WoD):
http://i.imgur.com/fx3S8Tm.jpg

Greetings, Rochet!

I've updated LordPsyan's NewNPCMod patch and i'm using it in combo with your patch.

With NewNPCMod players can equip their controlled bots (which are treated much like pets) with equipment from their bags. That said, i modded the script to also update the NPCBot's creature_outfit_template with the new outfit data, and reload their entry from said table so to display the newly equipped items.

My problem is that, when i issue a change in outfits from the table, and reload it, the change does not actually take place for already-spawned creatures until they get unloaded and re-loaded, so my players have to log in and out before they can see the visual changes in the bot equipment.

I was wondering if there's any way to make it more "dynamic", can I force a reload of outfit info for already-active Creature objects?

Dynamic loading is a pain in the ass.
There is a way and it is sending the mirror image packets to everyone. (I mean the creature’s packet is sent to everyone nearby)

Take a look at WorldSession::HandleMirrorImageDataRequest for sending the packets.
However if you want to for example add or remove rows or change races or something like that, you also need to change the creature flags: UNIT_FLAG2_MIRROR_IMAGE
And you need to set his modelID to the correct one for the race. I believe I implemented the function ObjectMgr::GetCreatureDisplay for getting the model. You would pass the negative modelid to that (basically the outfitID, but it needs to be a negative number)

Could be something more is needed, but I cant come up with it right now. At least not without testing anything.

I have been thinking about that but i have no idea how i could somehow prompt nearby player clients to request a Mirror Image packet. I’m not so good with coding/networking theory, but i don’t think i can just send them the packet myself, or can i?

EDIT: Nevermind, i did try to send the packet, but it had no effect. I’m currently trying to figure whether or not the client even receives the packet but i’m having no luck atm.
For reference, this is my code.

void bot_minion_ai::_reloadBotOutfit() {
sObjectMgr->LoadCreatureOutfits();
ObjectGuid guid = me->GetCharmerOrOwnerPlayerOrPlayerItself()->GetGUID();

CreatureOutfitContainer const& outfits = sObjectMgr->GetCreatureOutfitMap();
CreatureOutfitContainer::const_iterator it = outfits.find(me->GetEntry());

WorldPacket data(SMSG_MIRRORIMAGE_DATA, 68);
data << uint64(guid);
data << uint32(me->GetNativeDisplayId()); // displayId
data << uint8(it->second.race); // race
data << uint8(it->second.gender); // gender
data << uint8(me->getClass()); // class
data << uint8(it->second.skin); // skin
data << uint8(it->second.face); // face
data << uint8(it->second.hair); // hair
data << uint8(it->second.haircolor); // haircolor
data << uint8(it->second.facialhair); // facialhair
data << uint32(0); // guildId

// item displays
for (uint8 i = 0; i != MAX_CREATURE_OUTFIT_DISPLAYS; ++i)
data << uint32(it->second.outfit);

[I]

[/I]
me->GetCharmerOrOwnerPlayerOrPlayerItself()->GetSession()->SendPacket(&data);

}

[I]

[/I]
void bot_minion_ai::_updateCreatureOutfits(uint8 slot, Item* item) {



// BOT_SLOT_NONE = 0,


// BOT_SLOT_MAINHAND = 1,


// BOT_SLOT_OFFHAND = 2,


// BOT_SLOT_RANGED = 3,


// BOT_SLOT_HEAD = 4,


// BOT_SLOT_SHOULDERS = 5,


// BOT_SLOT_CHEST = 6,


// BOT_SLOT_WAIST = 7,


// BOT_SLOT_LEGS = 8,


// BOT_SLOT_FEET = 9,


// BOT_SLOT_WRIST = 10,


// BOT_SLOT_HANDS = 11,


// BOT_SLOT_BACK = 12,


// BOT_SLOT_BODY = 13,


// BOT_SLOT_FINGER1 = 14,


// BOT_SLOT_FINGER2 = 15,


// BOT_SLOT_TRINKET1 = 16,


// BOT_SLOT_TRINKET2 = 17,


// BOT_SLOT_NECK = 18,

[I]

[/I]
/*"SELECT entry, race, gender, skin, face, hair, haircolor, facialhair, "

8 9 10 11 12 13 14 15 16 17 18


“head, shoulders, body, chest, waist, legs, feet, wrists, hands, back, tabard FROM creature_template_outfits”*/


QueryResult result;


QueryResult displayQuery;


uint32 displayid;

[I]

[/I]
if (!item) {

displayid = 0;


}


else {


displayQuery = WorldDatabase.PQuery(“SELECT displayid FROM item_template WHERE entry=%d”, item->GetEntry());


displayid = displayQuery->Fetch()[0].GetUInt32();


}

[I]

[/I]
switch (slot+1) {

case BOT_SLOT_HEAD:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET head=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_SHOULDERS:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET shoulders=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_CHEST:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET chest=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_WAIST:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET waist=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_LEGS:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET legs=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_FEET:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET feet=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_WRIST:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET wrists=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_HANDS:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET hands=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_BACK:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET back=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


case BOT_SLOT_BODY:


result = WorldDatabase.PQuery(“UPDATE creature_template_outfits SET body=%d WHERE entry=%d”, displayid, me->GetEntry());


break;


}




_reloadBotOutfit();


}

@atheostg
It seems you insert wrong stuff to the packet - the guid at the top is the creature guid, not charmerorowner which I think is the player.

Im not sure if the code somehow changed when you pasted it here, but the way you do the loop for items ( [COLOR=rgb(39,42,52)]MAX_CREATURE_OUTFIT_DISPLAYS ) is different than what I do.
The loop you have doesnt insert the items to the packet but just the outfitID over and over again. Think that is wrong.

Instead of sending the packet to the player directly you can use me->SendMessageToSet(&data, false); This will send the packet to everyone that can see the creature.

Instead of doing the DB query for the item displayID you can do item->GetTemplate()->DisplayInfoID
Unless you have some reason to use the DB query...

If you have to do these update statements to the DB, I suggest you use WorldDatabase.DirectPExecute which does the same job but doesnt expect a return value because you are doing an UPDATE and not a SELECT statement.
I do NOT recommend using PExecute in this case since you seem to update and directly reload the data afterwards. PExecute is asynchronous and the SQL could (will) execute after your query for reloading the data is executed meaning you will load the old data on reload.

@Rochet2

Thanks a lot rochet, i did it!
The bots now auto-update when a player changes their equipment. Salutations!

[ATTACH]1814._xfImport[/ATTACH]

Bumping this a bit. 7.x support on TC
Also had 6.x support and 3.3.5 support.

7.x has demon hunter features and mythic etc item support.

New for 7.x dressnpcs:
- appearanceid as a separate column
- workaround for missing gossip sounds, supply your own sounds in DB
- added guildid to allow define tabards
http://rochet2.github.io/Dress-NPCs.html

A bit of an update yet again.

Now .morph x works properly and you can use an outfit entry as the morphed display.
Same with .npc set model x.
You can use C++ to create and assign an outfit that is not in DB.
You can use outfits with smart_scripts and game_event tables and creature.modelid column.
Outfits now share entry space with modelids.
You can use Get/SetDisplayId and it should get/set the outfit if an outfit ID is used. This allows the seamless interaction of dressnpcs and other core functionalities.

Read the readme on how to use C++ and how outfit ID is now used.