From ae08c81ce6583e0a9db411363bcc80c6ccb1fef5 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 1 Aug 2018 14:14:51 -0400 Subject: [PATCH] Core/Artifact Handle Artifact tiers + Artifact unlock (3rd relic bonus) --- Source/Framework/Constants/CliDBConst.cs | 11 ++- Source/Framework/Constants/ItemConst.cs | 1 - Source/Framework/Constants/PlayerConst.cs | 2 + Source/Framework/Constants/SharedConst.cs | 1 + .../Database/Databases/CharacterDatabase.cs | 4 +- .../Database/Databases/HotfixDatabase.cs | 12 +++ Source/Game/DataStorage/CliDB.cs | 4 + Source/Game/DataStorage/Structs/A_Records.cs | 20 +++++ Source/Game/Entities/Item/Item.cs | 71 ++++++++++------ Source/Game/Entities/Object/WorldObject.cs | 11 +++ Source/Game/Entities/Player/Player.DB.cs | 28 +++--- Source/Game/Entities/Player/Player.cs | 18 ++++ Source/Game/Handlers/ArtifactHandler.cs | 85 ++++++++++++++----- Source/Game/Handlers/CharacterHandler.cs | 10 +++ .../Game/Network/Packets/ArtifactPackets.cs | 14 +++ Source/Game/Server/WorldConfig.cs | 7 ++ Source/Game/Spells/SpellEffects.cs | 2 +- Source/WorldServer/WorldServer.conf.dist | 8 ++ .../master/2018_03_18_00_hotfixes.sql | 29 +++++++ 19 files changed, 275 insertions(+), 63 deletions(-) create mode 100644 sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql diff --git a/Source/Framework/Constants/CliDBConst.cs b/Source/Framework/Constants/CliDBConst.cs index b442c808c..9fcb1e472 100644 --- a/Source/Framework/Constants/CliDBConst.cs +++ b/Source/Framework/Constants/CliDBConst.cs @@ -883,13 +883,22 @@ namespace Framework.Constants Unk9 = 0x40000000, } + public enum ArtifactCategory + { + Primary = 1, + Fishing = 2 + } + public enum ArtifactPowerFlag : byte { Gold = 0x01, - First = 0x02, + NoLinkRequired = 0x02, Final = 0x04, ScalesWithNumPowers = 0x08, DontCountFirstBonusRank = 0x10, + MaxRankWithTier = 0x20, + + First = NoLinkRequired | DontCountFirstBonusRank, } public enum BattlegroundBracketId // bracketId for level ranges diff --git a/Source/Framework/Constants/ItemConst.cs b/Source/Framework/Constants/ItemConst.cs index d86c7639f..48d4f9827 100644 --- a/Source/Framework/Constants/ItemConst.cs +++ b/Source/Framework/Constants/ItemConst.cs @@ -1052,7 +1052,6 @@ namespace Framework.Constants JusticePoints = 395, ValorPoints = 396, ApexisCrystals = 823, - ArtifactKnowledge = 1171, } public enum PlayerCurrencyState diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index face15717..756d6d0cf 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -67,6 +67,8 @@ namespace Framework.Constants public const int ArtifactsAllWeaponsGeneralWeaponEquippedPassive = 197886; + public const int MaxArtifactTier = 1; + public const byte MaxHonorLevel = 50; public const byte LevelMinHonor = 110; public const uint SpellPvpRulesEnabled = 134735; diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index 4b144b3a8..06ff390fc 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -1066,6 +1066,7 @@ namespace Framework.Constants CurrencyResetInterval, CurrencyStartApexisCrystals, CurrencyStartJusticePoints, + CurrencyStartArtifactKnowledge, DailyQuestResetTimeHour, DbcEnforceItemAttributes, DeathBonesBgOrArena, diff --git a/Source/Framework/Database/Databases/CharacterDatabase.cs b/Source/Framework/Database/Databases/CharacterDatabase.cs index 359be60f4..e189bfeff 100644 --- a/Source/Framework/Database/Databases/CharacterDatabase.cs +++ b/Source/Framework/Database/Databases/CharacterDatabase.cs @@ -180,8 +180,8 @@ namespace Framework.Database "spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_TRANSMOG, "DELETE FROM item_instance_transmog WHERE itemGuid = ?"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER, "DELETE iit FROM item_instance_transmog iit LEFT JOIN item_instance ii ON iit.itemGuid = ii.guid WHERE ii.owner_guid = ?"); - PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_ARTIFACT, "SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.itemGuid WHERE ci.guid = ?"); - PrepareStatement(CharStatements.INS_ITEM_INSTANCE_ARTIFACT, "INSERT INTO item_instance_artifact (itemGuid, xp, artifactAppearanceId) VALUES (?, ?, ?)"); + PrepareStatement(CharStatements.SEL_ITEM_INSTANCE_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 character_inventory ci ON ci.item = ap.itemGuid WHERE ci.guid = ?"); + PrepareStatement(CharStatements.INS_ITEM_INSTANCE_ARTIFACT, "INSERT INTO item_instance_artifact (itemGuid, xp, artifactAppearanceId, artifactTierId) VALUES (?, ?, ?, ?)"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_ARTIFACT, "DELETE FROM item_instance_artifact WHERE itemGuid = ?"); PrepareStatement(CharStatements.DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER, "DELETE iia FROM item_instance_artifact iia LEFT JOIN item_instance ii ON iia.itemGuid = ii.guid WHERE ii.owner_guid = ?"); PrepareStatement(CharStatements.INS_ITEM_INSTANCE_ARTIFACT_POWERS, "INSERT INTO item_instance_artifact_powers (itemGuid, artifactPowerId, purchasedRank) VALUES (?, ?, ?)"); diff --git a/Source/Framework/Database/Databases/HotfixDatabase.cs b/Source/Framework/Database/Databases/HotfixDatabase.cs index e609df22d..b03b290ae 100644 --- a/Source/Framework/Database/Databases/HotfixDatabase.cs +++ b/Source/Framework/Database/Databases/HotfixDatabase.cs @@ -85,6 +85,14 @@ namespace Framework.Database PrepareStatement(HotfixStatements.SEL_ARTIFACT_QUEST_XP, "SELECT ID, Difficulty1, Difficulty2, Difficulty3, Difficulty4, Difficulty5, Difficulty6, " + "Difficulty7, Difficulty8, Difficulty9, Difficulty10 FROM artifact_quest_xp ORDER BY ID DESC"); + // ArtifactTier.db2 + PrepareStatement(HotfixStatements.SEL_ARTIFACT_TIER, "SELECT ID, ArtifactTier, MaxNumTraits, MaxArtifactKnowledge, KnowledgePlayerCondition, " + + "MinimumEmpowerKnowledge FROM artifact_tier ORDER BY ID DESC"); + + // ArtifactUnlock.db2 + PrepareStatement(HotfixStatements.SEL_ARTIFACT_UNLOCK, "SELECT ID, ItemBonusListID, PowerRank, PowerID, PlayerConditionID, ArtifactID FROM artifact_unlock" + + " ORDER BY ID DESC"); + // AuctionHouse.db2 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 = ?"); @@ -1094,6 +1102,10 @@ namespace Framework.Database SEL_ARTIFACT_QUEST_XP, + SEL_ARTIFACT_TIER, + + SEL_ARTIFACT_UNLOCK, + SEL_AUCTION_HOUSE, SEL_AUCTION_HOUSE_LOCALE, diff --git a/Source/Game/DataStorage/CliDB.cs b/Source/Game/DataStorage/CliDB.cs index a23186e1f..d544778e0 100644 --- a/Source/Game/DataStorage/CliDB.cs +++ b/Source/Game/DataStorage/CliDB.cs @@ -50,6 +50,8 @@ namespace Game.DataStorage ArtifactPowerPickerStorage = DBReader.Read("ArtifactPowerPicker.db2", HotfixStatements.SEL_ARTIFACT_POWER_PICKER); ArtifactPowerRankStorage = DBReader.Read("ArtifactPowerRank.db2", HotfixStatements.SEL_ARTIFACT_POWER_RANK); //ArtifactQuestXPStorage = DBReader.Read("ArtifactQuestXP.db2", HotfixStatements.SEL_ARTIFACT_QUEST_XP); + 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); BankBagSlotPricesStorage = DBReader.Read("BankBagSlotPrices.db2", HotfixStatements.SEL_BANK_BAG_SLOT_PRICES); //BannedAddOnsStorage = DBReader.Read("BannedAddons.db2", HotfixStatements.SEL_BANNED_ADDONS); @@ -383,6 +385,8 @@ namespace Game.DataStorage public static DB6Storage ArtifactPowerPickerStorage; public static DB6Storage ArtifactPowerRankStorage; //public static DB6Storage ArtifactQuestXPStorage; + public static DB6Storage ArtifactTierStorage; + public static DB6Storage ArtifactUnlockStorage; public static DB6Storage AuctionHouseStorage; public static DB6Storage BankBagSlotPricesStorage; //public static DB6Storage BannedAddOnsStorage; diff --git a/Source/Game/DataStorage/Structs/A_Records.cs b/Source/Game/DataStorage/Structs/A_Records.cs index 4ca4a56ac..b9977e40f 100644 --- a/Source/Game/DataStorage/Structs/A_Records.cs +++ b/Source/Game/DataStorage/Structs/A_Records.cs @@ -214,6 +214,26 @@ namespace Game.DataStorage public uint[] Difficulty = new uint[10]; } + public class ArtifactTierRecord + { + public uint ID; + public uint ArtifactTier; + public uint MaxNumTraits; + public uint MaxArtifactKnowledge; + public uint KnowledgePlayerCondition; + public uint MinimumEmpowerKnowledge; + } + + public class ArtifactUnlockRecord + { + public uint ID; + public ushort ItemBonusListID; + public byte PowerRank; + public uint PowerID; + public uint PlayerConditionID; + public byte ArtifactID; + } + public sealed class AuctionHouseRecord { public uint Id; diff --git a/Source/Game/Entities/Item/Item.cs b/Source/Game/Entities/Item/Item.cs index a9c43fc56..3f57add15 100644 --- a/Source/Game/Entities/Item/Item.cs +++ b/Source/Game/Entities/Item/Item.cs @@ -81,7 +81,7 @@ namespace Game.Entities { if (spellInfo.HasEffect(SpellEffectName.GiveArtifactPower)) { - uint artifactKnowledgeLevel = owner.GetCurrency((uint)CurrencyTypes.ArtifactKnowledge); + uint artifactKnowledgeLevel = WorldConfig.GetUIntValue(WorldCfg.CurrencyStartArtifactKnowledge); if (artifactKnowledgeLevel != 0) SetModifier(ItemModifier.ArtifactKnowledgeLevel, artifactKnowledgeLevel + 1); } @@ -112,6 +112,8 @@ namespace Game.Entities break; } } + + CheckArtifactRelicSlotUnlock(owner != null ? owner : GetOwner()); } return true; } @@ -295,6 +297,7 @@ namespace Game.Entities stmt.AddValue(0, GetGUID().GetCounter()); stmt.AddValue(1, GetUInt64Value(ItemFields.ArtifactXp)); stmt.AddValue(2, GetModifier(ItemModifier.ArtifactAppearanceId)); + stmt.AddValue(3, GetModifier(ItemModifier.ArtifactTier)); trans.Append(stmt); foreach (ItemDynamicFieldArtifactPowers artifactPower in GetArtifactPowers()) @@ -547,11 +550,15 @@ namespace Game.Entities return true; } - public void LoadArtifactData(Player owner, ulong xp, uint artifactAppearanceId, List powers) + public void LoadArtifactData(Player owner, ulong xp, uint artifactAppearanceId, uint artifactTier, List powers) { - InitArtifactPowers(GetTemplate().GetArtifactID(), 0); + for (byte i = 0; i <= artifactTier; ++i) + InitArtifactPowers(GetTemplate().GetArtifactID(), i); + SetUInt64Value(ItemFields.ArtifactXp, xp); SetModifier(ItemModifier.ArtifactAppearanceId, artifactAppearanceId); + SetModifier(ItemModifier.ArtifactTier, artifactTier); + ArtifactAppearanceRecord artifactAppearance = CliDB.ArtifactAppearanceStorage.LookupByKey(artifactAppearanceId); if (artifactAppearance != null) SetAppearanceModId(artifactAppearance.ItemAppearanceModifierID); @@ -612,6 +619,23 @@ namespace Game.Entities power.CurrentRankWithBonus = (byte)(totalPurchasedRanks + 1); SetArtifactPower(power); } + + CheckArtifactRelicSlotUnlock(owner != null ? owner : GetOwner()); + } + + public void CheckArtifactRelicSlotUnlock(Player owner) + { + if (!owner) + return; + + byte artifactId = GetTemplate().GetArtifactID(); + if (artifactId == 0) + return; + + foreach (ArtifactUnlockRecord artifactUnlock in CliDB.ArtifactUnlockStorage.Values) + if (artifactUnlock.ArtifactID == artifactId) + if (owner.MeetPlayerCondition(artifactUnlock.PlayerConditionID)) + AddBonuses(artifactUnlock.ItemBonusListID); } public static void DeleteFromDB(SQLTransaction trans, ulong itemGuid) @@ -2194,6 +2218,9 @@ namespace Game.Entities public void AddBonuses(uint bonusListID) { + if (HasDynamicValue(ItemDynamicFields.BonusListIds, bonusListID)) + return; + var bonuses = Global.DB2Mgr.GetItemBonusList(bonusListID); if (bonuses != null) { @@ -2237,7 +2264,7 @@ namespace Game.Entities SetDynamicStructuredValue(ItemDynamicFields.ArtifactPowers, index, artifactPower); } - void InitArtifactPowers(byte artifactId, byte artifactTier) + public void InitArtifactPowers(byte artifactId, byte artifactTier) { foreach (ArtifactPowerRecord artifactPower in Global.DB2Mgr.GetArtifactPowers(artifactId)) { @@ -2250,7 +2277,7 @@ namespace Game.Entities ItemDynamicFieldArtifactPowers powerData = new ItemDynamicFieldArtifactPowers(); powerData.ArtifactPowerId = artifactPower.Id; powerData.PurchasedRank = 0; - powerData.CurrentRankWithBonus = (byte)(artifactPower.Flags.HasAnyFlag(ArtifactPowerFlag.First) ? 1 : 0); + powerData.CurrentRankWithBonus = (byte)((artifactPower.Flags & ArtifactPowerFlag.First) == ArtifactPowerFlag.First ? 1 : 0); SetArtifactPower(powerData, true); } } @@ -2366,7 +2393,7 @@ namespace Game.Entities SetAppearanceModId(parent.GetAppearanceModId()); } - public void GiveArtifactXp(ulong amount, Item sourceItem, uint artifactCategoryId) + public void GiveArtifactXp(ulong amount, Item sourceItem, ArtifactCategory artifactCategoryId) { Player owner = GetOwner(); if (!owner) @@ -2374,26 +2401,22 @@ namespace Game.Entities if (artifactCategoryId != 0) { - ArtifactCategoryRecord artifactCategory = CliDB.ArtifactCategoryStorage.LookupByKey(artifactCategoryId); - if (artifactCategory != null) - { - uint artifactKnowledgeLevel = 1; - if (sourceItem && sourceItem.GetModifier(ItemModifier.ArtifactKnowledgeLevel) != 0) - artifactKnowledgeLevel = sourceItem.GetModifier(ItemModifier.ArtifactKnowledgeLevel); - else - artifactKnowledgeLevel = owner.GetCurrency(artifactCategory.XpMultCurrencyID) + 1; + uint artifactKnowledgeLevel = 1; + if (sourceItem != null && sourceItem.GetModifier(ItemModifier.ArtifactKnowledgeLevel) != 0) + artifactKnowledgeLevel = sourceItem.GetModifier(ItemModifier.ArtifactKnowledgeLevel); + else if (artifactCategoryId == ArtifactCategory.Primary) + artifactKnowledgeLevel = WorldConfig.GetUIntValue(WorldCfg.CurrencyStartArtifactKnowledge) + 1; - GtArtifactKnowledgeMultiplierRecord artifactKnowledge = CliDB.ArtifactKnowledgeMultiplierGameTable.GetRow(artifactKnowledgeLevel); - if (artifactKnowledge != null) - amount = (ulong)(amount * artifactKnowledge.Multiplier); + GtArtifactKnowledgeMultiplierRecord artifactKnowledge = CliDB.ArtifactKnowledgeMultiplierGameTable.GetRow(artifactKnowledgeLevel); + if (artifactKnowledge != null) + amount = (ulong)(amount * artifactKnowledge.Multiplier); - if (amount >= 5000) - amount = 50 * (amount / 50); - else if (amount >= 1000) - amount = 25 * (amount / 25); - else if (amount >= 50) - amount = 5 * (amount / 5); - } + if (amount >= 5000) + amount = 50 * (amount / 50); + else if (amount >= 1000) + amount = 25 * (amount / 25); + else if (amount >= 50) + amount = 5 * (amount / 5); } SetUInt64Value(ItemFields.ArtifactXp, GetUInt64Value(ItemFields.ArtifactXp) + amount); diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index 03bd5bf99..cc9133dcf 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1401,6 +1401,17 @@ namespace Game.Entities return _dynamicValues[(int)index][offset]; } + public bool HasDynamicValue(object index, uint value) + { + Cypher.Assert((int)index < _dynamicValuesCount || PrintIndexError(index, false)); + uint[] values = _dynamicValues[(int)index]; + for (var i = 0; i < values.Length; ++i) + if (values[i] == value) + return true; + + return false; + } + public void AddDynamicValue(object index, uint value) { Cypher.Assert((int)index < _dynamicValuesCount || PrintIndexError(index, true)); diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 5aa444da3..122596152 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -39,28 +39,32 @@ namespace Game.Entities { void _LoadInventory(SQLResult result, SQLResult artifactsResult, uint timeDiff) { - // 0 1 2 3 4 - // SELECT a.itemGuid, a.xp, a.artifactAppearanceId, ap.artifactPowerId, ap.purchasedRank FROM item_instance_artifact_powers ap LEFT JOIN item_instance_artifact a ON ap.itemGuid = a.itemGuid INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ? - Dictionary>> artifactData = new Dictionary>>(); - //MultiMap artifactPowerData = new MultiMap(); + // 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 INNER JOIN character_inventory ci ON ci.item = ap.guid WHERE ci.guid = ? + var artifactData = new Dictionary>>(); if (!artifactsResult.IsEmpty()) { do { - var artifactDataEntry = Tuple.Create(artifactsResult.Read(1), artifactsResult.Read(2), new List()); + var artifactDataEntry = Tuple.Create(artifactsResult.Read(1), artifactsResult.Read(2), artifactsResult.Read(3), new List()); ItemDynamicFieldArtifactPowers artifactPowerData = new ItemDynamicFieldArtifactPowers(); - artifactPowerData.ArtifactPowerId = artifactsResult.Read(3); - artifactPowerData.PurchasedRank = artifactsResult.Read(4); + artifactPowerData.ArtifactPowerId = artifactsResult.Read(4); + artifactPowerData.PurchasedRank = artifactsResult.Read(5); ArtifactPowerRecord artifactPower = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerData.ArtifactPowerId); if (artifactPower != null) { - if (artifactPowerData.PurchasedRank > artifactPower.MaxPurchasableRank) - artifactPowerData.PurchasedRank = artifactPower.MaxPurchasableRank; + uint maxRank = artifactPower.MaxPurchasableRank; + // allow ARTIFACT_POWER_FLAG_FINAL to overflow maxrank here - needs to be handled in Item::CheckArtifactUnlock (will refund artifact power) + if (artifactPower.Flags.HasAnyFlag(ArtifactPowerFlag.MaxRankWithTier) && artifactPower.Tier < artifactDataEntry.Item3) + maxRank += artifactDataEntry.Item3 - artifactPower.Tier; - artifactPowerData.CurrentRankWithBonus = (byte)(artifactPower.Flags.HasAnyFlag(ArtifactPowerFlag.First) ? 1 : 0); + if (artifactPowerData.PurchasedRank > maxRank) + artifactPowerData.PurchasedRank = (byte)maxRank; - artifactDataEntry.Item3.Add(artifactPowerData); + artifactPowerData.CurrentRankWithBonus = (byte)((artifactPower.Flags & ArtifactPowerFlag.First) == ArtifactPowerFlag.First ? 1 : 0); + + artifactDataEntry.Item4.Add(artifactPowerData); } artifactData[ObjectGuid.Create(HighGuid.Item, artifactsResult.Read(0))] = artifactDataEntry; @@ -85,7 +89,7 @@ namespace Game.Entities { var artifactDataPair = artifactData.LookupByKey(item.GetGUID()); if (item.GetTemplate().GetArtifactID() != 0 && artifactDataPair != null) - item.LoadArtifactData(this, artifactDataPair.Item1, artifactDataPair.Item2, artifactDataPair.Item3); + item.LoadArtifactData(this, artifactDataPair.Item1, artifactDataPair.Item2, artifactDataPair.Item3, artifactDataPair.Item4); ulong counter = result.Read(45); ObjectGuid bagGuid = counter != 0 ? ObjectGuid.Create(HighGuid.Item, counter) : ObjectGuid.Empty; diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index e2aa65916..f16eb7e20 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -5085,6 +5085,16 @@ namespace Game.Entities SendPacket(displayPlayerChoice); } + public bool MeetPlayerCondition(uint conditionId) + { + PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(conditionId); + if (playerCondition != null) + if (!ConditionManager.IsPlayerMeetingCondition(this, playerCondition)) + return false; + + return true; + } + public float GetCollisionHeight(bool mounted) { if (mounted) @@ -5333,6 +5343,14 @@ namespace Game.Entities _ApplyAllLevelScaleItemMods(true); // Moved to above SetFullHealth so player will have full health from Heirlooms + Aura artifactAura = GetAura(PlayerConst.ArtifactsAllWeaponsGeneralWeaponEquippedPassive); + if (artifactAura != null) + { + Item artifact = GetItemByGuid(artifactAura.GetCastItemGUID()); + if (artifact != null) + artifact.CheckArtifactRelicSlotUnlock(this); + } + // Only health and mana are set to maximum. SetFullHealth(); SetFullPower(PowerType.Mana); diff --git a/Source/Game/Handlers/ArtifactHandler.cs b/Source/Game/Handlers/ArtifactHandler.cs index 4979a9bae..2c49b787e 100644 --- a/Source/Game/Handlers/ArtifactHandler.cs +++ b/Source/Game/Handlers/ArtifactHandler.cs @@ -37,10 +37,12 @@ namespace Game if (!artifact) return; + uint currentArtifactTier = artifact.GetModifier(ItemModifier.ArtifactTier); + ulong xpCost = 0; GtArtifactLevelXPRecord cost = CliDB.ArtifactLevelXPGameTable.GetRow(artifact.GetTotalPurchasedArtifactPowers() + 1); if (cost != null) - xpCost = (ulong)(artifact.GetModifier(ItemModifier.ArtifactTier) == 1 ? cost.XP2 : cost.XP); + xpCost = (ulong)(currentArtifactTier == PlayerConst.MaxArtifactTier ? cost.XP2 : cost.XP); if (xpCost > artifact.GetUInt64Value(ItemFields.ArtifactXp)) return; @@ -56,33 +58,47 @@ namespace Game if (artifactPowerEntry == null) return; - if (artifactAddPower.PowerChoices[0].Rank != artifactPower.PurchasedRank + 1 || - artifactAddPower.PowerChoices[0].Rank > artifactPowerEntry.MaxPurchasableRank) + if (artifactPowerEntry.Tier > currentArtifactTier) return; - var artifactPowerLinks = Global.DB2Mgr.GetArtifactPowerLinks(artifactPower.ArtifactPowerId); - if (artifactPowerLinks != null) + uint maxRank = artifactPowerEntry.MaxPurchasableRank; + if (artifactPowerEntry.Tier < currentArtifactTier) { - bool hasAnyLink = false; - foreach (uint artifactPowerLinkId in artifactPowerLinks) + if (artifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.Final)) + maxRank = 1; + else if (artifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.MaxRankWithTier)) + maxRank += currentArtifactTier - artifactPowerEntry.Tier; + } + + if (artifactAddPower.PowerChoices[0].Rank != artifactPower.PurchasedRank + 1 || + artifactAddPower.PowerChoices[0].Rank > maxRank) + return; + if (!artifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.NoLinkRequired)) + { + var artifactPowerLinks = Global.DB2Mgr.GetArtifactPowerLinks(artifactPower.ArtifactPowerId); + if (artifactPowerLinks != null) { - ArtifactPowerRecord artifactPowerLink = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerLinkId); - if (artifactPowerLink == null) - continue; - - ItemDynamicFieldArtifactPowers artifactPowerLinkLearned = artifact.GetArtifactPower(artifactPowerLinkId); - if (artifactPowerLinkLearned == null) - continue; - - if (artifactPowerLinkLearned.PurchasedRank >= artifactPowerLink.MaxPurchasableRank) + bool hasAnyLink = false; + foreach (uint artifactPowerLinkId in artifactPowerLinks) { - hasAnyLink = true; - break; - } - } + ArtifactPowerRecord artifactPowerLink = CliDB.ArtifactPowerStorage.LookupByKey(artifactPowerLinkId); + if (artifactPowerLink == null) + continue; - if (!hasAnyLink) - return; + ItemDynamicFieldArtifactPowers artifactPowerLinkLearned = artifact.GetArtifactPower(artifactPowerLinkId); + if (artifactPowerLinkLearned == null) + continue; + + if (artifactPowerLinkLearned.PurchasedRank >= artifactPowerLink.MaxPurchasableRank) + { + hasAnyLink = true; + break; + } + } + + if (!hasAnyLink) + return; + } } ArtifactPowerRankRecord artifactPowerRank = Global.DB2Mgr.GetArtifactPowerRank(artifactPower.ArtifactPowerId, (byte)(artifactPower.CurrentRankWithBonus + 1 - 1)); // need data for next rank, but -1 because of how db2 data is structured @@ -119,6 +135,31 @@ namespace Game artifact.SetUInt64Value(ItemFields.ArtifactXp, artifact.GetUInt64Value(ItemFields.ArtifactXp) - xpCost); artifact.SetState(ItemUpdateState.Changed, _player); + + uint totalPurchasedArtifactPower = artifact.GetTotalPurchasedArtifactPowers(); + uint artifactTier = 0; + + foreach (ArtifactTierRecord tier in CliDB.ArtifactTierStorage.Values) + { + if (artifactPowerEntry.Flags.HasAnyFlag(ArtifactPowerFlag.Final) && artifactPowerEntry.Tier < PlayerConst.MaxArtifactTier) + { + artifactTier = artifactPowerEntry.Tier + 1u; + break; + } + + if (totalPurchasedArtifactPower < tier.MaxNumTraits) + { + artifactTier = tier.ArtifactTier; + break; + } + } + + artifactTier = Math.Max(artifactTier, currentArtifactTier); + + for (uint i = currentArtifactTier; i <= artifactTier; ++i) + artifact.InitArtifactPowers(artifact.GetTemplate().GetArtifactID(), (byte)i); + + artifact.SetModifier(ItemModifier.ArtifactTier, artifactTier); } [WorldPacketHandler(ClientOpcodes.ArtifactSetAppearance)] diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 828fe2ac9..313eba747 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -691,6 +691,16 @@ namespace Game // TODO: Move this to BattlePetMgr::SendJournalLock() just to have all packets in one file SendPacket(new BattlePetJournalLockAcquired()); + ArtifactKnowledge artifactKnowledge = new ArtifactKnowledge(); + artifactKnowledge.ArtifactCategoryID = ArtifactCategory.Primary; + artifactKnowledge.KnowledgeLevel = (sbyte)WorldConfig.GetIntValue(WorldCfg.CurrencyStartArtifactKnowledge); + SendPacket(artifactKnowledge); + + ArtifactKnowledge artifactKnowledgeFishingPole = new ArtifactKnowledge(); + artifactKnowledgeFishingPole.ArtifactCategoryID = ArtifactCategory.Fishing; + artifactKnowledgeFishingPole.KnowledgeLevel = 0; + SendPacket(artifactKnowledgeFishingPole); + pCurrChar.SendInitialPacketsBeforeAddToMap(); //Show cinematic at the first time that player login diff --git a/Source/Game/Network/Packets/ArtifactPackets.cs b/Source/Game/Network/Packets/ArtifactPackets.cs index 9bc709115..5d84915e1 100644 --- a/Source/Game/Network/Packets/ArtifactPackets.cs +++ b/Source/Game/Network/Packets/ArtifactPackets.cs @@ -122,4 +122,18 @@ namespace Game.Network.Packets public ObjectGuid ArtifactGUID; public ulong Amount; } + + class ArtifactKnowledge : ServerPacket + { + public ArtifactKnowledge() : base(ServerOpcodes.ArtifactKnowledge) { } + + public override void Write() + { + _worldPacket.WriteInt32(ArtifactCategoryID); + _worldPacket.WriteInt8(KnowledgeLevel); + } + + public ArtifactCategory ArtifactCategoryID; + public sbyte KnowledgeLevel; + } } diff --git a/Source/Game/Server/WorldConfig.cs b/Source/Game/Server/WorldConfig.cs index d7af0a0b2..3d95e619e 100644 --- a/Source/Game/Server/WorldConfig.cs +++ b/Source/Game/Server/WorldConfig.cs @@ -495,6 +495,13 @@ namespace Game } Values[WorldCfg.CurrencyMaxJusticePoints] = (int)Values[WorldCfg.CurrencyMaxJusticePoints] * 100; //precision mod + Values[WorldCfg.CurrencyStartArtifactKnowledge] = GetDefaultValue("Currency.StartArtifactKnowledge", 55); + if ((int)(Values[WorldCfg.CurrencyStartArtifactKnowledge]) < 0) + { + Log.outError(LogFilter.ServerLoading, "Currency.StartArtifactKnowledge ({0}) must be >= 0, set to default 0.", Values[WorldCfg.CurrencyStartArtifactKnowledge]); + Values[WorldCfg.CurrencyStartArtifactKnowledge] = 0; + } + Values[WorldCfg.MaxRecruitAFriendBonusPlayerLevel] = GetDefaultValue("RecruitAFriend.MaxLevel", 85); if ((int)Values[WorldCfg.MaxRecruitAFriendBonusPlayerLevel] > (int)Values[WorldCfg.MaxPlayerLevel]) { diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 2337bf393..869bc2a0b 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -5674,7 +5674,7 @@ namespace Game.Spells { Item artifact = m_caster.ToPlayer().GetItemByGuid(artifactAura.GetCastItemGUID()); if (artifact) - artifact.GiveArtifactXp((ulong)damage, m_CastItem, (uint)effectInfo.MiscValue); + artifact.GiveArtifactXp((ulong)damage, m_CastItem, (ArtifactCategory)effectInfo.MiscValue); } } diff --git a/Source/WorldServer/WorldServer.conf.dist b/Source/WorldServer/WorldServer.conf.dist index 7aaefb90f..290f56228 100644 --- a/Source/WorldServer/WorldServer.conf.dist +++ b/Source/WorldServer/WorldServer.conf.dist @@ -3539,6 +3539,14 @@ Currency.StartJusticePoints = 0 Currency.MaxJusticePoints = 4000 +# +# Currency.StartArtifactKnowledge +# Amount artifact knowledge that new players will start with +# Default: 55 (max) +# + +Currency.StartArtifactKnowledge = 55 + # ################################################################################################### diff --git a/sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql b/sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql new file mode 100644 index 000000000..d4271bb25 --- /dev/null +++ b/sql/updates/hotfixes/master/2018_03_18_00_hotfixes.sql @@ -0,0 +1,29 @@ +-- +-- Table structure for table `artifact_tier` +-- +DROP TABLE IF EXISTS `artifact_tier`; +CREATE TABLE `artifact_tier` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `ArtifactTier` int(10) unsigned NOT NULL DEFAULT '0', + `MaxNumTraits` int(10) unsigned NOT NULL DEFAULT '0', + `MaxArtifactKnowledge` int(10) unsigned NOT NULL DEFAULT '0', + `KnowledgePlayerCondition` int(10) unsigned NOT NULL DEFAULT '0', + `MinimumEmpowerKnowledge` int(10) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `artifact_unlock` +-- +DROP TABLE IF EXISTS `artifact_unlock`; +CREATE TABLE `artifact_unlock` ( + `ID` int(10) unsigned NOT NULL DEFAULT '0', + `ItemBonusListID` smallint(5) unsigned NOT NULL DEFAULT '0', + `PowerRank` tinyint(3) unsigned NOT NULL DEFAULT '0', + `PowerID` int(10) unsigned NOT NULL DEFAULT '0', + `PlayerConditionID` int(10) unsigned NOT NULL DEFAULT '0', + `ArtifactID` tinyint(3) unsigned NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8;