· 9 years ago · Dec 08, 2016, 01:52 AM
1diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
2index 051b5e8..5a11eca 100644
3--- a/src/server/game/DataStores/DBCStores.cpp
4+++ b/src/server/game/DataStores/DBCStores.cpp
5@@ -122,7 +122,7 @@ DBCStorage <HolidaysEntry> sHolidaysStore(Holidaysfmt);
6 DBCStorage <ItemEntry> sItemStore(Itemfmt);
7 DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore(ItemBagFamilyfmt);
8 //DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt);
9-//DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently
10+DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt);
11 DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt);
12 DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore(ItemLimitCategoryEntryfmt);
13 DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt);
14@@ -377,7 +377,7 @@ void LoadDBCStores(const std::string& dataPath)
15
16 LoadDBC(availableDbcLocales, bad_dbc_files, sItemStore, dbcPath, "Item.dbc");
17 LoadDBC(availableDbcLocales, bad_dbc_files, sItemBagFamilyStore, dbcPath, "ItemBagFamily.dbc");
18- //LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemDisplayInfoStore, dbcPath, "ItemDisplayInfo.dbc"); -- not used currently
19+ LoadDBC(availableDbcLocales, bad_dbc_files, sItemDisplayInfoStore, dbcPath, "ItemDisplayInfo.dbc");
20 //LoadDBC(dbcCount, availableDbcLocales, bad_dbc_files, sItemCondExtCostsStore, dbcPath, "ItemCondExtCosts.dbc");
21 LoadDBC(availableDbcLocales, bad_dbc_files, sItemExtendedCostStore, dbcPath, "ItemExtendedCost.dbc");
22 LoadDBC(availableDbcLocales, bad_dbc_files, sItemLimitCategoryStore, dbcPath, "ItemLimitCategory.dbc");
23diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
24index 128ff7a..00f430e 100644
25--- a/src/server/game/DataStores/DBCStores.h
26+++ b/src/server/game/DataStores/DBCStores.h
27@@ -134,7 +134,7 @@ TC_GAME_API extern DBCStorage <GtRegenMPPerSptEntry> sGtRegenMPPerSptSto
28 TC_GAME_API extern DBCStorage <HolidaysEntry> sHolidaysStore;
29 TC_GAME_API extern DBCStorage <ItemEntry> sItemStore;
30 TC_GAME_API extern DBCStorage <ItemBagFamilyEntry> sItemBagFamilyStore;
31-//TC_GAME_API extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore; -- not used currently
32+TC_GAME_API extern DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore;
33 TC_GAME_API extern DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore;
34 TC_GAME_API extern DBCStorage <ItemLimitCategoryEntry> sItemLimitCategoryStore;
35 TC_GAME_API extern DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore;
36diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
37index 8431f36..6d15721e 100644
38--- a/src/server/game/DataStores/DBCStructure.h
39+++ b/src/server/game/DataStores/DBCStructure.h
40@@ -850,7 +850,7 @@ struct ItemDisplayInfoEntry
41 uint32 ID; // 0 m_ID
42 // 1 m_modelName[2]
43 // 2 m_modelTexture[2]
44- // 3 m_inventoryIcon
45+ char* inventoryIcon; // 3 m_inventoryIcon
46 // 4 m_geosetGroup[3]
47 // 5 m_flags
48 // 6 m_spellVisualID
49diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
50index 1accc81..8dc0392 100644
51--- a/src/server/game/DataStores/DBCfmt.h
52+++ b/src/server/game/DataStores/DBCfmt.h
53@@ -75,7 +75,7 @@ char const GtRegenMPPerSptfmt[] = "f";
54 char const Holidaysfmt[] = "niiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiixxsiix";
55 char const Itemfmt[] = "niiiiiii";
56 char const ItemBagFamilyfmt[] = "nxxxxxxxxxxxxxxxxx";
57-//char const ItemDisplayTemplateEntryfmt[] = "nxxxxxxxxxxixxxxxxxxxxx";
58+char const ItemDisplayTemplateEntryfmt[] = "nxxxxsxxxxxxxxxxxxxxxxxxx";
59 //char const ItemCondExtCostsEntryfmt[] = "xiii";
60 char const ItemExtendedCostEntryfmt[] = "niiiiiiiiiiiiiix";
61 char const ItemLimitCategoryEntryfmt[] = "nxxxxxxxxxxxxxxxxxii";
62diff --git a/src/server/game/Entities/Item/Transmogrification.cpp b/src/server/game/Entities/Item/Transmogrification.cpp
63new file mode 100644
64index 0000000..ec35462
65--- /dev/null
66+++ b/src/server/game/Entities/Item/Transmogrification.cpp
67@@ -0,0 +1,755 @@
68+#include "Transmogrification.h"
69+#include "Bag.h"
70+#include "Common.h"
71+#include "Config.h"
72+#include "DatabaseEnv.h"
73+#include "DBCStructure.h"
74+#include "Define.h"
75+#include "Field.h"
76+#include "GameEventMgr.h"
77+#include "Item.h"
78+#include "ItemPrototype.h"
79+#include "Language.h"
80+#include "Log.h"
81+#include "ObjectGuid.h"
82+#include "ObjectMgr.h"
83+#include "Player.h"
84+#include "QueryResult.h"
85+#include "ScriptMgr.h"
86+#include "SharedDefines.h"
87+#include "Transaction.h"
88+#include "WorldSession.h"
89+#include <sstream>
90+#include <string>
91+
92+#ifdef PRESETS
93+void Transmogrification::PresetTransmog(Player* player, Item* itemTransmogrified, uint32 fakeEntry, uint8 slot)
94+{
95+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::PresetTransmog");
96+
97+ if (!EnableSets)
98+ return;
99+ if (!player || !itemTransmogrified)
100+ return;
101+ if (slot >= EQUIPMENT_SLOT_END)
102+ return;
103+ if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), sObjectMgr->GetItemTemplate(fakeEntry)))
104+ return;
105+
106+ SetFakeEntry(player, itemTransmogrified, fakeEntry);
107+
108+ itemTransmogrified->UpdatePlayedTime(player);
109+
110+ itemTransmogrified->SetOwnerGUID(player->GetGUID());
111+ itemTransmogrified->SetNotRefundable(player);
112+ itemTransmogrified->ClearSoulboundTradeable(player);
113+}
114+
115+void Transmogrification::LoadPlayerSets(Player* player)
116+{
117+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::LoadPlayerSets");
118+
119+ player->presetMap.clear();
120+
121+ QueryResult result = CharacterDatabase.PQuery("SELECT `PresetID`, `SetName`, `SetData` FROM `custom_transmogrification_sets` WHERE Owner = %u", player->GetGUID().GetCounter());
122+ if (!result)
123+ return;
124+
125+ do
126+ {
127+ Field* field = result->Fetch();
128+ uint8 PresetID = field[0].GetUInt8();
129+ std::string SetName = field[1].GetString();
130+ std::istringstream SetData(field[2].GetString());
131+
132+ player->presetMap[PresetID].name = SetName;
133+
134+ while (SetData.good())
135+ {
136+ uint32 slot;
137+ uint32 entry;
138+ SetData >> slot >> entry;
139+ if (SetData.fail())
140+ break;
141+ if (slot >= EQUIPMENT_SLOT_END)
142+ {
143+ TC_LOG_ERROR("custom.transmog", "Item entry (FakeEntry: %u, playerGUID: %u, slot: %u, presetId: %u) has invalid slot, ignoring.", entry, player->GetGUID().GetCounter(), uint32(slot), uint32(PresetID));
144+ continue;
145+ }
146+ if (sObjectMgr->GetItemTemplate(entry))
147+ {
148+ player->presetMap[PresetID].slotMap[slot] = entry;
149+ }
150+ else
151+ TC_LOG_ERROR("custom.transmog", "Item entry (FakeEntry: %u, playerGUID: %u, slot: %u, presetId: %u) does not exist, ignoring.", entry, player->GetGUID().GetCounter(), uint32(slot), uint32(PresetID));
152+ }
153+
154+ if (player->presetMap[PresetID].slotMap.empty())
155+ {
156+ // Should never happen
157+ player->presetMap.erase(PresetID);
158+ CharacterDatabase.PExecute("DELETE FROM `custom_transmogrification_sets` WHERE Owner = %u AND PresetID = %u", player->GetGUID().GetCounter(), uint32(PresetID));
159+ return;
160+ }
161+
162+ } while (result->NextRow());
163+}
164+#endif
165+
166+Transmogrification* Transmogrification::instance()
167+{
168+ // Thread safe in C++11 standard
169+ static Transmogrification instance;
170+ return &instance;
171+}
172+
173+const char* Transmogrification::GetSlotName(uint8 slot, WorldSession* /*session*/) const
174+{
175+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetSlotName");
176+
177+ switch (slot)
178+ {
179+ case EQUIPMENT_SLOT_HEAD: return "Head";// session->GetTrinityString(LANG_SLOT_NAME_HEAD);
180+ case EQUIPMENT_SLOT_SHOULDERS: return "Shoulders";// session->GetTrinityString(LANG_SLOT_NAME_SHOULDERS);
181+ case EQUIPMENT_SLOT_BODY: return "Shirt";// session->GetTrinityString(LANG_SLOT_NAME_BODY);
182+ case EQUIPMENT_SLOT_CHEST: return "Chest";// session->GetTrinityString(LANG_SLOT_NAME_CHEST);
183+ case EQUIPMENT_SLOT_WAIST: return "Waist";// session->GetTrinityString(LANG_SLOT_NAME_WAIST);
184+ case EQUIPMENT_SLOT_LEGS: return "Legs";// session->GetTrinityString(LANG_SLOT_NAME_LEGS);
185+ case EQUIPMENT_SLOT_FEET: return "Feet";// session->GetTrinityString(LANG_SLOT_NAME_FEET);
186+ case EQUIPMENT_SLOT_WRISTS: return "Wrists";// session->GetTrinityString(LANG_SLOT_NAME_WRISTS);
187+ case EQUIPMENT_SLOT_HANDS: return "Hands";// session->GetTrinityString(LANG_SLOT_NAME_HANDS);
188+ case EQUIPMENT_SLOT_BACK: return "Back";// session->GetTrinityString(LANG_SLOT_NAME_BACK);
189+ case EQUIPMENT_SLOT_MAINHAND: return "Main hand";// session->GetTrinityString(LANG_SLOT_NAME_MAINHAND);
190+ case EQUIPMENT_SLOT_OFFHAND: return "Off hand";// session->GetTrinityString(LANG_SLOT_NAME_OFFHAND);
191+ case EQUIPMENT_SLOT_RANGED: return "Ranged";// session->GetTrinityString(LANG_SLOT_NAME_RANGED);
192+ case EQUIPMENT_SLOT_TABARD: return "Tabard";// session->GetTrinityString(LANG_SLOT_NAME_TABARD);
193+ default: return NULL;
194+ }
195+}
196+
197+std::string Transmogrification::GetItemIcon(uint32 entry, uint32 width, uint32 height, int x, int y) const
198+{
199+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetItemIcon");
200+
201+ std::ostringstream ss;
202+ ss << "|TInterface";
203+ const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
204+ const ItemDisplayInfoEntry* dispInfo = NULL;
205+ if (temp)
206+ {
207+ dispInfo = sItemDisplayInfoStore.LookupEntry(temp->DisplayInfoID);
208+ if (dispInfo)
209+ ss << "/ICONS/" << dispInfo->inventoryIcon;
210+ }
211+ if (!dispInfo)
212+ ss << "/InventoryItems/WoWUnknownItem01";
213+ ss << ":" << width << ":" << height << ":" << x << ":" << y << "|t";
214+ return ss.str();
215+}
216+
217+std::string Transmogrification::GetSlotIcon(uint8 slot, uint32 width, uint32 height, int x, int y) const
218+{
219+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetSlotIcon");
220+
221+ std::ostringstream ss;
222+ ss << "|TInterface/PaperDoll/";
223+ switch (slot)
224+ {
225+ case EQUIPMENT_SLOT_HEAD: ss << "UI-PaperDoll-Slot-Head"; break;
226+ case EQUIPMENT_SLOT_SHOULDERS: ss << "UI-PaperDoll-Slot-Shoulder"; break;
227+ case EQUIPMENT_SLOT_BODY: ss << "UI-PaperDoll-Slot-Shirt"; break;
228+ case EQUIPMENT_SLOT_CHEST: ss << "UI-PaperDoll-Slot-Chest"; break;
229+ case EQUIPMENT_SLOT_WAIST: ss << "UI-PaperDoll-Slot-Waist"; break;
230+ case EQUIPMENT_SLOT_LEGS: ss << "UI-PaperDoll-Slot-Legs"; break;
231+ case EQUIPMENT_SLOT_FEET: ss << "UI-PaperDoll-Slot-Feet"; break;
232+ case EQUIPMENT_SLOT_WRISTS: ss << "UI-PaperDoll-Slot-Wrists"; break;
233+ case EQUIPMENT_SLOT_HANDS: ss << "UI-PaperDoll-Slot-Hands"; break;
234+ case EQUIPMENT_SLOT_BACK: ss << "UI-PaperDoll-Slot-Chest"; break;
235+ case EQUIPMENT_SLOT_MAINHAND: ss << "UI-PaperDoll-Slot-MainHand"; break;
236+ case EQUIPMENT_SLOT_OFFHAND: ss << "UI-PaperDoll-Slot-SecondaryHand"; break;
237+ case EQUIPMENT_SLOT_RANGED: ss << "UI-PaperDoll-Slot-Ranged"; break;
238+ case EQUIPMENT_SLOT_TABARD: ss << "UI-PaperDoll-Slot-Tabard"; break;
239+ default: ss << "UI-Backpack-EmptySlot";
240+ }
241+ ss << ":" << width << ":" << height << ":" << x << ":" << y << "|t";
242+ return ss.str();
243+}
244+
245+std::string Transmogrification::GetItemLink(Item* item, WorldSession* session) const
246+{
247+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetItemLink");
248+
249+ int loc_idx = session->GetSessionDbLocaleIndex();
250+ const ItemTemplate* temp = item->GetTemplate();
251+ std::string name = temp->Name1;
252+ if (ItemLocale const* il = sObjectMgr->GetItemLocale(temp->ItemId))
253+ ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
254+
255+ if (int32 itemRandPropId = item->GetItemRandomPropertyId())
256+ {
257+ char* const* suffix = NULL;
258+ if (itemRandPropId < 0)
259+ {
260+ const ItemRandomSuffixEntry* itemRandEntry = sItemRandomSuffixStore.LookupEntry(-item->GetItemRandomPropertyId());
261+ if (itemRandEntry)
262+ suffix = itemRandEntry->nameSuffix;
263+ }
264+ else
265+ {
266+ const ItemRandomPropertiesEntry* itemRandEntry = sItemRandomPropertiesStore.LookupEntry(item->GetItemRandomPropertyId());
267+ if (itemRandEntry)
268+ suffix = itemRandEntry->nameSuffix;
269+ }
270+ if (suffix)
271+ {
272+ std::string test(suffix[(name != temp->Name1) ? loc_idx : DEFAULT_LOCALE]);
273+ if (!test.empty())
274+ {
275+ name += ' ';
276+ name += test;
277+ }
278+ }
279+ }
280+
281+ std::ostringstream oss;
282+ oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec <<
283+ "|Hitem:" << temp->ItemId << ":" <<
284+ item->GetEnchantmentId(PERM_ENCHANTMENT_SLOT) << ":" <<
285+ item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT) << ":" <<
286+ item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_2) << ":" <<
287+ item->GetEnchantmentId(SOCK_ENCHANTMENT_SLOT_3) << ":" <<
288+ item->GetEnchantmentId(BONUS_ENCHANTMENT_SLOT) << ":" <<
289+ item->GetItemRandomPropertyId() << ":" << item->GetItemSuffixFactor() << ":" <<
290+ (uint32)item->GetOwner()->getLevel() << "|h[" << name << "]|h|r";
291+
292+ return oss.str();
293+}
294+
295+std::string Transmogrification::GetItemLink(uint32 entry, WorldSession* session) const
296+{
297+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetItemLink");
298+
299+ const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
300+ int loc_idx = session->GetSessionDbLocaleIndex();
301+ std::string name = temp->Name1;
302+ if (ItemLocale const* il = sObjectMgr->GetItemLocale(entry))
303+ ObjectMgr::GetLocaleString(il->Name, loc_idx, name);
304+
305+ std::ostringstream oss;
306+ oss << "|c" << std::hex << ItemQualityColors[temp->Quality] << std::dec <<
307+ "|Hitem:" << entry << ":0:0:0:0:0:0:0:0:0|h[" << name << "]|h|r";
308+
309+ return oss.str();
310+}
311+
312+uint32 Transmogrification::GetFakeEntry(const Item* item)
313+{
314+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetFakeEntry");
315+
316+ Player* owner = item->GetOwner();
317+
318+ if (!owner)
319+ return 0;
320+ if (owner->transmogMap.empty())
321+ return 0;
322+
323+ TransmogMapType::const_iterator it = owner->transmogMap.find(item->GetGUID());
324+ if (it == owner->transmogMap.end())
325+ return 0;
326+ return it->second;
327+}
328+
329+void Transmogrification::UpdateItem(Player* player, Item* item) const
330+{
331+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::UpdateItem");
332+
333+ if (item->IsEquipped())
334+ {
335+ player->SetVisibleItemSlot(item->GetSlot(), item);
336+ if (player->IsInWorld())
337+ item->SendUpdateToPlayer(player);
338+ }
339+}
340+
341+void Transmogrification::DeleteFakeEntry(Player* player, Item* item)
342+{
343+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::DeleteFakeEntry");
344+
345+ if (player->transmogMap.erase(item->GetGUID()) != 0)
346+ UpdateItem(player, item);
347+}
348+
349+void Transmogrification::SetFakeEntry(Player* player, Item* item, uint32 entry)
350+{
351+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::SetFakeEntry");
352+
353+ player->transmogMap[item->GetGUID()] = entry;
354+ UpdateItem(player, item);
355+}
356+
357+TransmogTrinityStrings Transmogrification::Transmogrify(Player* player, ObjectGuid itemGUID, uint8 slot, bool no_cost)
358+{
359+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify");
360+
361+ // slot of the transmogrified item
362+ if (slot >= EQUIPMENT_SLOT_END)
363+ {
364+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) tried to transmogrify an %s with a wrong slot (%u) when transmogrifying items.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemGUID.ToString().c_str(), slot);
365+ return LANG_ERR_TRANSMOG_INVALID_SLOT;
366+ }
367+
368+ Item* itemTransmogrifier = NULL;
369+ // guid of the transmogrifier item, if it's not 0
370+ if (!itemGUID.IsEmpty())
371+ {
372+ itemTransmogrifier = player->GetItemByGuid(itemGUID);
373+ if (!itemTransmogrifier)
374+ {
375+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) tried to transmogrify with an invalid %s.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemGUID.ToString().c_str());
376+ return LANG_ERR_TRANSMOG_MISSING_SRC_ITEM;
377+ }
378+ }
379+
380+ // transmogrified item
381+ Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
382+ if (!itemTransmogrified)
383+ {
384+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), slot);
385+ return LANG_ERR_TRANSMOG_MISSING_DEST_ITEM;
386+ }
387+
388+ if (!itemTransmogrifier) // reset look newEntry
389+ {
390+ DeleteFakeEntry(player, itemTransmogrified);
391+ }
392+ else
393+ {
394+ if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier->GetTemplate()))
395+ {
396+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
397+ return LANG_ERR_TRANSMOG_INVALID_ITEMS;
398+ }
399+
400+ if (!no_cost)
401+ {
402+ if (RequireToken)
403+ {
404+ if (player->HasItemCount(TokenEntry, TokenAmount))
405+ player->DestroyItemCount(TokenEntry, TokenAmount, true);
406+ else
407+ return LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS;
408+ }
409+
410+ int32 cost = 0;
411+ cost = GetSpecialPrice(itemTransmogrified->GetTemplate());
412+ cost *= ScaledCostModifier;
413+ cost += CopperCost;
414+
415+ if (cost) // 0 cost if reverting look
416+ {
417+ if (cost < 0)
418+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::Transmogrify - %s (%s) transmogrification invalid cost (non negative, amount %i). Transmogrified %u with %u", player->GetName().c_str(), player->GetGUID().ToString().c_str(), -cost, itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
419+ else
420+ {
421+ if (!player->HasEnoughMoney(cost))
422+ return LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY;
423+ player->ModifyMoney(-cost, false);
424+ }
425+ }
426+ }
427+
428+ SetFakeEntry(player, itemTransmogrified, itemTransmogrifier->GetEntry());
429+
430+ itemTransmogrified->UpdatePlayedTime(player);
431+
432+ itemTransmogrified->SetOwnerGUID(player->GetGUID());
433+ itemTransmogrified->SetNotRefundable(player);
434+ itemTransmogrified->ClearSoulboundTradeable(player);
435+
436+ if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE)
437+ itemTransmogrifier->SetBinding(true);
438+
439+ itemTransmogrifier->SetOwnerGUID(player->GetGUID());
440+ itemTransmogrifier->SetNotRefundable(player);
441+ itemTransmogrifier->ClearSoulboundTradeable(player);
442+ }
443+
444+ return LANG_ERR_TRANSMOG_OK;
445+}
446+
447+bool Transmogrification::CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* target, ItemTemplate const* source) const
448+{
449+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::CanTransmogrifyItemWithItem");
450+
451+ if (!target || !source)
452+ return false;
453+
454+ if (source->ItemId == target->ItemId)
455+ return false;
456+
457+ if (source->DisplayInfoID == target->DisplayInfoID)
458+ return false;
459+
460+ if (source->Class != target->Class)
461+ return false;
462+
463+ if (source->InventoryType == INVTYPE_BAG ||
464+ source->InventoryType == INVTYPE_RELIC ||
465+ // source->InventoryType == INVTYPE_BODY ||
466+ source->InventoryType == INVTYPE_FINGER ||
467+ source->InventoryType == INVTYPE_TRINKET ||
468+ source->InventoryType == INVTYPE_AMMO ||
469+ source->InventoryType == INVTYPE_QUIVER)
470+ return false;
471+
472+ if (target->InventoryType == INVTYPE_BAG ||
473+ target->InventoryType == INVTYPE_RELIC ||
474+ // target->InventoryType == INVTYPE_BODY ||
475+ target->InventoryType == INVTYPE_FINGER ||
476+ target->InventoryType == INVTYPE_TRINKET ||
477+ target->InventoryType == INVTYPE_AMMO ||
478+ target->InventoryType == INVTYPE_QUIVER)
479+ return false;
480+
481+ if (!SuitableForTransmogrification(player, target) || !SuitableForTransmogrification(player, source)) // if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified())
482+ return false;
483+
484+ if (IsRangedWeapon(source->Class, source->SubClass) != IsRangedWeapon(target->Class, target->SubClass))
485+ return false;
486+
487+ if (source->SubClass != target->SubClass && !IsRangedWeapon(target->Class, target->SubClass))
488+ {
489+ if (source->Class == ITEM_CLASS_ARMOR && !AllowMixedArmorTypes)
490+ return false;
491+ if (source->Class == ITEM_CLASS_WEAPON && !AllowMixedWeaponTypes)
492+ return false;
493+ }
494+
495+ if (source->InventoryType != target->InventoryType)
496+ {
497+ if (source->Class == ITEM_CLASS_WEAPON && !((IsRangedWeapon(target->Class, target->SubClass) ||
498+ ((target->InventoryType == INVTYPE_WEAPON || target->InventoryType == INVTYPE_2HWEAPON) &&
499+ (source->InventoryType == INVTYPE_WEAPON || source->InventoryType == INVTYPE_2HWEAPON)) ||
500+ ((target->InventoryType == INVTYPE_WEAPONMAINHAND || target->InventoryType == INVTYPE_WEAPONOFFHAND) &&
501+ (source->InventoryType == INVTYPE_WEAPON || source->InventoryType == INVTYPE_2HWEAPON)))))
502+ return false;
503+ if (source->Class == ITEM_CLASS_ARMOR &&
504+ !((source->InventoryType == INVTYPE_CHEST || source->InventoryType == INVTYPE_ROBE) &&
505+ (target->InventoryType == INVTYPE_CHEST || target->InventoryType == INVTYPE_ROBE)))
506+ return false;
507+ }
508+
509+ return true;
510+}
511+
512+bool Transmogrification::SuitableForTransmogrification(Player* player, ItemTemplate const* proto) const
513+{
514+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::SuitableForTransmogrification");
515+
516+ // ItemTemplate const* proto = item->GetTemplate();
517+ if (!player || !proto)
518+ return false;
519+
520+ if (proto->Class != ITEM_CLASS_ARMOR &&
521+ proto->Class != ITEM_CLASS_WEAPON)
522+ return false;
523+
524+ // Skip all checks for allowed items
525+ if (IsAllowed(proto->ItemId))
526+ return true;
527+
528+ if (IsNotAllowed(proto->ItemId))
529+ return false;
530+
531+ if (!AllowFishingPoles && proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
532+ return false;
533+
534+ if (!IsAllowedQuality(proto->Quality)) // (proto->Quality == ITEM_QUALITY_LEGENDARY)
535+ return false;
536+
537+ if (!IgnoreReqClass && (proto->AllowableClass & player->getClassMask()) == 0)
538+ return false;
539+
540+ if (!IgnoreReqRace && (proto->AllowableRace & player->getRaceMask()) == 0)
541+ return false;
542+
543+ if (!IgnoreReqSkill && proto->RequiredSkill != 0)
544+ {
545+ if (player->GetSkillValue(proto->RequiredSkill) == 0)
546+ return false;
547+ else if (player->GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
548+ return false;
549+ }
550+
551+ if (!IgnoreReqSpell && proto->RequiredSpell != 0 && !player->HasSpell(proto->RequiredSpell))
552+ return false;
553+
554+ if (!IgnoreReqLevel && player->getLevel() < proto->RequiredLevel)
555+ return false;
556+
557+ // If World Event is not active, prevent using event dependant items
558+ if (!IgnoreReqEvent && proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId))
559+ return false;
560+
561+ if (!IgnoreReqStats)
562+ {
563+ if (!proto->RandomProperty && !proto->RandomSuffix)
564+ {
565+ bool found = false;
566+ for (uint8 i = 0; i < proto->StatsCount; ++i)
567+ {
568+ if (proto->ItemStat[i].ItemStatValue != 0)
569+ {
570+ found = true;
571+ break;
572+ }
573+ }
574+ if (!found)
575+ return false;
576+ }
577+ }
578+
579+ return true;
580+}
581+
582+/*
583+bool Transmogrification::CanTransmogrify(Item const* item)
584+{
585+ItemTemplate const* proto = item->GetTemplate();
586+
587+if (!proto)
588+return false;
589+
590+if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG)
591+return false;
592+
593+if (proto->Quality == ITEM_QUALITY_LEGENDARY)
594+return false;
595+
596+if (proto->Class != ITEM_CLASS_ARMOR &&
597+proto->Class != ITEM_CLASS_WEAPON)
598+return false;
599+
600+if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
601+return false;
602+
603+if (proto->Flags2 & ITEM_FLAGS_EXTRA_CAN_TRANSMOG)
604+return true;
605+
606+if (item->GetItemRandomPropertyId() == 0)
607+return false;
608+
609+for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
610+if (proto->ItemStat[i].ItemStatValue != 0)
611+return true;
612+
613+return false;
614+}
615+bool Transmogrification::CanBeTransmogrified(Item const* item)
616+{
617+ItemTemplate const* proto = item->GetTemplate();
618+
619+if (!proto)
620+return false;
621+
622+if (proto->Quality == ITEM_QUALITY_LEGENDARY)
623+return false;
624+
625+if (proto->Class != ITEM_CLASS_ARMOR &&
626+proto->Class != ITEM_CLASS_WEAPON)
627+return false;
628+
629+if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
630+return false;
631+
632+if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG)
633+return false;
634+
635+if (item->GetItemRandomPropertyId() == 0)
636+return false;
637+
638+for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
639+if (proto->ItemStat[i].ItemStatValue != 0)
640+return true;
641+
642+return false;
643+}
644+*/
645+
646+uint32 Transmogrification::GetSpecialPrice(ItemTemplate const* proto) const
647+{
648+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetSpecialPrice");
649+
650+ uint32 cost = proto->SellPrice < 10000 ? 10000 : proto->SellPrice;
651+ return cost;
652+}
653+
654+bool Transmogrification::IsRangedWeapon(uint32 Class, uint32 SubClass) const
655+{
656+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsRangedWeapon");
657+
658+ return Class == ITEM_CLASS_WEAPON && (
659+ SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
660+ SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
661+ SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW);
662+}
663+
664+bool Transmogrification::IsAllowed(uint32 entry) const
665+{
666+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsAllowed");
667+
668+ return Allowed.find(entry) != Allowed.end();
669+}
670+
671+bool Transmogrification::IsNotAllowed(uint32 entry) const
672+{
673+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsNotAllowed");
674+
675+ return NotAllowed.find(entry) != NotAllowed.end();
676+}
677+
678+bool Transmogrification::IsAllowedQuality(uint32 quality) const
679+{
680+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsAllowedQuality");
681+
682+ switch (quality)
683+ {
684+ case ITEM_QUALITY_POOR: return AllowPoor;
685+ case ITEM_QUALITY_NORMAL: return AllowCommon;
686+ case ITEM_QUALITY_UNCOMMON: return AllowUncommon;
687+ case ITEM_QUALITY_RARE: return AllowRare;
688+ case ITEM_QUALITY_EPIC: return AllowEpic;
689+ case ITEM_QUALITY_LEGENDARY: return AllowLegendary;
690+ case ITEM_QUALITY_ARTIFACT: return AllowArtifact;
691+ case ITEM_QUALITY_HEIRLOOM: return AllowHeirloom;
692+ default: return false;
693+ }
694+}
695+
696+void Transmogrification::LoadConfig(bool reload)
697+{
698+ TC_LOG_DEBUG("custom.transmog", "Transmogrification::LoadConfig");
699+
700+#ifdef PRESETS
701+ EnableSetInfo = sConfigMgr->GetBoolDefault("Transmogrification.EnableSetInfo", true);
702+ SetNpcText = uint32(sConfigMgr->GetIntDefault("Transmogrification.SetNpcText", 65001));
703+
704+ EnableSets = sConfigMgr->GetBoolDefault("Transmogrification.EnableSets", true);
705+ MaxSets = (uint8)sConfigMgr->GetIntDefault("Transmogrification.MaxSets", 10);
706+ SetCostModifier = sConfigMgr->GetFloatDefault("Transmogrification.SetCostModifier", 3.0f);
707+ SetCopperCost = sConfigMgr->GetIntDefault("Transmogrification.SetCopperCost", 0);
708+
709+ if (MaxSets > MAX_OPTIONS)
710+ MaxSets = MAX_OPTIONS;
711+
712+ if (reload) // dont store presets for nothing
713+ {
714+ // this should be thread safe as long as LoadConfig is triggered on thread safe env
715+ SessionMap const& sessions = sWorld->GetAllSessions();
716+ for (SessionMap::const_iterator it = sessions.begin(); it != sessions.end(); ++it)
717+ {
718+ if (Player* player = it->second->GetPlayer())
719+ {
720+ // skipping session check
721+ if (EnableSets)
722+ LoadPlayerSets(player);
723+ }
724+ }
725+ }
726+#endif
727+
728+ EnableTransmogInfo = sConfigMgr->GetBoolDefault("Transmogrification.EnableTransmogInfo", true);
729+ TransmogNpcText = uint32(sConfigMgr->GetIntDefault("Transmogrification.TransmogNpcText", 65000));
730+
731+ std::istringstream issAllowed(sConfigMgr->GetStringDefault("Transmogrification.Allowed", ""));
732+ std::istringstream issNotAllowed(sConfigMgr->GetStringDefault("Transmogrification.NotAllowed", ""));
733+ while (issAllowed.good())
734+ {
735+ uint32 entry;
736+ issAllowed >> entry;
737+ if (issAllowed.fail())
738+ break;
739+ Allowed.insert(entry);
740+ }
741+ while (issNotAllowed.good())
742+ {
743+ uint32 entry;
744+ issNotAllowed >> entry;
745+ if (issNotAllowed.fail())
746+ break;
747+ NotAllowed.insert(entry);
748+ }
749+
750+ ScaledCostModifier = sConfigMgr->GetFloatDefault("Transmogrification.ScaledCostModifier", 1.0f);
751+ CopperCost = sConfigMgr->GetIntDefault("Transmogrification.CopperCost", 0);
752+
753+ RequireToken = sConfigMgr->GetBoolDefault("Transmogrification.RequireToken", false);
754+ TokenEntry = uint32(sConfigMgr->GetIntDefault("Transmogrification.TokenEntry", 49426));
755+ TokenAmount = uint32(sConfigMgr->GetIntDefault("Transmogrification.TokenAmount", 1));
756+
757+ AllowPoor = sConfigMgr->GetBoolDefault("Transmogrification.AllowPoor", false);
758+ AllowCommon = sConfigMgr->GetBoolDefault("Transmogrification.AllowCommon", false);
759+ AllowUncommon = sConfigMgr->GetBoolDefault("Transmogrification.AllowUncommon", true);
760+ AllowRare = sConfigMgr->GetBoolDefault("Transmogrification.AllowRare", true);
761+ AllowEpic = sConfigMgr->GetBoolDefault("Transmogrification.AllowEpic", true);
762+ AllowLegendary = sConfigMgr->GetBoolDefault("Transmogrification.AllowLegendary", false);
763+ AllowArtifact = sConfigMgr->GetBoolDefault("Transmogrification.AllowArtifact", false);
764+ AllowHeirloom = sConfigMgr->GetBoolDefault("Transmogrification.AllowHeirloom", true);
765+
766+ AllowMixedArmorTypes = sConfigMgr->GetBoolDefault("Transmogrification.AllowMixedArmorTypes", false);
767+ AllowMixedWeaponTypes = sConfigMgr->GetBoolDefault("Transmogrification.AllowMixedWeaponTypes", false);
768+ AllowFishingPoles = sConfigMgr->GetBoolDefault("Transmogrification.AllowFishingPoles", false);
769+
770+ IgnoreReqRace = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqRace", false);
771+ IgnoreReqClass = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqClass", false);
772+ IgnoreReqSkill = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqSkill", false);
773+ IgnoreReqSpell = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqSpell", false);
774+ IgnoreReqLevel = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqLevel", false);
775+ IgnoreReqEvent = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqEvent", false);
776+ IgnoreReqStats = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqStats", false);
777+
778+ if (!sObjectMgr->GetItemTemplate(TokenEntry))
779+ {
780+ TC_LOG_INFO("custom.transmog", "Transmogrification.TokenEntry (%u) does not exist. Using default (%u).", TokenEntry, 49426);
781+ TokenEntry = 49426;
782+ }
783+}
784+
785+std::vector<ObjectGuid> Transmogrification::GetItemList(const Player* player) const
786+{
787+ std::vector<ObjectGuid> itemlist;
788+
789+ // Copy paste from Player::GetItemByGuid(guid)
790+
791+ for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
792+ if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
793+ itemlist.push_back(pItem->GetGUID());
794+
795+ for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
796+ if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
797+ itemlist.push_back(pItem->GetGUID());
798+
799+ for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
800+ if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
801+ itemlist.push_back(pItem->GetGUID());
802+
803+ for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
804+ if (Bag* pBag = player->GetBagByPos(i))
805+ for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
806+ if (Item* pItem = pBag->GetItemByPos(j))
807+ itemlist.push_back(pItem->GetGUID());
808+
809+ for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
810+ if (Bag* pBag = player->GetBagByPos(i))
811+ for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
812+ if (Item* pItem = pBag->GetItemByPos(j))
813+ itemlist.push_back(pItem->GetGUID());
814+
815+ return itemlist;
816+}
817diff --git a/src/server/game/Entities/Item/Transmogrification.h b/src/server/game/Entities/Item/Transmogrification.h
818new file mode 100644
819index 0000000..21acc75
820--- /dev/null
821+++ b/src/server/game/Entities/Item/Transmogrification.h
822@@ -0,0 +1,124 @@
823+#ifndef DEF_TRANSMOGRIFICATION_H
824+#define DEF_TRANSMOGRIFICATION_H
825+
826+#include <vector>
827+#include "Define.h"
828+#include "ObjectGuid.h"
829+
830+#define PRESETS // comment this line to disable preset feature totally
831+#define MAX_OPTIONS 25 // do not alter
832+
833+class Item;
834+class Player;
835+class WorldSession;
836+struct ItemTemplate;
837+
838+enum TransmogTrinityStrings // Language.h might have same entries, appears when executing SQL, change if needed
839+{
840+ LANG_ERR_TRANSMOG_OK = 11100, // change this
841+ LANG_ERR_TRANSMOG_INVALID_SLOT,
842+ LANG_ERR_TRANSMOG_INVALID_SRC_ENTRY,
843+ LANG_ERR_TRANSMOG_MISSING_SRC_ITEM,
844+ LANG_ERR_TRANSMOG_MISSING_DEST_ITEM,
845+ LANG_ERR_TRANSMOG_INVALID_ITEMS,
846+ LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY,
847+ LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS,
848+
849+ LANG_ERR_UNTRANSMOG_OK,
850+ LANG_ERR_UNTRANSMOG_NO_TRANSMOGS,
851+
852+#ifdef PRESETS
853+ LANG_PRESET_ERR_INVALID_NAME,
854+#endif
855+};
856+
857+class TC_GAME_API Transmogrification
858+{
859+private:
860+ Transmogrification() { };
861+ ~Transmogrification() { };
862+ Transmogrification(const Transmogrification&);
863+ Transmogrification& operator=(const Transmogrification&);
864+
865+public:
866+ static Transmogrification* instance();
867+
868+#ifdef PRESETS
869+
870+ bool EnableSetInfo;
871+ uint32 SetNpcText;
872+
873+ bool EnableSets;
874+ uint8 MaxSets;
875+ float SetCostModifier;
876+ int32 SetCopperCost;
877+
878+ void LoadPlayerSets(Player* player);
879+
880+ void PresetTransmog(Player* player, Item* itemTransmogrified, uint32 fakeEntry, uint8 slot);
881+#endif
882+
883+ bool EnableTransmogInfo;
884+ uint32 TransmogNpcText;
885+
886+ // Use IsAllowed() and IsNotAllowed()
887+ // these are thread unsafe, but assumed to be static data so it should be safe
888+ std::set<uint32> Allowed;
889+ std::set<uint32> NotAllowed;
890+
891+ float ScaledCostModifier;
892+ int32 CopperCost;
893+
894+ bool RequireToken;
895+ uint32 TokenEntry;
896+ uint32 TokenAmount;
897+
898+ bool AllowPoor;
899+ bool AllowCommon;
900+ bool AllowUncommon;
901+ bool AllowRare;
902+ bool AllowEpic;
903+ bool AllowLegendary;
904+ bool AllowArtifact;
905+ bool AllowHeirloom;
906+
907+ bool AllowMixedArmorTypes;
908+ bool AllowMixedWeaponTypes;
909+ bool AllowFishingPoles;
910+
911+ bool IgnoreReqRace;
912+ bool IgnoreReqClass;
913+ bool IgnoreReqSkill;
914+ bool IgnoreReqSpell;
915+ bool IgnoreReqLevel;
916+ bool IgnoreReqEvent;
917+ bool IgnoreReqStats;
918+
919+ bool IsAllowed(uint32 entry) const;
920+ bool IsNotAllowed(uint32 entry) const;
921+ bool IsAllowedQuality(uint32 quality) const;
922+ bool IsRangedWeapon(uint32 Class, uint32 SubClass) const;
923+
924+ void LoadConfig(bool reload); // thread unsafe
925+
926+ std::string GetItemIcon(uint32 entry, uint32 width, uint32 height, int x, int y) const;
927+ std::string GetSlotIcon(uint8 slot, uint32 width, uint32 height, int x, int y) const;
928+ const char * GetSlotName(uint8 slot, WorldSession* session) const;
929+ std::string GetItemLink(Item* item, WorldSession* session) const;
930+ std::string GetItemLink(uint32 entry, WorldSession* session) const;
931+ uint32 GetFakeEntry(const Item* item);
932+ void UpdateItem(Player* player, Item* item) const;
933+ void DeleteFakeEntry(Player* player, Item* item);
934+ void SetFakeEntry(Player* player, Item* item, uint32 entry);
935+
936+ TransmogTrinityStrings Transmogrify(Player* player, ObjectGuid itemGUID, uint8 slot, bool no_cost = false);
937+ bool CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* destination, ItemTemplate const* source) const;
938+ bool SuitableForTransmogrification(Player* player, ItemTemplate const* proto) const;
939+ // bool CanBeTransmogrified(Item const* item);
940+ // bool CanTransmogrify(Item const* item);
941+ uint32 GetSpecialPrice(ItemTemplate const* proto) const;
942+ std::vector<ObjectGuid> GetItemList(const Player* player) const;
943+};
944+#define sTransmogrification Transmogrification::instance()
945+
946+#endif
947diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
948index a1e44cd..0d524a2 100644
949--- a/src/server/game/Entities/Player/Player.cpp
950+++ b/src/server/game/Entities/Player/Player.cpp
951@@ -16,6 +16,7 @@
952 * with this program. If not, see <http://www.gnu.org/licenses/>.
953 */
954
955+#include "Transmogrification.h"
956 #include "Player.h"
957 #include "AccountMgr.h"
958 #include "AchievementMgr.h"
959@@ -12096,7 +12097,10 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem)
960 {
961 if (pItem)
962 {
963- SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
964+ if (uint32 entry = sTransmogrification->GetFakeEntry(pItem))
965+ SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), entry);
966+ else
967+ SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
968 SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
969 SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT));
970 }
971@@ -12226,6 +12230,7 @@ void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
972 {
973 if (Item* it = GetItemByPos(bag, slot))
974 {
975+ sTransmogrification->DeleteFakeEntry(this, it);
976 ItemRemovedQuestCheck(it->GetEntry(), it->GetCount());
977 RemoveItem(bag, slot, update);
978 it->SetNotRefundable(this, false);
979diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
980index 256deef..0c65de7 100644
981--- a/src/server/game/Entities/Player/Player.h
982+++ b/src/server/game/Entities/Player/Player.h
983@@ -29,6 +29,7 @@
984 #include "SpellMgr.h"
985 #include "SpellHistory.h"
986 #include "Unit.h"
987+#include "Transmogrification.h"
988 #include "TradeData.h"
989 #include "CinematicMgr.h"
990
991@@ -129,6 +130,18 @@ struct SpellModifier
992 Aura* const ownerAura;
993 };
994
995+typedef std::unordered_map<ObjectGuid, uint32> TransmogMapType;
996+
997+#ifdef PRESETS
998+typedef std::map<uint8, uint32> PresetslotMapType;
999+struct PresetData
1000+{
1001+ std::string name;
1002+ PresetslotMapType slotMap; // slotMap[slotId] = entry
1003+};
1004+typedef std::map<uint8, PresetData> PresetMapType;
1005+#endif
1006+
1007 typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
1008 typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
1009 typedef std::unordered_set<SpellModifier*> SpellModContainer;
1010@@ -2280,6 +2293,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
1011 std::string GetMapAreaAndZoneString() const;
1012 std::string GetCoordsMapAreaAndZoneString() const;
1013
1014+ TransmogMapType transmogMap; // transmogMap[iGUID] = entry
1015+#ifdef PRESETS
1016+ PresetMapType presetMap; // presetMap[presetId] = presetData
1017+#endif
1018+
1019 protected:
1020 // Gamemaster whisper whitelist
1021 GuidList WhisperList;
1022diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
1023index 728fda8..5da2b30 100644
1024--- a/src/server/game/Handlers/SpellHandler.cpp
1025+++ b/src/server/game/Handlers/SpellHandler.cpp
1026@@ -26,6 +26,7 @@
1027 #include "Opcodes.h"
1028 #include "Spell.h"
1029 #include "Totem.h"
1030+#include "Transmogrification.h"
1031 #include "ScriptMgr.h"
1032 #include "GameObjectAI.h"
1033 #include "SpellAuraEffects.h"
1034@@ -625,7 +626,12 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData)
1035 else if (*itr == EQUIPMENT_SLOT_BACK && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
1036 data << uint32(0);
1037 else if (Item const* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr))
1038- data << uint32(item->GetTemplate()->DisplayInfoID);
1039+ {
1040+ if (uint32 entry = sTransmogrification->GetFakeEntry(item))
1041+ data << uint32(sObjectMgr->GetItemTemplate(entry)->DisplayInfoID);
1042+ else
1043+ data << uint32(item->GetTemplate()->DisplayInfoID);
1044+ }
1045 else
1046 data << uint32(0);
1047 }
1048diff --git a/src/server/scripts/Custom/Transmog/CHANGELOG.md b/src/server/scripts/Custom/Transmog/CHANGELOG.md
1049new file mode 100644
1050index 0000000..5903bf0
1051--- /dev/null
1052+++ b/src/server/scripts/Custom/Transmog/CHANGELOG.md
1053@@ -0,0 +1,126 @@
1054+####6.1
1055+- Update to newest TC
1056+- Made guid changes
1057+
1058+####6.0
1059+- Removed mutex locks - Different code style, works with ACE and boost, probably more efficient
1060+- Added regex checking for preset name
1061+- Fixed random properties not registering as item stats (Thanks Aokromes)
1062+- Made the code / patch compatible with herbs+veins patch (Thanks Aokromes)
1063+- Moved to bithub - Allows autogenerate patch and diff and management is easier:
1064+- https://github.com/Rochet2/TrinityCore/tree/transmog
1065+- Gist was at: https://gist.github.com/Rochet2/2c8765b53f8dda1e296a
1066+
1067+####5.6
1068+- Fixed few linux compile warnings
1069+- Moved to GIST
1070+- Old versions etc still available from:
1071+https://drive.google.com/folderview?id=0Bx5knS2IsjatTlVtWHRwbUN3VlE&usp=sharing
1072+
1073+####5.5
1074+- Updated to latest TC rev
1075+- Fixed some tabs to spaces
1076+- Fixed a warning on gcc
1077+
1078+####5.4
1079+- Updated to latest TC rev
1080+
1081+####5.3
1082+- Rewrote transmogrification logic to be blizzlike.
1083+- Implemented multithread support.
1084+- Tweaked saving to work so that your data is saved whenever the player is saved.
1085+- This means that crashes can not be abused and DB wont have SQL executing and querying all the time.
1086+
1087+####5.2
1088+- Some logic fixes and other
1089+
1090+####5.1
1091+- Config options should now work properly. Please notify here if some still bug
1092+- Can transmog bows with guns and crossbows
1093+- Can transmog cloth to leather with config settings set
1094+- Can transmog robes with chest pieces
1095+- You should now be able to view the info menus with the new NPC
1096+- Allow shirt's to be transmogrified (were shown in menu but you weren't able to before)
1097+- Mirror image (mage spell) should now correctly copy the transmogrified outfit. Before it still got your old item displays.
1098+- Added new config options:
1099+
1100+####5.0
1101+- Ripped cata branch functions and thus altered how everything is coded pretty much.
1102+- Dropped translation support
1103+- Added colored item links as well as icons all over the place
1104+- Added new feature: Sets
1105+- Added many config options, for example to allow cloth and plate to be transmogrified with each other
1106+
1107+####4.0
1108+- I changed all the methods to normal functions and moved them to Transmogrification.cpp
1109+- I also updated the way transmogrifications are stored
1110+
1111+####3.9
1112+- Nothing was added
1113+- Now supporting latest TDB: 0d3554d4bf
1114+- Also tested and works on latest
1115+- Changed diff to patch for better compability
1116+
1117+####3.8
1118+- Nothing was added
1119+- Now supporting latest TDB: da9865b683
1120+
1121+####3.7
1122+- Quick update to the patch for latest trinitycore version
1123+
1124+####3.6
1125+- Updated the code to work with the new trinitycore changes
1126+- Added config (See the bottom of worldserver.conf)
1127+- Added token cost possibility -- in config
1128+- Added cost modification possibility -- in config
1129+- Added quality requirement modification possibility -- in config
1130+
1131+####3.5
1132+- Fixed a crash on item deletion from guild deleting and more
1133+
1134+####3.4
1135+- Added localization possibilities, even though I am not quite sure if it works and if it is good or good enough. Only tested that english works
1136+- Added possibility to disable gold cost before compiling
1137+- Cleaned all the code I could find to TrinityCore standards .. I think
1138+
1139+####3.3
1140+- Transformed the script into a full coremod instead of having some code in the gossip script. This allows the transmogrification methods to be used on any item anywhere.
1141+- Changed the way fake display entries are stored in the core. Instead of having a new variable for the item class, I am now having a contained, much like locales have.
1142+- Changed the files into one patch file like Aokromes suggested. You can find the DB table creation SQLs from sql/characters_transmogrification/
1143+- Removed prepared statements
1144+- Fake display entries are now loaded when the server starts up. All nonexistant item guids will be deleted before loading and when loading, all invalid item entries are deleted (deleted some custom items aye?
1145+
1146+####3.2
1147+- Fixed an issue with DB saving not taking action on login or server restart.
1148+
1149+####3.1
1150+- Corrected the quality check, which was left to return true in any case
1151+- Fixed invisible item entries from newly created items (.additem for example)
1152+
1153+####3.0
1154+- It will have mailing and auction etc restrictions properly coded (yay, no more Fake owner!)
1155+- Having its own prepared statement now
1156+- Moved loading transmogs to the item loading part.
1157+- The script should now be added to scriptloader by the patch. So you just need to add it to solution.
1158+- Included an NPC sql for everyone with NPC problems :3
1159+
1160+####2.2
1161+- Added a few sounds, altered to use switch instead of an IF block
1162+- Modified to have a separate table
1163+- And more?
1164+
1165+####2.1
1166+- Fixed a crash when getting item template of item entry 0
1167+
1168+####2.0
1169+- Possibly more ..
1170+- Implemented cost
1171+- Changed quality checks
1172+- Fixed few problems
1173+- Changed some messages for more blizzlike feeling
1174+- After trying to transmogrify or remove a transmogrification, you get to the item selection screen instead of main menu
1175+- Added Remove Transmogrification buttons and update main menu button (removed nevermind)
1176+- Added more checks for safety and blizzlike feeling
1177+
1178+####1.0
1179+- Added DB saving and remove transmogrifications option -> patch, sql and script needed
1180\ No newline at end of file
1181diff --git a/src/server/scripts/Custom/Transmog/README.md b/src/server/scripts/Custom/Transmog/README.md
1182new file mode 100644
1183index 0000000..f7f1588
1184--- /dev/null
1185+++ b/src/server/scripts/Custom/Transmog/README.md
1186@@ -0,0 +1,53 @@
1187+#Transmogrification [](https://travis-ci.org/Rochet2/TrinityCore)
1188+
1189+####About
1190+Transmogrification allows you to change the display of an item to something else.
1191+You can use any item in your bags as source of display, as long as it fits the requirements.
1192+Requirements can be tweaked in the server configuration file.
1193+Basically any item should work with transmogrification. Custom items as well. No item is hardcoded to the system.
1194+Has a feature to store sets of displays. This can be removed before compiling or in the configuration file.
1195+Made for 3.3.5a.<br />
1196+Source: http://rochet2.github.io/Transmogrification.html
1197+
1198+Video: https://youtu.be/xtH4ogz12iM
1199+
1200+####Installation
1201+
1202+Available as:
1203+- Direct merge: https://github.com/Rochet2/TrinityCore/tree/transmog
1204+- Diff: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...transmog.diff
1205+- Diff in github view: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...transmog
1206+
1207+Using direct merge:
1208+- open git bash to source location
1209+- do `git remote add rochet2 https://github.com/Rochet2/TrinityCore.git`
1210+- do `git pull rochet2 transmog`
1211+- use cmake and compile
1212+
1213+Using diff:
1214+- DO NOT COPY THE DIFF DIRECTLY! It causes apply to fail.
1215+- download the diff by __right clicking__ the link and select __Save link as__
1216+- place the downloaded `transmog.diff` to the source root folder
1217+- open git bash to source location
1218+- do `git apply transmog.diff`
1219+- use cmake and compile
1220+
1221+After compiling:
1222+- Navigate to `\src\server\scripts\Custom\Transmog\sql\`
1223+- Run `characters.sql` to your characters database
1224+- Run `world_texts.sql` to your world database
1225+ - optionally you can also insert a transmogrifier NPC to your database by running `world_NPC.sql` to your world database.
1226+- Change the settings to your liking in `worldserver.conf` (Note that you should copy over the new config created)
1227+
1228+####Usage
1229+Equip an item that is suitable for transmogrification.
1230+Have an item in your bags that is suitable to be used to transmogrify the equipped item
1231+Talk to Transmogrifier and select the item slot. Then select the item you want to transmogrify to.
1232+Click to proceed when prompted and your items are transmogrified.
1233+Currently the default settings are according to this: http://wowwiki.wikia.com/Transmogrification#Current_rules
1234+Tweak the settings if you need in worldserver.conf
1235+
1236+####Changelog: [Changelog](https://github.com/Rochet2/TrinityCore/blob/transmog/src/server/scripts/Custom/Transmog/CHANGELOG.md)
1237+
1238+####Bugs and Contact
1239+Report issues and similar to https://rochet2.github.io/
1240diff --git a/src/server/scripts/Custom/Transmog/Transmogrifier.cpp b/src/server/scripts/Custom/Transmog/Transmogrifier.cpp
1241new file mode 100644
1242index 0000000..fb30109
1243--- /dev/null
1244+++ b/src/server/scripts/Custom/Transmog/Transmogrifier.cpp
1245@@ -0,0 +1,541 @@
1246+/*
1247+6.1
1248+Transmogrification 3.3.5a - Gossip menu
1249+By Rochet2
1250+
1251+ScriptName for NPC:
1252+Creature_Transmogrify
1253+
1254+TODO:
1255+Fix the cost formula
1256+-- Too much data handling, use default costs
1257+
1258+Cant transmogrify rediculus items // Foereaper: would be fun to stab people with a fish
1259+-- Cant think of any good way to handle this easily, could rip flagged items from cata DB
1260+*/
1261+
1262+#include "Transmogrification.h"
1263+#include "Bag.h"
1264+#include "Common.h"
1265+#include "Config.h"
1266+#include "Creature.h"
1267+#include "DatabaseEnv.h"
1268+#include "DBCStructure.h"
1269+#include "Define.h"
1270+#include "Field.h"
1271+#include "GameEventMgr.h"
1272+#include "GossipDef.h"
1273+#include "Item.h"
1274+#include "ItemPrototype.h"
1275+#include "Language.h"
1276+#include "Log.h"
1277+#include "Player.h"
1278+#include "ObjectGuid.h"
1279+#include "ObjectMgr.h"
1280+#include "QueryResult.h"
1281+#include "ScriptedGossip.h"
1282+#include "ScriptMgr.h"
1283+#include "SharedDefines.h"
1284+#include "Transaction.h"
1285+#include "WorldSession.h"
1286+#include <sstream>
1287+#include <string>
1288+
1289+#define GTS session->GetTrinityString
1290+
1291+namespace
1292+{
1293+ class CS_Transmogrification : public CreatureScript
1294+ {
1295+ public:
1296+ CS_Transmogrification() : CreatureScript("Creature_Transmogrify") { }
1297+
1298+ bool OnGossipHello(Player* player, Creature* creature) override
1299+ {
1300+ WorldSession* session = player->GetSession();
1301+ if (sTransmogrification->EnableTransmogInfo)
1302+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Book_11:30:30:-18:0|tHow transmogrification works", EQUIPMENT_SLOT_END + 9, 0);
1303+ for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
1304+ {
1305+ if (const char* slotName = sTransmogrification->GetSlotName(slot, session))
1306+ {
1307+ Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
1308+ uint32 entry = newItem ? sTransmogrification->GetFakeEntry(newItem) : 0;
1309+ std::string icon = entry ? sTransmogrification->GetItemIcon(entry, 30, 30, -18, 0) : sTransmogrification->GetSlotIcon(slot, 30, 30, -18, 0);
1310+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, icon + std::string(slotName), EQUIPMENT_SLOT_END, slot);
1311+ }
1312+ }
1313+#ifdef PRESETS
1314+ if (sTransmogrification->EnableSets)
1315+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/RAIDFRAME/UI-RAIDFRAME-MAINASSIST:30:30:-18:0|tManage sets", EQUIPMENT_SLOT_END + 4, 0);
1316+#endif
1317+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Enchant_Disenchant:30:30:-18:0|tRemove all transmogrifications", EQUIPMENT_SLOT_END + 2, 0, "Remove transmogrifications from all equipped items?", 0, false);
1318+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", EQUIPMENT_SLOT_END + 1, 0);
1319+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
1320+ return true;
1321+ }
1322+
1323+ bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
1324+ {
1325+ player->PlayerTalkClass->ClearMenus();
1326+ WorldSession* session = player->GetSession();
1327+ switch (sender)
1328+ {
1329+ case EQUIPMENT_SLOT_END: // Show items you can use
1330+ ShowTransmogItems(player, creature, action);
1331+ break;
1332+ case EQUIPMENT_SLOT_END + 1: // Main menu
1333+ OnGossipHello(player, creature);
1334+ break;
1335+ case EQUIPMENT_SLOT_END + 2: // Remove Transmogrifications
1336+ {
1337+ bool removed = false;
1338+ for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
1339+ {
1340+ if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
1341+ {
1342+ if (!sTransmogrification->GetFakeEntry(newItem))
1343+ continue;
1344+ sTransmogrification->DeleteFakeEntry(player, newItem);
1345+ removed = true;
1346+ }
1347+ }
1348+ if (removed)
1349+ session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_UNTRANSMOG_OK));
1350+ else
1351+ session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
1352+ OnGossipHello(player, creature);
1353+ } break;
1354+ case EQUIPMENT_SLOT_END + 3: // Remove Transmogrification from single item
1355+ {
1356+ if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
1357+ {
1358+ if (sTransmogrification->GetFakeEntry(newItem))
1359+ {
1360+ sTransmogrification->DeleteFakeEntry(player, newItem);
1361+ session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_UNTRANSMOG_OK));
1362+ }
1363+ else
1364+ session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
1365+ }
1366+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, action);
1367+ } break;
1368+#ifdef PRESETS
1369+ case EQUIPMENT_SLOT_END + 4: // Presets menu
1370+ {
1371+ if (!sTransmogrification->EnableSets)
1372+ {
1373+ OnGossipHello(player, creature);
1374+ return true;
1375+ }
1376+ if (sTransmogrification->EnableSetInfo)
1377+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Book_11:30:30:-18:0|tHow sets work", EQUIPMENT_SLOT_END + 10, 0);
1378+
1379+ if (!player->presetMap.empty())
1380+ {
1381+ for (PresetMapType::const_iterator it = player->presetMap.begin(); it != player->presetMap.end(); ++it)
1382+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Statue_02:30:30:-18:0|t" + it->second.name, EQUIPMENT_SLOT_END + 6, it->first);
1383+
1384+ if (player->presetMap.size() < sTransmogrification->MaxSets)
1385+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", EQUIPMENT_SLOT_END + 8, 0);
1386+ }
1387+ else
1388+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", EQUIPMENT_SLOT_END + 8, 0);
1389+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
1390+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
1391+ } break;
1392+ case EQUIPMENT_SLOT_END + 5: // Use preset
1393+ {
1394+ if (!sTransmogrification->EnableSets)
1395+ {
1396+ OnGossipHello(player, creature);
1397+ return true;
1398+ }
1399+ // action = presetID
1400+
1401+ PresetMapType::const_iterator it = player->presetMap.find(action);
1402+ if (it != player->presetMap.end())
1403+ {
1404+ for (PresetslotMapType::const_iterator it2 = it->second.slotMap.begin(); it2 != it->second.slotMap.end(); ++it2)
1405+ if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, it2->first))
1406+ sTransmogrification->PresetTransmog(player, item, it2->second, it2->first);
1407+ }
1408+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 6, action);
1409+ } break;
1410+ case EQUIPMENT_SLOT_END + 6: // view preset
1411+ {
1412+ if (!sTransmogrification->EnableSets)
1413+ {
1414+ OnGossipHello(player, creature);
1415+ return true;
1416+ }
1417+ // action = presetID
1418+
1419+ PresetMapType::const_iterator it = player->presetMap.find(action);
1420+ if (it == player->presetMap.end())
1421+ {
1422+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
1423+ return true;
1424+ }
1425+
1426+ for (PresetslotMapType::const_iterator it2 = it->second.slotMap.begin(); it2 != it->second.slotMap.end(); ++it2)
1427+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, sTransmogrification->GetItemIcon(it2->second, 30, 30, -18, 0) + sTransmogrification->GetItemLink(it2->second, session), sender, action);
1428+
1429+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Misc_Statue_02:30:30:-18:0|tUse set", EQUIPMENT_SLOT_END + 5, action, "Using this set for transmogrify will bind transmogrified items to you and make them non-refundable and non-tradeable.\nDo you wish to continue?\n\n" + it->second.name, 0, false);
1430+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-LeaveItem-Opaque:30:30:-18:0|tDelete set", EQUIPMENT_SLOT_END + 7, action, "Are you sure you want to delete " + it->second.name + "?", 0, false);
1431+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
1432+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
1433+ } break;
1434+ case EQUIPMENT_SLOT_END + 7: // Delete preset
1435+ {
1436+ if (!sTransmogrification->EnableSets)
1437+ {
1438+ OnGossipHello(player, creature);
1439+ return true;
1440+ }
1441+ // action = presetID
1442+
1443+ player->presetMap.erase(action);
1444+
1445+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
1446+ } break;
1447+ case EQUIPMENT_SLOT_END + 8: // Save preset
1448+ {
1449+ if (!sTransmogrification->EnableSets)
1450+ {
1451+ OnGossipHello(player, creature);
1452+ return true;
1453+ }
1454+
1455+ if (player->presetMap.size() >= sTransmogrification->MaxSets)
1456+ {
1457+ OnGossipHello(player, creature);
1458+ return true;
1459+ }
1460+
1461+ uint32 cost = 0;
1462+ bool canSave = false;
1463+ for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
1464+ {
1465+ if (!sTransmogrification->GetSlotName(slot, session))
1466+ continue;
1467+ if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
1468+ {
1469+ uint32 entry = sTransmogrification->GetFakeEntry(newItem);
1470+ if (!entry)
1471+ continue;
1472+ const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
1473+ if (!temp)
1474+ continue;
1475+ if (!sTransmogrification->SuitableForTransmogrification(player, temp)) // no need to check?
1476+ continue;
1477+ cost += sTransmogrification->GetSpecialPrice(temp);
1478+ canSave = true;
1479+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, sTransmogrification->GetItemIcon(entry, 30, 30, -18, 0) + sTransmogrification->GetItemLink(entry, session), EQUIPMENT_SLOT_END + 8, 0);
1480+ }
1481+ }
1482+ if (canSave)
1483+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", 0, 0, "Insert set name", cost*sTransmogrification->SetCostModifier + sTransmogrification->SetCopperCost, true);
1484+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", sender, action);
1485+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
1486+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
1487+ } break;
1488+ case EQUIPMENT_SLOT_END + 10: // Set info
1489+ {
1490+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
1491+ player->SEND_GOSSIP_MENU(sTransmogrification->SetNpcText, creature->GetGUID());
1492+ } break;
1493+#endif
1494+ case EQUIPMENT_SLOT_END + 9: // Transmog info
1495+ {
1496+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
1497+ player->SEND_GOSSIP_MENU(sTransmogrification->TransmogNpcText, creature->GetGUID());
1498+ } break;
1499+ default: // Transmogrify
1500+ {
1501+ if (!sender && !action)
1502+ {
1503+ OnGossipHello(player, creature);
1504+ return true;
1505+ }
1506+ // sender = slot, action = display
1507+ TransmogTrinityStrings res = sTransmogrification->Transmogrify(player, ObjectGuid(HighGuid::Item, 0, action), sender);
1508+ if (res == LANG_ERR_TRANSMOG_OK)
1509+ session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_TRANSMOG_OK));
1510+ else
1511+ session->SendNotification(res);
1512+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, sender);
1513+ } break;
1514+ }
1515+ return true;
1516+ }
1517+
1518+#ifdef PRESETS
1519+ bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) override
1520+ {
1521+ player->PlayerTalkClass->ClearMenus();
1522+ if (sender || action)
1523+ return true; // should never happen
1524+ if (!sTransmogrification->EnableSets)
1525+ {
1526+ OnGossipHello(player, creature);
1527+ return true;
1528+ }
1529+
1530+ // Allow only alnum
1531+ std::string name = code;
1532+ static const char* allowedcharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz _.,'1234567890";
1533+ if (!name.length() || name.find_first_not_of(allowedcharacters) != std::string::npos)
1534+ {
1535+ player->GetSession()->SendNotification(LANG_PRESET_ERR_INVALID_NAME);
1536+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
1537+ return true;
1538+ }
1539+
1540+ int32 cost = 0;
1541+ PresetslotMapType items;
1542+ for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
1543+ {
1544+ if (!sTransmogrification->GetSlotName(slot, player->GetSession()))
1545+ continue;
1546+ if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
1547+ {
1548+ uint32 entry = sTransmogrification->GetFakeEntry(newItem);
1549+ if (!entry)
1550+ continue;
1551+ const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
1552+ if (!temp)
1553+ continue;
1554+ if (!sTransmogrification->SuitableForTransmogrification(player, temp))
1555+ continue;
1556+ cost += sTransmogrification->GetSpecialPrice(temp);
1557+ items[slot] = entry;
1558+ }
1559+ }
1560+
1561+ if (!items.empty())
1562+ {
1563+ // transmogrified items were found to be saved
1564+ cost *= sTransmogrification->SetCostModifier;
1565+ cost += sTransmogrification->SetCopperCost;
1566+
1567+ if (!player->HasEnoughMoney(cost))
1568+ {
1569+ player->GetSession()->SendNotification(LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY);
1570+ }
1571+ else
1572+ {
1573+ uint8 presetID = sTransmogrification->MaxSets;
1574+ if (player->presetMap.size() < sTransmogrification->MaxSets)
1575+ {
1576+ for (uint8 i = 0; i < sTransmogrification->MaxSets; ++i) // should never reach over max
1577+ {
1578+ if (player->presetMap.find(i) == player->presetMap.end())
1579+ {
1580+ presetID = i;
1581+ break;
1582+ }
1583+ }
1584+ }
1585+
1586+ if (presetID < sTransmogrification->MaxSets)
1587+ {
1588+ // Make sure code doesnt mess up SQL!
1589+ player->presetMap[presetID].name = name;
1590+ player->presetMap[presetID].slotMap = items;
1591+
1592+ if (cost)
1593+ player->ModifyMoney(-cost);
1594+ }
1595+ }
1596+ }
1597+
1598+ OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
1599+ return true;
1600+ }
1601+#endif
1602+
1603+ void ShowTransmogItems(Player* player, Creature* creature, uint8 slot) // Only checks bags while can use an item from anywhere in inventory
1604+ {
1605+ WorldSession* session = player->GetSession();
1606+ Item* oldItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
1607+ if (oldItem)
1608+ {
1609+ uint32 limit = 0;
1610+ uint32 price = sTransmogrification->GetSpecialPrice(oldItem->GetTemplate());
1611+ price *= sTransmogrification->ScaledCostModifier;
1612+ price += sTransmogrification->CopperCost;
1613+ std::ostringstream ss;
1614+ ss << std::endl;
1615+ if (sTransmogrification->RequireToken)
1616+ ss << std::endl << std::endl << sTransmogrification->TokenAmount << " x " << sTransmogrification->GetItemLink(sTransmogrification->TokenEntry, session);
1617+
1618+ for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
1619+ {
1620+ if (limit >= MAX_OPTIONS)
1621+ break;
1622+ Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
1623+ if (!newItem)
1624+ continue;
1625+ if (!sTransmogrification->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
1626+ continue;
1627+ if (sTransmogrification->GetFakeEntry(oldItem) == newItem->GetEntry())
1628+ continue;
1629+ ++limit;
1630+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, sTransmogrification->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sTransmogrification->GetItemLink(newItem, session), slot, newItem->GetGUID().GetCounter(), "Using this item for transmogrify will bind it to you and make it non-refundable and non-tradeable.\nDo you wish to continue?\n\n" + sTransmogrification->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sTransmogrification->GetItemLink(newItem, session) + ss.str(), price, false);
1631+ }
1632+
1633+ for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
1634+ {
1635+ Bag* bag = player->GetBagByPos(i);
1636+ if (!bag)
1637+ continue;
1638+ for (uint32 j = 0; j < bag->GetBagSize(); ++j)
1639+ {
1640+ if (limit >= MAX_OPTIONS)
1641+ break;
1642+ Item* newItem = player->GetItemByPos(i, j);
1643+ if (!newItem)
1644+ continue;
1645+ if (!sTransmogrification->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
1646+ continue;
1647+ if (sTransmogrification->GetFakeEntry(oldItem) == newItem->GetEntry())
1648+ continue;
1649+ ++limit;
1650+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, sTransmogrification->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sTransmogrification->GetItemLink(newItem, session), slot, newItem->GetGUID().GetCounter(), "Using this item for transmogrify will bind it to you and make it non-refundable and non-tradeable.\nDo you wish to continue?\n\n" + sTransmogrification->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sTransmogrification->GetItemLink(newItem, session) + ss.str(), price, false);
1651+ }
1652+ }
1653+ }
1654+
1655+ player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Enchant_Disenchant:30:30:-18:0|tRemove transmogrification", EQUIPMENT_SLOT_END + 3, slot, "Remove transmogrification from the slot?", 0, false);
1656+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", EQUIPMENT_SLOT_END, slot);
1657+ player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
1658+ player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
1659+ }
1660+ };
1661+}
1662+
1663+namespace
1664+{
1665+ class PS_Transmogrification : public PlayerScript
1666+ {
1667+ public:
1668+ PS_Transmogrification() : PlayerScript("PS_Transmogrification") { }
1669+
1670+ void OnSave(Player* player) override
1671+ {
1672+ uint32 lowguid = player->GetGUID().GetCounter();
1673+ SQLTransaction trans = CharacterDatabase.BeginTransaction();
1674+ trans->PAppend("DELETE FROM `custom_transmogrification` WHERE `Owner` = %u", lowguid);
1675+#ifdef PRESETS
1676+ trans->PAppend("DELETE FROM `custom_transmogrification_sets` WHERE `Owner` = %u", lowguid);
1677+#endif
1678+
1679+ if (!player->transmogMap.empty())
1680+ {
1681+ // Only save items that are in inventory / bank / etc
1682+ std::vector<ObjectGuid> items = sTransmogrification->GetItemList(player);
1683+ for (std::vector<ObjectGuid>::const_iterator it = items.begin(); it != items.end(); ++it)
1684+ {
1685+ TransmogMapType::const_iterator it2 = player->transmogMap.find(*it);
1686+ if (it2 == player->transmogMap.end())
1687+ continue;
1688+
1689+ trans->PAppend("REPLACE INTO custom_transmogrification (GUID, FakeEntry, Owner) VALUES (%u, %u, %u)", it2->first.GetCounter(), it2->second, lowguid);
1690+ }
1691+ }
1692+
1693+#ifdef PRESETS
1694+ if (!player->presetMap.empty())
1695+ {
1696+ for (PresetMapType::const_iterator it = player->presetMap.begin(); it != player->presetMap.end(); ++it)
1697+ {
1698+ std::ostringstream ss;
1699+ for (PresetslotMapType::const_iterator it2 = it->second.slotMap.begin(); it2 != it->second.slotMap.end(); ++it2)
1700+ ss << uint32(it2->first) << ' ' << it2->second << ' ';
1701+ trans->PAppend("REPLACE INTO `custom_transmogrification_sets` (`Owner`, `PresetID`, `SetName`, `SetData`) VALUES (%u, %u, \"%s\", \"%s\")", lowguid, uint32(it->first), it->second.name.c_str(), ss.str().c_str());
1702+ }
1703+ }
1704+#endif
1705+
1706+ if (trans->GetSize()) // basically never false
1707+ CharacterDatabase.CommitTransaction(trans);
1708+ }
1709+
1710+ void OnLogin(Player* player, bool /*firstLogin*/) override
1711+ {
1712+ QueryResult result = CharacterDatabase.PQuery("SELECT GUID, FakeEntry FROM custom_transmogrification WHERE Owner = %u", player->GetGUID().GetCounter());
1713+
1714+ if (result)
1715+ {
1716+ do
1717+ {
1718+ Field* field = result->Fetch();
1719+ ObjectGuid itemGUID(HighGuid::Item, 0, field[0].GetUInt32());
1720+ uint32 fakeEntry = field[1].GetUInt32();
1721+ // Only load items that are in inventory / bank / etc
1722+ if (sObjectMgr->GetItemTemplate(fakeEntry) && player->GetItemByGuid(itemGUID))
1723+ {
1724+ player->transmogMap[itemGUID] = fakeEntry;
1725+ }
1726+ else
1727+ {
1728+ // Ignore, will be erased on next save.
1729+ // Additionally this can happen if an item was deleted from DB but still exists for the player
1730+ // TC_LOG_ERROR("custom.transmog", "Item entry (Entry: %u, itemGUID: %u, playerGUID: %u) does not exist, ignoring.", fakeEntry, GUID_LOPART(itemGUID), player->GetGUID().GetCounter());
1731+ // CharacterDatabase.PExecute("DELETE FROM custom_transmogrification WHERE FakeEntry = %u", fakeEntry);
1732+ }
1733+ } while (result->NextRow());
1734+
1735+ if (!player->transmogMap.empty())
1736+ {
1737+ for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
1738+ {
1739+ if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
1740+ {
1741+ player->SetVisibleItemSlot(slot, item);
1742+ if (player->IsInWorld())
1743+ item->SendUpdateToPlayer(player);
1744+ }
1745+ }
1746+ }
1747+ }
1748+
1749+#ifdef PRESETS
1750+ if (sTransmogrification->EnableSets)
1751+ sTransmogrification->LoadPlayerSets(player);
1752+#endif
1753+ }
1754+ };
1755+
1756+ class WS_Transmogrification : public WorldScript
1757+ {
1758+ public:
1759+ WS_Transmogrification() : WorldScript("WS_Transmogrification") { }
1760+
1761+ void OnConfigLoad(bool reload) override
1762+ {
1763+ sTransmogrification->LoadConfig(reload);
1764+ }
1765+
1766+ void OnStartup() override
1767+ {
1768+ TC_LOG_INFO("custom.transmog", "Deleting non-existing transmogrification entries...");
1769+ CharacterDatabase.DirectExecute("DELETE FROM custom_transmogrification WHERE NOT EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_transmogrification.GUID)");
1770+
1771+#ifdef PRESETS
1772+ // Clean even if disabled
1773+ // Dont delete even if player has more presets than should
1774+ CharacterDatabase.DirectExecute("DELETE FROM `custom_transmogrification_sets` WHERE NOT EXISTS(SELECT 1 FROM characters WHERE characters.guid = custom_transmogrification_sets.Owner)");
1775+#endif
1776+ sTransmogrification->LoadConfig(false);
1777+ }
1778+ };
1779+}
1780+
1781+void AddSC_Transmogrification()
1782+{
1783+ new WS_Transmogrification();
1784+ new PS_Transmogrification();
1785+ new CS_Transmogrification();
1786+}
1787diff --git a/src/server/scripts/Custom/Transmog/sql/characters.sql b/src/server/scripts/Custom/Transmog/sql/characters.sql
1788new file mode 100644
1789index 0000000..4529815
1790--- /dev/null
1791+++ b/src/server/scripts/Custom/Transmog/sql/characters.sql
1792@@ -0,0 +1,37 @@
1793+-- --------------------------------------------------------
1794+-- Host: localhost
1795+-- Server version: 5.5.39 - MySQL Community Server (GPL)
1796+-- Server OS: Win32
1797+-- HeidiSQL Version: 9.1.0.4894
1798+-- --------------------------------------------------------
1799+
1800+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
1801+/*!40101 SET NAMES utf8mb4 */;
1802+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
1803+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
1804+
1805+-- Dumping structure for table tc_c.custom_transmogrification
1806+CREATE TABLE IF NOT EXISTS `custom_transmogrification` (
1807+ `GUID` int(10) unsigned NOT NULL COMMENT 'Item guidLow',
1808+ `FakeEntry` int(10) unsigned NOT NULL COMMENT 'Item entry',
1809+ `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidLow',
1810+ PRIMARY KEY (`GUID`),
1811+ KEY `Owner` (`Owner`)
1812+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_2';
1813+
1814+-- Data exporting was unselected.
1815+
1816+
1817+-- Dumping structure for table tc_c.custom_transmogrification_sets
1818+CREATE TABLE IF NOT EXISTS `custom_transmogrification_sets` (
1819+ `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidlow',
1820+ `PresetID` tinyint(3) unsigned NOT NULL COMMENT 'Preset identifier',
1821+ `SetName` text COMMENT 'SetName',
1822+ `SetData` text COMMENT 'Slot1 Entry1 Slot2 Entry2',
1823+ PRIMARY KEY (`Owner`,`PresetID`)
1824+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_1';
1825+
1826+-- Data exporting was unselected.
1827+/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
1828+/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
1829+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
1830diff --git a/src/server/scripts/Custom/Transmog/sql/updates/2016_07_15_00_world.sql b/src/server/scripts/Custom/Transmog/sql/updates/2016_07_15_00_world.sql
1831new file mode 100644
1832index 0000000..9603089
1833--- /dev/null
1834+++ b/src/server/scripts/Custom/Transmog/sql/updates/2016_07_15_00_world.sql
1835@@ -0,0 +1,4 @@
1836+SET @TEXT_ID := 65000;
1837+INSERT INTO `npc_text` (`ID`, `text0_0`) VALUES
1838+(@TEXT_ID, 'Transmogrification allows you to change how your items look like without changing the stats of the items.\r\nItems used in transmogrification are no longer refundable, tradeable and are bound to you.\r\nUpdating a menu updates the view and prices.\r\n\r\nNot everything can be transmogrified with eachother.\r\nRestrictions include but are not limited to:\r\nOnly armor and weapons can be transmogrified\r\nGuns, bows and crossbows can be transmogrified with eachother\r\nFishing poles can not be transmogrified\r\nYou must be able to equip both items used in the process.\r\n\r\nTransmogrifications stay on your items as long as you own them.\r\nIf you try to put the item in guild bank or mail it to someone else, the transmogrification is stripped.\r\n\r\nYou can also remove transmogrifications for free at the transmogrifier.'),
1839+(@TEXT_ID+1, 'You can save your own transmogrification sets.\r\n\r\nTo save, first you must transmogrify your equipped items.\r\nThen when you go to the set management menu and go to save set menu,\r\nall items you have transmogrified are displayed so you see what you are saving.\r\nIf you think the set is fine, you can click to save the set and name it as you wish.\r\n\r\nTo use a set you can click the saved set in the set management menu and then select use set.\r\nIf the set has a transmogrification for an item that is already transmogrified, the old transmogrification is lost.\r\nNote that same transmogrification restrictions apply when trying to use a set as in normal transmogrification.\r\n\r\nTo delete a set you can go to the set\'s menu and select delete set.');
1840diff --git a/src/server/scripts/Custom/Transmog/sql/updates/_README.md b/src/server/scripts/Custom/Transmog/sql/updates/_README.md
1841new file mode 100644
1842index 0000000..2632510
1843--- /dev/null
1844+++ b/src/server/scripts/Custom/Transmog/sql/updates/_README.md
1845@@ -0,0 +1 @@
1846+DO NOT RUN THE UPDATES WHEN MAKING A CLEAN INSTALL
1847diff --git a/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_1_to_2_2.sql b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_1_to_2_2.sql
1848new file mode 100644
1849index 0000000..86c6947
1850--- /dev/null
1851+++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_1_to_2_2.sql
1852@@ -0,0 +1,12 @@
1853+CREATE TABLE IF NOT EXISTS `custom_transmogrification` (
1854+ `GUID` INT(10) UNSIGNED NOT NULL DEFAULT '0',
1855+ `FakeOwner` INT(10) UNSIGNED NOT NULL DEFAULT '0',
1856+ `FakeEntry` INT(10) UNSIGNED NOT NULL DEFAULT '0'
1857+)
1858+COLLATE='latin1_swedish_ci'
1859+ENGINE=InnoDB;
1860+
1861+REPLACE INTO custom_transmogrification (GUID, FakeOwner, FakeEntry) SELECT guid, FakeOwner, FakeEntry FROM item_instance WHERE FakeOwner != 0 AND FakeEntry != 0;
1862+ALTER TABLE `item_instance`
1863+ DROP COLUMN `FakeEntry`,
1864+ DROP COLUMN `FakeOwner`;
1865diff --git a/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_2_to_3_0.sql b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_2_to_3_0.sql
1866new file mode 100644
1867index 0000000..1508a68
1868--- /dev/null
1869+++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_2_to_3_0.sql
1870@@ -0,0 +1,2 @@
1871+ALTER TABLE `custom_transmogrification`
1872+ DROP COLUMN `FakeOwner`;
1873diff --git a/src/server/scripts/Custom/Transmog/sql/updates/characters_update_4_x_to_5_0.sql b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_4_x_to_5_0.sql
1874new file mode 100644
1875index 0000000..89c91ac
1876--- /dev/null
1877+++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_4_x_to_5_0.sql
1878@@ -0,0 +1,16 @@
1879+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
1880+/*!40101 SET NAMES utf8 */;
1881+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
1882+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
1883+
1884+CREATE TABLE `custom_transmogrification_sets` (
1885+ `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidlow',
1886+ `PresetID` tinyint(3) unsigned NOT NULL COMMENT 'Preset identifier',
1887+ `SetName` text COMMENT 'SetName',
1888+ `SetData` text COMMENT 'Slot1 Entry1 Slot2 Entry2',
1889+ PRIMARY KEY (`Owner`,`PresetID`)
1890+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1891+
1892+/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
1893+/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
1894+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
1895diff --git a/src/server/scripts/Custom/Transmog/sql/updates/characters_update_5_x_to_6_1.sql b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_5_x_to_6_1.sql
1896new file mode 100644
1897index 0000000..817de91
1898--- /dev/null
1899+++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_5_x_to_6_1.sql
1900@@ -0,0 +1,6 @@
1901+ALTER TABLE `custom_transmogrification`
1902+ COMMENT='6_1',
1903+ ADD INDEX `Owner` (`Owner`);
1904+
1905+ALTER TABLE `custom_transmogrification_sets`
1906+ COMMENT='6_1';
1907diff --git a/src/server/scripts/Custom/Transmog/sql/updates/characters_update_6_1_to_6_2.sql b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_6_1_to_6_2.sql
1908new file mode 100644
1909index 0000000..0e675b5
1910--- /dev/null
1911+++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_6_1_to_6_2.sql
1912@@ -0,0 +1,3 @@
1913+ALTER TABLE `custom_transmogrification`
1914+ COMMENT='6_2',
1915+ COLLATE='utf8_general_ci';
1916diff --git a/src/server/scripts/Custom/Transmog/sql/updates/world_update_3_5_to_3_6.sql b/src/server/scripts/Custom/Transmog/sql/updates/world_update_3_5_to_3_6.sql
1917new file mode 100644
1918index 0000000..03cc6d2
1919--- /dev/null
1920+++ b/src/server/scripts/Custom/Transmog/sql/updates/world_update_3_5_to_3_6.sql
1921@@ -0,0 +1 @@
1922+REPLACE INTO `trinity_string` (`entry`, `content_default`, `content_loc1`, `content_loc2`, `content_loc3`, `content_loc4`, `content_loc5`, `content_loc6`, `content_loc7`, `content_loc8`) VALUES (11129, 'You don\'t have enough %ss', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
1923diff --git a/src/server/scripts/Custom/Transmog/sql/updates/world_update_4_x_to_5_0.sql b/src/server/scripts/Custom/Transmog/sql/updates/world_update_4_x_to_5_0.sql
1924new file mode 100644
1925index 0000000..8723683
1926--- /dev/null
1927+++ b/src/server/scripts/Custom/Transmog/sql/updates/world_update_4_x_to_5_0.sql
1928@@ -0,0 +1,27 @@
1929+DELETE FROM `trinity_string` WHERE `entry` BETWEEN 11100 AND 11129;
1930+
1931+SET @TEXT_ID := 50000;
1932+INSERT INTO `npc_text` (`ID`, `text0_0`, `WDBVerified`) VALUES
1933+(@TEXT_ID, 'Transmogrification allows you to change how your items look like without changing the stats of the items.\r\nItems used in transmogrification are no longer refundable, tradeable and are bound to you.\r\nUpdating a menu updates the view and prices.\r\n\r\nNot everything can be transmogrified with eachother.\r\nRestrictions include but are not limited to:\r\nOnly armor and weapons can be transmogrified\r\nGuns, bows and crossbows can be transmogrified with eachother\r\nFishing poles can not be transmogrified\r\nYou must be able to equip both items used in the process.\r\n\r\nTransmogrifications stay on your items as long as you own them.\r\nIf you try to put the item in guild bank or mail it to someone else, the transmogrification is stripped.\r\n\r\nYou can also remove transmogrifications for free at the transmogrifier.', 1),
1934+(@TEXT_ID+1, 'You can save your own transmogrification sets.\r\n\r\nTo save, first you must transmogrify your equipped items.\r\nThen when you go to the set management menu and go to save set menu,\r\nall items you have transmogrified are displayed so you see what you are saving.\r\nIf you think the set is fine, you can click to save the set and name it as you wish.\r\n\r\nTo use a set you can click the saved set in the set management menu and then select use set.\r\nIf the set has a transmogrification for an item that is already transmogrified, the old transmogrification is lost.\r\nNote that same transmogrification restrictions apply when trying to use a set as in normal transmogrification.\r\n\r\nTo delete a set you can go to the set\'s menu and select delete set.', 1);
1935+
1936+SET @STRING_ENTRY := 11100;
1937+INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
1938+(@STRING_ENTRY+0, 'Item transmogrified'),
1939+(@STRING_ENTRY+1, 'Equipment slot is empty'),
1940+(@STRING_ENTRY+2, 'Invalid source item selected'),
1941+(@STRING_ENTRY+3, 'Source item does not exist'),
1942+(@STRING_ENTRY+4, 'Destination item does not exist'),
1943+(@STRING_ENTRY+5, 'Selected items are invalid'),
1944+(@STRING_ENTRY+6, 'Not enough money'),
1945+(@STRING_ENTRY+7, 'You don\'t have enough tokens'),
1946+(@STRING_ENTRY+8, 'Transmogrifications removed'),
1947+(@STRING_ENTRY+9, 'There are no transmogrifications'),
1948+(@STRING_ENTRY+10, 'Invalid name inserted');
1949+
1950+SET
1951+@Entry = 190010,
1952+@Name = "Warpweaver";
1953+
1954+REPLACE INTO `creature_template` (`entry`, `modelid1`, `modelid2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction_A`, `faction_H`, `npcflag`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Armor_mod`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified`) VALUES
1955+(@Entry, 19646, 0, @Name, "Transmogrifier", NULL, 0, 80, 80, 2, 35, 35, 1, 1, 0, 500, 500, 0, 350, 1, 2000, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, '', 0, 3, 1, 1, 1, 1, 0, 0, 1, 0, 0, 'Creature_Transmogrify', 0);
1956diff --git a/src/server/scripts/Custom/Transmog/sql/updates/world_update_5_0_to_5_1.sql b/src/server/scripts/Custom/Transmog/sql/updates/world_update_5_0_to_5_1.sql
1957new file mode 100644
1958index 0000000..2a5e854
1959--- /dev/null
1960+++ b/src/server/scripts/Custom/Transmog/sql/updates/world_update_5_0_to_5_1.sql
1961@@ -0,0 +1,6 @@
1962+SET
1963+@Entry = 190010,
1964+@Name = "Warpweaver";
1965+
1966+REPLACE INTO `creature_template` (`entry`, `modelid1`, `modelid2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction_A`, `faction_H`, `npcflag`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Armor_mod`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified`) VALUES
1967+(@Entry, 19646, 0, @Name, "Transmogrifier", NULL, 0, 80, 80, 2, 35, 35, 1, 1, 0, 500, 500, 0, 350, 1, 2000, 0, 1, 0, 0, 0, 0, 7, 138936390, 0, 0, 0, '', 0, 3, 1, 1, 1, 1, 0, 0, 1, 0, 0, 'Creature_Transmogrify', 0);
1968diff --git a/src/server/scripts/Custom/Transmog/sql/world_NPC.sql b/src/server/scripts/Custom/Transmog/sql/world_NPC.sql
1969new file mode 100644
1970index 0000000..de1597e
1971--- /dev/null
1972+++ b/src/server/scripts/Custom/Transmog/sql/world_NPC.sql
1973@@ -0,0 +1,6 @@
1974+SET
1975+@Entry = 190010,
1976+@Name = "Warpweaver";
1977+
1978+INSERT INTO `creature_template` (`entry`, `modelid1`, `modelid2`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `faction`, `npcflag`, `scale`, `rank`, `dmgschool`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `type`, `type_flags`, `lootid`, `pickpocketloot`, `skinloot`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `RacialLeader`, `movementId`, `RegenHealth`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`) VALUES
1979+(@Entry, 19646, 0, @Name, "Transmogrifier", NULL, 0, 80, 80, 2, 35, 1, 1, 0, 0, 2000, 0, 1, 0, 7, 138936390, 0, 0, 0, '', 0, 3, 1, 0, 0, 1, 0, 0, 'Creature_Transmogrify');
1980diff --git a/src/server/scripts/Custom/Transmog/sql/world_texts.sql b/src/server/scripts/Custom/Transmog/sql/world_texts.sql
1981new file mode 100644
1982index 0000000..87713f5
1983--- /dev/null
1984+++ b/src/server/scripts/Custom/Transmog/sql/world_texts.sql
1985@@ -0,0 +1,18 @@
1986+SET @TEXT_ID := 65000;
1987+INSERT INTO `npc_text` (`ID`, `text0_0`) VALUES
1988+(@TEXT_ID, 'Transmogrification allows you to change how your items look like without changing the stats of the items.\r\nItems used in transmogrification are no longer refundable, tradeable and are bound to you.\r\nUpdating a menu updates the view and prices.\r\n\r\nNot everything can be transmogrified with eachother.\r\nRestrictions include but are not limited to:\r\nOnly armor and weapons can be transmogrified\r\nGuns, bows and crossbows can be transmogrified with eachother\r\nFishing poles can not be transmogrified\r\nYou must be able to equip both items used in the process.\r\n\r\nTransmogrifications stay on your items as long as you own them.\r\nIf you try to put the item in guild bank or mail it to someone else, the transmogrification is stripped.\r\n\r\nYou can also remove transmogrifications for free at the transmogrifier.'),
1989+(@TEXT_ID+1, 'You can save your own transmogrification sets.\r\n\r\nTo save, first you must transmogrify your equipped items.\r\nThen when you go to the set management menu and go to save set menu,\r\nall items you have transmogrified are displayed so you see what you are saving.\r\nIf you think the set is fine, you can click to save the set and name it as you wish.\r\n\r\nTo use a set you can click the saved set in the set management menu and then select use set.\r\nIf the set has a transmogrification for an item that is already transmogrified, the old transmogrification is lost.\r\nNote that same transmogrification restrictions apply when trying to use a set as in normal transmogrification.\r\n\r\nTo delete a set you can go to the set\'s menu and select delete set.');
1990+
1991+SET @STRING_ENTRY := 11100;
1992+INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
1993+(@STRING_ENTRY+0, 'Item transmogrified'),
1994+(@STRING_ENTRY+1, 'Equipment slot is empty'),
1995+(@STRING_ENTRY+2, 'Invalid source item selected'),
1996+(@STRING_ENTRY+3, 'Source item does not exist'),
1997+(@STRING_ENTRY+4, 'Destination item does not exist'),
1998+(@STRING_ENTRY+5, 'Selected items are invalid'),
1999+(@STRING_ENTRY+6, 'Not enough money'),
2000+(@STRING_ENTRY+7, 'You don\'t have enough tokens'),
2001+(@STRING_ENTRY+8, 'Transmogrifications removed'),
2002+(@STRING_ENTRY+9, 'There are no transmogrifications'),
2003+(@STRING_ENTRY+10, 'Invalid name inserted');
2004diff --git a/src/server/scripts/Custom/custom_script_loader.cpp b/src/server/scripts/Custom/custom_script_loader.cpp
2005index dd4b5e9..26f8383 100644
2006--- a/src/server/scripts/Custom/custom_script_loader.cpp
2007+++ b/src/server/scripts/Custom/custom_script_loader.cpp
2008@@ -16,10 +16,12 @@
2009 */
2010
2011 // This is where scripts' loading functions should be declared:
2012+void AddSC_Transmogrification();
2013
2014
2015 // The name of this function should match:
2016 // void Add${NameOfDirectory}Scripts()
2017 void AddCustomScripts()
2018 {
2019+ AddSC_Transmogrification();
2020 }
2021diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
2022index d0fcd108..1e79761 100644
2023--- a/src/server/scripts/Spells/spell_generic.cpp
2024+++ b/src/server/scripts/Spells/spell_generic.cpp
2025@@ -38,6 +38,7 @@
2026 #include "SpellScript.h"
2027 #include "SpellAuraEffects.h"
2028 #include "Vehicle.h"
2029+#include "Transmogrification.h"
2030
2031 class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader
2032 {
2033@@ -917,7 +918,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
2034 if (Player* player = caster->ToPlayer())
2035 {
2036 if (Item* mainItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
2037- target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
2038+ {
2039+ if (uint32 entry = sTransmogrification->GetFakeEntry(mainItem))
2040+ target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, entry);
2041+ else
2042+ target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
2043+ }
2044 }
2045 else
2046 target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID));
2047@@ -931,7 +937,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
2048 if (Player* player = caster->ToPlayer())
2049 {
2050 if (Item* offItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
2051- target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, offItem->GetEntry());
2052+ {
2053+ if (uint32 entry = sTransmogrification->GetFakeEntry(offItem))
2054+ target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, entry);
2055+ else
2056+ target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, offItem->GetEntry());
2057+ }
2058 }
2059 else
2060 target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1));
2061@@ -944,7 +955,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
2062 if (Player* player = caster->ToPlayer())
2063 {
2064 if (Item* rangedItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
2065- target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, rangedItem->GetEntry());
2066+ {
2067+ if (uint32 entry = sTransmogrification->GetFakeEntry(rangedItem))
2068+ target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, entry);
2069+ else
2070+ target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, rangedItem->GetEntry());
2071+ }
2072 }
2073 else
2074 target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2));
2075diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
2076index 1d17305..f017bc0 100644
2077--- a/src/server/worldserver/worldserver.conf.dist
2078+++ b/src/server/worldserver/worldserver.conf.dist
2079@@ -3749,6 +3749,212 @@ PacketSpoof.BanDuration = 86400
2080 ###################################################################################################
2081
2082 ###################################################################################################
2083+# Transmogrification config
2084+###################################################################################################
2085+#
2086+# SETTINGS
2087+#
2088+# Logger.custom.transmog
2089+# Description: Transmogrification logging setting, see logger settings
2090+# Default: 3, Console Server
2091+#
2092+# Transmogrification.EnableTransmogInfo
2093+# Description: Enables / Disables the info button for transmogrification
2094+# Default: 1
2095+#
2096+# Transmogrification.TransmogNpcText
2097+# Description: The npc_text entry of the info menu for transmogrification
2098+# Default: 65000
2099+#
2100+# Transmogrification.Allowed
2101+# Description: A list of item entries that are allowed for transmogrification (skips quality and CanUseItem check)
2102+# Example: "25 35674 5623"
2103+# Default: ""
2104+#
2105+# Transmogrification.NotAllowed
2106+# Description: A list of item entries that are NOT allowed for transmogrification
2107+# Example: "25 35674 5623"
2108+# Default: ""
2109+
2110+Logger.custom.transmog = 3, Console Server
2111+
2112+Transmogrification.EnableTransmogInfo = 1
2113+Transmogrification.TransmogNpcText = 65000
2114+
2115+Transmogrification.Allowed = ""
2116+Transmogrification.NotAllowed = ""
2117+
2118+#
2119+# COPPER COST
2120+#
2121+# Transmogrification.ScaledCostModifier
2122+# Description: A multiplier for the default gold cost (change to 0 for no default cost)
2123+# Default: 1.0
2124+#
2125+# Transmogrification.CopperCost
2126+# Description: Cost added on top of other costs (can be negative)
2127+# Default: 0
2128+#
2129+# For custom gold cost set ScaledCostModifier to 0.0 and CopperCost to what ever cost you want
2130+
2131+Transmogrification.ScaledCostModifier = 1.0
2132+Transmogrification.CopperCost = 0
2133+
2134+#
2135+# TOKEN COST
2136+#
2137+# Transmogrification.RequireToken
2138+# Description: Adds/disables token cost
2139+# Default: 0
2140+#
2141+# Transmogrification.TokenEntry
2142+# Description: Entry of the token item
2143+# Default: 49426
2144+#
2145+# Transmogrification.TokenAmount
2146+# Description: Amount of tokens required
2147+# Default: 1
2148+
2149+Transmogrification.RequireToken = 0
2150+Transmogrification.TokenEntry = 49426
2151+Transmogrification.TokenAmount = 1
2152+
2153+#
2154+# REQUIREMENTS
2155+#
2156+# Transmogrification.AllowPoor
2157+# Description: Allow poor quality items to be used as source and target items
2158+# Default: 0
2159+#
2160+# Transmogrification.AllowCommon
2161+# Description: Allow common quality items to be used as source and target items
2162+# Default: 0
2163+#
2164+# Transmogrification.AllowUncommon
2165+# Description: Allow uncommon quality items to be used as source and target items
2166+# Default: 1
2167+#
2168+# Transmogrification.AllowRare
2169+# Description: Allow rare quality items to be used as source and target items
2170+# Default: 1
2171+#
2172+# Transmogrification.AllowEpic
2173+# Description: Allow epic quality items to be used as source and target items
2174+# Default: 1
2175+#
2176+# Transmogrification.AllowLegendary
2177+# Description: Allow legendary quality items to be used as source and target items
2178+# Default: 0
2179+#
2180+# Transmogrification.AllowArtifact
2181+# Description: Allow artifact quality items to be used as source and target items
2182+# Default: 0
2183+#
2184+# Transmogrification.AllowHeirloom
2185+# Description: Allow heirloom quality items to be used as source and target items
2186+# Default: 1
2187+#
2188+# Transmogrification.AllowMixedArmorTypes
2189+# Description: Allow cloth items to be transmogrified with plate for example
2190+# Default: 0
2191+#
2192+# Transmogrification.AllowMixedWeaponTypes
2193+# Description: Allow axe to be transmogrified with dagger for example
2194+# Default: 0
2195+#
2196+# Transmogrification.AllowFishingPoles
2197+# Description: Allow fishing poles to be transmogrified
2198+# Default: 0
2199+#
2200+# Transmogrification.IgnoreReqRace
2201+# Description: Ignore required race for source items
2202+# Default: 0
2203+#
2204+# Transmogrification.IgnoreReqClass
2205+# Description: Ignore required class for source items
2206+# Default: 0
2207+#
2208+# Transmogrification.IgnoreReqSkill
2209+# Description: Ignore required skill for source items
2210+# Default: 0
2211+#
2212+# Transmogrification.IgnoreReqSpell
2213+# Description: Ignore required spell for source items
2214+# Default: 0
2215+#
2216+# Transmogrification.IgnoreReqLevel
2217+# Description: Ignore required level for source items
2218+# Default: 0
2219+#
2220+# Transmogrification.IgnoreReqEvent
2221+# Description: Ignore required event for source items
2222+# Default: 0
2223+#
2224+# Transmogrification.IgnoreReqStats
2225+# Description: Ignore stat count > 0 requirement for source items
2226+# Default: 0
2227+
2228+Transmogrification.AllowPoor = 0
2229+Transmogrification.AllowCommon = 0
2230+Transmogrification.AllowUncommon = 1
2231+Transmogrification.AllowRare = 1
2232+Transmogrification.AllowEpic = 1
2233+Transmogrification.AllowLegendary = 0
2234+Transmogrification.AllowArtifact = 0
2235+Transmogrification.AllowHeirloom = 1
2236+
2237+Transmogrification.AllowMixedArmorTypes = 0
2238+Transmogrification.AllowMixedWeaponTypes = 0
2239+Transmogrification.AllowFishingPoles = 0
2240+
2241+Transmogrification.IgnoreReqRace = 0
2242+Transmogrification.IgnoreReqClass = 0
2243+Transmogrification.IgnoreReqSkill = 0
2244+Transmogrification.IgnoreReqSpell = 0
2245+Transmogrification.IgnoreReqLevel = 0
2246+Transmogrification.IgnoreReqEvent = 0
2247+Transmogrification.IgnoreReqStats = 0
2248+
2249+#
2250+# SET FEATURE
2251+#
2252+# Transmogrification.EnableSets
2253+# Description: Enables / Disables the set feature. If you want permanent disable, check Transmogrification.h
2254+# Default: 1
2255+#
2256+# Transmogrification.MaxSets
2257+# Description: Maximum amount of sets a player can save (hardcap at 25)
2258+# Default: 10
2259+#
2260+# Transmogrification.EnableSetInfo
2261+# Description: Enables / Disables the info button for set fature
2262+# Default: 1
2263+#
2264+# Transmogrification.SetNpcText
2265+# Description: The npc_text entry of the info menu for the set feature
2266+# Default: 65001
2267+#
2268+# Transmogrification.SetCostModifier
2269+# Description: A multiplier for the default gold cost (all costs summed together) (change to 0 for no default cost)
2270+# Default: 3.0
2271+#
2272+# Transmogrification.SetCopperCost
2273+# Description: Cost added on top of other costs (can be negative)
2274+# Default: 0
2275+
2276+Transmogrification.EnableSets = 1
2277+Transmogrification.MaxSets = 10
2278+
2279+Transmogrification.EnableSetInfo = 1
2280+Transmogrification.SetNpcText = 65001
2281+
2282+Transmogrification.SetCostModifier = 3.0
2283+Transmogrification.SetCopperCost = 0
2284+
2285+#
2286+###################################################################################################
2287+
2288+###################################################################################################
2289 # METRIC SETTINGS
2290 #
2291 # These settings control the statistics sent to the metric database (currently InfluxDB)