diff options
author | Shauren <shauren.trinity@gmail.com> | 2019-11-12 00:28:59 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-11-12 00:28:59 +0100 |
commit | ab6ae44b638136665e2ae6c6a434ad7426621c39 (patch) | |
tree | f90f17c7faee28e096dff114d5c643f56038a45e | |
parent | d1af9d9cf4672d9bdb5e18be4ae6f2c7dce93006 (diff) |
Core/Items: Implemented AzeriteItem
31 files changed, 671 insertions, 53 deletions
diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index eff92f48b57..6058fffde31 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -2856,6 +2856,31 @@ LOCK TABLES `item_instance_artifact_powers` WRITE; UNLOCK TABLES; -- +-- Table structure for table `item_instance_azerite` +-- + +DROP TABLE IF EXISTS `item_instance_azerite`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `item_instance_azerite` ( + `itemGuid` bigint(20) unsigned NOT NULL, + `xp` bigint(20) unsigned NOT NULL DEFAULT '0', + `level` int(10) unsigned NOT NULL DEFAULT '1', + `knowledgeLevel` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`itemGuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `item_instance_azerite` +-- + +LOCK TABLES `item_instance_azerite` WRITE; +/*!40000 ALTER TABLE `item_instance_azerite` DISABLE KEYS */; +/*!40000 ALTER TABLE `item_instance_azerite` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `item_instance_gems` -- @@ -3570,7 +3595,8 @@ INSERT INTO `updates` VALUES ('2019_07_15_00_characters.sql','E1C77F604FB2A2FE8B32258CD0C9EC71BEA4F0FF','RELEASED','2019-06-25 22:40:37',0), ('2019_10_26_00_characters.sql','F1090ACDEB876A7BB5ED8829373F6305A217949A','RELEASED','2019-10-25 23:04:42',0), ('2019_10_26_01_characters.sql','59D5860930D02AB77D2AAA704C564957A9143760','RELEASED','2019-10-26 22:04:46',0), -('2019_11_03_00_characters.sql','DC789597F85B890E9A7901B4443DAD9CAEE2A02A','RELEASED','2019-11-03 14:13:27',0); +('2019_11_03_00_characters.sql','DC789597F85B890E9A7901B4443DAD9CAEE2A02A','RELEASED','2019-11-03 14:13:27',0), +('2019_11_12_00_characters.sql','D4C642B4D48DAE9F56329BDE51C258323A132A91','RELEASED','2019-11-12 16:31:29',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/master/2019_11_12_00_characters.sql b/sql/updates/characters/master/2019_11_12_00_characters.sql new file mode 100644 index 00000000000..010e1693298 --- /dev/null +++ b/sql/updates/characters/master/2019_11_12_00_characters.sql @@ -0,0 +1,11 @@ +-- +-- Table structure for table `item_instance_azerite` +-- +DROP TABLE IF EXISTS `item_instance_azerite`; +CREATE TABLE `item_instance_azerite` ( + `itemGuid` bigint(20) unsigned NOT NULL, + `xp` bigint(20) unsigned NOT NULL DEFAULT '0', + `level` int(10) unsigned NOT NULL DEFAULT '1', + `knowledgeLevel` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`itemGuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/sql/updates/hotfixes/master/2019_11_12_00_hotfixes.sql b/sql/updates/hotfixes/master/2019_11_12_00_hotfixes.sql new file mode 100644 index 00000000000..a7c36362ca8 --- /dev/null +++ b/sql/updates/hotfixes/master/2019_11_12_00_hotfixes.sql @@ -0,0 +1,34 @@ +-- +-- Table structure for table `azerite_item` +-- +DROP TABLE IF EXISTS `azerite_item`; +CREATE TABLE `azerite_item` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `ItemID` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `azerite_knowledge_multiplier` +-- +DROP TABLE IF EXISTS `azerite_knowledge_multiplier`; +CREATE TABLE `azerite_knowledge_multiplier` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `Multiplier` float NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `azerite_level_info` +-- +DROP TABLE IF EXISTS `azerite_level_info`; +CREATE TABLE `azerite_level_info` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `BaseExperienceToNextLevel` bigint(20) unsigned NOT NULL DEFAULT '0', + `MinimumExperienceToNextLevel` bigint(20) unsigned NOT NULL DEFAULT '0', + `ItemLevel` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/world/master/2019_11_12_00_world.sql b/sql/updates/world/master/2019_11_12_00_world.sql new file mode 100644 index 00000000000..d4392a7a9ef --- /dev/null +++ b/sql/updates/world/master/2019_11_12_00_world.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `ScriptName`='spell_item_heart_of_azeroth'; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(277253,'spell_item_heart_of_azeroth'); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 34ec4149d98..2dad206c6ff 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -28,7 +28,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() "iit.itemModifiedAppearanceAllSpecs, iit.itemModifiedAppearanceSpec1, iit.itemModifiedAppearanceSpec2, iit.itemModifiedAppearanceSpec3, iit.itemModifiedAppearanceSpec4, " \ "iit.spellItemEnchantmentAllSpecs, iit.spellItemEnchantmentSpec1, iit.spellItemEnchantmentSpec2, iit.spellItemEnchantmentSpec3, iit.spellItemEnchantmentSpec4, " \ "ig.gemItemId1, ig.gemBonuses1, ig.gemContext1, ig.gemScalingLevel1, ig.gemItemId2, ig.gemBonuses2, ig.gemContext2, ig.gemScalingLevel2, ig.gemItemId3, ig.gemBonuses3, ig.gemContext3, ig.gemScalingLevel3, " \ - "im.fixedScalingLevel, im.artifactKnowledgeLevel" + "im.fixedScalingLevel, im.artifactKnowledgeLevel, iz.xp, iz.level, iz.knowledgeLevel" PrepareStatement(CHAR_DEL_QUEST_POOL_SAVE, "DELETE FROM pool_quest_save WHERE pool_id = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_INS_QUEST_POOL_SAVE, "INSERT INTO pool_quest_save (pool_id, quest_id) VALUES (?, ?)", CONNECTION_ASYNC); @@ -112,7 +112,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT " SelectItemInstanceContent ", bag, slot FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid WHERE ci.guid = ? ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0", CONNECTION_ASYNC); @@ -144,8 +144,8 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES, "SELECT instanceId, releaseTime FROM account_instance_times WHERE accountId = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button", CONNECTION_ASYNC); - PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT " SelectItemInstanceContent ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid WHERE mail_id = ?", CONNECTION_SYNCH); - PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT " SelectItemInstanceContent " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_MAILITEMS, "SELECT " SelectItemInstanceContent ", ii.owner_guid FROM mail_items mi JOIN item_instance ii ON mi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid WHERE mail_id = ?", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_AUCTION_ITEMS, "SELECT " SelectItemInstanceContent " FROM auctionhouse ah JOIN item_instance ii ON ah.itemguid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid", CONNECTION_SYNCH); PrepareStatement(CHAR_SEL_AUCTIONS, "SELECT id, auctioneerguid, itemguid, itemEntry, count, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit FROM auctionhouse ah INNER JOIN item_instance ii ON ii.guid = ah.itemguid", CONNECTION_SYNCH); PrepareStatement(CHAR_INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_AUCTION, "DELETE FROM auctionhouse WHERE id = ?", CONNECTION_ASYNC); @@ -189,6 +189,10 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_INS_ITEM_INSTANCE_MODIFIERS, "INSERT INTO item_instance_modifiers (itemGuid, fixedScalingLevel, artifactKnowledgeLevel) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS, "DELETE FROM item_instance_modifiers WHERE itemGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, "DELETE im FROM item_instance_modifiers im LEFT JOIN item_instance ii ON im.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_ITEM_INSTANCE_AZERITE, "INSERT INTO item_instance_azerite (itemGuid, xp, level, knowledgeLevel) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_UPD_ITEM_INSTANCE_AZERITE_ON_LOAD, "UPDATE item_instance_azerite SET xp = ?, knowledgeLevel = ? WHERE itemGuid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE, "DELETE FROM item_instance_azerite WHERE itemGuid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, "DELETE iz FROM item_instance_azerite iz LEFT JOIN item_instance ii ON iz.itemGuid = ii.guid WHERE ii.owner_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_UPD_GIFT_OWNER, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?", CONNECTION_ASYNC); @@ -220,7 +224,7 @@ void CharacterDatabaseConnection::DoPrepareStatements() // 0: uint32, 1: uint8, 2: uint8, 3: uint32, 4: uint32 PrepareStatement(CHAR_INS_GUILD_BANK_ITEM, "INSERT INTO guild_bank_item (guildid, TabId, SlotId, item_guid) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_GUILD_BANK_ITEM, "DELETE FROM guild_bank_item WHERE guildid = ? AND TabId = ? AND SlotId = ?", CONNECTION_ASYNC); // 0: uint32, 1: uint8, 2: uint8 - PrepareStatement(CHAR_SEL_GUILD_BANK_ITEMS, "SELECT " SelectItemInstanceContent ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid", CONNECTION_SYNCH); + PrepareStatement(CHAR_SEL_GUILD_BANK_ITEMS, "SELECT " SelectItemInstanceContent ", guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid LEFT JOIN item_instance_azerite iz ON ii.guid = iz.itemGuid", CONNECTION_SYNCH); PrepareStatement(CHAR_DEL_GUILD_BANK_ITEMS, "DELETE FROM guild_bank_item WHERE guildid = ?", CONNECTION_ASYNC); // 0: uint32 // 0: uint32, 1: uint8, 2: uint8, 3: uint8, 4: uint32 PrepareStatement(CHAR_INS_GUILD_BANK_RIGHT, "INSERT INTO guild_bank_right (guildid, TabId, rid, gbright, SlotPerDay) VALUES (?, ?, ?, ?, ?) " diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index fa2f0071a23..b66594c82ab 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -158,6 +158,10 @@ enum CharacterDatabaseStatements : uint32 CHAR_INS_ITEM_INSTANCE_MODIFIERS, CHAR_DEL_ITEM_INSTANCE_MODIFIERS, CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER, + CHAR_INS_ITEM_INSTANCE_AZERITE, + CHAR_UPD_ITEM_INSTANCE_AZERITE_ON_LOAD, + CHAR_DEL_ITEM_INSTANCE_AZERITE, + CHAR_DEL_ITEM_INSTANCE_AZERITE_BY_OWNER, CHAR_UPD_GIFT_OWNER, CHAR_DEL_GIFT, CHAR_SEL_CHARACTER_GIFT_BY_ITEM, diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp index 5f75f288a1c..daa8fade9c4 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.cpp +++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp @@ -110,6 +110,16 @@ void HotfixDatabaseConnection::DoPrepareStatements() PrepareStatement(HOTFIX_SEL_AUCTION_HOUSE, "SELECT ID, Name, FactionID, DepositRate, ConsignmentRate FROM auction_house ORDER BY ID DESC", CONNECTION_SYNCH); PREPARE_LOCALE_STMT(HOTFIX_SEL_AUCTION_HOUSE, "SELECT ID, Name_lang FROM auction_house_locale WHERE locale = ?", CONNECTION_SYNCH); + // AzeriteItem.db2 + PrepareStatement(HOTFIX_SEL_AZERITE_ITEM, "SELECT ID, ItemID FROM azerite_item ORDER BY ID DESC", CONNECTION_SYNCH); + + // AzeriteKnowledgeMultiplier.db2 + PrepareStatement(HOTFIX_SEL_AZERITE_KNOWLEDGE_MULTIPLIER, "SELECT ID, Multiplier FROM azerite_knowledge_multiplier ORDER BY ID DESC", CONNECTION_SYNCH); + + // AzeriteLevelInfo.db2 + PrepareStatement(HOTFIX_SEL_AZERITE_LEVEL_INFO, "SELECT ID, BaseExperienceToNextLevel, MinimumExperienceToNextLevel, ItemLevel" + " FROM azerite_level_info ORDER BY ID DESC", CONNECTION_SYNCH); + // BankBagSlotPrices.db2 PrepareStatement(HOTFIX_SEL_BANK_BAG_SLOT_PRICES, "SELECT ID, Cost FROM bank_bag_slot_prices ORDER BY ID DESC", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h index d1d97a1f0cc..0038716a43d 100644 --- a/src/server/database/Database/Implementation/HotfixDatabase.h +++ b/src/server/database/Database/Implementation/HotfixDatabase.h @@ -75,6 +75,12 @@ enum HotfixDatabaseStatements : uint32 HOTFIX_SEL_AUCTION_HOUSE, HOTFIX_SEL_AUCTION_HOUSE_LOCALE, + HOTFIX_SEL_AZERITE_ITEM, + + HOTFIX_SEL_AZERITE_KNOWLEDGE_MULTIPLIER, + + HOTFIX_SEL_AZERITE_LEVEL_INFO, + HOTFIX_SEL_BANK_BAG_SLOT_PRICES, HOTFIX_SEL_BANNED_ADDONS, diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index f182c261b17..aed59d63830 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -524,6 +524,7 @@ void CriteriaHandler::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0 case CRITERIA_TYPE_COMPLETE_BATTLEGROUND: case CRITERIA_TYPE_DAMAGE_DONE: case CRITERIA_TYPE_HEALING_DONE: + case CRITERIA_TYPE_HEART_OF_AZEROTH_ARTIFACT_POWER_EARNED: SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_ACCUMULATE); break; case CRITERIA_TYPE_KILL_CREATURE: @@ -541,6 +542,7 @@ void CriteriaHandler::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0 case CRITERIA_TYPE_HIGHEST_HIT_RECEIVED: case CRITERIA_TYPE_HIGHEST_HEAL_CAST: case CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED: + case CRITERIA_TYPE_HEART_OF_AZEROTH_LEVEL_REACHED: SetCriteriaProgress(criteria, miscValue1, referencePlayer, PROGRESS_HIGHEST); break; case CRITERIA_TYPE_REACH_LEVEL: @@ -786,8 +788,6 @@ void CriteriaHandler::UpdateCriteria(CriteriaTypes type, uint64 miscValue1 /*= 0 case CRITERIA_TYPE_EARN_HONOR_XP: case CRITERIA_TYPE_RELIC_TALENT_UNLOCKED: case CRITERIA_TYPE_REACH_ACCOUNT_HONOR_LEVEL: - case CRITERIA_TYPE_HEART_OF_AZEROTH_ARTIFACT_POWER_EARNED: - case CRITERIA_TYPE_HEART_OF_AZEROTH_LEVEL_REACHED: break; // Not implemented yet :( } diff --git a/src/server/game/DataStores/DB2LoadInfo.h b/src/server/game/DataStores/DB2LoadInfo.h index acea806bdb6..bce776c6034 100644 --- a/src/server/game/DataStores/DB2LoadInfo.h +++ b/src/server/game/DataStores/DB2LoadInfo.h @@ -418,6 +418,50 @@ struct AuctionHouseLoadInfo } }; +struct AzeriteItemLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { true, FT_INT, "ItemID" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, AzeriteItemMeta::Instance(), HOTFIX_SEL_AZERITE_ITEM); + return &loadInfo; + } +}; + +struct AzeriteKnowledgeMultiplierLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_FLOAT, "Multiplier" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, AzeriteKnowledgeMultiplierMeta::Instance(), HOTFIX_SEL_AZERITE_KNOWLEDGE_MULTIPLIER); + return &loadInfo; + } +}; + +struct AzeriteLevelInfoLoadInfo +{ + static DB2LoadInfo const* Instance() + { + static DB2FieldMeta const fields[] = + { + { false, FT_INT, "ID" }, + { false, FT_LONG, "BaseExperienceToNextLevel" }, + { false, FT_LONG, "MinimumExperienceToNextLevel" }, + { true, FT_INT, "ItemLevel" }, + }; + static DB2LoadInfo const loadInfo(&fields[0], std::extent<decltype(fields)>::value, AzeriteLevelInfoMeta::Instance(), HOTFIX_SEL_AZERITE_LEVEL_INFO); + return &loadInfo; + } +}; + struct BankBagSlotPricesLoadInfo { static DB2LoadInfo const* Instance() diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp index 9541a6bc551..955347006cc 100644 --- a/src/server/game/DataStores/DB2Stores.cpp +++ b/src/server/game/DataStores/DB2Stores.cpp @@ -55,6 +55,9 @@ DB2Storage<ArtifactQuestXPEntry> sArtifactQuestXPStore("ArtifactQ DB2Storage<ArtifactTierEntry> sArtifactTierStore("ArtifactTier.db2", ArtifactTierLoadInfo::Instance()); DB2Storage<ArtifactUnlockEntry> sArtifactUnlockStore("ArtifactUnlock.db2", ArtifactUnlockLoadInfo::Instance()); DB2Storage<AuctionHouseEntry> sAuctionHouseStore("AuctionHouse.db2", AuctionHouseLoadInfo::Instance()); +DB2Storage<AzeriteItemEntry> sAzeriteItemStore("AzeriteItem.db2", AzeriteItemLoadInfo::Instance()); +DB2Storage<AzeriteKnowledgeMultiplierEntry> sAzeriteKnowledgeMultiplierStore("AzeriteKnowledgeMultiplier.db2", AzeriteKnowledgeMultiplierLoadInfo::Instance()); +DB2Storage<AzeriteLevelInfoEntry> sAzeriteLevelInfoStore("AzeriteLevelInfo.db2", AzeriteLevelInfoLoadInfo::Instance()); DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore("BankBagSlotPrices.db2", BankBagSlotPricesLoadInfo::Instance()); DB2Storage<BannedAddonsEntry> sBannedAddonsStore("BannedAddons.db2", BannedAddonsLoadInfo::Instance()); DB2Storage<BarberShopStyleEntry> sBarberShopStyleStore("BarberShopStyle.db2", BarberShopStyleLoadInfo::Instance()); @@ -510,6 +513,9 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale) LOAD_DB2(sArtifactTierStore); LOAD_DB2(sArtifactUnlockStore); LOAD_DB2(sAuctionHouseStore); + LOAD_DB2(sAzeriteItemStore); + LOAD_DB2(sAzeriteKnowledgeMultiplierStore); + LOAD_DB2(sAzeriteLevelInfoStore); LOAD_DB2(sBankBagSlotPricesStore); LOAD_DB2(sBannedAddonsStore); LOAD_DB2(sBarberShopStyleStore); @@ -1435,6 +1441,12 @@ ArtifactPowerRankEntry const* DB2Manager::GetArtifactPowerRank(uint32 artifactPo return nullptr; } +bool DB2Manager::IsAzeriteItem(uint32 itemId) const +{ + return std::find_if(sAzeriteItemStore.begin(), sAzeriteItemStore.end(), + [&](AzeriteItemEntry const* azeriteItem) { return azeriteItem->ItemID == int32(itemId); }) != sAzeriteItemStore.end(); +} + char const* DB2Manager::GetBroadcastTextValue(BroadcastTextEntry const* broadcastText, LocaleConstant locale /*= DEFAULT_LOCALE*/, uint8 gender /*= GENDER_MALE*/, bool forceGender /*= false*/) { if ((gender == GENDER_FEMALE || gender == GENDER_NONE) && (forceGender || broadcastText->Text1->Str[DEFAULT_LOCALE][0] != '\0')) diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h index bf00a0e4303..2eb886e893a 100644 --- a/src/server/game/DataStores/DB2Stores.h +++ b/src/server/game/DataStores/DB2Stores.h @@ -49,6 +49,8 @@ TC_GAME_API extern DB2Storage<ArtifactPowerPickerEntry> sArtifactPow TC_GAME_API extern DB2Storage<ArtifactTierEntry> sArtifactTierStore; TC_GAME_API extern DB2Storage<ArtifactUnlockEntry> sArtifactUnlockStore; TC_GAME_API extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore; +TC_GAME_API extern DB2Storage<AzeriteKnowledgeMultiplierEntry> sAzeriteKnowledgeMultiplierStore; +TC_GAME_API extern DB2Storage<AzeriteLevelInfoEntry> sAzeriteLevelInfoStore; TC_GAME_API extern DB2Storage<BankBagSlotPricesEntry> sBankBagSlotPricesStore; TC_GAME_API extern DB2Storage<BannedAddonsEntry> sBannedAddonsStore; TC_GAME_API extern DB2Storage<BarberShopStyleEntry> sBarberShopStyleStore; @@ -269,6 +271,7 @@ public: std::vector<ArtifactPowerEntry const*> GetArtifactPowers(uint8 artifactId) const; std::unordered_set<uint32> const* GetArtifactPowerLinks(uint32 artifactPowerId) const; ArtifactPowerRankEntry const* GetArtifactPowerRank(uint32 artifactPowerId, uint8 rank) const; + bool IsAzeriteItem(uint32 itemId) const; static char const* GetBroadcastTextValue(BroadcastTextEntry const* broadcastText, LocaleConstant locale = DEFAULT_LOCALE, uint8 gender = GENDER_MALE, bool forceGender = false); bool HasCharacterFacialHairStyle(uint8 race, uint8 gender, uint8 variationId) const; bool HasCharSections(uint8 race, uint8 gender, CharBaseSectionVariation variation) const; diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h index 0beef77330c..37a15c7a443 100644 --- a/src/server/game/DataStores/DB2Structure.h +++ b/src/server/game/DataStores/DB2Structure.h @@ -259,6 +259,26 @@ struct AuctionHouseEntry uint8 ConsignmentRate; }; +struct AzeriteItemEntry +{ + uint32 ID; + int32 ItemID; +}; + +struct AzeriteKnowledgeMultiplierEntry +{ + uint32 ID; + float Multiplier; +}; + +struct AzeriteLevelInfoEntry +{ + uint32 ID; + uint64 BaseExperienceToNextLevel; + uint64 MinimumExperienceToNextLevel; + int32 ItemLevel; +}; + struct BankBagSlotPricesEntry { uint32 ID; diff --git a/src/server/game/DataStores/DBCEnums.h b/src/server/game/DataStores/DBCEnums.h index d33645346e2..9c2515c5b44 100644 --- a/src/server/game/DataStores/DBCEnums.h +++ b/src/server/game/DataStores/DBCEnums.h @@ -1172,6 +1172,7 @@ enum CurrencyTypes CURRENCY_TYPE_JUSTICE_POINTS = 395, CURRENCY_TYPE_VALOR_POINTS = 396, CURRENCY_TYPE_APEXIS_CRYSTALS = 823, + CURRENCY_TYPE_AZERITE = 1553 }; enum WorldMapTransformsFlags diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp new file mode 100644 index 00000000000..284aa202d7e --- /dev/null +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> + * + * 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 "AzeriteItem.h" +#include "AzeriteItemPackets.h" +#include "DatabaseEnv.h" +#include "DB2Stores.h" +#include "GameTime.h" +#include "Player.h" +#include <boost/date_time/gregorian/gregorian_types.hpp> +#include <boost/date_time/posix_time/conversion.hpp> + +AzeriteItem::AzeriteItem() : Item() +{ + m_objectType |= TYPEMASK_AZERITE_ITEM; + m_objectTypeId = TYPEID_AZERITE_ITEM; + + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::DEBUGknowledgeWeek), -1); +} + +bool AzeriteItem::Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owner) +{ + if (!Item::Create(guidlow, itemId, owner)) + return false; + + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Level), 1); + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::KnowledgeLevel), GetCurrentKnowledgeLevel()); + return true; +} + +void AzeriteItem::SaveToDB(CharacterDatabaseTransaction& trans) +{ + Item::SaveToDB(trans); + + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ITEM_INSTANCE_AZERITE); + stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt64(1, m_azeriteItemData->Xp); + stmt->setUInt32(2, m_azeriteItemData->Level); + stmt->setUInt32(3, m_azeriteItemData->KnowledgeLevel); + trans->Append(stmt); +} + +bool AzeriteItem::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry) +{ + if (!Item::LoadFromDB(guid, ownerGuid, fields, entry)) + return false; + + bool needSave = false; + + uint64 xp = fields[43].GetUInt64(); + uint32 level = fields[44].GetUInt32(); + uint32 knowledgeLevel = fields[45].GetUInt32(); + + if (!sAzeriteLevelInfoStore.LookupEntry(level)) + { + xp = 0; + level = 1; + knowledgeLevel = GetCurrentKnowledgeLevel(); + needSave = true; + } + else if (level > MAX_AZERITE_ITEM_LEVEL) + { + xp = 0; + level = MAX_AZERITE_ITEM_LEVEL; + needSave = true; + } + + if (knowledgeLevel != GetCurrentKnowledgeLevel()) + { + // rescale XP to maintain same progress % + uint64 oldMax = CalcTotalXPToNextLevel(level, knowledgeLevel); + knowledgeLevel = GetCurrentKnowledgeLevel(); + uint64 newMax = CalcTotalXPToNextLevel(level, knowledgeLevel); + xp = uint64(xp / double(oldMax) * newMax); + needSave = true; + } + else if (knowledgeLevel > MAX_AZERITE_ITEM_KNOWLEDGE_LEVEL) + { + knowledgeLevel = MAX_AZERITE_ITEM_KNOWLEDGE_LEVEL; + needSave = true; + } + + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Xp), xp); + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Level), level); + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::KnowledgeLevel), knowledgeLevel); + + if (needSave) + { + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ITEM_INSTANCE_AZERITE_ON_LOAD); + stmt->setUInt64(0, xp); + stmt->setUInt32(1, knowledgeLevel); + stmt->setUInt64(2, guid); + CharacterDatabase.Execute(stmt); + } + + return true; +} + +void AzeriteItem::DeleteFromDB(CharacterDatabaseTransaction& trans) +{ + CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE); + stmt->setUInt64(0, GetGUID().GetCounter()); + trans->Append(stmt); + + Item::DeleteFromDB(trans); +} + +uint32 AzeriteItem::GetItemLevel(Player const* /*owner*/) const +{ + return sAzeriteLevelInfoStore.AssertEntry(m_azeriteItemData->Level)->ItemLevel; +} + +uint32 AzeriteItem::GetCurrentKnowledgeLevel() +{ + // count weeks from 26.06.2019 + boost::gregorian::date now = boost::posix_time::from_time_t(GameTime::GetGameTime()).date(); + boost::gregorian::week_iterator itr(boost::gregorian::date(2019, boost::date_time::Jun, 26)); + uint32 knowledge = 0; + while (*itr < now && knowledge < MAX_AZERITE_ITEM_KNOWLEDGE_LEVEL) + { + ++knowledge; + ++itr; + } + return knowledge; +} + +uint64 AzeriteItem::CalcTotalXPToNextLevel(uint32 level, uint32 knowledgeLevel) +{ + AzeriteLevelInfoEntry const* levelInfo = sAzeriteLevelInfoStore.AssertEntry(level); + uint64 totalXp = levelInfo->BaseExperienceToNextLevel * sAzeriteKnowledgeMultiplierStore.AssertEntry(knowledgeLevel)->Multiplier; + return std::max(totalXp, levelInfo->MinimumExperienceToNextLevel); +} + +void AzeriteItem::GiveXP(uint64 xp) +{ + Player* owner = GetOwner(); + uint32 level = m_azeriteItemData->Level; + if (level < MAX_AZERITE_ITEM_LEVEL) + { + uint64 currentXP = m_azeriteItemData->Xp; + uint64 remainingXP = xp; + do + { + uint64 totalXp = CalcTotalXPToNextLevel(level, m_azeriteItemData->KnowledgeLevel); + if (currentXP + remainingXP >= totalXp) + { + // advance to next level + ++level; + remainingXP -= totalXp - currentXP; + currentXP = 0; + } + else + { + currentXP += remainingXP; + remainingXP = 0; + } + } while (remainingXP > 0 && level < MAX_AZERITE_ITEM_LEVEL); + + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Xp), currentXP); + + owner->UpdateCriteria(CRITERIA_TYPE_HEART_OF_AZEROTH_ARTIFACT_POWER_EARNED, xp); + + // changing azerite level changes item level, need to update stats + if (m_azeriteItemData->Level != level) + { + if (IsEquipped()) + owner->_ApplyItemBonuses(this, GetSlot(), false); + + SetUpdateFieldValue(m_values.ModifyValue(&AzeriteItem::m_azeriteItemData).ModifyValue(&UF::AzeriteItemData::Level), level); + owner->UpdateCriteria(CRITERIA_TYPE_HEART_OF_AZEROTH_LEVEL_REACHED, level); + + if (IsEquipped()) + owner->_ApplyItemBonuses(this, GetSlot(), true); + } + + SetState(ITEM_CHANGED, owner); + } + + WorldPackets::AzeriteItem::AzeriteXpGain xpGain; + xpGain.ItemGUID = GetGUID(); + xpGain.XP = xp; + owner->SendDirectMessage(xpGain.Write()); +} + +void AzeriteItem::BuildValuesCreate(ByteBuffer* data, Player const* target) const +{ + UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target); + std::size_t sizePos = data->wpos(); + *data << uint32(0); + *data << uint8(flags); + m_objectData->WriteCreate(*data, flags, this, target); + m_itemData->WriteCreate(*data, flags, this, target); + m_azeriteItemData->WriteCreate(*data, flags, this, target); + data->put<uint32>(sizePos, data->wpos() - sizePos - 4); +} + +void AzeriteItem::BuildValuesUpdate(ByteBuffer* data, Player const* target) const +{ + UF::UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target); + std::size_t sizePos = data->wpos(); + *data << uint32(0); + *data << uint32(m_values.GetChangedObjectTypeMask()); + + if (m_values.HasChanged(TYPEID_OBJECT)) + m_objectData->WriteUpdate(*data, flags, this, target); + + if (m_values.HasChanged(TYPEID_ITEM)) + m_itemData->WriteUpdate(*data, flags, this, target); + + if (m_values.HasChanged(TYPEID_AZERITE_ITEM)) + m_azeriteItemData->WriteUpdate(*data, flags, this, target); + + data->put<uint32>(sizePos, data->wpos() - sizePos - 4); +} + +void AzeriteItem::BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const +{ + UpdateMask<NUM_CLIENT_OBJECT_TYPES> valuesMask; + valuesMask.Set(TYPEID_ITEM); + valuesMask.Set(TYPEID_AZERITE_ITEM); + + std::size_t sizePos = data->wpos(); + *data << uint32(0); + *data << uint32(valuesMask.GetBlock(0)); + + UF::ItemData::Mask mask; + m_itemData->AppendAllowedFieldsMaskForFlag(mask, flags); + m_itemData->WriteUpdate(*data, mask, flags, this, target); + + UF::AzeriteItemData::Mask mask2; + m_azeriteItemData->AppendAllowedFieldsMaskForFlag(mask2, flags); + m_azeriteItemData->WriteUpdate(*data, mask2, flags, this, target); + + data->put<uint32>(sizePos, data->wpos() - sizePos - 4); +} + +void AzeriteItem::ClearUpdateMask(bool remove) +{ + m_values.ClearChangesMask(&AzeriteItem::m_azeriteItemData); + Item::ClearUpdateMask(remove); +} diff --git a/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h new file mode 100644 index 00000000000..b255e094358 --- /dev/null +++ b/src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> + * + * 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 AzeriteItem_h__ +#define AzeriteItem_h__ + +#include "Item.h" + +constexpr uint32 ITEM_ID_HEART_OF_AZEROTH = 158075; +constexpr uint32 MAX_AZERITE_ITEM_LEVEL = 70; +constexpr uint32 MAX_AZERITE_ITEM_KNOWLEDGE_LEVEL = 30; + +class TC_GAME_API AzeriteItem : public Item +{ +public: + AzeriteItem(); + + bool Create(ObjectGuid::LowType guidlow, uint32 itemId, Player const* owner) override; + + void SaveToDB(CharacterDatabaseTransaction& trans) override; + bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fields, uint32 entry) override; + void DeleteFromDB(CharacterDatabaseTransaction& trans) override; + + uint32 GetItemLevel(Player const* owner) const override; + + static uint32 GetCurrentKnowledgeLevel(); + static uint64 CalcTotalXPToNextLevel(uint32 level, uint32 knowledgeLevel); + void GiveXP(uint64 xp); + + void BuildValuesCreate(ByteBuffer* data, Player const* target) const override; + void BuildValuesUpdate(ByteBuffer* data, Player const* target) const override; + void BuildValuesUpdateWithFlag(ByteBuffer* data, UF::UpdateFieldFlag flags, Player const* target) const override; + void ClearUpdateMask(bool remove) override; + + UF::UpdateField<UF::AzeriteItemData, 0, TYPEID_AZERITE_ITEM> m_azeriteItemData; +}; + +#endif // AzeriteItem_h__ diff --git a/src/server/game/Entities/Item/Container/Bag.h b/src/server/game/Entities/Item/Container/Bag.h index b59acb52b1c..b9f4f3c1beb 100644 --- a/src/server/game/Entities/Item/Container/Bag.h +++ b/src/server/game/Entities/Item/Container/Bag.h @@ -72,9 +72,4 @@ class TC_GAME_API Bag : public Item Item* m_bagslot[MAX_BAG_SIZE]; }; -inline Item* NewItemOrBag(ItemTemplate const* proto) -{ - return (proto->GetInventoryType() == INVTYPE_BAG) ? new Bag : new Item; -} - #endif diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index cecf6d8b103..6329195f439 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -18,6 +18,7 @@ #include "Item.h" #include "ArtifactPackets.h" +#include "AzeriteItem.h" #include "Bag.h" #include "CollectionMgr.h" #include "Common.h" @@ -42,6 +43,17 @@ #include "World.h" #include "WorldSession.h" +Item* NewItemOrBag(ItemTemplate const* proto) +{ + if (proto->GetInventoryType() == INVTYPE_BAG) + return new Bag(); + + if (sDB2Manager.IsAzeriteItem(proto->GetId())) + return new AzeriteItem(); + + return new Item(); +} + void AddItemsSetItem(Player* player, Item* item) { ItemTemplate const* proto = item->GetTemplate(); @@ -628,8 +640,8 @@ bool Item::LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field* fie // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, // 29 30 31 32 33 34 35 36 37 38 39 40 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3 - // 41 42 - // fixedScalingLevel, artifactKnowledgeLevel FROM item_instance + // 41 42 43 44 45 + // fixedScalingLevel, artifactKnowledgeLevel, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance // create item before any checks for store correct guid // and allow use "FSetState(ITEM_REMOVED); SaveToDB();" for deleting item from DB diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index b8a8c242ba1..695bccfb9dc 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -115,15 +115,14 @@ struct ArtifactPowerLoadInfo uint8 CurrentRankWithBonus; }; -#pragma pack(push, 1) struct ItemDynamicFieldGems { uint32 ItemId; uint16 BonusListIDs[16]; uint8 Context; - uint8 Padding[3]; }; -#pragma pack(pop) + +Item* NewItemOrBag(ItemTemplate const* proto); class TC_GAME_API Item : public Object { @@ -164,6 +163,10 @@ class TC_GAME_API Item : public Object void AddItemFlag(ItemFieldFlags flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::DynamicFlags), flags); } void RemoveItemFlag(ItemFieldFlags flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::DynamicFlags), flags); } void SetItemFlags(ItemFieldFlags flags) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::DynamicFlags), flags); } + bool HasItemFlag2(ItemFieldFlags2 flag) const { return (*m_itemData->DynamicFlags2 & flag) != 0; } + void AddItemFlag2(ItemFieldFlags2 flags) { SetUpdateFieldFlagValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::DynamicFlags2), flags); } + void RemoveItemFlag2(ItemFieldFlags2 flags) { RemoveUpdateFieldFlagValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::DynamicFlags2), flags); } + void SetItemFlags2(ItemFieldFlags2 flags) { SetUpdateFieldValue(m_values.ModifyValue(&Item::m_itemData).ModifyValue(&UF::ItemData::DynamicFlags2), flags); } bool IsSoulBound() const { return HasItemFlag(ITEM_FIELD_FLAG_SOULBOUND); } bool IsBoundAccountWide() const { return (GetTemplate()->GetFlags() & ITEM_FLAG_IS_BOUND_TO_ACCOUNT) != 0; } bool IsBattlenetAccountBound() const { return (GetTemplate()->GetFlags2() & ITEM_FLAG2_BNET_ACCOUNT_TRADE_OK) != 0; } @@ -196,9 +199,12 @@ class TC_GAME_API Item : public Object Bag* ToBag() { if (IsBag()) return reinterpret_cast<Bag*>(this); else return NULL; } const Bag* ToBag() const { if (IsBag()) return reinterpret_cast<const Bag*>(this); else return NULL; } + AzeriteItem* ToAzeriteItem() { return IsAzeriteItem() ? reinterpret_cast<AzeriteItem*>(this) : nullptr; } + AzeriteItem const* ToAzeriteItem() const { return IsAzeriteItem() ? reinterpret_cast<AzeriteItem const*>(this) : nullptr; } bool IsLocked() const { return !HasItemFlag(ITEM_FIELD_FLAG_UNLOCKED); } bool IsBag() const { return GetTemplate()->GetInventoryType() == INVTYPE_BAG; } + bool IsAzeriteItem() const { return GetTypeId() == TYPEID_AZERITE_ITEM; } bool IsCurrencyToken() const { return GetTemplate()->IsCurrencyToken(); } bool IsNotEmptyBag() const; bool IsBroken() const { return *m_itemData->MaxDurability > 0 && *m_itemData->Durability == 0; } @@ -279,7 +285,7 @@ class TC_GAME_API Item : public Object bool IsConjuredConsumable() const { return GetTemplate()->IsConjuredConsumable(); } bool IsRangedWeapon() const { return GetTemplate()->IsRangedWeapon(); } uint32 GetQuality() const { return _bonusData.Quality; } - uint32 GetItemLevel(Player const* owner) const; + virtual uint32 GetItemLevel(Player const* owner) const; static uint32 GetItemLevel(ItemTemplate const* itemTemplate, BonusData const& bonusData, uint32 level, uint32 fixedLevel, uint32 minItemLevel, uint32 minItemLevelCutoff, uint32 maxItemLevel, bool pvpBonus); int32 GetRequiredLevel() const; diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index 2f3d5b805a4..2c1717aea15 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -169,6 +169,11 @@ enum ItemFieldFlags : uint32 ITEM_FIELD_FLAG_UNK26 = 0x80000000 }; +enum ItemFieldFlags2 : uint32 +{ + ITEM_FIELD_FLAG2_HEART_OF_AZEROTH_EQUIPPED = 0x1 +}; + enum ItemFlags : uint32 { ITEM_FLAG_NO_PICKUP = 0x00000001, diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.cpp b/src/server/game/Entities/Object/Updates/UpdateFields.cpp index 0f0e45a3696..141f6f27317 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateFields.cpp @@ -221,7 +221,7 @@ void ItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fiel data << uint32(Gems.size()); if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) { - data << uint32(Field_130); + data << uint32(DynamicFlags2); } for (std::size_t i = 0; i < Modifiers.size(); ++i) { @@ -375,7 +375,7 @@ void ItemData::WriteUpdate(ByteBuffer& data, UpdateMask<40> const& changesMask, } if (changesMask[19]) { - data << uint32(Field_130); + data << uint32(DynamicFlags2); } } if (changesMask[20]) @@ -420,7 +420,7 @@ void ItemData::ClearChangesMask() Base::ClearChangesMask(Context); Base::ClearChangesMask(ArtifactXP); Base::ClearChangesMask(ItemAppearanceModID); - Base::ClearChangesMask(Field_130); + Base::ClearChangesMask(DynamicFlags2); Base::ClearChangesMask(SpellCharges); Base::ClearChangesMask(Enchantment); _changesMask.ResetAll(); @@ -504,19 +504,19 @@ void AzeriteEmpoweredItemData::ClearChangesMask() _changesMask.ResetAll(); } -void UnlockedAzeriteEssence::WriteCreate(ByteBuffer& data, Item const* owner, Player const* receiver) const +void UnlockedAzeriteEssence::WriteCreate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const { data << uint32(AzeriteEssenceID); data << uint32(Rank); } -void UnlockedAzeriteEssence::WriteUpdate(ByteBuffer& data, Item const* owner, Player const* receiver) const +void UnlockedAzeriteEssence::WriteUpdate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const { data << uint32(AzeriteEssenceID); data << uint32(Rank); } -void SelectedAzeriteEssences::WriteCreate(ByteBuffer& data, Item const* owner, Player const* receiver) const +void SelectedAzeriteEssences::WriteCreate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const { for (std::size_t i = 0; i < 3; ++i) { @@ -527,7 +527,7 @@ void SelectedAzeriteEssences::WriteCreate(ByteBuffer& data, Item const* owner, P data.FlushBits(); } -void SelectedAzeriteEssences::WriteUpdate(ByteBuffer& data, Item const* owner, Player const* receiver) const +void SelectedAzeriteEssences::WriteUpdate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const { UpdateMask<7> const& changesMask = _changesMask; data.WriteBits(changesMask.GetBlocksMask(0), 1); @@ -567,7 +567,7 @@ void SelectedAzeriteEssences::ClearChangesMask() _changesMask.ResetAll(); } -void AzeriteItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const +void AzeriteItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteItem const* owner, Player const* receiver) const { if (fieldVisibilityFlags.HasFlag(UpdateFieldFlag::Owner)) { @@ -594,7 +594,7 @@ void AzeriteItemData::WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFla } } -void AzeriteItemData::WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const +void AzeriteItemData::WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteItem const* owner, Player const* receiver) const { UpdateMask<9> allowedMaskForTarget({ 0x0000000Fu }); AppendAllowedFieldsMaskForFlag(allowedMaskForTarget, fieldVisibilityFlags); @@ -607,7 +607,7 @@ void AzeriteItemData::AppendAllowedFieldsMaskForFlag(UpdateMask<9>& allowedMaskF allowedMaskForTarget |= { 0x000001F0u }; } -void AzeriteItemData::WriteUpdate(ByteBuffer& data, UpdateMask<9> const& changesMask, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const +void AzeriteItemData::WriteUpdate(ByteBuffer& data, UpdateMask<9> const& changesMask, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteItem const* owner, Player const* receiver) const { data.WriteBits(changesMask.GetBlock(0), 9); diff --git a/src/server/game/Entities/Object/Updates/UpdateFields.h b/src/server/game/Entities/Object/Updates/UpdateFields.h index dcc4cb15076..75c15ad52d8 100644 --- a/src/server/game/Entities/Object/Updates/UpdateFields.h +++ b/src/server/game/Entities/Object/Updates/UpdateFields.h @@ -26,6 +26,7 @@ #include "UpdateMask.h" class AreaTrigger; +class AzeriteItem; class Bag; class ByteBuffer; class Conversation; @@ -104,7 +105,7 @@ struct ItemData : public IsUpdateFieldStructureTag, public HasChangesMask<40> UpdateField<int32, 0, 16> Context; UpdateField<uint64, 0, 17> ArtifactXP; UpdateField<uint8, 0, 18> ItemAppearanceModID; - UpdateField<uint32, 0, 19> Field_130; + UpdateField<uint32, 0, 19> DynamicFlags2; UpdateFieldArray<int32, 5, 20, 21> SpellCharges; UpdateFieldArray<UF::ItemEnchantment, 13, 26, 27> Enchantment; @@ -139,8 +140,8 @@ struct UnlockedAzeriteEssence : public IsUpdateFieldStructureTag uint32 AzeriteEssenceID; uint32 Rank; - void WriteCreate(ByteBuffer& data, Item const* owner, Player const* receiver) const; - void WriteUpdate(ByteBuffer& data, Item const* owner, Player const* receiver) const; + void WriteCreate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const; }; struct SelectedAzeriteEssences : public IsUpdateFieldStructureTag, public HasChangesMask<7> @@ -149,8 +150,8 @@ struct SelectedAzeriteEssences : public IsUpdateFieldStructureTag, public HasCha UpdateField<uint32, 0, 2> Enabled; UpdateFieldArray<uint32, 3, 3, 4> AzeriteEssenceID; - void WriteCreate(ByteBuffer& data, Item const* owner, Player const* receiver) const; - void WriteUpdate(ByteBuffer& data, Item const* owner, Player const* receiver) const; + void WriteCreate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, AzeriteItem const* owner, Player const* receiver) const; void ClearChangesMask(); }; @@ -165,10 +166,10 @@ struct AzeriteItemData : public IsUpdateFieldStructureTag, public HasChangesMask UpdateField<uint32, 0, 7> KnowledgeLevel; UpdateField<int32, 0, 8> DEBUGknowledgeWeek; - void WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const; - void WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const; + void WriteCreate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteItem const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteItem const* owner, Player const* receiver) const; void AppendAllowedFieldsMaskForFlag(UpdateMask<9>& allowedMaskForTarget, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags) const; - void WriteUpdate(ByteBuffer& data, UpdateMask<9> const& changesMask, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, Item const* owner, Player const* receiver) const; + void WriteUpdate(ByteBuffer& data, UpdateMask<9> const& changesMask, EnumClassFlag<UpdateFieldFlag> fieldVisibilityFlags, AzeriteItem const* owner, Player const* receiver) const; void ClearChangesMask(); }; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ca47e79e99d..644fe75758f 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -22,6 +22,7 @@ #include "AchievementMgr.h" #include "ArenaTeam.h" #include "ArenaTeamMgr.h" +#include "AzeriteItem.h" #include "Bag.h" #include "Battlefield.h" #include "BattlefieldMgr.h" @@ -4048,6 +4049,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt64(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_AZERITE_BY_OWNER); + stmt->setUInt64(0, guid); + trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER); stmt->setUInt64(0, guid); trans->Append(stmt); @@ -6753,6 +6758,14 @@ void Player::ModifyCurrency(uint32 id, int32 count, bool printLog/* = true*/, bo return; } + if (id == CURRENCY_TYPE_AZERITE) + { + if (count > 0) + if (Item* heartOfAzeroth = GetItemByEntry(ITEM_ID_HEART_OF_AZEROTH)) + heartOfAzeroth->ToAzeriteItem()->GiveXP(uint64(count)); + return; + } + uint32 oldTotalCount = 0; uint32 oldWeekCount = 0; uint32 oldTrackedCount = 0; @@ -14989,6 +15002,7 @@ void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver) break; case TYPEID_ITEM: case TYPEID_CONTAINER: + case TYPEID_AZERITE_ITEM: { Item* item = static_cast<Item*>(questGiver); sScriptMgr->OnQuestAccept(this, item, quest); @@ -18570,9 +18584,9 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, // 29 30 31 32 33 34 35 36 37 38 39 40 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3 - // 41 42 - // fixedScalingLevel, artifactKnowledgeLevel FROM item_instance - // 43 44 + // 41 42 43 44 45 + // fixedScalingLevel, artifactKnowledgeLevel, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance + // 46 47 // bag, slot // FROM character_inventory ci // JOIN item_instance ii ON ci.item = ii.guid @@ -18641,8 +18655,8 @@ void Player::_LoadInventory(PreparedQueryResult result, PreparedQueryResult arti if (item->GetTemplate()->GetArtifactID() && artifactDataItr != artifactData.end()) item->LoadArtifactData(this, std::get<0>(artifactDataItr->second), std::get<1>(artifactDataItr->second), std::get<2>(artifactDataItr->second), std::get<3>(artifactDataItr->second)); - ObjectGuid bagGuid = fields[43].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[43].GetUInt64()) : ObjectGuid::Empty; - uint8 slot = fields[44].GetUInt8(); + ObjectGuid bagGuid = fields[46].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[46].GetUInt64()) : ObjectGuid::Empty; + uint8 slot = fields[47].GetUInt8(); GetSession()->GetCollectionMgr()->CheckHeirloomUpgrades(item); GetSession()->GetCollectionMgr()->AddItemAppearance(item); @@ -18983,7 +18997,7 @@ void Player::_LoadMailedItems(Mail* mail) Item* item = NewItemOrBag(proto); - ObjectGuid ownerGuid = fields[43].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[43].GetUInt64()) : ObjectGuid::Empty; + ObjectGuid ownerGuid = fields[46].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[46].GetUInt64()) : ObjectGuid::Empty; if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry)) { TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: " UI64FMTD ") in mail (%u) doesn't exist, deleted from mail.", itemGuid, mail->messageID); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 6133fa2cf95..33f74a4c9de 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -374,7 +374,7 @@ void Guild::BankTab::LoadFromDB(Field* fields) bool Guild::BankTab::LoadItemFromDB(Field* fields) { - uint8 slotId = fields[45].GetUInt8(); + uint8 slotId = fields[48].GetUInt8(); ObjectGuid::LowType itemGuid = fields[0].GetUInt64(); uint32 itemEntry = fields[1].GetUInt32(); if (slotId >= GUILD_BANK_MAX_SLOTS) @@ -2498,7 +2498,7 @@ void Guild::LoadBankTabFromDB(Field* fields) bool Guild::LoadBankItemFromDB(Field* fields) { - uint8 tabId = fields[44].GetUInt8(); + uint8 tabId = fields[47].GetUInt8(); if (tabId >= _GetPurchasedTabsSize()) { TC_LOG_ERROR("guild", "Invalid tab for item (GUID: %u, id: #%u) in guild bank, skipped.", diff --git a/src/server/game/Guilds/GuildMgr.cpp b/src/server/game/Guilds/GuildMgr.cpp index 4c1fc45c5f9..938f317eb65 100644 --- a/src/server/game/Guilds/GuildMgr.cpp +++ b/src/server/game/Guilds/GuildMgr.cpp @@ -418,9 +418,9 @@ void GuildMgr::LoadGuilds() // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4, // 29 30 31 32 33 34 35 36 37 38 39 40 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3 - // 41 42 - // fixedScalingLevel, artifactKnowledgeLevel - // 43 44 45 + // 41 42 43 44 45 + // fixedScalingLevel, artifactKnowledgeLevel, iz.xp, iz.level, iz.knowledgeLevel + // 46 47 48 // guildid, TabId, SlotId FROM guild_bank_item gbi INNER JOIN item_instance ii ON gbi.item_guid = ii.guid PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_BANK_ITEMS)); @@ -434,7 +434,7 @@ void GuildMgr::LoadGuilds() do { Field* fields = result->Fetch(); - uint64 guildId = fields[43].GetUInt64(); + uint64 guildId = fields[46].GetUInt64(); if (Guild* guild = GetGuildById(guildId)) guild->LoadBankItemFromDB(fields); diff --git a/src/server/game/Maps/MapScripts.cpp b/src/server/game/Maps/MapScripts.cpp index 2e886a287c4..1819b2e6739 100644 --- a/src/server/game/Maps/MapScripts.cpp +++ b/src/server/game/Maps/MapScripts.cpp @@ -44,7 +44,7 @@ void Map::ScriptsStart(ScriptMapMap const& scripts, uint32 id, Object* source, O // prepare static data ObjectGuid sourceGUID = source ? source->GetGUID() : ObjectGuid::Empty; //some script commands doesn't have source ObjectGuid targetGUID = target ? target->GetGUID() : ObjectGuid::Empty; - ObjectGuid ownerGUID = (source && source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : ObjectGuid::Empty; + ObjectGuid ownerGUID = (source && source->isType(TYPEMASK_ITEM)) ? ((Item*)source)->GetOwnerGUID() : ObjectGuid::Empty; ///- Schedule script execution for all scripts in the script map ScriptMap const* s2 = &(s->second); @@ -79,7 +79,7 @@ void Map::ScriptCommandStart(ScriptInfo const& script, uint32 delay, Object* sou // prepare static data ObjectGuid sourceGUID = source ? source->GetGUID() : ObjectGuid::Empty; ObjectGuid targetGUID = target ? target->GetGUID() : ObjectGuid::Empty; - ObjectGuid ownerGUID = (source && source->GetTypeId() == TYPEID_ITEM) ? ((Item*)source)->GetOwnerGUID() : ObjectGuid::Empty; + ObjectGuid ownerGUID = (source && source->isType(TYPEMASK_ITEM)) ? ((Item*)source)->GetOwnerGUID() : ObjectGuid::Empty; ScriptAction sa; sa.sourceGUID = sourceGUID; diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index a2ae7c74113..b4a22e1dd48 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -23,6 +23,7 @@ #include "ArtifactPackets.h" #include "AuctionHousePackets.h" #include "AuthenticationPackets.h" +#include "AzeriteItemPackets.h" #include "BankPackets.h" #include "BlackMarketPackets.h" #include "BattlefieldPackets.h" diff --git a/src/server/game/Server/Packets/AzeriteItemPackets.cpp b/src/server/game/Server/Packets/AzeriteItemPackets.cpp new file mode 100644 index 00000000000..d66035a3ab6 --- /dev/null +++ b/src/server/game/Server/Packets/AzeriteItemPackets.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> + * + * 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 "AzeriteItemPackets.h" + +WorldPacket const* WorldPackets::AzeriteItem::AzeriteXpGain::Write() +{ + _worldPacket << ItemGUID; + _worldPacket << uint64(XP); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/AzeriteItemPackets.h b/src/server/game/Server/Packets/AzeriteItemPackets.h new file mode 100644 index 00000000000..d8862f707bd --- /dev/null +++ b/src/server/game/Server/Packets/AzeriteItemPackets.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2008-2019 TrinityCore <https://www.trinitycore.org/> + * + * 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 AzeriteItemPackets_h__ +#define AzeriteItemPackets_h__ + +#include "Packet.h" +#include "ObjectGuid.h" + +namespace WorldPackets +{ + namespace AzeriteItem + { + class AzeriteXpGain final : public ServerPacket + { + public: + AzeriteXpGain() : ServerPacket(SMSG_AZERITE_XP_GAIN, 16 + 8) { } + + WorldPacket const* Write() override; + + ObjectGuid ItemGUID; + uint64 XP = 0; + }; + } +} + +#endif // AzeriteItemPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 72638402eb8..b26656010ca 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -952,7 +952,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_AZERITE_ESSENCE_FORGE_CLOSE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AZERITE_ESSENCE_FORGE_OPENED, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AZERITE_ESSENCE_SELECTION_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_AZERITE_XP_GAIN, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AZERITE_XP_GAIN, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BAN_REASON, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BARBER_SHOP_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEFIELD_LIST, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/scripts/Spells/spell_item.cpp b/src/server/scripts/Spells/spell_item.cpp index 4b6a39f978b..d54a0411009 100644 --- a/src/server/scripts/Spells/spell_item.cpp +++ b/src/server/scripts/Spells/spell_item.cpp @@ -4769,6 +4769,32 @@ public: } }; +// 277253 - Heart of Azeroth +class spell_item_heart_of_azeroth : public AuraScript +{ + PrepareAuraScript(spell_item_heart_of_azeroth); + + void SetEquippedFlag(AuraEffect const* /*effect*/, AuraEffectHandleModes /*mode*/) + { + if (Player* target = GetTarget()->ToPlayer()) + if (Item* item = target->GetItemByGuid(GetAura()->GetCastItemGUID())) + item->AddItemFlag2(ITEM_FIELD_FLAG2_HEART_OF_AZEROTH_EQUIPPED); + } + + void ClearEquippedFlag(AuraEffect const* /*effect*/, AuraEffectHandleModes /*mode*/) + { + if (Player* target = GetTarget()->ToPlayer()) + if (Item* item = target->GetItemByGuid(GetAura()->GetCastItemGUID())) + item->RemoveItemFlag2(ITEM_FIELD_FLAG2_HEART_OF_AZEROTH_EQUIPPED); + } + + void Register() + { + OnEffectApply += AuraEffectApplyFn(spell_item_heart_of_azeroth::SetEquippedFlag, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + OnEffectRemove += AuraEffectRemoveFn(spell_item_heart_of_azeroth::ClearEquippedFlag, EFFECT_0, SPELL_AURA_DUMMY, AURA_EFFECT_HANDLE_REAL); + } +}; + void AddSC_item_spell_scripts() { // 23074 Arcanite Dragonling @@ -4885,7 +4911,9 @@ void AddSC_item_spell_scripts() new spell_item_world_queller_focus(); new spell_item_water_strider(); new spell_item_brutal_kinship(); - + new spell_item_mad_alchemists_potion(); new spell_item_crazy_alchemists_potion(); + + RegisterAuraScript(spell_item_heart_of_azeroth); } |