aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp14
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.h4
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp10
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h6
-rw-r--r--src/server/game/Achievements/CriteriaHandler.cpp4
-rw-r--r--src/server/game/DataStores/DB2LoadInfo.h44
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp12
-rw-r--r--src/server/game/DataStores/DB2Stores.h3
-rw-r--r--src/server/game/DataStores/DB2Structure.h20
-rw-r--r--src/server/game/DataStores/DBCEnums.h1
-rw-r--r--src/server/game/Entities/Item/AzeriteItem/AzeriteItem.cpp259
-rw-r--r--src/server/game/Entities/Item/AzeriteItem/AzeriteItem.h52
-rw-r--r--src/server/game/Entities/Item/Container/Bag.h5
-rw-r--r--src/server/game/Entities/Item/Item.cpp16
-rw-r--r--src/server/game/Entities/Item/Item.h14
-rw-r--r--src/server/game/Entities/Item/ItemTemplate.h5
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.cpp20
-rw-r--r--src/server/game/Entities/Object/Updates/UpdateFields.h17
-rw-r--r--src/server/game/Entities/Player/Player.cpp26
-rw-r--r--src/server/game/Guilds/Guild.cpp4
-rw-r--r--src/server/game/Guilds/GuildMgr.cpp8
-rw-r--r--src/server/game/Maps/MapScripts.cpp4
-rw-r--r--src/server/game/Server/Packets/AllPackets.h1
-rw-r--r--src/server/game/Server/Packets/AzeriteItemPackets.cpp26
-rw-r--r--src/server/game/Server/Packets/AzeriteItemPackets.h41
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/scripts/Spells/spell_item.cpp30
27 files changed, 596 insertions, 52 deletions
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);
}