Skip to content

Commit b8d2838

Browse files
committed
Update Transmog Module 2-13-26
1 parent b28d365 commit b8d2838

File tree

8 files changed

+102
-77
lines changed

8 files changed

+102
-77
lines changed

modules/mod-transmog/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Transmog Module
22

3-
- Latest Transmog build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-transmog/workflows/core-build/badge.svg?branch=master&event=push)](https://github.com/azerothcore/mod-transmog)
3+
> [!WARNING]
4+
> If you used the old-subscription system for TransmogPlus option before this [commit](https://github.com/azerothcore/mod-transmog/commit/8237df6f88d40d1d83a6f11b86a7187f99f57c99), please update your mod-transmog module to the latest revision and also download the new module [mod-acore-subscriptions](https://github.com/azerothcore/mod-acore-subscriptions).
45
5-
This is a module for [AzerothCore](http://www.azerothcore.org) that adds transmog feature, it's based on [Rochet2 Transmog Script](http://rochet2.github.io/Transmogrification.html)
6+
- Latest Transmog build status with azerothcore: [![Build Status](https://github.com/azerothcore/mod-transmog/actions/workflows/core_build.yml/badge.svg)](https://github.com/azerothcore/mod-transmog/actions)
7+
8+
This is a module for [AzerothCore](http://www.azerothcore.org) that adds **Transmog**rification feature, it's based on [Rochet2 Transmog Script](http://rochet2.github.io/Transmogrification.html)
69

710
## Important notes
811

modules/mod-transmog/conf/transmog.conf.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,7 @@ Transmogrification.MembershipLevels = ""
327327
Transmogrification.MembershipLevelsLegendary = ""
328328
Transmogrification.MembershipLevelsPet = ""
329329
Transmogrification.MembershipLevelsSkipLevelReq = ""
330-
Transmogrification.PetSpellId = 2000100
330+
Transmogrification.PetSpellId = 200100
331331

332332
#
333333
###################################################################################################

modules/mod-transmog/data/sql/db-characters/trasmorg.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS `custom_transmogrification` (
55
`Owner` int(10) unsigned NOT NULL COMMENT 'Player guidLow',
66
PRIMARY KEY (`GUID`),
77
KEY `Owner` (`Owner`)
8-
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_2';
8+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='6_2';
99

1010
-- Data exporting was unselected.
1111

@@ -17,10 +17,10 @@ CREATE TABLE IF NOT EXISTS `custom_transmogrification_sets` (
1717
`SetName` text COMMENT 'SetName',
1818
`SetData` text COMMENT 'Slot1 Entry1 Slot2 Entry2',
1919
PRIMARY KEY (`Owner`,`PresetID`)
20-
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='6_1';
20+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='6_1';
2121

2222
CREATE TABLE IF NOT EXISTS `custom_unlocked_appearances` (
2323
`account_id` int(10) unsigned NOT NULL,
2424
`item_template_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
2525
PRIMARY KEY (`account_id`, `item_template_id`)
26-
) ENGINE = InnoDB DEFAULT CHARSET = utf8;
26+
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4;

modules/mod-transmog/data/sql/db-world/trasm_world_NPC.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,6 @@ INSERT INTO `creature_template_locale` (`entry`, `locale`, `Name`, `Title`) VALU
4444
(@Entry, 'esMX', @Name, "Transfigurador"),
4545
(@Entry, 'ruRU', @Name, "Трансмогрификатор");
4646

47-
DELETE FROM `spell_dbc` WHERE `ID` = 2000100;
47+
DELETE FROM `spell_dbc` WHERE `ID` = 200100;
4848
INSERT INTO `spell_dbc` (`ID`, `Category`, `DispelType`, `Mechanic`, `Attributes`, `AttributesEx`, `AttributesEx2`, `AttributesEx3`, `AttributesEx4`, `AttributesEx5`, `AttributesEx6`, `AttributesEx7`, `ShapeshiftMask`, `unk_320_2`, `ShapeshiftExclude`, `unk_320_3`, `Targets`, `TargetCreatureType`, `RequiresSpellFocus`, `FacingCasterFlags`, `CasterAuraState`, `TargetAuraState`, `ExcludeCasterAuraState`, `ExcludeTargetAuraState`, `CasterAuraSpell`, `TargetAuraSpell`, `ExcludeCasterAuraSpell`, `ExcludeTargetAuraSpell`, `CastingTimeIndex`, `RecoveryTime`, `CategoryRecoveryTime`, `InterruptFlags`, `AuraInterruptFlags`, `ChannelInterruptFlags`, `ProcTypeMask`, `ProcChance`, `ProcCharges`, `MaxLevel`, `BaseLevel`, `SpellLevel`, `DurationIndex`, `PowerType`, `ManaCost`, `ManaCostPerLevel`, `ManaPerSecond`, `ManaPerSecondPerLevel`, `RangeIndex`, `Speed`, `ModalNextSpell`, `CumulativeAura`, `Totem_1`, `Totem_2`, `Reagent_1`, `Reagent_2`, `Reagent_3`, `Reagent_4`, `Reagent_5`, `Reagent_6`, `Reagent_7`, `Reagent_8`, `ReagentCount_1`, `ReagentCount_2`, `ReagentCount_3`, `ReagentCount_4`, `ReagentCount_5`, `ReagentCount_6`, `ReagentCount_7`, `ReagentCount_8`, `EquippedItemClass`, `EquippedItemSubclass`, `EquippedItemInvTypes`, `Effect_1`, `Effect_2`, `Effect_3`, `EffectDieSides_1`, `EffectDieSides_2`, `EffectDieSides_3`, `EffectRealPointsPerLevel_1`, `EffectRealPointsPerLevel_2`, `EffectRealPointsPerLevel_3`, `EffectBasePoints_1`, `EffectBasePoints_2`, `EffectBasePoints_3`, `EffectMechanic_1`, `EffectMechanic_2`, `EffectMechanic_3`, `ImplicitTargetA_1`, `ImplicitTargetA_2`, `ImplicitTargetA_3`, `ImplicitTargetB_1`, `ImplicitTargetB_2`, `ImplicitTargetB_3`, `EffectRadiusIndex_1`, `EffectRadiusIndex_2`, `EffectRadiusIndex_3`, `EffectAura_1`, `EffectAura_2`, `EffectAura_3`, `EffectAuraPeriod_1`, `EffectAuraPeriod_2`, `EffectAuraPeriod_3`, `EffectMultipleValue_1`, `EffectMultipleValue_2`, `EffectMultipleValue_3`, `EffectChainTargets_1`, `EffectChainTargets_2`, `EffectChainTargets_3`, `EffectItemType_1`, `EffectItemType_2`, `EffectItemType_3`, `EffectMiscValue_1`, `EffectMiscValue_2`, `EffectMiscValue_3`, `EffectMiscValueB_1`, `EffectMiscValueB_2`, `EffectMiscValueB_3`, `EffectTriggerSpell_1`, `EffectTriggerSpell_2`, `EffectTriggerSpell_3`, `EffectPointsPerCombo_1`, `EffectPointsPerCombo_2`, `EffectPointsPerCombo_3`, `EffectSpellClassMaskA_1`, `EffectSpellClassMaskA_2`, `EffectSpellClassMaskA_3`, `EffectSpellClassMaskB_1`, `EffectSpellClassMaskB_2`, `EffectSpellClassMaskB_3`, `EffectSpellClassMaskC_1`, `EffectSpellClassMaskC_2`, `EffectSpellClassMaskC_3`, `SpellVisualID_1`, `SpellVisualID_2`, `SpellIconID`, `ActiveIconID`, `SpellPriority`, `Name_Lang_enUS`, `Name_Lang_enGB`, `Name_Lang_koKR`, `Name_Lang_frFR`, `Name_Lang_deDE`, `Name_Lang_enCN`, `Name_Lang_zhCN`, `Name_Lang_enTW`, `Name_Lang_zhTW`, `Name_Lang_esES`, `Name_Lang_esMX`, `Name_Lang_ruRU`, `Name_Lang_ptPT`, `Name_Lang_ptBR`, `Name_Lang_itIT`, `Name_Lang_Unk`, `Name_Lang_Mask`, `NameSubtext_Lang_enUS`, `NameSubtext_Lang_enGB`, `NameSubtext_Lang_koKR`, `NameSubtext_Lang_frFR`, `NameSubtext_Lang_deDE`, `NameSubtext_Lang_enCN`, `NameSubtext_Lang_zhCN`, `NameSubtext_Lang_enTW`, `NameSubtext_Lang_zhTW`, `NameSubtext_Lang_esES`, `NameSubtext_Lang_esMX`, `NameSubtext_Lang_ruRU`, `NameSubtext_Lang_ptPT`, `NameSubtext_Lang_ptBR`, `NameSubtext_Lang_itIT`, `NameSubtext_Lang_Unk`, `NameSubtext_Lang_Mask`, `Description_Lang_enUS`, `Description_Lang_enGB`, `Description_Lang_koKR`, `Description_Lang_frFR`, `Description_Lang_deDE`, `Description_Lang_enCN`, `Description_Lang_zhCN`, `Description_Lang_enTW`, `Description_Lang_zhTW`, `Description_Lang_esES`, `Description_Lang_esMX`, `Description_Lang_ruRU`, `Description_Lang_ptPT`, `Description_Lang_ptBR`, `Description_Lang_itIT`, `Description_Lang_Unk`, `Description_Lang_Mask`, `AuraDescription_Lang_enUS`, `AuraDescription_Lang_enGB`, `AuraDescription_Lang_koKR`, `AuraDescription_Lang_frFR`, `AuraDescription_Lang_deDE`, `AuraDescription_Lang_enCN`, `AuraDescription_Lang_zhCN`, `AuraDescription_Lang_enTW`, `AuraDescription_Lang_zhTW`, `AuraDescription_Lang_esES`, `AuraDescription_Lang_esMX`, `AuraDescription_Lang_ruRU`, `AuraDescription_Lang_ptPT`, `AuraDescription_Lang_ptBR`, `AuraDescription_Lang_itIT`, `AuraDescription_Lang_Unk`, `AuraDescription_Lang_Mask`, `ManaCostPct`, `StartRecoveryCategory`, `StartRecoveryTime`, `MaxTargetLevel`, `SpellClassSet`, `SpellClassMask_1`, `SpellClassMask_2`, `SpellClassMask_3`, `MaxTargets`, `DefenseType`, `PreventionType`, `StanceBarOrder`, `EffectChainAmplitude_1`, `EffectChainAmplitude_2`, `EffectChainAmplitude_3`, `MinFactionID`, `MinReputation`, `RequiredAuraVision`, `RequiredTotemCategoryID_1`, `RequiredTotemCategoryID_2`, `RequiredAreasID`, `SchoolMask`, `RuneCostID`, `SpellMissileID`, `PowerDisplayID`, `EffectBonusMultiplier_1`, `EffectBonusMultiplier_2`, `EffectBonusMultiplier_3`, `SpellDescriptionVariableID`, `SpellDifficultyID`) VALUE
49-
(2000100,0,0,0,262416,0,0,536870912,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,31,0,0,0,101,0,0,0,0,21,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,28,0,0,1,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,0,0,190011,0,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,458,0,2808,0,0,'Ethereal Warpweaver','','','','','','','','','','','','','','','',16712190,'','','','','','','','','','','','','','','','',16712190,'Right Click to summon and dismiss your Ethereal Warpweaver.','','','','','','','','','','','','','','','',16712190,'','','','','','','','','','','','','','','','',16712190,0,133,1500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
49+
(200100,0,0,0,262416,0,0,536870912,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,31,0,0,0,101,0,0,0,0,21,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-1,0,0,28,0,0,1,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,0,0,0,0,0,0,0,0,190011,0,0,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,458,0,2808,0,0,'Ethereal Warpweaver','','','','','','','','','','','','','','','',16712190,'','','','','','','','','','','','','','','','',16712190,'Right Click to summon and dismiss your Ethereal Warpweaver.','','','','','','','','','','','','','','','',16712190,'','','','','','','','','','','','','','','','',16712190,0,133,1500,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);

modules/mod-transmog/src/Transmogrification.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -465,22 +465,15 @@ void Transmogrification::SetFakeEntry(Player* player, uint32 newEntry, uint8 /*s
465465

466466
bool Transmogrification::AddCollectedAppearance(uint32 accountId, uint32 itemId)
467467
{
468-
if (collectionCache.find(accountId) == collectionCache.end())
468+
if (!collectionCache.contains(accountId))
469469
{
470-
collectionCache.insert({accountId, {itemId}});
470+
collectionCache.insert({ accountId, {itemId} });
471471
return true;
472472
}
473-
if (std::find(collectionCache[accountId].begin(), collectionCache[accountId].end(), itemId) == collectionCache[accountId].end())
474-
{
475-
collectionCache[accountId].push_back(itemId);
476-
477-
if (!sConfigMgr->GetOption<bool>("Transmogrification.EnableSortByQualityAndName", true)) {
478-
std::sort(collectionCache[accountId].begin(), collectionCache[accountId].end());
479-
}
480473

481-
return true;
482-
}
483-
return false;
474+
auto res = collectionCache[accountId].insert(itemId);
475+
bool inserted = res.second;
476+
return inserted;
484477
}
485478

486479
TransmogAcoreStrings Transmogrification::Transmogrify(Player* player, uint32 itemEntry, uint8 slot, /*uint32 newEntry, */bool no_cost) {
@@ -1229,6 +1222,9 @@ bool Transmogrification::IsPlusFeatureEligible(ObjectGuid const &playerGuid, uin
12291222
if (!player)
12301223
return false;
12311224

1225+
if (player->IsGameMaster())
1226+
return true; // GM can use all features
1227+
12321228
const auto membershipLevel = GetPlayerMembershipLevel(player);
12331229

12341230
if (!membershipLevel)
@@ -1244,6 +1240,29 @@ bool Transmogrification::IsPlusFeatureEligible(ObjectGuid const &playerGuid, uin
12441240
return false;
12451241
}
12461242

1243+
void Transmogrification::LoadCollections()
1244+
{
1245+
if (sTransmogrification->GetUseCollectionSystem())
1246+
{
1247+
LOG_INFO("module", "Loading transmog appearance collection cache....");
1248+
uint32 collectedAppearanceCount = 0;
1249+
QueryResult result = CharacterDatabase.Query("SELECT account_id, item_template_id FROM custom_unlocked_appearances");
1250+
if (result)
1251+
{
1252+
do
1253+
{
1254+
uint32 accountId = (*result)[0].Get<uint32>();
1255+
uint32 itemId = (*result)[1].Get<uint32>();
1256+
if (sTransmogrification->AddCollectedAppearance(accountId, itemId))
1257+
collectedAppearanceCount++;
1258+
1259+
} while (result->NextRow());
1260+
}
1261+
1262+
LOG_INFO("module", "Loaded {} collected appearances into cache", collectedAppearanceCount);
1263+
}
1264+
}
1265+
12471266
bool Transmogrification::GetEnableTransmogInfo() const
12481267
{
12491268
return EnableTransmogInfo;

modules/mod-transmog/src/Transmogrification.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "QuestDef.h"
1414
#include "ItemTemplate.h"
1515
#include <unordered_map>
16+
#include <unordered_set>
1617
#include <vector>
1718

1819
#define PRESETS // comment this line to disable preset feature totally
@@ -111,7 +112,7 @@ class Transmogrification
111112
typedef std::unordered_map<ObjectGuid, ObjectGuid> transmogData;
112113
typedef std::unordered_map<ObjectGuid, uint32> transmog2Data;
113114
typedef std::unordered_map<ObjectGuid, transmog2Data> transmogMap;
114-
typedef std::unordered_map<uint32, std::vector<uint32>> collectionCacheMap;
115+
typedef std::unordered_map<uint32, std::unordered_set<uint32>> collectionCacheMap;
115116
typedef std::unordered_map<uint32, std::string> searchStringMap;
116117
typedef std::unordered_map<uint32, std::vector<uint32>> transmogPlusData;
117118
typedef std::unordered_map<ObjectGuid, uint8> selectedSlotMap;
@@ -149,6 +150,7 @@ class Transmogrification
149150

150151
void LoadPlayerSets(ObjectGuid pGUID);
151152
void UnloadPlayerSets(ObjectGuid pGUID);
153+
void LoadCollections();
152154
#endif
153155

154156
bool EnableTransmogInfo;

modules/mod-transmog/src/cs_transmog.cpp

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "Transmogrification.h"
2323
#include "Tokenize.h"
2424
#include "DatabaseEnv.h"
25+
#include "SpellMgr.h"
2526

2627
using namespace Acore::ChatCommands;
2728

@@ -40,11 +41,12 @@ class transmog_commandscript : public CommandScript
4041

4142
static ChatCommandTable transmogTable =
4243
{
43-
{ "add", addCollectionTable },
44-
{ "", HandleDisableTransMogVisual, SEC_PLAYER, Console::No },
45-
{ "sync", HandleSyncTransMogCommand, SEC_PLAYER, Console::No },
46-
{ "portable", HandleTransmogPortableCommand, SEC_PLAYER, Console::No },
47-
{ "interface", HandleInterfaceOption, SEC_PLAYER, Console::No }
44+
{ "add", addCollectionTable },
45+
{ "", HandleDisableTransMogVisual, SEC_PLAYER, Console::No },
46+
{ "sync", HandleSyncTransMogCommand, SEC_PLAYER, Console::No },
47+
{ "portable", HandleTransmogPortableCommand, SEC_PLAYER, Console::No },
48+
{ "interface", HandleInterfaceOption, SEC_PLAYER, Console::No },
49+
{ "reload", HandleReloadTransmogConfig, SEC_ADMINISTRATOR, Console::Yes}
4850
};
4951

5052
static ChatCommandTable commandTable =
@@ -280,27 +282,31 @@ class transmog_commandscript : public CommandScript
280282
{
281283
if (!sTransmogrification->IsPortableNPCEnabled)
282284
{
283-
handler->GetPlayer()->SendSystemMessage("The portable transmogrification NPC is disabled.");
284-
handler->SetSentErrorMessage(true);
285+
handler->SendErrorMessage("The portable transmogrification NPC is disabled.");
285286
return true;
286287
}
287288

288-
if (Player* player = PlayerIdentifier::FromSelf(handler)->GetConnectedPlayer())
289+
if (!sTransmogrification->IsTransmogPlusEnabled)
289290
{
291+
handler->SendErrorMessage("The portable transmogrification NPC is a plus feature. Plus features are currently disabled.");
292+
return true;
293+
}
290294

291-
if (sTransmogrification->IsTransmogPlusEnabled)
292-
if (sTransmogrification->IsPlusFeatureEligible(player->GetGUID(), PLUS_FEATURE_PET))
293-
{
294-
player->CastSpell((Unit*)nullptr, sTransmogrification->PetSpellId, true);
295-
return true;
296-
}
295+
Player* player = PlayerIdentifier::FromSelf(handler)->GetConnectedPlayer();
297296

298-
if (player->GetSession()->GetSecurity() < SEC_MODERATOR)
299-
return true;
297+
if (!sTransmogrification->IsPlusFeatureEligible(player->GetGUID(), PLUS_FEATURE_PET))
298+
{
299+
handler->SendErrorMessage("You are not eligible for the portable transmogrification NPC. Please check your subscription level.");
300+
return true;
301+
}
300302

301-
player->CastSpell((Unit*)nullptr, sTransmogrification->PetSpellId, true);
303+
if (!sSpellMgr->GetSpellInfo(sTransmogrification->PetSpellId))
304+
{
305+
handler->SendErrorMessage("The portable transmogrification NPC spell is not available.");
306+
return true;
302307
}
303308

309+
player->CastSpell((Unit*)nullptr, sTransmogrification->PetSpellId, true);
304310
return true;
305311
};
306312

@@ -310,6 +316,15 @@ class transmog_commandscript : public CommandScript
310316
handler->SendSysMessage(enable ? LANG_CMD_TRANSMOG_VENDOR_INTERFACE_ENABLE : LANG_CMD_TRANSMOG_VENDOR_INTERFACE_DISABLE);
311317
return true;
312318
}
319+
320+
static bool HandleReloadTransmogConfig(ChatHandler* handler)
321+
{
322+
sTransmogrification->LoadConfig(true);
323+
handler->SendSysMessage("Transmog configs reloaded.");
324+
sTransmogrification->LoadCollections();
325+
handler->SendSysMessage("Transmog collections reloaded.");
326+
return true;
327+
}
313328
};
314329

315330
void AddSC_transmog_commandscript()

0 commit comments

Comments
 (0)