Core/Transmog: Update transmog system to 12.0

This commit is contained in:
Shauren
2026-03-21 13:41:42 +01:00
parent ec3065b354
commit db8552567d
43 changed files with 2883 additions and 290 deletions
+26 -1
View File
@@ -459,6 +459,30 @@ LOCK TABLES `battlenet_account_transmog_illusions` WRITE;
/*!40000 ALTER TABLE `battlenet_account_transmog_illusions` ENABLE KEYS */; /*!40000 ALTER TABLE `battlenet_account_transmog_illusions` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
--
-- Table structure for table `battlenet_account_transmog_outfits`
--
DROP TABLE IF EXISTS `battlenet_account_transmog_outfits`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `battlenet_account_transmog_outfits` (
`battlenetAccountId` int unsigned NOT NULL,
`transmogOutfitId` int NOT NULL DEFAULT '0',
PRIMARY KEY (`battlenetAccountId`,`blobIndex`),
CONSTRAINT `fk_battlenet_account_transmog_outfits` FOREIGN KEY (`battlenetAccountId`) REFERENCES `battlenet_accounts` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `battlenet_account_transmog_outfits`
--
LOCK TABLES `battlenet_account_transmog_outfits` WRITE;
/*!40000 ALTER TABLE `battlenet_account_transmog_outfits` DISABLE KEYS */;
/*!40000 ALTER TABLE `battlenet_account_transmog_outfits` ENABLE KEYS */;
UNLOCK TABLES;
-- --
-- Table structure for table `battlenet_account_warband_scenes` -- Table structure for table `battlenet_account_warband_scenes`
-- --
@@ -4147,7 +4171,8 @@ INSERT INTO `updates` VALUES
('2026_03_10_00_auth.sql','4BB4EBC719F80F7BEA667E6DA49815B358956FEA','RELEASED','2026-03-10 20:42:13',0), ('2026_03_10_00_auth.sql','4BB4EBC719F80F7BEA667E6DA49815B358956FEA','RELEASED','2026-03-10 20:42:13',0),
('2026_03_14_00_auth.sql','4CE4AF3D9E1BF173832B25F4D1A730A93ED016FA','RELEASED','2026-03-14 12:03:14',0), ('2026_03_14_00_auth.sql','4CE4AF3D9E1BF173832B25F4D1A730A93ED016FA','RELEASED','2026-03-14 12:03:14',0),
('2026_03_18_00_auth.sql','7A755DADF9AAC9016FD01B26ACEC714FAB5E3269','RELEASED','2026-03-18 12:36:48',0), ('2026_03_18_00_auth.sql','7A755DADF9AAC9016FD01B26ACEC714FAB5E3269','RELEASED','2026-03-18 12:36:48',0),
('2026_03_20_00_auth.sql','9083386953291DA3D0634E90D40863F7625FF37E','RELEASED','2026-03-20 01:11:00',0); ('2026_03_20_00_auth.sql','9083386953291DA3D0634E90D40863F7625FF37E','RELEASED','2026-03-20 01:11:00',0),
('2026_03_21_00_auth.sql','6D47EFD7FBCD159F5BC5B5A6020E61824280E92A','RELEASED','2026-03-21 00:08:26',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */; /*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
+87 -1
View File
@@ -1891,6 +1891,89 @@ LOCK TABLES `character_trait_entry` WRITE;
/*!40000 ALTER TABLE `character_trait_entry` ENABLE KEYS */; /*!40000 ALTER TABLE `character_trait_entry` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
--
-- Table structure for table `character_transmog_outfit`
--
DROP TABLE IF EXISTS `character_transmog_outfit`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `character_transmog_outfit` (
`guid` bigint NOT NULL,
`transmogOutfitId` int NOT NULL,
`name` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
`icon` int NOT NULL,
`situationsEnabled` tinyint(1) NOT NULL,
PRIMARY KEY (`guid`,`transmogOutfitId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `character_transmog_outfit`
--
LOCK TABLES `character_transmog_outfit` WRITE;
/*!40000 ALTER TABLE `character_transmog_outfit` DISABLE KEYS */;
/*!40000 ALTER TABLE `character_transmog_outfit` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `character_transmog_outfit_situation`
--
DROP TABLE IF EXISTS `character_transmog_outfit_situation`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `character_transmog_outfit_situation` (
`guid` bigint NOT NULL,
`transmogOutfitId` int NOT NULL,
`situationID` int NOT NULL,
`specID` int NOT NULL,
`loadoutID` int NOT NULL,
`equipmentSetID` int NOT NULL,
PRIMARY KEY (`guid`,`transmogOutfitId`,`situationID`,`specID`,`loadoutID`,`equipmentSetID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `character_transmog_outfit_situation`
--
LOCK TABLES `character_transmog_outfit_situation` WRITE;
/*!40000 ALTER TABLE `character_transmog_outfit_situation` DISABLE KEYS */;
/*!40000 ALTER TABLE `character_transmog_outfit_situation` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `character_transmog_outfit_slot`
--
DROP TABLE IF EXISTS `character_transmog_outfit_slot`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!50503 SET character_set_client = utf8mb4 */;
CREATE TABLE `character_transmog_outfit_slot` (
`guid` bigint NOT NULL,
`transmogOutfitId` int NOT NULL,
`slot` tinyint NOT NULL,
`slotOption` tinyint NOT NULL,
`itemModifiedAppearanceID` int NOT NULL,
`appearanceDisplayType` tinyint NOT NULL,
`spellItemEnchantmentID` int NOT NULL,
`illusionDisplayType` tinyint NOT NULL,
`flags` int NOT NULL,
PRIMARY KEY (`guid`,`transmogOutfitId`,`slot`,`slotOption`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `character_transmog_outfit_slot`
--
LOCK TABLES `character_transmog_outfit_slot` WRITE;
/*!40000 ALTER TABLE `character_transmog_outfit_slot` DISABLE KEYS */;
/*!40000 ALTER TABLE `character_transmog_outfit_slot` ENABLE KEYS */;
UNLOCK TABLES;
-- --
-- Table structure for table `character_transmog_outfits` -- Table structure for table `character_transmog_outfits`
-- --
@@ -2043,6 +2126,8 @@ CREATE TABLE `characters` (
`personalTabardBorderStyle` int NOT NULL DEFAULT '-1', `personalTabardBorderStyle` int NOT NULL DEFAULT '-1',
`personalTabardBorderColor` int NOT NULL DEFAULT '-1', `personalTabardBorderColor` int NOT NULL DEFAULT '-1',
`personalTabardBackgroundColor` int NOT NULL DEFAULT '-1', `personalTabardBackgroundColor` int NOT NULL DEFAULT '-1',
`transmogOutfitEquippedId` int NOT NULL DEFAULT '2',
`transmogOutfitLocked` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`guid`), PRIMARY KEY (`guid`),
UNIQUE KEY `idx_name` (`name`), UNIQUE KEY `idx_name` (`name`),
KEY `idx_account` (`account`), KEY `idx_account` (`account`),
@@ -3832,7 +3917,8 @@ INSERT INTO `updates` VALUES
('2025_11_25_00_characters.sql','A0C04B2404B1832421402F78436DDC4AA18EBAD8','ARCHIVED','2025-11-25 22:28:32',0), ('2025_11_25_00_characters.sql','A0C04B2404B1832421402F78436DDC4AA18EBAD8','ARCHIVED','2025-11-25 22:28:32',0),
('2026_01_14_00_characters.sql','FF5D889A41BBD9F9827489DEC08BCA9DB457933E','ARCHIVED','2026-01-14 23:40:33',0), ('2026_01_14_00_characters.sql','FF5D889A41BBD9F9827489DEC08BCA9DB457933E','ARCHIVED','2026-01-14 23:40:33',0),
('2026_01_28_00_characters.sql','807B6622970E81089806C3B45C6C7A32EF531BCA','ARCHIVED','2026-01-25 21:53:51',0), ('2026_01_28_00_characters.sql','807B6622970E81089806C3B45C6C7A32EF531BCA','ARCHIVED','2026-01-25 21:53:51',0),
('2026_02_06_00_characters.sql','90735F4481A137E79B8371F291008CF6051657AC','ARCHIVED','2026-02-06 12:45:48',0); ('2026_02_06_00_characters.sql','90735F4481A137E79B8371F291008CF6051657AC','ARCHIVED','2026-02-06 12:45:48',0),
('2026_03_21_00_characters.sql','87963F4E341B195D4B4C4514A3119092DF127431','RELEASED','2026-03-21 00:42:13',0);
/*!40000 ALTER TABLE `updates` ENABLE KEYS */; /*!40000 ALTER TABLE `updates` ENABLE KEYS */;
UNLOCK TABLES; UNLOCK TABLES;
@@ -0,0 +1,10 @@
--
-- Table structure for table `battlenet_account_transmog_outfits`
--
DROP TABLE IF EXISTS `battlenet_account_transmog_outfits`;
CREATE TABLE `battlenet_account_transmog_outfits` (
`battlenetAccountId` int unsigned NOT NULL,
`transmogOutfitId` int NOT NULL DEFAULT '0',
PRIMARY KEY (`battlenetAccountId`,`transmogOutfitId`),
CONSTRAINT `fk_battlenet_account_transmog_outfits` FOREIGN KEY (`battlenetAccountId`) REFERENCES `battlenet_accounts` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -0,0 +1,47 @@
ALTER TABLE `characters`
ADD `transmogOutfitEquippedId` int NOT NULL DEFAULT 2 AFTER `personalTabardBackgroundColor`,
ADD `transmogOutfitLocked` tinyint(1) NOT NULL DEFAULT 0 AFTER `transmogOutfitEquippedId`;
--
-- Table structure for table `character_transmog_outfit`
--
DROP TABLE IF EXISTS `character_transmog_outfit`;
CREATE TABLE `character_transmog_outfit` (
`guid` bigint NOT NULL,
`transmogOutfitId` int NOT NULL,
`name` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
`icon` int NOT NULL,
`situationsEnabled` tinyint(1) NOT NULL,
PRIMARY KEY (`guid`,`transmogOutfitId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `character_transmog_outfit_situation`
--
DROP TABLE IF EXISTS `character_transmog_outfit_situation`;
CREATE TABLE `character_transmog_outfit_situation` (
`guid` bigint NOT NULL,
`transmogOutfitId` int NOT NULL,
`situationID` int NOT NULL,
`specID` int NOT NULL,
`loadoutID` int NOT NULL,
`equipmentSetID` int NOT NULL,
PRIMARY KEY (`guid`,`transmogOutfitId`,`situationID`,`specID`,`loadoutID`,`equipmentSetID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `character_transmog_outfit_slot`
--
DROP TABLE IF EXISTS `character_transmog_outfit_slot`;
CREATE TABLE `character_transmog_outfit_slot` (
`guid` bigint NOT NULL,
`transmogOutfitId` int NOT NULL,
`slot` tinyint NOT NULL,
`slotOption` tinyint NOT NULL,
`itemModifiedAppearanceID` int NOT NULL,
`appearanceDisplayType` tinyint NOT NULL,
`spellItemEnchantmentID` int NOT NULL,
`illusionDisplayType` tinyint NOT NULL,
`flags` int NOT NULL,
PRIMARY KEY (`guid`,`transmogOutfitId`,`slot`,`slotOption`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
@@ -0,0 +1,190 @@
--
-- Table structure for table `transmog_outfit_entry`
--
DROP TABLE IF EXISTS `transmog_outfit_entry`;
CREATE TABLE `transmog_outfit_entry` (
`Cost` bigint unsigned NOT NULL DEFAULT '0',
`Name` text,
`ID` int unsigned NOT NULL DEFAULT '0',
`OrderIndex` int NOT NULL DEFAULT '0',
`Source` tinyint unsigned NOT NULL DEFAULT '0',
`Flags` int NOT NULL DEFAULT '0',
`SetType` tinyint unsigned NOT NULL DEFAULT '0',
`OverrideCostModifier` float NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `transmog_outfit_entry_locale`
--
DROP TABLE IF EXISTS `transmog_outfit_entry_locale`;
CREATE TABLE `transmog_outfit_entry_locale` (
`ID` int unsigned NOT NULL DEFAULT '0',
`locale` varchar(4) NOT NULL,
`Name_lang` text,
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST COLUMNS(locale)
(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB,
PARTITION esES VALUES IN ('esES') ENGINE = InnoDB,
PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB,
PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB,
PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB,
PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB,
PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB,
PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB,
PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB,
PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB);
--
-- Table structure for table `transmog_outfit_slot_info`
--
DROP TABLE IF EXISTS `transmog_outfit_slot_info`;
CREATE TABLE `transmog_outfit_slot_info` (
`InventorySlotName` text,
`ID` int unsigned NOT NULL DEFAULT '0',
`TransmogOutfitSlotEnum` tinyint NOT NULL DEFAULT '0',
`InventorySlotEnum` int NOT NULL DEFAULT '0',
`Flags` int NOT NULL DEFAULT '0',
`Unused1200` tinyint unsigned NOT NULL DEFAULT '0',
`TransmogCollectionType` tinyint unsigned NOT NULL DEFAULT '0',
`SecondarySlotID` int NOT NULL DEFAULT '0',
`InventorySlotID` int NOT NULL DEFAULT '0',
`UnassignedAtlasID` int NOT NULL DEFAULT '0',
`UnassignedDisplayAtlasID` int NOT NULL DEFAULT '0',
`ItemCostMultiplier` float NOT NULL DEFAULT '0',
`IllusionCostMultiplier` float NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `transmog_outfit_slot_option`
--
DROP TABLE IF EXISTS `transmog_outfit_slot_option`;
CREATE TABLE `transmog_outfit_slot_option` (
`ID` int unsigned NOT NULL DEFAULT '0',
`Name` text,
`OptionEnum` tinyint unsigned NOT NULL DEFAULT '0',
`TransmogOutfitSlotInfoID` int unsigned NOT NULL DEFAULT '0',
`Flags` int NOT NULL DEFAULT '0',
`SecondaryOptionID` int NOT NULL DEFAULT '0',
`ItemCostMultiplier` float NOT NULL DEFAULT '0',
`IllusionCostMultiplier` float NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `transmog_outfit_slot_option_locale`
--
DROP TABLE IF EXISTS `transmog_outfit_slot_option_locale`;
CREATE TABLE `transmog_outfit_slot_option_locale` (
`ID` int unsigned NOT NULL DEFAULT '0',
`locale` varchar(4) NOT NULL,
`Name_lang` text,
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST COLUMNS(locale)
(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB,
PARTITION esES VALUES IN ('esES') ENGINE = InnoDB,
PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB,
PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB,
PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB,
PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB,
PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB,
PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB,
PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB,
PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB);
--
-- Table structure for table `transmog_situation`
--
DROP TABLE IF EXISTS `transmog_situation`;
CREATE TABLE `transmog_situation` (
`Name` text,
`ID` int unsigned NOT NULL DEFAULT '0',
`SituationEnum` tinyint NOT NULL DEFAULT '0',
`Flags` int NOT NULL DEFAULT '0',
`TransmogSituationGroupID` int unsigned NOT NULL DEFAULT '0',
`OrderIndex` int NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `transmog_situation_locale`
--
DROP TABLE IF EXISTS `transmog_situation_locale`;
CREATE TABLE `transmog_situation_locale` (
`ID` int unsigned NOT NULL DEFAULT '0',
`locale` varchar(4) NOT NULL,
`Name_lang` text,
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST COLUMNS(locale)
(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB,
PARTITION esES VALUES IN ('esES') ENGINE = InnoDB,
PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB,
PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB,
PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB,
PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB,
PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB,
PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB,
PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB,
PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB);
--
-- Table structure for table `transmog_situation_group`
--
DROP TABLE IF EXISTS `transmog_situation_group`;
CREATE TABLE `transmog_situation_group` (
`ID` int unsigned NOT NULL DEFAULT '0',
`TransmogSituationTriggerID` int unsigned NOT NULL DEFAULT '0',
`OrderIndex` int NOT NULL DEFAULT '0',
`Flags` int NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `transmog_situation_trigger`
--
DROP TABLE IF EXISTS `transmog_situation_trigger`;
CREATE TABLE `transmog_situation_trigger` (
`Name` text,
`Description` text,
`ID` int unsigned NOT NULL DEFAULT '0',
`TriggerEnum` tinyint unsigned NOT NULL DEFAULT '0',
`Flags` int NOT NULL DEFAULT '0',
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Table structure for table `transmog_situation_trigger_locale`
--
DROP TABLE IF EXISTS `transmog_situation_trigger_locale`;
CREATE TABLE `transmog_situation_trigger_locale` (
`ID` int unsigned NOT NULL DEFAULT '0',
`locale` varchar(4) NOT NULL,
`Name_lang` text,
`Description_lang` text,
`VerifiedBuild` int NOT NULL DEFAULT '0',
PRIMARY KEY (`ID`,`locale`,`VerifiedBuild`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
PARTITION BY LIST COLUMNS(locale)
(PARTITION deDE VALUES IN ('deDE') ENGINE = InnoDB,
PARTITION esES VALUES IN ('esES') ENGINE = InnoDB,
PARTITION esMX VALUES IN ('esMX') ENGINE = InnoDB,
PARTITION frFR VALUES IN ('frFR') ENGINE = InnoDB,
PARTITION itIT VALUES IN ('itIT') ENGINE = InnoDB,
PARTITION koKR VALUES IN ('koKR') ENGINE = InnoDB,
PARTITION ptBR VALUES IN ('ptBR') ENGINE = InnoDB,
PARTITION ruRU VALUES IN ('ruRU') ENGINE = InnoDB,
PARTITION zhCN VALUES IN ('zhCN') ENGINE = InnoDB,
PARTITION zhTW VALUES IN ('zhTW') ENGINE = InnoDB);
@@ -99,7 +99,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, "
"health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, " "health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, "
"raidDifficulty, legacyRaidDifficulty, fishingSteps, honor, honorLevel, honorRestState, honorRestBonus, numRespecs, " "raidDifficulty, legacyRaidDifficulty, fishingSteps, honor, honorLevel, honorRestState, honorRestBonus, numRespecs, "
"personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor " "personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor, transmogOutfitEquippedId, transmogOutfitLocked "
"FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC); "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_CUSTOMIZATIONS, "SELECT chrCustomizationOptionID, chrCustomizationChoiceID FROM character_customizations WHERE guid = ? ORDER BY chrCustomizationOptionID", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_CUSTOMIZATIONS, "SELECT chrCustomizationOptionID, chrCustomizationChoiceID FROM character_customizations WHERE guid = ? ORDER BY chrCustomizationOptionID", CONNECTION_ASYNC);
@@ -150,6 +150,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, "SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4, " PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, "SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4, "
"appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, " "appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, "
"appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC); "appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT, "SELECT transmogOutfitId, name, icon, situationsEnabled FROM character_transmog_outfit WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT_SITUATION, "SELECT transmogOutfitId, situationID, specID, loadoutID, equipmentSetID FROM character_transmog_outfit_situation WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT_SLOT, "SELECT transmogOutfitId, slot, slotOption, itemModifiedAppearanceID, appearanceDisplayType, spellItemEnchantmentID, illusionDisplayType, flags FROM character_transmog_outfit_slot WHERE guid = ? ORDER BY transmogOutfitId, slot, slotOption", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell, queueId FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell, queueId FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC);
@@ -360,6 +363,12 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"appearance16, appearance17, appearance18, mainHandEnchant, offHandEnchant) " "appearance16, appearance17, appearance18, mainHandEnchant, offHandEnchant) "
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT, "DELETE FROM character_transmog_outfits WHERE setguid=?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT, "DELETE FROM character_transmog_outfits WHERE setguid=?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_TRANSMOG_OUTFIT_2, "INSERT INTO character_transmog_outfit (guid, transmogOutfitId, name, icon, situationsEnabled) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT_2, "DELETE FROM character_transmog_outfit WHERE guid = ? AND transmogOutfitId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_TRANSMOG_OUTFIT_SITUATION, "INSERT INTO character_transmog_outfit_situation (guid, transmogOutfitId, situationID, specID, loadoutID, equipmentSetID) VALUES (?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT_SITUATION, "DELETE FROM character_transmog_outfit_situation WHERE guid = ? AND transmogOutfitId = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_TRANSMOG_OUTFIT_SLOT, "INSERT INTO character_transmog_outfit_slot (guid, transmogOutfitId, slot, slotOption, itemModifiedAppearanceID, appearanceDisplayType, spellItemEnchantmentID, illusionDisplayType, flags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_TRANSMOG_OUTFIT_SLOT, "DELETE FROM character_transmog_outfit_slot WHERE guid = ? AND transmogOutfitId = ?", CONNECTION_ASYNC);
// Auras // Auras
PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel) " PrepareStatement(CHAR_INS_AURA, "INSERT INTO character_aura (guid, casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel) "
@@ -481,17 +490,19 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"taximask, createTime, createMode, cinematic, " "taximask, createTime, createMode, cinematic, "
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, primarySpecialization, " "totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, primarySpecialization, "
"extra_flags, summonedPetNumber, at_login, " "extra_flags, summonedPetNumber, at_login, "
"death_expire_time, taxi_path, totalKills, " "death_expire_time, taxi_path, totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, "
"todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, " "power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, "
"power4, power5, power6, power7, power8, power9, power10, latency, activeTalentGroup, lootSpecId, exploredZones, equipmentCache, knownTitles, actionBars, lastLoginBuild) VALUES " "latency, activeTalentGroup, lootSpecId, exploredZones, equipmentCache, knownTitles, actionBars, lastLoginBuild, "
"(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC); "personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor, transmogOutfitEquippedId, transmogOutfitLocked) VALUES "
"(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,inventorySlots=?,inventoryBagFlags=?,bagSlotFlags1=?,bagSlotFlags2=?,bagSlotFlags3=?,bagSlotFlags4=?,bagSlotFlags5=?," PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,inventorySlots=?,inventoryBagFlags=?,bagSlotFlags1=?,bagSlotFlags2=?,bagSlotFlags3=?,bagSlotFlags4=?,bagSlotFlags5=?,"
"bankSlots=?,bankTabs=?,bankBagFlags=?,restState=?,playerFlags=?,playerFlagsEx=?," "bankSlots=?,bankTabs=?,bankBagFlags=?,restState=?,playerFlags=?,playerFlagsEx=?,"
"map=?,instance_id=?,dungeonDifficulty=?,raidDifficulty=?,legacyRaidDifficulty=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?,totaltime=?,leveltime=?,rest_bonus=?," "map=?,instance_id=?,dungeonDifficulty=?,raidDifficulty=?,legacyRaidDifficulty=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?,totaltime=?,leveltime=?,rest_bonus=?,"
"logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,numRespecs=?,primarySpecialization=?,extra_flags=?,summonedPetNumber=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?," "logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,numRespecs=?,primarySpecialization=?,extra_flags=?,summonedPetNumber=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?,"
"totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?," "totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?,"
"watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,power7=?,power8=?,power9=?,power10=?,latency=?,activeTalentGroup=?,lootSpecId=?,exploredZones=?," "watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,power6=?,power7=?,power8=?,power9=?,power10=?,latency=?,activeTalentGroup=?,lootSpecId=?,exploredZones=?,"
"equipmentCache=?,knownTitles=?,actionBars=?,online=?,honor=?,honorLevel=?,honorRestState=?,honorRestBonus=?,lastLoginBuild=? WHERE guid=?", CONNECTION_ASYNC); "equipmentCache=?,knownTitles=?,actionBars=?,online=?,honor=?,honorLevel=?,honorRestState=?,honorRestBonus=?,lastLoginBuild=?,"
"personalTabardEmblemStyle=?,personalTabardEmblemColor=?,personalTabardBorderStyle=?,personalTabardBorderColor=?,personalTabardBackgroundColor=?,transmogOutfitEquippedId=?,transmogOutfitLocked=? WHERE guid=?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_REM_AT_LOGIN_FLAG, "UPDATE characters set at_login = at_login & ~ ? WHERE guid = ?", CONNECTION_ASYNC);
@@ -626,6 +637,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENTS, "DELETE FROM character_achievement WHERE guid = ? AND achievement NOT IN (456,457,458,459,460,461,462,463,464,465,466,467,1400,1402,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1463,3117,3259,4078,4576,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,6433,6523,6524,6743,6744,6745,6746,6747,6748,6749,6750,6751,6752,6829,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872,6873)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_ACHIEVEMENTS, "DELETE FROM character_achievement WHERE guid = ? AND achievement NOT IN (456,457,458,459,460,461,462,463,464,465,466,467,1400,1402,1404,1405,1406,1407,1408,1409,1410,1411,1412,1413,1414,1415,1416,1417,1418,1419,1420,1421,1422,1423,1424,1425,1426,1427,1463,3117,3259,4078,4576,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,6433,6523,6524,6743,6744,6745,6746,6747,6748,6749,6750,6751,6752,6829,6859,6860,6861,6862,6863,6864,6865,6866,6867,6868,6869,6870,6871,6872,6873)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_EQUIPMENTSETS, "DELETE FROM character_equipmentsets WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_EQUIPMENTSETS, "DELETE FROM character_equipmentsets WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS, "DELETE FROM character_transmog_outfits WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS, "DELETE FROM character_transmog_outfits WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFIT_BY_CHAR, "DELETE FROM character_transmog_outfit WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFIT_SITUATION_BY_CHAR, "DELETE FROM character_transmog_outfit_slot WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFIT_SLOT_BY_CHAR, "DELETE FROM character_transmog_outfit_situation WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, "DELETE FROM guild_eventlog WHERE PlayerGuid1 = ? OR PlayerGuid2 = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, "DELETE FROM guild_eventlog WHERE PlayerGuid1 = ? OR PlayerGuid2 = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, "DELETE FROM guild_bank_eventlog WHERE PlayerGuid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CHAR_GLYPHS, "DELETE FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
@@ -107,6 +107,9 @@ enum CharacterDatabaseStatements : uint32
CHAR_SEL_CHARACTER_CRITERIAPROGRESS, CHAR_SEL_CHARACTER_CRITERIAPROGRESS,
CHAR_SEL_CHARACTER_EQUIPMENTSETS, CHAR_SEL_CHARACTER_EQUIPMENTSETS,
CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS, CHAR_SEL_CHARACTER_TRANSMOG_OUTFITS,
CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT,
CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT_SITUATION,
CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT_SLOT,
CHAR_SEL_CHARACTER_BGDATA, CHAR_SEL_CHARACTER_BGDATA,
CHAR_SEL_CHARACTER_GLYPHS, CHAR_SEL_CHARACTER_GLYPHS,
CHAR_SEL_CHARACTER_TALENTS, CHAR_SEL_CHARACTER_TALENTS,
@@ -270,6 +273,13 @@ enum CharacterDatabaseStatements : uint32
CHAR_INS_TRANSMOG_OUTFIT, CHAR_INS_TRANSMOG_OUTFIT,
CHAR_DEL_TRANSMOG_OUTFIT, CHAR_DEL_TRANSMOG_OUTFIT,
CHAR_INS_TRANSMOG_OUTFIT_2,
CHAR_DEL_TRANSMOG_OUTFIT_2,
CHAR_INS_TRANSMOG_OUTFIT_SITUATION,
CHAR_DEL_TRANSMOG_OUTFIT_SITUATION,
CHAR_INS_TRANSMOG_OUTFIT_SLOT,
CHAR_DEL_TRANSMOG_OUTFIT_SLOT,
CHAR_INS_AURA, CHAR_INS_AURA,
CHAR_INS_AURA_EFFECT, CHAR_INS_AURA_EFFECT,
@@ -496,6 +506,9 @@ enum CharacterDatabaseStatements : uint32
CHAR_DEL_CHAR_ACHIEVEMENTS, CHAR_DEL_CHAR_ACHIEVEMENTS,
CHAR_DEL_CHAR_EQUIPMENTSETS, CHAR_DEL_CHAR_EQUIPMENTSETS,
CHAR_DEL_CHAR_TRANSMOG_OUTFITS, CHAR_DEL_CHAR_TRANSMOG_OUTFITS,
CHAR_DEL_CHAR_TRANSMOG_OUTFIT_BY_CHAR,
CHAR_DEL_CHAR_TRANSMOG_OUTFIT_SITUATION_BY_CHAR,
CHAR_DEL_CHAR_TRANSMOG_OUTFIT_SLOT_BY_CHAR,
CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER, CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER,
CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER, CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER,
CHAR_DEL_CHAR_GLYPHS, CHAR_DEL_CHAR_GLYPHS,
@@ -1997,6 +1997,26 @@ void HotfixDatabaseConnection::DoPrepareStatements()
" WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_ILLUSION, "SELECT MAX(ID) + 1 FROM transmog_illusion", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_ILLUSION, "SELECT MAX(ID) + 1 FROM transmog_illusion", CONNECTION_SYNCH);
// TransmogOutfitEntry.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY, "SELECT Cost, Name, ID, OrderIndex, Source, Flags, SetType, OverrideCostModifier"
" FROM transmog_outfit_entry WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY, "SELECT MAX(ID) + 1 FROM transmog_outfit_entry", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY, "SELECT ID, Name_lang FROM transmog_outfit_entry_locale WHERE (`VerifiedBuild` > 0) = ?"
" AND locale = ?", CONNECTION_SYNCH);
// TransmogOutfitSlotInfo.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_INFO, "SELECT InventorySlotName, ID, TransmogOutfitSlotEnum, InventorySlotEnum, Flags, "
"Unused1200, TransmogCollectionType, SecondarySlotID, InventorySlotID, UnassignedAtlasID, UnassignedDisplayAtlasID, ItemCostMultiplier, "
"IllusionCostMultiplier FROM transmog_outfit_slot_info WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_INFO, "SELECT MAX(ID) + 1 FROM transmog_outfit_slot_info", CONNECTION_SYNCH);
// TransmogOutfitSlotOption.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION, "SELECT ID, Name, OptionEnum, TransmogOutfitSlotInfoID, Flags, SecondaryOptionID, "
"ItemCostMultiplier, IllusionCostMultiplier FROM transmog_outfit_slot_option WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION, "SELECT MAX(ID) + 1 FROM transmog_outfit_slot_option", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION, "SELECT ID, Name_lang FROM transmog_outfit_slot_option_locale"
" WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH);
// TransmogSet.db2 // TransmogSet.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_SET, "SELECT Name, ID, ClassMask, TrackingQuestID, Flags, TransmogSetGroupID, ItemNameDescriptionID, " PrepareStatement(HOTFIX_SEL_TRANSMOG_SET, "SELECT Name, ID, ClassMask, TrackingQuestID, Flags, TransmogSetGroupID, ItemNameDescriptionID, "
"ParentTransmogSetID, Unknown810, ExpansionID, PatchID, UiOrder, PlayerConditionID FROM transmog_set WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); "ParentTransmogSetID, Unknown810, ExpansionID, PatchID, UiOrder, PlayerConditionID FROM transmog_set WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
@@ -2014,6 +2034,25 @@ void HotfixDatabaseConnection::DoPrepareStatements()
" WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_SET_ITEM, "SELECT MAX(ID) + 1 FROM transmog_set_item", CONNECTION_SYNCH); PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_SET_ITEM, "SELECT MAX(ID) + 1 FROM transmog_set_item", CONNECTION_SYNCH);
// TransmogSituation.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_SITUATION, "SELECT Name, ID, SituationEnum, Flags, TransmogSituationGroupID, OrderIndex"
" FROM transmog_situation WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_SITUATION, "SELECT MAX(ID) + 1 FROM transmog_situation", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_TRANSMOG_SITUATION, "SELECT ID, Name_lang FROM transmog_situation_locale WHERE (`VerifiedBuild` > 0) = ?"
" AND locale = ?", CONNECTION_SYNCH);
// TransmogSituationGroup.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_SITUATION_GROUP, "SELECT ID, TransmogSituationTriggerID, OrderIndex, Flags FROM transmog_situation_group"
" WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_SITUATION_GROUP, "SELECT MAX(ID) + 1 FROM transmog_situation_group", CONNECTION_SYNCH);
// TransmogSituationTrigger.db2
PrepareStatement(HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER, "SELECT Name, Description, ID, TriggerEnum, Flags FROM transmog_situation_trigger"
" WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
PREPARE_MAX_ID_STMT(HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER, "SELECT MAX(ID) + 1 FROM transmog_situation_trigger", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER, "SELECT ID, Name_lang, Description_lang FROM transmog_situation_trigger_locale"
" WHERE (`VerifiedBuild` > 0) = ? AND locale = ?", CONNECTION_SYNCH);
// TransportAnimation.db2 // TransportAnimation.db2
PrepareStatement(HOTFIX_SEL_TRANSPORT_ANIMATION, "SELECT ID, PosX, PosY, PosZ, SequenceID, TimeIndex, TransportID FROM transport_animation" PrepareStatement(HOTFIX_SEL_TRANSPORT_ANIMATION, "SELECT ID, PosX, PosY, PosZ, SequenceID, TimeIndex, TransportID FROM transport_animation"
" WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH); " WHERE (`VerifiedBuild` > 0) = ?", CONNECTION_SYNCH);
@@ -1155,6 +1155,17 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_TRANSMOG_ILLUSION, HOTFIX_SEL_TRANSMOG_ILLUSION,
HOTFIX_SEL_TRANSMOG_ILLUSION_MAX_ID, HOTFIX_SEL_TRANSMOG_ILLUSION_MAX_ID,
HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY,
HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY_MAX_ID,
HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY_LOCALE,
HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_INFO,
HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_INFO_MAX_ID,
HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION,
HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION_MAX_ID,
HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION_LOCALE,
HOTFIX_SEL_TRANSMOG_SET, HOTFIX_SEL_TRANSMOG_SET,
HOTFIX_SEL_TRANSMOG_SET_MAX_ID, HOTFIX_SEL_TRANSMOG_SET_MAX_ID,
HOTFIX_SEL_TRANSMOG_SET_LOCALE, HOTFIX_SEL_TRANSMOG_SET_LOCALE,
@@ -1166,6 +1177,17 @@ enum HotfixDatabaseStatements : uint32
HOTFIX_SEL_TRANSMOG_SET_ITEM, HOTFIX_SEL_TRANSMOG_SET_ITEM,
HOTFIX_SEL_TRANSMOG_SET_ITEM_MAX_ID, HOTFIX_SEL_TRANSMOG_SET_ITEM_MAX_ID,
HOTFIX_SEL_TRANSMOG_SITUATION,
HOTFIX_SEL_TRANSMOG_SITUATION_MAX_ID,
HOTFIX_SEL_TRANSMOG_SITUATION_LOCALE,
HOTFIX_SEL_TRANSMOG_SITUATION_GROUP,
HOTFIX_SEL_TRANSMOG_SITUATION_GROUP_MAX_ID,
HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER,
HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER_MAX_ID,
HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER_LOCALE,
HOTFIX_SEL_TRANSPORT_ANIMATION, HOTFIX_SEL_TRANSPORT_ANIMATION,
HOTFIX_SEL_TRANSPORT_ANIMATION_MAX_ID, HOTFIX_SEL_TRANSPORT_ANIMATION_MAX_ID,
@@ -191,6 +191,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_BNET_TRANSMOG_ILLUSIONS, "SELECT blobIndex, illusionMask FROM battlenet_account_transmog_illusions WHERE battlenetAccountId = ? ORDER BY blobIndex DESC", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_TRANSMOG_ILLUSIONS, "SELECT blobIndex, illusionMask FROM battlenet_account_transmog_illusions WHERE battlenetAccountId = ? ORDER BY blobIndex DESC", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_BNET_TRANSMOG_ILLUSIONS, "INSERT INTO battlenet_account_transmog_illusions (battlenetAccountId, blobIndex, illusionMask) VALUES (?, ?, ?) " PrepareStatement(LOGIN_INS_BNET_TRANSMOG_ILLUSIONS, "INSERT INTO battlenet_account_transmog_illusions (battlenetAccountId, blobIndex, illusionMask) VALUES (?, ?, ?) "
"ON DUPLICATE KEY UPDATE illusionMask = illusionMask | VALUES(illusionMask)", CONNECTION_ASYNC); "ON DUPLICATE KEY UPDATE illusionMask = illusionMask | VALUES(illusionMask)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_BNET_TRANSMOG_OUTFITS, "SELECT transmogOutfitId FROM battlenet_account_transmog_outfits WHERE battlenetAccountId = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_BNET_TRANSMOG_OUTFITS, "INSERT IGNORE INTO battlenet_account_transmog_outfits (battlenetAccountId, transmogOutfitId) VALUES (?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_BNET_WARBAND_SCENES, "SELECT warbandSceneId, isFavorite, hasFanfare FROM battlenet_account_warband_scenes WHERE battlenetAccountId = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_WARBAND_SCENES, "SELECT warbandSceneId, isFavorite, hasFanfare FROM battlenet_account_warband_scenes WHERE battlenetAccountId = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_BNET_WARBAND_SCENE, "INSERT INTO battlenet_account_warband_scenes (battlenetAccountId, warbandSceneId, isFavorite, hasFanfare) VALUES (?, ?, ?, ?) " PrepareStatement(LOGIN_INS_BNET_WARBAND_SCENE, "INSERT INTO battlenet_account_warband_scenes (battlenetAccountId, warbandSceneId, isFavorite, hasFanfare) VALUES (?, ?, ?, ?) "
"ON DUPLICATE KEY UPDATE isFavorite = VALUES(isFavorite)", CONNECTION_ASYNC); "ON DUPLICATE KEY UPDATE isFavorite = VALUES(isFavorite)", CONNECTION_ASYNC);
@@ -176,6 +176,8 @@ enum LoginDatabaseStatements : uint32
LOGIN_DEL_BNET_ITEM_FAVORITE_APPEARANCE, LOGIN_DEL_BNET_ITEM_FAVORITE_APPEARANCE,
LOGIN_SEL_BNET_TRANSMOG_ILLUSIONS, LOGIN_SEL_BNET_TRANSMOG_ILLUSIONS,
LOGIN_INS_BNET_TRANSMOG_ILLUSIONS, LOGIN_INS_BNET_TRANSMOG_ILLUSIONS,
LOGIN_SEL_BNET_TRANSMOG_OUTFITS,
LOGIN_INS_BNET_TRANSMOG_OUTFITS,
LOGIN_SEL_BNET_WARBAND_SCENES, LOGIN_SEL_BNET_WARBAND_SCENES,
LOGIN_INS_BNET_WARBAND_SCENE, LOGIN_INS_BNET_WARBAND_SCENE,
LOGIN_UPD_BNET_WARBAND_SCENE, LOGIN_UPD_BNET_WARBAND_SCENE,
@@ -3227,8 +3227,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
{ {
itemSubclass = itemTemplate->GetSubClass(); itemSubclass = itemTemplate->GetSubClass();
if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sDB2Manager.GetItemModifiedAppearance(visibleItem.ItemID, visibleItem.ItemAppearanceModID)) if (ItemModifiedAppearanceExtraEntry const* itemModifiedAppearaceExtra = sItemModifiedAppearanceExtraStore.LookupEntry(visibleItem.ItemModifiedAppearanceID))
if (ItemModifiedAppearanceExtraEntry const* itemModifiedAppearaceExtra = sItemModifiedAppearanceExtraStore.LookupEntry(itemModifiedAppearance->ID))
if (itemModifiedAppearaceExtra->DisplayWeaponSubclassID > 0) if (itemModifiedAppearaceExtra->DisplayWeaponSubclassID > 0)
itemSubclass = itemModifiedAppearaceExtra->DisplayWeaponSubclassID; itemSubclass = itemModifiedAppearaceExtra->DisplayWeaponSubclassID;
} }
@@ -3247,8 +3246,7 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6
{ {
itemSubclass = itemTemplate->GetSubClass(); itemSubclass = itemTemplate->GetSubClass();
if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sDB2Manager.GetItemModifiedAppearance(visibleItem.ItemID, visibleItem.ItemAppearanceModID)) if (ItemModifiedAppearanceExtraEntry const* itemModifiedAppearaceExtra = sItemModifiedAppearanceExtraStore.LookupEntry(visibleItem.ItemModifiedAppearanceID))
if (ItemModifiedAppearanceExtraEntry const* itemModifiedAppearaceExtra = sItemModifiedAppearanceExtraStore.LookupEntry(itemModifiedAppearance->ID))
if (itemModifiedAppearaceExtra->DisplayWeaponSubclassID > 0) if (itemModifiedAppearaceExtra->DisplayWeaponSubclassID > 0)
itemSubclass = itemModifiedAppearaceExtra->DisplayWeaponSubclassID; itemSubclass = itemModifiedAppearaceExtra->DisplayWeaponSubclassID;
} }
+2 -1
View File
@@ -22,6 +22,7 @@
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "SpellInfo.h" #include "SpellInfo.h"
#include "SpellMgr.h" #include "SpellMgr.h"
#include "TransmogMgr.h"
static constexpr char HYPERLINK_DATA_DELIMITER = ':'; static constexpr char HYPERLINK_DATA_DELIMITER = ':';
@@ -527,7 +528,7 @@ bool Trinity::Hyperlinks::LinkTags::transmogillusion::StoreTo(SpellItemEnchantme
if (!t.TryConsumeTo(spellItemEnchantmentId)) if (!t.TryConsumeTo(spellItemEnchantmentId))
return false; return false;
return !!(val = sSpellItemEnchantmentStore.LookupEntry(spellItemEnchantmentId)) return !!(val = sSpellItemEnchantmentStore.LookupEntry(spellItemEnchantmentId))
&& sDB2Manager.GetTransmogIllusionForEnchantment(spellItemEnchantmentId) && t.IsEmpty(); && TransmogMgr::GetTransmogIllusionForSpellItemEnchantment(spellItemEnchantmentId) && t.IsEmpty();
} }
bool Trinity::Hyperlinks::LinkTags::transmogset::StoreTo(TransmogSetEntry const*& val, std::string_view text) bool Trinity::Hyperlinks::LinkTags::transmogset::StoreTo(TransmogSetEntry const*& val, std::string_view text)
+98
View File
@@ -6579,6 +6579,62 @@ struct TransmogIllusionLoadInfo
static constexpr DB2LoadInfo Instance{ Fields, 5, &TransmogIllusionMeta::Instance, HOTFIX_SEL_TRANSMOG_ILLUSION }; static constexpr DB2LoadInfo Instance{ Fields, 5, &TransmogIllusionMeta::Instance, HOTFIX_SEL_TRANSMOG_ILLUSION };
}; };
struct TransmogOutfitEntryLoadInfo
{
static constexpr DB2FieldMeta Fields[8] =
{
{ .IsSigned = false, .Type = FT_LONG, .Name = "Cost" },
{ .IsSigned = false, .Type = FT_STRING, .Name = "Name" },
{ .IsSigned = false, .Type = FT_INT, .Name = "ID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "OrderIndex" },
{ .IsSigned = false, .Type = FT_BYTE, .Name = "Source" },
{ .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
{ .IsSigned = false, .Type = FT_BYTE, .Name = "SetType" },
{ .IsSigned = false, .Type = FT_FLOAT, .Name = "OverrideCostModifier" },
};
static constexpr DB2LoadInfo Instance{ Fields, 8, &TransmogOutfitEntryMeta::Instance, HOTFIX_SEL_TRANSMOG_OUTFIT_ENTRY };
};
struct TransmogOutfitSlotInfoLoadInfo
{
static constexpr DB2FieldMeta Fields[13] =
{
{ .IsSigned = false, .Type = FT_STRING_NOT_LOCALIZED, .Name = "InventorySlotName" },
{ .IsSigned = false, .Type = FT_INT, .Name = "ID" },
{ .IsSigned = true, .Type = FT_BYTE, .Name = "TransmogOutfitSlotEnum" },
{ .IsSigned = true, .Type = FT_INT, .Name = "InventorySlotEnum" },
{ .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
{ .IsSigned = false, .Type = FT_BYTE, .Name = "Unused1200" },
{ .IsSigned = false, .Type = FT_BYTE, .Name = "TransmogCollectionType" },
{ .IsSigned = true, .Type = FT_INT, .Name = "SecondarySlotID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "InventorySlotID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "UnassignedAtlasID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "UnassignedDisplayAtlasID" },
{ .IsSigned = false, .Type = FT_FLOAT, .Name = "ItemCostMultiplier" },
{ .IsSigned = false, .Type = FT_FLOAT, .Name = "IllusionCostMultiplier" },
};
static constexpr DB2LoadInfo Instance{ Fields, 13, &TransmogOutfitSlotInfoMeta::Instance, HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_INFO };
};
struct TransmogOutfitSlotOptionLoadInfo
{
static constexpr DB2FieldMeta Fields[8] =
{
{ .IsSigned = false, .Type = FT_INT, .Name = "ID" },
{ .IsSigned = false, .Type = FT_STRING, .Name = "Name" },
{ .IsSigned = false, .Type = FT_BYTE, .Name = "OptionEnum" },
{ .IsSigned = false, .Type = FT_INT, .Name = "TransmogOutfitSlotInfoID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
{ .IsSigned = true, .Type = FT_INT, .Name = "SecondaryOptionID" },
{ .IsSigned = false, .Type = FT_FLOAT, .Name = "ItemCostMultiplier" },
{ .IsSigned = false, .Type = FT_FLOAT, .Name = "IllusionCostMultiplier" },
};
static constexpr DB2LoadInfo Instance{ Fields, 8, &TransmogOutfitSlotOptionMeta::Instance, HOTFIX_SEL_TRANSMOG_OUTFIT_SLOT_OPTION };
};
struct TransmogSetLoadInfo struct TransmogSetLoadInfo
{ {
static constexpr DB2FieldMeta Fields[13] = static constexpr DB2FieldMeta Fields[13] =
@@ -6625,6 +6681,48 @@ struct TransmogSetItemLoadInfo
static constexpr DB2LoadInfo Instance{ Fields, 4, &TransmogSetItemMeta::Instance, HOTFIX_SEL_TRANSMOG_SET_ITEM }; static constexpr DB2LoadInfo Instance{ Fields, 4, &TransmogSetItemMeta::Instance, HOTFIX_SEL_TRANSMOG_SET_ITEM };
}; };
struct TransmogSituationLoadInfo
{
static constexpr DB2FieldMeta Fields[6] =
{
{ .IsSigned = false, .Type = FT_STRING, .Name = "Name" },
{ .IsSigned = false, .Type = FT_INT, .Name = "ID" },
{ .IsSigned = true, .Type = FT_BYTE, .Name = "SituationEnum" },
{ .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
{ .IsSigned = false, .Type = FT_INT, .Name = "TransmogSituationGroupID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "OrderIndex" },
};
static constexpr DB2LoadInfo Instance{ Fields, 6, &TransmogSituationMeta::Instance, HOTFIX_SEL_TRANSMOG_SITUATION };
};
struct TransmogSituationGroupLoadInfo
{
static constexpr DB2FieldMeta Fields[4] =
{
{ .IsSigned = false, .Type = FT_INT, .Name = "ID" },
{ .IsSigned = false, .Type = FT_INT, .Name = "TransmogSituationTriggerID" },
{ .IsSigned = true, .Type = FT_INT, .Name = "OrderIndex" },
{ .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
};
static constexpr DB2LoadInfo Instance{ Fields, 4, &TransmogSituationGroupMeta::Instance, HOTFIX_SEL_TRANSMOG_SITUATION_GROUP };
};
struct TransmogSituationTriggerLoadInfo
{
static constexpr DB2FieldMeta Fields[5] =
{
{ .IsSigned = false, .Type = FT_STRING, .Name = "Name" },
{ .IsSigned = false, .Type = FT_STRING, .Name = "Description" },
{ .IsSigned = false, .Type = FT_INT, .Name = "ID" },
{ .IsSigned = false, .Type = FT_BYTE, .Name = "TriggerEnum" },
{ .IsSigned = true, .Type = FT_INT, .Name = "Flags" },
};
static constexpr DB2LoadInfo Instance{ Fields, 5, &TransmogSituationTriggerMeta::Instance, HOTFIX_SEL_TRANSMOG_SITUATION_TRIGGER };
};
struct TransportAnimationLoadInfo struct TransportAnimationLoadInfo
{ {
static constexpr DB2FieldMeta Fields[7] = static constexpr DB2FieldMeta Fields[7] =
+12 -70
View File
@@ -382,6 +382,12 @@ DB2Storage<TraitTreeXTraitCostEntry> sTraitTreeXTraitCostStore("Trait
DB2Storage<TraitTreeXTraitCurrencyEntry> sTraitTreeXTraitCurrencyStore("TraitTreeXTraitCurrency.db2", &TraitTreeXTraitCurrencyLoadInfo::Instance); DB2Storage<TraitTreeXTraitCurrencyEntry> sTraitTreeXTraitCurrencyStore("TraitTreeXTraitCurrency.db2", &TraitTreeXTraitCurrencyLoadInfo::Instance);
DB2Storage<TransmogHolidayEntry> sTransmogHolidayStore("TransmogHoliday.db2", &TransmogHolidayLoadInfo::Instance); DB2Storage<TransmogHolidayEntry> sTransmogHolidayStore("TransmogHoliday.db2", &TransmogHolidayLoadInfo::Instance);
DB2Storage<TransmogIllusionEntry> sTransmogIllusionStore("TransmogIllusion.db2", &TransmogIllusionLoadInfo::Instance); DB2Storage<TransmogIllusionEntry> sTransmogIllusionStore("TransmogIllusion.db2", &TransmogIllusionLoadInfo::Instance);
DB2Storage<TransmogOutfitEntryEntry> sTransmogOutfitEntryStore("TransmogOutfitEntry.db2", &TransmogOutfitEntryLoadInfo::Instance);
DB2Storage<TransmogOutfitSlotInfoEntry> sTransmogOutfitSlotInfoStore("TransmogOutfitSlotInfo.db2", &TransmogOutfitSlotInfoLoadInfo::Instance);
DB2Storage<TransmogOutfitSlotOptionEntry> sTransmogOutfitSlotOptionInfoStore("TransmogOutfitSlotOption.db2", &TransmogOutfitSlotOptionLoadInfo::Instance);
DB2Storage<TransmogSituationEntry> sTransmogSituationStore("TransmogSituation.db2", &TransmogSituationLoadInfo::Instance);
DB2Storage<TransmogSituationGroupEntry> sTransmogSituationGroupStore("TransmogSituationGroup.db2", &TransmogSituationGroupLoadInfo::Instance);
DB2Storage<TransmogSituationTriggerEntry> sTransmogSituationTriggerStore("TransmogSituationTrigger.db2", &TransmogSituationTriggerLoadInfo::Instance);
DB2Storage<TransmogSetEntry> sTransmogSetStore("TransmogSet.db2", &TransmogSetLoadInfo::Instance); DB2Storage<TransmogSetEntry> sTransmogSetStore("TransmogSet.db2", &TransmogSetLoadInfo::Instance);
DB2Storage<TransmogSetGroupEntry> sTransmogSetGroupStore("TransmogSetGroup.db2", &TransmogSetGroupLoadInfo::Instance); DB2Storage<TransmogSetGroupEntry> sTransmogSetGroupStore("TransmogSetGroup.db2", &TransmogSetGroupLoadInfo::Instance);
DB2Storage<TransmogSetItemEntry> sTransmogSetItemStore("TransmogSetItem.db2", &TransmogSetItemLoadInfo::Instance); DB2Storage<TransmogSetItemEntry> sTransmogSetItemStore("TransmogSetItem.db2", &TransmogSetItemLoadInfo::Instance);
@@ -426,7 +432,6 @@ typedef std::unordered_map<uint32 /*glyphPropertiesId*/, std::vector<ChrSpeciali
typedef std::unordered_map<uint32 /*itemId*/, ItemChildEquipmentEntry const*> ItemChildEquipmentContainer; typedef std::unordered_map<uint32 /*itemId*/, ItemChildEquipmentEntry const*> ItemChildEquipmentContainer;
typedef std::array<ItemClassEntry const*, 21> ItemClassByOldEnumContainer; typedef std::array<ItemClassEntry const*, 21> ItemClassByOldEnumContainer;
typedef std::unordered_map<uint32, std::vector<ItemLimitCategoryConditionEntry const*>> ItemLimitCategoryConditionContainer; typedef std::unordered_map<uint32, std::vector<ItemLimitCategoryConditionEntry const*>> ItemLimitCategoryConditionContainer;
typedef std::unordered_map<uint32 /*itemId | appearanceMod << 24*/, ItemModifiedAppearanceEntry const*> ItemModifiedAppearanceByItemContainer;
typedef std::unordered_map<uint32, std::vector<ItemSetSpellEntry const*>> ItemSetSpellContainer; typedef std::unordered_map<uint32, std::vector<ItemSetSpellEntry const*>> ItemSetSpellContainer;
typedef std::unordered_map<uint32, std::vector<ItemSpecOverrideEntry const*>> ItemSpecOverridesContainer; typedef std::unordered_map<uint32, std::vector<ItemSpecOverrideEntry const*>> ItemSpecOverridesContainer;
typedef std::unordered_map<uint32, std::unordered_map<uint32, MapDifficultyEntry const*>> MapDifficultyContainer; typedef std::unordered_map<uint32, std::unordered_map<uint32, MapDifficultyEntry const*>> MapDifficultyContainer;
@@ -505,7 +510,6 @@ namespace
ItemClassByOldEnumContainer _itemClassByOldEnum; ItemClassByOldEnumContainer _itemClassByOldEnum;
std::unordered_set<uint32> _itemsWithCurrencyCost; std::unordered_set<uint32> _itemsWithCurrencyCost;
ItemLimitCategoryConditionContainer _itemCategoryConditions; ItemLimitCategoryConditionContainer _itemCategoryConditions;
ItemModifiedAppearanceByItemContainer _itemModifiedAppearancesByItem;
ItemSetSpellContainer _itemSetSpells; ItemSetSpellContainer _itemSetSpells;
ItemSpecOverridesContainer _itemSpecOverrides; ItemSpecOverridesContainer _itemSpecOverrides;
std::vector<JournalTierEntry const*> _journalTiersByIndex; std::vector<JournalTierEntry const*> _journalTiersByIndex;
@@ -536,9 +540,6 @@ namespace
TalentsByPosition _talentsByPosition; TalentsByPosition _talentsByPosition;
std::unordered_map<std::pair<uint32, uint32>, TaxiPathEntry const*> _taxiPaths; std::unordered_map<std::pair<uint32, uint32>, TaxiPathEntry const*> _taxiPaths;
ToyItemIdsContainer _toys; ToyItemIdsContainer _toys;
std::unordered_map<uint32, TransmogIllusionEntry const*> _transmogIllusionsByEnchantmentId;
std::unordered_map<uint32, std::vector<TransmogSetEntry const*>> _transmogSetsByItemModifiedAppearance;
std::unordered_map<uint32, std::vector<TransmogSetItemEntry const*>> _transmogSetItemsByTransmogSet;
std::unordered_map<int32, UiMapBounds> _uiMapBounds; std::unordered_map<int32, UiMapBounds> _uiMapBounds;
std::unordered_multimap<int32, UiMapAssignmentEntry const*> _uiMapAssignmentByMap[MAX_UI_MAP_SYSTEM]; std::unordered_multimap<int32, UiMapAssignmentEntry const*> _uiMapAssignmentByMap[MAX_UI_MAP_SYSTEM];
std::unordered_multimap<int32, UiMapAssignmentEntry const*> _uiMapAssignmentByArea[MAX_UI_MAP_SYSTEM]; std::unordered_multimap<int32, UiMapAssignmentEntry const*> _uiMapAssignmentByArea[MAX_UI_MAP_SYSTEM];
@@ -1013,6 +1014,12 @@ uint32 DB2Manager::LoadStores(std::string const& dataPath, LocaleConstant defaul
LOAD_DB2(sTraitTreeXTraitCurrencyStore); LOAD_DB2(sTraitTreeXTraitCurrencyStore);
LOAD_DB2(sTransmogHolidayStore); LOAD_DB2(sTransmogHolidayStore);
LOAD_DB2(sTransmogIllusionStore); LOAD_DB2(sTransmogIllusionStore);
LOAD_DB2(sTransmogOutfitEntryStore);
LOAD_DB2(sTransmogOutfitSlotInfoStore);
LOAD_DB2(sTransmogOutfitSlotOptionInfoStore);
LOAD_DB2(sTransmogSituationStore);
LOAD_DB2(sTransmogSituationGroupStore);
LOAD_DB2(sTransmogSituationTriggerStore);
LOAD_DB2(sTransmogSetStore); LOAD_DB2(sTransmogSetStore);
LOAD_DB2(sTransmogSetGroupStore); LOAD_DB2(sTransmogSetGroupStore);
LOAD_DB2(sTransmogSetItemStore); LOAD_DB2(sTransmogSetItemStore);
@@ -1359,12 +1366,6 @@ void DB2Manager::IndexLoadedStores()
for (ItemLimitCategoryConditionEntry const* condition : sItemLimitCategoryConditionStore) for (ItemLimitCategoryConditionEntry const* condition : sItemLimitCategoryConditionStore)
_itemCategoryConditions[condition->ParentItemLimitCategoryID].push_back(condition); _itemCategoryConditions[condition->ParentItemLimitCategoryID].push_back(condition);
for (ItemModifiedAppearanceEntry const* appearanceMod : sItemModifiedAppearanceStore)
{
ASSERT(appearanceMod->ItemID <= 0xFFFFFF);
_itemModifiedAppearancesByItem[appearanceMod->ItemID | (appearanceMod->ItemAppearanceModifierID << 24)] = appearanceMod;
}
for (ItemSetSpellEntry const* itemSetSpell : sItemSetSpellStore) for (ItemSetSpellEntry const* itemSetSpell : sItemSetSpellStore)
_itemSetSpells[itemSetSpell->ItemSetID].push_back(itemSetSpell); _itemSetSpells[itemSetSpell->ItemSetID].push_back(itemSetSpell);
@@ -1576,19 +1577,6 @@ void DB2Manager::IndexLoadedStores()
for (ToyEntry const* toy : sToyStore) for (ToyEntry const* toy : sToyStore)
_toys.insert(toy->ItemID); _toys.insert(toy->ItemID);
for (TransmogIllusionEntry const* transmogIllusion : sTransmogIllusionStore)
_transmogIllusionsByEnchantmentId[transmogIllusion->SpellItemEnchantmentID] = transmogIllusion;
for (TransmogSetItemEntry const* transmogSetItem : sTransmogSetItemStore)
{
TransmogSetEntry const* set = sTransmogSetStore.LookupEntry(transmogSetItem->TransmogSetID);
if (!set)
continue;
_transmogSetsByItemModifiedAppearance[transmogSetItem->ItemModifiedAppearanceID].push_back(set);
_transmogSetItemsByTransmogSet[transmogSetItem->TransmogSetID].push_back(transmogSetItem);
}
std::unordered_multimap<int32, UiMapAssignmentEntry const*> uiMapAssignmentByUiMap; std::unordered_multimap<int32, UiMapAssignmentEntry const*> uiMapAssignmentByUiMap;
for (UiMapAssignmentEntry const* uiMapAssignment : sUiMapAssignmentStore) for (UiMapAssignmentEntry const* uiMapAssignment : sUiMapAssignmentStore)
{ {
@@ -2649,37 +2637,6 @@ std::vector<ItemLimitCategoryConditionEntry const*> const* DB2Manager::GetItemLi
return Trinity::Containers::MapGetValuePtr(_itemCategoryConditions, categoryId); return Trinity::Containers::MapGetValuePtr(_itemCategoryConditions, categoryId);
} }
uint32 DB2Manager::GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const
{
if (ItemModifiedAppearanceEntry const* modifiedAppearance = GetItemModifiedAppearance(itemId, appearanceModId))
if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(modifiedAppearance->ItemAppearanceID))
return itemAppearance->ItemDisplayInfoID;
return 0;
}
ItemModifiedAppearanceEntry const* DB2Manager::GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId) const
{
auto itr = _itemModifiedAppearancesByItem.find(itemId | (appearanceModId << 24));
if (itr != _itemModifiedAppearancesByItem.end())
return itr->second;
// Fall back to unmodified appearance
if (appearanceModId)
{
itr = _itemModifiedAppearancesByItem.find(itemId);
if (itr != _itemModifiedAppearancesByItem.end())
return itr->second;
}
return nullptr;
}
ItemModifiedAppearanceEntry const* DB2Manager::GetDefaultItemModifiedAppearance(uint32 itemId) const
{
return Trinity::Containers::MapGetValuePtr(_itemModifiedAppearancesByItem, itemId);
}
std::vector<ItemSetSpellEntry const*> const* DB2Manager::GetItemSetSpells(uint32 itemSetId) const std::vector<ItemSetSpellEntry const*> const* DB2Manager::GetItemSetSpells(uint32 itemSetId) const
{ {
return Trinity::Containers::MapGetValuePtr(_itemSetSpells, itemSetId); return Trinity::Containers::MapGetValuePtr(_itemSetSpells, itemSetId);
@@ -3116,21 +3073,6 @@ bool DB2Manager::IsToyItem(uint32 toy) const
return _toys.count(toy) > 0; return _toys.count(toy) > 0;
} }
TransmogIllusionEntry const* DB2Manager::GetTransmogIllusionForEnchantment(uint32 spellItemEnchantmentId) const
{
return Trinity::Containers::MapGetValuePtr(_transmogIllusionsByEnchantmentId, spellItemEnchantmentId);
}
std::vector<TransmogSetEntry const*> const* DB2Manager::GetTransmogSetsForItemModifiedAppearance(uint32 itemModifiedAppearanceId) const
{
return Trinity::Containers::MapGetValuePtr(_transmogSetsByItemModifiedAppearance, itemModifiedAppearanceId);
}
std::vector<TransmogSetItemEntry const*> const* DB2Manager::GetTransmogSetItems(uint32 transmogSetId) const
{
return Trinity::Containers::MapGetValuePtr(_transmogSetItemsByTransmogSet, transmogSetId);
}
struct UiMapAssignmentStatus struct UiMapAssignmentStatus
{ {
UiMapAssignmentEntry const* UiMapAssignment = nullptr; UiMapAssignmentEntry const* UiMapAssignment = nullptr;
+6 -6
View File
@@ -306,6 +306,12 @@ TC_GAME_API extern DB2Storage<TraitTreeXTraitCostEntry> sTraitTreeXT
TC_GAME_API extern DB2Storage<TraitTreeXTraitCurrencyEntry> sTraitTreeXTraitCurrencyStore; TC_GAME_API extern DB2Storage<TraitTreeXTraitCurrencyEntry> sTraitTreeXTraitCurrencyStore;
TC_GAME_API extern DB2Storage<TransmogHolidayEntry> sTransmogHolidayStore; TC_GAME_API extern DB2Storage<TransmogHolidayEntry> sTransmogHolidayStore;
TC_GAME_API extern DB2Storage<TransmogIllusionEntry> sTransmogIllusionStore; TC_GAME_API extern DB2Storage<TransmogIllusionEntry> sTransmogIllusionStore;
TC_GAME_API extern DB2Storage<TransmogOutfitEntryEntry> sTransmogOutfitEntryStore;
TC_GAME_API extern DB2Storage<TransmogOutfitSlotInfoEntry> sTransmogOutfitSlotInfoStore;
TC_GAME_API extern DB2Storage<TransmogOutfitSlotOptionEntry> sTransmogOutfitSlotOptionInfoStore;
TC_GAME_API extern DB2Storage<TransmogSituationEntry> sTransmogSituationStore;
TC_GAME_API extern DB2Storage<TransmogSituationGroupEntry> sTransmogSituationGroupStore;
TC_GAME_API extern DB2Storage<TransmogSituationTriggerEntry> sTransmogSituationTriggerStore;
TC_GAME_API extern DB2Storage<TransmogSetEntry> sTransmogSetStore; TC_GAME_API extern DB2Storage<TransmogSetEntry> sTransmogSetStore;
TC_GAME_API extern DB2Storage<TransmogSetGroupEntry> sTransmogSetGroupStore; TC_GAME_API extern DB2Storage<TransmogSetGroupEntry> sTransmogSetGroupStore;
TC_GAME_API extern DB2Storage<TransmogSetItemEntry> sTransmogSetItemStore; TC_GAME_API extern DB2Storage<TransmogSetItemEntry> sTransmogSetItemStore;
@@ -499,9 +505,6 @@ public:
ItemClassEntry const* GetItemClassByOldEnum(uint32 itemClass) const; ItemClassEntry const* GetItemClassByOldEnum(uint32 itemClass) const;
bool HasItemCurrencyCost(uint32 itemId) const; bool HasItemCurrencyCost(uint32 itemId) const;
std::vector<ItemLimitCategoryConditionEntry const*> const* GetItemLimitCategoryConditions(uint32 categoryId) const; std::vector<ItemLimitCategoryConditionEntry const*> const* GetItemLimitCategoryConditions(uint32 categoryId) const;
uint32 GetItemDisplayId(uint32 itemId, uint32 appearanceModId) const;
ItemModifiedAppearanceEntry const* GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId) const;
ItemModifiedAppearanceEntry const* GetDefaultItemModifiedAppearance(uint32 itemId) const;
std::vector<ItemSetSpellEntry const*> const* GetItemSetSpells(uint32 itemSetId) const; std::vector<ItemSetSpellEntry const*> const* GetItemSetSpells(uint32 itemSetId) const;
std::vector<ItemSpecOverrideEntry const*> const* GetItemSpecOverrides(uint32 itemId) const; std::vector<ItemSpecOverrideEntry const*> const* GetItemSpecOverrides(uint32 itemId) const;
JournalTierEntry const* GetJournalTier(uint32 index) const; JournalTierEntry const* GetJournalTier(uint32 index) const;
@@ -548,9 +551,6 @@ public:
TaxiPathEntry const* GetTaxiPath(uint32 from, uint32 to) const; TaxiPathEntry const* GetTaxiPath(uint32 from, uint32 to) const;
static bool IsTotemCategoryCompatibleWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId, bool requireAllTotems = true); static bool IsTotemCategoryCompatibleWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId, bool requireAllTotems = true);
bool IsToyItem(uint32 toy) const; bool IsToyItem(uint32 toy) const;
TransmogIllusionEntry const* GetTransmogIllusionForEnchantment(uint32 spellItemEnchantmentId) const;
std::vector<TransmogSetEntry const*> const* GetTransmogSetsForItemModifiedAppearance(uint32 itemModifiedAppearanceId) const;
std::vector<TransmogSetItemEntry const*> const* GetTransmogSetItems(uint32 transmogSetId) const;
static bool GetUiMapPosition(float x, float y, float z, int32 mapId, int32 areaId, int32 wmoDoodadPlacementId, int32 wmoGroupId, UiMapSystem system, bool local, static bool GetUiMapPosition(float x, float y, float z, int32 mapId, int32 areaId, int32 wmoDoodadPlacementId, int32 wmoGroupId, UiMapSystem system, bool local,
uint32* uiMapId = nullptr, DBCPosition2D* newPos = nullptr); uint32* uiMapId = nullptr, DBCPosition2D* newPos = nullptr);
bool Zone2MapCoordinates(uint32 areaId, float& x, float& y) const; bool Zone2MapCoordinates(uint32 areaId, float& x, float& y) const;
+84
View File
@@ -4696,6 +4696,57 @@ struct TransmogIllusionEntry
EnumFlag<TransmogIllusionFlags> GetFlags() const { return static_cast<TransmogIllusionFlags>(Flags); } EnumFlag<TransmogIllusionFlags> GetFlags() const { return static_cast<TransmogIllusionFlags>(Flags); }
}; };
struct TransmogOutfitEntryEntry
{
uint64 Cost;
LocalizedString Name;
uint32 ID;
int32 OrderIndex;
uint8 Source;
int32 Flags;
uint8 SetType;
float OverrideCostModifier;
TransmogOutfitEntrySource GetSource() const { return static_cast<TransmogOutfitEntrySource>(Source); }
bool HasFlag(TransmogOutfitEntryFlags flag) const { return EnumFlag(static_cast<TransmogOutfitEntryFlags>(Flags)).HasFlag(flag); }
TransmogOutfitSetType GetSetType() const { return static_cast<TransmogOutfitSetType>(SetType); }
};
struct TransmogOutfitSlotInfoEntry
{
char const* InventorySlotName;
uint32 ID;
int8 TransmogOutfitSlotEnum;
int32 InventorySlotEnum;
int32 Flags;
uint8 Unused1200;
uint8 TransmogCollectionType;
int32 SecondarySlotID;
int32 InventorySlotID;
int32 UnassignedAtlasID;
int32 UnassignedDisplayAtlasID;
float ItemCostMultiplier;
float IllusionCostMultiplier;
TransmogOutfitSlot GetSlot() const { return static_cast<TransmogOutfitSlot>(TransmogOutfitSlotEnum); }
bool HasFlag(TransmogOutfitSlotFlags flag) const { return EnumFlag(static_cast<TransmogOutfitSlotFlags>(Flags)).HasFlag(flag); }
};
struct TransmogOutfitSlotOptionEntry
{
uint32 ID;
LocalizedString Name;
uint8 OptionEnum;
uint32 TransmogOutfitSlotInfoID;
int32 Flags;
int32 SecondaryOptionID;
float ItemCostMultiplier;
float IllusionCostMultiplier;
TransmogOutfitSlotOption GetOption() const { return static_cast<TransmogOutfitSlotOption>(OptionEnum); }
bool HasFlag(TransmogOutfitSlotOptionFlags flag) const { return EnumFlag(static_cast<TransmogOutfitSlotOptionFlags>(Flags)).HasFlag(flag); }
};
struct TransmogSetEntry struct TransmogSetEntry
{ {
LocalizedString Name; LocalizedString Name;
@@ -4727,6 +4778,39 @@ struct TransmogSetItemEntry
int32 Flags; int32 Flags;
}; };
struct TransmogSituationEntry
{
LocalizedString Name;
uint32 ID;
int8 SituationEnum;
int32 Flags;
uint32 TransmogSituationGroupID;
int32 OrderIndex;
TransmogSituation GetSituation() const { return static_cast<TransmogSituation>(SituationEnum); }
bool HasFlag(TransmogSituationFlags flag) const { return EnumFlag(static_cast<TransmogSituationFlags>(Flags)).HasFlag(flag); }
};
struct TransmogSituationGroupEntry
{
uint32 ID;
uint32 TransmogSituationTriggerID;
int32 OrderIndex;
int32 Flags;
};
struct TransmogSituationTriggerEntry
{
LocalizedString Name;
LocalizedString Description;
uint32 ID;
uint8 TriggerEnum;
int32 Flags;
TransmogSituationTrigger GetTrigger() const { return static_cast<TransmogSituationTrigger>(TriggerEnum); }
bool HasFlag(TransmogSituationTriggerFlags flag) const { return EnumFlag(static_cast<TransmogSituationTriggerFlags>(Flags)).HasFlag(flag); }
};
struct TransportAnimationEntry struct TransportAnimationEntry
{ {
uint32 ID; uint32 ID;
+173
View File
@@ -2520,6 +2520,179 @@ enum class TransmogIllusionFlags : int32
DEFINE_ENUM_FLAG(TransmogIllusionFlags); DEFINE_ENUM_FLAG(TransmogIllusionFlags);
enum class TransmogOutfitDisplayType : uint8
{
Unassigned = 0,
Assigned = 1,
Equipped = 2,
Hidden = 3,
Disabled = 4,
Max
};
enum class TransmogOutfitEquipAction : uint8
{
Equip = 0,
EquipAndLock = 1,
Remove = 2,
RemoveAndLock = 3,
Unlock = 4,
Lock = 5,
};
enum class TransmogOutfitEntryFlags : int32
{
AutomaticallyAwardedOnLogin = 0x01,
UseOverrideName = 0x02,
OnlyAvailableDuringEvent = 0x04,
SortedToTopOfList = 0x08,
UseOverrideCostModifier = 0x10,
IsDefaultEquipped = 0x20
};
DEFINE_ENUM_FLAG(TransmogOutfitEntryFlags);
enum class TransmogOutfitEntrySource : uint8
{
StampedSource = 0,
AutomaticallyAwarded = 1,
PlayerPurchased = 2,
Max
};
enum class TransmogOutfitSetType : uint8
{
Equipped = 0,
Outfit = 1,
CustomSet = 2
};
enum class TransmogOutfitSlot : int8
{
Head = 0,
ShoulderRight = 1,
ShoulderLeft = 2,
Back = 3,
Chest = 4,
Tabard = 5,
Body = 6,
Wrist = 7,
Hand = 8,
Waist = 9,
Legs = 10,
Feet = 11,
WeaponMainHand = 12,
WeaponOffHand = 13,
WeaponRanged = 14,
Max
};
enum class TransmogOutfitSlotFlags : int32
{
CannotBeHidden = 0x01,
CanHaveIllusions = 0x02,
IsSecondarySlot = 0x04
};
DEFINE_ENUM_FLAG(TransmogOutfitSlotFlags);
enum class TransmogOutfitSlotOption : uint8
{
None = 0,
OneHandedWeapon = 1,
TwoHandedWeapon = 2,
RangedWeapon = 3,
OffHand = 4,
Shield = 5,
DeprecatedReuseMe = 6,
FuryTwoHandedWeapon = 7,
ArtifactSpecOne = 8,
ArtifactSpecTwo = 9,
ArtifactSpecThree = 10,
ArtifactSpecFour = 11,
Max
};
enum class TransmogOutfitSlotOptionFlags : int32
{
IllusionNotAllowed = 0x01,
DynamicOptionName = 0x02,
DisablesOffhandSlot = 0x04
};
DEFINE_ENUM_FLAG(TransmogOutfitSlotOptionFlags);
enum class TransmogSituation : int8
{
AllSpecs = 0,
Spec = 1,
AllLocations = 2,
LocationRested = 3,
LocationHouse = 4,
LocationCharacterSelect = 5,
LocationWorld = 6,
LocationDelves = 7,
LocationDungeons = 8,
LocationRaids = 9,
LocationArenas = 10,
LocationBattlegrounds = 11,
AllMovement = 12,
MovementUnmounted = 13,
MovementSwimming = 14,
MovementGroundMount = 15,
MovementFlyingMount = 16,
AllEquipmentSets = 17,
EquipmentSets = 18,
AllRacialForms = 19,
FormNative = 20,
FormNonNative = 21,
Max
};
enum class TransmogSituationFlags : int32
{
IsPlayerFacing = 0x01,
SpecUseTalentLoadout = 0x02,
AllSituation = 0x04,
DefaultsToOn = 0x08,
DynamicallyNamed = 0x10,
NoneSituation = 0x20,
DisabledSituation = 0x40
};
DEFINE_ENUM_FLAG(TransmogSituationFlags);
enum class TransmogSituationTrigger : uint8
{
None = 0,
Manual = 1,
TransmogUpdate = 2,
Location = 3,
Movement = 4,
Specialization = 5,
EquipmentSet = 6,
Forms = 7,
EventOutfit = 8,
Max
};
enum class TransmogSituationTriggerFlags : int32
{
CanLockOutfit = 0x01,
CanChangeLockedOutfit = 0x02,
IsPlayerFacing = 0x04,
SituationsAreExclusive = 0x08,
DisabledTrigger = 0x10
};
DEFINE_ENUM_FLAG(TransmogSituationTriggerFlags);
// SummonProperties.dbc, col 1 // SummonProperties.dbc, col 1
enum SummonPropGroup enum SummonPropGroup
{ {
+10 -50
View File
@@ -46,6 +46,7 @@
#include "SpellMgr.h" #include "SpellMgr.h"
#include "StringConvert.h" #include "StringConvert.h"
#include "TradeData.h" #include "TradeData.h"
#include "TransmogMgr.h"
#include "UpdateData.h" #include "UpdateData.h"
#include "World.h" #include "World.h"
#include "WorldSession.h" #include "WorldSession.h"
@@ -2010,51 +2011,6 @@ bool Item::IsValidTransmogrificationTarget() const
return true; return true;
} }
enum class ItemTransmogrificationWeaponCategory : uint8
{
// Two-handed
MELEE_2H,
RANGED,
// One-handed
AXE_MACE_SWORD_1H,
DAGGER,
INVALID
};
static ItemTransmogrificationWeaponCategory GetTransmogrificationWeaponCategory(ItemTemplate const* proto)
{
if (proto->GetClass() == ITEM_CLASS_WEAPON)
{
switch (proto->GetSubClass())
{
case ITEM_SUBCLASS_WEAPON_AXE2:
case ITEM_SUBCLASS_WEAPON_MACE2:
case ITEM_SUBCLASS_WEAPON_SWORD2:
case ITEM_SUBCLASS_WEAPON_STAFF:
case ITEM_SUBCLASS_WEAPON_POLEARM:
return ItemTransmogrificationWeaponCategory::MELEE_2H;
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_GUN:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
return ItemTransmogrificationWeaponCategory::RANGED;
case ITEM_SUBCLASS_WEAPON_AXE:
case ITEM_SUBCLASS_WEAPON_MACE:
case ITEM_SUBCLASS_WEAPON_SWORD:
case ITEM_SUBCLASS_WEAPON_WARGLAIVES:
case ITEM_SUBCLASS_WEAPON_FIST_WEAPON:
return ItemTransmogrificationWeaponCategory::AXE_MACE_SWORD_1H;
case ITEM_SUBCLASS_WEAPON_DAGGER:
return ItemTransmogrificationWeaponCategory::DAGGER;
default:
break;
}
}
return ItemTransmogrificationWeaponCategory::INVALID;
}
int32 const ItemTransmogrificationSlots[MAX_INVTYPE] = int32 const ItemTransmogrificationSlots[MAX_INVTYPE] =
{ {
-1, // INVTYPE_NON_EQUIP -1, // INVTYPE_NON_EQUIP
@@ -2124,7 +2080,7 @@ bool Item::CanTransmogrifyItemWithItem(Item const* item, ItemModifiedAppearanceE
switch (source->GetClass()) switch (source->GetClass())
{ {
case ITEM_CLASS_WEAPON: case ITEM_CLASS_WEAPON:
if (GetTransmogrificationWeaponCategory(source) != GetTransmogrificationWeaponCategory(target)) if (source->GetWeaponTransmogOutfitSlotOption() != target->GetWeaponTransmogOutfitSlotOption())
return false; return false;
break; break;
case ITEM_CLASS_ARMOR: case ITEM_CLASS_ARMOR:
@@ -2495,16 +2451,20 @@ uint32 Item::GetDisplayId(Player const* owner) const
if (!itemModifiedAppearanceId) if (!itemModifiedAppearanceId)
itemModifiedAppearanceId = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS); itemModifiedAppearanceId = GetModifier(ITEM_MODIFIER_TRANSMOG_APPEARANCE_ALL_SPECS);
if (ItemModifiedAppearanceEntry const* transmog = sItemModifiedAppearanceStore.LookupEntry(itemModifiedAppearanceId)) ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(itemModifiedAppearanceId);
if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(transmog->ItemAppearanceID)) if (!itemModifiedAppearance)
itemModifiedAppearance = GetItemModifiedAppearance();
if (itemModifiedAppearance)
if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(itemModifiedAppearance->ItemAppearanceID))
return itemAppearance->ItemDisplayInfoID; return itemAppearance->ItemDisplayInfoID;
return sDB2Manager.GetItemDisplayId(GetEntry(), GetAppearanceModId()); return 0;
} }
ItemModifiedAppearanceEntry const* Item::GetItemModifiedAppearance() const ItemModifiedAppearanceEntry const* Item::GetItemModifiedAppearance() const
{ {
return sDB2Manager.GetItemModifiedAppearance(GetEntry(), _bonusData.AppearanceModID); return TransmogMgr::GetItemModifiedAppearance(GetEntry(), _bonusData.AppearanceModID);
} }
uint32 Item::GetModifier(ItemModifier modifier) const uint32 Item::GetModifier(ItemModifier modifier) const
@@ -297,3 +297,49 @@ std::size_t ItemTemplate::CalculateItemSpecBit(ChrSpecializationEntry const* spe
{ {
return (spec->ClassID - 1) * MAX_SPECIALIZATIONS + spec->OrderIndex; return (spec->ClassID - 1) * MAX_SPECIALIZATIONS + spec->OrderIndex;
} }
TransmogOutfitSlotOption ItemTemplate::GetWeaponTransmogOutfitSlotOption() const
{
switch (GetClass())
{
case ITEM_CLASS_WEAPON:
switch (GetSubClass())
{
case ITEM_SUBCLASS_WEAPON_AXE2:
case ITEM_SUBCLASS_WEAPON_MACE2:
case ITEM_SUBCLASS_WEAPON_SWORD2:
case ITEM_SUBCLASS_WEAPON_STAFF:
case ITEM_SUBCLASS_WEAPON_POLEARM:
return TransmogOutfitSlotOption::TwoHandedWeapon;
case ITEM_SUBCLASS_WEAPON_BOW:
case ITEM_SUBCLASS_WEAPON_GUN:
case ITEM_SUBCLASS_WEAPON_CROSSBOW:
return TransmogOutfitSlotOption::RangedWeapon;
case ITEM_SUBCLASS_WEAPON_AXE:
case ITEM_SUBCLASS_WEAPON_MACE:
case ITEM_SUBCLASS_WEAPON_SWORD:
case ITEM_SUBCLASS_WEAPON_WARGLAIVES:
case ITEM_SUBCLASS_WEAPON_FIST_WEAPON:
case ITEM_SUBCLASS_WEAPON_DAGGER:
return TransmogOutfitSlotOption::OneHandedWeapon;
default:
break;
}
break;
case ITEM_CLASS_ARMOR:
switch (GetInventoryType())
{
case INVTYPE_SHIELD:
return TransmogOutfitSlotOption::Shield;
case INVTYPE_HOLDABLE:
return TransmogOutfitSlotOption::OffHand;
default:
break;
}
break;
default:
break;
}
return TransmogOutfitSlotOption::None;
}
@@ -967,6 +967,7 @@ struct TC_GAME_API ItemTemplate
void GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const; void GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const;
bool IsUsableByLootSpecialization(Player const* player, bool alwaysAllowBoundToAccount) const; bool IsUsableByLootSpecialization(Player const* player, bool alwaysAllowBoundToAccount) const;
static std::size_t CalculateItemSpecBit(ChrSpecializationEntry const* spec); static std::size_t CalculateItemSpecBit(ChrSpecializationEntry const* spec);
TransmogOutfitSlotOption GetWeaponTransmogOutfitSlotOption() const;
}; };
#endif #endif
@@ -882,7 +882,7 @@ void VisibleItem::WriteCreate(ByteBuffer& data, Player const* receiver, Unit con
data << uint16(ItemAppearanceModID); data << uint16(ItemAppearanceModID);
data << uint16(ItemVisual); data << uint16(ItemVisual);
data << uint32(ItemModifiedAppearanceID); data << uint32(ItemModifiedAppearanceID);
data << uint8(Field_18); data << uint8(TransmogSlotOption);
data.WriteBit(HasTransmog); data.WriteBit(HasTransmog);
data.WriteBit(HasIllusion); data.WriteBit(HasIllusion);
data.FlushBits(); data.FlushBits();
@@ -936,7 +936,7 @@ void VisibleItem::WriteUpdate(bool ignoreChangesMask, ByteBuffer& data, Player c
} }
if (changesMask[9]) if (changesMask[9])
{ {
data << uint8(Field_18); data << uint8(TransmogSlotOption);
} }
} }
data.FlushBits(); data.FlushBits();
@@ -952,7 +952,7 @@ void VisibleItem::ClearChangesMask()
Base::ClearChangesMask(ItemAppearanceModID); Base::ClearChangesMask(ItemAppearanceModID);
Base::ClearChangesMask(ItemVisual); Base::ClearChangesMask(ItemVisual);
Base::ClearChangesMask(ItemModifiedAppearanceID); Base::ClearChangesMask(ItemModifiedAppearanceID);
Base::ClearChangesMask(Field_18); Base::ClearChangesMask(TransmogSlotOption);
_changesMask.ResetAll(); _changesMask.ResetAll();
} }
@@ -5444,7 +5444,7 @@ void ActivePlayerData::WriteCreate(EnumFlag<UpdateFieldFlag> fieldVisibilityFlag
data << uint32(HouseThemes.size()); data << uint32(HouseThemes.size());
data << uint32(HouseRoomComponentTextures.size()); data << uint32(HouseRoomComponentTextures.size());
data << uint32(HouseTypes.size()); data << uint32(HouseTypes.size());
data << uint32(Field_1980.size()); data << uint32(UnlockedTransmogOutfits.size());
data << uint32(CharacterRestrictions.size()); data << uint32(CharacterRestrictions.size());
data << uint32(SpellPctModByLabel.size()); data << uint32(SpellPctModByLabel.size());
data << uint32(SpellFlatModByLabel.size()); data << uint32(SpellFlatModByLabel.size());
@@ -5563,9 +5563,9 @@ void ActivePlayerData::WriteCreate(EnumFlag<UpdateFieldFlag> fieldVisibilityFlag
{ {
data << uint32(HouseTypes[i]); data << uint32(HouseTypes[i]);
} }
for (uint32 i = 0; i < Field_1980.size(); ++i) for (uint32 i = 0; i < UnlockedTransmogOutfits.size(); ++i)
{ {
data << int32(Field_1980[i]); data << int32(UnlockedTransmogOutfits[i]);
} }
for (uint32 i = 0; i < SpellPctModByLabel.size(); ++i) for (uint32 i = 0; i < SpellPctModByLabel.size(); ++i)
{ {
@@ -5979,9 +5979,9 @@ void ActivePlayerData::WriteUpdate(Mask const& changesMask, ByteBuffer& data, Pl
if (changesMask[29]) if (changesMask[29])
{ {
if (!ignoreNestedChangesMask) if (!ignoreNestedChangesMask)
Field_1980.WriteUpdateMask(data); UnlockedTransmogOutfits.WriteUpdateMask(data);
else else
WriteCompleteDynamicFieldUpdateMask(Field_1980.size(), data); WriteCompleteDynamicFieldUpdateMask(UnlockedTransmogOutfits.size(), data);
} }
if (changesMask[30]) if (changesMask[30])
{ {
@@ -6321,11 +6321,11 @@ void ActivePlayerData::WriteUpdate(Mask const& changesMask, ByteBuffer& data, Pl
} }
if (changesMask[29]) if (changesMask[29])
{ {
for (uint32 i = 0; i < Field_1980.size(); ++i) for (uint32 i = 0; i < UnlockedTransmogOutfits.size(); ++i)
{ {
if (Field_1980.HasChanged(i) || ignoreNestedChangesMask) if (UnlockedTransmogOutfits.HasChanged(i) || ignoreNestedChangesMask)
{ {
data << int32(Field_1980[i]); data << int32(UnlockedTransmogOutfits[i]);
} }
} }
} }
@@ -7158,7 +7158,7 @@ void ActivePlayerData::ClearChangesMask()
Base::ClearChangesMask(HouseThemes); Base::ClearChangesMask(HouseThemes);
Base::ClearChangesMask(HouseRoomComponentTextures); Base::ClearChangesMask(HouseRoomComponentTextures);
Base::ClearChangesMask(HouseTypes); Base::ClearChangesMask(HouseTypes);
Base::ClearChangesMask(Field_1980); Base::ClearChangesMask(UnlockedTransmogOutfits);
Base::ClearChangesMask(SpellPctModByLabel); Base::ClearChangesMask(SpellPctModByLabel);
Base::ClearChangesMask(SpellFlatModByLabel); Base::ClearChangesMask(SpellFlatModByLabel);
Base::ClearChangesMask(SpellPctModPVPByLabel); Base::ClearChangesMask(SpellPctModPVPByLabel);
@@ -262,7 +262,7 @@ struct VisibleItem : public IsUpdateFieldStructureTag, public HasChangesMask<10>
UpdateField<uint16, 0, 6> ItemAppearanceModID; UpdateField<uint16, 0, 6> ItemAppearanceModID;
UpdateField<uint16, 0, 7> ItemVisual; UpdateField<uint16, 0, 7> ItemVisual;
UpdateField<uint32, 0, 8> ItemModifiedAppearanceID; UpdateField<uint32, 0, 8> ItemModifiedAppearanceID;
UpdateField<uint8, 0, 9> Field_18; UpdateField<uint8, 0, 9> TransmogSlotOption;
using OwnerObject = Unit; using OwnerObject = Unit;
void WriteCreate(ByteBuffer& data, Player const* receiver, Unit const* owner) const; void WriteCreate(ByteBuffer& data, Player const* receiver, Unit const* owner) const;
@@ -1311,7 +1311,7 @@ struct ActivePlayerData : public IsUpdateFieldStructureTag, public HasChangesMas
DynamicUpdateField<uint32, 0, 26> HouseThemes; DynamicUpdateField<uint32, 0, 26> HouseThemes;
DynamicUpdateField<uint32, 0, 27> HouseRoomComponentTextures; DynamicUpdateField<uint32, 0, 27> HouseRoomComponentTextures;
DynamicUpdateField<uint32, 0, 28> HouseTypes; DynamicUpdateField<uint32, 0, 28> HouseTypes;
DynamicUpdateField<int32, 0, 29> Field_1980; DynamicUpdateField<int32, 0, 29> UnlockedTransmogOutfits;
DynamicUpdateField<UF::SpellPctModByLabel, 0, 31> SpellPctModByLabel; DynamicUpdateField<UF::SpellPctModByLabel, 0, 31> SpellPctModByLabel;
DynamicUpdateField<UF::SpellFlatModByLabel, 32, 33> SpellFlatModByLabel; DynamicUpdateField<UF::SpellFlatModByLabel, 32, 33> SpellFlatModByLabel;
DynamicUpdateField<UF::SpellPctPVPModByLabel, 32, 34> SpellPctModPVPByLabel; DynamicUpdateField<UF::SpellPctPVPModByLabel, 32, 34> SpellPctModPVPByLabel;
@@ -26,6 +26,7 @@
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
#include "Timer.h" #include "Timer.h"
#include "TransmogMgr.h"
#include "TransmogrificationPackets.h" #include "TransmogrificationPackets.h"
#include "WorldSession.h" #include "WorldSession.h"
#include <boost/dynamic_bitset.hpp> #include <boost/dynamic_bitset.hpp>
@@ -95,12 +96,36 @@ namespace
} }
} }
CollectionMgr::CollectionMgr(WorldSession* owner) : _owner(owner), _appearances(std::make_unique<boost::dynamic_bitset<uint32>>()), _transmogIllusions(std::make_unique<boost::dynamic_bitset<uint32>>()) CollectionMgr::CollectionMgr(WorldSession* owner) : _owner(owner),
_appearances(std::make_unique<boost::dynamic_bitset<uint32>>()),
_transmogIllusions(std::make_unique<boost::dynamic_bitset<uint32>>())
{ {
} }
CollectionMgr::~CollectionMgr() = default; CollectionMgr::~CollectionMgr() = default;
void CollectionMgr::LoadCharacterData()
{
LoadToys();
LoadHeirlooms();
LoadMounts();
LoadItemAppearances();
LoadTransmogIllusions();
LoadTransmogOutfits();
LoadWarbandScenes();
}
void CollectionMgr::SaveToDB(LoginDatabaseTransaction trans)
{
SaveAccountToys(trans);
SaveAccountHeirlooms(trans);
SaveAccountMounts(trans);
SaveAccountItemAppearances(trans);
SaveAccountTransmogIllusions(trans);
SaveAccountTransmogOutfits(trans);
SaveAccountWarbandScenes(trans);
}
void CollectionMgr::LoadToys() void CollectionMgr::LoadToys()
{ {
for (auto const& [itemId, flags] : _toys) for (auto const& [itemId, flags] : _toys)
@@ -529,7 +554,7 @@ void CollectionMgr::LoadAccountItemAppearances(PreparedQueryResult knownAppearan
for (uint32 hiddenItem : hiddenAppearanceItems) for (uint32 hiddenItem : hiddenAppearanceItems)
{ {
ItemModifiedAppearanceEntry const* hiddenAppearance = sDB2Manager.GetItemModifiedAppearance(hiddenItem, 0); ItemModifiedAppearanceEntry const* hiddenAppearance = TransmogMgr::GetDefaultItemModifiedAppearance(hiddenItem);
ASSERT(hiddenAppearance); ASSERT(hiddenAppearance);
if (_appearances->size() <= hiddenAppearance->ID) if (_appearances->size() <= hiddenAppearance->ID)
_appearances->resize(hiddenAppearance->ID + 1); _appearances->resize(hiddenAppearance->ID + 1);
@@ -603,7 +628,7 @@ void CollectionMgr::AddItemAppearance(Item* item)
void CollectionMgr::AddItemAppearance(uint32 itemId, uint32 appearanceModId /*= 0*/) void CollectionMgr::AddItemAppearance(uint32 itemId, uint32 appearanceModId /*= 0*/)
{ {
ItemModifiedAppearanceEntry const* itemModifiedAppearance = sDB2Manager.GetItemModifiedAppearance(itemId, appearanceModId); ItemModifiedAppearanceEntry const* itemModifiedAppearance = TransmogMgr::GetItemModifiedAppearance(itemId, appearanceModId);
if (!CanAddAppearance(itemModifiedAppearance)) if (!CanAddAppearance(itemModifiedAppearance))
return; return;
@@ -612,11 +637,7 @@ void CollectionMgr::AddItemAppearance(uint32 itemId, uint32 appearanceModId /*=
void CollectionMgr::AddTransmogSet(uint32 transmogSetId) void CollectionMgr::AddTransmogSet(uint32 transmogSetId)
{ {
std::vector<TransmogSetItemEntry const*> const* items = sDB2Manager.GetTransmogSetItems(transmogSetId); for (TransmogSetItemEntry const* item : TransmogMgr::GetTransmogSetItems(transmogSetId))
if (!items)
return;
for (TransmogSetItemEntry const* item : *items)
{ {
ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(item->ItemModifiedAppearanceID); ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(item->ItemModifiedAppearanceID);
if (!itemModifiedAppearance) if (!itemModifiedAppearance)
@@ -628,13 +649,13 @@ void CollectionMgr::AddTransmogSet(uint32 transmogSetId)
bool CollectionMgr::IsSetCompleted(uint32 transmogSetId) const bool CollectionMgr::IsSetCompleted(uint32 transmogSetId) const
{ {
std::vector<TransmogSetItemEntry const*> const* transmogSetItems = sDB2Manager.GetTransmogSetItems(transmogSetId); std::span<TransmogSetItemEntry const* const> transmogSetItems = TransmogMgr::GetTransmogSetItems(transmogSetId);
if (!transmogSetItems) if (transmogSetItems.empty())
return false; return false;
std::array<int8, EQUIPMENT_SLOT_END> knownPieces; std::array<int8, EQUIPMENT_SLOT_END> knownPieces;
knownPieces.fill(-1); knownPieces.fill(-1);
for (TransmogSetItemEntry const* transmogSetItem : *transmogSetItems) for (TransmogSetItemEntry const* transmogSetItem : transmogSetItems)
{ {
ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(transmogSetItem->ItemModifiedAppearanceID); ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(transmogSetItem->ItemModifiedAppearanceID);
if (!itemModifiedAppearance) if (!itemModifiedAppearance)
@@ -756,13 +777,10 @@ void CollectionMgr::AddItemAppearance(ItemModifiedAppearanceEntry const* itemMod
owner->UpdateCriteria(CriteriaType::LearnAnyTransmogInSlot, transmogSlot, itemModifiedAppearance->ID); owner->UpdateCriteria(CriteriaType::LearnAnyTransmogInSlot, transmogSlot, itemModifiedAppearance->ID);
} }
if (std::vector<TransmogSetEntry const*> const* sets = sDB2Manager.GetTransmogSetsForItemModifiedAppearance(itemModifiedAppearance->ID)) for (TransmogSetEntry const* set : TransmogMgr::GetTransmogSetsForItemModifiedAppearance(itemModifiedAppearance->ID))
{
for (TransmogSetEntry const* set : *sets)
{ {
if (IsSetCompleted(set->ID)) if (IsSetCompleted(set->ID))
{ {
if (Quest const* quest = sObjectMgr->GetQuestTemplate(set->TrackingQuestID)) if (Quest const* quest = sObjectMgr->GetQuestTemplate(set->TrackingQuestID))
owner->RewardQuest(quest, LootItemType::Item, 0, owner, false); owner->RewardQuest(quest, LootItemType::Item, 0, owner, false);
@@ -770,7 +788,6 @@ void CollectionMgr::AddItemAppearance(ItemModifiedAppearanceEntry const* itemMod
} }
} }
} }
}
void CollectionMgr::AddTemporaryAppearance(ObjectGuid const& itemGuid, ItemModifiedAppearanceEntry const* itemModifiedAppearance) void CollectionMgr::AddTemporaryAppearance(ObjectGuid const& itemGuid, ItemModifiedAppearanceEntry const* itemModifiedAppearance)
{ {
@@ -966,6 +983,55 @@ bool CollectionMgr::HasTransmogIllusion(uint32 transmogIllusionId) const
return transmogIllusionId < _transmogIllusions->size() && _transmogIllusions->test(transmogIllusionId); return transmogIllusionId < _transmogIllusions->size() && _transmogIllusions->test(transmogIllusionId);
} }
void CollectionMgr::LoadTransmogOutfits()
{
_owner->GetPlayer()->AddUnlockedTransmogOutfits(_transmogOutfits);
}
void CollectionMgr::LoadAccountTransmogOutfits(PreparedQueryResult unlockedTransmogOutfits)
{
if (unlockedTransmogOutfits)
{
do
{
Field* fields = unlockedTransmogOutfits->Fetch();
int32 transmogOutfitId = fields[0].GetInt32();
if (!sTransmogOutfitEntryStore.HasRecord(transmogOutfitId))
continue;
_transmogOutfits.insert(transmogOutfitId);
} while (unlockedTransmogOutfits->NextRow());
}
for (TransmogOutfitEntryEntry const* transmogOutfitEntry : TransmogMgr::GetAutomaticallyUnlockedOutfits())
_transmogOutfits.insert(transmogOutfitEntry->ID);
}
void CollectionMgr::SaveAccountTransmogOutfits(LoginDatabaseTransaction trans)
{
for (int32 transmogOutfitId : _transmogOutfits)
{
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_TRANSMOG_OUTFITS);
stmt->setUInt32(0, _owner->GetBattlenetAccountId());
stmt->setInt32(1, transmogOutfitId);
trans->Append(stmt);
}
}
void CollectionMgr::AddTransmogOutfit(int32 transmogOutfitId)
{
if (_transmogOutfits.insert(transmogOutfitId).second)
_owner->GetPlayer()->AddUnlockedTransmogOutfit(transmogOutfitId);
}
bool CollectionMgr::HasTransmogOutfit(int32 transmogOutfitId) const
{
return _transmogOutfits.contains(transmogOutfitId);
}
void CollectionMgr::LoadWarbandScenes() void CollectionMgr::LoadWarbandScenes()
{ {
Player* owner = _owner->GetPlayer(); Player* owner = _owner->GetPlayer();
@@ -21,6 +21,7 @@
#include "Define.h" #include "Define.h"
#include "DatabaseEnvFwd.h" #include "DatabaseEnvFwd.h"
#include "EnumFlag.h" #include "EnumFlag.h"
#include "FlatSet.h"
#include "ObjectGuid.h" #include "ObjectGuid.h"
#include <boost/dynamic_bitset_fwd.hpp> #include <boost/dynamic_bitset_fwd.hpp>
#include <map> #include <map>
@@ -117,6 +118,9 @@ public:
static void LoadMountDefinitions(); static void LoadMountDefinitions();
static void LoadWarbandSceneDefinitions(); static void LoadWarbandSceneDefinitions();
void LoadCharacterData();
void SaveToDB(LoginDatabaseTransaction trans);
// Account-wide toys // Account-wide toys
void LoadToys(); void LoadToys();
void LoadAccountToys(PreparedQueryResult result); void LoadAccountToys(PreparedQueryResult result);
@@ -179,6 +183,12 @@ public:
void AddTransmogIllusion(uint32 transmogIllusionId); void AddTransmogIllusion(uint32 transmogIllusionId);
bool HasTransmogIllusion(uint32 transmogIllusionId) const; bool HasTransmogIllusion(uint32 transmogIllusionId) const;
void LoadTransmogOutfits();
void LoadAccountTransmogOutfits(PreparedQueryResult unlockedTransmogOutfits);
void SaveAccountTransmogOutfits(LoginDatabaseTransaction trans);
void AddTransmogOutfit(int32 transmogOutfitId);
bool HasTransmogOutfit(int32 transmogOutfitId) const;
// Warband Scenes // Warband Scenes
void LoadWarbandScenes(); void LoadWarbandScenes();
void LoadAccountWarbandScenes(PreparedQueryResult knownWarbandScenes); void LoadAccountWarbandScenes(PreparedQueryResult knownWarbandScenes);
@@ -204,6 +214,7 @@ private:
std::unordered_map<uint32, std::unordered_set<ObjectGuid>> _temporaryAppearances; std::unordered_map<uint32, std::unordered_set<ObjectGuid>> _temporaryAppearances;
std::unordered_map<uint32, CollectionItemState> _favoriteAppearances; std::unordered_map<uint32, CollectionItemState> _favoriteAppearances;
std::unique_ptr<boost::dynamic_bitset<uint32>> _transmogIllusions; std::unique_ptr<boost::dynamic_bitset<uint32>> _transmogIllusions;
Trinity::Containers::FlatSet<int32> _transmogOutfits;
WarbandSceneCollectionContainer _warbandScenes; WarbandSceneCollectionContainer _warbandScenes;
}; };
+682 -84
View File
@@ -131,6 +131,8 @@
#include "TradeData.h" #include "TradeData.h"
#include "TraitMgr.h" #include "TraitMgr.h"
#include "TraitPacketsCommon.h" #include "TraitPacketsCommon.h"
#include "TransmogMgr.h"
#include "TransmogrificationPackets.h"
#include "Transport.h" #include "Transport.h"
#include "UpdateData.h" #include "UpdateData.h"
#include "Util.h" #include "Util.h"
@@ -559,6 +561,8 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
GetThreatManager().Initialize(); GetThreatManager().Initialize();
EquipTransmogOutfit(0, TransmogSituationTrigger::Manual, false);
return true; return true;
} }
@@ -4146,6 +4150,18 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
stmt->setUInt64(0, guid); stmt->setUInt64(0, guid);
trans->Append(stmt); trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFIT_SITUATION_BY_CHAR);
stmt->setUInt64(0, guid);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFIT_SLOT_BY_CHAR);
stmt->setUInt64(0, guid);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFIT_BY_CHAR);
stmt->setUInt64(0, guid);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER); stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER);
stmt->setUInt64(0, guid); stmt->setUInt64(0, guid);
stmt->setUInt64(1, guid); stmt->setUInt64(1, guid);
@@ -4521,19 +4537,10 @@ Corpse* Player::CreateCorpse()
corpse->SetFactionTemplate(sChrRacesStore.AssertEntry(GetRace())->FactionID); corpse->SetFactionTemplate(sChrRacesStore.AssertEntry(GetRace())->FactionID);
for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++) for (uint8 i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i++)
{ if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(m_playerData->VisibleItems[i].ItemModifiedAppearanceID))
if (m_items[i]) if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(itemModifiedAppearance->ItemAppearanceID))
{ if (ItemEntry const* item = sItemStore.LookupEntry(itemModifiedAppearance->ItemID))
uint32 itemDisplayId = m_items[i]->GetDisplayId(this); corpse->SetItem(i, itemAppearance->ItemDisplayInfoID | int32(item->InventoryType) << 24);
uint32 itemInventoryType;
if (ItemEntry const* itemEntry = sItemStore.LookupEntry(m_items[i]->GetVisibleEntry(this)))
itemInventoryType = itemEntry->InventoryType;
else
itemInventoryType = m_items[i]->GetTemplate()->GetInventoryType();
corpse->SetItem(i, itemDisplayId | (itemInventoryType << 24));
}
}
// register for player, but not show // register for player, but not show
GetMap()->AddCorpse(corpse); GetMap()->AddCorpse(corpse);
@@ -6176,6 +6183,7 @@ bool Player::IsActionButtonDataValid(uint8 button, uint64 action, uint8 type) co
case ACTION_BUTTON_MACRO: case ACTION_BUTTON_MACRO:
case ACTION_BUTTON_EQSET: case ACTION_BUTTON_EQSET:
case ACTION_BUTTON_DROPDOWN: case ACTION_BUTTON_DROPDOWN:
case ACTION_BUTTON_OUTFIT:
break; break;
default: default:
TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Unknown action type {}", type); TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Unknown action type {}", type);
@@ -11825,25 +11833,123 @@ void Player::QuickEquipItem(uint16 pos, Item* pItem)
} }
} }
void Player::SetVisibleItemSlot(uint8 slot, Item* pItem) void Player::SetVisibleItemSlot(uint8 slot, Item const* item)
{
auto setVisibleItemSlot = [this](uint32 slot, int32 itemId, int32 secondaryItemModifiedAppearanceId, int32 conditionalItemAppearanceId,
uint16 itemAppearanceModId, uint16 itemVisual, uint32 itemModifiedAppearanceId, TransmogOutfitSlotOption transmogSlotOption,
bool hasTransmog, bool hasIllusion)
{ {
auto itemField = m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::VisibleItems, slot); auto itemField = m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::VisibleItems, slot);
if (pItem) SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemID), itemId);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::SecondaryItemModifiedAppearanceID), secondaryItemModifiedAppearanceId);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ConditionalItemAppearanceID), conditionalItemAppearanceId);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), itemAppearanceModId);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemVisual), itemVisual);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemModifiedAppearanceID), itemModifiedAppearanceId);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::TransmogSlotOption), AsUnderlyingType(transmogSlotOption));
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::HasTransmog), hasTransmog);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::HasIllusion), hasIllusion);
auto transmogMetadata = m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::TransmogMetadata);
if (slot == EQUIPMENT_SLOT_MAINHAND)
SetUpdateFieldValue(transmogMetadata.ModifyValue(&UF::TransmogOutfitMetadata::StampedOptionMainHand), AsUnderlyingType(transmogSlotOption));
else if (slot == EQUIPMENT_SLOT_OFFHAND)
SetUpdateFieldValue(transmogMetadata.ModifyValue(&UF::TransmogOutfitMetadata::StampedOptionOffHand), AsUnderlyingType(transmogSlotOption));
};
if (item)
{ {
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemID), pItem->GetVisibleEntry(this)); TransmogOutfitSlotOption transmogSlotOption = item->GetTemplate()->GetWeaponTransmogOutfitSlotOption();
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::SecondaryItemModifiedAppearanceID), pItem->GetVisibleSecondaryModifiedAppearanceId(this)); if (transmogSlotOption == TransmogOutfitSlotOption::TwoHandedWeapon && CanTitanGrip())
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), pItem->GetVisibleAppearanceModId(this)); transmogSlotOption = TransmogOutfitSlotOption::FuryTwoHandedWeapon;
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemVisual), pItem->GetVisibleItemVisual(this));
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemModifiedAppearanceID), pItem->GetVisibleModifiedAppearanceId(this)); int32 itemId = item->GetVisibleEntry(this);
int32 secondaryItemModifiedAppearanceId = item->GetVisibleSecondaryModifiedAppearanceId(this);
int32 conditionalItemAppearanceId = 0;
uint16 itemAppearanceModId = item->GetVisibleAppearanceModId(this);
uint16 itemVisual = item->GetVisibleItemVisual(this);
uint32 itemModifiedAppearanceId = item->GetVisibleModifiedAppearanceId(this);
bool hasTransmog = false;
bool hasIllusion = false;
if (!m_activePlayerData->ViewedOutfit->Slots.empty())
{
TransmogMgr::TransmogOutfitSlotAndOptionInfo const* slotInfo = TransmogMgr::GetSlotAndOption(EquipmentSlots(slot), transmogSlotOption);
if (transmogSlotOption != TransmogOutfitSlotOption::None)
{
// check if artifact override is active
TransmogOutfitSlotOption artifactOption = static_cast<TransmogOutfitSlotOption>(AsUnderlyingType(TransmogOutfitSlotOption::ArtifactSpecOne) + GetPrimarySpecializationEntry()->OrderIndex);
TransmogMgr::TransmogOutfitSlotAndOptionInfo const* artifactSlotInfo = TransmogMgr::GetSlotAndOption(EquipmentSlots(slot), artifactOption);
if (artifactSlotInfo && static_cast<TransmogOutfitDisplayType>(*m_activePlayerData->ViewedOutfit->Slots[artifactSlotInfo->SlotIndex].AppearanceDisplayType) == TransmogOutfitDisplayType::Assigned)
{
transmogSlotOption = artifactOption;
slotInfo = artifactSlotInfo;
}
}
if (slotInfo)
{
auto isTransmogDisplayed = [](TransmogOutfitDisplayType displayType)
{
return displayType == TransmogOutfitDisplayType::Assigned || displayType == TransmogOutfitDisplayType::Hidden;
};
UF::TransmogOutfitSlotData const& transmogOutfitItem = m_activePlayerData->ViewedOutfit->Slots[slotInfo->SlotIndex];
if (isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*transmogOutfitItem.AppearanceDisplayType)))
{
if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(transmogOutfitItem.ItemModifiedAppearanceID))
{
itemId = itemModifiedAppearance->ItemID;
itemAppearanceModId = itemModifiedAppearance->ItemAppearanceModifierID;
itemModifiedAppearanceId = itemModifiedAppearance->ID;
}
hasTransmog = true;
}
if (TransmogOutfitSlotInfoEntry const* secondarySlot = sTransmogOutfitSlotInfoStore.LookupEntry(slotInfo->Slot->SecondarySlotID))
{
if (TransmogMgr::TransmogOutfitSlotAndOptionInfo const* secondarySlotInfo = TransmogMgr::GetSlotAndOption(secondarySlot->GetSlot(), transmogSlotOption))
{
UF::TransmogOutfitSlotData const& secondaryTransmogOutfitItem = m_activePlayerData->ViewedOutfit->Slots[secondarySlotInfo->SlotIndex];
if (isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*secondaryTransmogOutfitItem.AppearanceDisplayType))
|| static_cast<TransmogOutfitDisplayType>(*secondaryTransmogOutfitItem.AppearanceDisplayType) == TransmogOutfitDisplayType::Equipped)
{
secondaryItemModifiedAppearanceId = secondaryTransmogOutfitItem.ItemModifiedAppearanceID;
hasTransmog = true;
}
}
}
if (TransmogOutfitSlotOptionEntry const* secondarySlotOption = sTransmogOutfitSlotOptionInfoStore.LookupEntry(slotInfo->SlotOption ? slotInfo->SlotOption->SecondaryOptionID : 0))
{
if (TransmogMgr::TransmogOutfitSlotAndOptionInfo const* secondarySlotInfo = TransmogMgr::GetSlotAndOption(slotInfo->Slot->GetSlot(), secondarySlotOption->GetOption()))
{
UF::TransmogOutfitSlotData const& secondaryTransmogOutfitItem = m_activePlayerData->ViewedOutfit->Slots[secondarySlotInfo->SlotIndex];
if (isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*secondaryTransmogOutfitItem.AppearanceDisplayType))
|| static_cast<TransmogOutfitDisplayType>(*secondaryTransmogOutfitItem.AppearanceDisplayType) == TransmogOutfitDisplayType::Equipped)
{
secondaryItemModifiedAppearanceId = secondaryTransmogOutfitItem.ItemModifiedAppearanceID;
hasTransmog = true;
}
}
}
if (isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*transmogOutfitItem.IllusionDisplayType)))
{
if (SpellItemEnchantmentEntry const* spellItemEnchantment = sSpellItemEnchantmentStore.LookupEntry(transmogOutfitItem.SpellItemEnchantmentID))
itemVisual = spellItemEnchantment->ItemVisual;
hasIllusion = true;
}
}
}
setVisibleItemSlot(slot, itemId, secondaryItemModifiedAppearanceId, conditionalItemAppearanceId, itemAppearanceModId,
itemVisual, itemModifiedAppearanceId, transmogSlotOption, hasTransmog, hasIllusion);
} }
else else
{ setVisibleItemSlot(slot, 0, 0, 0, 0, 0, 0, TransmogOutfitSlotOption::None, false, false);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemID), 0);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::SecondaryItemModifiedAppearanceID), 0);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemAppearanceModID), 0);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemVisual), 0);
SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemModifiedAppearanceID), 0);
}
} }
void Player::VisualizeItem(uint8 slot, Item* pItem) void Player::VisualizeItem(uint8 slot, Item* pItem)
@@ -17579,7 +17685,7 @@ void Player::_LoadEquipmentSets(PreparedQueryResult result)
} while (result->NextRow()); } while (result->NextRow());
} }
void Player::_LoadTransmogOutfits(PreparedQueryResult result) void Player::_LoadTransmogCustomSets(PreparedQueryResult result)
{ {
// 0 1 2 3 4 5 6 7 8 9 // 0 1 2 3 4 5 6 7 8 9
//SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4, //SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4,
@@ -17616,6 +17722,153 @@ void Player::_LoadTransmogOutfits(PreparedQueryResult result)
} while (result->NextRow()); } while (result->NextRow());
} }
void Player::_LoadTransmogOutfits(PreparedQueryResult setsResult, PreparedQueryResult situationsResult, PreparedQueryResult slotsResult,
int32 equippedTransmogOutfitId, bool locked)
{
struct SetData
{
std::vector<WorldPackets::Transmogrification::TransmogOutfitSituationInfo> situations;
std::vector<WorldPackets::Transmogrification::TransmogOutfitSlotData> slots;
};
std::unordered_map<uint32, SetData> sets;
// SELECT transmogOutfitId, situationID, specID, loadoutID, equipmentSetID FROM character_transmog_outfit_situation WHERE guid = ?
if (situationsResult)
{
do
{
DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (transmogOutfitId)(situationID)(specID)(loadoutID)(equipmentSetID)) fields { *situationsResult };
uint32 transmogOutfitId = fields.transmogOutfitId().GetUInt32();
WorldPackets::Transmogrification::TransmogOutfitSituationInfo& situation = sets[transmogOutfitId].situations.emplace_back();
situation.SituationID = fields.situationID().GetUInt32();
situation.SpecID = fields.specID().GetUInt32();
situation.LoadoutID = fields.loadoutID().GetUInt32();
situation.EquipmentSetID = fields.equipmentSetID().GetUInt32();
} while (situationsResult->NextRow());
}
// SELECT transmogOutfitId, slot, slotOption, itemModifiedAppearanceID, appearanceDisplayType, spellItemEnchantmentID, illusionDisplayType, flags FROM character_transmog_outfit_slot guid = ?
if (slotsResult)
{
do
{
DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (transmogOutfitId)(slot)(slotOption)(itemModifiedAppearanceID)(appearanceDisplayType)
(spellItemEnchantmentID)(illusionDisplayType)(flags)) fields { *slotsResult };
uint32 transmogOutfitId = fields.transmogOutfitId().GetUInt32();
WorldPackets::Transmogrification::TransmogOutfitSlotData& slot = sets[transmogOutfitId].slots.emplace_back();
slot.Slot = static_cast<TransmogOutfitSlot>(fields.slot().GetInt8());
slot.SlotOption = static_cast<TransmogOutfitSlotOption>(fields.slotOption().GetUInt8());
slot.ItemModifiedAppearanceID = fields.itemModifiedAppearanceID().GetUInt32();
slot.AppearanceDisplayType = static_cast<TransmogOutfitDisplayType>(fields.appearanceDisplayType().GetUInt8());
slot.SpellItemEnchantmentID = fields.spellItemEnchantmentID().GetUInt32();
slot.IllusionDisplayType = static_cast<TransmogOutfitDisplayType>(fields.illusionDisplayType().GetUInt8());
slot.Flags = fields.flags().GetUInt32();
} while (slotsResult->NextRow());
}
auto activePlayerData = m_values.ModifyValue(&Player::m_activePlayerData);
// SELECT transmogOutfitId, name, icon, situationsEnabled FROM character_transmog_outfit WHERE guid = ?
if (setsResult)
{
do
{
DEFINE_FIELD_ACCESSOR_CACHE_ANONYMOUS(PreparedResultSet, (transmogOutfitId)(name)(icon)(situationsEnabled)) fields { *setsResult };
uint32 transmogOutfitId = fields.transmogOutfitId().GetUInt32();
TransmogOutfitEntryEntry const* transmogOutfitEntry = sTransmogOutfitEntryStore.LookupEntry(transmogOutfitId);
if (!transmogOutfitEntry || transmogOutfitEntry->GetSetType() == TransmogOutfitSetType::CustomSet)
continue;
if (transmogOutfitEntry->HasFlag(TransmogOutfitEntryFlags::OnlyAvailableDuringEvent) && !IsHolidayActive(HOLIDAY_TRIAL_OF_STYLE))
continue;
WorldPackets::Transmogrification::TransmogOutfitDataInfo outfitInfo;
outfitInfo.SetType = transmogOutfitEntry->GetSetType();
outfitInfo.Name = fields.name().GetString();
outfitInfo.Icon = fields.icon().GetUInt32();
outfitInfo.SituationsEnabled = fields.situationsEnabled().GetBool();
auto transmogOutfit = activePlayerData.ModifyValue(&UF::ActivePlayerData::TransmogOutfits, transmogOutfitId);
InitializeNewTransmogOutfit(transmogOutfit, transmogOutfitId, outfitInfo);
auto setData = sets.extract(transmogOutfitId);
if (!setData)
continue;
auto situations = transmogOutfit.ModifyValue(&UF::TransmogOutfitData::Situations);
ClearDynamicUpdateFieldValues(situations);
for (WorldPackets::Transmogrification::TransmogOutfitSituationInfo const& situationInfo : setData.mapped().situations)
{
auto situation = AddDynamicUpdateFieldValue(situations);
situation.ModifyValue(&UF::TransmogOutfitSituationInfo::SituationID).SetValue(situationInfo.SituationID);
situation.ModifyValue(&UF::TransmogOutfitSituationInfo::SpecID).SetValue(situationInfo.SpecID);
situation.ModifyValue(&UF::TransmogOutfitSituationInfo::LoadoutID).SetValue(situationInfo.LoadoutID);
situation.ModifyValue(&UF::TransmogOutfitSituationInfo::EquipmentSetID).SetValue(situationInfo.EquipmentSetID);
}
for (WorldPackets::Transmogrification::TransmogOutfitSlotData const& slotData : setData.mapped().slots)
{
TransmogMgr::TransmogOutfitSlotAndOptionInfo const* slotInfo = TransmogMgr::GetSlotAndOption(slotData.Slot, slotData.SlotOption);
if (!slotInfo)
continue;
auto slot = transmogOutfit.ModifyValue(&UF::TransmogOutfitData::Slots, slotInfo->SlotIndex);
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::Slot), AsUnderlyingType(slotData.Slot));
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::SlotOption), AsUnderlyingType(slotData.SlotOption));
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::ItemModifiedAppearanceID), slotData.ItemModifiedAppearanceID);
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::AppearanceDisplayType), AsUnderlyingType(slotData.AppearanceDisplayType));
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::SpellItemEnchantmentID), slotData.SpellItemEnchantmentID);
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::IllusionDisplayType), AsUnderlyingType(slotData.IllusionDisplayType));
SetUpdateFieldValue(slot.ModifyValue(&UF::TransmogOutfitSlotData::Flags), slotData.Flags);
}
} while (setsResult->NextRow());
}
for (int32 transmogOutfitId : m_activePlayerData->UnlockedTransmogOutfits)
{
TransmogOutfitEntryEntry const* transmogOutfitEntry = sTransmogOutfitEntryStore.AssertEntry(transmogOutfitId);
if (transmogOutfitEntry->HasFlag(TransmogOutfitEntryFlags::OnlyAvailableDuringEvent) && !IsHolidayActive(HOLIDAY_TRIAL_OF_STYLE))
continue;
WorldPackets::Transmogrification::TransmogOutfitDataInfo outfitData;
outfitData.SetType = transmogOutfitEntry->GetSetType();
outfitData.SituationsEnabled = false;
outfitData.Icon = TransmogMgr::DefaultOutfitIcon;
outfitData.Name = TransmogMgr::DefaultOutfitName[GetSession()->GetSessionDbcLocale()];
if (transmogOutfitEntry->Name.Str[GetSession()->GetSessionDbcLocale()][0])
outfitData.Name = transmogOutfitEntry->Name.Str[GetSession()->GetSessionDbcLocale()];
switch (transmogOutfitEntry->GetSetType())
{
case TransmogOutfitSetType::Equipped:
{
outfitData.SituationsEnabled = true;
auto equippedOutfit = activePlayerData.ModifyValue(&UF::ActivePlayerData::ViewedOutfit);
InitializeNewTransmogOutfit(equippedOutfit, transmogOutfitId, outfitData);
break;
}
case TransmogOutfitSetType::Outfit:
if (!m_activePlayerData->TransmogOutfits.Get(transmogOutfitId))
CreateTransmogOutfit(transmogOutfitId, outfitData);
break;
case TransmogOutfitSetType::CustomSet:
default:
break;
}
}
EquipTransmogOutfit(equippedTransmogOutfitId, TransmogSituationTrigger::Manual, locked);
}
void Player::_LoadBGData(PreparedQueryResult result) void Player::_LoadBGData(PreparedQueryResult result)
{ {
if (!result) if (!result)
@@ -17717,7 +17970,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
// "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, " // "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, "
// "health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, " // "health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, "
// "raidDifficulty, legacyRaidDifficulty, fishingSteps, honor, honorLevel, honorRestState, honorRestBonus, numRespecs, " // "raidDifficulty, legacyRaidDifficulty, fishingSteps, honor, honorLevel, honorRestState, honorRestBonus, numRespecs, "
// "personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor " // "personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor, transmogOutfitEquippedId, transmogOutfitLocked "
// "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC); // "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC);
ObjectGuid::LowType guid; ObjectGuid::LowType guid;
@@ -17795,6 +18048,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
int32 personalTabardBorderStyle; int32 personalTabardBorderStyle;
int32 personalTabardBorderColor; int32 personalTabardBorderColor;
int32 personalTabardBackgroundColor; int32 personalTabardBackgroundColor;
int32 transmogOutfitEquippedId;
bool transmogOutfitLocked;
explicit PlayerLoadData(Field const* fields) explicit PlayerLoadData(Field const* fields)
{ {
@@ -17876,6 +18131,8 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
personalTabardBorderStyle = fields[i++].GetInt32(); personalTabardBorderStyle = fields[i++].GetInt32();
personalTabardBorderColor = fields[i++].GetInt32(); personalTabardBorderColor = fields[i++].GetInt32();
personalTabardBackgroundColor = fields[i++].GetInt32(); personalTabardBackgroundColor = fields[i++].GetInt32();
transmogOutfitEquippedId = fields[i++].GetInt32();
transmogOutfitLocked = fields[i++].GetBool();
} }
} fields(result->Fetch()); } fields(result->Fetch());
@@ -18379,12 +18636,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
_LoadTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS)); _LoadTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
_LoadPvpTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS)); _LoadPvpTalents(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS));
_LoadSpells(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_FAVORITES)); _LoadSpells(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS), holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_FAVORITES));
GetSession()->GetCollectionMgr()->LoadToys(); GetSession()->GetCollectionMgr()->LoadCharacterData();
GetSession()->GetCollectionMgr()->LoadHeirlooms();
GetSession()->GetCollectionMgr()->LoadMounts();
GetSession()->GetCollectionMgr()->LoadItemAppearances();
GetSession()->GetCollectionMgr()->LoadTransmogIllusions();
GetSession()->GetCollectionMgr()->LoadWarbandScenes();
LearnSpecializationSpells(); LearnSpecializationSpells();
@@ -18560,6 +18812,9 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
} }
} }
if (extraflags & PLAYER_EXTRA_FLAG_FREE_TRANSMOG_CLAIMED)
SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_FREE_TRANSMOG_CLAIMED);
InitPvP(); InitPvP();
// RaF stuff. // RaF stuff.
@@ -18569,7 +18824,11 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
_LoadDeclinedNames(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES)); _LoadDeclinedNames(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES));
_LoadEquipmentSets(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS)); _LoadEquipmentSets(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS));
_LoadTransmogOutfits(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS)); _LoadTransmogCustomSets(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS));
_LoadTransmogOutfits(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT),
holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SITUATION),
holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SLOT),
fields.transmogOutfitEquippedId, fields.transmogOutfitLocked);
_LoadCUFProfiles(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES)); _LoadCUFProfiles(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES));
@@ -20314,27 +20573,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
} }
stmt->setString(index++, ss.str()); stmt->setString(index++, ss.str());
ss.str(""); stmt->setString(index++, GetCharacterSelectOutfit());
// cache equipment...
for (uint32 i = 0; i < REAGENT_BAG_SLOT_END; ++i)
{
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
ss << uint32(item->GetTemplate()->GetInventoryType()) << ' ' << item->GetDisplayId(this) << ' ';
if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetVisibleEnchantmentId(this)))
ss << enchant->ItemVisual;
else
ss << '0';
ss << ' '
<< uint32(sItemStore.AssertEntry(item->GetVisibleEntry(this))->SubclassID) << ' '
<< uint32(item->GetVisibleSecondaryModifiedAppearanceId(this)) << ' ';
}
else
ss << "0 0 0 0 0 ";
}
stmt->setString(index++, ss.str());
ss.str(""); ss.str("");
for (uint32 i = 0; i < m_activePlayerData->KnownTitles.size(); ++i) for (uint32 i = 0; i < m_activePlayerData->KnownTitles.size(); ++i)
@@ -20349,6 +20588,14 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
stmt->setUInt32(index++, ClientBuild::GetMinorMajorBugfixVersionForBuild(currentRealm->Build)); stmt->setUInt32(index++, ClientBuild::GetMinorMajorBugfixVersionForBuild(currentRealm->Build));
else else
stmt->setUInt32(index++, 0); stmt->setUInt32(index++, 0);
stmt->setInt32(index++, m_playerData->PersonalTabard->EmblemStyle);
stmt->setInt32(index++, m_playerData->PersonalTabard->EmblemColor);
stmt->setInt32(index++, m_playerData->PersonalTabard->BorderStyle);
stmt->setInt32(index++, m_playerData->PersonalTabard->BorderColor);
stmt->setInt32(index++, m_playerData->PersonalTabard->BackgroundColor);
stmt->setInt32(index++, m_activePlayerData->TransmogMetadata->TransmogOutfitID);
stmt->setBool(index++, m_activePlayerData->TransmogMetadata->Locked);
} }
else else
{ {
@@ -20473,27 +20720,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
} }
stmt->setString(index++, ss.str()); stmt->setString(index++, ss.str());
ss.str(""); stmt->setString(index++, GetCharacterSelectOutfit());
// cache equipment...
for (uint32 i = 0; i < REAGENT_BAG_SLOT_END; ++i)
{
if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
{
ss << uint32(item->GetTemplate()->GetInventoryType()) << ' ' << item->GetDisplayId(this) << ' ';
if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetVisibleEnchantmentId(this)))
ss << enchant->ItemVisual;
else
ss << '0';
ss << ' '
<< uint32(sItemStore.AssertEntry(item->GetVisibleEntry(this))->SubclassID) << ' '
<< uint32(item->GetVisibleSecondaryModifiedAppearanceId(this)) << ' ';
}
else
ss << "0 0 0 0 0 ";
}
stmt->setString(index++, ss.str());
ss.str(""); ss.str("");
for (uint32 i = 0; i < m_activePlayerData->KnownTitles.size(); ++i) for (uint32 i = 0; i < m_activePlayerData->KnownTitles.size(); ++i)
@@ -20515,6 +20742,14 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
else else
stmt->setUInt32(index++, 0); stmt->setUInt32(index++, 0);
stmt->setInt32(index++, m_playerData->PersonalTabard->EmblemStyle);
stmt->setInt32(index++, m_playerData->PersonalTabard->EmblemColor);
stmt->setInt32(index++, m_playerData->PersonalTabard->BorderStyle);
stmt->setInt32(index++, m_playerData->PersonalTabard->BorderColor);
stmt->setInt32(index++, m_playerData->PersonalTabard->BackgroundColor);
stmt->setInt32(index++, m_activePlayerData->TransmogMetadata->TransmogOutfitID);
stmt->setBool(index++, m_activePlayerData->TransmogMetadata->Locked);
// Index // Index
stmt->setUInt64(index, GetGUID().GetCounter()); stmt->setUInt64(index, GetGUID().GetCounter());
} }
@@ -20554,6 +20789,7 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
m_reputationMgr->SaveToDB(trans); m_reputationMgr->SaveToDB(trans);
m_questObjectiveCriteriaMgr->SaveToDB(trans); m_questObjectiveCriteriaMgr->SaveToDB(trans);
_SaveEquipmentSets(trans); _SaveEquipmentSets(trans);
_SaveTransmogOutfits(trans);
GetSession()->SaveTutorialsData(trans); // changed only while character in game GetSession()->SaveTutorialsData(trans); // changed only while character in game
_SaveInstanceTimeRestrictions(trans); _SaveInstanceTimeRestrictions(trans);
_SaveCurrency(trans); _SaveCurrency(trans);
@@ -20569,13 +20805,8 @@ void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDataba
_SaveStats(trans); _SaveStats(trans);
// TODO: Move this out // TODO: Move this out
GetSession()->GetCollectionMgr()->SaveAccountToys(loginTransaction); GetSession()->GetCollectionMgr()->SaveToDB(loginTransaction);
GetSession()->GetBattlePetMgr()->SaveToDB(loginTransaction); GetSession()->GetBattlePetMgr()->SaveToDB(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountHeirlooms(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountMounts(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountItemAppearances(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountTransmogIllusions(loginTransaction);
GetSession()->GetCollectionMgr()->SaveAccountWarbandScenes(loginTransaction);
GetSession()->SavePlayerDataAccount(loginTransaction); GetSession()->SavePlayerDataAccount(loginTransaction);
Battlenet::RealmHandle currentRealmId = sRealmList->GetCurrentRealmId(); Battlenet::RealmHandle currentRealmId = sRealmList->GetCurrentRealmId();
@@ -28047,6 +28278,71 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans)
} }
} }
void Player::_SaveTransmogOutfits(CharacterDatabaseTransaction trans)
{
CharacterDatabasePreparedStatement* stmt = nullptr;
ObjectGuid::LowType guid = GetGUID().GetCounter();
for (uint32 transmogOutfitId : m_changedTransmogOutfits)
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TRANSMOG_OUTFIT_SLOT);
stmt->setUInt64(0, guid);
stmt->setUInt32(1, transmogOutfitId);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TRANSMOG_OUTFIT_SITUATION);
stmt->setUInt64(0, guid);
stmt->setUInt32(1, transmogOutfitId);
trans->Append(stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TRANSMOG_OUTFIT_2);
stmt->setUInt64(0, guid);
stmt->setUInt32(1, transmogOutfitId);
trans->Append(stmt);
UF::TransmogOutfitData const* transmogOutfit = m_activePlayerData->TransmogOutfits.Get(transmogOutfitId);
if (!transmogOutfit)
continue;
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_TRANSMOG_OUTFIT_2);
stmt->setUInt64(0, guid);
stmt->setUInt32(1, transmogOutfitId);
stmt->setString(2, *transmogOutfit->OutfitInfo->Name);
stmt->setUInt32(3, *transmogOutfit->OutfitInfo->Icon);
stmt->setBool(4, *transmogOutfit->OutfitInfo->SituationsEnabled);
trans->Append(stmt);
for (UF::TransmogOutfitSituationInfo const& situation : transmogOutfit->Situations)
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_TRANSMOG_OUTFIT_SITUATION);
stmt->setUInt64(0, guid);
stmt->setUInt32(1, transmogOutfitId);
stmt->setUInt32(2, *situation.SituationID);
stmt->setUInt32(3, *situation.SpecID);
stmt->setUInt32(4, *situation.LoadoutID);
stmt->setUInt32(5, *situation.EquipmentSetID);
trans->Append(stmt);
}
for (UF::TransmogOutfitSlotData const& slot : transmogOutfit->Slots)
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_TRANSMOG_OUTFIT_SLOT);
stmt->setUInt64(0, guid);
stmt->setUInt32(1, transmogOutfitId);
stmt->setInt8(2, *slot.Slot);
stmt->setUInt8(3, *slot.SlotOption);
stmt->setUInt32(4, *slot.ItemModifiedAppearanceID);
stmt->setUInt8(5, *slot.AppearanceDisplayType);
stmt->setUInt32(6, *slot.SpellItemEnchantmentID);
stmt->setUInt8(7, *slot.IllusionDisplayType);
stmt->setUInt32(8, *slot.Flags);
trans->Append(stmt);
}
}
m_changedTransmogOutfits.clear();
}
void Player::_SaveBGData(CharacterDatabaseTransaction trans) void Player::_SaveBGData(CharacterDatabaseTransaction trans)
{ {
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA); CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
@@ -30891,6 +31187,308 @@ void Player::UpdateWarModeAuras()
} }
} }
void Player::AddUnlockedTransmogOutfits(std::span<int32 const> transmogOutfitIds)
{
auto unlockedTransmogOutfits = m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::UnlockedTransmogOutfits);
for (int32 transmogOutfitId : transmogOutfitIds)
AddDynamicUpdateFieldValue(unlockedTransmogOutfits) = transmogOutfitId;
}
void Player::CreateTransmogOutfit(uint32 id, WorldPackets::Transmogrification::TransmogOutfitDataInfo const& outfitData)
{
auto outfit = m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::TransmogOutfits, id);
InitializeNewTransmogOutfit(outfit, id, outfitData);
m_changedTransmogOutfits.insert(id);
}
void Player::InitializeNewTransmogOutfit(UF::MutableFieldReference<UF::TransmogOutfitData, false> outfit,
uint32 id, WorldPackets::Transmogrification::TransmogOutfitDataInfo const& outfitData)
{
SetUpdateFieldValue(outfit.ModifyValue(&UF::TransmogOutfitData::Id), id);
auto outfitInfo = outfit.ModifyValue(&UF::TransmogOutfitData::OutfitInfo);
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::SetType), AsUnderlyingType(outfitData.SetType));
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::SituationsEnabled), outfitData.SituationsEnabled);
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::Icon), outfitData.Icon);
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::Name), std::string(outfitData.Name));
auto situations = outfit.ModifyValue(&UF::TransmogOutfitData::Situations);
for (TransmogSituationEntry const* defaultSituation : TransmogMgr::GetDefaultSituations())
{
auto situation = AddDynamicUpdateFieldValue(situations);
situation.ModifyValue(&UF::TransmogOutfitSituationInfo::SituationID).SetValue(defaultSituation->ID);
}
auto slots = outfit.ModifyValue(&UF::TransmogOutfitData::Slots);
for (TransmogMgr::TransmogOutfitSlotAndOptionInfo const& slotInfo : TransmogMgr::GetAllSlots())
{
auto slot = AddDynamicUpdateFieldValue(slots);
slot.ModifyValue(&UF::TransmogOutfitSlotData::Slot).SetValue(AsUnderlyingType(slotInfo.Slot->GetSlot()));
if (slotInfo.SlotOption)
{
slot.ModifyValue(&UF::TransmogOutfitSlotData::SlotOption).SetValue(AsUnderlyingType(slotInfo.SlotOption->GetOption()));
switch (slotInfo.SlotOption->GetOption())
{
case TransmogOutfitSlotOption::ArtifactSpecOne:
case TransmogOutfitSlotOption::ArtifactSpecTwo:
case TransmogOutfitSlotOption::ArtifactSpecThree:
case TransmogOutfitSlotOption::ArtifactSpecFour:
// artifacts are disabled by default
slot.ModifyValue(&UF::TransmogOutfitSlotData::AppearanceDisplayType).SetValue(AsUnderlyingType(TransmogOutfitDisplayType::Disabled));
slot.ModifyValue(&UF::TransmogOutfitSlotData::IllusionDisplayType).SetValue(AsUnderlyingType(TransmogOutfitDisplayType::Disabled));
break;
default:
break;
}
}
}
}
bool Player::UpdateTransmogOutfit(uint32 id, WorldPackets::Transmogrification::TransmogOutfitDataInfo const& outfitData)
{
if (!m_activePlayerData->TransmogOutfits.Get(id))
return false;
auto outfitInfo = m_values.ModifyValue(&Player::m_activePlayerData)
.ModifyValue(&UF::ActivePlayerData::TransmogOutfits, id)
.ModifyValue(&UF::TransmogOutfitData::OutfitInfo);
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::SetType), AsUnderlyingType(outfitData.SetType));
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::SituationsEnabled), outfitData.SituationsEnabled);
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::Icon), outfitData.Icon);
SetUpdateFieldValue(outfitInfo.ModifyValue(&UF::TransmogOutfitDataInfo::Name), std::string(outfitData.Name));
m_changedTransmogOutfits.insert(id);
return true;
}
void Player::UpdateTransmogOutfitSituations(uint32 id, bool situationsEnabled, std::span<WorldPackets::Transmogrification::TransmogOutfitSituationInfo const> situations)
{
auto outfit = m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::TransmogOutfits, id);
SetUpdateFieldValue(outfit.ModifyValue(&UF::TransmogOutfitData::OutfitInfo).ModifyValue(&UF::TransmogOutfitDataInfo::SituationsEnabled), situationsEnabled);
auto outfitSituations = outfit.ModifyValue(&UF::TransmogOutfitData::Situations);
ClearDynamicUpdateFieldValues(outfitSituations);
for (WorldPackets::Transmogrification::TransmogOutfitSituationInfo const& situation : situations)
{
auto outfitSituation = AddDynamicUpdateFieldValue(outfitSituations);
outfitSituation.ModifyValue(&UF::TransmogOutfitSituationInfo::SituationID).SetValue(situation.SituationID);
outfitSituation.ModifyValue(&UF::TransmogOutfitSituationInfo::SpecID).SetValue(situation.SpecID);
outfitSituation.ModifyValue(&UF::TransmogOutfitSituationInfo::LoadoutID).SetValue(situation.LoadoutID);
outfitSituation.ModifyValue(&UF::TransmogOutfitSituationInfo::EquipmentSetID).SetValue(situation.EquipmentSetID);
}
m_changedTransmogOutfits.insert(id);
}
void Player::UpdateTransmogOutfitSlots(uint32 id, std::span<WorldPackets::Transmogrification::TransmogOutfitSlotData const> slots)
{
UF::TransmogOutfitData const* transmogOutfit = m_activePlayerData->TransmogOutfits.Get(id);
if (!transmogOutfit)
return;
auto outfit = m_values.ModifyValue(&Player::m_activePlayerData)
.ModifyValue(&UF::ActivePlayerData::TransmogOutfits, id);
uint32 outfitSlotIndex = 0;
for (WorldPackets::Transmogrification::TransmogOutfitSlotData const& slot : slots)
{
while (std::pair(*transmogOutfit->Slots[outfitSlotIndex].Slot, *transmogOutfit->Slots[outfitSlotIndex].SlotOption) < std::pair(AsUnderlyingType(slot.Slot), AsUnderlyingType(slot.SlotOption)))
if (++outfitSlotIndex >= transmogOutfit->Slots.size())
return;
auto viewedOutfitSlot = outfit.ModifyValue(&UF::TransmogOutfitData::Slots, outfitSlotIndex);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::Slot), AsUnderlyingType(slot.Slot));
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::SlotOption), AsUnderlyingType(slot.SlotOption));
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::ItemModifiedAppearanceID), slot.ItemModifiedAppearanceID);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::AppearanceDisplayType), AsUnderlyingType(slot.AppearanceDisplayType));
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::SpellItemEnchantmentID), slot.SpellItemEnchantmentID);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::IllusionDisplayType), AsUnderlyingType(slot.IllusionDisplayType));
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::Flags), slot.Flags);
}
m_changedTransmogOutfits.insert(id);
}
void Player::EquipTransmogOutfit(uint32 id, TransmogSituationTrigger trigger, Optional<bool> locked)
{
auto activePlayerData = m_values.ModifyValue(&Player::m_activePlayerData);
auto transmogMetadata = activePlayerData.ModifyValue(&UF::ActivePlayerData::TransmogMetadata);
SetUpdateFieldValue(transmogMetadata.ModifyValue(&UF::TransmogOutfitMetadata::TransmogOutfitID), id);
SetUpdateFieldValue(transmogMetadata.ModifyValue(&UF::TransmogOutfitMetadata::SituationTrigger), AsUnderlyingType(trigger));
if (locked.has_value())
SetUpdateFieldValue(transmogMetadata.ModifyValue(&UF::TransmogOutfitMetadata::Locked), *locked);
auto viewedOutfit = activePlayerData.ModifyValue(&UF::ActivePlayerData::ViewedOutfit);
if (UF::TransmogOutfitData const* transmogOutfit = m_activePlayerData->TransmogOutfits.Get(id))
{
for (UF::TransmogOutfitSlotData const& slot : transmogOutfit->Slots)
{
uint32 slotIndex = TransmogMgr::GetSlotAndOption(static_cast<TransmogOutfitSlot>(*slot.Slot), static_cast<TransmogOutfitSlotOption>(*slot.SlotOption))->SlotIndex;
auto viewedOutfitSlot = viewedOutfit.ModifyValue(&UF::TransmogOutfitData::Slots, slotIndex);
if (static_cast<TransmogOutfitDisplayType>(*slot.AppearanceDisplayType) != TransmogOutfitDisplayType::Unassigned)
{
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::ItemModifiedAppearanceID), slot.ItemModifiedAppearanceID);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::AppearanceDisplayType), slot.AppearanceDisplayType);
}
if (static_cast<TransmogOutfitDisplayType>(*slot.IllusionDisplayType) != TransmogOutfitDisplayType::Unassigned)
{
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::SpellItemEnchantmentID), slot.SpellItemEnchantmentID);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::IllusionDisplayType), slot.IllusionDisplayType);
}
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::Flags), slot.Flags);
}
}
else
{
for (TransmogMgr::TransmogOutfitSlotAndOptionInfo const& slotInfo : TransmogMgr::GetAllSlots())
{
auto viewedOutfitSlot = viewedOutfit.ModifyValue(&UF::TransmogOutfitData::Slots, slotInfo.SlotIndex);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::Slot), AsUnderlyingType(slotInfo.Slot->GetSlot()));
TransmogOutfitSlotOption slotOption = slotInfo.SlotOption ? slotInfo.SlotOption->GetOption() : TransmogOutfitSlotOption::None;
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::SlotOption), AsUnderlyingType(slotOption));
if (Item const* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slotInfo.Slot->InventorySlotEnum))
{
if (item->GetTemplate()->GetWeaponTransmogOutfitSlotOption() == slotOption)
{
if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = item->GetItemModifiedAppearance())
{
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::ItemModifiedAppearanceID), itemModifiedAppearance->ID);
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::AppearanceDisplayType), AsUnderlyingType(TransmogOutfitDisplayType::Equipped));
}
}
}
switch (slotOption)
{
case TransmogOutfitSlotOption::ArtifactSpecOne:
case TransmogOutfitSlotOption::ArtifactSpecTwo:
case TransmogOutfitSlotOption::ArtifactSpecThree:
case TransmogOutfitSlotOption::ArtifactSpecFour:
// artifacts are disabled by default
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::AppearanceDisplayType), AsUnderlyingType(TransmogOutfitDisplayType::Disabled));
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::IllusionDisplayType), AsUnderlyingType(TransmogOutfitDisplayType::Disabled));
break;
case TransmogOutfitSlotOption::None:
break;
default:
SetUpdateFieldValue(viewedOutfitSlot.ModifyValue(&UF::TransmogOutfitSlotData::IllusionDisplayType), AsUnderlyingType(TransmogOutfitDisplayType::Equipped));
break;
}
}
}
for (uint8 equipSlot = EQUIPMENT_SLOT_START; equipSlot < EQUIPMENT_SLOT_END; ++equipSlot)
SetVisibleItemSlot(equipSlot, GetItemByPos(INVENTORY_SLOT_BAG_0, equipSlot));
}
std::string Player::GetCharacterSelectOutfit() const
{
std::vector<UF::TransmogOutfitData const*> outfits;
for (auto const& [_, transmogOutfit] : m_activePlayerData->TransmogOutfits)
{
if (!transmogOutfit.value.OutfitInfo->SituationsEnabled)
continue;
bool isCharacterSelect = transmogOutfit.value.Situations.FindIndexIf([](UF::TransmogOutfitSituationInfo const& situation)
{
return sTransmogSituationStore.AssertEntry(situation.SituationID)->GetSituation() == TransmogSituation::LocationCharacterSelect;
}) >= 0;
if (!isCharacterSelect)
continue;
outfits.push_back(&transmogOutfit.value);
}
UF::TransmogOutfitData const* outfit = &*m_activePlayerData->ViewedOutfit;
if (!outfits.empty())
outfit = Trinity::Containers::SelectRandomContainerElement(outfits);
auto isTransmogDisplayed = [](TransmogOutfitDisplayType displayType)
{
return displayType == TransmogOutfitDisplayType::Assigned || displayType == TransmogOutfitDisplayType::Hidden;
};
std::string result;
for (EquipmentSlots i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; i = EquipmentSlots(i + 1))
{
TransmogOutfitSlotOption transmogSlotOption = TransmogOutfitSlotOption::None;
switch (i)
{
case EQUIPMENT_SLOT_MAINHAND:
transmogSlotOption = static_cast<TransmogOutfitSlotOption>(m_activePlayerData->TransmogMetadata->StampedOptionMainHand);
break;
case EQUIPMENT_SLOT_OFFHAND:
transmogSlotOption = static_cast<TransmogOutfitSlotOption>(m_activePlayerData->TransmogMetadata->StampedOptionOffHand);
break;
default:
break;
}
if (TransmogMgr::TransmogOutfitSlotAndOptionInfo const* slotInfo = TransmogMgr::GetSlotAndOption(i, transmogSlotOption))
{
UF::TransmogOutfitSlotData const& transmogOutfitSlot = outfit->Slots[slotInfo->SlotIndex];
uint32 itemModifiedAppearanceId = transmogOutfitSlot.ItemModifiedAppearanceID;
if (!isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*transmogOutfitSlot.AppearanceDisplayType)))
itemModifiedAppearanceId = m_activePlayerData->ViewedOutfit->Slots[slotInfo->SlotIndex].ItemModifiedAppearanceID;
uint32 spellItemEnchantmentId = transmogOutfitSlot.SpellItemEnchantmentID;
if (!isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*transmogOutfitSlot.IllusionDisplayType)))
spellItemEnchantmentId = m_activePlayerData->ViewedOutfit->Slots[slotInfo->SlotIndex].SpellItemEnchantmentID;
InventoryType inventoryType = INVTYPE_NON_EQUIP;
int32 displayId = 0;
uint16 itemVisual = 0;
uint8 subClass = 0;
uint32 secondaryItemModifiedAppearanceId = 0;
if (ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(itemModifiedAppearanceId))
{
if (ItemEntry const* item = sItemStore.LookupEntry(itemModifiedAppearance->ItemID))
{
subClass = item->SubclassID;
inventoryType = static_cast<InventoryType>(item->InventoryType);
}
if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(itemModifiedAppearance->ItemAppearanceID))
displayId = itemAppearance->ItemDisplayInfoID;
}
if (SpellItemEnchantmentEntry const* spellItemEnchantment = sSpellItemEnchantmentStore.LookupEntry(spellItemEnchantmentId))
itemVisual = spellItemEnchantment->ItemVisual;
if (TransmogOutfitSlotInfoEntry const* secondarySlot = sTransmogOutfitSlotInfoStore.LookupEntry(slotInfo->Slot->SecondarySlotID))
{
if (TransmogMgr::TransmogOutfitSlotAndOptionInfo const* secondarySlotInfo = TransmogMgr::GetSlotAndOption(secondarySlot->GetSlot(), transmogSlotOption))
{
UF::TransmogOutfitSlotData const& secondaryTransmogOutfitSlot = outfit->Slots[secondarySlotInfo->SlotIndex];
secondaryItemModifiedAppearanceId = secondaryTransmogOutfitSlot.ItemModifiedAppearanceID;
if (!isTransmogDisplayed(static_cast<TransmogOutfitDisplayType>(*secondaryTransmogOutfitSlot.AppearanceDisplayType)))
secondaryItemModifiedAppearanceId = m_activePlayerData->ViewedOutfit->Slots[secondarySlotInfo->SlotIndex].ItemModifiedAppearanceID;
}
}
Trinity::StringFormatTo(std::back_inserter(result), "{} {} {} {} {} ", inventoryType, displayId, itemVisual, subClass, secondaryItemModifiedAppearanceId);
}
else
result += "0 0 0 0 0 "sv;
}
for (uint32 i = EQUIPMENT_SLOT_END; i < REAGENT_BAG_SLOT_END; ++i)
result += "0 0 0 0 0 "sv;
return result;
}
void Player::OnPhaseChange() void Player::OnPhaseChange()
{ {
Unit::OnPhaseChange(); Unit::OnPhaseChange();
+35 -3
View File
@@ -135,6 +135,13 @@ namespace WorldPackets
struct TraitConfig; struct TraitConfig;
struct TraitEntry; struct TraitEntry;
} }
namespace Transmogrification
{
struct TransmogOutfitDataInfo;
struct TransmogOutfitSituationInfo;
struct TransmogOutfitSlotData;
}
} }
TC_GAME_API uint32 GetBagSize(Bag const* bag); TC_GAME_API uint32 GetBagSize(Bag const* bag);
@@ -334,7 +341,8 @@ enum ActionButtonType
ACTION_BUTTON_CMACRO = ACTION_BUTTON_C | ACTION_BUTTON_MACRO, ACTION_BUTTON_CMACRO = ACTION_BUTTON_C | ACTION_BUTTON_MACRO,
ACTION_BUTTON_COMPANION = 0x50, ACTION_BUTTON_COMPANION = 0x50,
ACTION_BUTTON_MOUNT = 0x60, ACTION_BUTTON_MOUNT = 0x60,
ACTION_BUTTON_ITEM = 0x80 ACTION_BUTTON_ITEM = 0x80,
ACTION_BUTTON_OUTFIT = 0x90
}; };
enum class HonorGainSource : uint8 enum class HonorGainSource : uint8
@@ -548,6 +556,7 @@ enum PlayerLocalFlags
PLAYER_LOCAL_FLAG_CHARACTER_BANK_DISABLED = 0x00080000, PLAYER_LOCAL_FLAG_CHARACTER_BANK_DISABLED = 0x00080000,
PLAYER_LOCAL_FLAG_CHARACTER_BANK_CONVERSION_FAILED = 0x00100000, PLAYER_LOCAL_FLAG_CHARACTER_BANK_CONVERSION_FAILED = 0x00100000,
PLAYER_LOCAL_FLAG_ACCOUNT_BANK_DISABLED = 0x00200000, PLAYER_LOCAL_FLAG_ACCOUNT_BANK_DISABLED = 0x00200000,
PLAYER_LOCAL_FLAG_FREE_TRANSMOG_CLAIMED = 0x00400000,
}; };
DEFINE_ENUM_FLAG(PlayerLocalFlags); DEFINE_ENUM_FLAG(PlayerLocalFlags);
@@ -586,6 +595,8 @@ enum PlayerExtraFlags
PLAYER_EXTRA_HAS_RACE_CHANGED = 0x0200, PLAYER_EXTRA_HAS_RACE_CHANGED = 0x0200,
PLAYER_EXTRA_GRANTED_LEVELS_FROM_RAF = 0x0400, PLAYER_EXTRA_GRANTED_LEVELS_FROM_RAF = 0x0400,
PLAYER_EXTRA_LEVEL_BOOSTED = 0x0800, PLAYER_EXTRA_LEVEL_BOOSTED = 0x0800,
PLAYER_EXTRA_FLAG_FREE_TRANSMOG_CLAIMED = 0x1000,
}; };
// 2^n values // 2^n values
@@ -937,6 +948,9 @@ enum PlayerLoginQueryIndex
PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS, PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS,
PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS, PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS,
PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS,
PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT,
PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SITUATION,
PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SLOT,
PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS, PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS,
PLAYER_LOGIN_QUERY_LOAD_BG_DATA, PLAYER_LOGIN_QUERY_LOAD_BG_DATA,
PLAYER_LOGIN_QUERY_LOAD_GLYPHS, PLAYER_LOGIN_QUERY_LOAD_GLYPHS,
@@ -1264,6 +1278,8 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void SetBeenGrantedLevelsFromRaF() { m_ExtraFlags |= PLAYER_EXTRA_GRANTED_LEVELS_FROM_RAF; } void SetBeenGrantedLevelsFromRaF() { m_ExtraFlags |= PLAYER_EXTRA_GRANTED_LEVELS_FROM_RAF; }
bool HasLevelBoosted() const { return (m_ExtraFlags & PLAYER_EXTRA_LEVEL_BOOSTED) != 0; } bool HasLevelBoosted() const { return (m_ExtraFlags & PLAYER_EXTRA_LEVEL_BOOSTED) != 0; }
void SetHasLevelBoosted() { m_ExtraFlags |= PLAYER_EXTRA_LEVEL_BOOSTED; } void SetHasLevelBoosted() { m_ExtraFlags |= PLAYER_EXTRA_LEVEL_BOOSTED; }
bool HasClaimedFreeTransmog() const { return (m_ExtraFlags & PLAYER_EXTRA_FLAG_FREE_TRANSMOG_CLAIMED) != 0; }
void SetHasClaimedFreeTransmog() { m_ExtraFlags |= PLAYER_EXTRA_FLAG_FREE_TRANSMOG_CLAIMED; }
uint32 GetXP() const { return m_activePlayerData->XP; } uint32 GetXP() const { return m_activePlayerData->XP; }
uint32 GetXPForNextLevel() const { return m_activePlayerData->NextLevelXP; } uint32 GetXPForNextLevel() const { return m_activePlayerData->NextLevelXP; }
@@ -1550,7 +1566,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void ApplyEquipCooldown(Item* pItem); void ApplyEquipCooldown(Item* pItem);
void QuickEquipItem(uint16 pos, Item* pItem); void QuickEquipItem(uint16 pos, Item* pItem);
void VisualizeItem(uint8 slot, Item* pItem); void VisualizeItem(uint8 slot, Item* pItem);
void SetVisibleItemSlot(uint8 slot, Item* pItem); void SetVisibleItemSlot(uint8 slot, Item const* item);
Item* BankItem(ItemPosCountVec const& dest, Item* pItem, bool update); Item* BankItem(ItemPosCountVec const& dest, Item* pItem, bool update);
void RemoveItem(uint8 bag, uint8 slot, bool update); void RemoveItem(uint8 bag, uint8 slot, bool update);
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update); void MoveItemFromInventory(uint8 bag, uint8 slot, bool update);
@@ -2987,6 +3003,18 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
bool CanEnableWarModeInArea() const; bool CanEnableWarModeInArea() const;
void UpdateWarModeAuras(); void UpdateWarModeAuras();
void AddUnlockedTransmogOutfits(std::span<int32 const> transmogOutfitIds);
void AddUnlockedTransmogOutfit(int32 transmogOutfitIds) { AddUnlockedTransmogOutfits(std::span(&transmogOutfitIds, 1)); }
void CreateTransmogOutfit(uint32 id, WorldPackets::Transmogrification::TransmogOutfitDataInfo const& outfitData);
void InitializeNewTransmogOutfit(UF::MutableFieldReference<UF::TransmogOutfitData, false> outfit,
uint32 id, WorldPackets::Transmogrification::TransmogOutfitDataInfo const& outfitData);
bool UpdateTransmogOutfit(uint32 id, WorldPackets::Transmogrification::TransmogOutfitDataInfo const& outfitData);
void UpdateTransmogOutfitSituations(uint32 id, bool situationsEnabled, std::span<WorldPackets::Transmogrification::TransmogOutfitSituationInfo const> situations);
void UpdateTransmogOutfitSlots(uint32 id, std::span<WorldPackets::Transmogrification::TransmogOutfitSlotData const> slots);
void EquipTransmogOutfit(uint32 id, TransmogSituationTrigger trigger, Optional<bool> locked);
std::string GetCharacterSelectOutfit() const;
std::string GetDebugInfo() const override; std::string GetDebugInfo() const override;
UF::UpdateField<UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER> m_playerData; UF::UpdateField<UF::PlayerData, int32(WowCS::EntityFragment::CGObject), TYPEID_PLAYER> m_playerData;
@@ -3075,7 +3103,9 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void _LoadDeclinedNames(PreparedQueryResult result); void _LoadDeclinedNames(PreparedQueryResult result);
void _LoadArenaTeamInfo(PreparedQueryResult result); void _LoadArenaTeamInfo(PreparedQueryResult result);
void _LoadEquipmentSets(PreparedQueryResult result); void _LoadEquipmentSets(PreparedQueryResult result);
void _LoadTransmogOutfits(PreparedQueryResult result); void _LoadTransmogCustomSets(PreparedQueryResult result);
void _LoadTransmogOutfits(PreparedQueryResult setsResult, PreparedQueryResult situationsResult, PreparedQueryResult slotsResult,
int32 equippedTransmogOutfitId, bool locked);
void _LoadBGData(PreparedQueryResult result); void _LoadBGData(PreparedQueryResult result);
void _LoadGlyphs(PreparedQueryResult result); void _LoadGlyphs(PreparedQueryResult result);
void _LoadTalents(PreparedQueryResult result); void _LoadTalents(PreparedQueryResult result);
@@ -3106,6 +3136,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
void _SaveSpells(CharacterDatabaseTransaction trans); void _SaveSpells(CharacterDatabaseTransaction trans);
void _SaveStoredAuraTeleportLocations(CharacterDatabaseTransaction trans); void _SaveStoredAuraTeleportLocations(CharacterDatabaseTransaction trans);
void _SaveEquipmentSets(CharacterDatabaseTransaction trans); void _SaveEquipmentSets(CharacterDatabaseTransaction trans);
void _SaveTransmogOutfits(CharacterDatabaseTransaction trans);
void _SaveBGData(CharacterDatabaseTransaction trans); void _SaveBGData(CharacterDatabaseTransaction trans);
void _SaveGlyphs(CharacterDatabaseTransaction trans) const; void _SaveGlyphs(CharacterDatabaseTransaction trans) const;
void _SaveTalents(CharacterDatabaseTransaction trans); void _SaveTalents(CharacterDatabaseTransaction trans);
@@ -3254,6 +3285,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
std::unique_ptr<Runes> m_runes; std::unique_ptr<Runes> m_runes;
EquipmentSetContainer _equipmentSets; EquipmentSetContainer _equipmentSets;
std::set<uint32> m_changedTransmogOutfits;
bool CanNeverSee(WorldObject const* obj, bool ignorePhaseShift = false) const override; bool CanNeverSee(WorldObject const* obj, bool ignorePhaseShift = false) const override;
bool CanAlwaysSee(WorldObject const* obj) const override; bool CanAlwaysSee(WorldObject const* obj) const override;
+3 -2
View File
@@ -70,6 +70,7 @@
#include "TerrainMgr.h" #include "TerrainMgr.h"
#include "ThreadPool.h" #include "ThreadPool.h"
#include "Timer.h" #include "Timer.h"
#include "TransmogMgr.h"
#include "TransportMgr.h" #include "TransportMgr.h"
#include "VMapFactory.h" #include "VMapFactory.h"
#include "VMapManager.h" #include "VMapManager.h"
@@ -1509,12 +1510,12 @@ void ObjectMgr::LoadEquipmentTemplates()
} }
// AppearanceModId 0 is always valid // AppearanceModId 0 is always valid
if (equipmentInfo.Items[i].AppearanceModId && !sDB2Manager.GetItemModifiedAppearance(equipmentInfo.Items[i].ItemId, equipmentInfo.Items[i].AppearanceModId)) if (equipmentInfo.Items[i].AppearanceModId && !TransmogMgr::GetItemModifiedAppearance(equipmentInfo.Items[i].ItemId, equipmentInfo.Items[i].AppearanceModId))
{ {
TC_LOG_ERROR("sql.sql", "Unknown item appearance for (ID={}, AppearanceModID={}) pair in creature_equip_template.ItemID{} creature_equip_template.AppearanceModID{} " TC_LOG_ERROR("sql.sql", "Unknown item appearance for (ID={}, AppearanceModID={}) pair in creature_equip_template.ItemID{} creature_equip_template.AppearanceModID{} "
"for CreatureID = {} and ID={}, forced to default.", "for CreatureID = {} and ID={}, forced to default.",
equipmentInfo.Items[i].ItemId, equipmentInfo.Items[i].AppearanceModId, i + 1, i + 1, entry, id); equipmentInfo.Items[i].ItemId, equipmentInfo.Items[i].AppearanceModId, i + 1, i + 1, entry, id);
if (ItemModifiedAppearanceEntry const* defaultAppearance = sDB2Manager.GetDefaultItemModifiedAppearance(equipmentInfo.Items[i].ItemId)) if (ItemModifiedAppearanceEntry const* defaultAppearance = TransmogMgr::GetDefaultItemModifiedAppearance(equipmentInfo.Items[i].ItemId))
equipmentInfo.Items[i].AppearanceModId = defaultAppearance->ItemAppearanceModifierID; equipmentInfo.Items[i].AppearanceModId = defaultAppearance->ItemAppearanceModifierID;
else else
equipmentInfo.Items[i].AppearanceModId = 0; equipmentInfo.Items[i].AppearanceModId = 0;
+14 -4
View File
@@ -61,6 +61,7 @@
#include "SocialMgr.h" #include "SocialMgr.h"
#include "StringConvert.h" #include "StringConvert.h"
#include "SystemPackets.h" #include "SystemPackets.h"
#include "TransmogMgr.h"
#include "Util.h" #include "Util.h"
#include "World.h" #include "World.h"
#include <boost/circular_buffer.hpp> #include <boost/circular_buffer.hpp>
@@ -257,6 +258,18 @@ bool LoginQueryHolder::Initialize()
stmt->setUInt64(0, lowGuid); stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS, stmt); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT);
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT_SITUATION);
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SITUATION, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TRANSMOG_OUTFIT_SLOT);
stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFIT_SLOT, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUF_PROFILES); stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_CUF_PROFILES);
stmt->setUInt64(0, lowGuid); stmt->setUInt64(0, lowGuid);
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, stmt); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES, stmt);
@@ -2047,10 +2060,7 @@ void WorldSession::HandleEquipmentSetSave(WorldPackets::EquipmentSet::SaveEquipm
auto validateIllusion = [this](uint32 enchantId) -> bool auto validateIllusion = [this](uint32 enchantId) -> bool
{ {
SpellItemEnchantmentEntry const* illusion = sSpellItemEnchantmentStore.LookupEntry(enchantId); SpellItemEnchantmentEntry const* illusion = sSpellItemEnchantmentStore.LookupEntry(enchantId);
if (!illusion) if (!illusion || !TransmogMgr::GetTransmogIllusionForSpellItemEnchantment(enchantId))
return false;
if (!illusion->ItemVisual || !illusion->GetFlags().HasFlag(SpellItemEnchantmentFlags::AllowTransmog))
return false; return false;
if (!ConditionMgr::IsPlayerMeetingCondition(_player, illusion->TransmogUseConditionID)) if (!ConditionMgr::IsPlayerMeetingCondition(_player, illusion->TransmogUseConditionID))
@@ -23,6 +23,7 @@
#include "NPCPackets.h" #include "NPCPackets.h"
#include "ObjectMgr.h" #include "ObjectMgr.h"
#include "Player.h" #include "Player.h"
#include "TransmogMgr.h"
#include "TransmogrificationPackets.h" #include "TransmogrificationPackets.h"
void WorldSession::HandleTransmogrifyItems(WorldPackets::Transmogrification::TransmogrifyItems& transmogrifyItems) void WorldSession::HandleTransmogrifyItems(WorldPackets::Transmogrification::TransmogrifyItems& transmogrifyItems)
@@ -128,7 +129,7 @@ void WorldSession::HandleTransmogrifyItems(WorldPackets::Transmogrification::Tra
return; return;
} }
TransmogIllusionEntry const* illusion = sDB2Manager.GetTransmogIllusionForEnchantment(transmogItem.SpellItemEnchantmentID); TransmogIllusionEntry const* illusion = TransmogMgr::GetTransmogIllusionForSpellItemEnchantment(transmogItem.SpellItemEnchantmentID);
if (!illusion) if (!illusion)
{ {
TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - {}, Name: {} tried to transmogrify illusion using invalid enchant ({}).", player->GetGUID().ToString(), player->GetName(), transmogItem.SpellItemEnchantmentID); TC_LOG_DEBUG("network", "WORLD: HandleTransmogrifyItems - {}, Name: {} tried to transmogrify illusion using invalid enchant ({}).", player->GetGUID().ToString(), player->GetName(), transmogItem.SpellItemEnchantmentID);
@@ -326,6 +327,283 @@ void WorldSession::HandleTransmogrifyItems(WorldPackets::Transmogrification::Tra
} }
} }
void WorldSession::HandleTransmogOutfitNew(WorldPackets::Transmogrification::TransmogOutfitNew const& transmogOutfitNew)
{
if (!_player->GetNPCIfCanInteractWith(transmogOutfitNew.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER, UNIT_NPC_FLAG_2_NONE))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - {} not found or player can't interact with it.",
GetPlayerInfo(), transmogOutfitNew.Npc);
return;
}
_player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
if (transmogOutfitNew.Source != TransmogOutfitEntrySource::PlayerPurchased)
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - source {} not allowed.",
GetPlayerInfo(), transmogOutfitNew.Source);
return;
}
if (transmogOutfitNew.Info.SetType != TransmogOutfitSetType::Outfit)
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - set type {} not allowed.",
GetPlayerInfo(), transmogOutfitNew.Info.SetType);
return;
}
TransmogOutfitEntryEntry const* transmogOutfitEntry = TransmogMgr::GetNextOutfitToUnlock(transmogOutfitNew.Source, _player);
if (!transmogOutfitEntry)
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - no next unlockable outfit entry found for source {}.",
GetPlayerInfo(), transmogOutfitNew.Source);
return;
}
if (!_player->HasEnoughMoney(transmogOutfitEntry->Cost))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - not enough money.",
GetPlayerInfo());
return;
}
GetCollectionMgr()->AddTransmogOutfit(transmogOutfitEntry->ID);
_player->CreateTransmogOutfit(transmogOutfitEntry->ID, transmogOutfitNew.Info);
_player->ModifyMoney(-int64(transmogOutfitEntry->Cost));
WorldPackets::Transmogrification::TransmogOutfitNewEntryAdded transmogOutfitNewEntryAdded;
transmogOutfitNewEntryAdded.TransmogOutfitID = transmogOutfitEntry->ID;
SendPacket(transmogOutfitNewEntryAdded.Write());
}
void WorldSession::HandleTransmogOutfitUpdateInfo(WorldPackets::Transmogrification::TransmogOutfitUpdateInfo const& transmogOutfitUpdateInfo)
{
if (!_player->GetNPCIfCanInteractWith(transmogOutfitUpdateInfo.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER, UNIT_NPC_FLAG_2_NONE))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - {} not found or player can't interact with it.",
GetPlayerInfo(), transmogOutfitUpdateInfo.Npc);
return;
}
_player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
if (!_player->UpdateTransmogOutfit(transmogOutfitUpdateInfo.OutfitID, transmogOutfitUpdateInfo.Info))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateInfo - player does not have outfit {}.",
GetPlayerInfo(), transmogOutfitUpdateInfo.OutfitID);
return;
}
// SMSG_UPDATE_OBJECT must be received by client before transmog packet for UI to properly update
Player::ValuesUpdateForPlayerWithMaskSender sendUpdateObject(_player);
sendUpdateObject.ActivePlayerMask.MarkChanged(&UF::ActivePlayerData::TransmogOutfits);
sendUpdateObject(_player);
WorldPackets::Transmogrification::TransmogOutfitInfoUpdated transmogOutfitInfoUpdated;
transmogOutfitInfoUpdated.TransmogOutfitID = transmogOutfitUpdateInfo.OutfitID;
transmogOutfitInfoUpdated.OutfitInfo = &transmogOutfitUpdateInfo.Info;
SendPacket(transmogOutfitInfoUpdated.Write());
}
void WorldSession::HandleTransmogOutfitUpdateSituations(WorldPackets::Transmogrification::TransmogOutfitUpdateSituations const& transmogOutfitUpdateSituations)
{
if (!_player->GetNPCIfCanInteractWith(transmogOutfitUpdateSituations.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER, UNIT_NPC_FLAG_2_NONE))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - {} not found or player can't interact with it.",
GetPlayerInfo(), transmogOutfitUpdateSituations.Npc);
return;
}
_player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
if (!_player->m_activePlayerData->TransmogOutfits.Get(transmogOutfitUpdateSituations.OutfitID))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSituations - player does not have outfit {}.",
GetPlayerInfo(), transmogOutfitUpdateSituations.OutfitID);
return;
}
if (!TransmogMgr::ValidateSituations(transmogOutfitUpdateSituations.Situations))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSituations - player sent invalid situations.",
GetPlayerInfo());
return;
}
_player->UpdateTransmogOutfitSituations(transmogOutfitUpdateSituations.OutfitID, transmogOutfitUpdateSituations.SituationsEnabled,
transmogOutfitUpdateSituations.Situations);
// SMSG_UPDATE_OBJECT must be received by client before transmog packet for UI to properly update
Player::ValuesUpdateForPlayerWithMaskSender sendUpdateObject(_player);
sendUpdateObject.ActivePlayerMask.MarkChanged(&UF::ActivePlayerData::TransmogOutfits);
sendUpdateObject(_player);
WorldPackets::Transmogrification::TransmogOutfitSituationsUpdated transmogOutfitSituationsUpdated;
transmogOutfitSituationsUpdated.TransmogOutfitID = transmogOutfitUpdateSituations.OutfitID;
transmogOutfitSituationsUpdated.SituationsEnabled = transmogOutfitUpdateSituations.SituationsEnabled;
transmogOutfitSituationsUpdated.Situations = transmogOutfitUpdateSituations.Situations;
SendPacket(transmogOutfitSituationsUpdated.Write());
}
void WorldSession::HandleTransmogOutfitUpdateSlots(WorldPackets::Transmogrification::TransmogOutfitUpdateSlots const& transmogOutfitUpdateSlots)
{
if (!_player->GetNPCIfCanInteractWith(transmogOutfitUpdateSlots.Npc, UNIT_NPC_FLAG_TRANSMOGRIFIER, UNIT_NPC_FLAG_2_NONE))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitNew - {} not found or player can't interact with it.",
GetPlayerInfo(), transmogOutfitUpdateSlots.Npc);
return;
}
_player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
UF::TransmogOutfitData const* transmogOutfit = _player->m_activePlayerData->TransmogOutfits.Get(transmogOutfitUpdateSlots.OutfitID);
if (!transmogOutfit)
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - player does not have outfit {}.",
GetPlayerInfo(), transmogOutfitUpdateSlots.OutfitID);
return;
}
if (!TransmogMgr::ValidateSlots(transmogOutfitUpdateSlots.Slots))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - player sent invalid slots.",
GetPlayerInfo());
return;
}
std::vector<uint32> bindAppearances;
for (WorldPackets::Transmogrification::TransmogOutfitSlotData const& slot : transmogOutfitUpdateSlots.Slots)
{
if (slot.ItemModifiedAppearanceID)
{
auto [hasAppearance, isTemporary] = GetCollectionMgr()->HasItemAppearance(slot.ItemModifiedAppearanceID);
if (!hasAppearance)
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - player does not have appearance {} in collection.",
GetPlayerInfo(), slot.ItemModifiedAppearanceID);
return;
}
if (isTemporary)
bindAppearances.push_back(slot.ItemModifiedAppearanceID);
}
if (slot.SpellItemEnchantmentID && !GetCollectionMgr()->HasTransmogIllusion(TransmogMgr::GetTransmogIllusionForSpellItemEnchantment(slot.SpellItemEnchantmentID)->ID))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - player does not have enchant {} in illusion collection.",
GetPlayerInfo(), slot.SpellItemEnchantmentID);
return;
}
}
if (transmogOutfitUpdateSlots.UseAvailableDiscount && _player->HasPlayerLocalFlag(PLAYER_LOCAL_FLAG_FREE_TRANSMOG_CLAIMED))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - player has already claimed free transmog before.",
GetPlayerInfo());
return;
}
// calculate cost
float baseCost = 0;
if (uint32 curveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::TransmogCost))
baseCost = sDB2Manager.GetCurveValueAt(curveId, std::max<int32>(_player->GetLevel(), _player->m_activePlayerData->MaxLevel));
float costMultiplier = 1.0f;
TransmogOutfitEntryEntry const* transmogOutfitEntry = sTransmogOutfitEntryStore.AssertEntry(transmogOutfitUpdateSlots.OutfitID);
if (transmogOutfitEntry->HasFlag(TransmogOutfitEntryFlags::UseOverrideCostModifier))
costMultiplier *= transmogOutfitEntry->OverrideCostModifier;
if (_player->HasAuraType(SPELL_AURA_MOD_TRANSMOG_OUTFIT_UPDATE_COST))
costMultiplier *= _player->m_activePlayerData->TransmogMetadata->CostMod;
if (sChrRacesStore.AssertEntry(_player->GetRace())->GetFlags().HasFlag(ChrRacesFlag::VoidVendorDiscount))
costMultiplier *= 0.5f;
uint64 cost = 0;
if (!transmogOutfitUpdateSlots.UseAvailableDiscount)
{
auto oldSlotItr = transmogOutfit->Slots.begin();
auto oldSlotEnd = transmogOutfit->Slots.end();
for (WorldPackets::Transmogrification::TransmogOutfitSlotData const& slot : transmogOutfitUpdateSlots.Slots)
{
oldSlotItr = std::ranges::find(oldSlotItr, oldSlotEnd,
std::pair(AsUnderlyingType(slot.Slot), AsUnderlyingType(slot.SlotOption)),
[](UF::TransmogOutfitSlotData const& slotData) { return std::pair(*slotData.Slot, *slotData.SlotOption); });
auto [slotEntry, slotOptionEntry, _] = *TransmogMgr::GetSlotAndOption(slot.Slot, slot.SlotOption);
if (slot.AppearanceDisplayType == TransmogOutfitDisplayType::Assigned && oldSlotItr->ItemModifiedAppearanceID != slot.ItemModifiedAppearanceID)
{
if (slotEntry)
cost = static_cast<uint64>(std::floor(baseCost * slotEntry->ItemCostMultiplier)) + cost;
if (slotOptionEntry)
cost = static_cast<uint64>(std::floor(baseCost * slotOptionEntry->ItemCostMultiplier)) + cost;
}
if (slot.IllusionDisplayType == TransmogOutfitDisplayType::Assigned && oldSlotItr->SpellItemEnchantmentID != slot.SpellItemEnchantmentID)
{
if (slotEntry)
cost = static_cast<uint64>(std::floor(baseCost * slotEntry->IllusionCostMultiplier)) + cost;
if (slotOptionEntry)
cost = static_cast<uint64>(std::floor(baseCost * slotOptionEntry->IllusionCostMultiplier)) + cost;
}
++oldSlotItr;
}
cost = static_cast<uint64>(std::clamp(costMultiplier, 0.0f, 1.0f) * cost);
if (cost != transmogOutfitUpdateSlots.Cost)
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - player sent invalid cost {}.",
GetPlayerInfo(), transmogOutfitUpdateSlots.Cost);
return;
}
if (!_player->HasEnoughMoney(cost))
{
TC_LOG_ERROR("entities.player.cheat", "{} WorldSession::HandleTransmogOutfitUpdateSlots - not enough money.",
GetPlayerInfo());
return;
}
}
else
{
_player->SetPlayerLocalFlag(PLAYER_LOCAL_FLAG_FREE_TRANSMOG_CLAIMED);
_player->SetHasClaimedFreeTransmog();
}
_player->ModifyMoney(-int64(cost));
_player->UpdateTransmogOutfitSlots(transmogOutfitUpdateSlots.OutfitID, transmogOutfitUpdateSlots.Slots);
if (transmogOutfitUpdateSlots.OutfitID == _player->m_activePlayerData->TransmogMetadata->TransmogOutfitID)
_player->EquipTransmogOutfit(transmogOutfitUpdateSlots.OutfitID, TransmogSituationTrigger::TransmogUpdate, {});
WorldPackets::Transmogrification::TransmogOutfitSlotsUpdated transmogOutfitSlotsUpdated;
transmogOutfitSlotsUpdated.TransmogOutfitID = transmogOutfitUpdateSlots.OutfitID;
transmogOutfitSlotsUpdated.Slots = transmogOutfitUpdateSlots.Slots;
SendPacket(transmogOutfitSlotsUpdated.Write());
for (uint32 itemModifedAppearanceId : bindAppearances)
{
std::unordered_set<ObjectGuid> itemsProvidingAppearance = GetCollectionMgr()->GetItemsProvidingTemporaryAppearance(itemModifedAppearanceId);
for (ObjectGuid const& itemGuid : itemsProvidingAppearance)
{
if (Item* item = _player->GetItemByGuid(itemGuid))
{
item->SetNotRefundable(_player);
item->ClearSoulboundTradeable(_player);
GetCollectionMgr()->AddItemAppearance(item);
}
}
}
}
void WorldSession::SendOpenTransmogrifier(ObjectGuid const& guid) void WorldSession::SendOpenTransmogrifier(ObjectGuid const& guid)
{ {
WorldPackets::NPC::NPCInteractionOpenResult npcInteraction; WorldPackets::NPC::NPCInteractionOpenResult npcInteraction;
@@ -37,9 +37,164 @@ void TransmogrifyItems::Read()
for (TransmogrifyItem& item : Items) for (TransmogrifyItem& item : Items)
_worldPacket >> item; _worldPacket >> item;
_worldPacket.ResetBitPos();
_worldPacket >> Bits<1>(CurrentSpecOnly); _worldPacket >> Bits<1>(CurrentSpecOnly);
} }
ByteBuffer& operator>>(ByteBuffer& data, TransmogOutfitDataInfo& transmogOutfitDataInfo)
{
data.ResetBitPos();
data >> As<uint8>(transmogOutfitDataInfo.SetType);
data >> transmogOutfitDataInfo.Icon;
data >> SizedString::BitsSize<8>(transmogOutfitDataInfo.Name);
data >> Bits<1>(transmogOutfitDataInfo.SituationsEnabled);
data >> SizedString::Data(transmogOutfitDataInfo.Name);
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, TransmogOutfitDataInfo const& transmogOutfitDataInfo)
{
data << As<uint8>(transmogOutfitDataInfo.SetType);
data << uint32(transmogOutfitDataInfo.Icon);
data << SizedString::BitsSize<8>(transmogOutfitDataInfo.Name);
data << Bits<1>(transmogOutfitDataInfo.SituationsEnabled);
data.FlushBits();
data << SizedString::Data(transmogOutfitDataInfo.Name);
return data;
}
void TransmogOutfitNew::Read()
{
_worldPacket >> Npc;
_worldPacket >> As<uint8>(Source);
_worldPacket >> Info;
}
WorldPacket const* TransmogOutfitNewEntryAdded::Write()
{
_worldPacket << uint32(TransmogOutfitID);
return &_worldPacket;
}
void TransmogOutfitUpdateInfo::Read()
{
_worldPacket >> OutfitID;
_worldPacket >> Npc;
_worldPacket >> Info;
}
WorldPacket const* TransmogOutfitInfoUpdated::Write()
{
_worldPacket << uint32(TransmogOutfitID);
_worldPacket << *OutfitInfo;
return &_worldPacket;
}
ByteBuffer& operator>>(ByteBuffer& data, TransmogOutfitSituationInfo& transmogOutfitSituationInfo)
{
data >> transmogOutfitSituationInfo.SituationID;
data >> transmogOutfitSituationInfo.SpecID;
data >> transmogOutfitSituationInfo.LoadoutID;
data >> transmogOutfitSituationInfo.EquipmentSetID;
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, TransmogOutfitSituationInfo const& transmogOutfitSituationInfo)
{
data << uint32(transmogOutfitSituationInfo.SituationID);
data << uint32(transmogOutfitSituationInfo.SpecID);
data << uint32(transmogOutfitSituationInfo.LoadoutID);
data << uint32(transmogOutfitSituationInfo.EquipmentSetID);
return data;
}
void TransmogOutfitUpdateSituations::Read()
{
_worldPacket >> OutfitID;
_worldPacket >> Npc;
_worldPacket >> Size<uint32>(Situations);
for (TransmogOutfitSituationInfo& situation : Situations)
_worldPacket >> situation;
_worldPacket.ResetBitPos();
_worldPacket >> Bits<1>(SituationsEnabled);
}
WorldPacket const* TransmogOutfitSituationsUpdated::Write()
{
_worldPacket << uint32(TransmogOutfitID);
_worldPacket << Size<uint32>(Situations);
for (TransmogOutfitSituationInfo const& situation : Situations)
_worldPacket << situation;
_worldPacket << Bits<1>(SituationsEnabled);
_worldPacket.FlushBits();
return &_worldPacket;
}
ByteBuffer& operator>>(ByteBuffer& data, TransmogOutfitSlotData& transmogOutfitSlotData)
{
data >> As<int8>(transmogOutfitSlotData.Slot);
data >> As<uint8>(transmogOutfitSlotData.SlotOption);
data >> transmogOutfitSlotData.ItemModifiedAppearanceID;
data >> As<uint8>(transmogOutfitSlotData.AppearanceDisplayType);
data >> transmogOutfitSlotData.SpellItemEnchantmentID;
data >> As<uint8>(transmogOutfitSlotData.IllusionDisplayType);
data >> transmogOutfitSlotData.Flags;
return data;
}
ByteBuffer& operator<<(ByteBuffer& data, TransmogOutfitSlotData const& transmogOutfitSlotData)
{
data << As<int8>(transmogOutfitSlotData.Slot);
data << As<uint8>(transmogOutfitSlotData.SlotOption);
data << uint32(transmogOutfitSlotData.ItemModifiedAppearanceID);
data << As<uint8>(transmogOutfitSlotData.AppearanceDisplayType);
data << uint32(transmogOutfitSlotData.SpellItemEnchantmentID);
data << As<uint8>(transmogOutfitSlotData.IllusionDisplayType);
data << uint32(transmogOutfitSlotData.Flags);
return data;
}
void TransmogOutfitUpdateSlots::Read()
{
_worldPacket >> OutfitID;
_worldPacket >> Size<uint32>(Slots);
_worldPacket >> Npc;
_worldPacket >> Cost;
for (TransmogOutfitSlotData& slot : Slots)
_worldPacket >> slot;
_worldPacket.ResetBitPos();
_worldPacket >> Bits<1>(UseAvailableDiscount);
std::ranges::sort(Slots, std::ranges::less(), [](TransmogOutfitSlotData const& slot) { return std::pair(slot.Slot, slot.SlotOption); });
}
WorldPacket const* TransmogOutfitSlotsUpdated::Write()
{
_worldPacket << uint32(TransmogOutfitID);
_worldPacket << Size<uint32>(Slots);
for (TransmogOutfitSlotData const& slot : Slots)
_worldPacket << slot;
return &_worldPacket;
}
WorldPacket const* AccountTransmogUpdate::Write() WorldPacket const* AccountTransmogUpdate::Write()
{ {
_worldPacket << Bits<1>(IsFullUpdate); _worldPacket << Bits<1>(IsFullUpdate);
@@ -22,6 +22,12 @@
#include "ObjectGuid.h" #include "ObjectGuid.h"
#include "PacketUtilities.h" #include "PacketUtilities.h"
enum class TransmogOutfitDisplayType : uint8;
enum class TransmogOutfitEntrySource : uint8;
enum class TransmogOutfitSetType : uint8;
enum class TransmogOutfitSlot : int8;
enum class TransmogOutfitSlotOption : uint8;
namespace WorldPackets namespace WorldPackets
{ {
namespace Transmogrification namespace Transmogrification
@@ -51,6 +57,128 @@ namespace WorldPackets
bool CurrentSpecOnly = false; bool CurrentSpecOnly = false;
}; };
struct TransmogOutfitDataInfo
{
TransmogOutfitSetType SetType = { };
bool SituationsEnabled = false;
uint32 Icon = 0;
std::string_view Name;
};
class TransmogOutfitNew final : public ClientPacket
{
public:
explicit TransmogOutfitNew(WorldPacket&& packet) : ClientPacket(CMSG_TRANSMOG_OUTFIT_NEW, std::move(packet)) { }
void Read() override;
ObjectGuid Npc;
TransmogOutfitDataInfo Info;
TransmogOutfitEntrySource Source = { };
};
class TransmogOutfitNewEntryAdded final : public ServerPacket
{
public:
explicit TransmogOutfitNewEntryAdded() : ServerPacket(SMSG_TRANSMOG_OUTFIT_NEW_ENTRY_ADDED, 4) { }
WorldPacket const* Write() override;
uint32 TransmogOutfitID = 0;
};
class TransmogOutfitUpdateInfo final : public ClientPacket
{
public:
explicit TransmogOutfitUpdateInfo(WorldPacket&& packet) : ClientPacket(CMSG_TRANSMOG_OUTFIT_UPDATE_INFO, std::move(packet)) { }
void Read() override;
uint32 OutfitID = 0;
ObjectGuid Npc;
TransmogOutfitDataInfo Info;
};
class TransmogOutfitInfoUpdated final : public ServerPacket
{
public:
explicit TransmogOutfitInfoUpdated() : ServerPacket(SMSG_TRANSMOG_OUTFIT_INFO_UPDATED, 4 + 1 + 4 + 1 + 1 + 128) { }
WorldPacket const* Write() override;
uint32 TransmogOutfitID = 0;
TransmogOutfitDataInfo const* OutfitInfo = nullptr;
};
struct TransmogOutfitSituationInfo
{
uint32 SituationID = 0;
uint32 SpecID = 0;
uint32 LoadoutID = 0;
uint32 EquipmentSetID = 0;
};
class TransmogOutfitUpdateSituations final : public ClientPacket
{
public:
explicit TransmogOutfitUpdateSituations(WorldPacket&& packet) : ClientPacket(CMSG_TRANSMOG_OUTFIT_UPDATE_SITUATIONS, std::move(packet)) { }
void Read() override;
uint32 OutfitID = 0;
ObjectGuid Npc;
bool SituationsEnabled = false;
Array<TransmogOutfitSituationInfo, 100> Situations;
};
class TransmogOutfitSituationsUpdated final : public ServerPacket
{
public:
explicit TransmogOutfitSituationsUpdated() : ServerPacket(SMSG_TRANSMOG_OUTFIT_SITUATIONS_UPDATED, 4 + 4 + 10 * (4 + 4 + 4 + 4) + 1) { }
WorldPacket const* Write() override;
uint32 TransmogOutfitID = 0;
bool SituationsEnabled = false;
std::span<TransmogOutfitSituationInfo const> Situations;
};
struct TransmogOutfitSlotData
{
TransmogOutfitSlot Slot = { };
TransmogOutfitSlotOption SlotOption = { };
TransmogOutfitDisplayType AppearanceDisplayType = { };
TransmogOutfitDisplayType IllusionDisplayType = { };
uint32 ItemModifiedAppearanceID = 0;
uint32 SpellItemEnchantmentID = 0;
uint32 Flags = 0;
};
class TransmogOutfitUpdateSlots final : public ClientPacket
{
public:
explicit TransmogOutfitUpdateSlots(WorldPacket&& packet) : ClientPacket(CMSG_TRANSMOG_OUTFIT_UPDATE_SLOTS, std::move(packet)) { }
void Read() override;
uint32 OutfitID = 0;
Array<TransmogOutfitSlotData, 30> Slots;
ObjectGuid Npc;
uint64 Cost = 0;
bool UseAvailableDiscount = false;
};
class TransmogOutfitSlotsUpdated final : public ServerPacket
{
public:
explicit TransmogOutfitSlotsUpdated() : ServerPacket(SMSG_TRANSMOG_OUTFIT_SLOTS_UPDATED, 4 + 4 + 30 * (1 + 1 + 4 + 1 + 4 + 1 + 4)) { }
WorldPacket const* Write() override;
uint32 TransmogOutfitID = 0;
std::span<TransmogOutfitSlotData const> Slots;
};
class AccountTransmogUpdate final : public ServerPacket class AccountTransmogUpdate final : public ServerPacket
{ {
public: public:
+8 -8
View File
@@ -1105,10 +1105,10 @@ void OpcodeTable::InitializeClientOpcodes()
DEFINE_HANDLER(CMSG_TRAITS_TALENT_TEST_UNLEARN_SPELLS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRAITS_TALENT_TEST_UNLEARN_SPELLS, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_TRANSFER_CURRENCY_FROM_ACCOUNT_CHARACTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRANSFER_CURRENCY_FROM_ACCOUNT_CHARACTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_TRANSMOGRIFY_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogrifyItems); DEFINE_HANDLER(CMSG_TRANSMOGRIFY_ITEMS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogrifyItems);
DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_NEW, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_NEW, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogOutfitNew);
DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_UPDATE_INFO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_UPDATE_INFO, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogOutfitUpdateInfo);
DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_UPDATE_SITUATIONS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_UPDATE_SITUATIONS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogOutfitUpdateSituations);
DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_UPDATE_SLOTS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL); DEFINE_HANDLER(CMSG_TRANSMOG_OUTFIT_UPDATE_SLOTS, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTransmogOutfitUpdateSlots);
DEFINE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTurnInPetition); DEFINE_HANDLER(CMSG_TURN_IN_PETITION, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTurnInPetition);
DEFINE_HANDLER(CMSG_TUTORIAL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag); DEFINE_HANDLER(CMSG_TUTORIAL, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleTutorialFlag);
DEFINE_HANDLER(CMSG_UI_MAP_QUEST_LINES_REQUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUiMapQuestLinesRequest); DEFINE_HANDLER(CMSG_UI_MAP_QUEST_LINES_REQUEST, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleUiMapQuestLinesRequest);
@@ -2454,10 +2454,10 @@ void OpcodeTable::InitializeServerOpcodes()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAIT_CONFIG_COMMIT_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRAIT_CONFIG_COMMIT_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_ABORTED, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_PENDING, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSFER_PENDING, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_INFO_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_INFO_UPDATED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_NEW_ENTRY_ADDED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_NEW_ENTRY_ADDED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_SITUATIONS_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_SITUATIONS_UPDATED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_SLOTS_UPDATED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRANSMOG_OUTFIT_SLOTS_UPDATED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TREASURE_PICKER_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TREASURE_PICKER_RESPONSE, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TREASURE_PUNCH_LIST_ITEMS_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TREASURE_PUNCH_LIST_ITEMS_RESPONSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_CINEMATIC, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TRIGGER_CINEMATIC, STATUS_NEVER, CONNECTION_TYPE_REALM);
+7 -5
View File
@@ -1136,11 +1136,7 @@ bool WorldSession::IsAddonRegistered(std::string_view prefix) const
if (!_filterAddonMessages) // if we have hit the softcap (64) nothing should be filtered if (!_filterAddonMessages) // if we have hit the softcap (64) nothing should be filtered
return true; return true;
if (_registeredAddonPrefixes.empty()) return advstd::ranges::contains(_registeredAddonPrefixes, prefix);
return false;
std::vector<std::string>::const_iterator itr = std::find(_registeredAddonPrefixes.begin(), _registeredAddonPrefixes.end(), prefix);
return itr != _registeredAddonPrefixes.end();
} }
void WorldSession::HandleUnregisterAllAddonPrefixesOpcode(WorldPackets::Chat::ChatUnregisterAllAddonPrefixes& /*packet*/) // empty packet void WorldSession::HandleUnregisterAllAddonPrefixesOpcode(WorldPackets::Chat::ChatUnregisterAllAddonPrefixes& /*packet*/) // empty packet
@@ -1259,6 +1255,7 @@ public:
ITEM_APPEARANCES, ITEM_APPEARANCES,
ITEM_FAVORITE_APPEARANCES, ITEM_FAVORITE_APPEARANCES,
TRANSMOG_ILLUSIONS, TRANSMOG_ILLUSIONS,
TRANSMOG_OUTFITS,
WARBAND_SCENES, WARBAND_SCENES,
PLAYER_DATA_ELEMENTS_ACCOUNT, PLAYER_DATA_ELEMENTS_ACCOUNT,
PLAYER_DATA_FLAGS_ACCOUNT, PLAYER_DATA_FLAGS_ACCOUNT,
@@ -1309,6 +1306,10 @@ public:
stmt->setUInt32(0, battlenetAccountId); stmt->setUInt32(0, battlenetAccountId);
ok = SetPreparedQuery(TRANSMOG_ILLUSIONS, stmt) && ok; ok = SetPreparedQuery(TRANSMOG_ILLUSIONS, stmt) && ok;
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_TRANSMOG_OUTFITS);
stmt->setUInt32(0, battlenetAccountId);
ok = SetPreparedQuery(TRANSMOG_OUTFITS, stmt) && ok;
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_WARBAND_SCENES); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_WARBAND_SCENES);
stmt->setUInt32(0, battlenetAccountId); stmt->setUInt32(0, battlenetAccountId);
ok = SetPreparedQuery(WARBAND_SCENES, stmt) && ok; ok = SetPreparedQuery(WARBAND_SCENES, stmt) && ok;
@@ -1373,6 +1374,7 @@ void WorldSession::InitializeSessionCallback(LoginDatabaseQueryHolder const& hol
_collectionMgr->LoadAccountMounts(holder.GetPreparedResult(AccountInfoQueryHolder::MOUNTS)); _collectionMgr->LoadAccountMounts(holder.GetPreparedResult(AccountInfoQueryHolder::MOUNTS));
_collectionMgr->LoadAccountItemAppearances(holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_APPEARANCES), holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_FAVORITE_APPEARANCES)); _collectionMgr->LoadAccountItemAppearances(holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_APPEARANCES), holder.GetPreparedResult(AccountInfoQueryHolder::ITEM_FAVORITE_APPEARANCES));
_collectionMgr->LoadAccountTransmogIllusions(holder.GetPreparedResult(AccountInfoQueryHolder::TRANSMOG_ILLUSIONS)); _collectionMgr->LoadAccountTransmogIllusions(holder.GetPreparedResult(AccountInfoQueryHolder::TRANSMOG_ILLUSIONS));
_collectionMgr->LoadAccountTransmogOutfits(holder.GetPreparedResult(AccountInfoQueryHolder::TRANSMOG_OUTFITS));
_collectionMgr->LoadAccountWarbandScenes(holder.GetPreparedResult(AccountInfoQueryHolder::WARBAND_SCENES)); _collectionMgr->LoadAccountWarbandScenes(holder.GetPreparedResult(AccountInfoQueryHolder::WARBAND_SCENES));
LoadPlayerDataAccount(holder.GetPreparedResult(AccountInfoQueryHolder::PLAYER_DATA_ELEMENTS_ACCOUNT), holder.GetPreparedResult(AccountInfoQueryHolder::PLAYER_DATA_FLAGS_ACCOUNT)); LoadPlayerDataAccount(holder.GetPreparedResult(AccountInfoQueryHolder::PLAYER_DATA_ELEMENTS_ACCOUNT), holder.GetPreparedResult(AccountInfoQueryHolder::PLAYER_DATA_FLAGS_ACCOUNT));
+8
View File
@@ -819,6 +819,10 @@ namespace WorldPackets
namespace Transmogrification namespace Transmogrification
{ {
class TransmogrifyItems; class TransmogrifyItems;
class TransmogOutfitNew;
class TransmogOutfitUpdateInfo;
class TransmogOutfitUpdateSituations;
class TransmogOutfitUpdateSlots;
} }
namespace Vehicle namespace Vehicle
@@ -1790,6 +1794,10 @@ class TC_GAME_API WorldSession
// Transmogrification // Transmogrification
void HandleTransmogrifyItems(WorldPackets::Transmogrification::TransmogrifyItems& transmogrifyItems); void HandleTransmogrifyItems(WorldPackets::Transmogrification::TransmogrifyItems& transmogrifyItems);
void HandleTransmogOutfitNew(WorldPackets::Transmogrification::TransmogOutfitNew const& transmogOutfitNew);
void HandleTransmogOutfitUpdateInfo(WorldPackets::Transmogrification::TransmogOutfitUpdateInfo const& transmogOutfitUpdateInfo);
void HandleTransmogOutfitUpdateSituations(WorldPackets::Transmogrification::TransmogOutfitUpdateSituations const& transmogOutfitUpdateSituations);
void HandleTransmogOutfitUpdateSlots(WorldPackets::Transmogrification::TransmogOutfitUpdateSlots const& transmogOutfitUpdateSlots);
// Miscellaneous // Miscellaneous
void HandleSpellClick(WorldPackets::Spells::SpellClick& spellClick); void HandleSpellClick(WorldPackets::Spells::SpellClick& spellClick);
@@ -735,7 +735,7 @@ enum AuraType : uint32
SPELL_AURA_ADD_FLAT_PVP_MODIFIER_BY_SPELL_LABEL = 648, SPELL_AURA_ADD_FLAT_PVP_MODIFIER_BY_SPELL_LABEL = 648,
SPELL_AURA_ADD_PCT_PVP_MODIFIER_BY_SPELL_LABEL = 649, SPELL_AURA_ADD_PCT_PVP_MODIFIER_BY_SPELL_LABEL = 649,
SPELL_AURA_650 = 650, SPELL_AURA_650 = 650,
SPELL_AURA_651 = 651, SPELL_AURA_ENABLE_EVENT_TRANSMOG_OUTFIT = 651,
SPELL_AURA_652 = 652, SPELL_AURA_652 = 652,
SPELL_AURA_653 = 653, SPELL_AURA_653 = 653,
SPELL_AURA_654 = 654, SPELL_AURA_654 = 654,
@@ -720,7 +720,7 @@ NonDefaultConstructible<pAuraEffectHandler> AuraEffectHandler[TOTAL_AURAS]=
&AuraEffect::HandleNULL, //648 SPELL_AURA_ADD_FLAT_PVP_MODIFIER_BY_SPELL_LABEL &AuraEffect::HandleNULL, //648 SPELL_AURA_ADD_FLAT_PVP_MODIFIER_BY_SPELL_LABEL
&AuraEffect::HandleNULL, //649 SPELL_AURA_ADD_PCT_PVP_MODIFIER_BY_SPELL_LABEL &AuraEffect::HandleNULL, //649 SPELL_AURA_ADD_PCT_PVP_MODIFIER_BY_SPELL_LABEL
&AuraEffect::HandleNULL, //650 &AuraEffect::HandleNULL, //650
&AuraEffect::HandleNULL, //651 &AuraEffect::HandleNULL, //651 SPELL_AURA_ENABLE_EVENT_TRANSMOG_OUTFIT
&AuraEffect::HandleNULL, //652 &AuraEffect::HandleNULL, //652
&AuraEffect::HandleNULL, //653 &AuraEffect::HandleNULL, //653
&AuraEffect::HandleNULL, //654 &AuraEffect::HandleNULL, //654
+9 -2
View File
@@ -61,6 +61,7 @@
#include "TemporarySummon.h" #include "TemporarySummon.h"
#include "TradeData.h" #include "TradeData.h"
#include "TraitPackets.h" #include "TraitPackets.h"
#include "TransmogMgr.h"
#include "UniqueTrackablePtr.h" #include "UniqueTrackablePtr.h"
#include "Util.h" #include "Util.h"
#include "VMapFactory.h" #include "VMapFactory.h"
@@ -4973,7 +4974,10 @@ int32 Spell::GetSpellCastDataAmmo()
switch (itemEntry->SubclassID) switch (itemEntry->SubclassID)
{ {
case ITEM_SUBCLASS_WEAPON_THROWN: case ITEM_SUBCLASS_WEAPON_THROWN:
ammoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i)); if (ItemModifiedAppearanceEntry const* modifiedAppearance = TransmogMgr::GetItemModifiedAppearance(item_id, unitCaster->GetVirtualItemAppearanceMod(i)))
if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(modifiedAppearance->ItemAppearanceID))
ammoDisplayID = itemAppearance->ItemDisplayInfoID;
ammoInventoryType = itemEntry->InventoryType; ammoInventoryType = itemEntry->InventoryType;
break; break;
case ITEM_SUBCLASS_WEAPON_BOW: case ITEM_SUBCLASS_WEAPON_BOW:
@@ -4986,7 +4990,10 @@ int32 Spell::GetSpellCastDataAmmo()
ammoInventoryType = INVTYPE_AMMO; ammoInventoryType = INVTYPE_AMMO;
break; break;
default: default:
nonRangedAmmoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i)); if (ItemModifiedAppearanceEntry const* modifiedAppearance = TransmogMgr::GetItemModifiedAppearance(item_id, unitCaster->GetVirtualItemAppearanceMod(i)))
if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(modifiedAppearance->ItemAppearanceID))
nonRangedAmmoDisplayID = itemAppearance->ItemDisplayInfoID;
nonRangedAmmoInventoryType = itemEntry->InventoryType; nonRangedAmmoInventoryType = itemEntry->InventoryType;
break; break;
} }
+9
View File
@@ -464,6 +464,7 @@ class TC_GAME_API Spell
void EffectSetPlayerDataElementCharacter(); void EffectSetPlayerDataElementCharacter();
void EffectSetPlayerDataFlagAccount(); void EffectSetPlayerDataFlagAccount();
void EffectSetPlayerDataFlagCharacter(); void EffectSetPlayerDataFlagCharacter();
void EffectEquipTransmogOutfit();
typedef std::unordered_set<Aura*> UsedSpellMods; typedef std::unordered_set<Aura*> UsedSpellMods;
@@ -632,6 +633,14 @@ class TC_GAME_API Spell
// SPELL_EFFECT_UPGRADE_HEIRLOOM // SPELL_EFFECT_UPGRADE_HEIRLOOM
uint32 ItemId; uint32 ItemId;
// SPELL_EFFECT_EQUIP_TRANSMOG_OUTFIT
struct
{
uint32 EquipAction;
uint32 TransmogOutfitId;
uint32 SituationTrigger;
} EquipTransmogOutfit;
struct struct
{ {
uint32 Data[3]; uint32 Data[3];
+28 -1
View File
@@ -436,7 +436,7 @@ NonDefaultConstructible<SpellEffectHandlerFn> SpellEffectHandlers[TOTAL_SPELL_EF
&Spell::EffectNULL, //344 SPELL_EFFECT_344 &Spell::EffectNULL, //344 SPELL_EFFECT_344
&Spell::EffectNULL, //345 SPELL_EFFECT_ASSIST_ACTION &Spell::EffectNULL, //345 SPELL_EFFECT_ASSIST_ACTION
&Spell::EffectNULL, //346 SPELL_EFFECT_346 &Spell::EffectNULL, //346 SPELL_EFFECT_346
&Spell::EffectNULL, //347 SPELL_EFFECT_EQUIP_TRANSMOG_OUTFIT &Spell::EffectEquipTransmogOutfit, //347 SPELL_EFFECT_EQUIP_TRANSMOG_OUTFIT
&Spell::EffectNULL, //348 SPELL_EFFECT_GIVE_HOUSE_LEVEL &Spell::EffectNULL, //348 SPELL_EFFECT_GIVE_HOUSE_LEVEL
&Spell::EffectNULL, //349 SPELL_EFFECT_LEARN_HOUSE_ROOM &Spell::EffectNULL, //349 SPELL_EFFECT_LEARN_HOUSE_ROOM
&Spell::EffectNULL, //350 SPELL_EFFECT_LEARN_HOUSE_EXTERIOR_COMPONENT &Spell::EffectNULL, //350 SPELL_EFFECT_LEARN_HOUSE_EXTERIOR_COMPONENT
@@ -6338,3 +6338,30 @@ void Spell::EffectSetPlayerDataFlagCharacter()
target->SetDataFlagCharacter(effectInfo->MiscValue, damage != 0); target->SetDataFlagCharacter(effectInfo->MiscValue, damage != 0);
} }
void Spell::EffectEquipTransmogOutfit()
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
Player* target = Object::ToPlayer(unitTarget);
if (!target)
return;
Optional<bool> locked;
switch (static_cast<TransmogOutfitEquipAction>(m_misc.EquipTransmogOutfit.EquipAction))
{
case TransmogOutfitEquipAction::EquipAndLock:
case TransmogOutfitEquipAction::RemoveAndLock:
case TransmogOutfitEquipAction::Lock:
locked = true;
break;
case TransmogOutfitEquipAction::Unlock:
locked = false;
break;
default:
break;
}
target->EquipTransmogOutfit(m_misc.EquipTransmogOutfit.TransmogOutfitId, static_cast<TransmogSituationTrigger>(m_misc.EquipTransmogOutfit.SituationTrigger), locked);
}
+416
View File
@@ -0,0 +1,416 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TransmogMgr.h"
#include "DB2Stores.h"
#include "FlatSet.h"
#include "MapUtils.h"
#include "ObjectMgr.h"
#include "Player.h"
#include "TransmogrificationPackets.h"
#include "Util.h"
namespace
{
struct TransmogOutfitSlotOptionInfo
{
TransmogOutfitSlotOptionEntry const* Data = nullptr;
int32 SlotIndex = -1;
};
struct TransmogOutfitSlotInfo
{
TransmogOutfitSlotInfoEntry const* Data = nullptr;
std::variant<int32, std::unique_ptr<TransmogOutfitSlotOptionInfo[]>> SlotIndexOrOptions;
int32 GetSlotIndex(TransmogOutfitSlotOption slotOption) const
{
switch (SlotIndexOrOptions.index())
{
case 0:
return std::get<0>(SlotIndexOrOptions);
case 1:
return std::get<1>(SlotIndexOrOptions)[AsUnderlyingType(slotOption)].SlotIndex;
default:
return -1;
}
}
};
std::unordered_map<std::pair<uint32 /*itemId*/, uint32 /*appearanceMod*/>, ItemModifiedAppearanceEntry const*> ItemModifiedAppearancesByItem;
std::unordered_map<uint32, TransmogIllusionEntry const*> TransmogIllusionBySpellItemEnchantment;
std::unordered_map<uint32, Trinity::Containers::FlatSet<TransmogSetEntry const*>> TransmogSetsByItemModifiedAppearance;
std::vector<TransmogSetItemEntry const*> TransmogSetItemsByTransmogSet;
std::array<std::vector<TransmogOutfitEntryEntry const*>, AsUnderlyingType(TransmogOutfitEntrySource::Max)> TransmogOutfitsBySource;
std::vector<TransmogOutfitEntryEntry const*> TransmogOutfitsAutomaticallyCreated;
std::vector<TransmogMgr::TransmogOutfitSlotAndOptionInfo> AllSlots;
std::array<TransmogOutfitSlotInfo, AsUnderlyingType(TransmogOutfitSlot::Max)> SlotInfoByOutfitSlot;
std::array<TransmogOutfitSlotInfo const*, EQUIPMENT_SLOT_END> SlotInfoByInvSlot;
std::vector<TransmogSituationEntry const*> DefaultSituations;
constexpr bool IsArtifactTransmogOutfitSlotOption(TransmogOutfitSlotOption option)
{
return option == TransmogOutfitSlotOption::ArtifactSpecOne
|| option == TransmogOutfitSlotOption::ArtifactSpecTwo
|| option == TransmogOutfitSlotOption::ArtifactSpecThree
|| option == TransmogOutfitSlotOption::ArtifactSpecFour;
}
bool IsValidTransmogOutfitSlotForItem(ItemTemplate const* item, TransmogOutfitSlot slot, TransmogOutfitSlotOption option)
{
if (IsArtifactTransmogOutfitSlotOption(option))
if (ArtifactEntry const* artifact = sArtifactStore.LookupEntry(item->GetArtifactID()))
if (ChrSpecializationEntry const* specialization = sChrSpecializationStore.LookupEntry(artifact->ChrSpecializationID))
if ((int8(option) - int8(TransmogOutfitSlotOption::ArtifactSpecOne)) != specialization->OrderIndex)
return false;
switch (item->GetInventoryType())
{
case INVTYPE_HEAD:
return slot == TransmogOutfitSlot::Head;
case INVTYPE_SHOULDERS:
return slot == TransmogOutfitSlot::ShoulderLeft || slot == TransmogOutfitSlot::ShoulderRight;
case INVTYPE_BODY:
return slot == TransmogOutfitSlot::Body;
case INVTYPE_CHEST:
case INVTYPE_ROBE:
return slot == TransmogOutfitSlot::Chest;
case INVTYPE_WAIST:
return slot == TransmogOutfitSlot::Waist;
case INVTYPE_LEGS:
return slot == TransmogOutfitSlot::Legs;
case INVTYPE_FEET:
return slot == TransmogOutfitSlot::Feet;
case INVTYPE_WRISTS:
return slot == TransmogOutfitSlot::Wrist;
case INVTYPE_HANDS:
return slot == TransmogOutfitSlot::Hand;
case INVTYPE_WEAPON:
case INVTYPE_WEAPONMAINHAND:
case INVTYPE_WEAPONOFFHAND:
return slot == TransmogOutfitSlot::WeaponMainHand || slot == TransmogOutfitSlot::WeaponOffHand || IsArtifactTransmogOutfitSlotOption(option);
case INVTYPE_SHIELD:
case INVTYPE_HOLDABLE:
return slot == TransmogOutfitSlot::WeaponOffHand || IsArtifactTransmogOutfitSlotOption(option);
case INVTYPE_RANGED:
return (slot == TransmogOutfitSlot::WeaponMainHand && option == TransmogOutfitSlotOption::RangedWeapon) || IsArtifactTransmogOutfitSlotOption(option);
case INVTYPE_CLOAK:
return slot == TransmogOutfitSlot::Back;
case INVTYPE_2HWEAPON:
return slot == TransmogOutfitSlot::WeaponMainHand || (slot == TransmogOutfitSlot::WeaponOffHand && option == TransmogOutfitSlotOption::FuryTwoHandedWeapon) || IsArtifactTransmogOutfitSlotOption(option);
case INVTYPE_TABARD:
return slot == TransmogOutfitSlot::Tabard;
case INVTYPE_RANGEDRIGHT:
return slot == (item->GetSubClass() == ITEM_SUBCLASS_WEAPON_WAND ? TransmogOutfitSlot::WeaponMainHand : TransmogOutfitSlot::WeaponRanged) || IsArtifactTransmogOutfitSlotOption(option);
default:
break;
}
return false;
}
}
void TransmogMgr::Load()
{
for (ItemModifiedAppearanceEntry const* appearanceMod : sItemModifiedAppearanceStore)
ItemModifiedAppearancesByItem[{ appearanceMod->ItemID, appearanceMod->ItemAppearanceModifierID }] = appearanceMod;
for (TransmogIllusionEntry const* transmogIllusion : sTransmogIllusionStore)
TransmogIllusionBySpellItemEnchantment[transmogIllusion->SpellItemEnchantmentID] = transmogIllusion;
for (TransmogSetItemEntry const* transmogSetItem : sTransmogSetItemStore)
{
TransmogSetEntry const* set = sTransmogSetStore.LookupEntry(transmogSetItem->TransmogSetID);
if (!set)
continue;
TransmogSetsByItemModifiedAppearance[transmogSetItem->ItemModifiedAppearanceID].insert(set);
TransmogSetItemsByTransmogSet.push_back(transmogSetItem);
}
std::ranges::sort(TransmogSetItemsByTransmogSet, {}, &TransmogSetItemEntry::TransmogSetID);
for (TransmogOutfitEntryEntry const* transmogOutfitEntry : sTransmogOutfitEntryStore)
{
if (transmogOutfitEntry->HasFlag(TransmogOutfitEntryFlags::AutomaticallyAwardedOnLogin))
TransmogOutfitsAutomaticallyCreated.push_back(transmogOutfitEntry);
if (transmogOutfitEntry->GetSetType() == TransmogOutfitSetType::Outfit)
TransmogOutfitsBySource[AsUnderlyingType(transmogOutfitEntry->GetSource())].push_back(transmogOutfitEntry);
}
for (std::vector<TransmogOutfitEntryEntry const*>& transmogOutfitEntries : TransmogOutfitsBySource)
std::ranges::sort(transmogOutfitEntries, {}, &TransmogOutfitEntryEntry::OrderIndex);
for (TransmogOutfitSlotInfoEntry const* transmogOutfitSlot : sTransmogOutfitSlotInfoStore)
{
ASSERT(transmogOutfitSlot->GetSlot() < TransmogOutfitSlot::Max);
TransmogOutfitSlotInfo* slot = &SlotInfoByOutfitSlot[AsUnderlyingType(transmogOutfitSlot->GetSlot())];
slot->Data = transmogOutfitSlot;
if (!transmogOutfitSlot->HasFlag(TransmogOutfitSlotFlags::IsSecondarySlot))
{
ASSERT(transmogOutfitSlot->InventorySlotEnum < EQUIPMENT_SLOT_END);
SlotInfoByInvSlot[transmogOutfitSlot->InventorySlotEnum] = slot;
}
}
for (TransmogOutfitSlotOptionEntry const* transmogOutfitSlotOption : sTransmogOutfitSlotOptionInfoStore)
{
ASSERT(transmogOutfitSlotOption->GetOption() < TransmogOutfitSlotOption::Max);
TransmogOutfitSlotInfoEntry const* transmogOutfitSlot = sTransmogOutfitSlotInfoStore.AssertEntry(transmogOutfitSlotOption->TransmogOutfitSlotInfoID);
TransmogOutfitSlotInfo& slotInfo = SlotInfoByOutfitSlot[AsUnderlyingType(transmogOutfitSlot->GetSlot())];
if (!std::holds_alternative<std::unique_ptr<TransmogOutfitSlotOptionInfo[]>>(slotInfo.SlotIndexOrOptions))
slotInfo.SlotIndexOrOptions.emplace<std::unique_ptr<TransmogOutfitSlotOptionInfo[]>>(new TransmogOutfitSlotOptionInfo[AsUnderlyingType(TransmogOutfitSlotOption::Max)]);
std::get<std::unique_ptr<TransmogOutfitSlotOptionInfo[]>>(slotInfo.SlotIndexOrOptions)[AsUnderlyingType(transmogOutfitSlotOption->GetOption())].Data = transmogOutfitSlotOption;
}
for (TransmogOutfitSlotInfo& slotInfo : SlotInfoByOutfitSlot)
{
if (!slotInfo.Data)
continue;
TransmogOutfitSlotAndOptionInfo& slot = AllSlots.emplace_back();
slot.Slot = slotInfo.Data;
slot.SlotIndex = AllSlots.size() - 1;
if (std::holds_alternative<std::unique_ptr<TransmogOutfitSlotOptionInfo[]>>(slotInfo.SlotIndexOrOptions))
{
// if slot has options, keep adding transmog slots for every option
auto options = std::span<TransmogOutfitSlotOptionInfo, AsUnderlyingType(TransmogOutfitSlotOption::Max)>(
&std::get<std::unique_ptr<TransmogOutfitSlotOptionInfo[]>>(slotInfo.SlotIndexOrOptions)[0],
AsUnderlyingType(TransmogOutfitSlotOption::Max));
auto optionItr = std::ranges::find_if(options,
[](TransmogOutfitSlotOptionEntry const* option) { return option != nullptr; },
&TransmogOutfitSlotOptionInfo::Data);
slot.SlotOption = optionItr->Data;
optionItr->SlotIndex = AllSlots.size() - 1;
while (++optionItr != options.end())
{
if (!optionItr->Data)
continue;
TransmogOutfitSlotAndOptionInfo& newSlot = AllSlots.emplace_back();
newSlot.Slot = slotInfo.Data;
newSlot.SlotOption = optionItr->Data;
newSlot.SlotIndex = AllSlots.size() - 1;
optionItr->SlotIndex = AllSlots.size() - 1;
}
}
if (std::holds_alternative<int32>(slotInfo.SlotIndexOrOptions))
std::get<int32>(slotInfo.SlotIndexOrOptions) = AllSlots.size() - 1;
}
for (TransmogSituationEntry const* transmogSituation : sTransmogSituationStore)
if (transmogSituation->HasFlag(TransmogSituationFlags::DefaultsToOn))
DefaultSituations.push_back(transmogSituation);
}
ItemModifiedAppearanceEntry const* TransmogMgr::GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId)
{
auto itr = ItemModifiedAppearancesByItem.find({ itemId, appearanceModId });
if (itr != ItemModifiedAppearancesByItem.end())
return itr->second;
// Fall back to unmodified appearance
if (appearanceModId)
return GetDefaultItemModifiedAppearance(itemId);
return nullptr;
}
ItemModifiedAppearanceEntry const* TransmogMgr::GetDefaultItemModifiedAppearance(uint32 itemId)
{
return Trinity::Containers::MapGetValuePtr(ItemModifiedAppearancesByItem, { itemId, 0 });
}
TransmogIllusionEntry const* TransmogMgr::GetTransmogIllusionForSpellItemEnchantment(uint32 spellItemEnchantmentId)
{
return Trinity::Containers::MapGetValuePtr(TransmogIllusionBySpellItemEnchantment, spellItemEnchantmentId);
}
std::span<TransmogSetEntry const* const> TransmogMgr::GetTransmogSetsForItemModifiedAppearance(uint32 itemModifiedAppearanceId)
{
std::span<TransmogSetEntry const* const> result;
auto itr = TransmogSetsByItemModifiedAppearance.find(itemModifiedAppearanceId);
if (itr != TransmogSetsByItemModifiedAppearance.end())
result = itr->second;
return result;
}
std::span<TransmogSetItemEntry const* const> TransmogMgr::GetTransmogSetItems(uint32 transmogSetId)
{
return std::ranges::equal_range(TransmogSetItemsByTransmogSet, transmogSetId, {}, &TransmogSetItemEntry::TransmogSetID);
}
std::span<TransmogOutfitEntryEntry const* const> TransmogMgr::GetAutomaticallyUnlockedOutfits()
{
return TransmogOutfitsAutomaticallyCreated;
}
std::span<TransmogMgr::TransmogOutfitSlotAndOptionInfo const> TransmogMgr::GetAllSlots()
{
return AllSlots;
}
TransmogMgr::TransmogOutfitSlotAndOptionInfo const* TransmogMgr::GetSlotAndOption(TransmogOutfitSlot slot, TransmogOutfitSlotOption slotOption)
{
int32 slotIndex = SlotInfoByOutfitSlot[AsUnderlyingType(slot)].GetSlotIndex(slotOption);
if (slotIndex >= 0)
return &AllSlots[slotIndex];
return nullptr;
}
TransmogMgr::TransmogOutfitSlotAndOptionInfo const* TransmogMgr::GetSlotAndOption(EquipmentSlots inventorySlot, TransmogOutfitSlotOption slotOption)
{
if (TransmogOutfitSlotInfo const* slotInfo = SlotInfoByInvSlot[inventorySlot])
if (int32 slotIndex = slotInfo->GetSlotIndex(slotOption); slotIndex >= 0)
return &AllSlots[slotIndex];
return nullptr;
}
std::span<TransmogSituationEntry const* const> TransmogMgr::GetDefaultSituations()
{
return DefaultSituations;
}
TransmogOutfitEntryEntry const* TransmogMgr::GetNextOutfitToUnlock(TransmogOutfitEntrySource source, Player const* player)
{
if (source >= TransmogOutfitEntrySource::Max)
return nullptr;
TransmogOutfitEntryEntry const* lastOwnedOutfit = nullptr;
for (auto const& [id, transmogOutfit] : player->m_activePlayerData->TransmogOutfits)
{
TransmogOutfitEntryEntry const* transmogOutfitEntry = sTransmogOutfitEntryStore.LookupEntry(transmogOutfit.value.Id);
if (!transmogOutfitEntry || transmogOutfitEntry->GetSource() != source)
continue;
if (!lastOwnedOutfit || transmogOutfitEntry->OrderIndex > lastOwnedOutfit->OrderIndex)
lastOwnedOutfit = transmogOutfitEntry;
}
if (!lastOwnedOutfit)
return TransmogOutfitsBySource[AsUnderlyingType(source)].front();
auto itr = std::ranges::find(TransmogOutfitsBySource[AsUnderlyingType(source)], lastOwnedOutfit) + 1;
if (itr != TransmogOutfitsBySource[AsUnderlyingType(source)].end())
return *itr;
return nullptr;
}
bool TransmogMgr::ValidateSituations(std::span<WorldPackets::Transmogrification::TransmogOutfitSituationInfo const> situations)
{
struct SituationTriggerStatus
{
uint8 AllSituationCount = 0;
uint8 NoneSituationCount = 0;
uint8 RegularSituationCount = 0;
};
std::array<SituationTriggerStatus, AsUnderlyingType(TransmogSituationTrigger::Max)> statusByTrigger;
for (WorldPackets::Transmogrification::TransmogOutfitSituationInfo const& situation : situations)
{
TransmogSituationEntry const* transmogSituation = sTransmogSituationStore.LookupEntry(situation.SituationID);
if (!transmogSituation)
return false;
TransmogSituationGroupEntry const* transmogSituationGroup = sTransmogSituationGroupStore.LookupEntry(transmogSituation->TransmogSituationGroupID);
if (!transmogSituationGroup)
return false;
TransmogSituationTriggerEntry const* transmogSituationTrigger = sTransmogSituationTriggerStore.LookupEntry(transmogSituationGroup->TransmogSituationTriggerID);
if (!transmogSituationTrigger)
return false;
SituationTriggerStatus& triggers = statusByTrigger[AsUnderlyingType(transmogSituationTrigger->GetTrigger())];
uint8* count = nullptr;
if (transmogSituation->HasFlag(TransmogSituationFlags::AllSituation))
count = &triggers.AllSituationCount;
else if (transmogSituation->HasFlag(TransmogSituationFlags::NoneSituation))
count = &triggers.NoneSituationCount;
else
count = &triggers.RegularSituationCount;
*count += 1;
if (transmogSituationTrigger->HasFlag(TransmogSituationTriggerFlags::SituationsAreExclusive) && *count > 1)
return false;
}
for (SituationTriggerStatus const& triggers : statusByTrigger)
if ((triggers.AllSituationCount > 0) + (triggers.NoneSituationCount > 0) + (triggers.RegularSituationCount > 0) > 1) // only 1 group can be active
return false;
return true;
}
bool TransmogMgr::ValidateSlots(std::span<WorldPackets::Transmogrification::TransmogOutfitSlotData const> slots)
{
for (WorldPackets::Transmogrification::TransmogOutfitSlotData const& slot : slots)
{
if (slot.Slot >= TransmogOutfitSlot::Max)
return false;
if (slot.SlotOption >= TransmogOutfitSlotOption::Max)
return false;
if (slot.AppearanceDisplayType >= TransmogOutfitDisplayType::Max)
return false;
if (slot.IllusionDisplayType >= TransmogOutfitDisplayType::Max)
return false;
if (!GetSlotAndOption(slot.Slot, slot.SlotOption))
return false;
if (slot.ItemModifiedAppearanceID)
{
ItemModifiedAppearanceEntry const* itemModifiedAppearance = sItemModifiedAppearanceStore.LookupEntry(slot.ItemModifiedAppearanceID);
if (!itemModifiedAppearance)
return false;
ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemModifiedAppearance->ItemID);
if (!itemTemplate)
return false;
if (!IsValidTransmogOutfitSlotForItem(itemTemplate, slot.Slot, slot.SlotOption))
return false;
TransmogOutfitSlotOption appearanceSlotOption = itemTemplate->GetWeaponTransmogOutfitSlotOption();
if (appearanceSlotOption != slot.SlotOption
&& (slot.SlotOption != TransmogOutfitSlotOption::FuryTwoHandedWeapon
|| appearanceSlotOption != TransmogOutfitSlotOption::TwoHandedWeapon))
return false;
}
if (slot.SpellItemEnchantmentID && !TransmogIllusionBySpellItemEnchantment.contains(slot.SpellItemEnchantmentID))
return false;
}
return true;
}
+88
View File
@@ -0,0 +1,88 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITYCORE_TRANSMOG_MGR_H
#define TRINITYCORE_TRANSMOG_MGR_H
#include "Common.h"
#include <span>
class Player;
struct ItemModifiedAppearanceEntry;
struct TransmogIllusionEntry;
struct TransmogOutfitEntryEntry;
struct TransmogOutfitSlotInfoEntry;
struct TransmogOutfitSlotOptionEntry;
struct TransmogSetEntry;
struct TransmogSetItemEntry;
struct TransmogSituationEntry;
enum EquipmentSlots : uint8;
enum class TransmogOutfitEntrySource : uint8;
enum class TransmogOutfitSlot : int8;
enum class TransmogOutfitSlotOption : uint8;
namespace WorldPackets::Transmogrification
{
struct TransmogOutfitSituationInfo;
struct TransmogOutfitSlotData;
}
namespace TransmogMgr
{
struct TransmogOutfitSlotAndOptionInfo
{
TransmogOutfitSlotInfoEntry const* Slot = nullptr;
TransmogOutfitSlotOptionEntry const* SlotOption = nullptr;
uint32 SlotIndex = 0;
};
inline constexpr std::array<std::string_view, TOTAL_LOCALES> DefaultOutfitName =
{
"Outfit"sv,
"\354\235\230\354\203\201"sv,
"Tenue"sv,
"Outfit"sv,
"\345\244\226\350\247\202\346\226\271\346\241\210"sv,
"\346\234\215\350\243\235"sv,
"Atuendo"sv,
"Indumentaria"sv,
"\320\241\320\275\320\260\321\200\321\217\320\266\320\265\320\275\320\270\320\265"sv,
""sv,
"Roupa"sv,
"Completo"sv
};
inline constexpr uint32 DefaultOutfitIcon = 134400;
void Load();
ItemModifiedAppearanceEntry const* GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId);
ItemModifiedAppearanceEntry const* GetDefaultItemModifiedAppearance(uint32 itemId);
TransmogIllusionEntry const* GetTransmogIllusionForSpellItemEnchantment(uint32 spellItemEnchantmentId);
std::span<TransmogSetEntry const* const> GetTransmogSetsForItemModifiedAppearance(uint32 itemModifiedAppearanceId);
std::span<TransmogSetItemEntry const* const> GetTransmogSetItems(uint32 transmogSetId);
std::span<TransmogOutfitEntryEntry const* const> GetAutomaticallyUnlockedOutfits();
std::span<TransmogOutfitSlotAndOptionInfo const> GetAllSlots();
TransmogOutfitSlotAndOptionInfo const* GetSlotAndOption(TransmogOutfitSlot slot, TransmogOutfitSlotOption slotOption);
TransmogOutfitSlotAndOptionInfo const* GetSlotAndOption(EquipmentSlots inventorySlot, TransmogOutfitSlotOption slotOption);
std::span<TransmogSituationEntry const* const> GetDefaultSituations();
TransmogOutfitEntryEntry const* GetNextOutfitToUnlock(TransmogOutfitEntrySource source, Player const* player);
bool ValidateSituations(std::span<WorldPackets::Transmogrification::TransmogOutfitSituationInfo const> situations);
bool ValidateSlots(std::span<WorldPackets::Transmogrification::TransmogOutfitSlotData const> slots);
}
#endif // TRINITYCORE_TRANSMOG_MGR_H
+4
View File
@@ -96,6 +96,7 @@
#include "TaxiPathGraph.h" #include "TaxiPathGraph.h"
#include "TerrainMgr.h" #include "TerrainMgr.h"
#include "TraitMgr.h" #include "TraitMgr.h"
#include "TransmogMgr.h"
#include "TransportMgr.h" #include "TransportMgr.h"
#include "Unit.h" #include "Unit.h"
#include "UpdateTime.h" #include "UpdateTime.h"
@@ -2066,6 +2067,9 @@ bool World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading phase names..."); TC_LOG_INFO("server.loading", "Loading phase names...");
sObjectMgr->LoadPhaseNames(); sObjectMgr->LoadPhaseNames();
TC_LOG_INFO("server.loading", "Loading transmog data...");
TransmogMgr::Load();
uint32 startupDuration = GetMSTimeDiffToNow(startupBegin); uint32 startupDuration = GetMSTimeDiffToNow(startupBegin);
TC_LOG_INFO("server.worldserver", "World initialized in {} minutes {} seconds", startupDuration / 60000, startupDuration % 60000 / 1000); TC_LOG_INFO("server.worldserver", "World initialized in {} minutes {} seconds", startupDuration / 60000, startupDuration % 60000 / 1000);