mirror of
https://github.com/araxiaonline/mod-transmog.git
synced 2026-06-13 02:32:22 -04:00
Merge branch 'master' of https://github.com/azerothcore/mod-transmog
This commit is contained in:
@@ -18,11 +18,24 @@
|
||||
# If disabled, players must have an item in their bags to use as a transmogrification appearance source.
|
||||
# Default: 1
|
||||
#
|
||||
# Transmogrification.UseVendorInterface
|
||||
# Description: Enables/Disables the use of a fake vendor interface for item selection.
|
||||
# There are (optional) custom items available for Hide Item and Remove Transmog if data/sql/db-world/tasm_world_VendorItems.sql is imported.
|
||||
# If enabled, players can select items from a vendor menu, complete with ctrl-click previews.
|
||||
# If disabled, players will use the gossip menu to select items and will not have access to previews.
|
||||
# Default: 0
|
||||
#
|
||||
# Transmogrification.AllowHiddenTransmog
|
||||
# Description: Enables/Disables the hiding of equipment through transmog
|
||||
# If enabled, players can select an "invisible" appearance for items at the transmog vendor
|
||||
# Default: 1
|
||||
#
|
||||
# Transmogrification.HiddenTransmogIsFree
|
||||
# Description: Enables/Disables free hiding of items through the transmog system.
|
||||
# If enabled, players can hide pieces of equipment for free.
|
||||
# If disabled, players will be charged the standard transmog price (affected by all modifiers) to hide an item.
|
||||
# Default: 1
|
||||
#
|
||||
# Transmogrification.TrackUnusableItems
|
||||
# Description: If enabled, appearances are collected even for items that are not suitable for transmogrification.
|
||||
# This allows these appearances to be used later if the configuration is changed.
|
||||
@@ -59,10 +72,17 @@
|
||||
# Transmogrification.EnablePortable
|
||||
# Description: Enables / Disables the portable transmogrification NPC.
|
||||
# Default: 1
|
||||
#
|
||||
# Transmogrification.EnableSortByQualityAndName
|
||||
# Description: Enables / Disables the sorting of the items by quality and then by names
|
||||
# Default: 1
|
||||
#
|
||||
|
||||
Transmogrification.Enable = 1
|
||||
Transmogrification.UseCollectionSystem = 1
|
||||
Transmogrification.UseVendorInterface = 0
|
||||
Transmogrification.AllowHiddenTransmog = 1
|
||||
Transmogrification.HiddenTransmogIsFree = 1
|
||||
Transmogrification.TrackUnusableItems = 1
|
||||
Transmogrification.RetroActiveAppearances = 1
|
||||
Transmogrification.ResetRetroActiveAppearancesFlag = 0
|
||||
@@ -75,6 +95,8 @@ Transmogrification.NotAllowed = ""
|
||||
|
||||
Transmogrification.EnablePortable = 1
|
||||
|
||||
Transmogrification.EnableSortByQualityAndName = 1
|
||||
|
||||
#
|
||||
# COPPER COST
|
||||
#
|
||||
@@ -205,6 +227,7 @@ Transmogrification.TokenAmount = 1
|
||||
# Description: Ignore stat count > 0 requirement for source items
|
||||
# Default: 0
|
||||
|
||||
|
||||
Transmogrification.AllowPoor = 0
|
||||
Transmogrification.AllowCommon = 0
|
||||
Transmogrification.AllowUncommon = 1
|
||||
|
||||
4
data/sql/db-auth/acore_cms_subscriptions.sql
Normal file
4
data/sql/db-auth/acore_cms_subscriptions.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
CREATE TABLE IF NOT EXISTS `acore_cms_subscriptions` (
|
||||
`account_name` VARCHAR(255) NOT NULL,
|
||||
`membership_level` INT NOT NULL
|
||||
);
|
||||
30
data/sql/db-world/trasm_world_VendorItems.sql
Normal file
30
data/sql/db-world/trasm_world_VendorItems.sql
Normal file
@@ -0,0 +1,30 @@
|
||||
SET
|
||||
@HideEntry = 57575,
|
||||
@RemoveEntry = 57576,
|
||||
@HideName = "Hide Equipped",
|
||||
@RemoveName = "Clear Transmog";
|
||||
|
||||
DELETE FROM `item_template` WHERE `entry` = @HideEntry OR `entry` = @RemoveEntry;
|
||||
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `name`, `displayid`, `InventoryType`, `description`) VALUES
|
||||
(@HideEntry, 15, 0, @HideName, 55112, 0, "Hide the item in this slot."),
|
||||
(@RemoveEntry, 15, 0, @RemoveName, 8931, 0, "Remove active transmog for this item.");
|
||||
|
||||
DELETE FROM `item_template_locale` WHERE `ID` = @HideEntry OR `ID` = @RemoveEntry;
|
||||
INSERT INTO `item_template_locale` (`ID`, `locale`, `Name`, `Description`) VALUES
|
||||
(@HideEntry, "koKR", "장착된 아이템 숨기기", "이 슬롯의 아이템을 숨깁니다."),
|
||||
(@RemoveEntry,"koKR", "변형 지우기", "이 아이템의 활성화된 변형을 제거합니다."),
|
||||
(@HideEntry, "frFR", "Masquer l'équipement", "Masquer l'objet dans cet emplacement."),
|
||||
(@RemoveEntry,"frFR", "Effacer transmog", "Supprimer la transmog active."),
|
||||
(@HideEntry, "deDE", "Ausgerüstet verbergen", "Item in diesem Slot verbergen."),
|
||||
(@RemoveEntry,"deDE", "Transmog zurücksetzen", "Aktive Transmogrifikation entfernen."),
|
||||
(@HideEntry, "zhCN", "隐藏已装备", "隐藏此物品。"),
|
||||
(@RemoveEntry,"zhCN", "清除幻化", "移除激活的幻化。"),
|
||||
(@HideEntry, "zhTW", "隱藏已裝備", "隱藏此物品。"),
|
||||
(@RemoveEntry,"zhTW", "清除幻化", "移除啟用的幻化。"),
|
||||
(@HideEntry, "esES", "Ocultar equipado", "Ocultar el objeto en esta ranura."),
|
||||
(@RemoveEntry,"esES", "Borrar transmog", "Eliminar la transmog activa."),
|
||||
(@HideEntry, "esMX", "Ocultar equipado", "Ocultar el objeto en este espacio."),
|
||||
(@RemoveEntry,"esMX", "Borrar transmog", "Eliminar la transmog activa."),
|
||||
(@HideEntry, "ruRU", "Скрыть экипированное", "Скрыть предмет в слоте."),
|
||||
(@RemoveEntry,"ruRU", "Очистить трансмог", "Удалить активный трансмог.");
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "Transmogrification.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "SpellMgr.h"
|
||||
#include "Tokenize.h"
|
||||
|
||||
Transmogrification* Transmogrification::instance()
|
||||
@@ -471,7 +472,11 @@ bool Transmogrification::AddCollectedAppearance(uint32 accountId, uint32 itemId)
|
||||
if (std::find(collectionCache[accountId].begin(), collectionCache[accountId].end(), itemId) == collectionCache[accountId].end())
|
||||
{
|
||||
collectionCache[accountId].push_back(itemId);
|
||||
std::sort(collectionCache[accountId].begin(), collectionCache[accountId].end());
|
||||
|
||||
if (!sConfigMgr->GetOption<bool>("Transmogrification.EnableSortByQualityAndName", true)) {
|
||||
std::sort(collectionCache[accountId].begin(), collectionCache[accountId].end());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -521,6 +526,22 @@ TransmogAcoreStrings Transmogrification::Transmogrify(Player* player, Item* item
|
||||
|
||||
if (hidden_transmog)
|
||||
{
|
||||
cost = GetSpecialPrice(itemTransmogrified->GetTemplate());
|
||||
cost *= ScaledCostModifier;
|
||||
cost += CopperCost;
|
||||
|
||||
if (!HiddenTransmogIsFree && cost)
|
||||
{
|
||||
if (cost < 0)
|
||||
LOG_DEBUG("module", "Transmogrification::Transmogrify - {} ({}) transmogrification invalid cost (non negative, amount {}). Transmogrified {} with {}",
|
||||
player->GetName(), player->GetGUID().ToString(), -cost, itemTransmogrified->GetEntry(), itemTransmogrifier->GetEntry());
|
||||
else
|
||||
{
|
||||
if (!player->HasEnoughMoney(cost))
|
||||
return LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY;
|
||||
player->ModifyMoney(-cost, false);
|
||||
}
|
||||
}
|
||||
SetFakeEntry(player, HIDDEN_ITEM_ID, slot, itemTransmogrified); // newEntry
|
||||
return LANG_ERR_TRANSMOG_OK;
|
||||
}
|
||||
@@ -575,7 +596,7 @@ TransmogAcoreStrings Transmogrification::Transmogrify(Player* player, Item* item
|
||||
itemTransmogrified->SetNotRefundable(player);
|
||||
itemTransmogrified->ClearSoulboundTradeable(player);
|
||||
|
||||
if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE)
|
||||
if (itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_EQUIPPED || itemTransmogrifier->GetTemplate()->Bonding == BIND_WHEN_USE)
|
||||
itemTransmogrifier->SetBinding(true);
|
||||
|
||||
itemTransmogrifier->SetOwnerGUID(player->GetGUID());
|
||||
@@ -637,19 +658,19 @@ bool Transmogrification::CanTransmogrifyItemWithItem(Player* player, ItemTemplat
|
||||
bool Transmogrification::IsSubclassMismatchAllowed(Player *player, const ItemTemplate *source, const ItemTemplate *target) const
|
||||
{
|
||||
if (IsAllowed(source->ItemId)) return true;
|
||||
|
||||
|
||||
uint32 sourceType = source->InventoryType;
|
||||
uint32 targetType = target->InventoryType;
|
||||
uint32 sourceClass = source->Class;
|
||||
uint32 targetClass = target->Class;
|
||||
uint32 sourceSub = source->SubClass;
|
||||
uint32 targetSub = target->SubClass;
|
||||
|
||||
|
||||
if (targetClass == ITEM_CLASS_WEAPON)
|
||||
{
|
||||
if (IsRangedWeapon(sourceClass, sourceSub))
|
||||
return true;
|
||||
|
||||
|
||||
if (AllowMixedWeaponTypes == MIXED_WEAPONS_MODERN)
|
||||
{
|
||||
switch (targetSub)
|
||||
@@ -657,8 +678,8 @@ bool Transmogrification::IsSubclassMismatchAllowed(Player *player, const ItemTem
|
||||
case ITEM_SUBCLASS_WEAPON_AXE:
|
||||
case ITEM_SUBCLASS_WEAPON_SWORD:
|
||||
case ITEM_SUBCLASS_WEAPON_MACE:
|
||||
if (sourceSub == ITEM_SUBCLASS_WEAPON_AXE ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_SWORD ||
|
||||
if (sourceSub == ITEM_SUBCLASS_WEAPON_AXE ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_SWORD ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_MACE )
|
||||
return true;
|
||||
break;
|
||||
@@ -667,37 +688,39 @@ bool Transmogrification::IsSubclassMismatchAllowed(Player *player, const ItemTem
|
||||
case ITEM_SUBCLASS_WEAPON_MACE2:
|
||||
case ITEM_SUBCLASS_WEAPON_STAFF:
|
||||
case ITEM_SUBCLASS_WEAPON_POLEARM:
|
||||
if (sourceSub == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_SWORD2 ||
|
||||
if (sourceSub == ITEM_SUBCLASS_WEAPON_AXE2 ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_SWORD2 ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_MACE2 ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_STAFF ||
|
||||
sourceSub == ITEM_SUBCLASS_WEAPON_POLEARM )
|
||||
return true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (sourceSub == ITEM_SUBCLASS_WEAPON_MISC)
|
||||
return sourceType == targetType;
|
||||
}
|
||||
else if (targetClass == ITEM_CLASS_ARMOR)
|
||||
{
|
||||
if (AllowMixedArmorTypes)
|
||||
return true;
|
||||
if (AllowLowerTiers && IsTieredArmorSubclass(targetSub) && TierAvailable(player, 0, sourceSub))
|
||||
if (AllowLowerTiers && IsTieredArmorSubclass(targetSub) && TierAvailable(player, 0, sourceSub))
|
||||
return true;
|
||||
if (AllowMixedOffhandArmorTypes && IsValidOffhandArmor(targetSub, targetType) && IsValidOffhandArmor(sourceSub, sourceType))
|
||||
return true;
|
||||
if (sourceSub == ITEM_SUBCLASS_ARMOR_MISC)
|
||||
return sourceType == targetType;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Transmogrification::IsInvTypeMismatchAllowed(const ItemTemplate *source, const ItemTemplate *target) const
|
||||
{
|
||||
{
|
||||
uint32 sourceType = source->InventoryType;
|
||||
uint32 targetType = target->InventoryType;
|
||||
uint32 sourceClass = source->Class;
|
||||
@@ -709,20 +732,20 @@ bool Transmogrification::IsInvTypeMismatchAllowed(const ItemTemplate *source, co
|
||||
{
|
||||
if (IsRangedWeapon(sourceClass, sourceSub))
|
||||
return true;
|
||||
|
||||
|
||||
// Main-hand to offhand restrictions - see https://wowpedia.fandom.com/wiki/Transmogrification
|
||||
if (targetType == INVTYPE_WEAPONMAINHAND || targetType == INVTYPE_WEAPONOFFHAND)
|
||||
if (AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE)
|
||||
return true;
|
||||
else if (targetType == INVTYPE_WEAPONMAINHAND || targetType == INVTYPE_WEAPONOFFHAND)
|
||||
{
|
||||
if (AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE)
|
||||
return true;
|
||||
if (sourceType == INVTYPE_WEAPONMAINHAND || sourceType == INVTYPE_WEAPONOFFHAND)
|
||||
return (AllowMixedWeaponHandedness || AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE);
|
||||
return AllowMixedWeaponHandedness;
|
||||
if (sourceType == INVTYPE_WEAPON)
|
||||
return true;
|
||||
}
|
||||
else if (targetType == INVTYPE_WEAPON)
|
||||
{
|
||||
return sourceType == INVTYPE_WEAPONMAINHAND || (AllowMixedWeaponTypes == MIXED_WEAPONS_LOOSE && sourceType == INVTYPE_WEAPONOFFHAND);
|
||||
return sourceType == INVTYPE_WEAPONMAINHAND || (AllowMixedWeaponHandedness && sourceType == INVTYPE_WEAPONOFFHAND);
|
||||
}
|
||||
}
|
||||
else if (targetClass == ITEM_CLASS_ARMOR)
|
||||
@@ -732,7 +755,7 @@ bool Transmogrification::IsInvTypeMismatchAllowed(const ItemTemplate *source, co
|
||||
if (targetType == INVTYPE_CHEST || targetType == INVTYPE_ROBE)
|
||||
return sourceType == INVTYPE_CHEST || sourceType == INVTYPE_ROBE;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -764,7 +787,8 @@ bool Transmogrification::SuitableForTransmogrification(Player* player, ItemTempl
|
||||
return false;
|
||||
|
||||
//[AZTH] Yehonal
|
||||
if (proto->SubClass > 0 && player->GetSkillValue(proto->GetSkill()) == 0)
|
||||
uint32 subclassSkill = proto->GetSkill();
|
||||
if (proto->SubClass > 0 && subclassSkill && player->GetSkillValue(proto->GetSkill()) == 0)
|
||||
{
|
||||
if (proto->Class == ITEM_CLASS_ARMOR && !AllowMixedArmorTypes)
|
||||
{
|
||||
@@ -777,10 +801,10 @@ bool Transmogrification::SuitableForTransmogrification(Player* player, ItemTempl
|
||||
}
|
||||
}
|
||||
|
||||
if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && player->GetTeamId() != TEAM_HORDE)
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && player->GetTeamId() != TEAM_HORDE)
|
||||
return false;
|
||||
|
||||
if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && player->GetTeamId() != TEAM_ALLIANCE)
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && player->GetTeamId() != TEAM_ALLIANCE)
|
||||
return false;
|
||||
|
||||
if (!IgnoreReqClass && (proto->AllowableClass & player->getClassMask()) == 0)
|
||||
@@ -866,10 +890,10 @@ bool Transmogrification::SuitableForTransmogrification(ObjectGuid guid, ItemTemp
|
||||
}
|
||||
}
|
||||
|
||||
if ((proto->Flags2 & ITEM_FLAGS_EXTRA_HORDE_ONLY) && playerTeamId != TEAM_HORDE)
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_HORDE) && playerTeamId != TEAM_HORDE)
|
||||
return false;
|
||||
|
||||
if ((proto->Flags2 & ITEM_FLAGS_EXTRA_ALLIANCE_ONLY) && playerTeamId != TEAM_ALLIANCE)
|
||||
if (proto->HasFlag2(ITEM_FLAG2_FACTION_ALLIANCE) && playerTeamId != TEAM_ALLIANCE)
|
||||
return false;
|
||||
|
||||
if (!IgnoreReqClass && (proto->AllowableClass & playerClassMask) == 0)
|
||||
@@ -1124,7 +1148,9 @@ void Transmogrification::LoadConfig(bool reload)
|
||||
IgnoreReqEvent = sConfigMgr->GetOption<bool>("Transmogrification.IgnoreReqEvent", false);
|
||||
IgnoreReqStats = sConfigMgr->GetOption<bool>("Transmogrification.IgnoreReqStats", false);
|
||||
UseCollectionSystem = sConfigMgr->GetOption<bool>("Transmogrification.UseCollectionSystem", true);
|
||||
UseVendorInterface = sConfigMgr->GetOption<bool>("Transmogrification.UseVendorInterface", false);
|
||||
AllowHiddenTransmog = sConfigMgr->GetOption<bool>("Transmogrification.AllowHiddenTransmog", true);
|
||||
HiddenTransmogIsFree = sConfigMgr->GetOption<bool>("Transmogrification.HiddenTransmogIsFree", true);
|
||||
TrackUnusableItems = sConfigMgr->GetOption<bool>("Transmogrification.TrackUnusableItems", true);
|
||||
RetroActiveAppearances = sConfigMgr->GetOption<bool>("Transmogrification.RetroActiveAppearances", true);
|
||||
ResetRetroActiveAppearances = sConfigMgr->GetOption<bool>("Transmogrification.ResetRetroActiveAppearancesFlag", false);
|
||||
@@ -1167,6 +1193,9 @@ void Transmogrification::LoadConfig(bool reload)
|
||||
}
|
||||
|
||||
PetSpellId = sConfigMgr->GetOption<uint32>("Transmogrification.PetSpellId", 2000100);
|
||||
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(PetSpellId))
|
||||
PetEntry = spellInfo->Effects[EFFECT_0].MiscValue;
|
||||
}
|
||||
|
||||
void Transmogrification::DeleteFakeFromDB(ObjectGuid::LowType itemLowGuid, CharacterDatabaseTransaction* trans /*= nullptr*/)
|
||||
@@ -1185,21 +1214,6 @@ void Transmogrification::DeleteFakeFromDB(ObjectGuid::LowType itemLowGuid, Chara
|
||||
CharacterDatabase.Execute("DELETE FROM custom_transmogrification WHERE GUID = {}", itemGUID.GetCounter());
|
||||
}
|
||||
|
||||
uint32 Transmogrification::getPlayerMembershipLevel(ObjectGuid const & playerGuid) const
|
||||
{
|
||||
CharacterCacheEntry const* playerData = sCharacterCache->GetCharacterCacheByGuid(playerGuid);
|
||||
if (!playerData)
|
||||
return 0;
|
||||
|
||||
uint32 accountId = playerData->AccountId;
|
||||
QueryResult resultAcc = LoginDatabase.Query("SELECT `membership_level` FROM `acore_cms_subscriptions` WHERE `account_name` COLLATE utf8mb4_general_ci = (SELECT `username` FROM `account` WHERE `id` = {})", accountId);
|
||||
|
||||
if (resultAcc)
|
||||
return (*resultAcc)[0].Get<uint32>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Transmogrification::IsPlusFeatureEligible(ObjectGuid const &playerGuid, uint32 feature) const
|
||||
{
|
||||
if (!IsTransmogPlusEnabled)
|
||||
@@ -1209,7 +1223,12 @@ bool Transmogrification::IsPlusFeatureEligible(ObjectGuid const &playerGuid, uin
|
||||
if (it == plusDataMap.end() || it->second.empty())
|
||||
return false;
|
||||
|
||||
const auto membershipLevel = getPlayerMembershipLevel(playerGuid);
|
||||
Player* player = ObjectAccessor::FindConnectedPlayer(playerGuid);
|
||||
|
||||
if (!player)
|
||||
return false;
|
||||
|
||||
const auto membershipLevel = GetPlayerMembershipLevel(player);
|
||||
|
||||
if (!membershipLevel)
|
||||
return false;
|
||||
@@ -1280,12 +1299,18 @@ bool Transmogrification::GetUseCollectionSystem() const
|
||||
{
|
||||
return UseCollectionSystem;
|
||||
};
|
||||
|
||||
bool Transmogrification::GetUseVendorInterface() const
|
||||
{
|
||||
return UseVendorInterface;
|
||||
}
|
||||
bool Transmogrification::GetAllowHiddenTransmog() const
|
||||
{
|
||||
return AllowHiddenTransmog;
|
||||
}
|
||||
|
||||
bool Transmogrification::GetHiddenTransmogIsFree() const
|
||||
{
|
||||
return HiddenTransmogIsFree;
|
||||
}
|
||||
bool Transmogrification::GetAllowTradeable() const
|
||||
{
|
||||
return AllowTradeable;
|
||||
|
||||
@@ -27,8 +27,11 @@ struct ItemTemplate;
|
||||
|
||||
enum TransmogSettings
|
||||
{
|
||||
SETTING_HIDE_TRANSMOG = 0,
|
||||
SETTING_RETROACTIVE_CHECK = 1
|
||||
SETTING_HIDE_TRANSMOG = 0,
|
||||
SETTING_RETROACTIVE_CHECK = 1,
|
||||
|
||||
// Subscriptions
|
||||
SETTING_TRANSMOG_MEMBERSHIP_LEVEL = 0
|
||||
};
|
||||
|
||||
enum MixedWeaponSettings
|
||||
@@ -95,6 +98,8 @@ enum PlusFeatures
|
||||
PLUS_FEATURE_SKIP_LEVEL_REQ
|
||||
};
|
||||
|
||||
const uint32 TMOG_VENDOR_CREATURE_ID = 190010;
|
||||
|
||||
class Transmogrification
|
||||
{
|
||||
public:
|
||||
@@ -106,10 +111,13 @@ public:
|
||||
typedef std::unordered_map<uint32, std::vector<uint32>> collectionCacheMap;
|
||||
typedef std::unordered_map<uint32, std::string> searchStringMap;
|
||||
typedef std::unordered_map<uint32, std::vector<uint32>> transmogPlusData;
|
||||
typedef std::unordered_map<ObjectGuid, uint8> selectedSlotMap;
|
||||
|
||||
transmogPlusData plusDataMap;
|
||||
transmogMap entryMap; // entryMap[pGUID][iGUID] = entry
|
||||
transmogData dataMap; // dataMap[iGUID] = pGUID
|
||||
collectionCacheMap collectionCache;
|
||||
selectedSlotMap selectionCache;
|
||||
|
||||
#ifdef PRESETS
|
||||
bool EnableSetInfo;
|
||||
@@ -131,8 +139,6 @@ public:
|
||||
float SetCostModifier;
|
||||
int32 SetCopperCost;
|
||||
|
||||
uint32 PetSpellId;
|
||||
|
||||
bool GetEnableSets() const;
|
||||
uint8 GetMaxSets() const;
|
||||
float GetSetCostModifier() const;
|
||||
@@ -184,7 +190,11 @@ public:
|
||||
bool IgnoreReqStats;
|
||||
|
||||
bool UseCollectionSystem;
|
||||
bool UseVendorInterface;
|
||||
|
||||
bool AllowHiddenTransmog;
|
||||
bool HiddenTransmogIsFree;
|
||||
|
||||
bool TrackUnusableItems;
|
||||
bool RetroActiveAppearances;
|
||||
bool ResetRetroActiveAppearances;
|
||||
@@ -241,7 +251,9 @@ public:
|
||||
bool GetAllowTradeable() const;
|
||||
|
||||
bool GetUseCollectionSystem() const;
|
||||
bool GetUseVendorInterface() const;
|
||||
bool GetAllowHiddenTransmog() const;
|
||||
bool GetHiddenTransmogIsFree() const;
|
||||
bool GetTrackUnusableItems() const;
|
||||
bool EnableRetroActiveAppearances() const;
|
||||
bool EnableResetRetroActiveAppearances() const;
|
||||
@@ -261,10 +273,12 @@ public:
|
||||
// Transmog Plus
|
||||
bool IsTransmogPlusEnabled;
|
||||
[[nodiscard]] bool IsPlusFeatureEligible(ObjectGuid const& playerGuid, uint32 feature) const;
|
||||
uint32 getPlayerMembershipLevel(ObjectGuid const & playerGuid) const;
|
||||
|
||||
[[nodiscard]] uint32 GetPlayerMembershipLevel(Player* player) const { return player->GetPlayerSetting("acore_cms_subscriptions", SETTING_TRANSMOG_MEMBERSHIP_LEVEL).value; };
|
||||
[[nodiscard]] bool IgnoreLevelRequirement(ObjectGuid const& playerGuid) const { return IgnoreReqLevel || IsPlusFeatureEligible(playerGuid, PLUS_FEATURE_SKIP_LEVEL_REQ); }
|
||||
|
||||
uint32 PetSpellId;
|
||||
uint32 PetEntry;
|
||||
[[nodiscard]] bool IsTransmogVendor(uint32 entry) const { return entry == TMOG_VENDOR_CREATURE_ID || entry == PetEntry; };
|
||||
};
|
||||
#define sTransmogrification Transmogrification::instance()
|
||||
|
||||
|
||||
@@ -59,10 +59,10 @@ public:
|
||||
Player* player = handler->GetPlayer();
|
||||
uint32 accountId = player->GetSession()->GetAccountId();
|
||||
handler->SendSysMessage(LANG_CMD_TRANSMOG_BEGIN_SYNC);
|
||||
|
||||
for (uint32 itemId : sTransmogrification->collectionCache[accountId])
|
||||
{
|
||||
handler->PSendSysMessage("TRANSMOG_SYNC:%u", itemId);
|
||||
}
|
||||
handler->PSendSysMessage("TRANSMOG_SYNC:{}", itemId);
|
||||
|
||||
handler->SendSysMessage(LANG_CMD_TRANSMOG_COMPLETE_SYNC);
|
||||
return true;
|
||||
}
|
||||
@@ -158,15 +158,11 @@ public:
|
||||
{
|
||||
// Notify target of new item in appearance collection
|
||||
if (target && !(target->GetPlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG).value) && !sTransmogrification->CanNeverTransmog(itemTemplate))
|
||||
{
|
||||
ChatHandler(target->GetSession()).PSendSysMessage(R"(|c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r has been added to your appearance collection.)", itemQuality.c_str(), itemId, itemName.c_str());
|
||||
}
|
||||
ChatHandler(target->GetSession()).PSendSysMessage(R"(|c{}|Hitem:{}:0:0:0:0:0:0:0:0|h[{}]|h|r has been added to your appearance collection.)", itemQuality.c_str(), itemId, itemName.c_str());
|
||||
|
||||
// Feedback of successful command execution to GM
|
||||
if (isNotConsole && target != handler->GetPlayer())
|
||||
{
|
||||
handler->PSendSysMessage(R"(|c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r has been added to the appearance collection of Player %s.)", itemQuality.c_str(), itemId, itemName.c_str(), nameLink);
|
||||
}
|
||||
handler->PSendSysMessage(R"(|c{}|Hitem:{}:0:0:0:0:0:0:0:0|h[{}]|h|r has been added to the appearance collection of Player {}.)", itemQuality.c_str(), itemId, itemName.c_str(), nameLink);
|
||||
|
||||
CharacterDatabase.Execute("INSERT INTO custom_unlocked_appearances (account_id, item_template_id) VALUES ({}, {})", accountId, itemId);
|
||||
}
|
||||
@@ -175,7 +171,7 @@ public:
|
||||
// Feedback of failed command execution to GM
|
||||
if (isNotConsole)
|
||||
{
|
||||
handler->PSendSysMessage(R"(Player %s already has item |c%s|Hitem:%u:0:0:0:0:0:0:0:0|h[%s]|h|r in the appearance collection.)", nameLink, itemQuality.c_str(), itemId, itemName.c_str());
|
||||
handler->PSendSysMessage(R"(Player {} already has item |c{}|Hitem:{}:0:0:0:0:0:0:0:0|h[{}]|h|r in the appearance collection.)", nameLink, itemQuality.c_str(), itemId, itemName.c_str());
|
||||
handler->SetSentErrorMessage(true);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +270,7 @@ public:
|
||||
// Failed command execution
|
||||
if (!added)
|
||||
{
|
||||
handler->PSendSysMessage("Player %s already has ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r in the appearance collection.", nameLink, uint32(itemSetId), setName.c_str(), localeNames[locale]);
|
||||
handler->PSendSysMessage("Player {} already has ItemSet |cffffffff|Hitemset:{}|h[{} {}]|h|r in the appearance collection.", nameLink, uint32(itemSetId), setName.c_str(), localeNames[locale]);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return true;
|
||||
}
|
||||
@@ -282,14 +278,14 @@ public:
|
||||
// Successful command execution
|
||||
if (target != handler->GetPlayer())
|
||||
{
|
||||
handler->PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r has been added to the appearance collection of Player %s.", uint32(itemSetId), setName.c_str(), localeNames[locale], nameLink);
|
||||
handler->PSendSysMessage("ItemSet |cffffffff|Hitemset:{}|h[{} {}]|h|r has been added to the appearance collection of Player {}.", uint32(itemSetId), setName.c_str(), localeNames[locale], nameLink);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify target of new item in appearance collection
|
||||
if (target && !(target->GetPlayerSetting("mod-transmog", SETTING_HIDE_TRANSMOG).value))
|
||||
{
|
||||
ChatHandler(target->GetSession()).PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[%s %s]|h|r has been added to your appearance collection.", uint32(itemSetId), setName.c_str(), localeNames[locale]);
|
||||
ChatHandler(target->GetSession()).PSendSysMessage("ItemSet |cffffffff|Hitemset:%d|h[{} {}]|h|r has been added to your appearance collection.", uint32(itemSetId), setName.c_str(), localeNames[locale]);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -25,6 +25,8 @@ Cant transmogrify rediculus items // Foereaper: would be fun to stab people with
|
||||
#include "ScriptedCreature.h"
|
||||
#include "ItemTemplate.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "Opcodes.h"
|
||||
|
||||
#define sT sTransmogrification
|
||||
#define GTS session->GetAcoreString // dropped translation support, no one using?
|
||||
@@ -331,6 +333,11 @@ std::unordered_map<std::string, const std::unordered_map<LocaleConstant, std::st
|
||||
{"added_appearance", &TRANSMOG_TEXT_ADDED_APPEARANCE}
|
||||
};
|
||||
|
||||
const uint32 FALLBACK_HIDE_ITEM_VENDOR_ID = 9172; //Invisibility potion
|
||||
const uint32 FALLBACK_REMOVE_TMOG_VENDOR_ID = 1049; //Tablet of Purge
|
||||
const uint32 CUSTOM_HIDE_ITEM_VENDOR_ID = 57575;//Custom Hide Item item
|
||||
const uint32 CUSTOM_REMOVE_TMOG_VENDOR_ID = 57576;//Custom Remove Transmog item
|
||||
|
||||
std::string GetLocaleText(LocaleConstant locale, const std::string& titleType) {
|
||||
auto textMapIt = textMaps.find(titleType);
|
||||
if (textMapIt != textMaps.end()) {
|
||||
@@ -344,6 +351,119 @@ std::string GetLocaleText(LocaleConstant locale, const std::string& titleType) {
|
||||
return "";
|
||||
}
|
||||
|
||||
uint32 GetTransmogPrice (ItemTemplate const* targetItem)
|
||||
{
|
||||
uint32 price = sT->GetSpecialPrice(targetItem);
|
||||
price *= sT->GetScaledCostModifier();
|
||||
price += sT->GetCopperCost();
|
||||
return price;
|
||||
}
|
||||
|
||||
bool ValidForTransmog (Player* player, Item* target, Item* source, bool hasSearch, std::string searchTerm)
|
||||
{
|
||||
if (!target || !source || !player) return false;
|
||||
ItemTemplate const* targetTemplate = target->GetTemplate();
|
||||
ItemTemplate const* sourceTemplate = source->GetTemplate();
|
||||
|
||||
if (!sT->CanTransmogrifyItemWithItem(player, targetTemplate, sourceTemplate))
|
||||
return false;
|
||||
if (sT->GetFakeEntry(target->GetGUID()) == source->GetEntry())
|
||||
return false;
|
||||
if (hasSearch && sourceTemplate->Name1.find(searchTerm) == std::string::npos)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CmpTmog (Item* i1, Item* i2)
|
||||
{
|
||||
const ItemTemplate* i1t = i1->GetTemplate();
|
||||
const ItemTemplate* i2t = i2->GetTemplate();
|
||||
const int q1 = 7-i1t->Quality;
|
||||
const int q2 = 7-i2t->Quality;
|
||||
return std::tie(q1, i1t->Name1) < std::tie(q2, i2t->Name1);
|
||||
}
|
||||
|
||||
std::vector<Item*> GetValidTransmogs (Player* player, Item* target, bool hasSearch, std::string searchTerm)
|
||||
{
|
||||
std::vector<Item*> allowedItems;
|
||||
if (!target) return allowedItems;
|
||||
|
||||
if (sT->GetUseCollectionSystem())
|
||||
{
|
||||
uint32 accountId = player->GetSession()->GetAccountId();
|
||||
if (sT->collectionCache.find(accountId) == sT->collectionCache.end())
|
||||
return allowedItems;
|
||||
|
||||
for (uint32 itemId : sT->collectionCache[accountId])
|
||||
{
|
||||
if (!sObjectMgr->GetItemTemplate(itemId))
|
||||
continue;
|
||||
Item* srcItem = Item::CreateItem(itemId, 1, 0);
|
||||
if (ValidForTransmog(player, target, srcItem, hasSearch, searchTerm))
|
||||
allowedItems.push_back(srcItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||
{
|
||||
Item* srcItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
|
||||
if (ValidForTransmog(player, target, srcItem, hasSearch, searchTerm))
|
||||
allowedItems.push_back(srcItem);
|
||||
}
|
||||
for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
|
||||
{
|
||||
Bag* bag = player->GetBagByPos(i);
|
||||
if (!bag)
|
||||
continue;
|
||||
for (uint32 j = 0; j < bag->GetBagSize(); ++j)
|
||||
{
|
||||
Item* srcItem = player->GetItemByPos(i, j);
|
||||
if (ValidForTransmog(player, target, srcItem, hasSearch, searchTerm))
|
||||
allowedItems.push_back(srcItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sConfigMgr->GetOption<bool>("Transmogrification.EnableSortByQualityAndName", true)) {
|
||||
sort(allowedItems.begin(), allowedItems.end(), CmpTmog);
|
||||
}
|
||||
|
||||
return allowedItems;
|
||||
}
|
||||
|
||||
void PerformTransmogrification (Player* player, uint32 itemEntry, uint32 cost)
|
||||
{
|
||||
uint8 slot = sT->selectionCache[player->GetGUID()];
|
||||
WorldSession* session = player->GetSession();
|
||||
if (!player->HasEnoughMoney(cost))
|
||||
{
|
||||
ChatHandler(session).SendNotification(LANG_ERR_TRANSMOG_NOT_ENOUGH_MONEY);
|
||||
return;
|
||||
}
|
||||
TransmogAcoreStrings res = sT->Transmogrify(player, itemEntry, slot);
|
||||
if (res == LANG_ERR_TRANSMOG_OK)
|
||||
session->SendAreaTriggerMessage("%s",GTS(LANG_ERR_TRANSMOG_OK));
|
||||
else
|
||||
ChatHandler(session).SendNotification(res);
|
||||
}
|
||||
|
||||
void RemoveTransmogrification (Player* player)
|
||||
{
|
||||
uint8 slot = sT->selectionCache[player->GetGUID()];
|
||||
WorldSession* session = player->GetSession();
|
||||
if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
|
||||
{
|
||||
if (sT->GetFakeEntry(newItem->GetGUID()))
|
||||
{
|
||||
sT->DeleteFakeEntry(player, slot, newItem);
|
||||
session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_UNTRANSMOG_OK));
|
||||
}
|
||||
else
|
||||
ChatHandler(session).SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
|
||||
}
|
||||
}
|
||||
|
||||
class npc_transmogrifier : public CreatureScript
|
||||
{
|
||||
public:
|
||||
@@ -412,13 +532,18 @@ public:
|
||||
// Next page
|
||||
if (sender > EQUIPMENT_SLOT_END + 10)
|
||||
{
|
||||
ShowTransmogItems(player, creature, action, sender);
|
||||
ShowTransmogItemsInGossipMenu(player, creature, action, sender);
|
||||
return true;
|
||||
}
|
||||
switch (sender)
|
||||
{
|
||||
case EQUIPMENT_SLOT_END: // Show items you can use
|
||||
ShowTransmogItems(player, creature, action, sender);
|
||||
sT->selectionCache[player->GetGUID()] = action;
|
||||
|
||||
if (sT->GetUseVendorInterface())
|
||||
ShowTransmogItemsInFakeVendor(player, creature, action);
|
||||
else
|
||||
ShowTransmogItemsInGossipMenu(player, creature, action, sender);
|
||||
break;
|
||||
case EQUIPMENT_SLOT_END + 1: // Main menu
|
||||
OnGossipHello(player, creature);
|
||||
@@ -449,16 +574,7 @@ public:
|
||||
} break;
|
||||
case EQUIPMENT_SLOT_END + 3: // Remove Transmogrification from single item
|
||||
{
|
||||
if (Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, action))
|
||||
{
|
||||
if (sT->GetFakeEntry(newItem->GetGUID()))
|
||||
{
|
||||
sT->DeleteFakeEntry(player, action, newItem);
|
||||
session->SendAreaTriggerMessage("%s", GTS(LANG_ERR_UNTRANSMOG_OK));
|
||||
}
|
||||
else
|
||||
session->SendNotification(LANG_ERR_UNTRANSMOG_NO_TRANSMOGS);
|
||||
}
|
||||
RemoveTransmogrification(player);
|
||||
OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, action);
|
||||
} break;
|
||||
#ifdef PRESETS
|
||||
@@ -577,25 +693,7 @@ public:
|
||||
OnGossipHello(player, creature);
|
||||
return true;
|
||||
}
|
||||
// sender = slot, action = display
|
||||
if (sT->GetUseCollectionSystem())
|
||||
{
|
||||
TransmogAcoreStrings res = sT->Transmogrify(player, action, sender);
|
||||
if (res == LANG_ERR_TRANSMOG_OK)
|
||||
session->SendAreaTriggerMessage("%s",GTS(LANG_ERR_TRANSMOG_OK));
|
||||
else
|
||||
session->SendNotification(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransmogAcoreStrings res = sT->Transmogrify(player, ObjectGuid::Create<HighGuid::Item>(action), sender);
|
||||
if (res == LANG_ERR_TRANSMOG_OK)
|
||||
session->SendAreaTriggerMessage("%s",GTS(LANG_ERR_TRANSMOG_OK));
|
||||
else
|
||||
session->SendNotification(res);
|
||||
}
|
||||
// OnGossipSelect(player, creature, EQUIPMENT_SLOT_END, sender);
|
||||
// ShowTransmogItems(player, creature, sender);
|
||||
PerformTransmogrification(player, action, sender);
|
||||
CloseGossipMenuFor(player); // Wait for SetMoney to get fixed, issue #10053
|
||||
} break;
|
||||
}
|
||||
@@ -686,174 +784,206 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
void ShowTransmogItems(Player* player, Creature* creature, uint8 slot, uint16 gossipPageNumber) // Only checks bags while can use an item from anywhere in inventory
|
||||
void ShowTransmogItemsInGossipMenu(Player* player, Creature* creature, uint8 slot, uint16 gossipPageNumber) // Only checks bags while can use an item from anywhere in inventory
|
||||
{
|
||||
WorldSession* session = player->GetSession();
|
||||
LocaleConstant locale = session->GetSessionDbLocaleIndex();
|
||||
Item* oldItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
|
||||
bool sendGossip = true;
|
||||
bool hasSearchString;
|
||||
|
||||
uint16 pageNumber = 0;
|
||||
uint32 startValue = 0;
|
||||
uint32 endValue = MAX_OPTIONS - 4;
|
||||
bool lastPage = true;
|
||||
if (gossipPageNumber > EQUIPMENT_SLOT_END + 10)
|
||||
{
|
||||
pageNumber = gossipPageNumber - EQUIPMENT_SLOT_END - 10;
|
||||
startValue = (pageNumber * (MAX_OPTIONS - 2));
|
||||
endValue = (pageNumber + 1) * (MAX_OPTIONS - 2) - 1;
|
||||
}
|
||||
|
||||
if (oldItem)
|
||||
{
|
||||
uint32 price = sT->GetSpecialPrice(oldItem->GetTemplate());
|
||||
price *= sT->GetScaledCostModifier();
|
||||
price += sT->GetCopperCost();
|
||||
uint32 price = GetTransmogPrice(oldItem->GetTemplate());
|
||||
std::ostringstream ss;
|
||||
ss << std::endl;
|
||||
if (sT->GetRequireToken())
|
||||
ss << std::endl << std::endl << sT->GetTokenAmount() << " x " << sT->GetItemLink(sT->GetTokenEntry(), session);
|
||||
std::string lineEnd = ss.str();
|
||||
|
||||
if (sT->GetUseCollectionSystem())
|
||||
{
|
||||
sendGossip = false;
|
||||
std::unordered_map<uint32, std::string>::iterator searchStringIterator = sT->searchStringByPlayer.find(player->GetGUID().GetCounter());
|
||||
hasSearchString = !(searchStringIterator == sT->searchStringByPlayer.end());
|
||||
std::string searchDisplayValue(hasSearchString ? searchStringIterator->second : GetLocaleText(locale, "search"));
|
||||
std::vector<Item*> allowedItems = GetValidTransmogs(player, oldItem, hasSearchString, searchDisplayValue);
|
||||
|
||||
uint16 pageNumber = 0;
|
||||
uint32 startValue = 0;
|
||||
uint32 endValue = MAX_OPTIONS - 4;
|
||||
bool lastPage = false;
|
||||
if (gossipPageNumber > EQUIPMENT_SLOT_END + 10)
|
||||
if (allowedItems.size() > 0)
|
||||
{
|
||||
lastPage = false;
|
||||
// Offset values to add Search gossip item
|
||||
if (pageNumber == 0)
|
||||
{
|
||||
pageNumber = gossipPageNumber - EQUIPMENT_SLOT_END - 10;
|
||||
startValue = (pageNumber * (MAX_OPTIONS - 2));
|
||||
endValue = (pageNumber + 1) * (MAX_OPTIONS - 2) - 1;
|
||||
}
|
||||
uint32 accountId = player->GetSession()->GetAccountId();
|
||||
if (sT->collectionCache.find(accountId) != sT->collectionCache.end())
|
||||
{
|
||||
std::unordered_map<uint32, std::string>::iterator searchStringIterator = sT->searchStringByPlayer.find(player->GetGUID().GetCounter());
|
||||
hasSearchString = !(searchStringIterator == sT->searchStringByPlayer.end());
|
||||
std::string searchDisplayValue(hasSearchString ? searchStringIterator->second : GetLocaleText(locale, "search"));
|
||||
// Offset values to add Search gossip item
|
||||
if (pageNumber == 0)
|
||||
if (hasSearchString)
|
||||
{
|
||||
if (hasSearchString)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(30620, 30, 30, -18, 0) + GetLocaleText(locale, "searching_for") + searchDisplayValue, slot + 1, 0, GetLocaleText(locale, "search_for_item"), 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(30620, 30, 30, -18, 0) + GetLocaleText(locale, "search"), slot + 1, 0, GetLocaleText(locale, "search_for_item"), 0, true);
|
||||
}
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(30620, 30, 30, -18, 0) + GetLocaleText(locale, "searching_for") + searchDisplayValue, slot + 1, 0, GetLocaleText(locale, "search_for_item"), 0, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(30620, 30, 30, -18, 0) + GetLocaleText(locale, "search"), slot + 1, 0, GetLocaleText(locale, "search_for_item"), 0, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
startValue--;
|
||||
}
|
||||
if (sT->GetAllowHiddenTransmog())
|
||||
{
|
||||
// Offset the start and end values to make space for invisible item entry
|
||||
endValue--;
|
||||
if (pageNumber != 0)
|
||||
{
|
||||
startValue--;
|
||||
}
|
||||
std::vector<Item*> allowedItems;
|
||||
if (sT->GetAllowHiddenTransmog())
|
||||
else
|
||||
{
|
||||
// Offset the start and end values to make space for invisible item entry
|
||||
endValue--;
|
||||
if (pageNumber != 0)
|
||||
{
|
||||
startValue--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add invisible item entry
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/inv_misc_enggizmos_27:30:30:-18:0|t" + GetLocaleText(locale, "hide_slot"), slot, UINT_MAX, GetLocaleText(locale, "confirm_hide_item") + lineEnd, 0, false);
|
||||
}
|
||||
}
|
||||
for (uint32 newItemEntryId : sT->collectionCache[accountId]) {
|
||||
if (!sObjectMgr->GetItemTemplate(newItemEntryId))
|
||||
continue;
|
||||
Item* newItem = Item::CreateItem(newItemEntryId, 1, 0);
|
||||
if (!newItem)
|
||||
continue;
|
||||
if (!sT->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
|
||||
continue;
|
||||
if (sT->GetFakeEntry(oldItem->GetGUID()) == newItem->GetEntry())
|
||||
continue;
|
||||
if (hasSearchString && newItem->GetTemplate()->Name1.find(searchDisplayValue) == std::string::npos)
|
||||
continue;
|
||||
allowedItems.push_back(newItem);
|
||||
}
|
||||
for (uint32 i = startValue; i <= endValue; i++)
|
||||
{
|
||||
if (allowedItems.empty() || i > allowedItems.size() - 1)
|
||||
{
|
||||
lastPage = true;
|
||||
break;
|
||||
}
|
||||
Item* newItem = allowedItems.at(i);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sT->GetItemLink(newItem, session), slot, newItem->GetEntry(), GetLocaleText(locale, "confirm_use_item") + sT->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sT->GetItemLink(newItem, session) + lineEnd, price, false);
|
||||
// Add invisible item entry
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/inv_misc_enggizmos_27:30:30:-18:0|t" + GetLocaleText(locale, "hide_slot"), slot, UINT_MAX, GetLocaleText(locale, "confirm_hide_item") + lineEnd, 0, false);
|
||||
}
|
||||
}
|
||||
if (gossipPageNumber == EQUIPMENT_SLOT_END + 11)
|
||||
for (uint32 i = startValue; i <= endValue; i++)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "previous_page"), EQUIPMENT_SLOT_END, slot);
|
||||
if (!lastPage)
|
||||
if (allowedItems.empty() || i > allowedItems.size() - 1)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "next_page"), gossipPageNumber + 1, slot);
|
||||
}
|
||||
}
|
||||
else if (gossipPageNumber > EQUIPMENT_SLOT_END + 11)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "previous_page"), gossipPageNumber - 1, slot);
|
||||
if (!lastPage)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "next_page"), gossipPageNumber + 1, slot);
|
||||
}
|
||||
}
|
||||
else if (!lastPage)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Next Page", EQUIPMENT_SLOT_END + 11, slot);
|
||||
}
|
||||
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Enchant_Disenchant:30:30:-18:0|t" + GetLocaleText(locale, "remove_transmog"), EQUIPMENT_SLOT_END + 3, slot, GetLocaleText(locale, "remove_transmog_slot"), 0, false);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|t" + GetLocaleText(locale, "update_menu"), EQUIPMENT_SLOT_END, slot);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|t" + GetLocaleText(locale, "back"), EQUIPMENT_SLOT_END + 1, 0);
|
||||
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32 limit = 0;
|
||||
for (uint8 i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; ++i)
|
||||
{
|
||||
if (limit > MAX_OPTIONS)
|
||||
lastPage = true;
|
||||
break;
|
||||
Item* newItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, i);
|
||||
if (!newItem)
|
||||
continue;
|
||||
if (!sT->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
|
||||
continue;
|
||||
if (sT->GetFakeEntry(oldItem->GetGUID()) == newItem->GetEntry())
|
||||
continue;
|
||||
++limit;
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sT->GetItemLink(newItem, session), slot, newItem->GetGUID().GetCounter(), GetLocaleText(locale, "confirm_use_item") + sT->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sT->GetItemLink(newItem, session) + lineEnd, price, false);
|
||||
}
|
||||
|
||||
for (uint8 i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; ++i)
|
||||
{
|
||||
Bag* bag = player->GetBagByPos(i);
|
||||
if (!bag)
|
||||
continue;
|
||||
for (uint32 j = 0; j < bag->GetBagSize(); ++j)
|
||||
{
|
||||
if (limit > MAX_OPTIONS)
|
||||
break;
|
||||
Item* newItem = player->GetItemByPos(i, j);
|
||||
if (!newItem)
|
||||
continue;
|
||||
if (!sT->CanTransmogrifyItemWithItem(player, oldItem->GetTemplate(), newItem->GetTemplate()))
|
||||
continue;
|
||||
if (sT->GetFakeEntry(oldItem->GetGUID()) == newItem->GetEntry())
|
||||
continue;
|
||||
++limit;
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sT->GetItemLink(newItem, session), slot, newItem->GetGUID().GetCounter(), GetLocaleText(locale, "confirm_use_item") + sT->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sT->GetItemLink(newItem, session) + ss.str(), price, false);
|
||||
}
|
||||
Item* newItem = allowedItems.at(i);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, sT->GetItemIcon(newItem->GetEntry(), 30, 30, -18, 0) + sT->GetItemLink(newItem, session), slot, newItem->GetEntry(), GetLocaleText(locale, "confirm_use_item") + sT->GetItemIcon(newItem->GetEntry(), 40, 40, -15, -10) + sT->GetItemLink(newItem, session) + lineEnd, price, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gossipPageNumber == EQUIPMENT_SLOT_END + 11)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "previous_page"), EQUIPMENT_SLOT_END, slot);
|
||||
if (!lastPage)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "next_page"), gossipPageNumber + 1, slot);
|
||||
}
|
||||
}
|
||||
else if (gossipPageNumber > EQUIPMENT_SLOT_END + 11)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "previous_page"), gossipPageNumber - 1, slot);
|
||||
if (!lastPage)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, GetLocaleText(locale, "next_page"), gossipPageNumber + 1, slot);
|
||||
}
|
||||
}
|
||||
else if (!lastPage)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_CHAT, "Next Page", EQUIPMENT_SLOT_END + 11, slot);
|
||||
}
|
||||
|
||||
if (sendGossip)
|
||||
{
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/INV_Enchant_Disenchant:30:30:-18:0|t" + GetLocaleText(locale, "remove_transmog"), EQUIPMENT_SLOT_END + 3, slot, GetLocaleText(locale, "remove_transmog_slot"), 0, false);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/PaperDollInfoFrame/UI-GearManager-Undo:30:30:-18:0|t" + GetLocaleText(locale, "update_menu"), EQUIPMENT_SLOT_END, slot);
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|t" + GetLocaleText(locale, "back"), EQUIPMENT_SLOT_END + 1, 0);
|
||||
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
|
||||
}
|
||||
AddGossipItemFor(player, GOSSIP_ICON_MONEY_BAG, "|TInterface/ICONS/Ability_Spy:30:30:-18:0|t" + GetLocaleText(locale, "back"), EQUIPMENT_SLOT_END + 1, 0);
|
||||
SendGossipMenuFor(player, DEFAULT_GOSSIP_MESSAGE, creature->GetGUID());
|
||||
}
|
||||
|
||||
static std::vector<ItemTemplate const*> GetSpoofedVendorItems (Item* target)
|
||||
{
|
||||
std::vector<ItemTemplate const*> spoofedItems;
|
||||
uint32 existingTransmog = sT->GetFakeEntry(target->GetGUID());
|
||||
if (sT->AllowHiddenTransmog && !existingTransmog)
|
||||
{
|
||||
ItemTemplate const* _hideSlotButton = sObjectMgr->GetItemTemplate(CUSTOM_HIDE_ITEM_VENDOR_ID);
|
||||
if (_hideSlotButton)
|
||||
spoofedItems.push_back(_hideSlotButton);
|
||||
else
|
||||
{
|
||||
_hideSlotButton = sObjectMgr->GetItemTemplate(FALLBACK_HIDE_ITEM_VENDOR_ID);
|
||||
spoofedItems.push_back(_hideSlotButton);
|
||||
}
|
||||
}
|
||||
if (existingTransmog)
|
||||
{
|
||||
ItemTemplate const* _removeTransmogButton = sObjectMgr->GetItemTemplate(CUSTOM_REMOVE_TMOG_VENDOR_ID);
|
||||
if (_removeTransmogButton)
|
||||
spoofedItems.push_back(_removeTransmogButton);
|
||||
else
|
||||
{
|
||||
_removeTransmogButton = sObjectMgr->GetItemTemplate(FALLBACK_REMOVE_TMOG_VENDOR_ID);
|
||||
spoofedItems.push_back(_removeTransmogButton);
|
||||
}
|
||||
}
|
||||
return spoofedItems;
|
||||
}
|
||||
|
||||
static uint32 GetSpoofedItemPrice (uint32 itemId, ItemTemplate const* target)
|
||||
{
|
||||
switch (itemId)
|
||||
{
|
||||
case CUSTOM_HIDE_ITEM_VENDOR_ID:
|
||||
case FALLBACK_HIDE_ITEM_VENDOR_ID:
|
||||
return sT->HiddenTransmogIsFree ? 0 : sT->GetSpecialPrice(target);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void EncodeItemToPacket (WorldPacket& data, ItemTemplate const* proto, uint8& slot, uint32 price)
|
||||
{
|
||||
data << uint32(slot + 1);
|
||||
data << uint32(proto->ItemId);
|
||||
data << uint32(proto->DisplayInfoID);
|
||||
data << int32 (-1); //Infinite Stock
|
||||
data << uint32(price);
|
||||
data << uint32(proto->MaxDurability);
|
||||
data << uint32(1); //Buy Count of 1
|
||||
data << uint32(0);
|
||||
slot++;
|
||||
}
|
||||
|
||||
//The actual vendor options are handled in the player script below, OnBeforeBuyItemFromVendor
|
||||
static void ShowTransmogItemsInFakeVendor (Player* player, Creature* creature, uint8 slot)
|
||||
{
|
||||
Item* targetItem = player->GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
|
||||
if (!targetItem)
|
||||
{
|
||||
ChatHandler(player->GetSession()).SendNotification(LANG_ERR_TRANSMOG_MISSING_DEST_ITEM);
|
||||
CloseGossipMenuFor(player);
|
||||
return;
|
||||
}
|
||||
ItemTemplate const* targetTemplate = targetItem->GetTemplate();
|
||||
|
||||
std::vector<Item*> itemList = GetValidTransmogs(player, targetItem, false, "");
|
||||
std::vector<ItemTemplate const*> spoofedItems = GetSpoofedVendorItems(targetItem);
|
||||
|
||||
uint32 itemCount = itemList.size();
|
||||
uint32 spoofCount = spoofedItems.size();
|
||||
uint32 totalItems = itemCount + spoofCount;
|
||||
uint32 price = GetTransmogPrice(targetItem->GetTemplate());
|
||||
|
||||
WorldPacket data(SMSG_LIST_INVENTORY, 8 + 1 + totalItems * 8 * 4);
|
||||
data << uint64(creature->GetGUID().GetRawValue());
|
||||
|
||||
uint8 count = 0;
|
||||
size_t count_pos = data.wpos();
|
||||
data << uint8(count);
|
||||
|
||||
for (uint32 i = 0; i < spoofCount && count < MAX_VENDOR_ITEMS; ++i)
|
||||
{
|
||||
EncodeItemToPacket (
|
||||
data, spoofedItems[i], count,
|
||||
GetSpoofedItemPrice(spoofedItems[i]->ItemId, targetTemplate)
|
||||
);
|
||||
}
|
||||
for (uint32 i = 0; i < itemCount && count < MAX_VENDOR_ITEMS; ++i)
|
||||
{
|
||||
ItemTemplate const* _proto = itemList[i]->GetTemplate();
|
||||
if (_proto) EncodeItemToPacket(data, _proto, count, price);
|
||||
}
|
||||
|
||||
data.put(count_pos, count);
|
||||
player->GetSession()->SendPacket(&data);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -991,13 +1121,11 @@ public:
|
||||
void OnLogin(Player* player) override
|
||||
{
|
||||
if (sT->EnableResetRetroActiveAppearances())
|
||||
{
|
||||
player->UpdatePlayerSetting("mod-transmog", SETTING_RETROACTIVE_CHECK, 0);
|
||||
}
|
||||
|
||||
if (sT->EnableRetroActiveAppearances() && !(player->GetPlayerSetting("mod-transmog", SETTING_RETROACTIVE_CHECK).value))
|
||||
{
|
||||
CheckRetroActiveQuestAppearances(player);
|
||||
}
|
||||
|
||||
ObjectGuid playerGUID = player->GetGUID();
|
||||
sT->entryMap.erase(playerGUID);
|
||||
QueryResult result = CharacterDatabase.Query("SELECT GUID, FakeEntry FROM custom_transmogrification WHERE Owner = {}", player->GetGUID().GetCounter());
|
||||
@@ -1012,11 +1140,6 @@ public:
|
||||
sT->dataMap[itemGUID] = playerGUID;
|
||||
sT->entryMap[playerGUID][itemGUID] = fakeEntry;
|
||||
}
|
||||
else
|
||||
{
|
||||
//sLog->outError(LOG_FILTER_SQL, "Item entry (Entry: {}, itemGUID: {}, playerGUID: {}) does not exist, ignoring.", fakeEntry, GUID_LOPART(itemGUID), player->GetGUIDLow());
|
||||
// CharacterDatabase.Execute("DELETE FROM custom_transmogrification WHERE FakeEntry = {}", fakeEntry);
|
||||
}
|
||||
} while (result->NextRow());
|
||||
|
||||
for (uint8 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
|
||||
@@ -1026,6 +1149,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (sConfigMgr->GetOption<bool>("Transmogrification.EnablePlus", false))
|
||||
{
|
||||
uint32 accountId = 0;
|
||||
|
||||
if (player->GetSession())
|
||||
accountId = player->GetSession()->GetAccountId();
|
||||
|
||||
QueryResult resultAcc = LoginDatabase.Query("SELECT `membership_level` FROM `acore_cms_subscriptions` WHERE `account_name` COLLATE utf8mb4_general_ci = (SELECT `username` FROM `account` WHERE `id` = {})", accountId);
|
||||
|
||||
if (resultAcc)
|
||||
player->UpdatePlayerSetting("acore_cms_subscriptions", SETTING_TRANSMOG_MEMBERSHIP_LEVEL, (*resultAcc)[0].Get<uint32>());
|
||||
}
|
||||
|
||||
#ifdef PRESETS
|
||||
if (sT->GetEnableSets())
|
||||
sT->LoadPlayerSets(playerGUID);
|
||||
@@ -1038,12 +1174,40 @@ public:
|
||||
for (Transmogrification::transmog2Data::const_iterator it = sT->entryMap[pGUID].begin(); it != sT->entryMap[pGUID].end(); ++it)
|
||||
sT->dataMap.erase(it->first);
|
||||
sT->entryMap.erase(pGUID);
|
||||
sT->selectionCache.erase(pGUID);
|
||||
|
||||
#ifdef PRESETS
|
||||
if (sT->GetEnableSets())
|
||||
sT->UnloadPlayerSets(pGUID);
|
||||
#endif
|
||||
}
|
||||
|
||||
void OnBeforeBuyItemFromVendor(Player* player, ObjectGuid vendorguid, uint32 /*vendorslot*/, uint32& itemEntry, uint8 /*count*/, uint8 /*bag*/, uint8 /*slot*/) override
|
||||
{
|
||||
Creature* vendor = player->GetMap()->GetCreature(vendorguid);
|
||||
if (!vendor)
|
||||
return;
|
||||
|
||||
if (!sT->IsTransmogVendor(vendor->GetEntry()))
|
||||
return;
|
||||
|
||||
uint8 slot = sT->selectionCache[player->GetGUID()];
|
||||
|
||||
if (itemEntry == CUSTOM_HIDE_ITEM_VENDOR_ID || itemEntry == FALLBACK_HIDE_ITEM_VENDOR_ID)
|
||||
{
|
||||
PerformTransmogrification(player, UINT_MAX, 0);
|
||||
}
|
||||
else if (itemEntry == CUSTOM_REMOVE_TMOG_VENDOR_ID || itemEntry == FALLBACK_REMOVE_TMOG_VENDOR_ID)
|
||||
{
|
||||
RemoveTransmogrification(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformTransmogrification(player, itemEntry, 0);
|
||||
}
|
||||
npc_transmogrifier::ShowTransmogItemsInFakeVendor(player, vendor, slot); //Refresh menu
|
||||
itemEntry = 0; //Prevents the handler from proceeding to core vendor handling
|
||||
}
|
||||
};
|
||||
|
||||
class WS_Transmogrification : public WorldScript
|
||||
|
||||
Reference in New Issue
Block a user