kusanagy

transmogrification

Dec 7th, 2016
438
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 107.47 KB | None | 0 0
  1. diff --git a/src/server/game/DataStores/DBCStores.cpp b/src/server/game/DataStores/DBCStores.cpp
  2. index 11fde04..8d559d9 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");
  23. diff --git a/src/server/game/DataStores/DBCStores.h b/src/server/game/DataStores/DBCStores.h
  24. index 360b0d2..677fab6 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;
  36. diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h
  37. index 4943a43..af5fb35 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
  49. diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h
  50. index 934e040..d21325e 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";
  62. diff --git a/src/server/game/Entities/Item/Transmogrification.cpp b/src/server/game/Entities/Item/Transmogrification.cpp
  63. new file mode 100644
  64. index 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 ((proto->Flags2 & ITEM_FLAG2_FACTION_HORDE) && player->GetTeam() != HORDE)
  538. +        //return false;
  539. +
  540. +    //if ((proto->Flags2 & ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeam() != ALLIANCE)
  541. +        //return false;
  542. +
  543. +    if (!IgnoreReqClass && (proto->AllowableClass & player->getClassMask()) == 0)
  544. +        return false;
  545. +
  546. +    if (!IgnoreReqRace && (proto->AllowableRace & player->getRaceMask()) == 0)
  547. +        return false;
  548. +
  549. +    if (!IgnoreReqSkill && proto->RequiredSkill != 0)
  550. +    {
  551. +        if (player->GetSkillValue(proto->RequiredSkill) == 0)
  552. +            return false;
  553. +        else if (player->GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
  554. +            return false;
  555. +    }
  556. +
  557. +    if (!IgnoreReqSpell && proto->RequiredSpell != 0 && !player->HasSpell(proto->RequiredSpell))
  558. +        return false;
  559. +
  560. +    if (!IgnoreReqLevel && player->getLevel() < proto->RequiredLevel)
  561. +        return false;
  562. +
  563. +    // If World Event is not active, prevent using event dependant items
  564. +    if (!IgnoreReqEvent && proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId))
  565. +        return false;
  566. +
  567. +    if (!IgnoreReqStats)
  568. +    {
  569. +        if (!proto->RandomProperty && !proto->RandomSuffix)
  570. +        {
  571. +            bool found = false;
  572. +            for (uint8 i = 0; i < proto->StatsCount; ++i)
  573. +            {
  574. +                if (proto->ItemStat[i].ItemStatValue != 0)
  575. +                {
  576. +                    found = true;
  577. +                    break;
  578. +                }
  579. +            }
  580. +            if (!found)
  581. +                return false;
  582. +        }
  583. +    }
  584. +
  585. +    return true;
  586. +}
  587. +
  588. +/*
  589. +bool Transmogrification::CanTransmogrify(Item const* item)
  590. +{
  591. +ItemTemplate const* proto = item->GetTemplate();
  592. +
  593. +if (!proto)
  594. +return false;
  595. +
  596. +if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_TRANSMOG)
  597. +return false;
  598. +
  599. +if (proto->Quality == ITEM_QUALITY_LEGENDARY)
  600. +return false;
  601. +
  602. +if (proto->Class != ITEM_CLASS_ARMOR &&
  603. +proto->Class != ITEM_CLASS_WEAPON)
  604. +return false;
  605. +
  606. +if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
  607. +return false;
  608. +
  609. +if (proto->Flags2 & ITEM_FLAGS_EXTRA_CAN_TRANSMOG)
  610. +return true;
  611. +
  612. +if (item->GetItemRandomPropertyId() == 0)
  613. +return false;
  614. +
  615. +for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
  616. +if (proto->ItemStat[i].ItemStatValue != 0)
  617. +return true;
  618. +
  619. +return false;
  620. +}
  621. +bool Transmogrification::CanBeTransmogrified(Item const* item)
  622. +{
  623. +ItemTemplate const* proto = item->GetTemplate();
  624. +
  625. +if (!proto)
  626. +return false;
  627. +
  628. +if (proto->Quality == ITEM_QUALITY_LEGENDARY)
  629. +return false;
  630. +
  631. +if (proto->Class != ITEM_CLASS_ARMOR &&
  632. +proto->Class != ITEM_CLASS_WEAPON)
  633. +return false;
  634. +
  635. +if (proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
  636. +return false;
  637. +
  638. +if (proto->Flags2 & ITEM_FLAGS_EXTRA_CANNOT_BE_TRANSMOG)
  639. +return false;
  640. +
  641. +if (item->GetItemRandomPropertyId() == 0)
  642. +return false;
  643. +
  644. +for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
  645. +if (proto->ItemStat[i].ItemStatValue != 0)
  646. +return true;
  647. +
  648. +return false;
  649. +}
  650. +*/
  651. +
  652. +uint32 Transmogrification::GetSpecialPrice(ItemTemplate const* proto) const
  653. +{
  654. +    TC_LOG_DEBUG("custom.transmog", "Transmogrification::GetSpecialPrice");
  655. +
  656. +    uint32 cost = proto->SellPrice < 10000 ? 10000 : proto->SellPrice;
  657. +    return cost;
  658. +}
  659. +
  660. +bool Transmogrification::IsRangedWeapon(uint32 Class, uint32 SubClass) const
  661. +{
  662. +    TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsRangedWeapon");
  663. +
  664. +    return Class == ITEM_CLASS_WEAPON && (
  665. +        SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
  666. +        SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
  667. +        SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW);
  668. +}
  669. +
  670. +bool Transmogrification::IsAllowed(uint32 entry) const
  671. +{
  672. +    TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsAllowed");
  673. +
  674. +    return Allowed.find(entry) != Allowed.end();
  675. +}
  676. +
  677. +bool Transmogrification::IsNotAllowed(uint32 entry) const
  678. +{
  679. +    TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsNotAllowed");
  680. +
  681. +    return NotAllowed.find(entry) != NotAllowed.end();
  682. +}
  683. +
  684. +bool Transmogrification::IsAllowedQuality(uint32 quality) const
  685. +{
  686. +    TC_LOG_DEBUG("custom.transmog", "Transmogrification::IsAllowedQuality");
  687. +
  688. +    switch (quality)
  689. +    {
  690. +        case ITEM_QUALITY_POOR: return AllowPoor;
  691. +        case ITEM_QUALITY_NORMAL: return AllowCommon;
  692. +        case ITEM_QUALITY_UNCOMMON: return AllowUncommon;
  693. +        case ITEM_QUALITY_RARE: return AllowRare;
  694. +        case ITEM_QUALITY_EPIC: return AllowEpic;
  695. +        case ITEM_QUALITY_LEGENDARY: return AllowLegendary;
  696. +        case ITEM_QUALITY_ARTIFACT: return AllowArtifact;
  697. +        case ITEM_QUALITY_HEIRLOOM: return AllowHeirloom;
  698. +        default: return false;
  699. +    }
  700. +}
  701. +
  702. +void Transmogrification::LoadConfig(bool reload)
  703. +{
  704. +    TC_LOG_DEBUG("custom.transmog", "Transmogrification::LoadConfig");
  705. +
  706. +#ifdef PRESETS
  707. +    EnableSetInfo = sConfigMgr->GetBoolDefault("Transmogrification.EnableSetInfo", true);
  708. +    SetNpcText = uint32(sConfigMgr->GetIntDefault("Transmogrification.SetNpcText", 65001));
  709. +
  710. +    EnableSets = sConfigMgr->GetBoolDefault("Transmogrification.EnableSets", true);
  711. +    MaxSets = (uint8)sConfigMgr->GetIntDefault("Transmogrification.MaxSets", 10);
  712. +    SetCostModifier = sConfigMgr->GetFloatDefault("Transmogrification.SetCostModifier", 3.0f);
  713. +    SetCopperCost = sConfigMgr->GetIntDefault("Transmogrification.SetCopperCost", 0);
  714. +
  715. +    if (MaxSets > MAX_OPTIONS)
  716. +        MaxSets = MAX_OPTIONS;
  717. +
  718. +    if (reload) // dont store presets for nothing
  719. +    {
  720. +        // this should be thread safe as long as LoadConfig is triggered on thread safe env
  721. +        SessionMap const& sessions = sWorld->GetAllSessions();
  722. +        for (SessionMap::const_iterator it = sessions.begin(); it != sessions.end(); ++it)
  723. +        {
  724. +            if (Player* player = it->second->GetPlayer())
  725. +            {
  726. +                // skipping session check
  727. +                if (EnableSets)
  728. +                    LoadPlayerSets(player);
  729. +            }
  730. +        }
  731. +    }
  732. +#endif
  733. +
  734. +    EnableTransmogInfo = sConfigMgr->GetBoolDefault("Transmogrification.EnableTransmogInfo", true);
  735. +    TransmogNpcText = uint32(sConfigMgr->GetIntDefault("Transmogrification.TransmogNpcText", 65000));
  736. +
  737. +    std::istringstream issAllowed(sConfigMgr->GetStringDefault("Transmogrification.Allowed", ""));
  738. +    std::istringstream issNotAllowed(sConfigMgr->GetStringDefault("Transmogrification.NotAllowed", ""));
  739. +    while (issAllowed.good())
  740. +    {
  741. +        uint32 entry;
  742. +        issAllowed >> entry;
  743. +        if (issAllowed.fail())
  744. +            break;
  745. +        Allowed.insert(entry);
  746. +    }
  747. +    while (issNotAllowed.good())
  748. +    {
  749. +        uint32 entry;
  750. +        issNotAllowed >> entry;
  751. +        if (issNotAllowed.fail())
  752. +            break;
  753. +        NotAllowed.insert(entry);
  754. +    }
  755. +
  756. +    ScaledCostModifier = sConfigMgr->GetFloatDefault("Transmogrification.ScaledCostModifier", 1.0f);
  757. +    CopperCost = sConfigMgr->GetIntDefault("Transmogrification.CopperCost", 0);
  758. +
  759. +    RequireToken = sConfigMgr->GetBoolDefault("Transmogrification.RequireToken", false);
  760. +    TokenEntry = uint32(sConfigMgr->GetIntDefault("Transmogrification.TokenEntry", 49426));
  761. +    TokenAmount = uint32(sConfigMgr->GetIntDefault("Transmogrification.TokenAmount", 1));
  762. +
  763. +    AllowPoor = sConfigMgr->GetBoolDefault("Transmogrification.AllowPoor", false);
  764. +    AllowCommon = sConfigMgr->GetBoolDefault("Transmogrification.AllowCommon", false);
  765. +    AllowUncommon = sConfigMgr->GetBoolDefault("Transmogrification.AllowUncommon", true);
  766. +    AllowRare = sConfigMgr->GetBoolDefault("Transmogrification.AllowRare", true);
  767. +    AllowEpic = sConfigMgr->GetBoolDefault("Transmogrification.AllowEpic", true);
  768. +    AllowLegendary = sConfigMgr->GetBoolDefault("Transmogrification.AllowLegendary", false);
  769. +    AllowArtifact = sConfigMgr->GetBoolDefault("Transmogrification.AllowArtifact", false);
  770. +    AllowHeirloom = sConfigMgr->GetBoolDefault("Transmogrification.AllowHeirloom", true);
  771. +
  772. +    AllowMixedArmorTypes = sConfigMgr->GetBoolDefault("Transmogrification.AllowMixedArmorTypes", false);
  773. +    AllowMixedWeaponTypes = sConfigMgr->GetBoolDefault("Transmogrification.AllowMixedWeaponTypes", false);
  774. +    AllowFishingPoles = sConfigMgr->GetBoolDefault("Transmogrification.AllowFishingPoles", false);
  775. +
  776. +    IgnoreReqRace = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqRace", false);
  777. +    IgnoreReqClass = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqClass", false);
  778. +    IgnoreReqSkill = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqSkill", false);
  779. +    IgnoreReqSpell = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqSpell", false);
  780. +    IgnoreReqLevel = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqLevel", false);
  781. +    IgnoreReqEvent = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqEvent", false);
  782. +    IgnoreReqStats = sConfigMgr->GetBoolDefault("Transmogrification.IgnoreReqStats", false);
  783. +
  784. +    if (!sObjectMgr->GetItemTemplate(TokenEntry))
  785. +    {
  786. +        TC_LOG_INFO("custom.transmog", "Transmogrification.TokenEntry (%u) does not exist. Using default (%u).", TokenEntry, 49426);
  787. +        TokenEntry = 49426;
  788. +    }
  789. +}
  790. +
  791. +std::vector<ObjectGuid> Transmogrification::GetItemList(const Player* player) const
  792. +{
  793. +    std::vector<ObjectGuid> itemlist;
  794. +
  795. +    // Copy paste from Player::GetItemByGuid(guid)
  796. +
  797. +    for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  798. +        if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  799. +            itemlist.push_back(pItem->GetGUID());
  800. +
  801. +    for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  802. +        if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  803. +            itemlist.push_back(pItem->GetGUID());
  804. +
  805. +    for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
  806. +        if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  807. +            itemlist.push_back(pItem->GetGUID());
  808. +
  809. +    for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_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. +    for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  816. +        if (Bag* pBag = player->GetBagByPos(i))
  817. +            for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  818. +                if (Item* pItem = pBag->GetItemByPos(j))
  819. +                    itemlist.push_back(pItem->GetGUID());
  820. +
  821. +    return itemlist;
  822. +}
  823. diff --git a/src/server/game/Entities/Item/Transmogrification.h b/src/server/game/Entities/Item/Transmogrification.h
  824. new file mode 100644
  825. index 0000000..21acc75
  826. --- /dev/null
  827. +++ b/src/server/game/Entities/Item/Transmogrification.h
  828. @@ -0,0 +1,124 @@
  829. +#ifndef DEF_TRANSMOGRIFICATION_H
  830. +#define DEF_TRANSMOGRIFICATION_H
  831. +
  832. +#include <vector>
  833. +#include "Define.h"
  834. +#include "ObjectGuid.h"
  835. +
  836. +#define PRESETS // comment this line to disable preset feature totally
  837. +#define MAX_OPTIONS 25 // do not alter
  838. +
  839. +class Item;
  840. +class Player;
  841. +class WorldSession;
  842. +struct ItemTemplate;
  843. +
  844. +enum TransmogTrinityStrings // Language.h might have same entries, appears when executing SQL, change if needed
  845. +{
  846. +    LANG_ERR_TRANSMOG_OK = 11100, // change this
  847. +    LANG_ERR_TRANSMOG_INVALID_SLOT,
  848. +    LANG_ERR_TRANSMOG_INVALID_SRC_ENTRY,
  849. +    LANG_ERR_TRANSMOG_MISSING_SRC_ITEM,
  850. +    LANG_ERR_TRANSMOG_MISSING_DEST_ITEM,
  851. +    LANG_ERR_TRANSMOG_INVALID_ITEMS,
  852. +    LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY,
  853. +    LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS,
  854. +
  855. +    LANG_ERR_UNTRANSMOG_OK,
  856. +    LANG_ERR_UNTRANSMOG_NO_TRANSMOGS,
  857. +
  858. +#ifdef PRESETS
  859. +    LANG_PRESET_ERR_INVALID_NAME,
  860. +#endif
  861. +};
  862. +
  863. +class TC_GAME_API Transmogrification
  864. +{
  865. +private:
  866. +    Transmogrification() { };
  867. +    ~Transmogrification() { };
  868. +    Transmogrification(const Transmogrification&);
  869. +    Transmogrification& operator=(const Transmogrification&);
  870. +
  871. +public:
  872. +    static Transmogrification* instance();
  873. +
  874. +#ifdef PRESETS
  875. +
  876. +    bool EnableSetInfo;
  877. +    uint32 SetNpcText;
  878. +
  879. +    bool EnableSets;
  880. +    uint8 MaxSets;
  881. +    float SetCostModifier;
  882. +    int32 SetCopperCost;
  883. +
  884. +    void LoadPlayerSets(Player* player);
  885. +
  886. +    void PresetTransmog(Player* player, Item* itemTransmogrified, uint32 fakeEntry, uint8 slot);
  887. +#endif
  888. +
  889. +    bool EnableTransmogInfo;
  890. +    uint32 TransmogNpcText;
  891. +
  892. +    // Use IsAllowed() and IsNotAllowed()
  893. +    // these are thread unsafe, but assumed to be static data so it should be safe
  894. +    std::set<uint32> Allowed;
  895. +    std::set<uint32> NotAllowed;
  896. +
  897. +    float ScaledCostModifier;
  898. +    int32 CopperCost;
  899. +
  900. +    bool RequireToken;
  901. +    uint32 TokenEntry;
  902. +    uint32 TokenAmount;
  903. +
  904. +    bool AllowPoor;
  905. +    bool AllowCommon;
  906. +    bool AllowUncommon;
  907. +    bool AllowRare;
  908. +    bool AllowEpic;
  909. +    bool AllowLegendary;
  910. +    bool AllowArtifact;
  911. +    bool AllowHeirloom;
  912. +
  913. +    bool AllowMixedArmorTypes;
  914. +    bool AllowMixedWeaponTypes;
  915. +    bool AllowFishingPoles;
  916. +
  917. +    bool IgnoreReqRace;
  918. +    bool IgnoreReqClass;
  919. +    bool IgnoreReqSkill;
  920. +    bool IgnoreReqSpell;
  921. +    bool IgnoreReqLevel;
  922. +    bool IgnoreReqEvent;
  923. +    bool IgnoreReqStats;
  924. +
  925. +    bool IsAllowed(uint32 entry) const;
  926. +    bool IsNotAllowed(uint32 entry) const;
  927. +    bool IsAllowedQuality(uint32 quality) const;
  928. +    bool IsRangedWeapon(uint32 Class, uint32 SubClass) const;
  929. +
  930. +    void LoadConfig(bool reload); // thread unsafe
  931. +
  932. +    std::string GetItemIcon(uint32 entry, uint32 width, uint32 height, int x, int y) const;
  933. +    std::string GetSlotIcon(uint8 slot, uint32 width, uint32 height, int x, int y) const;
  934. +    const char * GetSlotName(uint8 slot, WorldSession* session) const;
  935. +    std::string GetItemLink(Item* item, WorldSession* session) const;
  936. +    std::string GetItemLink(uint32 entry, WorldSession* session) const;
  937. +    uint32 GetFakeEntry(const Item* item);
  938. +    void UpdateItem(Player* player, Item* item) const;
  939. +    void DeleteFakeEntry(Player* player, Item* item);
  940. +    void SetFakeEntry(Player* player, Item* item, uint32 entry);
  941. +
  942. +    TransmogTrinityStrings Transmogrify(Player* player, ObjectGuid itemGUID, uint8 slot, bool no_cost = false);
  943. +    bool CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* destination, ItemTemplate const* source) const;
  944. +    bool SuitableForTransmogrification(Player* player, ItemTemplate const* proto) const;
  945. +    // bool CanBeTransmogrified(Item const* item);
  946. +    // bool CanTransmogrify(Item const* item);
  947. +    uint32 GetSpecialPrice(ItemTemplate const* proto) const;
  948. +    std::vector<ObjectGuid> GetItemList(const Player* player) const;
  949. +};
  950. +#define sTransmogrification Transmogrification::instance()
  951. +
  952. +#endif
  953. diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
  954. index 65e7ec8..0dd6ea9 100644
  955. --- a/src/server/game/Entities/Player/Player.cpp
  956. +++ b/src/server/game/Entities/Player/Player.cpp
  957. @@ -16,6 +16,7 @@
  958.   * with this program. If not, see <http://www.gnu.org/licenses/>.
  959.   */
  960.  
  961. +#include "Transmogrification.h"
  962.  #include "Player.h"
  963.  #include "AccountMgr.h"
  964.  #include "AchievementMgr.h"
  965. @@ -12128,7 +12129,10 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem)
  966.  {
  967.      if (pItem)
  968.      {
  969. -        SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
  970. +        if (uint32 entry = sTransmogrification->GetFakeEntry(pItem))
  971. +            SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), entry);
  972. +        else
  973. +            SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
  974.          SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
  975.          SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT));
  976.      }
  977. @@ -12258,6 +12262,7 @@ void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
  978.  {
  979.      if (Item* it = GetItemByPos(bag, slot))
  980.      {
  981. +        sTransmogrification->DeleteFakeEntry(this, it);
  982.          ItemRemovedQuestCheck(it->GetEntry(), it->GetCount());
  983.          RemoveItem(bag, slot, update);
  984.          it->SetNotRefundable(this, false);
  985. diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
  986. index ad58794..2942ce5 100644
  987. --- a/src/server/game/Entities/Player/Player.h
  988. +++ b/src/server/game/Entities/Player/Player.h
  989. @@ -29,6 +29,7 @@
  990.  #include "SpellMgr.h"
  991.  #include "SpellHistory.h"
  992.  #include "Unit.h"
  993. +#include "Transmogrification.h"
  994.  #include "TradeData.h"
  995.  #include "CinematicMgr.h"
  996.  
  997. @@ -129,6 +130,18 @@ struct SpellModifier
  998.      Aura* const ownerAura;
  999.  };
  1000.  
  1001. +typedef std::unordered_map<ObjectGuid, uint32> TransmogMapType;
  1002. +
  1003. +#ifdef PRESETS
  1004. +typedef std::map<uint8, uint32> PresetslotMapType;
  1005. +struct PresetData
  1006. +{
  1007. +    std::string name;
  1008. +    PresetslotMapType slotMap; // slotMap[slotId] = entry
  1009. +};
  1010. +typedef std::map<uint8, PresetData> PresetMapType;
  1011. +#endif
  1012. +
  1013.  typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
  1014.  typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
  1015.  typedef std::unordered_set<SpellModifier*> SpellModContainer;
  1016. @@ -2280,6 +2293,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
  1017.          std::string GetMapAreaAndZoneString() const;
  1018.          std::string GetCoordsMapAreaAndZoneString() const;
  1019.  
  1020. +        TransmogMapType transmogMap; // transmogMap[iGUID] = entry
  1021. +#ifdef PRESETS
  1022. +        PresetMapType presetMap; // presetMap[presetId] = presetData
  1023. +#endif
  1024. +
  1025.      protected:
  1026.          // Gamemaster whisper whitelist
  1027.          GuidList WhisperList;
  1028. diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
  1029. index 554aee1..33527cb 100644
  1030. --- a/src/server/game/Handlers/SpellHandler.cpp
  1031. +++ b/src/server/game/Handlers/SpellHandler.cpp
  1032. @@ -26,6 +26,7 @@
  1033.  #include "Opcodes.h"
  1034.  #include "Spell.h"
  1035.  #include "Totem.h"
  1036. +#include "Transmogrification.h"
  1037.  #include "ScriptMgr.h"
  1038.  #include "GameObjectAI.h"
  1039.  #include "SpellAuraEffects.h"
  1040. @@ -625,7 +626,12 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData)
  1041.              else if (*itr == EQUIPMENT_SLOT_BACK && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
  1042.                  data << uint32(0);
  1043.              else if (Item const* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr))
  1044. -                data << uint32(item->GetTemplate()->DisplayInfoID);
  1045. +            {
  1046. +                if (uint32 entry = sTransmogrification->GetFakeEntry(item))
  1047. +                    data << uint32(sObjectMgr->GetItemTemplate(entry)->DisplayInfoID);
  1048. +                else
  1049. +                    data << uint32(item->GetTemplate()->DisplayInfoID);
  1050. +            }
  1051.              else
  1052.                  data << uint32(0);
  1053.          }
  1054. diff --git a/src/server/scripts/Custom/Transmog/CHANGELOG.md b/src/server/scripts/Custom/Transmog/CHANGELOG.md
  1055. new file mode 100644
  1056. index 0000000..5903bf0
  1057. --- /dev/null
  1058. +++ b/src/server/scripts/Custom/Transmog/CHANGELOG.md
  1059. @@ -0,0 +1,126 @@
  1060. +####6.1
  1061. +- Update to newest TC
  1062. +- Made guid changes
  1063. +
  1064. +####6.0
  1065. +- Removed mutex locks - Different code style, works with ACE and boost, probably more efficient
  1066. +- Added regex checking for preset name
  1067. +- Fixed random properties not registering as item stats (Thanks Aokromes)
  1068. +- Made the code / patch compatible with herbs+veins patch (Thanks Aokromes)
  1069. +- Moved to bithub - Allows autogenerate patch and diff and management is easier:
  1070. +- https://github.com/Rochet2/TrinityCore/tree/transmog
  1071. +- Gist was at: https://gist.github.com/Rochet2/2c8765b53f8dda1e296a
  1072. +
  1073. +####5.6
  1074. +- Fixed few linux compile warnings
  1075. +- Moved to GIST
  1076. +- Old versions etc still available from:
  1077. +https://drive.google.com/folderview?id=0Bx5knS2IsjatTlVtWHRwbUN3VlE&usp=sharing
  1078. +
  1079. +####5.5
  1080. +- Updated to latest TC  rev
  1081. +- Fixed some tabs to spaces
  1082. +- Fixed a warning on gcc
  1083. +
  1084. +####5.4
  1085. +- Updated to latest TC rev
  1086. +
  1087. +####5.3
  1088. +- Rewrote transmogrification logic to be blizzlike.
  1089. +- Implemented multithread support.
  1090. +- Tweaked saving to work so that your data is saved whenever the player is saved.
  1091. +- This means that crashes can not be abused and DB wont have SQL executing and querying all the time.
  1092. +
  1093. +####5.2
  1094. +- Some logic fixes and other
  1095. +
  1096. +####5.1
  1097. +- Config options should now work properly. Please notify here if some still bug
  1098. +- Can transmog bows with guns and crossbows
  1099. +- Can transmog cloth to leather with config settings set
  1100. +- Can transmog robes with chest pieces
  1101. +- You should now be able to view the info menus with the new NPC
  1102. +- Allow shirt's to be transmogrified (were shown in menu but you weren't able to before)
  1103. +- Mirror image (mage spell) should now correctly copy the transmogrified outfit. Before it still got your old item displays.
  1104. +- Added new config options:
  1105. +
  1106. +####5.0
  1107. +- Ripped cata branch functions and thus altered how everything is coded pretty much.
  1108. +- Dropped translation support
  1109. +- Added colored item links as well as icons all over the place
  1110. +- Added new feature: Sets
  1111. +- Added many config options, for example to allow cloth and plate to be transmogrified with each other
  1112. +
  1113. +####4.0
  1114. +- I changed all the methods to normal functions and moved them to Transmogrification.cpp
  1115. +- I also updated the way transmogrifications are stored
  1116. +
  1117. +####3.9
  1118. +- Nothing was added
  1119. +- Now supporting latest TDB: 0d3554d4bf
  1120. +- Also tested and works on latest
  1121. +- Changed diff to patch for better compability
  1122. +
  1123. +####3.8
  1124. +- Nothing was added
  1125. +- Now supporting latest TDB: da9865b683
  1126. +
  1127. +####3.7
  1128. +- Quick update to the patch for latest trinitycore version
  1129. +
  1130. +####3.6
  1131. +- Updated the code to work with the new trinitycore changes
  1132. +- Added config (See the bottom of worldserver.conf)
  1133. +- Added token cost possibility -- in config
  1134. +- Added cost modification possibility -- in config
  1135. +- Added quality requirement modification possibility -- in config
  1136. +
  1137. +####3.5
  1138. +- Fixed a crash on item deletion from guild deleting and more
  1139. +
  1140. +####3.4
  1141. +- 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
  1142. +- Added possibility to disable gold cost before compiling
  1143. +- Cleaned all the code I could find to TrinityCore standards .. I think
  1144. +
  1145. +####3.3
  1146. +- 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.
  1147. +- 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.
  1148. +- Changed the files into one patch file like Aokromes suggested. You can find the DB table creation SQLs from sql/characters_transmogrification/
  1149. +- Removed prepared statements
  1150. +- 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?
  1151. +
  1152. +####3.2
  1153. +- Fixed an issue with DB saving not taking action on login or server restart.
  1154. +
  1155. +####3.1
  1156. +- Corrected the quality check, which was left to return true in any case
  1157. +- Fixed invisible item entries from newly created items (.additem for example)
  1158. +
  1159. +####3.0
  1160. +- It will have mailing and auction etc restrictions properly coded (yay, no more Fake owner!)
  1161. +- Having its own prepared statement now
  1162. +- Moved loading transmogs to the item loading part.
  1163. +- The script should now be added to scriptloader by the patch. So you just need to add it to solution.
  1164. +- Included an NPC sql for everyone with NPC problems :3
  1165. +
  1166. +####2.2
  1167. +- Added a few sounds, altered to use switch instead of an IF block
  1168. +- Modified to have a separate table
  1169. +- And more?
  1170. +
  1171. +####2.1
  1172. +- Fixed a crash when getting item template of item entry 0
  1173. +
  1174. +####2.0
  1175. +- Possibly more ..
  1176. +- Implemented cost
  1177. +- Changed quality checks
  1178. +- Fixed few problems
  1179. +- Changed some messages for more blizzlike feeling
  1180. +- After trying to transmogrify or remove a transmogrification, you get to the item selection screen instead of main menu
  1181. +- Added Remove Transmogrification buttons and update main menu button (removed nevermind)
  1182. +- Added more checks for safety and blizzlike feeling
  1183. +
  1184. +####1.0
  1185. +- Added DB saving and remove transmogrifications option -> patch, sql and script needed
  1186. \ No newline at end of file
  1187. diff --git a/src/server/scripts/Custom/Transmog/README.md b/src/server/scripts/Custom/Transmog/README.md
  1188. new file mode 100644
  1189. index 0000000..f7f1588
  1190. --- /dev/null
  1191. +++ b/src/server/scripts/Custom/Transmog/README.md
  1192. @@ -0,0 +1,53 @@
  1193. +#Transmogrification [![Build Status](https://travis-ci.org/Rochet2/TrinityCore.svg?branch=transmog)](https://travis-ci.org/Rochet2/TrinityCore)
  1194. +
  1195. +####About
  1196. +Transmogrification allows you to change the display of an item to something else.
  1197. +You can use any item in your bags as source of display, as long as it fits the requirements.
  1198. +Requirements can be tweaked in the server configuration file.
  1199. +Basically any item should work with transmogrification. Custom items as well. No item is hardcoded to the system.
  1200. +Has a feature to store sets of displays. This can be removed before compiling or in the configuration file.
  1201. +Made for 3.3.5a.<br />
  1202. +Source: http://rochet2.github.io/Transmogrification.html
  1203. +
  1204. +Video: https://youtu.be/xtH4ogz12iM
  1205. +
  1206. +####Installation
  1207. +
  1208. +Available as:
  1209. +- Direct merge: https://github.com/Rochet2/TrinityCore/tree/transmog
  1210. +- Diff: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...transmog.diff
  1211. +- Diff in github view: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...transmog
  1212. +
  1213. +Using direct merge:
  1214. +- open git bash to source location
  1215. +- do `git remote add rochet2 https://github.com/Rochet2/TrinityCore.git`
  1216. +- do `git pull rochet2 transmog`
  1217. +- use cmake and compile
  1218. +
  1219. +Using diff:
  1220. +- DO NOT COPY THE DIFF DIRECTLY! It causes apply to fail.
  1221. +- download the diff by __right clicking__ the link and select __Save link as__
  1222. +- place the downloaded `transmog.diff` to the source root folder
  1223. +- open git bash to source location
  1224. +- do `git apply transmog.diff`
  1225. +- use cmake and compile
  1226. +
  1227. +After compiling:
  1228. +- Navigate to `\src\server\scripts\Custom\Transmog\sql\`
  1229. +- Run `characters.sql` to your characters database
  1230. +- Run `world_texts.sql` to your world database
  1231. + - optionally you can also insert a transmogrifier NPC to your database by running `world_NPC.sql` to your world database.
  1232. +- Change the settings to your liking in `worldserver.conf` (Note that you should copy over the new config created)
  1233. +
  1234. +####Usage
  1235. +Equip an item that is suitable for transmogrification.
  1236. +Have an item in your bags that is suitable to be used to transmogrify the equipped item
  1237. +Talk to Transmogrifier and select the item slot. Then select the item you want to transmogrify to.
  1238. +Click to proceed when prompted and your items are transmogrified.
  1239. +Currently the default settings are according to this: http://wowwiki.wikia.com/Transmogrification#Current_rules
  1240. +Tweak the settings if you need in worldserver.conf
  1241. +
  1242. +####Changelog: [Changelog](https://github.com/Rochet2/TrinityCore/blob/transmog/src/server/scripts/Custom/Transmog/CHANGELOG.md)
  1243. +
  1244. +####Bugs and Contact
  1245. +Report issues and similar to https://rochet2.github.io/
  1246. diff --git a/src/server/scripts/Custom/Transmog/Transmogrifier.cpp b/src/server/scripts/Custom/Transmog/Transmogrifier.cpp
  1247. new file mode 100644
  1248. index 0000000..fb30109
  1249. --- /dev/null
  1250. +++ b/src/server/scripts/Custom/Transmog/Transmogrifier.cpp
  1251. @@ -0,0 +1,541 @@
  1252. +/*
  1253. +6.1
  1254. +Transmogrification 3.3.5a - Gossip menu
  1255. +By Rochet2
  1256. +
  1257. +ScriptName for NPC:
  1258. +Creature_Transmogrify
  1259. +
  1260. +TODO:
  1261. +Fix the cost formula
  1262. +-- Too much data handling, use default costs
  1263. +
  1264. +Cant transmogrify rediculus items // Foereaper: would be fun to stab people with a fish
  1265. +-- Cant think of any good way to handle this easily, could rip flagged items from cata DB
  1266. +*/
  1267. +
  1268. +#include "Transmogrification.h"
  1269. +#include "Bag.h"
  1270. +#include "Common.h"
  1271. +#include "Config.h"
  1272. +#include "Creature.h"
  1273. +#include "DatabaseEnv.h"
  1274. +#include "DBCStructure.h"
  1275. +#include "Define.h"
  1276. +#include "Field.h"
  1277. +#include "GameEventMgr.h"
  1278. +#include "GossipDef.h"
  1279. +#include "Item.h"
  1280. +#include "ItemTemplate.h"
  1281. +#include "Language.h"
  1282. +#include "Log.h"
  1283. +#include "Player.h"
  1284. +#include "ObjectGuid.h"
  1285. +#include "ObjectMgr.h"
  1286. +#include "QueryResult.h"
  1287. +#include "ScriptedGossip.h"
  1288. +#include "ScriptMgr.h"
  1289. +#include "SharedDefines.h"
  1290. +#include "Transaction.h"
  1291. +#include "WorldSession.h"
  1292. +#include <sstream>
  1293. +#include <string>
  1294. +
  1295. +#define GTS session->GetTrinityString
  1296. +
  1297. +namespace
  1298. +{
  1299. +    class CS_Transmogrification : public CreatureScript
  1300. +    {
  1301. +    public:
  1302. +        CS_Transmogrification() : CreatureScript("Creature_Transmogrify") { }
  1303. +
  1304. +        bool OnGossipHello(Player* player, Creature* creature) override
  1305. +        {
  1306. +            WorldSession* session = player->GetSession();
  1307. +            if (sTransmogrification->EnableTransmogInfo)
  1308. +                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);
  1309. +            for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
  1310. +            {
  1311. +                if (const char* slotName = sTransmogrification->GetSlotName(slot, session))
  1312. +                {
  1313. +                    Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
  1314. +                    uint32 entry = newItem ? sTransmogrification->GetFakeEntry(newItem) : 0;
  1315. +                    std::string icon = entry ? sTransmogrification->GetItemIcon(entry, 30, 30, -18, 0) : sTransmogrification->GetSlotIcon(slot, 30, 30, -18, 0);
  1316. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, icon + std::string(slotName), EQUIPMENT_SLOT_END, slot);
  1317. +                }
  1318. +            }
  1319. +#ifdef PRESETS
  1320. +            if (sTransmogrification->EnableSets)
  1321. +                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/RAIDFRAME/UI-RAIDFRAME-MAINASSIST:30:30:-18:0|tManage sets", EQUIPMENT_SLOT_END + 4, 0);
  1322. +#endif
  1323. +            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);
  1324. +            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", EQUIPMENT_SLOT_END + 1, 0);
  1325. +            player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1326. +            return true;
  1327. +        }
  1328. +
  1329. +        bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
  1330. +        {
  1331. +            player->PlayerTalkClass->ClearMenus();
  1332. +            WorldSession* session = player->GetSession();
  1333. +            switch (sender)
  1334. +            {
  1335. +                case EQUIPMENT_SLOT_END: // Show items you can use
  1336. +                    ShowTransmogItems(player, creature, action);
  1337. +                    break;
  1338. +                case EQUIPMENT_SLOT_END + 1: // Main menu
  1339. +                    OnGossipHello(player, creature);
  1340. +                    break;
  1341. +                case EQUIPMENT_SLOT_END + 2: // Remove Transmogrifications
  1342. +                {
  1343. +                    bool removed = false;
  1344. +                    for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
  1345. +                    {
  1346. +                        if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  1347. +                        {
  1348. +                            if (!sTransmogrification->GetFakeEntry(newItem))
  1349. +                                continue;
  1350. +                            sTransmogrification->DeleteFakeEntry(player, newItem);
  1351. +                            removed = true;
  1352. +                        }
  1353. +                    }
  1354. +                    if (removed)
  1355. +                        session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_UNTRANSMOG_OK));
  1356. +                    else
  1357. +                        session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
  1358. +                    OnGossipHello(player, creature);
  1359. +                } break;
  1360. +                case EQUIPMENT_SLOT_END + 3: // Remove Transmogrification from single item
  1361. +                {
  1362. +                    if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
  1363. +                    {
  1364. +                        if (sTransmogrification->GetFakeEntry(newItem))
  1365. +                        {
  1366. +                            sTransmogrification->DeleteFakeEntry(player, newItem);
  1367. +                            session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_UNTRANSMOG_OK));
  1368. +                        }
  1369. +                        else
  1370. +                            session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
  1371. +                    }
  1372. +                    OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, action);
  1373. +                } break;
  1374. +#ifdef PRESETS
  1375. +                case EQUIPMENT_SLOT_END + 4: // Presets menu
  1376. +                {
  1377. +                    if (!sTransmogrification->EnableSets)
  1378. +                    {
  1379. +                        OnGossipHello(player, creature);
  1380. +                        return true;
  1381. +                    }
  1382. +                    if (sTransmogrification->EnableSetInfo)
  1383. +                        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);
  1384. +
  1385. +                    if (!player->presetMap.empty())
  1386. +                    {
  1387. +                        for (PresetMapType::const_iterator it = player->presetMap.begin(); it != player->presetMap.end(); ++it)
  1388. +                            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);
  1389. +
  1390. +                        if (player->presetMap.size() < sTransmogrification->MaxSets)
  1391. +                            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", EQUIPMENT_SLOT_END + 8, 0);
  1392. +                    }
  1393. +                    else
  1394. +                        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/GuildBankFrame/UI-GuildBankFrame-NewTab:30:30:-18:0|tSave set", EQUIPMENT_SLOT_END + 8, 0);
  1395. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
  1396. +                    player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1397. +                } break;
  1398. +                case EQUIPMENT_SLOT_END + 5: // Use preset
  1399. +                {
  1400. +                    if (!sTransmogrification->EnableSets)
  1401. +                    {
  1402. +                        OnGossipHello(player, creature);
  1403. +                        return true;
  1404. +                    }
  1405. +                    // action = presetID
  1406. +
  1407. +                    PresetMapType::const_iterator it = player->presetMap.find(action);
  1408. +                    if (it != player->presetMap.end())
  1409. +                    {
  1410. +                        for (PresetslotMapType::const_iterator it2 = it->second.slotMap.begin(); it2 != it->second.slotMap.end(); ++it2)
  1411. +                            if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, it2->first))
  1412. +                                sTransmogrification->PresetTransmog(player, item, it2->second, it2->first);
  1413. +                    }
  1414. +                    OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 6, action);
  1415. +                } break;
  1416. +                case EQUIPMENT_SLOT_END + 6: // view preset
  1417. +                {
  1418. +                    if (!sTransmogrification->EnableSets)
  1419. +                    {
  1420. +                        OnGossipHello(player, creature);
  1421. +                        return true;
  1422. +                    }
  1423. +                    // action = presetID
  1424. +
  1425. +                    PresetMapType::const_iterator it = player->presetMap.find(action);
  1426. +                    if (it == player->presetMap.end())
  1427. +                    {
  1428. +                        OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
  1429. +                        return true;
  1430. +                    }
  1431. +
  1432. +                    for (PresetslotMapType::const_iterator it2 = it->second.slotMap.begin(); it2 != it->second.slotMap.end(); ++it2)
  1433. +                        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, sTransmogrification->GetItemIcon(it2->second, 30, 30, -18, 0) + sTransmogrification->GetItemLink(it2->second, session), sender, action);
  1434. +
  1435. +                    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);
  1436. +                    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);
  1437. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
  1438. +                    player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1439. +                } break;
  1440. +                case EQUIPMENT_SLOT_END + 7: // Delete preset
  1441. +                {
  1442. +                    if (!sTransmogrification->EnableSets)
  1443. +                    {
  1444. +                        OnGossipHello(player, creature);
  1445. +                        return true;
  1446. +                    }
  1447. +                    // action = presetID
  1448. +
  1449. +                    player->presetMap.erase(action);
  1450. +
  1451. +                    OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
  1452. +                } break;
  1453. +                case EQUIPMENT_SLOT_END + 8: // Save preset
  1454. +                {
  1455. +                    if (!sTransmogrification->EnableSets)
  1456. +                    {
  1457. +                        OnGossipHello(player, creature);
  1458. +                        return true;
  1459. +                    }
  1460. +
  1461. +                    if (player->presetMap.size() >= sTransmogrification->MaxSets)
  1462. +                    {
  1463. +                        OnGossipHello(player, creature);
  1464. +                        return true;
  1465. +                    }
  1466. +
  1467. +                    uint32 cost = 0;
  1468. +                    bool canSave = false;
  1469. +                    for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
  1470. +                    {
  1471. +                        if (!sTransmogrification->GetSlotName(slot, session))
  1472. +                            continue;
  1473. +                        if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  1474. +                        {
  1475. +                            uint32 entry = sTransmogrification->GetFakeEntry(newItem);
  1476. +                            if (!entry)
  1477. +                                continue;
  1478. +                            const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
  1479. +                            if (!temp)
  1480. +                                continue;
  1481. +                            if (!sTransmogrification->SuitableForTransmogrification(player, temp)) // no need to check?
  1482. +                                continue;
  1483. +                            cost += sTransmogrification->GetSpecialPrice(temp);
  1484. +                            canSave = true;
  1485. +                            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, sTransmogrification->GetItemIcon(entry, 30, 30, -18, 0) + sTransmogrification->GetItemLink(entry, session), EQUIPMENT_SLOT_END + 8, 0);
  1486. +                        }
  1487. +                    }
  1488. +                    if (canSave)
  1489. +                        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);
  1490. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", sender, action);
  1491. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
  1492. +                    player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1493. +                } break;
  1494. +                case EQUIPMENT_SLOT_END + 10: // Set info
  1495. +                {
  1496. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 4, 0);
  1497. +                    player->SEND_GOSSIP_MENU(sTransmogrification->SetNpcText, creature->GetGUID());
  1498. +                } break;
  1499. +#endif
  1500. +                case EQUIPMENT_SLOT_END + 9: // Transmog info
  1501. +                {
  1502. +                    player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
  1503. +                    player->SEND_GOSSIP_MENU(sTransmogrification->TransmogNpcText, creature->GetGUID());
  1504. +                } break;
  1505. +                default: // Transmogrify
  1506. +                {
  1507. +                    if (!sender && !action)
  1508. +                    {
  1509. +                        OnGossipHello(player, creature);
  1510. +                        return true;
  1511. +                    }
  1512. +                    // sender = slot, action = display
  1513. +                    TransmogTrinityStrings res = sTransmogrification->Transmogrify(player, ObjectGuid(HighGuid::Item, 0, action), sender);
  1514. +                    if (res == LANG_ERR_TRANSMOG_OK)
  1515. +                        session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_TRANSMOG_OK));
  1516. +                    else
  1517. +                        session->SendNotification(res);
  1518. +                    OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, sender);
  1519. +                } break;
  1520. +            }
  1521. +            return true;
  1522. +        }
  1523. +
  1524. +#ifdef PRESETS
  1525. +        bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code) override
  1526. +        {
  1527. +            player->PlayerTalkClass->ClearMenus();
  1528. +            if (sender || action)
  1529. +                return true; // should never happen
  1530. +            if (!sTransmogrification->EnableSets)
  1531. +            {
  1532. +                OnGossipHello(player, creature);
  1533. +                return true;
  1534. +            }
  1535. +
  1536. +            // Allow only alnum
  1537. +            std::string name = code;
  1538. +            static const char* allowedcharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz _.,'1234567890";
  1539. +            if (!name.length() || name.find_first_not_of(allowedcharacters) != std::string::npos)
  1540. +            {
  1541. +                player->GetSession()->SendNotification(LANG_PRESET_ERR_INVALID_NAME);
  1542. +                OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
  1543. +                return true;
  1544. +            }
  1545. +
  1546. +            int32 cost = 0;
  1547. +            PresetslotMapType items;
  1548. +            for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
  1549. +            {
  1550. +                if (!sTransmogrification->GetSlotName(slot, player->GetSession()))
  1551. +                    continue;
  1552. +                if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  1553. +                {
  1554. +                    uint32 entry = sTransmogrification->GetFakeEntry(newItem);
  1555. +                    if (!entry)
  1556. +                        continue;
  1557. +                    const ItemTemplate* temp = sObjectMgr->GetItemTemplate(entry);
  1558. +                    if (!temp)
  1559. +                        continue;
  1560. +                    if (!sTransmogrification->SuitableForTransmogrification(player, temp))
  1561. +                        continue;
  1562. +                    cost += sTransmogrification->GetSpecialPrice(temp);
  1563. +                    items[slot] = entry;
  1564. +                }
  1565. +            }
  1566. +
  1567. +            if (!items.empty())
  1568. +            {
  1569. +                // transmogrified items were found to be saved
  1570. +                cost *= sTransmogrification->SetCostModifier;
  1571. +                cost += sTransmogrification->SetCopperCost;
  1572. +
  1573. +                if (!player->HasEnoughMoney(cost))
  1574. +                {
  1575. +                    player->GetSession()->SendNotification(LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY);
  1576. +                }
  1577. +                else
  1578. +                {
  1579. +                    uint8 presetID = sTransmogrification->MaxSets;
  1580. +                    if (player->presetMap.size() < sTransmogrification->MaxSets)
  1581. +                    {
  1582. +                        for (uint8 i = 0; i < sTransmogrification->MaxSets; ++i) // should never reach over max
  1583. +                        {
  1584. +                            if (player->presetMap.find(i) == player->presetMap.end())
  1585. +                            {
  1586. +                                presetID = i;
  1587. +                                break;
  1588. +                            }
  1589. +                        }
  1590. +                    }
  1591. +
  1592. +                    if (presetID < sTransmogrification->MaxSets)
  1593. +                    {
  1594. +                        // Make sure code doesnt mess up SQL!
  1595. +                        player->presetMap[presetID].name = name;
  1596. +                        player->presetMap[presetID].slotMap = items;
  1597. +
  1598. +                        if (cost)
  1599. +                            player->ModifyMoney(-cost);
  1600. +                    }
  1601. +                }
  1602. +            }
  1603. +
  1604. +            OnGossipSelect(player, creature, EQUIPMENT_SLOT_END + 4, 0);
  1605. +            return true;
  1606. +        }
  1607. +#endif
  1608. +
  1609. +        void ShowTransmogItems(Player* player, Creature* creature, uint8 slot) // Only checks bags while can use an item from anywhere in inventory
  1610. +        {
  1611. +            WorldSession* session = player->GetSession();
  1612. +            Item* oldItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
  1613. +            if (oldItem)
  1614. +            {
  1615. +                uint32 limit = 0;
  1616. +                uint32 price = sTransmogrification->GetSpecialPrice(oldItem->GetTemplate());
  1617. +                price *= sTransmogrification->ScaledCostModifier;
  1618. +                price += sTransmogrification->CopperCost;
  1619. +                std::ostringstream ss;
  1620. +                ss << std::endl;
  1621. +                if (sTransmogrification->RequireToken)
  1622. +                    ss << std::endl << std::endl << sTransmogrification->TokenAmount << " x " << sTransmogrification->GetItemLink(sTransmogrification->TokenEntry, session);
  1623. +
  1624. +                for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  1625. +                {
  1626. +                    if (limit >= MAX_OPTIONS)
  1627. +                        break;
  1628. +                    Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
  1629. +                    if (!newItem)
  1630. +                        continue;
  1631. +                    if (!sTransmogrification->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
  1632. +                        continue;
  1633. +                    if (sTransmogrification->GetFakeEntry(oldItem) == newItem->GetEntry())
  1634. +                        continue;
  1635. +                    ++limit;
  1636. +                    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);
  1637. +                }
  1638. +
  1639. +                for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  1640. +                {
  1641. +                    Bag* bag = player->GetBagByPos(i);
  1642. +                    if (!bag)
  1643. +                        continue;
  1644. +                    for (uint32 j = 0; j < bag->GetBagSize(); ++j)
  1645. +                    {
  1646. +                        if (limit >= MAX_OPTIONS)
  1647. +                            break;
  1648. +                        Item* newItem = player->GetItemByPos(i, j);
  1649. +                        if (!newItem)
  1650. +                            continue;
  1651. +                        if (!sTransmogrification->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
  1652. +                            continue;
  1653. +                        if (sTransmogrification->GetFakeEntry(oldItem) == newItem->GetEntry())
  1654. +                            continue;
  1655. +                        ++limit;
  1656. +                        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);
  1657. +                    }
  1658. +                }
  1659. +            }
  1660. +
  1661. +            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);
  1662. +            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|tUpdate menu", EQUIPMENT_SLOT_END, slot);
  1663. +            player->ADD_GOSSIP_ITEM(GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|tBack..", EQUIPMENT_SLOT_END + 1, 0);
  1664. +            player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1665. +        }
  1666. +    };
  1667. +}
  1668. +
  1669. +namespace
  1670. +{
  1671. +    class PS_Transmogrification : public PlayerScript
  1672. +    {
  1673. +    public:
  1674. +        PS_Transmogrification() : PlayerScript("PS_Transmogrification") { }
  1675. +
  1676. +        void OnSave(Player* player) override
  1677. +        {
  1678. +            uint32 lowguid = player->GetGUID().GetCounter();
  1679. +            SQLTransaction trans = CharacterDatabase.BeginTransaction();
  1680. +            trans->PAppend("DELETE FROM `custom_transmogrification` WHERE `Owner` = %u", lowguid);
  1681. +#ifdef PRESETS
  1682. +            trans->PAppend("DELETE FROM `custom_transmogrification_sets` WHERE `Owner` = %u", lowguid);
  1683. +#endif
  1684. +
  1685. +            if (!player->transmogMap.empty())
  1686. +            {
  1687. +                // Only save items that are in inventory / bank / etc
  1688. +                std::vector<ObjectGuid> items = sTransmogrification->GetItemList(player);
  1689. +                for (std::vector<ObjectGuid>::const_iterator it = items.begin(); it != items.end(); ++it)
  1690. +                {
  1691. +                    TransmogMapType::const_iterator it2 = player->transmogMap.find(*it);
  1692. +                    if (it2 == player->transmogMap.end())
  1693. +                        continue;
  1694. +
  1695. +                    trans->PAppend("REPLACE INTO custom_transmogrification (GUID, FakeEntry, Owner) VALUES (%u, %u, %u)", it2->first.GetCounter(), it2->second, lowguid);
  1696. +                }
  1697. +            }
  1698. +
  1699. +#ifdef PRESETS
  1700. +            if (!player->presetMap.empty())
  1701. +            {
  1702. +                for (PresetMapType::const_iterator it = player->presetMap.begin(); it != player->presetMap.end(); ++it)
  1703. +                {
  1704. +                    std::ostringstream ss;
  1705. +                    for (PresetslotMapType::const_iterator it2 = it->second.slotMap.begin(); it2 != it->second.slotMap.end(); ++it2)
  1706. +                        ss << uint32(it2->first) << ' ' << it2->second << ' ';
  1707. +                    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());
  1708. +                }
  1709. +            }
  1710. +#endif
  1711. +
  1712. +            if (trans->GetSize()) // basically never false
  1713. +                CharacterDatabase.CommitTransaction(trans);
  1714. +        }
  1715. +
  1716. +        void OnLogin(Player* player, bool /*firstLogin*/) override
  1717. +        {
  1718. +            QueryResult result = CharacterDatabase.PQuery("SELECT GUID, FakeEntry FROM custom_transmogrification WHERE Owner = %u", player->GetGUID().GetCounter());
  1719. +
  1720. +            if (result)
  1721. +            {
  1722. +                do
  1723. +                {
  1724. +                    Field* field = result->Fetch();
  1725. +                    ObjectGuid itemGUID(HighGuid::Item, 0, field[0].GetUInt32());
  1726. +                    uint32 fakeEntry = field[1].GetUInt32();
  1727. +                    // Only load items that are in inventory / bank / etc
  1728. +                    if (sObjectMgr->GetItemTemplate(fakeEntry) && player->GetItemByGuid(itemGUID))
  1729. +                    {
  1730. +                        player->transmogMap[itemGUID] = fakeEntry;
  1731. +                    }
  1732. +                    else
  1733. +                    {
  1734. +                        // Ignore, will be erased on next save.
  1735. +                        // Additionally this can happen if an item was deleted from DB but still exists for the player
  1736. +                        // TC_LOG_ERROR("custom.transmog", "Item entry (Entry: %u, itemGUID: %u, playerGUID: %u) does not exist, ignoring.", fakeEntry, GUID_LOPART(itemGUID), player->GetGUID().GetCounter());
  1737. +                        // CharacterDatabase.PExecute("DELETE FROM custom_transmogrification WHERE FakeEntry = %u", fakeEntry);
  1738. +                    }
  1739. +                } while (result->NextRow());
  1740. +
  1741. +                if (!player->transmogMap.empty())
  1742. +                {
  1743. +                    for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
  1744. +                    {
  1745. +                        if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  1746. +                        {
  1747. +                            player->SetVisibleItemSlot(slot, item);
  1748. +                            if (player->IsInWorld())
  1749. +                                item->SendUpdateToPlayer(player);
  1750. +                        }
  1751. +                    }
  1752. +                }
  1753. +            }
  1754. +
  1755. +#ifdef PRESETS
  1756. +            if (sTransmogrification->EnableSets)
  1757. +                sTransmogrification->LoadPlayerSets(player);
  1758. +#endif
  1759. +        }
  1760. +    };
  1761. +
  1762. +    class WS_Transmogrification : public WorldScript
  1763. +    {
  1764. +    public:
  1765. +        WS_Transmogrification() : WorldScript("WS_Transmogrification") { }
  1766. +
  1767. +        void OnConfigLoad(bool reload) override
  1768. +        {
  1769. +            sTransmogrification->LoadConfig(reload);
  1770. +        }
  1771. +
  1772. +        void OnStartup() override
  1773. +        {
  1774. +            TC_LOG_INFO("custom.transmog", "Deleting non-existing transmogrification entries...");
  1775. +            CharacterDatabase.DirectExecute("DELETE FROM custom_transmogrification WHERE NOT EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_transmogrification.GUID)");
  1776. +
  1777. +#ifdef PRESETS
  1778. +            // Clean even if disabled
  1779. +            // Dont delete even if player has more presets than should
  1780. +            CharacterDatabase.DirectExecute("DELETE FROM `custom_transmogrification_sets` WHERE NOT EXISTS(SELECT 1 FROM characters WHERE characters.guid = custom_transmogrification_sets.Owner)");
  1781. +#endif
  1782. +            sTransmogrification->LoadConfig(false);
  1783. +        }
  1784. +    };
  1785. +}
  1786. +
  1787. +void AddSC_Transmogrification()
  1788. +{
  1789. +    new WS_Transmogrification();
  1790. +    new PS_Transmogrification();
  1791. +    new CS_Transmogrification();
  1792. +}
  1793. diff --git a/src/server/scripts/Custom/Transmog/sql/characters.sql b/src/server/scripts/Custom/Transmog/sql/characters.sql
  1794. new file mode 100644
  1795. index 0000000..4529815
  1796. --- /dev/null
  1797. +++ b/src/server/scripts/Custom/Transmog/sql/characters.sql
  1798. @@ -0,0 +1,37 @@
  1799. +-- --------------------------------------------------------
  1800. +-- Host:                         localhost
  1801. +-- Server version:               5.5.39 - MySQL Community Server (GPL)
  1802. +-- Server OS:                    Win32
  1803. +-- HeidiSQL Version:             9.1.0.4894
  1804. +-- --------------------------------------------------------
  1805. +
  1806. +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
  1807. +/*!40101 SET NAMES utf8mb4 */;
  1808. +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
  1809. +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
  1810. +
  1811. +-- Dumping structure for table tc_c.custom_transmogrification
  1812. +CREATE TABLE IF NOT EXISTS `custom_transmogrification` (
  1813. +  `GUID` int(10) unsigned NOT NULL COMMENT 'Item guidLow',
  1814. +  `FakeEntry` int(10) unsigned NOT NULL COMMENT 'Item entry',
  1815. +  `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidLow',
  1816. +  PRIMARY KEY (`GUID`),
  1817. +  KEY `Owner` (`Owner`)
  1818. +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_2';
  1819. +
  1820. +-- Data exporting was unselected.
  1821. +
  1822. +
  1823. +-- Dumping structure for table tc_c.custom_transmogrification_sets
  1824. +CREATE TABLE IF NOT EXISTS `custom_transmogrification_sets` (
  1825. +  `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidlow',
  1826. +  `PresetID` tinyint(3) unsigned NOT NULL COMMENT 'Preset identifier',
  1827. +  `SetName` text COMMENT 'SetName',
  1828. +  `SetData` text COMMENT 'Slot1 Entry1 Slot2 Entry2',
  1829. +  PRIMARY KEY (`Owner`,`PresetID`)
  1830. +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_1';
  1831. +
  1832. +-- Data exporting was unselected.
  1833. +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
  1834. +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
  1835. +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
  1836. diff --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
  1837. new file mode 100644
  1838. index 0000000..9603089
  1839. --- /dev/null
  1840. +++ b/src/server/scripts/Custom/Transmog/sql/updates/2016_07_15_00_world.sql
  1841. @@ -0,0 +1,4 @@
  1842. +SET @TEXT_ID := 65000;
  1843. +INSERT INTO `npc_text` (`ID`, `text0_0`) VALUES
  1844. +(@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.'),
  1845. +(@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.');
  1846. diff --git a/src/server/scripts/Custom/Transmog/sql/updates/_README.md b/src/server/scripts/Custom/Transmog/sql/updates/_README.md
  1847. new file mode 100644
  1848. index 0000000..2632510
  1849. --- /dev/null
  1850. +++ b/src/server/scripts/Custom/Transmog/sql/updates/_README.md
  1851. @@ -0,0 +1 @@
  1852. +DO NOT RUN THE UPDATES WHEN MAKING A CLEAN INSTALL
  1853. diff --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
  1854. new file mode 100644
  1855. index 0000000..86c6947
  1856. --- /dev/null
  1857. +++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_1_to_2_2.sql
  1858. @@ -0,0 +1,12 @@
  1859. +CREATE TABLE IF NOT EXISTS `custom_transmogrification` (
  1860. +    `GUID` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  1861. +    `FakeOwner` INT(10) UNSIGNED NOT NULL DEFAULT '0',
  1862. +    `FakeEntry` INT(10) UNSIGNED NOT NULL DEFAULT '0'
  1863. +)
  1864. +COLLATE='latin1_swedish_ci'
  1865. +ENGINE=InnoDB;
  1866. +
  1867. +REPLACE INTO custom_transmogrification (GUID, FakeOwner, FakeEntry) SELECT guid, FakeOwner, FakeEntry FROM item_instance WHERE FakeOwner != 0 AND FakeEntry != 0;
  1868. +ALTER TABLE `item_instance`
  1869. +    DROP COLUMN `FakeEntry`,
  1870. +    DROP COLUMN `FakeOwner`;
  1871. diff --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
  1872. new file mode 100644
  1873. index 0000000..1508a68
  1874. --- /dev/null
  1875. +++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_2_2_to_3_0.sql
  1876. @@ -0,0 +1,2 @@
  1877. +ALTER TABLE `custom_transmogrification`
  1878. +    DROP COLUMN `FakeOwner`;
  1879. diff --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
  1880. new file mode 100644
  1881. index 0000000..89c91ac
  1882. --- /dev/null
  1883. +++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_4_x_to_5_0.sql
  1884. @@ -0,0 +1,16 @@
  1885. +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
  1886. +/*!40101 SET NAMES utf8 */;
  1887. +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
  1888. +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
  1889. +
  1890. +CREATE TABLE `custom_transmogrification_sets` (
  1891. +  `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidlow',
  1892. +  `PresetID` tinyint(3) unsigned NOT NULL COMMENT 'Preset identifier',
  1893. +  `SetName` text COMMENT 'SetName',
  1894. +  `SetData` text COMMENT 'Slot1 Entry1 Slot2 Entry2',
  1895. +  PRIMARY KEY (`Owner`,`PresetID`)
  1896. +) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1897. +
  1898. +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
  1899. +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
  1900. +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
  1901. diff --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
  1902. new file mode 100644
  1903. index 0000000..817de91
  1904. --- /dev/null
  1905. +++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_5_x_to_6_1.sql
  1906. @@ -0,0 +1,6 @@
  1907. +ALTER TABLE `custom_transmogrification`
  1908. +    COMMENT='6_1',
  1909. +    ADD INDEX `Owner` (`Owner`);
  1910. +
  1911. +ALTER TABLE `custom_transmogrification_sets`
  1912. +    COMMENT='6_1';
  1913. diff --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
  1914. new file mode 100644
  1915. index 0000000..0e675b5
  1916. --- /dev/null
  1917. +++ b/src/server/scripts/Custom/Transmog/sql/updates/characters_update_6_1_to_6_2.sql
  1918. @@ -0,0 +1,3 @@
  1919. +ALTER TABLE `custom_transmogrification`
  1920. +   COMMENT='6_2',
  1921. +   COLLATE='utf8_general_ci';
  1922. diff --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
  1923. new file mode 100644
  1924. index 0000000..03cc6d2
  1925. --- /dev/null
  1926. +++ b/src/server/scripts/Custom/Transmog/sql/updates/world_update_3_5_to_3_6.sql
  1927. @@ -0,0 +1 @@
  1928. +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);
  1929. diff --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
  1930. new file mode 100644
  1931. index 0000000..8723683
  1932. --- /dev/null
  1933. +++ b/src/server/scripts/Custom/Transmog/sql/updates/world_update_4_x_to_5_0.sql
  1934. @@ -0,0 +1,27 @@
  1935. +DELETE FROM `trinity_string` WHERE `entry` BETWEEN 11100 AND 11129;
  1936. +
  1937. +SET @TEXT_ID := 50000;
  1938. +INSERT INTO `npc_text` (`ID`, `text0_0`, `WDBVerified`) VALUES
  1939. +(@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),
  1940. +(@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);
  1941. +
  1942. +SET @STRING_ENTRY := 11100;
  1943. +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
  1944. +(@STRING_ENTRY+0, 'Item transmogrified'),
  1945. +(@STRING_ENTRY+1, 'Equipment slot is empty'),
  1946. +(@STRING_ENTRY+2, 'Invalid source item selected'),
  1947. +(@STRING_ENTRY+3, 'Source item does not exist'),
  1948. +(@STRING_ENTRY+4, 'Destination item does not exist'),
  1949. +(@STRING_ENTRY+5, 'Selected items are invalid'),
  1950. +(@STRING_ENTRY+6, 'Not enough money'),
  1951. +(@STRING_ENTRY+7, 'You don\'t have enough tokens'),
  1952. +(@STRING_ENTRY+8, 'Transmogrifications removed'),
  1953. +(@STRING_ENTRY+9, 'There are no transmogrifications'),
  1954. +(@STRING_ENTRY+10, 'Invalid name inserted');
  1955. +
  1956. +SET
  1957. +@Entry = 190010,
  1958. +@Name = "Warpweaver";
  1959. +
  1960. +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
  1961. +(@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);
  1962. diff --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
  1963. new file mode 100644
  1964. index 0000000..2a5e854
  1965. --- /dev/null
  1966. +++ b/src/server/scripts/Custom/Transmog/sql/updates/world_update_5_0_to_5_1.sql
  1967. @@ -0,0 +1,6 @@
  1968. +SET
  1969. +@Entry = 190010,
  1970. +@Name = "Warpweaver";
  1971. +
  1972. +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
  1973. +(@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);
  1974. diff --git a/src/server/scripts/Custom/Transmog/sql/world_NPC.sql b/src/server/scripts/Custom/Transmog/sql/world_NPC.sql
  1975. new file mode 100644
  1976. index 0000000..de1597e
  1977. --- /dev/null
  1978. +++ b/src/server/scripts/Custom/Transmog/sql/world_NPC.sql
  1979. @@ -0,0 +1,6 @@
  1980. +SET
  1981. +@Entry = 190010,
  1982. +@Name = "Warpweaver";
  1983. +
  1984. +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
  1985. +(@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');
  1986. diff --git a/src/server/scripts/Custom/Transmog/sql/world_texts.sql b/src/server/scripts/Custom/Transmog/sql/world_texts.sql
  1987. new file mode 100644
  1988. index 0000000..87713f5
  1989. --- /dev/null
  1990. +++ b/src/server/scripts/Custom/Transmog/sql/world_texts.sql
  1991. @@ -0,0 +1,18 @@
  1992. +SET @TEXT_ID := 65000;
  1993. +INSERT INTO `npc_text` (`ID`, `text0_0`) VALUES
  1994. +(@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.'),
  1995. +(@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.');
  1996. +
  1997. +SET @STRING_ENTRY := 11100;
  1998. +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
  1999. +(@STRING_ENTRY+0, 'Item transmogrified'),
  2000. +(@STRING_ENTRY+1, 'Equipment slot is empty'),
  2001. +(@STRING_ENTRY+2, 'Invalid source item selected'),
  2002. +(@STRING_ENTRY+3, 'Source item does not exist'),
  2003. +(@STRING_ENTRY+4, 'Destination item does not exist'),
  2004. +(@STRING_ENTRY+5, 'Selected items are invalid'),
  2005. +(@STRING_ENTRY+6, 'Not enough money'),
  2006. +(@STRING_ENTRY+7, 'You don\'t have enough tokens'),
  2007. +(@STRING_ENTRY+8, 'Transmogrifications removed'),
  2008. +(@STRING_ENTRY+9, 'There are no transmogrifications'),
  2009. +(@STRING_ENTRY+10, 'Invalid name inserted');
  2010. diff --git a/src/server/scripts/Custom/custom_script_loader.cpp b/src/server/scripts/Custom/custom_script_loader.cpp
  2011. index b74145a..f203949 100644
  2012. --- a/src/server/scripts/Custom/custom_script_loader.cpp
  2013. +++ b/src/server/scripts/Custom/custom_script_loader.cpp
  2014. @@ -16,10 +16,12 @@
  2015.   */
  2016.  
  2017.  // This is where scripts' loading functions should be declared:
  2018. +void AddSC_Transmogrification();
  2019.  
  2020.  
  2021.  // The name of this function should match:
  2022.  // void Add${NameOfDirectory}Scripts()
  2023.  void AddCustomScripts()
  2024.  {
  2025. +    AddSC_Transmogrification();
  2026.  }
  2027. diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
  2028. index fe9277c..da08bf3 100644
  2029. --- a/src/server/scripts/Spells/spell_generic.cpp
  2030. +++ b/src/server/scripts/Spells/spell_generic.cpp
  2031. @@ -38,6 +38,7 @@
  2032.  #include "SpellScript.h"
  2033.  #include "SpellAuraEffects.h"
  2034.  #include "Vehicle.h"
  2035. +#include "Transmogrification.h"
  2036.  
  2037.  class spell_gen_absorb0_hitlimit1 : public SpellScriptLoader
  2038.  {
  2039. @@ -917,7 +918,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
  2040.                          if (Player* player = caster->ToPlayer())
  2041.                          {
  2042.                              if (Item* mainItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
  2043. -                                target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
  2044. +                            {
  2045. +                                if (uint32 entry = sTransmogrification->GetFakeEntry(mainItem))
  2046. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, entry);
  2047. +                                else
  2048. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
  2049. +                            }
  2050.                          }
  2051.                          else
  2052.                              target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID));
  2053. @@ -931,7 +937,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
  2054.                          if (Player* player = caster->ToPlayer())
  2055.                          {
  2056.                              if (Item* offItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
  2057. -                                target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, offItem->GetEntry());
  2058. +                            {
  2059. +                                if (uint32 entry = sTransmogrification->GetFakeEntry(offItem))
  2060. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, entry);
  2061. +                                else
  2062. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, offItem->GetEntry());
  2063. +                            }
  2064.                          }
  2065.                          else
  2066.                              target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1));
  2067. @@ -944,7 +955,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
  2068.                          if (Player* player = caster->ToPlayer())
  2069.                          {
  2070.                              if (Item* rangedItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
  2071. -                                target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, rangedItem->GetEntry());
  2072. +                            {
  2073. +                                if (uint32 entry = sTransmogrification->GetFakeEntry(rangedItem))
  2074. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, entry);
  2075. +                                else
  2076. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, rangedItem->GetEntry());
  2077. +                            }
  2078.                          }
  2079.                          else
  2080.                              target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2));
  2081. diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
  2082. index 0e287aa..4f6d803 100644
  2083. --- a/src/server/worldserver/worldserver.conf.dist
  2084. +++ b/src/server/worldserver/worldserver.conf.dist
  2085. @@ -3733,3 +3733,209 @@ PacketSpoof.BanDuration = 86400
  2086.  
  2087.  #
  2088.  ###################################################################################################
  2089. +
  2090. +###################################################################################################
  2091. +#    Transmogrification config
  2092. +###################################################################################################
  2093. +#
  2094. +#    SETTINGS
  2095. +#
  2096. +#    Logger.custom.transmog
  2097. +#        Description: Transmogrification logging setting, see logger settings
  2098. +#        Default:    3, Console Server
  2099. +#
  2100. +#    Transmogrification.EnableTransmogInfo
  2101. +#        Description: Enables / Disables the info button for transmogrification
  2102. +#        Default:    1
  2103. +#
  2104. +#    Transmogrification.TransmogNpcText
  2105. +#        Description: The npc_text entry of the info menu for transmogrification
  2106. +#        Default:    65000
  2107. +#
  2108. +#    Transmogrification.Allowed
  2109. +#        Description: A list of item entries that are allowed for transmogrification (skips quality and CanUseItem check)
  2110. +#                     Example: "25 35674 5623"
  2111. +#        Default:    ""
  2112. +#
  2113. +#    Transmogrification.NotAllowed
  2114. +#        Description: A list of item entries that are NOT allowed for transmogrification
  2115. +#                     Example: "25 35674 5623"
  2116. +#        Default:    ""
  2117. +
  2118. +Logger.custom.transmog = 3, Console Server
  2119. +
  2120. +Transmogrification.EnableTransmogInfo = 1
  2121. +Transmogrification.TransmogNpcText = 65000
  2122. +
  2123. +Transmogrification.Allowed = ""
  2124. +Transmogrification.NotAllowed = ""
  2125. +
  2126. +#
  2127. +#    COPPER COST
  2128. +#
  2129. +#    Transmogrification.ScaledCostModifier
  2130. +#        Description: A multiplier for the default gold cost (change to 0 for no default cost)
  2131. +#        Default:    1.0
  2132. +#
  2133. +#    Transmogrification.CopperCost
  2134. +#        Description: Cost added on top of other costs (can be negative)
  2135. +#        Default:    0
  2136. +#
  2137. +#    For custom gold cost set ScaledCostModifier to 0.0 and CopperCost to what ever cost you want
  2138. +
  2139. +Transmogrification.ScaledCostModifier = 1.0
  2140. +Transmogrification.CopperCost = 0
  2141. +
  2142. +#
  2143. +#    TOKEN COST
  2144. +#
  2145. +#    Transmogrification.RequireToken
  2146. +#        Description: Adds/disables token cost
  2147. +#        Default:    0
  2148. +#
  2149. +#    Transmogrification.TokenEntry
  2150. +#        Description: Entry of the token item
  2151. +#        Default:    49426
  2152. +#
  2153. +#    Transmogrification.TokenAmount
  2154. +#        Description: Amount of tokens required
  2155. +#        Default:    1
  2156. +
  2157. +Transmogrification.RequireToken = 0
  2158. +Transmogrification.TokenEntry = 49426
  2159. +Transmogrification.TokenAmount = 1
  2160. +
  2161. +#
  2162. +#    REQUIREMENTS
  2163. +#
  2164. +#    Transmogrification.AllowPoor
  2165. +#        Description: Allow poor quality items to be used as source and target items
  2166. +#        Default:    0
  2167. +#
  2168. +#    Transmogrification.AllowCommon
  2169. +#        Description: Allow common quality items to be used as source and target items
  2170. +#        Default:    0
  2171. +#
  2172. +#    Transmogrification.AllowUncommon
  2173. +#        Description: Allow uncommon quality items to be used as source and target items
  2174. +#        Default:    1
  2175. +#
  2176. +#    Transmogrification.AllowRare
  2177. +#        Description: Allow rare quality items to be used as source and target items
  2178. +#        Default:    1
  2179. +#
  2180. +#    Transmogrification.AllowEpic
  2181. +#        Description: Allow epic quality items to be used as source and target items
  2182. +#        Default:    1
  2183. +#
  2184. +#    Transmogrification.AllowLegendary
  2185. +#        Description: Allow legendary quality items to be used as source and target items
  2186. +#        Default:    0
  2187. +#
  2188. +#    Transmogrification.AllowArtifact
  2189. +#        Description: Allow artifact quality items to be used as source and target items
  2190. +#        Default:    0
  2191. +#
  2192. +#    Transmogrification.AllowHeirloom
  2193. +#        Description: Allow heirloom quality items to be used as source and target items
  2194. +#        Default:    1
  2195. +#
  2196. +#    Transmogrification.AllowMixedArmorTypes
  2197. +#        Description: Allow cloth items to be transmogrified with plate for example
  2198. +#        Default:    0
  2199. +#
  2200. +#    Transmogrification.AllowMixedWeaponTypes
  2201. +#        Description: Allow axe to be transmogrified with dagger for example
  2202. +#        Default:    0
  2203. +#
  2204. +#    Transmogrification.AllowFishingPoles
  2205. +#        Description: Allow fishing poles to be transmogrified
  2206. +#        Default:    0
  2207. +#
  2208. +#    Transmogrification.IgnoreReqRace
  2209. +#        Description: Ignore required race for source items
  2210. +#        Default:    0
  2211. +#
  2212. +#    Transmogrification.IgnoreReqClass
  2213. +#        Description: Ignore required class for source items
  2214. +#        Default:    0
  2215. +#
  2216. +#    Transmogrification.IgnoreReqSkill
  2217. +#        Description: Ignore required skill for source items
  2218. +#        Default:    0
  2219. +#
  2220. +#    Transmogrification.IgnoreReqSpell
  2221. +#        Description: Ignore required spell for source items
  2222. +#        Default:    0
  2223. +#
  2224. +#    Transmogrification.IgnoreReqLevel
  2225. +#        Description: Ignore required level for source items
  2226. +#        Default:    0
  2227. +#
  2228. +#    Transmogrification.IgnoreReqEvent
  2229. +#        Description: Ignore required event for source items
  2230. +#        Default:    0
  2231. +#
  2232. +#    Transmogrification.IgnoreReqStats
  2233. +#        Description: Ignore stat count > 0 requirement for source items
  2234. +#        Default:    0
  2235. +
  2236. +Transmogrification.AllowPoor = 0
  2237. +Transmogrification.AllowCommon = 0
  2238. +Transmogrification.AllowUncommon = 1
  2239. +Transmogrification.AllowRare = 1
  2240. +Transmogrification.AllowEpic = 1
  2241. +Transmogrification.AllowLegendary = 0
  2242. +Transmogrification.AllowArtifact = 0
  2243. +Transmogrification.AllowHeirloom = 1
  2244. +
  2245. +Transmogrification.AllowMixedArmorTypes = 0
  2246. +Transmogrification.AllowMixedWeaponTypes = 0
  2247. +Transmogrification.AllowFishingPoles = 0
  2248. +
  2249. +Transmogrification.IgnoreReqRace = 0
  2250. +Transmogrification.IgnoreReqClass = 0
  2251. +Transmogrification.IgnoreReqSkill = 0
  2252. +Transmogrification.IgnoreReqSpell = 0
  2253. +Transmogrification.IgnoreReqLevel = 0
  2254. +Transmogrification.IgnoreReqEvent = 0
  2255. +Transmogrification.IgnoreReqStats = 0
  2256. +
  2257. +#
  2258. +#    SET FEATURE
  2259. +#
  2260. +#    Transmogrification.EnableSets
  2261. +#        Description: Enables / Disables the set feature. If you want permanent disable, check Transmogrification.h
  2262. +#        Default:    1
  2263. +#
  2264. +#    Transmogrification.MaxSets
  2265. +#        Description: Maximum amount of sets a player can save (hardcap at 25)
  2266. +#        Default:    10
  2267. +#
  2268. +#    Transmogrification.EnableSetInfo
  2269. +#        Description: Enables / Disables the info button for set fature
  2270. +#        Default:    1
  2271. +#
  2272. +#    Transmogrification.SetNpcText
  2273. +#        Description: The npc_text entry of the info menu for the set feature
  2274. +#        Default:    65001
  2275. +#
  2276. +#    Transmogrification.SetCostModifier
  2277. +#        Description: A multiplier for the default gold cost (all costs summed together) (change to 0 for no default cost)
  2278. +#        Default:    3.0
  2279. +#
  2280. +#    Transmogrification.SetCopperCost
  2281. +#        Description: Cost added on top of other costs (can be negative)
  2282. +#        Default:    0
  2283. +
  2284. +Transmogrification.EnableSets = 1
  2285. +Transmogrification.MaxSets = 10
  2286. +
  2287. +Transmogrification.EnableSetInfo = 1
  2288. +Transmogrification.SetNpcText = 65001
  2289. +
  2290. +Transmogrification.SetCostModifier = 3.0
  2291. +Transmogrification.SetCopperCost = 0
  2292. +
  2293. +#
  2294. +###################################################################################################
Advertisement
Add Comment
Please, Sign In to add comment