diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index d3ff40ff5..8be6e8725 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -923,6 +923,13 @@ namespace Framework.Constants First = NoLinkRequired | DontCountFirstBonusRank, } + public enum AzeriteItemMilestoneType + { + MajorEssence = 0, + MinorEssence = 1, + BonusStamina = 2 + } + public enum BattlegroundBracketId // bracketId for level ranges { First = 0, diff --git a/Source/Framework/Constants/ItemConst.cs b/Source/Framework/Constants/ItemConst.cs index f31a63d5b..07ccab93f 100644 --- a/Source/Framework/Constants/ItemConst.cs +++ b/Source/Framework/Constants/ItemConst.cs @@ -1170,4 +1170,20 @@ namespace Framework.Constants Invalid } + + public enum AzeriteEssenceActivateResult + { + None = 0, + EssenceNotUnlocked = 2, // Arg: AzeriteEssenceID + CantDoThatRightNow = 3, + AffectingCombat = 4, + CantRemoveEssence = 5, // Arg: SpellID of active essence on cooldown + ChallengeModeActive = 6, + NotInRestArea = 7, + ConditionFailed = 8, + SlotLocked = 9, + NotAtForge = 10, + HeartLevelTooLow = 11, // Arg: RequiredLevel + NotEquipped = 12 + } } diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index ac7b11fa6..6f7e09412 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -69,6 +69,8 @@ namespace Framework.Constants public const uint ItemIdHeartOfAzeroth = 158075; public const uint MaxAzeriteItemLevel = 70; public const uint MaxAzeriteItemKnowledgeLevel = 30; + public const uint PlayerConditionIdUnlockedAzeriteEssences = 69048; + public const uint SpellIdHeartEssenceActionBarOverride = 298554; } public struct MoneyConstants diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index 1dd8256ef..fe0a766d5 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -40,6 +40,8 @@ namespace Framework.Constants public const int MaxWorldMapOverlayArea = 4; public const int MaxMountCapabilities = 24; public const int MaxLockCase = 8; + public const int MaxAzeriteEssenceSlot = 3; + public const int MaxAzeriteEssenceRank = 4; /// /// BattlePets Const diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index bfc440ba9..206160017 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -143,7 +143,14 @@ namespace Framework.Database PrepareStatement(CharStatements.SEL_CHARACTER_ACTIONS_SPEC, "SELECT button, action, type FROM character_action WHERE guid = ? AND spec = ? ORDER BY button"); PrepareStatement(CharStatements.SEL_MAILITEMS, "SELECT " + SelectItemInstanceContent + ", ii.owner_guid, m.id FROM mail_items mi INNER JOIN mail m ON mi.mail_id = m.id LEFT 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 m.receiver = ?"); PrepareStatement(CharStatements.SEL_MAILITEMS_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN mail_items mi ON a.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); - PrepareStatement(CharStatements.SEL_MAILITEMS_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN mail_items mi ON iz.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); + PrepareStatement(CharStatements.SEL_MAILITEMS_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel, " + + "iz.selectedAzeriteEssences1specId, iz.selectedAzeriteEssences1azeriteEssenceId1, iz.selectedAzeriteEssences1azeriteEssenceId2, iz.selectedAzeriteEssences1azeriteEssenceId3, " + + "iz.selectedAzeriteEssences2specId, iz.selectedAzeriteEssences2azeriteEssenceId1, iz.selectedAzeriteEssences2azeriteEssenceId2, iz.selectedAzeriteEssences2azeriteEssenceId3, " + + "iz.selectedAzeriteEssences3specId, iz.selectedAzeriteEssences3azeriteEssenceId1, iz.selectedAzeriteEssences3azeriteEssenceId2, iz.selectedAzeriteEssences3azeriteEssenceId3, " + + "iz.selectedAzeriteEssences4specId, iz.selectedAzeriteEssences4azeriteEssenceId1, iz.selectedAzeriteEssences4azeriteEssenceId2, iz.selectedAzeriteEssences4azeriteEssenceId3 " + + "FROM item_instance_azerite iz INNER JOIN mail_items mi ON iz.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, "SELECT iamp.itemGuid, iamp.azeriteItemMilestonePowerId FROM item_instance_azerite_milestone_power iamp INNER JOIN mail_items mi ON iamp.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, "SELECT iaue.itemGuid, iaue.azeriteEssenceId, iaue.`rank` FROM item_instance_azerite_unlocked_essence iaue INNER JOIN mail_items mi ON iaue.itemGuid = mi.item_guid INNER JOIN mail m ON mi.mail_id = m.id WHERE m.receiver = ?"); PrepareStatement(CharStatements.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"); PrepareStatement(CharStatements.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"); PrepareStatement(CharStatements.INS_AUCTION, "INSERT INTO auctionhouse (id, auctioneerguid, itemguid, itemowner, buyoutprice, time, buyguid, lastbid, startbid, deposit) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); @@ -188,11 +195,26 @@ namespace Framework.Database PrepareStatement(CharStatements.INS_ITEM_INSTANCE_MODIFIERS, "INSERT INTO item_instance_modifiers (itemGuid, fixedScalingLevel, artifactKnowledgeLevel) VALUES (?, ?, ?)"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_MODIFIERS, "DELETE FROM item_instance_modifiers WHERE itemGuid = ?"); PrepareStatement(CharStatements.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 = ?"); - PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN character_inventory ci ON iz.itemGuid = ci.item WHERE ci.guid = ?"); - PrepareStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE, "INSERT INTO item_instance_azerite (itemGuid, xp, level, knowledgeLevel) VALUES (?, ?, ?, ?)"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE, "SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel, " + + "iz.selectedAzeriteEssences1specId, iz.selectedAzeriteEssences1azeriteEssenceId1, iz.selectedAzeriteEssences1azeriteEssenceId2, iz.selectedAzeriteEssences1azeriteEssenceId3, " + + "iz.selectedAzeriteEssences2specId, iz.selectedAzeriteEssences2azeriteEssenceId1, iz.selectedAzeriteEssences2azeriteEssenceId2, iz.selectedAzeriteEssences2azeriteEssenceId3, " + + "iz.selectedAzeriteEssences3specId, iz.selectedAzeriteEssences3azeriteEssenceId1, iz.selectedAzeriteEssences3azeriteEssenceId2, iz.selectedAzeriteEssences3azeriteEssenceId3, " + + "iz.selectedAzeriteEssences4specId, iz.selectedAzeriteEssences4azeriteEssenceId1, iz.selectedAzeriteEssences4azeriteEssenceId2, iz.selectedAzeriteEssences4azeriteEssenceId3 " + + "FROM item_instance_azerite iz INNER JOIN character_inventory ci ON iz.itemGuid = ci.item WHERE ci.guid = ?"); + PrepareStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE, "INSERT INTO item_instance_azerite (itemGuid, xp, level, knowledgeLevel, selectedAzeriteEssences1specId, selectedAzeriteEssences1azeriteEssenceId1, selectedAzeriteEssences1azeriteEssenceId2, selectedAzeriteEssences1azeriteEssenceId3, " + + "selectedAzeriteEssences2specId, selectedAzeriteEssences2azeriteEssenceId1, selectedAzeriteEssences2azeriteEssenceId2, selectedAzeriteEssences2azeriteEssenceId3, selectedAzeriteEssences3specId, selectedAzeriteEssences3azeriteEssenceId1, selectedAzeriteEssences3azeriteEssenceId2, selectedAzeriteEssences3azeriteEssenceId3, " + + "selectedAzeriteEssences4specId, selectedAzeriteEssences4azeriteEssenceId1, selectedAzeriteEssences4azeriteEssenceId2, selectedAzeriteEssences4azeriteEssenceId3) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.UPD_ITEM_INSTANCE_AZERITE_ON_LOAD, "UPDATE item_instance_azerite SET xp = ?, knowledgeLevel = ? WHERE itemGuid = ?"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE, "DELETE FROM item_instance_azerite WHERE itemGuid = ?"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_BY_OWNER, "DELETE iz FROM item_instance_azerite iz LEFT JOIN item_instance ii ON iz.itemGuid = ii.guid WHERE ii.owner_guid = ?"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, "SELECT iamp.itemGuid, iamp.azeriteItemMilestonePowerId FROM item_instance_azerite_milestone_power iamp INNER JOIN character_inventory ci ON iamp.itemGuid = ci.item WHERE ci.guid = ?"); + PrepareStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, "INSERT INTO item_instance_azerite_milestone_power (itemGuid, azeriteItemMilestonePowerId) VALUES (?, ?)"); + PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, "DELETE FROM item_instance_azerite_milestone_power WHERE itemGuid = ?"); + PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER_BY_OWNER, "DELETE iamp FROM item_instance_azerite_milestone_power iamp LEFT JOIN item_instance ii ON iamp.itemGuid = ii.guid WHERE ii.owner_guid = ?"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, "SELECT iaue.itemGuid, iaue.azeriteEssenceId, iaue.`rank` FROM item_instance_azerite_unlocked_essence iaue INNER JOIN character_inventory ci ON iaue.itemGuid = ci.item WHERE ci.guid = ?"); + PrepareStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, "INSERT INTO item_instance_azerite_unlocked_essence (itemGuid, azeriteEssenceId, `rank`) VALUES (?, ?, ?)"); + PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, "DELETE FROM item_instance_azerite_unlocked_essence WHERE itemGuid = ?"); + PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE_BY_OWNER, "DELETE iaue FROM item_instance_azerite_unlocked_essence iaue LEFT JOIN item_instance ii ON iaue.itemGuid = ii.guid WHERE ii.owner_guid = ?"); PrepareStatement(CharStatements.UPD_GIFT_OWNER, "UPDATE character_gifts SET guid = ? WHERE item_guid = ?"); PrepareStatement(CharStatements.DEL_GIFT, "DELETE FROM character_gifts WHERE item_guid = ?"); PrepareStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM, "SELECT entry, flags FROM character_gifts WHERE item_guid = ?"); @@ -838,6 +860,8 @@ namespace Framework.Database SEL_MAILITEMS, SEL_MAILITEMS_ARTIFACT, SEL_MAILITEMS_AZERITE, + SEL_MAILITEMS_AZERITE_MILESTONE_POWER, + SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE, SEL_AUCTION_ITEMS, INS_AUCTION, DEL_AUCTION, @@ -885,6 +909,14 @@ namespace Framework.Database UPD_ITEM_INSTANCE_AZERITE_ON_LOAD, DEL_ITEM_INSTANCE_AZERITE, DEL_ITEM_INSTANCE_AZERITE_BY_OWNER, + SEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, + INS_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, + DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER, + DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER_BY_OWNER, + SEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, + INS_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, + DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE, + DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE_BY_OWNER, UPD_GIFT_OWNER, DEL_GIFT, SEL_CHARACTER_GIFT_BY_ITEM, diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index e79fcc6d3..536ca213d 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -100,15 +100,29 @@ namespace Framework.Database PrepareStatement(HotfixStatements.SEL_AUCTION_HOUSE, "SELECT ID, Name, FactionID, DepositRate, ConsignmentRate FROM auction_house ORDER BY ID DESC"); PrepareStatement(HotfixStatements.SEL_AUCTION_HOUSE_LOCALE, "SELECT ID, Name_lang FROM auction_house_locale WHERE locale = ?"); + // AzeriteEssence.db2 + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE, "SELECT Name, Description, ID, SpecSetID FROM azerite_essence ORDER BY ID DESC"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_LOCALE, "SELECT ID, Name_lang, Description_lang FROM azerite_essence_locale WHERE locale = ?"); + + // AzeriteEssencePower.db2 + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_POWER, "SELECT ID, SourceAlliance, SourceHorde, AzeriteEssenceID, Tier, MajorPowerDescription, " + + "MinorPowerDescription, MajorPowerActual, MinorPowerActual FROM azerite_essence_power ORDER BY ID DESC"); + PrepareStatement(HotfixStatements.SEL_AZERITE_ESSENCE_POWER_LOCALE, "SELECT ID, SourceAlliance_lang, SourceHorde_lang FROM azerite_essence_power_locale WHERE locale = ?"); + // AzeriteItem.db2 PrepareStatement(HotfixStatements.SEL_AZERITE_ITEM, "SELECT ID, ItemID FROM azerite_item ORDER BY ID DESC"); + // AzeriteItemMilestonePower.db2 + PrepareStatement(HotfixStatements.SEL_AZERITE_ITEM_MILESTONE_POWER, "SELECT ID, RequiredLevel, AzeritePowerID, Type, AutoUnlock FROM azerite_item_milestone_power ORDER BY ID DESC"); + // AzeriteKnowledgeMultiplier.db2 PrepareStatement(HotfixStatements.SEL_AZERITE_KNOWLEDGE_MULTIPLIER, "SELECT ID, Multiplier FROM azerite_knowledge_multiplier ORDER BY ID DESC"); // AzeriteLevelInfo.db2 - PrepareStatement(HotfixStatements.SEL_AZERITE_LEVEL_INFO, "SELECT ID, BaseExperienceToNextLevel, MinimumExperienceToNextLevel, ItemLevel" + - " FROM azerite_level_info ORDER BY ID DESC"); + PrepareStatement(HotfixStatements.SEL_AZERITE_LEVEL_INFO, "SELECT ID, BaseExperienceToNextLevel, MinimumExperienceToNextLevel, ItemLevel FROM azerite_level_info ORDER BY ID DESC"); + + // AzeritePower.db2 + PrepareStatement(HotfixStatements.SEL_AZERITE_POWER, "SELECT ID, SpellID, ItemBonusListID, SpecSetID, Flags FROM azerite_power ORDER BY ID DESC"); // BankBagSlotPrices.db2 PrepareStatement(HotfixStatements.SEL_BANK_BAG_SLOT_PRICES, "SELECT ID, Cost FROM bank_bag_slot_prices ORDER BY ID DESC"); @@ -831,6 +845,9 @@ namespace Framework.Database " FROM specialization_spells ORDER BY ID DESC"); PrepareStatement(HotfixStatements.SEL_SPECIALIZATION_SPELLS_LOCALE, "SELECT ID, Description_lang FROM specialization_spells_locale WHERE locale = ?"); + // SpecSetMember.db2 + PrepareStatement(HotfixStatements.SEL_SPEC_SET_MEMBER, "SELECT ID, ChrSpecializationID, SpecSetID FROM spec_set_member ORDER BY ID DESC"); + // SpellAuraOptions.db2 PrepareStatement(HotfixStatements.SEL_SPELL_AURA_OPTIONS, "SELECT ID, DifficultyID, CumulativeAura, ProcCategoryRecovery, ProcChance, ProcCharges, " + "SpellProcsPerMinuteID, ProcTypeMask1, ProcTypeMask2, SpellID FROM spell_aura_options ORDER BY ID DESC"); @@ -1137,12 +1154,22 @@ namespace Framework.Database SEL_AUCTION_HOUSE, SEL_AUCTION_HOUSE_LOCALE, + SEL_AZERITE_ESSENCE, + SEL_AZERITE_ESSENCE_LOCALE, + + SEL_AZERITE_ESSENCE_POWER, + SEL_AZERITE_ESSENCE_POWER_LOCALE, + SEL_AZERITE_ITEM, + SEL_AZERITE_ITEM_MILESTONE_POWER, + SEL_AZERITE_KNOWLEDGE_MULTIPLIER, SEL_AZERITE_LEVEL_INFO, + SEL_AZERITE_POWER, + SEL_BANK_BAG_SLOT_PRICES, SEL_BANNED_ADDONS, @@ -1506,6 +1533,8 @@ namespace Framework.Database SEL_SPECIALIZATION_SPELLS, SEL_SPECIALIZATION_SPELLS_LOCALE, + SEL_SPEC_SET_MEMBER, + SEL_SPELL_AURA_OPTIONS, SEL_SPELL_AURA_RESTRICTIONS, diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index 03a58106b..40515e06a 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -1652,10 +1652,11 @@ namespace Game.Achievements return false; break; case CriteriaAdditionalCondition.RewardedQuest: // 110 - if (!referencePlayer.GetQuestRewardStatus(reqValue)) + uint questBit = Global.DB2Mgr.GetQuestUniqueBitFlag(reqValue); + if (questBit != 0) + if ((referencePlayer.m_activePlayerData.QuestCompleted[((int)questBit - 1) >> 6] & (1ul << (((int)questBit - 1) & 63))) == 0) return false; break; - case CriteriaAdditionalCondition.CompletedQuest: // 111 if (referencePlayer.GetQuestStatus(reqValue) != QuestStatus.Complete) return false; @@ -2293,7 +2294,7 @@ namespace Game.Achievements case CriteriaAdditionalCondition.AzeriteItemLevel: // 235 { Item heartOfAzeroth = referencePlayer.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); - if (!heartOfAzeroth || heartOfAzeroth.ToAzeriteItem().m_azeriteItemData.Level < reqValue) + if (!heartOfAzeroth || heartOfAzeroth.ToAzeriteItem().GetLevel() < reqValue) return false; break; } diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index d056d6e9f..f99892d42 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -54,9 +54,13 @@ namespace Game.DataStorage ArtifactTierStorage = DBReader.Read("ArtifactTier.db2", HotfixStatements.SEL_ARTIFACT_TIER); ArtifactUnlockStorage = DBReader.Read("ArtifactUnlock.db2", HotfixStatements.SEL_ARTIFACT_UNLOCK); AuctionHouseStorage = DBReader.Read("AuctionHouse.db2", HotfixStatements.SEL_AUCTION_HOUSE, HotfixStatements.SEL_AUCTION_HOUSE_LOCALE); + AzeriteEssenceStorage = DBReader.Read("AzeriteEssence.db2", HotfixStatements.SEL_AZERITE_ESSENCE, HotfixStatements.SEL_AZERITE_ESSENCE_LOCALE); + AzeriteEssencePowerStorage = DBReader.Read("AzeriteEssencePower.db2", HotfixStatements.SEL_AZERITE_ESSENCE_POWER, HotfixStatements.SEL_AZERITE_ESSENCE_POWER_LOCALE); AzeriteItemStorage = DBReader.Read("AzeriteItem.db2", HotfixStatements.SEL_AZERITE_ITEM); + AzeriteItemMilestonePowerStorage = DBReader.Read("AzeriteItemMilestonePower.db2", HotfixStatements.SEL_AZERITE_ITEM_MILESTONE_POWER); AzeriteKnowledgeMultiplierStorage = DBReader.Read("AzeriteKnowledgeMultiplier.db2", HotfixStatements.SEL_AZERITE_KNOWLEDGE_MULTIPLIER); AzeriteLevelInfoStorage = DBReader.Read("AzeriteLevelInfo.db2", HotfixStatements.SEL_AZERITE_LEVEL_INFO); + AzeritePowerStorage = DBReader.Read("AzeritePower.db2", HotfixStatements.SEL_AZERITE_POWER); BankBagSlotPricesStorage = DBReader.Read("BankBagSlotPrices.db2", HotfixStatements.SEL_BANK_BAG_SLOT_PRICES); //BannedAddOnsStorage = DBReader.Read("BannedAddons.db2", HotfixStatements.SEL_BANNED_ADDONS); BarberShopStyleStorage = DBReader.Read("BarberShopStyle.db2", HotfixStatements.SEL_BARBER_SHOP_STYLE, HotfixStatements.SEL_BARBER_SHOP_STYLE_LOCALE); @@ -218,6 +222,7 @@ namespace Game.DataStorage SkillRaceClassInfoStorage = DBReader.Read("SkillRaceClassInfo.db2", HotfixStatements.SEL_SKILL_RACE_CLASS_INFO); SoundKitStorage = DBReader.Read("SoundKit.db2", HotfixStatements.SEL_SOUND_KIT); SpecializationSpellsStorage = DBReader.Read("SpecializationSpells.db2", HotfixStatements.SEL_SPECIALIZATION_SPELLS, HotfixStatements.SEL_SPECIALIZATION_SPELLS_LOCALE); + SpecSetMemberStorage = DBReader.Read("SpecSetMember.db2", HotfixStatements.SEL_SPEC_SET_MEMBER); SpellNameStorage = DBReader.Read("SpellName.db2", HotfixStatements.SEL_SPELL_NAME, HotfixStatements.SEL_SPELL_NAME_LOCALE); SpellAuraOptionsStorage = DBReader.Read("SpellAuraOptions.db2", HotfixStatements.SEL_SPELL_AURA_OPTIONS); SpellAuraRestrictionsStorage = DBReader.Read("SpellAuraRestrictions.db2", HotfixStatements.SEL_SPELL_AURA_RESTRICTIONS); @@ -400,9 +405,13 @@ namespace Game.DataStorage public static DB6Storage ArtifactTierStorage; public static DB6Storage ArtifactUnlockStorage; public static DB6Storage AuctionHouseStorage; + public static DB6Storage AzeriteEssenceStorage; + public static DB6Storage AzeriteEssencePowerStorage; public static DB6Storage AzeriteItemStorage; + public static DB6Storage AzeriteItemMilestonePowerStorage; public static DB6Storage AzeriteKnowledgeMultiplierStorage; public static DB6Storage AzeriteLevelInfoStorage; + public static DB6Storage AzeritePowerStorage; public static DB6Storage BankBagSlotPricesStorage; //public static DB6Storage BannedAddOnsStorage; public static DB6Storage BarberShopStyleStorage; @@ -564,6 +573,7 @@ namespace Game.DataStorage public static DB6Storage SkillRaceClassInfoStorage; public static DB6Storage SoundKitStorage; public static DB6Storage SpecializationSpellsStorage; + public static DB6Storage SpecSetMemberStorage; public static DB6Storage SpellAuraOptionsStorage; public static DB6Storage SpellAuraRestrictionsStorage; public static DB6Storage SpellCastTimesStorage; diff --git a/Source/Game/DataStorage/DB2Manager.cs b/Source/Game/DataStorage/DB2Manager.cs index 6a05bf280..09dcb3e30 100644 --- a/Source/Game/DataStorage/DB2Manager.cs +++ b/Source/Game/DataStorage/DB2Manager.cs @@ -59,10 +59,30 @@ namespace Game.DataStorage CliDB.ArtifactPowerLinkStorage.Clear(); foreach (ArtifactPowerRankRecord artifactPowerRank in CliDB.ArtifactPowerRankStorage.Values) - _artifactPowerRanks[Tuple.Create((uint)artifactPowerRank.ArtifactPowerID, artifactPowerRank.RankIndex)] = artifactPowerRank; + _artifactPowerRanks[Tuple.Create(artifactPowerRank.ArtifactPowerID, artifactPowerRank.RankIndex)] = artifactPowerRank; CliDB.ArtifactPowerRankStorage.Clear(); + foreach (AzeriteEssencePowerRecord azeriteEssencePower in CliDB.AzeriteEssencePowerStorage.Values) + _azeriteEssencePowersByIdAndRank[Tuple.Create((uint)azeriteEssencePower.AzeriteEssenceID, (uint)azeriteEssencePower.Tier)] = azeriteEssencePower; + + foreach (AzeriteItemMilestonePowerRecord azeriteItemMilestonePower in CliDB.AzeriteItemMilestonePowerStorage.Values) + _azeriteItemMilestonePowers.Add(azeriteItemMilestonePower); + + _azeriteItemMilestonePowers = _azeriteItemMilestonePowers.OrderBy(p => p.RequiredLevel).ToList(); + + uint azeriteEssenceSlot = 0; + foreach (AzeriteItemMilestonePowerRecord azeriteItemMilestonePower in _azeriteItemMilestonePowers) + { + AzeriteItemMilestoneType type = (AzeriteItemMilestoneType)azeriteItemMilestonePower.Type; + if (type == AzeriteItemMilestoneType.MajorEssence || type == AzeriteItemMilestoneType.MinorEssence) + { + //ASSERT(azeriteEssenceSlot < MAX_AZERITE_ESSENCE_SLOT); + _azeriteItemMilestonePowerByEssenceSlot[azeriteEssenceSlot] = azeriteItemMilestonePower; + ++azeriteEssenceSlot; + } + } + foreach (CharacterFacialHairStylesRecord characterFacialStyle in CliDB.CharacterFacialHairStylesStorage.Values) _characterFacialHairStyles.Add(Tuple.Create(characterFacialStyle.RaceID, characterFacialStyle.SexID, (uint)characterFacialStyle.VariationID)); @@ -417,6 +437,9 @@ namespace Game.DataStorage CliDB.SpecializationSpellsStorage.Clear(); + foreach (SpecSetMemberRecord specSetMember in CliDB.SpecSetMemberStorage.Values) + _specsBySpecSet.Add(Tuple.Create((int)specSetMember.SpecSetID, (uint)specSetMember.ChrSpecializationID)); + foreach (SpellClassOptionsRecord classOption in CliDB.SpellClassOptionsStorage.Values) _spellFamilyNames.Add(classOption.SpellClassSet); @@ -727,6 +750,22 @@ namespace Game.DataStorage return CliDB.AzeriteItemStorage.Any(pair => pair.Value.ItemID == itemId); } + public AzeriteEssencePowerRecord GetAzeriteEssencePower(uint azeriteEssenceId, uint rank) + { + return _azeriteEssencePowersByIdAndRank.LookupByKey((azeriteEssenceId, rank)); + } + + public List GetAzeriteItemMilestonePowers() + { + return _azeriteItemMilestonePowers; + } + + public AzeriteItemMilestonePowerRecord GetAzeriteItemMilestonePower(int slot) + { + //ASSERT(slot < MAX_AZERITE_ESSENCE_SLOT, "Slot %u must be lower than MAX_AZERITE_ESSENCE_SLOT (%u)", uint32(slot), MAX_AZERITE_ESSENCE_SLOT); + return _azeriteItemMilestonePowerByEssenceSlot[slot]; + } + public string GetBroadcastTextValue(BroadcastTextRecord broadcastText, LocaleConstant locale = LocaleConstant.enUS, Gender gender = Gender.Male, bool forceGender = false) { if ((gender == Gender.Female || gender == Gender.None) && (forceGender || broadcastText.Text1.HasString(SharedConst.DefaultLocale))) @@ -1549,6 +1588,11 @@ namespace Game.DataStorage return _specializationSpellsBySpec.LookupByKey(specId); } + public bool IsSpecSetMember(int specSetId, uint specId) + { + return _specsBySpecSet.Contains(Tuple.Create(specSetId, specId)); + } + bool IsValidSpellFamiliyName(SpellFamilyNames family) { return _spellFamilyNames.Contains((byte)family); @@ -1938,6 +1982,9 @@ namespace Game.DataStorage MultiMap _artifactPowers = new MultiMap(); MultiMap _artifactPowerLinks = new MultiMap(); Dictionary, ArtifactPowerRankRecord> _artifactPowerRanks = new Dictionary, ArtifactPowerRankRecord>(); + Dictionary, AzeriteEssencePowerRecord> _azeriteEssencePowersByIdAndRank = new Dictionary, AzeriteEssencePowerRecord>(); + List _azeriteItemMilestonePowers = new List(); + AzeriteItemMilestonePowerRecord[] _azeriteItemMilestonePowerByEssenceSlot = new AzeriteItemMilestonePowerRecord[SharedConst.MaxAzeriteEssenceSlot]; List> _characterFacialHairStyles = new List>(); MultiMap, CharSectionsRecord> _charSections = new MultiMap, CharSectionsRecord>(); Dictionary _charStartOutfits = new Dictionary(); @@ -1981,6 +2028,7 @@ namespace Game.DataStorage MultiMap _skillLineAbilitiesBySkillupSkill = new MultiMap(); MultiMap _skillRaceClassInfoBySkill = new MultiMap(); MultiMap _specializationSpellsBySpec = new MultiMap(); + List> _specsBySpecSet = new List>(); List _spellFamilyNames = new List(); Dictionary> _spellPowers = new Dictionary>(); Dictionary>> _spellPowerDifficulties = new Dictionary>>(); diff --git a/Source/Game/DataStorage/Structs/A_Records.cs b/Source/Game/DataStorage/Structs/A_Records.cs index 784aff753..818f20bfe 100644 --- a/Source/Game/DataStorage/Structs/A_Records.cs +++ b/Source/Game/DataStorage/Structs/A_Records.cs @@ -254,12 +254,42 @@ namespace Game.DataStorage public byte ConsignmentRate; } + public sealed class AzeriteEssenceRecord + { + public string Name; + public string Description; + public uint ID; + public int SpecSetID; + } + + public sealed class AzeriteEssencePowerRecord + { + public uint ID; + public string SourceAlliance; + public string SourceHorde; + public int AzeriteEssenceID; + public byte Tier; + public uint MajorPowerDescription; + public uint MinorPowerDescription; + public uint MajorPowerActual; + public uint MinorPowerActual; + } + public sealed class AzeriteItemRecord { public uint ID; public uint ItemID; } + public sealed class AzeriteItemMilestonePowerRecord + { + public uint ID; + public int RequiredLevel; + public int AzeritePowerID; + public int Type; + public int AutoUnlock; + } + public sealed class AzeriteKnowledgeMultiplierRecord { public uint ID; @@ -273,4 +303,13 @@ namespace Game.DataStorage public ulong MinimumExperienceToNextLevel; public uint ItemLevel; } + + public sealed class AzeritePowerRecord + { + public uint ID; + public uint SpellID; + public int ItemBonusListID; + public int SpecSetID; + public int Flags; + } } diff --git a/Source/Game/DataStorage/Structs/S_Records.cs b/Source/Game/DataStorage/Structs/S_Records.cs index 8c721bb5d..fd32f94c1 100644 --- a/Source/Game/DataStorage/Structs/S_Records.cs +++ b/Source/Game/DataStorage/Structs/S_Records.cs @@ -166,6 +166,13 @@ namespace Game.DataStorage public byte DisplayOrder; } + public sealed class SpecSetMemberRecord + { + public uint ID; + public uint ChrSpecializationID; + public uint SpecSetID; + } + public sealed class SpellAuraOptionsRecord { public uint Id; diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index fe996cbc7..f70b1fe72 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -1890,19 +1890,41 @@ namespace Game.Entities if (!ConditionManager.IsPlayerMeetingCondition(player, playerCondition)) return; - Aura artifactAura = player.GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); - Item item = artifactAura != null ? player.GetItemByGuid(artifactAura.GetCastItemGUID()) : null; - if (!item) + switch (info.ItemForge.ForgeType) { - player.SendPacket(new DisplayGameError(GameError.MustEquipArtifact)); - return; - } + case 0: // Artifact Forge + case 1: // Relic Forge + { - ArtifactForgeOpened artifactForgeOpened = new ArtifactForgeOpened(); - artifactForgeOpened.ArtifactGUID = item.GetGUID(); - artifactForgeOpened.ForgeGUID = GetGUID(); - player.SendPacket(artifactForgeOpened); - return; + Aura artifactAura = player.GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); + Item item = artifactAura != null ? player.GetItemByGuid(artifactAura.GetCastItemGUID()) : null; + if (!item) + { + player.SendPacket(new DisplayGameError(GameError.MustEquipArtifact)); + return; + } + + ArtifactForgeOpened artifactForgeOpened = new ArtifactForgeOpened(); + artifactForgeOpened.ArtifactGUID = item.GetGUID(); + artifactForgeOpened.ForgeGUID = GetGUID(); + player.SendPacket(artifactForgeOpened); + break; + } + case 2: // Heart Forge + { + Item item = player.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); + if (!item) + return; + + AzeriteEssenceForgeOpened azeriteEssenceForgeOpened = new AzeriteEssenceForgeOpened(); + azeriteEssenceForgeOpened.ForgeGUID = GetGUID(); + player.SendPacket(azeriteEssenceForgeOpened); + break; + } + default: + break; + } + break; } case GameObjectTypes.UILink: { diff --git a/Source/Game/Entities/Item/AzeriteItem.cs b/Source/Game/Entities/Item/AzeriteItem.cs index 5b1865678..5724e2974 100644 --- a/Source/Game/Entities/Item/AzeriteItem.cs +++ b/Source/Game/Entities/Item/AzeriteItem.cs @@ -47,6 +47,7 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Level), 1u); SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.KnowledgeLevel), GetCurrentKnowledgeLevel()); + UnlockDefaultMilestones(); return true; } @@ -63,10 +64,49 @@ namespace Game.Entities stmt.AddValue(1, m_azeriteItemData.Xp); stmt.AddValue(2, m_azeriteItemData.Level); stmt.AddValue(3, m_azeriteItemData.KnowledgeLevel); + + int specIndex = 0; + for (; specIndex < m_azeriteItemData.SelectedEssences.Size(); ++specIndex) + { + stmt.AddValue(4 + specIndex * 4, m_azeriteItemData.SelectedEssences[specIndex].SpecializationID); + for (var j = 0; j < SharedConst.MaxAzeriteEssenceSlot; ++j) + stmt.AddValue(5 + specIndex * 4 + j, m_azeriteItemData.SelectedEssences[specIndex].AzeriteEssenceID[j]); + } + for (; specIndex < PlayerConst.MaxSpecializations; ++specIndex) + { + stmt.AddValue(4 + specIndex * 4, 0); + for (var j = 0; j < SharedConst.MaxAzeriteEssenceSlot; ++j) + stmt.AddValue(5 + specIndex * 4 + j, 0); + } trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt.AddValue(0, GetGUID().GetCounter()); + trans.Append(stmt); + + foreach (uint azeriteItemMilestonePowerId in m_azeriteItemData.UnlockedEssenceMilestones) + { + stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, azeriteItemMilestonePowerId); + trans.Append(stmt); + } + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt.AddValue(0, GetGUID().GetCounter()); + trans.Append(stmt); + + foreach (UnlockedAzeriteEssence azeriteEssence in m_azeriteItemData.UnlockedEssences) + { + stmt = DB.Characters.GetPreparedStatement(CharStatements.INS_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt.AddValue(0, GetGUID().GetCounter()); + stmt.AddValue(1, azeriteEssence.AzeriteEssenceID); + stmt.AddValue(2, azeriteEssence.Rank); + trans.Append(stmt); + } } - public void LoadAzeriteItemData(AzeriteData azeriteData) + public void LoadAzeriteItemData(Player owner, AzeriteData azeriteData) { bool needSave = false; @@ -103,6 +143,40 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Level), azeriteData.Level); SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.KnowledgeLevel), azeriteData.KnowledgeLevel); + foreach (uint azeriteItemMilestonePowerId in azeriteData.AzeriteItemMilestonePowers) + AddUnlockedEssenceMilestone(azeriteItemMilestonePowerId); + + UnlockDefaultMilestones(); + + foreach (AzeriteEssencePowerRecord unlockedAzeriteEssence in azeriteData.UnlockedAzeriteEssences) + SetEssenceRank((uint)unlockedAzeriteEssence.AzeriteEssenceID, unlockedAzeriteEssence.Tier); + + foreach (AzeriteItemSelectedEssencesData selectedEssenceData in azeriteData.SelectedAzeriteEssences) + { + if (selectedEssenceData.SpecializationId == 0) + continue; + + var selectedEssences = new SelectedAzeriteEssences(); + selectedEssences.ModifyValue(selectedEssences.SpecializationID).SetValue(selectedEssenceData.SpecializationId); + for (int i = 0; i < SharedConst.MaxAzeriteEssenceSlot; ++i) + { + // Check if essence was unlocked + if (GetEssenceRank(selectedEssenceData.AzeriteEssenceId[i]) == 0) + continue; + + selectedEssences.ModifyValue(selectedEssences.AzeriteEssenceID, i) = selectedEssenceData.AzeriteEssenceId[i]; + } + + if (owner.GetPrimarySpecialization() == selectedEssenceData.SpecializationId) + selectedEssences.ModifyValue(selectedEssences.Enabled).SetValue(1); + + AddDynamicUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.SelectedEssences), selectedEssences); + } + + // add selected essences for current spec + if (GetSelectedAzeriteEssences() == null) + CreateSelectedAzeriteEssences(owner.GetPrimarySpecialization()); + if (needSave) { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_ITEM_INSTANCE_AZERITE_ON_LOAD); @@ -119,16 +193,20 @@ namespace Game.Entities stmt.AddValue(0, GetGUID().GetCounter()); trans.Append(stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt.AddValue(0, GetGUID().GetCounter()); + trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt.AddValue(0, GetGUID().GetCounter()); + trans.Append(stmt); + base.DeleteFromDB(trans); } - public override uint GetItemLevel(Player owner) - { - return CliDB.AzeriteLevelInfoStorage.LookupByKey(m_azeriteItemData.Level).ItemLevel; - } + public uint GetLevel() { return m_azeriteItemData.Level; } - uint GetLevel() { return m_azeriteItemData.Level; } - uint GetEffectiveLevel() + public uint GetEffectiveLevel() { uint level = m_azeriteItemData.AuraLevel; if (level == 0) @@ -193,7 +271,8 @@ namespace Game.Entities if (IsEquipped()) owner._ApplyItemBonuses(this, GetSlot(), false); - SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData. Level), level); + SetUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.Level), level); + UnlockDefaultMilestones(); owner.UpdateCriteria(CriteriaTypes.HeartOfAzerothLevelReached, level); if (IsEquipped()) @@ -209,6 +288,81 @@ namespace Game.Entities owner.SendPacket(xpGain); } + public static GameObject FindHeartForge(Player owner) + { + GameObject forge = owner.FindNearestGameObjectOfType(GameObjectTypes.ItemForge, 40.0f); + if (forge != null) + if (forge.GetGoInfo().ItemForge.ForgeType == 2) + return forge; + + return null; + } + + public bool CanUseEssences() + { + PlayerConditionRecord condition = CliDB.PlayerConditionStorage.LookupByKey(PlayerConst.PlayerConditionIdUnlockedAzeriteEssences); + if (condition != null) + return ConditionManager.IsPlayerMeetingCondition(GetOwner(), condition); + + return false; + } + + public bool HasUnlockedEssenceSlot(byte slot) + { + AzeriteItemMilestonePowerRecord milestone = Global.DB2Mgr.GetAzeriteItemMilestonePower(slot); + return m_azeriteItemData.UnlockedEssenceMilestones.FindIndex(milestone.ID) != -1; + } + + public bool HasUnlockedEssenceMilestone(uint azeriteItemMilestonePowerId) { return m_azeriteItemData.UnlockedEssenceMilestones.FindIndex(azeriteItemMilestonePowerId) != -1; } + + public void AddUnlockedEssenceMilestone(uint azeriteItemMilestonePowerId) + { + AddDynamicUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.UnlockedEssenceMilestones), azeriteItemMilestonePowerId); + } + + public uint GetEssenceRank(uint azeriteEssenceId) + { + int index = m_azeriteItemData.UnlockedEssences.FindIndexIf(essence => + { + return essence.AzeriteEssenceID == azeriteEssenceId; + }); + + if (index < 0) + return 0; + + return m_azeriteItemData.UnlockedEssences[index].Rank; + } + + public void SetEssenceRank(uint azeriteEssenceId, uint rank) + { + int index = m_azeriteItemData.UnlockedEssences.FindIndexIf(essence => + { + return essence.AzeriteEssenceID == azeriteEssenceId; + }); + + if (rank == 0 && index >= 0) + { + RemoveDynamicUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.UnlockedEssences), index); + return; + } + + if (Global.DB2Mgr.GetAzeriteEssencePower(azeriteEssenceId, rank) == null) + return; + + if (index < 0) + { + UnlockedAzeriteEssence unlockedEssence = new UnlockedAzeriteEssence(); + unlockedEssence.AzeriteEssenceID = azeriteEssenceId; + unlockedEssence.Rank = rank; + AddDynamicUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.UnlockedEssences), unlockedEssence); + } + else + { + UnlockedAzeriteEssence actorField = m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.UnlockedEssences, index); + SetUpdateFieldValue(ref actorField.Rank, rank); + } + } + public SelectedAzeriteEssences GetSelectedAzeriteEssences() { foreach (SelectedAzeriteEssences essences in m_azeriteItemData.SelectedEssences) @@ -218,6 +372,38 @@ namespace Game.Entities return null; } + public void SetSelectedAzeriteEssences(uint specializationId) + { + int index = m_azeriteItemData.SelectedEssences.FindIndexIf(essences => { return essences.Enabled == 1; }); + if (index >= 0) + { + SelectedAzeriteEssences selectedEssences = m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.SelectedEssences, index); + SetUpdateFieldValue(selectedEssences.ModifyValue(selectedEssences.Enabled), 0u); + } + + index = m_azeriteItemData.SelectedEssences.FindIndexIf(essences => + { + return essences.SpecializationID == specializationId; + }); + + if (index >= 0) + { + SelectedAzeriteEssences selectedEssences = m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.SelectedEssences, index); + SetUpdateFieldValue(selectedEssences.ModifyValue(selectedEssences.Enabled), 1u); + } + else + CreateSelectedAzeriteEssences(specializationId); + } + + public void SetSelectedAzeriteEssence(int slot, uint azeriteEssenceId) + { + //ASSERT(slot < MAX_AZERITE_ESSENCE_SLOT); + int index = m_azeriteItemData.SelectedEssences.FindIndexIf(essences => { return essences.Enabled == 1; }); + //ASSERT(index >= 0); + SelectedAzeriteEssences selectedEssences = m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.SelectedEssences, index); + SetUpdateFieldValue(ref selectedEssences.ModifyValue(selectedEssences.AzeriteEssenceID, slot), azeriteEssenceId); + } + public override void BuildValuesCreate(WorldPacket data, Player target) { UpdateFieldFlag flags = GetUpdateFieldFlagsFor(target); @@ -277,6 +463,44 @@ namespace Game.Entities m_values.ClearChangesMask(m_azeriteItemData); base.ClearUpdateMask(remove); } + + void UnlockDefaultMilestones() + { + bool hasPreviousMilestone = true; + foreach (AzeriteItemMilestonePowerRecord milestone in Global.DB2Mgr.GetAzeriteItemMilestonePowers()) + { + if (!hasPreviousMilestone) + break; + + if (milestone.RequiredLevel > GetLevel()) + break; + + if (HasUnlockedEssenceMilestone(milestone.ID)) + continue; + + if (milestone.AutoUnlock != 0) + { + AddUnlockedEssenceMilestone(milestone.ID); + hasPreviousMilestone = true; + } + else + hasPreviousMilestone = false; + } + } + + void CreateSelectedAzeriteEssences(uint specializationId) + { + var selectedEssences = new SelectedAzeriteEssences(); + selectedEssences.ModifyValue(selectedEssences.SpecializationID).SetValue(specializationId); + selectedEssences.ModifyValue(selectedEssences.Enabled).SetValue(1); + AddDynamicUpdateFieldValue(m_values.ModifyValue(m_azeriteItemData).ModifyValue(m_azeriteItemData.SelectedEssences), selectedEssences); + } + } + + public class AzeriteItemSelectedEssencesData + { + public uint SpecializationId; + public uint[] AzeriteEssenceId = new uint[SharedConst.MaxAzeriteEssenceSlot]; } public class AzeriteData @@ -284,5 +508,8 @@ namespace Game.Entities public ulong Xp; public uint Level; public uint KnowledgeLevel; + public List AzeriteItemMilestonePowers = new List(); + public List UnlockedAzeriteEssences = new List(); + public AzeriteItemSelectedEssencesData[] SelectedAzeriteEssences = new AzeriteItemSelectedEssencesData[PlayerConst.MaxSpecializations]; } } diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index 754336aba..9f147bb4b 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -1869,22 +1869,33 @@ namespace Game.Entities ItemContainerDeleteLootItemsFromDB(); } - public virtual uint GetItemLevel(Player owner) + public uint GetItemLevel(Player owner) { + ItemTemplate itemTemplate = GetTemplate(); uint minItemLevel = owner.m_unitData.MinItemLevel; uint minItemLevelCutoff = owner.m_unitData.MinItemLevelCutoff; - uint maxItemLevel = GetTemplate().GetFlags3().HasAnyFlag(ItemFlags3.IgnoreItemLevelCapInPvp) ? 0u : owner.m_unitData.MaxItemLevel; + uint maxItemLevel = itemTemplate.GetFlags3().HasAnyFlag(ItemFlags3.IgnoreItemLevelCapInPvp) ? 0u : owner.m_unitData.MaxItemLevel; bool pvpBonus = owner.IsUsingPvpItemLevels(); - return GetItemLevel(GetTemplate(), _bonusData, owner.GetLevel(), GetModifier(ItemModifier.TimewalkerLevel), - minItemLevel, minItemLevelCutoff, maxItemLevel, pvpBonus); + + uint azeriteLevel = 0; + AzeriteItem azeriteItem = ToAzeriteItem(); + if (azeriteItem != null) + azeriteLevel = azeriteItem.GetEffectiveLevel(); + + return GetItemLevel(itemTemplate, _bonusData, owner.GetLevel(), GetModifier(ItemModifier.TimewalkerLevel), + minItemLevel, minItemLevelCutoff, maxItemLevel, pvpBonus, azeriteLevel); } - public static uint GetItemLevel(ItemTemplate itemTemplate, BonusData bonusData, uint level, uint fixedLevel, uint minItemLevel, uint minItemLevelCutoff, uint maxItemLevel, bool pvpBonus) + public static uint GetItemLevel(ItemTemplate itemTemplate, BonusData bonusData, uint level, uint fixedLevel, uint minItemLevel, uint minItemLevelCutoff, uint maxItemLevel, bool pvpBonus, uint azeriteLevel) { if (itemTemplate == null) return 1; uint itemLevel = itemTemplate.GetBaseItemLevel(); + AzeriteLevelInfoRecord azeriteLevelInfo = CliDB.AzeriteLevelInfoStorage.LookupByKey(azeriteLevel); + if (azeriteLevelInfo != null) + itemLevel = azeriteLevelInfo.ItemLevel; + ScalingStatDistributionRecord ssd = CliDB.ScalingStatDistributionStorage.LookupByKey(bonusData.ScalingStatDistribution); if (ssd != null) { @@ -2965,15 +2976,21 @@ namespace Game.Entities public ArtifactData Artifact; public AzeriteData AzeriteItem; - public static void Init(Dictionary loadInfo, SQLResult artifactResult, SQLResult azeriteItemResult) + public static void Init(Dictionary loadInfo, SQLResult artifactResult, SQLResult azeriteItemResult, SQLResult azeriteItemMilestonePowersResult, SQLResult azeriteItemUnlockedEssencesResult) { - // 0 1 2 3 4 5 - // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, a.artifactTierId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid ... + ItemAdditionalLoadInfo GetOrCreateLoadInfo(ulong guid) + { + if (!loadInfo.ContainsKey(guid)) + loadInfo[guid] = new ItemAdditionalLoadInfo(); + + return loadInfo[guid]; + } + if (!artifactResult.IsEmpty()) { do { - ItemAdditionalLoadInfo info = new ItemAdditionalLoadInfo(); + ItemAdditionalLoadInfo info = GetOrCreateLoadInfo(artifactResult.Read(0)); if (info.Artifact == null) info.Artifact = new ArtifactData(); @@ -3001,29 +3018,69 @@ namespace Game.Entities info.Artifact.ArtifactPowers.Add(artifactPowerData); } - loadInfo[artifactResult.Read(0)] = info; - } while (artifactResult.NextRow()); } - // 0 1 2 3 - // SELECT iz.itemGuid, iz.xp, iz.level, iz.knowledgeLevel FROM item_instance_azerite iz INNER JOIN ... if (!azeriteItemResult.IsEmpty()) { do { - ItemAdditionalLoadInfo info = new ItemAdditionalLoadInfo(); + ItemAdditionalLoadInfo info = GetOrCreateLoadInfo(azeriteItemResult.Read(0)); if (info.AzeriteItem == null) info.AzeriteItem = new AzeriteData(); info.AzeriteItem.Xp = azeriteItemResult.Read(1); info.AzeriteItem.Level = azeriteItemResult.Read(2); info.AzeriteItem.KnowledgeLevel = azeriteItemResult.Read(3); + for (int i = 0; i < PlayerConst.MaxSpecializations; ++i) + { + uint specializationId = azeriteItemResult.Read(4 + i * 4); + if (!CliDB.ChrSpecializationStorage.ContainsKey(specializationId)) + continue; - loadInfo[azeriteItemResult.Read(0)] = info; + info.AzeriteItem.SelectedAzeriteEssences[i].SpecializationId = specializationId; + for (int j = 0; j < SharedConst.MaxAzeriteEssenceSlot; ++j) + { + AzeriteEssenceRecord azeriteEssence = CliDB.AzeriteEssenceStorage.LookupByKey(azeriteItemResult.Read(5 + i * 4 + j)); + if (azeriteEssence == null || !Global.DB2Mgr.IsSpecSetMember(azeriteEssence.SpecSetID, specializationId)) + continue; + + info.AzeriteItem.SelectedAzeriteEssences[i].AzeriteEssenceId[j] = azeriteEssence.ID; + } + } } while (azeriteItemResult.NextRow()); } + + if (!azeriteItemMilestonePowersResult.IsEmpty()) + { + do + { + ItemAdditionalLoadInfo info = GetOrCreateLoadInfo(azeriteItemMilestonePowersResult.Read(0)); + if (info.AzeriteItem == null) + info.AzeriteItem = new AzeriteData(); + + info.AzeriteItem.AzeriteItemMilestonePowers.Add(azeriteItemMilestonePowersResult.Read(1)); + } + while (azeriteItemMilestonePowersResult.NextRow()); + } + + if (!azeriteItemUnlockedEssencesResult.IsEmpty()) + { + do + { + AzeriteEssencePowerRecord azeriteEssencePower = Global.DB2Mgr.GetAzeriteEssencePower(azeriteItemUnlockedEssencesResult.Read(1), azeriteItemUnlockedEssencesResult.Read(2)); + if (azeriteEssencePower != null) + { + ItemAdditionalLoadInfo info = GetOrCreateLoadInfo(azeriteItemUnlockedEssencesResult.Read(0)); + if (info.AzeriteItem == null) + info.AzeriteItem = new AzeriteData(); + + info.AzeriteItem.UnlockedAzeriteEssences.Add(azeriteEssencePower); + } + } + while (azeriteItemUnlockedEssencesResult.NextRow()); + } } } diff --git a/Source/Game/Entities/Object/Update/UpdateField.cs b/Source/Game/Entities/Object/Update/UpdateField.cs index 7611a2ccc..a09a76068 100644 --- a/Source/Game/Entities/Object/Update/UpdateField.cs +++ b/Source/Game/Entities/Object/Update/UpdateField.cs @@ -160,6 +160,11 @@ namespace Game.Entities return _values.IndexOf(value); } + public int FindIndexIf(Predicate blah) + { + return _values.FindIndex(blah); + } + public bool HasChanged(int index) { return (_updateMask[index / 32] & (1 << (index % 32))) != 0; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index c99b041e9..7c0949dfc 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -38,10 +38,10 @@ namespace Game.Entities { public partial class Player { - void _LoadInventory(SQLResult result, SQLResult artifactsResult, SQLResult azeriteResult, uint timeDiff) + void _LoadInventory(SQLResult result, SQLResult artifactsResult, SQLResult azeriteResult, SQLResult azeriteItemMilestonePowersResult, SQLResult azeriteItemUnlockedEssencesResult, uint timeDiff) { Dictionary additionalData = new Dictionary(); - ItemAdditionalLoadInfo.Init(additionalData, artifactsResult, azeriteResult); + ItemAdditionalLoadInfo.Init(additionalData, artifactsResult, azeriteResult, azeriteItemMilestonePowersResult, azeriteItemUnlockedEssencesResult); if (!result.IsEmpty()) { @@ -68,7 +68,7 @@ namespace Game.Entities { AzeriteItem azeriteItem = item.ToAzeriteItem(); if (azeriteItem != null) - azeriteItem.LoadAzeriteItemData(addionalData.AzeriteItem); + azeriteItem.LoadAzeriteItemData(this, addionalData.AzeriteItem); } } @@ -1189,8 +1189,16 @@ namespace Game.Entities stmt.AddValue(0, GetGUID().GetCounter()); SQLResult azeriteResult = DB.Characters.Query(stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_AZERITE_MILESTONE_POWER); + stmt.AddValue(0, GetGUID().GetCounter()); + SQLResult azeriteItemMilestonePowersResult = DB.Characters.Query(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE); + stmt.AddValue(0, GetGUID().GetCounter()); + SQLResult azeriteItemUnlockedEssencesResult = DB.Characters.Query(stmt); + Dictionary additionalData = new Dictionary(); - ItemAdditionalLoadInfo.Init(additionalData, artifactResult, azeriteResult); + ItemAdditionalLoadInfo.Init(additionalData, artifactResult, azeriteResult, azeriteItemMilestonePowersResult, azeriteItemUnlockedEssencesResult); do { @@ -1250,7 +1258,7 @@ namespace Game.Entities { AzeriteItem azeriteItem = item.ToAzeriteItem(); if (azeriteItem != null) - azeriteItem.LoadAzeriteItemData(additionalLoadInfo.AzeriteItem); + azeriteItem.LoadAzeriteItemData(this, additionalLoadInfo.AzeriteItem); } } @@ -2898,7 +2906,8 @@ namespace Game.Entities // must be before inventory (some items required reputation check) reputationMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Reputation)); - _LoadInventory(holder.GetResult(PlayerLoginQueryLoad.Inventory), holder.GetResult(PlayerLoginQueryLoad.Artifacts), holder.GetResult(PlayerLoginQueryLoad.LoadAzerite), time_diff); + _LoadInventory(holder.GetResult(PlayerLoginQueryLoad.Inventory), holder.GetResult(PlayerLoginQueryLoad.Artifacts), holder.GetResult(PlayerLoginQueryLoad.LoadAzerite), + holder.GetResult(PlayerLoginQueryLoad.LoadAzeriteMilestonePowers), holder.GetResult(PlayerLoginQueryLoad.LoadAzeriteUnlockedEssences), time_diff); if (IsVoidStorageUnlocked()) _LoadVoidStorage(holder.GetResult(PlayerLoginQueryLoad.VoidStorage)); @@ -3846,6 +3855,14 @@ namespace Game.Entities stmt.AddValue(0, guid); trans.Append(stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER_BY_OWNER); + stmt.AddValue(0, guid); + trans.Append(stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE_BY_OWNER); + stmt.AddValue(0, guid); + trans.Append(stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_ITEM_INSTANCE_BY_OWNER); stmt.AddValue(0, guid); trans.Append(stmt); diff --git a/Source/Game/Entities/Player/Player.Items.cs b/Source/Game/Entities/Player/Player.Items.cs index 357bc8765..e7b9b0c61 100644 --- a/Source/Game/Entities/Player/Player.Items.cs +++ b/Source/Game/Entities/Player/Player.Items.cs @@ -3948,6 +3948,7 @@ namespace Game.Entities if (updateItemAuras) ApplyItemDependentAuras(item, apply); ApplyArtifactPowers(item, apply); + ApplyAzeritePowers(item, apply); ApplyEnchantment(item, apply); Log.outDebug(LogFilter.Player, "_ApplyItemMods complete."); @@ -4366,6 +4367,7 @@ namespace Game.Entities ApplyItemEquipSpell(m_items[i], false); ApplyEnchantment(m_items[i], false); + ApplyAzeritePowers(m_items[i], false); ApplyArtifactPowers(m_items[i], false); } } @@ -4418,6 +4420,7 @@ namespace Game.Entities ApplyItemEquipSpell(m_items[i], true); ApplyArtifactPowers(m_items[i], true); + ApplyAzeritePowers(m_items[i], true); ApplyEnchantment(m_items[i], true); } } @@ -5462,6 +5465,96 @@ namespace Game.Entities } } + void ApplyAzeritePowers(Item item, bool apply) + { + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem != null) + { + // milestone powers + foreach (uint azeriteItemMilestonePowerId in azeriteItem.m_azeriteItemData.UnlockedEssenceMilestones) + ApplyAzeriteItemMilestonePower(item, CliDB.AzeriteItemMilestonePowerStorage.LookupByKey(azeriteItemMilestonePowerId), apply); + + // essences + SelectedAzeriteEssences selectedEssences = azeriteItem.GetSelectedAzeriteEssences(); + if (selectedEssences != null) + { + for (byte slot = 0; slot < SharedConst.MaxAzeriteEssenceSlot; ++slot) + if (selectedEssences.AzeriteEssenceID[slot] != 0) + ApplyAzeriteEssence(item, selectedEssences.AzeriteEssenceID[slot], azeriteItem.GetEssenceRank(selectedEssences.AzeriteEssenceID[slot]), + (AzeriteItemMilestoneType)Global.DB2Mgr.GetAzeriteItemMilestonePower(slot).Type == AzeriteItemMilestoneType.MajorEssence, apply); + } + } + } + + public void ApplyAzeriteItemMilestonePower(Item item, AzeriteItemMilestonePowerRecord azeriteItemMilestonePower, bool apply) + { + AzeriteItemMilestoneType type = (AzeriteItemMilestoneType)azeriteItemMilestonePower.Type; + if (type == AzeriteItemMilestoneType.BonusStamina) + { + AzeritePowerRecord azeritePower = CliDB.AzeritePowerStorage.LookupByKey(azeriteItemMilestonePower.AzeritePowerID); + if (azeritePower != null) + { + if (apply) + CastSpell(this, azeritePower.SpellID, true, item); + else + RemoveAurasDueToItemSpell(azeritePower.SpellID, item.GetGUID()); + } + } + } + + public void ApplyAzeriteEssence(Item item, uint azeriteEssenceId, uint rank, bool major, bool apply) + { + for (uint currentRank = 1; currentRank <= rank; ++currentRank) + { + AzeriteEssencePowerRecord azeriteEssencePower = Global.DB2Mgr.GetAzeriteEssencePower(azeriteEssenceId, currentRank); + if (azeriteEssencePower != null) + { + ApplyAzeriteEssencePower(item, azeriteEssencePower, major, apply); + if (major && currentRank == 1) + { + if (apply) + CastCustomSpell(PlayerConst.SpellIdHeartEssenceActionBarOverride, SpellValueMod.BasePoint0, (int)azeriteEssencePower.MajorPowerDescription, this, TriggerCastFlags.FullMask); + else + RemoveAurasDueToSpell(PlayerConst.SpellIdHeartEssenceActionBarOverride); + } + } + } + } + + void ApplyAzeriteEssencePower(Item item, AzeriteEssencePowerRecord azeriteEssencePower, bool major, bool apply) + { + SpellInfo powerSpell = Global.SpellMgr.GetSpellInfo(azeriteEssencePower.MinorPowerDescription); + if (powerSpell != null) + { + if (apply) + CastSpell(this, powerSpell, true, item); + else + RemoveAurasDueToItemSpell(powerSpell.Id, item.GetGUID()); + } + + if (major) + { + powerSpell = Global.SpellMgr.GetSpellInfo(azeriteEssencePower.MajorPowerDescription); + if (powerSpell != null) + { + if (powerSpell.IsPassive()) + { + if (apply) + CastSpell(this, powerSpell, true, item); + else + RemoveAurasDueToItemSpell(powerSpell.Id, item.GetGUID()); + } + else + { + if (apply) + LearnSpell(powerSpell.Id, true, 0, true); + else + RemoveSpell(powerSpell.Id, false, false, true); + } + } + } + } + public bool HasItemOrGemWithIdEquipped(uint item, uint count, byte except_slot = ItemConst.NullSlot) { uint tempcount = 0; diff --git a/Source/Game/Entities/Player/Player.Spells.cs b/Source/Game/Entities/Player/Player.Spells.cs index 57c167012..4680ef8a7 100644 --- a/Source/Game/Entities/Player/Player.Spells.cs +++ b/Source/Game/Entities/Player/Player.Spells.cs @@ -2010,7 +2010,7 @@ namespace Game.Entities LearnSpellHighestRank(next); } - public void LearnSpell(uint spellId, bool dependent, uint fromSkill = 0) + public void LearnSpell(uint spellId, bool dependent, uint fromSkill = 0, bool suppressMessaging = false) { PlayerSpell spell = m_spells.LookupByKey(spellId); @@ -2024,6 +2024,7 @@ namespace Game.Entities { LearnedSpells packet = new LearnedSpells(); packet.SpellID.Add(spellId); + packet.SuppressMessaging = suppressMessaging; SendPacket(packet); } @@ -2049,9 +2050,9 @@ namespace Game.Entities } - public void RemoveSpell(uint spell_id, bool disabled = false, bool learn_low_rank = true) + public void RemoveSpell(uint spellId, bool disabled = false, bool learnLowRank = true, bool suppressMessaging = false) { - var pSpell = m_spells.LookupByKey(spell_id); + var pSpell = m_spells.LookupByKey(spellId); if (pSpell == null) return; @@ -2059,7 +2060,7 @@ namespace Game.Entities return; // unlearn non talent higher ranks (recursive) - uint nextSpell = Global.SpellMgr.GetNextSpellInChain(spell_id); + uint nextSpell = Global.SpellMgr.GetNextSpellInChain(spellId); if (nextSpell != 0) { SpellInfo spellInfo1 = Global.SpellMgr.GetSpellInfo(nextSpell); @@ -2067,12 +2068,12 @@ namespace Game.Entities RemoveSpell(nextSpell, disabled, false); } //unlearn spells dependent from recently removed spells - var spellsRequiringSpell = Global.SpellMgr.GetSpellsRequiringSpellBounds(spell_id); + var spellsRequiringSpell = Global.SpellMgr.GetSpellsRequiringSpellBounds(spellId); foreach (var id in spellsRequiringSpell) RemoveSpell(id, disabled); // re-search, it can be corrupted in prev loop - pSpell = m_spells.LookupByKey(spell_id); + pSpell = m_spells.LookupByKey(spellId); if (pSpell == null) return; // already unleared @@ -2088,23 +2089,23 @@ namespace Game.Entities else { if (pSpell.State == PlayerSpellState.New) - m_spells.Remove(spell_id); + m_spells.Remove(spellId); else pSpell.State = PlayerSpellState.Removed; } - RemoveOwnedAura(spell_id, GetGUID()); + RemoveOwnedAura(spellId, GetGUID()); // remove pet auras for (byte i = 0; i < SpellConst.MaxEffects; ++i) { - PetAura petSpell = Global.SpellMgr.GetPetAura(spell_id, i); + PetAura petSpell = Global.SpellMgr.GetPetAura(spellId, i); if (petSpell != null) RemovePetAura(petSpell); } // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning) - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spell_id); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId); if (spellInfo != null && spellInfo.IsPrimaryProfessionFirstRank()) { uint freeProfs = GetFreePrimaryProfessionPoints() + 1; @@ -2113,10 +2114,10 @@ namespace Game.Entities } // remove dependent skill - var spellLearnSkill = Global.SpellMgr.GetSpellLearnSkill(spell_id); + var spellLearnSkill = Global.SpellMgr.GetSpellLearnSkill(spellId); if (spellLearnSkill != null) { - uint prev_spell = Global.SpellMgr.GetPrevSpellInChain(spell_id); + uint prev_spell = Global.SpellMgr.GetPrevSpellInChain(spellId); if (prev_spell == 0) // first rank, remove skill SetSkill(spellLearnSkill.skill, 0, 0, 0); else @@ -2150,7 +2151,7 @@ namespace Game.Entities } // remove dependent spells - var spell_bounds = Global.SpellMgr.GetSpellLearnSpellMapBounds(spell_id); + var spell_bounds = Global.SpellMgr.GetSpellLearnSpellMapBounds(spellId); foreach (var spellNode in spell_bounds) { @@ -2162,7 +2163,7 @@ namespace Game.Entities // activate lesser rank in spellbook/action bar, and cast it if need bool prev_activate = false; - uint prev_id = Global.SpellMgr.GetPrevSpellInChain(spell_id); + uint prev_id = Global.SpellMgr.GetPrevSpellInChain(spellId); if (prev_id != 0) { // if ranked non-stackable spell: need activate lesser rank and update dendence state @@ -2181,12 +2182,12 @@ namespace Game.Entities } // now re-learn if need re-activate - if (cur_active && !prevSpell.Active && learn_low_rank) + if (cur_active && !prevSpell.Active && learnLowRank) { if (AddSpell(prev_id, true, false, prevSpell.Dependent, prevSpell.Disabled)) { // downgrade spell ranks in spellbook and action bar - SendSupercededSpell(spell_id, prev_id); + SendSupercededSpell(spellId, prev_id); prev_activate = true; } } @@ -2194,7 +2195,7 @@ namespace Game.Entities } } - m_overrideSpells.Remove(spell_id); + m_overrideSpells.Remove(spellId); if (m_canTitanGrip) { @@ -2217,9 +2218,10 @@ namespace Game.Entities // remove from spell book if not replaced by lesser rank if (!prev_activate) { - UnlearnedSpells removedSpells = new UnlearnedSpells(); - removedSpells.SpellID.Add(spell_id); - SendPacket(removedSpells); + UnlearnedSpells unlearnedSpells = new UnlearnedSpells(); + unlearnedSpells.SpellID.Add(spellId); + unlearnedSpells.SuppressMessaging = suppressMessaging; + SendPacket(unlearnedSpells); } } bool IsNeedCastPassiveSpellAtLearn(SpellInfo spellInfo) diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index 8288ecac9..0cf70047c 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -422,6 +422,24 @@ namespace Game.Entities activeGlyphs.IsFullUpdate = true; SendPacket(activeGlyphs); + Item item = GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); + if (item != null) + { + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem != null) + { + if (azeriteItem.IsEquipped()) + ApplyAzeritePowers(azeriteItem, false); + + azeriteItem.SetSelectedAzeriteEssences(spec.Id); + + if (azeriteItem.IsEquipped()) + ApplyAzeritePowers(azeriteItem, true); + + azeriteItem.SetState(ItemUpdateState.Changed, this); + } + } + var shapeshiftAuras = GetAuraEffectsByType(AuraType.ModShapeshift); foreach (AuraEffect aurEff in shapeshiftAuras) { diff --git a/Source/Game/Groups/Group.cs b/Source/Game/Groups/Group.cs index 5ec433880..b59d1df91 100644 --- a/Source/Game/Groups/Group.cs +++ b/Source/Game/Groups/Group.cs @@ -2675,7 +2675,7 @@ namespace Game.Groups BonusData bonusData = new BonusData(itemInstance); ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(itemid); - uint itemLevel = Item.GetItemLevel(itemTemplate, bonusData, player.GetLevel(), 0, 0, 0, 0, false); + uint itemLevel = Item.GetItemLevel(itemTemplate, bonusData, player.GetLevel(), 0, 0, 0, 0, false, 0); return Item.GetDisenchantLoot(itemTemplate, (uint)bonusData.Quality, itemLevel); } diff --git a/Source/Game/Handlers/AzeriteHandler.cs b/Source/Game/Handlers/AzeriteHandler.cs new file mode 100644 index 000000000..5cfff545e --- /dev/null +++ b/Source/Game/Handlers/AzeriteHandler.cs @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2012-2019 CypherCore + * + * 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 3 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 . + */ + +using Framework.Constants; +using Game.Entities; +using Game.Network; +using Game.DataStorage; +using System.Collections.Generic; +using Game.Network.Packets; + +namespace Game +{ + public partial class WorldSession + { + [WorldPacketHandler(ClientOpcodes.AzeriteEssenceUnlockMilestone)] + void HandleAzeriteEssenceUnlockMilestone(AzeriteEssenceUnlockMilestone azeriteEssenceUnlockMilestone) + { + if (!AzeriteItem.FindHeartForge(_player)) + return; + + Item item = _player.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); + if (!item) + return; + + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (!azeriteItem || !azeriteItem.CanUseEssences()) + return; + + AzeriteItemMilestonePowerRecord milestonePower = CliDB.AzeriteItemMilestonePowerStorage.LookupByKey(azeriteEssenceUnlockMilestone.AzeriteItemMilestonePowerID); + if (milestonePower == null || milestonePower.RequiredLevel > azeriteItem.GetLevel()) + return; + + // check that all previous milestones are unlocked + foreach (AzeriteItemMilestonePowerRecord previousMilestone in Global.DB2Mgr.GetAzeriteItemMilestonePowers()) + { + if (previousMilestone == milestonePower) + break; + + if (!azeriteItem.HasUnlockedEssenceMilestone(previousMilestone.ID)) + return; + } + + azeriteItem.AddUnlockedEssenceMilestone(milestonePower.ID); + _player.ApplyAzeriteItemMilestonePower(azeriteItem, milestonePower, true); + azeriteItem.SetState(ItemUpdateState.Changed, _player); + } + + [WorldPacketHandler(ClientOpcodes.AzeriteEssenceActivateEssence)] + void HandleAzeriteEssenceActivateEssence(AzeriteEssenceActivateEssence azeriteEssenceActivateEssence) + { + AzeriteEssenceSelectionResult activateEssenceResult = new AzeriteEssenceSelectionResult(); + activateEssenceResult.AzeriteEssenceID = azeriteEssenceActivateEssence.AzeriteEssenceID; + + Item item = _player.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); + if (!item || !item.IsEquipped()) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.NotEquipped; + activateEssenceResult.Slot = azeriteEssenceActivateEssence.Slot; + SendPacket(activateEssenceResult); + return; + } + + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem == null || !azeriteItem.CanUseEssences()) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.ConditionFailed; + SendPacket(activateEssenceResult); + return; + } + + if (azeriteEssenceActivateEssence.Slot >= SharedConst.MaxAzeriteEssenceSlot || !azeriteItem.HasUnlockedEssenceSlot(azeriteEssenceActivateEssence.Slot)) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.SlotLocked; + SendPacket(activateEssenceResult); + return; + } + + SelectedAzeriteEssences selectedEssences = azeriteItem.GetSelectedAzeriteEssences(); + // essence is already in that slot, nothing to do + if (selectedEssences.AzeriteEssenceID[azeriteEssenceActivateEssence.Slot] == azeriteEssenceActivateEssence.AzeriteEssenceID) + return; + + uint rank = azeriteItem.GetEssenceRank(azeriteEssenceActivateEssence.AzeriteEssenceID); + if (rank == 0) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.EssenceNotUnlocked; + activateEssenceResult.Arg = azeriteEssenceActivateEssence.AzeriteEssenceID; + SendPacket(activateEssenceResult); + return; + } + + if (_player.IsInCombat()) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.AffectingCombat; + activateEssenceResult.Slot = azeriteEssenceActivateEssence.Slot; + SendPacket(activateEssenceResult); + return; + } + + if (_player.IsDead()) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.CantDoThatRightNow; + activateEssenceResult.Slot = azeriteEssenceActivateEssence.Slot; + SendPacket(activateEssenceResult); + return; + } + + if (!_player.HasPlayerFlag(PlayerFlags.Resting) && !_player.HasUnitFlag2(UnitFlags2.AllowChangingTalents)) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.NotInRestArea; + activateEssenceResult.Slot = azeriteEssenceActivateEssence.Slot; + SendPacket(activateEssenceResult); + return; + } + + // need to remove selected essence from another slot if selected + int removeEssenceFromSlot = -1; + for (int slot = 0; slot < SharedConst.MaxAzeriteEssenceSlot; ++slot) + if (azeriteEssenceActivateEssence.Slot != slot && selectedEssences.AzeriteEssenceID[slot] == azeriteEssenceActivateEssence.AzeriteEssenceID) + removeEssenceFromSlot = slot; + + // check cooldown of major essence slot + if (selectedEssences.AzeriteEssenceID[0] != 0 && (azeriteEssenceActivateEssence.Slot == 0 || removeEssenceFromSlot == 0)) + { + for (uint essenceRank = 1; essenceRank <= rank; ++essenceRank) + { + AzeriteEssencePowerRecord azeriteEssencePower = Global.DB2Mgr.GetAzeriteEssencePower(selectedEssences.AzeriteEssenceID[0], essenceRank); + if (_player.GetSpellHistory().HasCooldown(azeriteEssencePower.MajorPowerDescription)) + { + activateEssenceResult.Reason = AzeriteEssenceActivateResult.CantRemoveEssence; + activateEssenceResult.Arg = azeriteEssencePower.MajorPowerDescription; + activateEssenceResult.Slot = azeriteEssenceActivateEssence.Slot; + SendPacket(activateEssenceResult); + return; + } + } + } + + if (removeEssenceFromSlot != -1) + { + _player.ApplyAzeriteEssence(azeriteItem, selectedEssences.AzeriteEssenceID[removeEssenceFromSlot], SharedConst.MaxAzeriteEssenceRank, + (AzeriteItemMilestoneType)Global.DB2Mgr.GetAzeriteItemMilestonePower(removeEssenceFromSlot).Type == AzeriteItemMilestoneType.MajorEssence, false); + azeriteItem.SetSelectedAzeriteEssence(removeEssenceFromSlot, 0); + } + + if (selectedEssences.AzeriteEssenceID[azeriteEssenceActivateEssence.Slot] != 0) + { + _player.ApplyAzeriteEssence(azeriteItem, selectedEssences.AzeriteEssenceID[azeriteEssenceActivateEssence.Slot], SharedConst.MaxAzeriteEssenceRank, + (AzeriteItemMilestoneType)Global.DB2Mgr.GetAzeriteItemMilestonePower(azeriteEssenceActivateEssence.Slot).Type == AzeriteItemMilestoneType.MajorEssence, false); + } + + _player.ApplyAzeriteEssence(azeriteItem, azeriteEssenceActivateEssence.AzeriteEssenceID, rank, + (AzeriteItemMilestoneType)Global.DB2Mgr.GetAzeriteItemMilestonePower(azeriteEssenceActivateEssence.Slot).Type == AzeriteItemMilestoneType.MajorEssence, true); + + azeriteItem.SetSelectedAzeriteEssence(azeriteEssenceActivateEssence.Slot, azeriteEssenceActivateEssence.AzeriteEssenceID); + azeriteItem.SetState(ItemUpdateState.Changed, _player); + } + } +} diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 9a44d2324..918b9bb44 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -2463,6 +2463,14 @@ namespace Game stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.LoadAzerite, stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER); + stmt.AddValue(0, lowGuid); + SetQuery(PlayerLoginQueryLoad.LoadAzeriteMilestonePowers, stmt); + + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE); + stmt.AddValue(0, lowGuid); + SetQuery(PlayerLoginQueryLoad.LoadAzeriteUnlockedEssences, stmt); + stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_VOID_STORAGE); stmt.AddValue(0, lowGuid); SetQuery(PlayerLoginQueryLoad.VoidStorage, stmt); @@ -2626,6 +2634,8 @@ namespace Game Inventory, Artifacts, LoadAzerite, + LoadAzeriteMilestonePowers, + LoadAzeriteUnlockedEssences, Actions, MailCount, MailDate, diff --git a/Source/Game/Handlers/InspectHandler.cs b/Source/Game/Handlers/InspectHandler.cs index df0fae4af..ce441e6aa 100644 --- a/Source/Game/Handlers/InspectHandler.cs +++ b/Source/Game/Handlers/InspectHandler.cs @@ -67,6 +67,15 @@ namespace Game inspectResult.GuildData.Set(guildData); } + Item heartOfAzeroth = player.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); + if (heartOfAzeroth != null) + { + AzeriteItem azeriteItem = heartOfAzeroth.ToAzeriteItem(); + if (azeriteItem != null) + inspectResult.AzeriteLevel = azeriteItem.GetEffectiveLevel(); + } + + inspectResult.ItemLevel = (int)player.GetAverageItemLevel(); inspectResult.LifetimeMaxRank = player.m_activePlayerData.LifetimeMaxRank; inspectResult.TodayHK = player.m_activePlayerData.TodayHonorableKills; inspectResult.YesterdayHK = player.m_activePlayerData.YesterdayHonorableKills; diff --git a/Source/Game/Network/Packets/AzeritePackets.cs b/Source/Game/Network/Packets/AzeritePackets.cs index d2b22039d..4220b5c4e 100644 --- a/Source/Game/Network/Packets/AzeritePackets.cs +++ b/Source/Game/Network/Packets/AzeritePackets.cs @@ -17,6 +17,7 @@ using Framework.Constants; using Game.Entities; +using Framework.Dynamic; namespace Game.Network.Packets { @@ -33,4 +34,69 @@ namespace Game.Network.Packets public ObjectGuid ItemGUID; public ulong XP; } + + class AzeriteEssenceForgeOpened : ServerPacket + { + public AzeriteEssenceForgeOpened() : base(ServerOpcodes.AzeriteEssenceForgeOpened) { } + + public override void Write() + { + _worldPacket.WritePackedGuid(ForgeGUID); + } + + public ObjectGuid ForgeGUID; + } + + class AzeriteEssenceForgeClose : ServerPacket + { + public AzeriteEssenceForgeClose() : base(ServerOpcodes.AzeriteEssenceForgeClose) { } + + public override void Write() { } + } + + class AzeriteEssenceUnlockMilestone : ClientPacket + { + public AzeriteEssenceUnlockMilestone(WorldPacket packet) : base(packet) { } + + public override void Read() + { + AzeriteItemMilestonePowerID = _worldPacket.ReadInt32(); + } + + public int AzeriteItemMilestonePowerID; + } + + class AzeriteEssenceActivateEssence : ClientPacket + { + public AzeriteEssenceActivateEssence(WorldPacket packet) : base(packet) { } + + public override void Read() + { + AzeriteEssenceID = _worldPacket.ReadUInt32(); + Slot = _worldPacket.ReadUInt8(); + } + + public uint AzeriteEssenceID; + public byte Slot; + } + + class AzeriteEssenceSelectionResult : ServerPacket + { + public AzeriteEssenceSelectionResult() : base(ServerOpcodes.AzeriteEssenceSelectionResult) { } + + public override void Write() + { + _worldPacket.WriteBits((int)Reason, 4); + _worldPacket.WriteBit(Slot.HasValue); + _worldPacket.WriteUInt32(Arg); + _worldPacket.WriteUInt32(AzeriteEssenceID); + if (Slot.HasValue) + _worldPacket.WriteUInt8(Slot.Value); + } + + public AzeriteEssenceActivateResult Reason; + public uint Arg; + public uint AzeriteEssenceID; + public byte? Slot; + } } diff --git a/Source/Game/Network/Packets/InspectPackets.cs b/Source/Game/Network/Packets/InspectPackets.cs index 95e0307c2..1c9342e62 100644 --- a/Source/Game/Network/Packets/InspectPackets.cs +++ b/Source/Game/Network/Packets/InspectPackets.cs @@ -75,7 +75,7 @@ namespace Game.Network.Packets GuildData.Value.Write(_worldPacket); if (AzeriteLevel.HasValue) - _worldPacket.WriteInt32(AzeriteLevel.Value); + _worldPacket.WriteUInt32((uint)AzeriteLevel); } public PlayerModelDisplayInfo DisplayInfo; @@ -84,7 +84,7 @@ namespace Game.Network.Packets public List PvpTalents = new List(); public Optional GuildData = new Optional(); public Array Bracket = new Array(6); - public Optional AzeriteLevel; + public uint? AzeriteLevel; public int ItemLevel; public uint LifetimeHK; public uint HonorLevel; @@ -156,6 +156,30 @@ namespace Game.Network.Packets } ++i; } + + AzeriteItem azeriteItem = item.ToAzeriteItem(); + if (azeriteItem != null) + { + SelectedAzeriteEssences essences = azeriteItem.GetSelectedAzeriteEssences(); + if (essences != null) + { + for (byte slot = 0; slot < essences.AzeriteEssenceID.GetSize(); ++slot) + { + AzeriteEssenceData essence = new AzeriteEssenceData(); + essence.Index = slot; + essence.AzeriteEssenceID = essences.AzeriteEssenceID[slot]; + if (essence.AzeriteEssenceID != 0) + { + essence.Rank = azeriteItem.GetEssenceRank(essence.AzeriteEssenceID); + essence.SlotUnlocked = true; + } + else + essence.SlotUnlocked = azeriteItem.HasUnlockedEssenceSlot(slot); + + AzeriteEssences.Add(essence); + } + } + } } public void Write(WorldPacket data) diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index b786fc9e7..bc3101cff 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -150,6 +150,8 @@ namespace Game.Spells } if (GetBase().GetSpellInfo().HasAttribute(SpellAttr8.AuraSendAmount) || + GetBase().HasEffectType(AuraType.OverrideActionbarSpells) || + GetBase().HasEffectType(AuraType.OverrideActionbarSpellsTriggered) || GetBase().HasEffectType(AuraType.ModSpellCategoryCooldown) || GetBase().HasEffectType(AuraType.ModMaxCharges) || GetBase().HasEffectType(AuraType.ChargeRecoveryMod) || diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 1a13e9611..3d9309623 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5747,6 +5747,47 @@ namespace Game.Spells unitTarget.ToPlayer().GetSession().GetCollectionMgr().AddTransmogSet((uint)effectInfo.MiscValue); } + + [SpellEffectHandler(SpellEffectName.LearnAzeriteEssencePower)] + void EffectLearnAzeriteEssencePower(uint effIndex) + { + if (effectHandleMode != SpellEffectHandleMode.HitTarget) + return; + + Player playerTarget = unitTarget != null ? unitTarget.ToPlayer() : null; + if (!playerTarget) + return; + + Item heartOfAzeroth = playerTarget.GetItemByEntry(PlayerConst.ItemIdHeartOfAzeroth); + if (heartOfAzeroth == null) + return; + + AzeriteItem azeriteItem = heartOfAzeroth.ToAzeriteItem(); + if (azeriteItem == null) + return; + + // remove old rank and apply new one + if (azeriteItem.IsEquipped()) + { + SelectedAzeriteEssences selectedEssences = azeriteItem.GetSelectedAzeriteEssences(); + if (selectedEssences != null) + { + for (int slot = 0; slot < SharedConst.MaxAzeriteEssenceSlot; ++slot) + { + if (selectedEssences.AzeriteEssenceID[slot] == effectInfo.MiscValue) + { + bool major = (AzeriteItemMilestoneType)Global.DB2Mgr.GetAzeriteItemMilestonePower(slot).Type == AzeriteItemMilestoneType.MajorEssence; + playerTarget.ApplyAzeriteEssence(azeriteItem, (uint)effectInfo.MiscValue, SharedConst.MaxAzeriteEssenceRank, major, false); + playerTarget.ApplyAzeriteEssence(azeriteItem, (uint)effectInfo.MiscValue, (uint)effectInfo.MiscValueB, major, false); + break; + } + } + } + } + + azeriteItem.SetEssenceRank((uint)effectInfo.MiscValue, (uint)effectInfo.MiscValueB); + azeriteItem.SetState(ItemUpdateState.Changed, playerTarget); + } } public class DispelableAura diff --git a/sql/base/characters_database.sql b/sql/base/characters_database.sql index 6058fffde..098ea47c8 100644 --- a/sql/base/characters_database.sql +++ b/sql/base/characters_database.sql @@ -2867,8 +2867,24 @@ CREATE TABLE `item_instance_azerite` ( `xp` bigint(20) unsigned NOT NULL DEFAULT '0', `level` int(10) unsigned NOT NULL DEFAULT '1', `knowledgeLevel` int(10) unsigned NOT NULL DEFAULT '0', + `selectedAzeriteEssences1specId` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences1azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences2specId` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences2azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences3specId` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences3azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences4specId` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + `selectedAzeriteEssences4azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', PRIMARY KEY (`itemGuid`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -2880,6 +2896,53 @@ LOCK TABLES `item_instance_azerite` WRITE; /*!40000 ALTER TABLE `item_instance_azerite` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `item_instance_azerite_milestone_power` +-- + +DROP TABLE IF EXISTS `item_instance_azerite_milestone_power`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `item_instance_azerite_milestone_power` ( + `itemGuid` bigint(20) unsigned NOT NULL, + `azeriteItemMilestonePowerId` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`itemGuid`,`azeriteItemMilestonePowerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `item_instance_azerite_milestone_power` +-- + +LOCK TABLES `item_instance_azerite_milestone_power` WRITE; +/*!40000 ALTER TABLE `item_instance_azerite_milestone_power` DISABLE KEYS */; +/*!40000 ALTER TABLE `item_instance_azerite_milestone_power` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `item_instance_azerite` +-- + +DROP TABLE IF EXISTS `item_instance_azerite_unlocked_essence`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `item_instance_azerite_unlocked_essence` ( + `itemGuid` bigint(20) unsigned NOT NULL, + `azeriteEssenceId` int(10) unsigned NOT NULL DEFAULT '0', + `rank` int(10) unsigned NOT NULL DEFAULT '0', + PRIMARY KEY (`itemGuid`,`azeriteEssenceId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `item_instance_azerite_unlocked_essence` +-- + +LOCK TABLES `item_instance_azerite_unlocked_essence` WRITE; +/*!40000 ALTER TABLE `item_instance_azerite_unlocked_essence` DISABLE KEYS */; +/*!40000 ALTER TABLE `item_instance_azerite_unlocked_essence` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `item_instance_gems` -- @@ -3596,7 +3659,8 @@ INSERT INTO `updates` VALUES ('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_12_00_characters.sql','D4C642B4D48DAE9F56329BDE51C258323A132A91','RELEASED','2019-11-12 16:31:29',0); +('2019_11_12_00_characters.sql','D4C642B4D48DAE9F56329BDE51C258323A132A91','RELEASED','2019-11-12 16:31:29',0), +('2019_11_22_00_characters.sql','95DFA71DBD75542C098CD86E9C0051C9690902F0','RELEASED','2019-11-20 15:10:12',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/characters/master/2019_11_22_00_characters.sql b/sql/updates/characters/master/2019_11_22_00_characters.sql new file mode 100644 index 000000000..97671dfbb --- /dev/null +++ b/sql/updates/characters/master/2019_11_22_00_characters.sql @@ -0,0 +1,38 @@ +ALTER TABLE `item_instance_azerite` + ADD `selectedAzeriteEssences1specId` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences1azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences1azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences1azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences2specId` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences2azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences2azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences2azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences3specId` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences3azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences3azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences3azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences4specId` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences4azeriteEssenceId1` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences4azeriteEssenceId2` int(10) unsigned NULL DEFAULT '0', + ADD `selectedAzeriteEssences4azeriteEssenceId3` int(10) unsigned NULL DEFAULT '0'; + +-- +-- Table structure for table `item_instance_azerite_milestone_power` +-- +DROP TABLE IF EXISTS `item_instance_azerite_milestone_power`; +CREATE TABLE `item_instance_azerite_milestone_power` ( + `itemGuid` bigint(20) unsigned NOT NULL, + `azeriteItemMilestonePowerId` int(10) unsigned NOT NULL, + PRIMARY KEY (`itemGuid`,`azeriteItemMilestonePowerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `item_instance_azerite_unlocked_essence` +-- +DROP TABLE IF EXISTS `item_instance_azerite_unlocked_essence`; +CREATE TABLE `item_instance_azerite_unlocked_essence` ( + `itemGuid` bigint(20) unsigned NOT NULL, + `azeriteEssenceId` int(10) unsigned NOT NULL, + `rank` int(10) unsigned NOT NULL, + PRIMARY KEY (`itemGuid`,`azeriteEssenceId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/sql/updates/hotfixes/master/2019_11_22_00_hotfixes.sql b/sql/updates/hotfixes/master/2019_11_22_00_hotfixes.sql new file mode 100644 index 000000000..5951dec9a --- /dev/null +++ b/sql/updates/hotfixes/master/2019_11_22_00_hotfixes.sql @@ -0,0 +1,96 @@ +-- +-- Table structure for table `azerite_essence` +-- +DROP TABLE IF EXISTS `azerite_essence`; +CREATE TABLE `azerite_essence` ( + `Name` text, + `Description` text, + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `SpecSetID` 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_essence_locale` +-- +DROP TABLE IF EXISTS `azerite_essence_locale`; +CREATE TABLE `azerite_essence_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `Name_lang` text, + `Description_lang` text, + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `azerite_essence_power` +-- +DROP TABLE IF EXISTS `azerite_essence_power`; +CREATE TABLE `azerite_essence_power` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `SourceAlliance` text, + `SourceHorde` text, + `AzeriteEssenceID` int(11) NOT NULL DEFAULT '0', + `Tier` tinyint(3) unsigned NOT NULL DEFAULT '0', + `MajorPowerDescription` int(11) NOT NULL DEFAULT '0', + `MinorPowerDescription` int(11) NOT NULL DEFAULT '0', + `MajorPowerActual` int(11) NOT NULL DEFAULT '0', + `MinorPowerActual` 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_essence_power_locale` +-- +DROP TABLE IF EXISTS `azerite_essence_power_locale`; +CREATE TABLE `azerite_essence_power_locale` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `locale` varchar(4) NOT NULL, + `SourceAlliance_lang` text, + `SourceHorde_lang` text, + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`,`locale`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `azerite_item_milestone_power` +-- +DROP TABLE IF EXISTS `azerite_item_milestone_power`; +CREATE TABLE `azerite_item_milestone_power` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `RequiredLevel` int(11) NOT NULL DEFAULT '0', + `AzeritePowerID` int(11) NOT NULL DEFAULT '0', + `Type` int(11) NOT NULL DEFAULT '0', + `AutoUnlock` 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_power` +-- +DROP TABLE IF EXISTS `azerite_power`; +CREATE TABLE `azerite_power` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `SpellID` int(11) NOT NULL DEFAULT '0', + `ItemBonusListID` int(11) NOT NULL DEFAULT '0', + `SpecSetID` int(11) NOT NULL DEFAULT '0', + `Flags` 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 `spec_set_member` +-- +DROP TABLE IF EXISTS `spec_set_member`; +CREATE TABLE `spec_set_member` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `ChrSpecializationID` int(11) NOT NULL DEFAULT '0', + `SpecSetID` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;