kusanagy

transVendor

Nov 9th, 2016
1,797
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 72.89 KB | None | 0 0
  1. diff --git a/src/server/game/Entities/Item/TransmogDisplayVendor.cpp b/src/server/game/Entities/Item/TransmogDisplayVendor.cpp
  2. new file mode 100644
  3. index 0000000..aa7193b
  4. --- /dev/null
  5. +++ b/src/server/game/Entities/Item/TransmogDisplayVendor.cpp
  6. @@ -0,0 +1,560 @@
  7. +/*
  8. +Transmog display vendor
  9. +Code by Rochet2
  10. +Ideas LilleCarl
  11. +
  12. +ScriptName for NPC:
  13. +NPC_TransmogDisplayVendor
  14. +
  15. +Compatible with Transmogrification 6.1 by Rochet2
  16. +http://rochet2.github.io/Transmogrification
  17. +*/
  18. +
  19. +#include "TransmogDisplayVendorConf.h"
  20. +#include "Common.h"
  21. +#include "QueryResult.h"
  22. +#include "DatabaseEnv.h"
  23. +#include "Transaction.h"
  24. +#include "Field.h"
  25. +#include "DBCStructure.h"
  26. +#include "Item.h"
  27. +#include "ItemPrototype.h"
  28. +#include "Language.h"
  29. +#include "Log.h"
  30. +#include "Player.h"
  31. +#include "ObjectGuid.h"
  32. +#include "ObjectMgr.h"
  33. +#include "WorldSession.h"
  34. +#include "GameEventMgr.h"
  35. +#include <sstream>
  36. +#include <string>
  37. +
  38. +// Config start
  39. +
  40. +// Edit Transmogrification compatibility in TransmogDisplayVendorConf.h
  41. +
  42. +// A multiplier for the default gold cost (change to 0.0f for no default cost)
  43. +const float TransmogDisplayVendorMgr::ScaledCostModifier = 1.0f;
  44. +// Cost added on top of other costs (can be negative)
  45. +const int32 TransmogDisplayVendorMgr::CopperCost = 0;
  46. +// For custom gold cost set ScaledCostModifier to 0.0f and CopperCost to what ever cost you want
  47. +
  48. +const bool TransmogDisplayVendorMgr::RequireToken = false;
  49. +const uint32 TransmogDisplayVendorMgr::TokenEntry = 49426;
  50. +const uint32 TransmogDisplayVendorMgr::TokenAmount = 1;
  51. +
  52. +const bool TransmogDisplayVendorMgr::AllowPoor = false;
  53. +const bool TransmogDisplayVendorMgr::AllowCommon = false;
  54. +const bool TransmogDisplayVendorMgr::AllowUncommon = true;
  55. +const bool TransmogDisplayVendorMgr::AllowRare = true;
  56. +const bool TransmogDisplayVendorMgr::AllowEpic = true;
  57. +const bool TransmogDisplayVendorMgr::AllowLegendary = false;
  58. +const bool TransmogDisplayVendorMgr::AllowArtifact = false;
  59. +const bool TransmogDisplayVendorMgr::AllowHeirloom = true;
  60. +
  61. +const bool TransmogDisplayVendorMgr::AllowMixedArmorTypes = false;
  62. +const bool TransmogDisplayVendorMgr::AllowMixedWeaponTypes = false;
  63. +const bool TransmogDisplayVendorMgr::AllowFishingPoles = false;
  64. +
  65. +const bool TransmogDisplayVendorMgr::IgnoreReqRace = false;
  66. +const bool TransmogDisplayVendorMgr::IgnoreReqClass = false;
  67. +const bool TransmogDisplayVendorMgr::IgnoreReqSkill = false;
  68. +const bool TransmogDisplayVendorMgr::IgnoreReqSpell = false;
  69. +const bool TransmogDisplayVendorMgr::IgnoreReqLevel = false;
  70. +const bool TransmogDisplayVendorMgr::IgnoreReqEvent = false;
  71. +const bool TransmogDisplayVendorMgr::IgnoreReqStats = false;
  72. +
  73. +// Example AllowedItems[] = { 123, 234, 345 };
  74. +const std::set<uint32> TransmogDisplayVendorMgr::AllowedItems = { };
  75. +const std::set<uint32> TransmogDisplayVendorMgr::NotAllowedItems = { };
  76. +
  77. +// Config end
  78. +
  79. +std::vector<uint32> TransmogDisplayVendorMgr::Allowed;
  80. +std::vector<uint32> TransmogDisplayVendorMgr::NotAllowed;
  81. +SelectionStore TransmogDisplayVendorMgr::selectionStore;
  82. +TransmogDisplayVendorMgr::EntryVector* TransmogDisplayVendorMgr::optionMap[MAX_ITEM_SUBCLASS_WEAPON + MAX_ITEM_SUBCLASS_ARMOR][MAX_INVTYPE][MAX_ITEM_QUALITY];
  83. +
  84. +uint32 TransmogDisplayVendorMgr::GetFakeEntry(const Item* item)
  85. +{
  86. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::GetFakeEntry");
  87. +
  88. +    Player* owner = item->GetOwner();
  89. +
  90. +    if (!owner)
  91. +        return 0;
  92. +    if (owner->transmogMap.empty())
  93. +        return 0;
  94. +
  95. +    TransmogMapType::const_iterator it = owner->transmogMap.find(item->GetGUID());
  96. +    if (it == owner->transmogMap.end())
  97. +        return 0;
  98. +    return it->second;
  99. +}
  100. +void TransmogDisplayVendorMgr::DeleteFakeEntry(Player* player, Item* item)
  101. +{
  102. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::DeleteFakeEntry");
  103. +
  104. +    if (player->transmogMap.erase(item->GetGUID()) != 0)
  105. +        UpdateItem(player, item);
  106. +}
  107. +void TransmogDisplayVendorMgr::SetFakeEntry(Player* player, Item* item, uint32 entry)
  108. +{
  109. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::SetFakeEntry");
  110. +
  111. +    player->transmogMap[item->GetGUID()] = entry;
  112. +    UpdateItem(player, item);
  113. +}
  114. +void TransmogDisplayVendorMgr::UpdateItem(Player* player, Item* item)
  115. +{
  116. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::UpdateItem");
  117. +
  118. +    if (item->IsEquipped())
  119. +    {
  120. +        player->SetVisibleItemSlot(item->GetSlot(), item);
  121. +        if (player->IsInWorld())
  122. +            item->SendUpdateToPlayer(player);
  123. +    }
  124. +}
  125. +const char* TransmogDisplayVendorMgr::getSlotName(uint8 slot, WorldSession* /*session*/)
  126. +{
  127. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::TransmogDisplayVendorMgr::getSlotName");
  128. +
  129. +    switch (slot)
  130. +    {
  131. +        case EQUIPMENT_SLOT_HEAD: return  "Head";// session->GetTrinityString(LANG_SLOT_NAME_HEAD);
  132. +        case EQUIPMENT_SLOT_SHOULDERS: return  "Shoulders";// session->GetTrinityString(LANG_SLOT_NAME_SHOULDERS);
  133. +        case EQUIPMENT_SLOT_BODY: return  "Shirt";// session->GetTrinityString(LANG_SLOT_NAME_BODY);
  134. +        case EQUIPMENT_SLOT_CHEST: return  "Chest";// session->GetTrinityString(LANG_SLOT_NAME_CHEST);
  135. +        case EQUIPMENT_SLOT_WAIST: return  "Waist";// session->GetTrinityString(LANG_SLOT_NAME_WAIST);
  136. +        case EQUIPMENT_SLOT_LEGS: return  "Legs";// session->GetTrinityString(LANG_SLOT_NAME_LEGS);
  137. +        case EQUIPMENT_SLOT_FEET: return  "Feet";// session->GetTrinityString(LANG_SLOT_NAME_FEET);
  138. +        case EQUIPMENT_SLOT_WRISTS: return  "Wrists";// session->GetTrinityString(LANG_SLOT_NAME_WRISTS);
  139. +        case EQUIPMENT_SLOT_HANDS: return  "Hands";// session->GetTrinityString(LANG_SLOT_NAME_HANDS);
  140. +        case EQUIPMENT_SLOT_BACK: return  "Back";// session->GetTrinityString(LANG_SLOT_NAME_BACK);
  141. +        case EQUIPMENT_SLOT_MAINHAND: return  "Main hand";// session->GetTrinityString(LANG_SLOT_NAME_MAINHAND);
  142. +        case EQUIPMENT_SLOT_OFFHAND: return  "Off hand";// session->GetTrinityString(LANG_SLOT_NAME_OFFHAND);
  143. +        case EQUIPMENT_SLOT_RANGED: return  "Ranged";// session->GetTrinityString(LANG_SLOT_NAME_RANGED);
  144. +        case EQUIPMENT_SLOT_TABARD: return  "Tabard";// session->GetTrinityString(LANG_SLOT_NAME_TABARD);
  145. +        default: return NULL;
  146. +    }
  147. +}
  148. +uint32 TransmogDisplayVendorMgr::GetSpecialPrice(ItemTemplate const* proto)
  149. +{
  150. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::GetSpecialPrice");
  151. +
  152. +    uint32 cost = proto->SellPrice < 10000 ? 10000 : proto->SellPrice;
  153. +    return cost;
  154. +}
  155. +bool TransmogDisplayVendorMgr::CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* target, ItemTemplate const* source)
  156. +{
  157. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::CanTransmogrifyItemWithItem");
  158. +
  159. +    if (!target || !source)
  160. +        return false;
  161. +
  162. +    if (source->ItemId == target->ItemId)
  163. +        return false;
  164. +
  165. +    if (source->DisplayInfoID == target->DisplayInfoID)
  166. +        return false;
  167. +
  168. +    if (source->Class != target->Class)
  169. +        return false;
  170. +
  171. +    if (source->InventoryType == INVTYPE_BAG ||
  172. +        source->InventoryType == INVTYPE_RELIC ||
  173. +        // source->InventoryType == INVTYPE_BODY ||
  174. +        source->InventoryType == INVTYPE_FINGER ||
  175. +        source->InventoryType == INVTYPE_TRINKET ||
  176. +        source->InventoryType == INVTYPE_AMMO ||
  177. +        source->InventoryType == INVTYPE_QUIVER)
  178. +        return false;
  179. +
  180. +    if (target->InventoryType == INVTYPE_BAG ||
  181. +        target->InventoryType == INVTYPE_RELIC ||
  182. +        // target->InventoryType == INVTYPE_BODY ||
  183. +        target->InventoryType == INVTYPE_FINGER ||
  184. +        target->InventoryType == INVTYPE_TRINKET ||
  185. +        target->InventoryType == INVTYPE_AMMO ||
  186. +        target->InventoryType == INVTYPE_QUIVER)
  187. +        return false;
  188. +
  189. +    if (!SuitableForTransmogrification(player, target) || !SuitableForTransmogrification(player, source)) // if (!transmogrified->CanTransmogrify() || !transmogrifier->CanBeTransmogrified())
  190. +        return false;
  191. +
  192. +    if (IsRangedWeapon(source->Class, source->SubClass) != IsRangedWeapon(target->Class, target->SubClass))
  193. +        return false;
  194. +
  195. +    if (source->SubClass != target->SubClass && !IsRangedWeapon(target->Class, target->SubClass))
  196. +    {
  197. +        if (source->Class == ITEM_CLASS_ARMOR && !AllowMixedArmorTypes)
  198. +            return false;
  199. +        if (source->Class == ITEM_CLASS_WEAPON && !AllowMixedWeaponTypes)
  200. +            return false;
  201. +    }
  202. +
  203. +    if (source->InventoryType != target->InventoryType)
  204. +    {
  205. +        if (source->Class == ITEM_CLASS_WEAPON && !((IsRangedWeapon(target->Class, target->SubClass) ||
  206. +            ((target->InventoryType == INVTYPE_WEAPON || target->InventoryType == INVTYPE_2HWEAPON) &&
  207. +                (source->InventoryType == INVTYPE_WEAPON || source->InventoryType == INVTYPE_2HWEAPON)) ||
  208. +            ((target->InventoryType == INVTYPE_WEAPONMAINHAND || target->InventoryType == INVTYPE_WEAPONOFFHAND) &&
  209. +                (source->InventoryType == INVTYPE_WEAPON || source->InventoryType == INVTYPE_2HWEAPON)))))
  210. +            return false;
  211. +        if (source->Class == ITEM_CLASS_ARMOR &&
  212. +            !((source->InventoryType == INVTYPE_CHEST || source->InventoryType == INVTYPE_ROBE) &&
  213. +                (target->InventoryType == INVTYPE_CHEST || target->InventoryType == INVTYPE_ROBE)))
  214. +            return false;
  215. +    }
  216. +
  217. +    return true;
  218. +}
  219. +bool TransmogDisplayVendorMgr::SuitableForTransmogrification(Player* player, ItemTemplate const* proto)
  220. +{
  221. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::SuitableForTransmogrification");
  222. +
  223. +    // ItemTemplate const* proto = item->GetTemplate();
  224. +    if (!proto)
  225. +        return false;
  226. +
  227. +    if (proto->Class != ITEM_CLASS_ARMOR &&
  228. +        proto->Class != ITEM_CLASS_WEAPON)
  229. +        return false;
  230. +
  231. +    // Skip all checks for allowed items
  232. +    if (IsAllowed(proto->ItemId))
  233. +        return true;
  234. +
  235. +    if (IsNotAllowed(proto->ItemId))
  236. +        return false;
  237. +
  238. +    if (!AllowFishingPoles && proto->Class == ITEM_CLASS_WEAPON && proto->SubClass == ITEM_SUBCLASS_WEAPON_FISHING_POLE)
  239. +        return false;
  240. +
  241. +    if (!IsAllowedQuality(proto->Quality)) // (proto->Quality == ITEM_QUALITY_LEGENDARY)
  242. +        return false;
  243. +
  244. +    if (player)
  245. +    {
  246. +        if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeam() != HORDE)
  247. +            return false;
  248. +
  249. +        if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeam() != ALLIANCE)
  250. +            return false;
  251. +
  252. +        if (!IgnoreReqClass && (proto->AllowableClass & player->getClassMask()) == 0)
  253. +            return false;
  254. +
  255. +        if (!IgnoreReqRace && (proto->AllowableRace & player->getRaceMask()) == 0)
  256. +            return false;
  257. +
  258. +        if (!IgnoreReqSkill && proto->RequiredSkill != 0)
  259. +        {
  260. +            if (player->GetSkillValue(proto->RequiredSkill) == 0)
  261. +                return false;
  262. +            else if (player->GetSkillValue(proto->RequiredSkill) < proto->RequiredSkillRank)
  263. +                return false;
  264. +        }
  265. +
  266. +        if (!IgnoreReqSpell && proto->RequiredSpell != 0 && !player->HasSpell(proto->RequiredSpell))
  267. +            return false;
  268. +
  269. +        if (!IgnoreReqLevel && player->getLevel() < proto->RequiredLevel)
  270. +            return false;
  271. +    }
  272. +
  273. +    // If World Event is not active, prevent using event dependant items
  274. +    if (!IgnoreReqEvent && proto->HolidayId && !IsHolidayActive((HolidayIds)proto->HolidayId))
  275. +        return false;
  276. +
  277. +    if (!IgnoreReqStats)
  278. +    {
  279. +        if (!proto->RandomProperty && !proto->RandomSuffix)
  280. +        {
  281. +            bool found = false;
  282. +            for (uint8 i = 0; i < proto->StatsCount; ++i)
  283. +            {
  284. +                if (proto->ItemStat[i].ItemStatValue != 0)
  285. +                {
  286. +                    found = true;
  287. +                    break;
  288. +                }
  289. +            }
  290. +            if (!found)
  291. +                return false;
  292. +        }
  293. +    }
  294. +
  295. +    return true;
  296. +}
  297. +
  298. +bool TransmogDisplayVendorMgr::IsRangedWeapon(uint32 Class, uint32 SubClass)
  299. +{
  300. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::IsRangedWeapon");
  301. +
  302. +    return Class == ITEM_CLASS_WEAPON && (
  303. +        SubClass == ITEM_SUBCLASS_WEAPON_BOW ||
  304. +        SubClass == ITEM_SUBCLASS_WEAPON_GUN ||
  305. +        SubClass == ITEM_SUBCLASS_WEAPON_CROSSBOW);
  306. +}
  307. +bool TransmogDisplayVendorMgr::IsAllowed(uint32 entry)
  308. +{
  309. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::IsAllowed");
  310. +
  311. +    return std::find(Allowed.begin(), Allowed.end(), entry) != Allowed.end();
  312. +}
  313. +bool TransmogDisplayVendorMgr::IsNotAllowed(uint32 entry)
  314. +{
  315. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::IsNotAllowed");
  316. +
  317. +    return std::find(NotAllowed.begin(), NotAllowed.end(), entry) != NotAllowed.end();
  318. +}
  319. +bool TransmogDisplayVendorMgr::IsAllowedQuality(uint32 quality)
  320. +{
  321. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::IsAllowedQuality");
  322. +
  323. +    switch (quality)
  324. +    {
  325. +        case ITEM_QUALITY_POOR: return AllowPoor;
  326. +        case ITEM_QUALITY_NORMAL: return AllowCommon;
  327. +        case ITEM_QUALITY_UNCOMMON: return AllowUncommon;
  328. +        case ITEM_QUALITY_RARE: return AllowRare;
  329. +        case ITEM_QUALITY_EPIC: return AllowEpic;
  330. +        case ITEM_QUALITY_LEGENDARY: return AllowLegendary;
  331. +        case ITEM_QUALITY_ARTIFACT: return AllowArtifact;
  332. +        case ITEM_QUALITY_HEIRLOOM: return AllowHeirloom;
  333. +        default: return false;
  334. +    }
  335. +}
  336. +
  337. +void TransmogDisplayVendorMgr::HandleTransmogrify(Player* player, Creature* /*creature*/, uint32 vendorslot, uint32 itemEntry, bool no_cost)
  338. +{
  339. +    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify");
  340. +
  341. +    SelectionStore::Selection selection;
  342. +    if (!selectionStore.GetSelection(player->GetGUID().GetCounter(), selection))
  343. +        return; // cheat, no slot selected
  344. +
  345. +    const char* slotname = TransmogDisplayVendorMgr::getSlotName(selection.slot, player->GetSession());
  346. +    if (!slotname)
  347. +        return;
  348. +    uint8 slot = selection.slot;
  349. +
  350. +    // slot of the transmogrified item
  351. +    if (slot >= EQUIPMENT_SLOT_END)
  352. +    {
  353. +        TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) tried to transmogrify item %u with a wrong slot (%u) when transmogrifying items.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemEntry, slot);
  354. +        return; // LANG_ERR_TRANSMOG_INVALID_SLOT
  355. +    }
  356. +
  357. +    const ItemTemplate* itemTransmogrifier = NULL;
  358. +    // guid of the transmogrifier item, if it's not 0
  359. +    if (itemEntry)
  360. +    {
  361. +        itemTransmogrifier = sObjectMgr->GetItemTemplate(itemEntry);
  362. +        if (!itemTransmogrifier)
  363. +        {
  364. +            TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) tried to transmogrify with an invalid item entry %u.", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemEntry);
  365. +            return; // LANG_ERR_TRANSMOG_MISSING_SRC_ITEM
  366. +        }
  367. +    }
  368. +
  369. +    // transmogrified item
  370. +    Item* itemTransmogrified = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
  371. +    if (!itemTransmogrified)
  372. +    {
  373. +        TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) tried to transmogrify an invalid item in a valid slot (slot: %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), slot);
  374. +        player->GetSession()->SendNotification("No item in %s slot", slotname);
  375. +        return; // LANG_ERR_TRANSMOG_MISSING_DEST_ITEM
  376. +    }
  377. +
  378. +    if (!itemTransmogrifier) // reset look newEntry
  379. +    {
  380. +        DeleteFakeEntry(player, itemTransmogrified);
  381. +    }
  382. +    else
  383. +    {
  384. +        if (!CanTransmogrifyItemWithItem(player, itemTransmogrified->GetTemplate(), itemTransmogrifier))
  385. +        {
  386. +            TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %s (%s) failed CanTransmogrifyItemWithItem (%u with %u).", player->GetName().c_str(), player->GetGUID().ToString().c_str(), itemTransmogrified->GetEntry(), itemTransmogrifier->ItemId);
  387. +            player->GetSession()->SendNotification("Equipped item is not suitable for selected transmogrification");
  388. +            return; // LANG_ERR_TRANSMOG_INVALID_ITEMS
  389. +        }
  390. +
  391. +        if (uint32 fakeEntry = GetFakeEntry(itemTransmogrified))
  392. +        {
  393. +            if (const ItemTemplate* fakeItemTemplate = sObjectMgr->GetItemTemplate(fakeEntry))
  394. +            {
  395. +                if (fakeItemTemplate->DisplayInfoID == itemTransmogrifier->DisplayInfoID)
  396. +                {
  397. +                    player->GetSession()->SendNotification("%s already transmogrified with %s", slotname, getItemName(itemTransmogrifier, player->GetSession()).c_str());
  398. +                    return;
  399. +                }
  400. +            }
  401. +        }
  402. +
  403. +        // {{entry}, {entry}, ...}
  404. +        std::list<uint32> L;
  405. +        uint32 counter = 0;
  406. +        bool over = false;
  407. +        if (itemTransmogrified->GetTemplate()->Class != ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedArmorTypes)
  408. +        {
  409. +            for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_ARMOR; ++i)
  410. +            {
  411. +                const EntryVector* oM = optionMap[MAX_ITEM_SUBCLASS_WEAPON + i][getCorrectInvType(itemTransmogrified->GetTemplate()->InventoryType)][selection.quality];
  412. +                if (!oM)
  413. +                    continue;
  414. +                if (!over && counter + oM->size() < selection.offset)
  415. +                {
  416. +                    counter += oM->size();
  417. +                }
  418. +                else
  419. +                {
  420. +                    over = true;
  421. +                    L.insert(L.end(), oM->begin(), oM->end());
  422. +                }
  423. +            }
  424. +        }
  425. +        else if (itemTransmogrified->GetTemplate()->Class == ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedWeaponTypes)
  426. +        {
  427. +            for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON; ++i)
  428. +            {
  429. +                const EntryVector* oM = optionMap[i][getCorrectInvType(itemTransmogrified->GetTemplate()->InventoryType)][selection.quality];
  430. +                if (!oM)
  431. +                    continue;
  432. +                if (!over && counter + oM->size() < selection.offset)
  433. +                {
  434. +                    counter += oM->size();
  435. +                }
  436. +                else
  437. +                {
  438. +                    over = true;
  439. +                    L.insert(L.end(), oM->begin(), oM->end());
  440. +                }
  441. +            }
  442. +        }
  443. +        else
  444. +        {
  445. +            const EntryVector* oM = optionMap[(itemTransmogrified->GetTemplate()->Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itemTransmogrified->GetTemplate()->SubClass][getCorrectInvType(itemTransmogrified->GetTemplate()->InventoryType)][selection.quality];
  446. +            if (oM)
  447. +            {
  448. +                if (!over && counter + oM->size() < selection.offset)
  449. +                {
  450. +                    counter += oM->size();
  451. +                }
  452. +                else
  453. +                {
  454. +                    over = true;
  455. +                    L.insert(L.end(), oM->begin(), oM->end());
  456. +                }
  457. +            }
  458. +        }
  459. +        std::list<uint32>::const_iterator it = L.begin();
  460. +        std::advance(it, (selection.offset - counter) + vendorslot);
  461. +        if (it == L.end() || (*it) != itemEntry)
  462. +        {
  463. +            player->GetSession()->SendNotification("Equipped item is not suitable for selected transmogrification");
  464. +            return; // either cheat or changed items (not found in correct place in transmog vendor view)
  465. +        }
  466. +
  467. +        if (!no_cost)
  468. +        {
  469. +            if (RequireToken)
  470. +            {
  471. +                if (player->HasItemCount(TokenEntry, TokenAmount))
  472. +                {
  473. +                    player->DestroyItemCount(TokenEntry, TokenAmount, true);
  474. +                }
  475. +                else
  476. +                {
  477. +                    player->GetSession()->SendNotification("You do not have enough %ss", getItemName(sObjectMgr->GetItemTemplate(TransmogDisplayVendorMgr::TokenEntry), player->GetSession()).c_str());
  478. +                    return; // LANG_ERR_TRANSMOG_NOT_ENOUGH_TOKENS
  479. +                }
  480. +            }
  481. +
  482. +            int32 cost = 0;
  483. +            cost = GetSpecialPrice(itemTransmogrified->GetTemplate());
  484. +            cost *= ScaledCostModifier;
  485. +            cost += CopperCost;
  486. +
  487. +            if (cost) // 0 cost if reverting look
  488. +            {
  489. +                if (cost < 0)
  490. +                {
  491. +                    TC_LOG_DEBUG("custom.transmog", "TransmogDisplayVendorMgr::HandleTransmogrify - %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->ItemId);
  492. +                }
  493. +                else
  494. +                {
  495. +                    if (!player->HasEnoughMoney(cost))
  496. +                    {
  497. +                        player->GetSession()->SendNotification("You do not have enough money");
  498. +                        return; // LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY
  499. +                    }
  500. +                    player->ModifyMoney(-cost, false);
  501. +                }
  502. +            }
  503. +
  504. +            SetFakeEntry(player, itemTransmogrified, itemTransmogrifier->ItemId);
  505. +
  506. +            itemTransmogrified->UpdatePlayedTime(player);
  507. +
  508. +            itemTransmogrified->SetOwnerGUID(player->GetGUID());
  509. +            itemTransmogrified->SetNotRefundable(player);
  510. +            itemTransmogrified->ClearSoulboundTradeable(player);
  511. +
  512. +            //if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE)
  513. +            //    itemTransmogrifier->SetBinding(true);
  514. +
  515. +            //itemTransmogrifier->SetOwnerGUID(player->GetGUID());
  516. +            //itemTransmogrifier->SetNotRefundable(player);
  517. +            //itemTransmogrifier->ClearSoulboundTradeable(player);
  518. +        }
  519. +
  520. +        player->PlayDirectSound(3337);
  521. +        player->GetSession()->SendAreaTriggerMessage("%s transmogrified", slotname);
  522. +        //return LANG_ERR_TRANSMOG_OK;
  523. +    }
  524. +}
  525. +
  526. +const char * TransmogDisplayVendorMgr::getQualityName(uint32 quality)
  527. +{
  528. +    switch (quality)
  529. +    {
  530. +    case ITEM_QUALITY_POOR: return "|CFF9d9d9d[Poor]";
  531. +    case ITEM_QUALITY_NORMAL: return "|CFFffffff[Common]";
  532. +    case ITEM_QUALITY_UNCOMMON: return "|CFF1eff00[Uncommon]";
  533. +    case ITEM_QUALITY_RARE: return "|CFF0070dd[Rare]";
  534. +    case ITEM_QUALITY_EPIC: return "|CFFa335ee[Epic]";
  535. +    case ITEM_QUALITY_LEGENDARY: return "|CFFff8000[Legendary]";
  536. +    case ITEM_QUALITY_ARTIFACT: return "|CFFe6cc80[Artifact]";
  537. +    case ITEM_QUALITY_HEIRLOOM: return "|CFFe5cc80[Heirloom]";
  538. +    default: return "[Unknown]";
  539. +    }
  540. +}
  541. +
  542. +std::string TransmogDisplayVendorMgr::getItemName(const ItemTemplate * itemTemplate, WorldSession * session)
  543. +{
  544. +    std::string name = itemTemplate->Name1;
  545. +    int loc_idx = session->GetSessionDbLocaleIndex();
  546. +    if (loc_idx >= 0)
  547. +        if (ItemLocale const* il = sObjectMgr->GetItemLocale(itemTemplate->ItemId))
  548. +            sObjectMgr->GetLocaleString(il->Name, loc_idx, name);
  549. +    return name;
  550. +}
  551. +
  552. +uint32 TransmogDisplayVendorMgr::getCorrectInvType(uint32 inventorytype)
  553. +{
  554. +    switch (inventorytype)
  555. +    {
  556. +    case INVTYPE_WEAPONMAINHAND:
  557. +    case INVTYPE_WEAPONOFFHAND:
  558. +        return INVTYPE_WEAPON;
  559. +    case INVTYPE_RANGEDRIGHT:
  560. +        return INVTYPE_RANGED;
  561. +    case INVTYPE_ROBE:
  562. +        return INVTYPE_CHEST;
  563. +    default:
  564. +        return inventorytype;
  565. +    }
  566. +}
  567. diff --git a/src/server/game/Entities/Item/TransmogDisplayVendorConf.h b/src/server/game/Entities/Item/TransmogDisplayVendorConf.h
  568. new file mode 100644
  569. index 0000000..496596d
  570. --- /dev/null
  571. +++ b/src/server/game/Entities/Item/TransmogDisplayVendorConf.h
  572. @@ -0,0 +1,160 @@
  573. +#ifndef DEF_TRANSMOGRIFICATION_DISPLAY_H
  574. +#define DEF_TRANSMOGRIFICATION_DISPLAY_H
  575. +
  576. +/*
  577. +Transmogrification display vendor
  578. +Code by Rochet2
  579. +Ideas LilleCarl
  580. +
  581. +ScriptName for NPC:
  582. +NPC_TransmogDisplayVendor
  583. +
  584. +Compatible with Transmogrification 6.1 by Rochet2
  585. +http://rochet2.github.io/Transmogrification
  586. +*/
  587. +
  588. +// use 0 or 1
  589. +#define TRANSMOGRIFICATION_ALREADY_INSTALLED    0
  590. +// Note! If you use both, set this to true (1) and in scriptloader make transmog load first
  591. +
  592. +#include "Define.h"
  593. +#include "ItemPrototype.h"
  594. +#include "SharedDefines.h"
  595. +#include <set>
  596. +#include <vector>
  597. +#include <unordered_map>
  598. +#include <boost/thread/locks.hpp>
  599. +#include <boost/thread/shared_mutex.hpp>
  600. +
  601. +class Creature;
  602. +class Item;
  603. +class Player;
  604. +class WorldSession;
  605. +struct ItemTemplate;
  606. +
  607. +enum TransmogDisplayVendorSenders
  608. +{
  609. +    SENDER_START = MAX_ITEM_QUALITY,
  610. +    SENDER_BACK,
  611. +    SENDER_SELECT_VENDOR,
  612. +    SENDER_REMOVE_ALL,
  613. +    SENDER_REMOVE_ONE,
  614. +    SENDER_REMOVE_MENU,
  615. +    SENDER_END,
  616. +};
  617. +
  618. +namespace
  619. +{
  620. +    class RWLockable
  621. +    {
  622. +    public:
  623. +        typedef boost::shared_mutex LockType;
  624. +        typedef boost::shared_lock<boost::shared_mutex> ReadGuard;
  625. +        typedef boost::unique_lock<boost::shared_mutex> WriteGuard;
  626. +        LockType& GetLock() { return _lock; }
  627. +    private:
  628. +        LockType _lock;
  629. +    };
  630. +};
  631. +
  632. +class TC_GAME_API SelectionStore : public RWLockable
  633. +{
  634. +public:
  635. +    struct Selection { uint32 item; uint8 slot; uint32 offset; uint32 quality; };
  636. +    typedef std::unordered_map<uint32, Selection> PlayerLowToSelection;
  637. +
  638. +    void SetSelection(uint32 playerLow, const Selection& selection)
  639. +    {
  640. +        WriteGuard guard(GetLock());
  641. +        hashmap[playerLow] = selection;
  642. +    }
  643. +
  644. +    bool GetSelection(uint32 playerLow, Selection& returnVal)
  645. +    {
  646. +        ReadGuard guard(GetLock());
  647. +
  648. +        PlayerLowToSelection::iterator it = hashmap.find(playerLow);
  649. +        if (it == hashmap.end())
  650. +            return false;
  651. +
  652. +        returnVal = it->second;
  653. +        return true;
  654. +    }
  655. +
  656. +    void RemoveSelection(uint32 playerLow)
  657. +    {
  658. +        WriteGuard guard(GetLock());
  659. +        hashmap.erase(playerLow);
  660. +    }
  661. +
  662. +private:
  663. +    PlayerLowToSelection hashmap;
  664. +};
  665. +
  666. +class TC_GAME_API TransmogDisplayVendorMgr
  667. +{
  668. +public:
  669. +    // Selection store
  670. +    static SelectionStore selectionStore; // selectionStore[lowGUID] = Selection
  671. +
  672. +    // Vendor data store
  673. +    // optionMap[Class? + SubClass][invtype][Quality] = EntryVector
  674. +    typedef std::vector<uint32> EntryVector;
  675. +    static EntryVector* optionMap[MAX_ITEM_SUBCLASS_WEAPON + MAX_ITEM_SUBCLASS_ARMOR][MAX_INVTYPE][MAX_ITEM_QUALITY];
  676. +
  677. +    static const std::set<uint32> AllowedItems;
  678. +    static const std::set<uint32> NotAllowedItems;
  679. +
  680. +    static const float ScaledCostModifier;
  681. +    static const int32 CopperCost;
  682. +
  683. +    static const bool RequireToken;
  684. +    static const uint32 TokenEntry;
  685. +    static const uint32 TokenAmount;
  686. +
  687. +    static const bool AllowPoor;
  688. +    static const bool AllowCommon;
  689. +    static const bool AllowUncommon;
  690. +    static const bool AllowRare;
  691. +    static const bool AllowEpic;
  692. +    static const bool AllowLegendary;
  693. +    static const bool AllowArtifact;
  694. +    static const bool AllowHeirloom;
  695. +
  696. +    static const bool AllowMixedArmorTypes;
  697. +    static const bool AllowMixedWeaponTypes;
  698. +    static const bool AllowFishingPoles;
  699. +
  700. +    static const bool IgnoreReqRace;
  701. +    static const bool IgnoreReqClass;
  702. +    static const bool IgnoreReqSkill;
  703. +    static const bool IgnoreReqSpell;
  704. +    static const bool IgnoreReqLevel;
  705. +    static const bool IgnoreReqEvent;
  706. +    static const bool IgnoreReqStats;
  707. +
  708. +    static std::vector<uint32> Allowed;
  709. +    static std::vector<uint32> NotAllowed;
  710. +
  711. +    static void HandleTransmogrify(Player* player, Creature* creature, uint32 vendorslot, uint32 itemEntry, bool no_cost = false);
  712. +
  713. +    static const char* getQualityName(uint32 quality);
  714. +    static std::string getItemName(const ItemTemplate* itemTemplate, WorldSession* session);
  715. +    static uint32 getCorrectInvType(uint32 inventorytype);
  716. +
  717. +    // From Transmogrification
  718. +    static uint32 GetFakeEntry(const Item* item);
  719. +    static void DeleteFakeEntry(Player* player, Item* item);
  720. +    static void SetFakeEntry(Player* player, Item* item, uint32 entry);
  721. +    static const char* getSlotName(uint8 slot, WorldSession* session);
  722. +    static void UpdateItem(Player* player, Item* item);
  723. +    static uint32 GetSpecialPrice(ItemTemplate const* proto);
  724. +    static bool CanTransmogrifyItemWithItem(Player* player, ItemTemplate const* target, ItemTemplate const* source);
  725. +    static bool SuitableForTransmogrification(Player* player, ItemTemplate const* proto);
  726. +    static bool IsRangedWeapon(uint32 Class, uint32 SubClass);
  727. +    static bool IsAllowed(uint32 entry);
  728. +    static bool IsNotAllowed(uint32 entry);
  729. +    static bool IsAllowedQuality(uint32 quality);
  730. +};
  731. +
  732. +#endif
  733. diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
  734. index 50e27d9..3d5ecd9 100644
  735. --- a/src/server/game/Entities/Player/Player.cpp
  736. +++ b/src/server/game/Entities/Player/Player.cpp
  737. @@ -16,6 +16,7 @@
  738.   * with this program. If not, see <http://www.gnu.org/licenses/>.
  739.   */
  740.  
  741. +#include "TransmogDisplayVendorConf.h"
  742.  #include "Player.h"
  743.  #include "AccountMgr.h"
  744.  #include "AchievementMgr.h"
  745. @@ -12069,7 +12070,10 @@ void Player::SetVisibleItemSlot(uint8 slot, Item* pItem)
  746.  {
  747.      if (pItem)
  748.      {
  749. -        SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
  750. +        if (uint32 entry = TransmogDisplayVendorMgr::GetFakeEntry(pItem))
  751. +            SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), entry);
  752. +        else
  753. +            SetUInt32Value(PLAYER_VISIBLE_ITEM_1_ENTRYID + (slot * 2), pItem->GetEntry());
  754.          SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 0, pItem->GetEnchantmentId(PERM_ENCHANTMENT_SLOT));
  755.          SetUInt16Value(PLAYER_VISIBLE_ITEM_1_ENCHANTMENT + (slot * 2), 1, pItem->GetEnchantmentId(TEMP_ENCHANTMENT_SLOT));
  756.      }
  757. @@ -12197,6 +12201,7 @@ void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
  758.  {
  759.      if (Item* it = GetItemByPos(bag, slot))
  760.      {
  761. +        TransmogDisplayVendorMgr::DeleteFakeEntry(this, it);
  762.          ItemRemovedQuestCheck(it->GetEntry(), it->GetCount());
  763.          RemoveItem(bag, slot, update);
  764.          it->SetNotRefundable(this, false);
  765. @@ -21355,24 +21360,30 @@ bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uin
  766.          return false;
  767.      }
  768.  
  769. -    if (!(pProto->AllowableClass & getClassMask()) && pProto->Bonding == BIND_WHEN_PICKED_UP && !IsGameMaster())
  770. +    Creature* creature = GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
  771. +    if (!creature)
  772.      {
  773. -        SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0);
  774. +        TC_LOG_DEBUG("network", "Player::BuyItemFromVendorSlot: Vendor (%s) not found or player '%s' (%s) can't interact with him.",
  775. +            vendorguid.ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str());
  776. +        SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, nullptr, item, 0);
  777.          return false;
  778.      }
  779.  
  780. -    if (!IsGameMaster() && ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && GetTeam() == ALLIANCE) || (pProto->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && GetTeam() == HORDE)))
  781. +    if (creature->GetScriptName() == "NPC_TransmogDisplayVendor")
  782. +    {
  783. +        TransmogDisplayVendorMgr::HandleTransmogrify(this, creature, vendorslot, item);
  784.          return false;
  785. +    }
  786.  
  787. -    Creature* creature = GetNPCIfCanInteractWith(vendorguid, UNIT_NPC_FLAG_VENDOR);
  788. -    if (!creature)
  789. +    if (!(pProto->AllowableClass & getClassMask()) && pProto->Bonding == BIND_WHEN_PICKED_UP && !IsGameMaster())
  790.      {
  791. -        TC_LOG_DEBUG("network", "Player::BuyItemFromVendorSlot: Vendor (%s) not found or player '%s' (%s) can't interact with him.",
  792. -            vendorguid.ToString().c_str(), GetName().c_str(), GetGUID().ToString().c_str());
  793. -        SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, nullptr, item, 0);
  794. +        SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0);
  795.          return false;
  796.      }
  797.  
  798. +    if (!IsGameMaster() && ((pProto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY && GetTeam() == ALLIANCE) || (pProto->Flags2 == ITEM_FLAGS_EXTRA_ALLIANCE_ONLY && GetTeam() == HORDE)))
  799. +        return false;
  800. +
  801.      if (!sConditionMgr->IsObjectMeetingVendorItemConditions(creature->GetEntry(), item, this, creature))
  802.      {
  803.          TC_LOG_DEBUG("condition", "Player::BuyItemFromVendorSlot: Player '%s' (%s) doesn't meed conditions for creature (Entry: %u, Item: %u)",
  804. diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
  805. index 372a49b..a5d24af 100644
  806. --- a/src/server/game/Entities/Player/Player.h
  807. +++ b/src/server/game/Entities/Player/Player.h
  808. @@ -128,6 +128,18 @@ struct SpellModifier
  809.      Aura* const ownerAura;
  810.  };
  811.  
  812. +typedef std::unordered_map<ObjectGuid, uint32> TransmogMapType;
  813. +
  814. +#ifdef PRESETS
  815. +typedef std::map<uint8, uint32> PresetslotMapType;
  816. +struct PresetData
  817. +{
  818. +    std::string name;
  819. +    PresetslotMapType slotMap; // slotMap[slotId] = entry
  820. +};
  821. +typedef std::map<uint8, PresetData> PresetMapType;
  822. +#endif
  823. +
  824.  typedef std::unordered_map<uint32, PlayerTalent*> PlayerTalentMap;
  825.  typedef std::unordered_map<uint32, PlayerSpell*> PlayerSpellMap;
  826.  typedef std::list<SpellModifier*> SpellModList;
  827. @@ -2271,6 +2283,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
  828.          std::string GetMapAreaAndZoneString() const;
  829.          std::string GetCoordsMapAreaAndZoneString() const;
  830.  
  831. +        TransmogMapType transmogMap; // transmogMap[iGUID] = entry
  832. +#ifdef PRESETS
  833. +        PresetMapType presetMap; // presetMap[presetId] = presetData
  834. +#endif
  835. +
  836.      protected:
  837.          // Gamemaster whisper whitelist
  838.          GuidList WhisperList;
  839. diff --git a/src/server/game/Handlers/SpellHandler.cpp b/src/server/game/Handlers/SpellHandler.cpp
  840. index e07e10a..3d8d654 100644
  841. --- a/src/server/game/Handlers/SpellHandler.cpp
  842. +++ b/src/server/game/Handlers/SpellHandler.cpp
  843. @@ -16,6 +16,7 @@
  844.   * with this program. If not, see <http://www.gnu.org/licenses/>.
  845.   */
  846.  
  847. +#include "TransmogDisplayVendorConf.h"
  848.  #include "Common.h"
  849.  #include "DBCStores.h"
  850.  #include "WorldPacket.h"
  851. @@ -625,7 +626,12 @@ void WorldSession::HandleMirrorImageDataRequest(WorldPacket& recvData)
  852.              else if (*itr == EQUIPMENT_SLOT_BACK && player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
  853.                  data << uint32(0);
  854.              else if (Item const* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, *itr))
  855. -                data << uint32(item->GetTemplate()->DisplayInfoID);
  856. +            {
  857. +                if (uint32 entry = TransmogDisplayVendorMgr::GetFakeEntry(item))
  858. +                    data << uint32(sObjectMgr->GetItemTemplate(entry)->DisplayInfoID);
  859. +                else
  860. +                    data << uint32(item->GetTemplate()->DisplayInfoID);
  861. +            }
  862.              else
  863.                  data << uint32(0);
  864.          }
  865. diff --git a/src/server/scripts/Custom/TransmogDisplayVendor/README.md b/src/server/scripts/Custom/TransmogDisplayVendor/README.md
  866. new file mode 100644
  867. index 0000000..de921d6
  868. --- /dev/null
  869. +++ b/src/server/scripts/Custom/TransmogDisplayVendor/README.md
  870. @@ -0,0 +1,49 @@
  871. +#Transmogrification Display Vendor [![Build Status](https://travis-ci.org/Rochet2/TrinityCore.svg?branch=transmogvendor)](https://travis-ci.org/Rochet2/TrinityCore)
  872. +
  873. +####About
  874. +Original idea by LilleCarl.
  875. +Coding work and execution by Rochet2.
  876. +Transmogrification Display Vendor allows you to change the display of an item to something else.
  877. +You can use any item display in the game, as long as it fits the requirements.
  878. +Requirements can be tweaked in the `TransmogDisplayVendor.cpp` file.
  879. +Basically any item should work with transmogrification. Custom items as well. No item is hardcoded to the system.
  880. +Has a feature to work with the regular [Transmogrification](http://rochet2.github.io/Transmogrification.html). This can be enabled before compiling in `TransmogDisplayVendor.h`.
  881. +Made for 3.3.5a.<br />
  882. +Source: http://www.trinitycore.org/f/topic/7993-transmogrification-display-vendor/
  883. +
  884. +Video: https://youtu.be/PIheEziN_dY
  885. +
  886. +####Installation
  887. +
  888. +Available as:
  889. +- Direct merge: https://github.com/Rochet2/TrinityCore/tree/transmogvendor
  890. +- Diff: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...transmogvendor.diff
  891. +- Diff in github view: https://github.com/Rochet2/TrinityCore/compare/TrinityCore:3.3.5...transmogvendor
  892. +
  893. +Using direct merge:
  894. +- open git bash to source location
  895. +- do `git remote add rochet2 https://github.com/Rochet2/TrinityCore.git`
  896. +- do `git pull rochet2 transmogvendor`
  897. +- use cmake and compile
  898. +
  899. +Using diff *(recommended)*:
  900. +- DO NOT COPY THE DIFF DIRECTLY! It causes apply to fail.
  901. +- download the diff by __right clicking__ the link and select __Save link as__
  902. +- place the downloaded `transmogvendor.diff` to the source root folder
  903. +- open git bash to source location
  904. +- do `git apply transmogvendor.diff`
  905. + - if using the regular transmogrification, simply use --reject with either and overwrite the parts of the other. Order doesnt matter, as long as duplicate code doesnt exist.
  906. +- use cmake and compile
  907. +
  908. +After compiling:
  909. +- Navigate to `\src\server\scripts\Custom\TransmogDisplayVendor\sql\`
  910. +- Run `characters.sql` to your characters database
  911. + - This is same file as with the regular transmog
  912. +- Optionally you can also insert a transmogrifier NPC to your database by running `world_NPC.sql` to your world database.
  913. +
  914. +####Usage
  915. +Equip an item that is suitable for transmogrification.
  916. +Talk to Transmogrifier and select the item slot. Then select the quality and then the item you want to transmogrify to.
  917. +
  918. +####Bugs and Contact
  919. +Report issues and similar to http://rochet2.github.io/
  920. diff --git a/src/server/scripts/Custom/TransmogDisplayVendor/TransmogVendor.cpp b/src/server/scripts/Custom/TransmogDisplayVendor/TransmogVendor.cpp
  921. new file mode 100644
  922. index 0000000..cbc604c
  923. --- /dev/null
  924. +++ b/src/server/scripts/Custom/TransmogDisplayVendor/TransmogVendor.cpp
  925. @@ -0,0 +1,553 @@
  926. +/*
  927. +Transmog display vendor
  928. +Code by Rochet2
  929. +Ideas LilleCarl
  930. +
  931. +ScriptName for NPC:
  932. +NPC_TransmogDisplayVendor
  933. +
  934. +Compatible with Transmogrification 6.1 by Rochet2
  935. +http://rochet2.github.io/Transmogrification
  936. +*/
  937. +
  938. +#include "TransmogDisplayVendorConf.h"
  939. +#include "Bag.h"
  940. +#include "Common.h"
  941. +#include "Config.h"
  942. +#include "Creature.h"
  943. +#include "DatabaseEnv.h"
  944. +#include "DBCStructure.h"
  945. +#include "Define.h"
  946. +#include "Field.h"
  947. +#include "GameEventMgr.h"
  948. +#include "GossipDef.h"
  949. +#include "Item.h"
  950. +#include "ItemPrototype.h"
  951. +#include "Language.h"
  952. +#include "Log.h"
  953. +#include "Player.h"
  954. +#include "ObjectGuid.h"
  955. +#include "ObjectMgr.h"
  956. +#include "QueryResult.h"
  957. +#include "ScriptedGossip.h"
  958. +#include "ScriptMgr.h"
  959. +#include "SharedDefines.h"
  960. +#include "Transaction.h"
  961. +#include "WorldSession.h"
  962. +#include <sstream>
  963. +#include <string>
  964. +
  965. +class NPC_TransmogDisplayVendor : public CreatureScript
  966. +{
  967. +public:
  968. +    NPC_TransmogDisplayVendor() : CreatureScript("NPC_TransmogDisplayVendor") { } // If you change this, also change in Player.cpp: if (creature->GetScriptName() == "NPC_TransmogDisplayVendor")
  969. +
  970. +    bool OnGossipHello(Player* player, Creature* creature) override
  971. +    {
  972. +        player->PlayerTalkClass->ClearMenus();
  973. +        TransmogDisplayVendorMgr::selectionStore.RemoveSelection(player->GetGUID().GetCounter());
  974. +        WorldSession* session = player->GetSession();
  975. +        for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
  976. +        {
  977. +            // if (player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  978. +            if (const char* slotName = TransmogDisplayVendorMgr::getSlotName(slot, session))
  979. +                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, slotName, SENDER_SELECT_VENDOR, slot);
  980. +        }
  981. +        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TRAINER, "Remove transmogrifications", SENDER_REMOVE_MENU, 0);
  982. +        player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  983. +        return true;
  984. +    }
  985. +
  986. +    bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action) override
  987. +    {
  988. +        WorldSession* session = player->GetSession();
  989. +        player->PlayerTalkClass->ClearMenus();
  990. +        switch (sender)
  991. +        {
  992. +            case SENDER_SELECT_VENDOR: // action = slot
  993. +            {
  994. +                Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action);
  995. +                if (!item)
  996. +                {
  997. +                    if (const char* slotname = TransmogDisplayVendorMgr::getSlotName(action, player->GetSession()))
  998. +                        session->SendNotification("No item equipped in %s slot", slotname);
  999. +                    OnGossipHello(player, creature);
  1000. +                    return true;
  1001. +                }
  1002. +                const ItemTemplate * itemTemplate = item->GetTemplate();
  1003. +                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_INTERACT_1, (std::string)"Update selected; " + TransmogDisplayVendorMgr::getItemName(itemTemplate, session), sender, action);
  1004. +
  1005. +                // [quality] = {size}
  1006. +                std::map<uint32, uint32> L;
  1007. +                if (itemTemplate->Class != ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedArmorTypes)
  1008. +                {
  1009. +                    for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_ARMOR; ++i)
  1010. +                    {
  1011. +                        TransmogDisplayVendorMgr::EntryVector** oM = TransmogDisplayVendorMgr::optionMap[MAX_ITEM_SUBCLASS_WEAPON + i][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)];
  1012. +                        for (uint32 i = 0; i < MAX_ITEM_QUALITY; ++i, ++oM)
  1013. +                            if (TransmogDisplayVendorMgr::IsAllowedQuality(i)) // skip not allowed qualities
  1014. +                                if (*oM)
  1015. +                                    L[i] += (*oM)->size();
  1016. +                    }
  1017. +                }
  1018. +                else if (itemTemplate->Class == ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedWeaponTypes)
  1019. +                {
  1020. +                    for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON; ++i)
  1021. +                    {
  1022. +                        TransmogDisplayVendorMgr::EntryVector** oM = TransmogDisplayVendorMgr::optionMap[i][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)];
  1023. +                        for (uint32 i = 0; i < MAX_ITEM_QUALITY; ++i, ++oM)
  1024. +                            if (TransmogDisplayVendorMgr::IsAllowedQuality(i)) // skip not allowed qualities
  1025. +                                if (*oM)
  1026. +                                    L[i] += (*oM)->size();
  1027. +                    }
  1028. +                }
  1029. +                else
  1030. +                {
  1031. +                    TransmogDisplayVendorMgr::EntryVector** oM = TransmogDisplayVendorMgr::optionMap[(itemTemplate->Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itemTemplate->SubClass][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)];
  1032. +                    for (uint32 i = 0; i < MAX_ITEM_QUALITY; ++i, ++oM)
  1033. +                        if (TransmogDisplayVendorMgr::IsAllowedQuality(i)) // skip not allowed qualities
  1034. +                            if (*oM)
  1035. +                                L[i] += (*oM)->size();
  1036. +                }
  1037. +
  1038. +                for (std::map<uint32, uint32>::const_iterator it = L.begin(); it != L.end(); ++it)
  1039. +                {
  1040. +                    for (uint32 count = 0; count*MAX_VENDOR_ITEMS < it->second; ++count)
  1041. +                    {
  1042. +                        std::ostringstream ss;
  1043. +                        ss << TransmogDisplayVendorMgr::getQualityName(it->first);
  1044. +                        if (count)
  1045. +                            ss << " [" << count << "]";
  1046. +                        player->ADD_GOSSIP_ITEM(GOSSIP_ICON_VENDOR, ss.str().c_str(), it->first, count*MAX_VENDOR_ITEMS);
  1047. +                    }
  1048. +                }
  1049. +
  1050. +                if (player->PlayerTalkClass->GetGossipMenu().GetMenuItemCount() <= 1)
  1051. +                {
  1052. +                    if (const char* slotname = TransmogDisplayVendorMgr::getSlotName(action, player->GetSession()))
  1053. +                        session->SendNotification("No transmogrifications available for %s", slotname);
  1054. +                    OnGossipHello(player, creature);
  1055. +                    return true;
  1056. +                }
  1057. +
  1058. +                SelectionStore::Selection temp = { item->GetEntry(), static_cast<uint8>(action), 0, 0 }; // entry, slot, offset, quality
  1059. +                TransmogDisplayVendorMgr::selectionStore.SetSelection(player->GetGUID().GetCounter(), temp);
  1060. +                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", SENDER_BACK, 0);
  1061. +                player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1062. +            } break;
  1063. +            case SENDER_BACK: // Back
  1064. +            {
  1065. +                OnGossipHello(player, creature);
  1066. +            } break;
  1067. +            case SENDER_REMOVE_ALL: // Remove TransmogDisplayVendorMgrs
  1068. +            {
  1069. +                bool removed = false;
  1070. +                for (uint8 Slot = EQUIPMENT_SLOT_START; Slot < EQUIPMENT_SLOT_END; Slot++)
  1071. +                {
  1072. +                    if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, Slot))
  1073. +                    {
  1074. +                        if (!TransmogDisplayVendorMgr::GetFakeEntry(newItem))
  1075. +                            continue;
  1076. +                        TransmogDisplayVendorMgr::DeleteFakeEntry(player, newItem);
  1077. +                        removed = true;
  1078. +                    }
  1079. +                }
  1080. +                if (removed)
  1081. +                {
  1082. +                    session->SendAreaTriggerMessage("Transmogrifications removed from equipped items");
  1083. +                    player->PlayDirectSound(3337);
  1084. +                }
  1085. +                else
  1086. +                {
  1087. +                    session->SendNotification("You have no transmogrified items equipped");
  1088. +                }
  1089. +                OnGossipSelect(player, creature, SENDER_REMOVE_MENU, 0);
  1090. +            } break;
  1091. +            case SENDER_REMOVE_ONE: // Remove TransmogDisplayVendorMgr from single item
  1092. +            {
  1093. +                const char* slotname = TransmogDisplayVendorMgr::getSlotName(action, player->GetSession());
  1094. +                if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
  1095. +                {
  1096. +                    if (TransmogDisplayVendorMgr::GetFakeEntry(newItem))
  1097. +                    {
  1098. +                        TransmogDisplayVendorMgr::DeleteFakeEntry(player, newItem);
  1099. +                        if (slotname)
  1100. +                            session->SendAreaTriggerMessage("%s transmogrification removed", slotname);
  1101. +                        player->PlayDirectSound(3337);
  1102. +                    }
  1103. +                    else if (slotname)
  1104. +                    {
  1105. +                        session->SendNotification("No transmogrification on %s slot", slotname);
  1106. +                    }
  1107. +                }
  1108. +                else if (slotname)
  1109. +                {
  1110. +                    session->SendNotification("No item equipped in %s slot", slotname);
  1111. +                }
  1112. +                OnGossipSelect(player, creature, SENDER_REMOVE_MENU, 0);
  1113. +            } break;
  1114. +            case SENDER_REMOVE_MENU:
  1115. +            {
  1116. +                for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; slot++)
  1117. +                {
  1118. +                    const char* slotname = TransmogDisplayVendorMgr::getSlotName(slot, player->GetSession());
  1119. +                    if (!slotname)
  1120. +                        continue;
  1121. +                    std::ostringstream ss;
  1122. +                    ss << "Remove transmogrification from " << slotname << "?";
  1123. +                    player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_INTERACT_1, (std::string)"Remove from " + slotname, SENDER_REMOVE_ONE, slot, ss.str().c_str(), 0, false);
  1124. +                }
  1125. +                player->ADD_GOSSIP_ITEM_EXTENDED(GOSSIP_ICON_INTERACT_1, "Remove all transmogrifications", SENDER_REMOVE_ALL, 0, "Are you sure you want to remove all transmogrifications?", 0, false);
  1126. +                player->ADD_GOSSIP_ITEM(GOSSIP_ICON_TALK, "Back..", SENDER_BACK, 0);
  1127. +                player->SEND_GOSSIP_MENU(DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
  1128. +            } break;
  1129. +            default: // Show items you can use
  1130. +            {
  1131. +                if (sender >= MAX_ITEM_QUALITY) // sender = quality, action = iterator
  1132. +                    return false; // cheat
  1133. +
  1134. +                SelectionStore::Selection selection;
  1135. +                if (!TransmogDisplayVendorMgr::selectionStore.GetSelection(player->GetGUID().GetCounter(), selection))
  1136. +                    return false; // cheat
  1137. +                if (selection.offset != 0 || selection.quality != 0)
  1138. +                    return false; // cheat (something is off)
  1139. +
  1140. +                selection.offset = action;
  1141. +                selection.quality = sender;
  1142. +                uint32 slot = selection.slot; // slot
  1143. +                TransmogDisplayVendorMgr::selectionStore.SetSelection(player->GetGUID().GetCounter(), selection);
  1144. +
  1145. +                if (const ItemTemplate* itemTemplate = sObjectMgr->GetItemTemplate(selection.item))
  1146. +                {
  1147. +                    if (!TransmogDisplayVendorMgr::SuitableForTransmogrification(player, itemTemplate))
  1148. +                    {
  1149. +                        player->GetSession()->SendNotification("Equipped item is not suitable for transmogrification");
  1150. +                        OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot);
  1151. +                        return true;
  1152. +                    }
  1153. +
  1154. +                    // {{entry}, {entry}, ...}
  1155. +                    std::list<uint32> L;
  1156. +                    uint32 counter = 0;
  1157. +                    bool over = false;
  1158. +                    if (itemTemplate->Class != ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedArmorTypes)
  1159. +                    {
  1160. +                        for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_ARMOR; ++i)
  1161. +                        {
  1162. +                            const TransmogDisplayVendorMgr::EntryVector* oM = TransmogDisplayVendorMgr::optionMap[MAX_ITEM_SUBCLASS_WEAPON + i][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)][selection.quality];
  1163. +                            if (!oM)
  1164. +                                continue;
  1165. +                            if (!over && counter + oM->size() < selection.offset)
  1166. +                            {
  1167. +                                counter += oM->size();
  1168. +                            }
  1169. +                            else
  1170. +                            {
  1171. +                                over = true;
  1172. +                                L.insert(L.end(), oM->begin(), oM->end());
  1173. +                            }
  1174. +                        }
  1175. +                    }
  1176. +                    else if (itemTemplate->Class == ITEM_CLASS_WEAPON && TransmogDisplayVendorMgr::AllowMixedWeaponTypes)
  1177. +                    {
  1178. +                        for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON; ++i)
  1179. +                        {
  1180. +                            const TransmogDisplayVendorMgr::EntryVector* oM = TransmogDisplayVendorMgr::optionMap[i][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)][selection.quality];
  1181. +                            if (!oM)
  1182. +                                continue;
  1183. +                            if (!over && counter + oM->size() < selection.offset)
  1184. +                                counter += oM->size();
  1185. +                            else
  1186. +                            {
  1187. +                                over = true;
  1188. +                                L.insert(L.end(), oM->begin(), oM->end());
  1189. +                            }
  1190. +                        }
  1191. +                    }
  1192. +                    else
  1193. +                    {
  1194. +                        const TransmogDisplayVendorMgr::EntryVector* oM = TransmogDisplayVendorMgr::optionMap[(itemTemplate->Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itemTemplate->SubClass][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)][selection.quality];
  1195. +                        if (oM)
  1196. +                        {
  1197. +                            if (!over && counter + oM->size() < selection.offset)
  1198. +                            {
  1199. +                                counter += oM->size();
  1200. +                            }
  1201. +                            else
  1202. +                            {
  1203. +                                over = true;
  1204. +                                L.insert(L.end(), oM->begin(), oM->end());
  1205. +                            }
  1206. +                        }
  1207. +                    }
  1208. +
  1209. +                    // TransmogDisplayVendorMgr::EntryVector oM = TransmogDisplayVendorMgr::optionMap[(itemTemplate->Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itemTemplate->SubClass][TransmogDisplayVendorMgr::getCorrectInvType(itemTemplate->InventoryType)][selection.quality];
  1210. +                    uint32 itemCount = L.size() - (selection.offset - counter);
  1211. +                    if (itemCount > MAX_VENDOR_ITEMS)
  1212. +                        itemCount = MAX_VENDOR_ITEMS;
  1213. +
  1214. +                    if (!itemCount)
  1215. +                    {
  1216. +                        session->SendAreaTriggerMessage("No items found");
  1217. +                        OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot);
  1218. +                        return true;
  1219. +                    }
  1220. +                    player->CLOSE_GOSSIP_MENU();
  1221. +
  1222. +                    TC_LOG_DEBUG("network", "WORLD: Sent SMSG_LIST_INVENTORY");
  1223. +
  1224. +                    Creature* vendor = player->GetNPCIfCanInteractWith(creature->GetGUID(), UNIT_NPC_FLAG_VENDOR);
  1225. +                    if (!vendor)
  1226. +                    {
  1227. +                        TC_LOG_DEBUG("network", "WORLD: SendListInventory - Unit (GUID: %u) not found or you can not interact with him.", creature->GetGUID().GetCounter());
  1228. +                        player->SendSellError(SELL_ERR_CANT_FIND_VENDOR, NULL, ObjectGuid::Empty, 0);
  1229. +                        return true;
  1230. +                    }
  1231. +
  1232. +                    if (player->HasUnitState(UNIT_STATE_DIED))
  1233. +                        player->RemoveAurasByType(SPELL_AURA_FEIGN_DEATH);
  1234. +
  1235. +                    if (vendor->HasUnitState(UNIT_STATE_MOVING))
  1236. +                        vendor->StopMoving();
  1237. +
  1238. +                    uint8 count = 0;
  1239. +
  1240. +                    WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + itemCount * 8 * 4);
  1241. +                    data << uint64(creature->GetGUID());
  1242. +
  1243. +                    size_t countPos = data.wpos();
  1244. +                    data << uint8(count);
  1245. +
  1246. +                    uint32 item_amount = 0;
  1247. +                    std::list<uint32>::const_iterator it = L.begin();
  1248. +                    std::advance(it, (selection.offset - counter));
  1249. +                    for (; it != L.end() && count < itemCount; ++it, ++count)
  1250. +                    {
  1251. +                        if (ItemTemplate const* curtemp = sObjectMgr->GetItemTemplate(*it))
  1252. +                        {
  1253. +                            if (!TransmogDisplayVendorMgr::CanTransmogrifyItemWithItem(player, itemTemplate, curtemp))
  1254. +                                continue;
  1255. +
  1256. +                            data << uint32(count + 1);
  1257. +                            data << uint32(curtemp->ItemId);
  1258. +                            data << uint32(curtemp->DisplayInfoID);
  1259. +                            data << int32(0xFFFFFFFF);
  1260. +                            data << uint32(0);
  1261. +                            data << uint32(curtemp->MaxDurability);
  1262. +                            data << uint32(curtemp->BuyCount);
  1263. +                            data << uint32(0);
  1264. +                            ++item_amount;
  1265. +                        }
  1266. +                    }
  1267. +
  1268. +                    if (!item_amount)
  1269. +                    {
  1270. +                        session->SendAreaTriggerMessage("No transmogrifications found for equipped item");
  1271. +                        OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot);
  1272. +                        return true;
  1273. +                    }
  1274. +                    else
  1275. +                    {
  1276. +                        data.put<uint8>(countPos, item_amount);
  1277. +                        session->SendPacket(&data);
  1278. +                    }
  1279. +                }
  1280. +                else
  1281. +                {
  1282. +                    session->SendNotification("Invalid item equipped");
  1283. +                    OnGossipSelect(player, creature, SENDER_SELECT_VENDOR, slot);
  1284. +                    return true;
  1285. +                }
  1286. +            } break;
  1287. +        }
  1288. +        return true;
  1289. +    }
  1290. +};
  1291. +
  1292. +#if !TRANSMOGRIFICATION_ALREADY_INSTALLED
  1293. +class Player_Transmogrify : public PlayerScript
  1294. +{
  1295. +public:
  1296. +    Player_Transmogrify() : PlayerScript("Player_Transmogrify") { }
  1297. +
  1298. +    std::vector<ObjectGuid> GetItemList(const Player* player) const
  1299. +    {
  1300. +        std::vector<ObjectGuid> itemlist;
  1301. +
  1302. +        // Copy paste from Player::GetItemByGuid(guid)
  1303. +
  1304. +        for (uint8 i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_ITEM_END; ++i)
  1305. +            if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  1306. +                itemlist.push_back(pItem->GetGUID());
  1307. +
  1308. +        for (uint8 i = KEYRING_SLOT_START; i < CURRENCYTOKEN_SLOT_END; ++i)
  1309. +            if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  1310. +                itemlist.push_back(pItem->GetGUID());
  1311. +
  1312. +        for (int i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
  1313. +            if (Item* pItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i))
  1314. +                itemlist.push_back(pItem->GetGUID());
  1315. +
  1316. +        for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
  1317. +            if (Bag* pBag = player->GetBagByPos(i))
  1318. +                for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  1319. +                    if (Item* pItem = pBag->GetItemByPos(j))
  1320. +                        itemlist.push_back(pItem->GetGUID());
  1321. +
  1322. +        for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
  1323. +            if (Bag* pBag = player->GetBagByPos(i))
  1324. +                for (uint32 j = 0; j < pBag->GetBagSize(); ++j)
  1325. +                    if (Item* pItem = pBag->GetItemByPos(j))
  1326. +                        itemlist.push_back(pItem->GetGUID());
  1327. +
  1328. +        return itemlist;
  1329. +    }
  1330. +
  1331. +    void OnSave(Player* player) override
  1332. +    {
  1333. +        uint32 lowguid = player->GetGUID().GetCounter();
  1334. +        SQLTransaction trans = CharacterDatabase.BeginTransaction();
  1335. +        trans->PAppend("DELETE FROM `custom_transmogrification` WHERE `Owner` = %u", lowguid);
  1336. +
  1337. +        if (!player->transmogMap.empty())
  1338. +        {
  1339. +            // Only save items that are in inventory / bank / etc
  1340. +            std::vector<ObjectGuid> items = GetItemList(player);
  1341. +            for (std::vector<ObjectGuid>::const_iterator it = items.begin(); it != items.end(); ++it)
  1342. +            {
  1343. +                TransmogMapType::const_iterator it2 = player->transmogMap.find(*it);
  1344. +                if (it2 == player->transmogMap.end())
  1345. +                    continue;
  1346. +
  1347. +                trans->PAppend("REPLACE INTO custom_transmogrification (GUID, FakeEntry, Owner) VALUES (%u, %u, %u)", it2->first.GetCounter(), it2->second, lowguid);
  1348. +            }
  1349. +        }
  1350. +
  1351. +        if (trans->GetSize()) // basically never false
  1352. +            CharacterDatabase.CommitTransaction(trans);
  1353. +    }
  1354. +
  1355. +    void OnLogin(Player* player, bool /*firstLogin*/) override
  1356. +    {
  1357. +        QueryResult result = CharacterDatabase.PQuery("SELECT GUID, FakeEntry FROM custom_transmogrification WHERE Owner = %u", player->GetGUID().GetCounter());
  1358. +
  1359. +        if (result)
  1360. +        {
  1361. +            do
  1362. +            {
  1363. +                Field* field = result->Fetch();
  1364. +                ObjectGuid itemGUID(HighGuid::Item, 0, field[0].GetUInt32());
  1365. +                uint32 fakeEntry = field[1].GetUInt32();
  1366. +                // Only load items that are in inventory / bank / etc
  1367. +                if (sObjectMgr->GetItemTemplate(fakeEntry) && player->GetItemByGuid(itemGUID))
  1368. +                {
  1369. +                    player->transmogMap[itemGUID] = fakeEntry;
  1370. +                }
  1371. +                else
  1372. +                {
  1373. +                    // Ignore, will be erased on next save.
  1374. +                    // Additionally this can happen if an item was deleted from DB but still exists for the player
  1375. +                    // TC_LOG_ERROR("custom.transmog", "Item entry (Entry: %u, itemGUID: %u, playerGUID: %u) does not exist, ignoring.", fakeEntry, GUID_LOPART(itemGUID), player->GetGUID().GetCounter());
  1376. +                    // CharacterDatabase.PExecute("DELETE FROM custom_transmogrification WHERE FakeEntry = %u", fakeEntry);
  1377. +                }
  1378. +            } while (result->NextRow());
  1379. +
  1380. +            if (!player->transmogMap.empty())
  1381. +            {
  1382. +                for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
  1383. +                {
  1384. +                    if (Item* item = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
  1385. +                    {
  1386. +                        player->SetVisibleItemSlot(slot, item);
  1387. +                        if (player->IsInWorld())
  1388. +                            item->SendUpdateToPlayer(player);
  1389. +                    }
  1390. +                }
  1391. +            }
  1392. +        }
  1393. +    }
  1394. +
  1395. +    void OnLogout(Player* player) override
  1396. +    {
  1397. +        TransmogDisplayVendorMgr::selectionStore.RemoveSelection(player->GetGUID().GetCounter());
  1398. +    }
  1399. +};
  1400. +#endif
  1401. +
  1402. +class PREP_TransmogDisplayVendor : public WorldScript
  1403. +{
  1404. +public:
  1405. +    PREP_TransmogDisplayVendor() : WorldScript("PREP_TransmogDisplayVendor") { }
  1406. +
  1407. +    void OnStartup() override
  1408. +    {
  1409. +        for (uint32 v : TransmogDisplayVendorMgr::AllowedItems)
  1410. +            TransmogDisplayVendorMgr::Allowed.push_back(v);
  1411. +        for (uint32 v : TransmogDisplayVendorMgr::NotAllowedItems)
  1412. +            TransmogDisplayVendorMgr::NotAllowed.push_back(v);
  1413. +
  1414. +        TC_LOG_INFO("server.loading", "Creating a list of usable transmogrification entries...");
  1415. +        // initialize .. for reload in future?
  1416. +        for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON + MAX_ITEM_SUBCLASS_ARMOR; ++i)
  1417. +            for (uint32 j = 0; j < MAX_INVTYPE; ++j)
  1418. +                for (uint32 k = 0; k < MAX_ITEM_QUALITY; ++k)
  1419. +                    delete TransmogDisplayVendorMgr::optionMap[i][j][k], TransmogDisplayVendorMgr::optionMap[i][j][k] = NULL;
  1420. +
  1421. +        std::unordered_set<uint32> displays;
  1422. +        ItemTemplateContainer const* its = sObjectMgr->GetItemTemplateStore();
  1423. +        for (ItemTemplateContainer::const_iterator itr = its->begin(); itr != its->end(); ++itr)
  1424. +        {
  1425. +            if (itr->second.Class != ITEM_CLASS_WEAPON && itr->second.Class != ITEM_CLASS_ARMOR)
  1426. +                continue;
  1427. +            if (!TransmogDisplayVendorMgr::SuitableForTransmogrification(NULL, &itr->second))
  1428. +                continue;
  1429. +            if (displays.find(itr->second.DisplayInfoID) != displays.end()) // skip duplicate item displays
  1430. +                continue;
  1431. +            TransmogDisplayVendorMgr::EntryVector* oM = TransmogDisplayVendorMgr::optionMap[(itr->second.Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itr->second.SubClass][TransmogDisplayVendorMgr::getCorrectInvType(itr->second.InventoryType)][itr->second.Quality];
  1432. +            if (!oM)
  1433. +            {
  1434. +                oM = new TransmogDisplayVendorMgr::EntryVector();
  1435. +                TransmogDisplayVendorMgr::optionMap[(itr->second.Class != ITEM_CLASS_WEAPON ? MAX_ITEM_SUBCLASS_WEAPON : 0) + itr->second.SubClass][TransmogDisplayVendorMgr::getCorrectInvType(itr->second.InventoryType)][itr->second.Quality] = oM;
  1436. +            }
  1437. +            if (oM->size() < MAX_VENDOR_ITEMS * 3)
  1438. +            {
  1439. +                oM->push_back(itr->second.ItemId);
  1440. +                displays.insert(itr->second.DisplayInfoID);
  1441. +            }
  1442. +            else
  1443. +            {
  1444. +                TC_LOG_INFO("server.loading", "Too many items for transmogrification: Class: %u SubClass: %u InventoryType: %u Quality: %u", itr->second.Class, itr->second.SubClass, TransmogDisplayVendorMgr::getCorrectInvType(itr->second.InventoryType), itr->second.Quality);
  1445. +            }
  1446. +        }
  1447. +
  1448. +        // resize entry lists
  1449. +        for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON + MAX_ITEM_SUBCLASS_ARMOR; ++i)
  1450. +            for (uint32 j = 0; j < MAX_INVTYPE; ++j)
  1451. +                for (uint32 k = 0; k < MAX_ITEM_QUALITY; ++k)
  1452. +                    if (TransmogDisplayVendorMgr::optionMap[i][j][k])
  1453. +                        TransmogDisplayVendorMgr::optionMap[i][j][k]->resize(TransmogDisplayVendorMgr::optionMap[i][j][k]->size());
  1454. +
  1455. +#if !TRANSMOGRIFICATION_ALREADY_INSTALLED
  1456. +        TC_LOG_INFO("custom.transmog", "Deleting non-existing transmogrification entries...");
  1457. +        CharacterDatabase.DirectExecute("DELETE FROM custom_transmogrification WHERE NOT EXISTS (SELECT 1 FROM item_instance WHERE item_instance.guid = custom_transmogrification.GUID)");
  1458. +#endif
  1459. +    }
  1460. +
  1461. +    void OnShutdown() override
  1462. +    {
  1463. +        for (uint32 i = 0; i < MAX_ITEM_SUBCLASS_WEAPON + MAX_ITEM_SUBCLASS_ARMOR; ++i)
  1464. +            for (uint32 j = 0; j < MAX_INVTYPE; ++j)
  1465. +                for (uint32 k = 0; k < MAX_ITEM_QUALITY; ++k)
  1466. +                    delete TransmogDisplayVendorMgr::optionMap[i][j][k], TransmogDisplayVendorMgr::optionMap[i][j][k] = NULL;
  1467. +    }
  1468. +};
  1469. +
  1470. +void AddSC_NPC_TransmogDisplayVendor()
  1471. +{
  1472. +    new NPC_TransmogDisplayVendor();
  1473. +    new PREP_TransmogDisplayVendor();
  1474. +
  1475. +#if !TRANSMOGRIFICATION_ALREADY_INSTALLED
  1476. +    new Player_Transmogrify();
  1477. +#endif
  1478. +}
  1479. diff --git a/src/server/scripts/Custom/TransmogDisplayVendor/sql/characters.sql b/src/server/scripts/Custom/TransmogDisplayVendor/sql/characters.sql
  1480. new file mode 100644
  1481. index 0000000..4529815
  1482. --- /dev/null
  1483. +++ b/src/server/scripts/Custom/TransmogDisplayVendor/sql/characters.sql
  1484. @@ -0,0 +1,37 @@
  1485. +-- --------------------------------------------------------
  1486. +-- Host:                         localhost
  1487. +-- Server version:               5.5.39 - MySQL Community Server (GPL)
  1488. +-- Server OS:                    Win32
  1489. +-- HeidiSQL Version:             9.1.0.4894
  1490. +-- --------------------------------------------------------
  1491. +
  1492. +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
  1493. +/*!40101 SET NAMES utf8mb4 */;
  1494. +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
  1495. +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
  1496. +
  1497. +-- Dumping structure for table tc_c.custom_transmogrification
  1498. +CREATE TABLE IF NOT EXISTS `custom_transmogrification` (
  1499. +  `GUID` int(10) unsigned NOT NULL COMMENT 'Item guidLow',
  1500. +  `FakeEntry` int(10) unsigned NOT NULL COMMENT 'Item entry',
  1501. +  `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidLow',
  1502. +  PRIMARY KEY (`GUID`),
  1503. +  KEY `Owner` (`Owner`)
  1504. +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_2';
  1505. +
  1506. +-- Data exporting was unselected.
  1507. +
  1508. +
  1509. +-- Dumping structure for table tc_c.custom_transmogrification_sets
  1510. +CREATE TABLE IF NOT EXISTS `custom_transmogrification_sets` (
  1511. +  `Owner` int(10) unsigned NOT NULL COMMENT 'Player guidlow',
  1512. +  `PresetID` tinyint(3) unsigned NOT NULL COMMENT 'Preset identifier',
  1513. +  `SetName` text COMMENT 'SetName',
  1514. +  `SetData` text COMMENT 'Slot1 Entry1 Slot2 Entry2',
  1515. +  PRIMARY KEY (`Owner`,`PresetID`)
  1516. +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_1';
  1517. +
  1518. +-- Data exporting was unselected.
  1519. +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
  1520. +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
  1521. +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
  1522. diff --git a/src/server/scripts/Custom/TransmogDisplayVendor/sql/updates/characters_update_6_1_to_6_2.sql b/src/server/scripts/Custom/TransmogDisplayVendor/sql/updates/characters_update_6_1_to_6_2.sql
  1523. new file mode 100644
  1524. index 0000000..0e675b5
  1525. --- /dev/null
  1526. +++ b/src/server/scripts/Custom/TransmogDisplayVendor/sql/updates/characters_update_6_1_to_6_2.sql
  1527. @@ -0,0 +1,3 @@
  1528. +ALTER TABLE `custom_transmogrification`
  1529. +   COMMENT='6_2',
  1530. +   COLLATE='utf8_general_ci';
  1531. diff --git a/src/server/scripts/Custom/TransmogDisplayVendor/sql/world_NPC.sql b/src/server/scripts/Custom/TransmogDisplayVendor/sql/world_NPC.sql
  1532. new file mode 100644
  1533. index 0000000..353e593
  1534. --- /dev/null
  1535. +++ b/src/server/scripts/Custom/TransmogDisplayVendor/sql/world_NPC.sql
  1536. @@ -0,0 +1,6 @@
  1537. +SET
  1538. +@Entry = 190011,
  1539. +@Name = "Narpweaver";
  1540. +
  1541. +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
  1542. +(@Entry, 19646, 0, @Name, "Transmogrifier", NULL, 0, 80, 80, 2, 35, 129, 1, 0, 0, 2000, 0, 1, 0, 7, 138936390, 0, 0, 0, '', 0, 3, 1, 0, 0, 1, 0, 0, 'NPC_TransmogDisplayVendor');
  1543. diff --git a/src/server/scripts/Custom/custom_script_loader.cpp b/src/server/scripts/Custom/custom_script_loader.cpp
  1544. index dd4b5e9..0ea2524 100644
  1545. --- a/src/server/scripts/Custom/custom_script_loader.cpp
  1546. +++ b/src/server/scripts/Custom/custom_script_loader.cpp
  1547. @@ -16,10 +16,12 @@
  1548.   */
  1549.  
  1550.  // This is where scripts' loading functions should be declared:
  1551. +void AddSC_NPC_TransmogDisplayVendor();
  1552.  
  1553.  
  1554.  // The name of this function should match:
  1555.  // void Add${NameOfDirectory}Scripts()
  1556.  void AddCustomScripts()
  1557.  {
  1558. +    AddSC_NPC_TransmogDisplayVendor();
  1559.  }
  1560. diff --git a/src/server/scripts/Spells/spell_generic.cpp b/src/server/scripts/Spells/spell_generic.cpp
  1561. index 8b8c530..fdd939d 100644
  1562. --- a/src/server/scripts/Spells/spell_generic.cpp
  1563. +++ b/src/server/scripts/Spells/spell_generic.cpp
  1564. @@ -22,6 +22,7 @@
  1565.   * Scriptnames of files in this file should be prefixed with "spell_gen_"
  1566.   */
  1567.  
  1568. +#include "TransmogDisplayVendorConf.h"
  1569.  #include "ScriptMgr.h"
  1570.  #include "Battleground.h"
  1571.  #include "Cell.h"
  1572. @@ -861,7 +862,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
  1573.                          if (Player* player = caster->ToPlayer())
  1574.                          {
  1575.                              if (Item* mainItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_MAINHAND))
  1576. -                                target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
  1577. +                            {
  1578. +                                if (uint32 entry = TransmogDisplayVendorMgr::GetFakeEntry(mainItem))
  1579. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, entry);
  1580. +                                else
  1581. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, mainItem->GetEntry());
  1582. +                            }
  1583.                          }
  1584.                          else
  1585.                              target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID));
  1586. @@ -875,7 +881,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
  1587.                          if (Player* player = caster->ToPlayer())
  1588.                          {
  1589.                              if (Item* offItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_OFFHAND))
  1590. -                                target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, offItem->GetEntry());
  1591. +                            {
  1592. +                                if (uint32 entry = TransmogDisplayVendorMgr::GetFakeEntry(offItem))
  1593. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, entry);
  1594. +                                else
  1595. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, offItem->GetEntry());
  1596. +                            }
  1597.                          }
  1598.                          else
  1599.                              target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 1));
  1600. @@ -888,7 +899,12 @@ class spell_gen_clone_weapon_aura : public SpellScriptLoader
  1601.                          if (Player* player = caster->ToPlayer())
  1602.                          {
  1603.                              if (Item* rangedItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, EQUIPMENT_SLOT_RANGED))
  1604. -                                target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, rangedItem->GetEntry());
  1605. +                            {
  1606. +                                if (uint32 entry = TransmogDisplayVendorMgr::GetFakeEntry(rangedItem))
  1607. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, entry);
  1608. +                                else
  1609. +                                    target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, rangedItem->GetEntry());
  1610. +                            }
  1611.                          }
  1612.                          else
  1613.                              target->SetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2, caster->GetUInt32Value(UNIT_VIRTUAL_ITEM_SLOT_ID + 2));
Advertisement
Add Comment
Please, Sign In to add comment