diff --git a/Source/Framework/Constants/PlayerConst.cs b/Source/Framework/Constants/PlayerConst.cs index 231407cd6..5d7291628 100644 --- a/Source/Framework/Constants/PlayerConst.cs +++ b/Source/Framework/Constants/PlayerConst.cs @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - */ + */ using System; @@ -65,7 +65,7 @@ namespace Framework.Constants public const int MaxArtifactTier = 1; public const int MaxHonorLevel = 500; - public const byte LevelMinHonor = 20; + public const byte LevelMinHonor = 10; public const uint SpellPvpRulesEnabled = 134735; //Azerite diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 09324827b..1095670ef 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -3153,8 +3153,6 @@ namespace Game.Entities InitTalentForLevel(); LearnDefaultSkills(); LearnCustomSpells(); - if (GetLevel() < PlayerConst.LevelMinHonor) - ResetPvpTalents(); // must be before inventory (some items required reputation check) reputationMgr.LoadFromDB(holder.GetResult(PlayerLoginQueryLoad.Reputation)); diff --git a/Source/Game/Entities/Player/Player.PvP.cs b/Source/Game/Entities/Player/Player.PvP.cs index 825917b91..89dedd098 100644 --- a/Source/Game/Entities/Player/Player.PvP.cs +++ b/Source/Game/Entities/Player/Player.PvP.cs @@ -27,7 +27,6 @@ using Game.PvP; using Game.Spells; using System; using System.Collections.Generic; -using System.Linq; namespace Game.Entities { @@ -308,146 +307,6 @@ namespace Game.Entities public void ActivatePvpItemLevels(bool activate) { _usePvpItemLevels = activate; } public bool IsUsingPvpItemLevels() { return _usePvpItemLevels; } - void ResetPvpTalents() - { - foreach (var talentInfo in CliDB.PvpTalentStorage.Values) - { - if (talentInfo == null) - continue; - - RemovePvpTalent(talentInfo); - } - - SQLTransaction trans = new(); - _SaveTalents(trans); - _SaveSpells(trans); - DB.Characters.CommitTransaction(trans); - } - - public TalentLearnResult LearnPvpTalent(uint talentID, byte slot, ref uint spellOnCooldown) - { - if (slot >= PlayerConst.MaxPvpTalentSlots) - return TalentLearnResult.FailedUnknown; - - if (IsInCombat()) - return TalentLearnResult.FailedAffectingCombat; - - if (IsDead()) - return TalentLearnResult.FailedCantDoThatRightNow; - - PvpTalentRecord talentInfo = CliDB.PvpTalentStorage.LookupByKey(talentID); - if (talentInfo == null) - return TalentLearnResult.FailedUnknown; - - if (talentInfo.SpecID != GetPrimarySpecialization()) - return TalentLearnResult.FailedUnknown; - - if (talentInfo.LevelRequired > GetLevel()) - return TalentLearnResult.FailedUnknown; - - if (Global.DB2Mgr.GetRequiredLevelForPvpTalentSlot(slot, GetClass()) > GetLevel()) - return TalentLearnResult.FailedUnknown; - - PvpTalentCategoryRecord talentCategory = CliDB.PvpTalentCategoryStorage.LookupByKey(talentInfo.PvpTalentCategoryID); - if (talentCategory != null) - if (!Convert.ToBoolean(talentCategory.TalentSlotMask & (1 << slot))) - return TalentLearnResult.FailedUnknown; - - // Check if player doesn't have this talent in other slot - if (HasPvpTalent(talentID, GetActiveTalentGroup())) - return TalentLearnResult.FailedUnknown; - - PvpTalentRecord talent = CliDB.PvpTalentStorage.LookupByKey(GetPvpTalentMap(GetActiveTalentGroup())[slot]); - if (talent != null) - { - if (!HasPlayerFlag(PlayerFlags.Resting) && !HasUnitFlag2(UnitFlags2.AllowChangingTalents)) - return TalentLearnResult.FailedRestArea; - - if (GetSpellHistory().HasCooldown(talent.SpellID)) - { - spellOnCooldown = talent.SpellID; - return TalentLearnResult.FailedCantRemoveTalent; - } - - RemovePvpTalent(talent); - } - - if (!AddPvpTalent(talentInfo, GetActiveTalentGroup(), slot)) - return TalentLearnResult.FailedUnknown; - - return TalentLearnResult.LearnOk; - } - - bool AddPvpTalent(PvpTalentRecord talent, byte activeTalentGroup, byte slot) - { - //ASSERT(talent); - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); - if (spellInfo == null) - { - Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) does not exist."); - return false; - } - - if (!Global.SpellMgr.IsSpellValid(spellInfo, this, false)) - { - Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) is invalid"); - return false; - } - - if (HasPvpRulesEnabled()) - LearnSpell(talent.SpellID, false); - - // Move this to toggle ? - if (talent.OverridesSpellID != 0) - AddOverrideSpell(talent.OverridesSpellID, talent.SpellID); - - GetPvpTalentMap(activeTalentGroup)[slot] = talent.Id; - - return true; - } - - void RemovePvpTalent(PvpTalentRecord talent) - { - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); - if (spellInfo == null) - return; - - RemoveSpell(talent.SpellID, true); - - // Move this to toggle ? - if (talent.OverridesSpellID != 0) - RemoveOverrideSpell(talent.OverridesSpellID, talent.SpellID); - - // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted - var talents = GetPvpTalentMap(GetActiveTalentGroup()); - for (var i = 0; i < PlayerConst.MaxPvpTalentSlots; ++i) - { - if (talents[i] == talent.Id) - talents[i] = 0; - } - } - - public void TogglePvpTalents(bool enable) - { - var pvpTalents = GetPvpTalentMap(GetActiveTalentGroup()); - foreach (uint pvpTalentId in pvpTalents) - { - PvpTalentRecord pvpTalentInfo = CliDB.PvpTalentStorage.LookupByKey(pvpTalentId); - if (pvpTalentInfo != null) - { - if (enable) - LearnSpell(pvpTalentInfo.SpellID, false); - else - RemoveSpell(pvpTalentInfo.SpellID, true); - } - } - } - - bool HasPvpTalent(uint talentID, byte activeTalentGroup) - { - return GetPvpTalentMap(activeTalentGroup).Contains(talentID); - } - public void EnablePvpRules(bool dueToCombat = false) { if (HasPvpRulesEnabled()) diff --git a/Source/Game/Entities/Player/Player.Talents.cs b/Source/Game/Entities/Player/Player.Talents.cs index b10115110..48e8e7b5b 100644 --- a/Source/Game/Entities/Player/Player.Talents.cs +++ b/Source/Game/Entities/Player/Player.Talents.cs @@ -20,6 +20,7 @@ using Framework.Database; using Game.DataStorage; using Game.Networking.Packets; using Game.Spells; +using System; using System.Collections.Generic; namespace Game.Entities @@ -52,6 +53,19 @@ namespace Game.Entities SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.MaxTalentTiers), talentTiers); + if (!GetSession().HasPermission(RBACPermissions.SkipCheckMoreTalentsThanAllowed)) + { + for (byte spec = 0; spec < PlayerConst.MaxSpecializations; ++spec) + { + for (int slot = Global.DB2Mgr.GetPvpTalentNumSlotsAtLevel(level, GetClass()); slot < PlayerConst.MaxPvpTalentSlots; ++slot) + { + var pvpTalent = CliDB.PvpTalentStorage.LookupByKey(GetPvpTalentMap(spec)[slot]); + if (pvpTalent != null) + RemovePvpTalent(pvpTalent, spec); + } + } + } + if (!GetSession().PlayerLoading()) SendTalentsInfoData(); // update at client } @@ -167,7 +181,7 @@ namespace Game.Entities if (!HasTalent(talent.Id, GetActiveTalentGroup())) continue; - + if (!HasPlayerFlag(PlayerFlags.Resting) && HasUnitFlag2(UnitFlags2.AllowChangingTalents)) return TalentLearnResult.FailedRestArea; @@ -219,6 +233,7 @@ namespace Game.Entities } } + ResetPvpTalents(); RemoveSpecializationSpells(); ChrSpecializationRecord defaultSpec = Global.DB2Mgr.GetDefaultChrSpecializationForClass(GetClass()); @@ -530,7 +545,7 @@ namespace Game.Entities continue; RemoveTalent(talentInfo); - } + } SQLTransaction trans = new(); _SaveTalents(trans); @@ -632,5 +647,143 @@ namespace Game.Entities respecWipeConfirm.RespecType = SpecResetType.Talents; SendPacket(respecWipeConfirm); } + + //Pvp + void ResetPvpTalents() + { + for (byte spec = 0; spec < PlayerConst.MaxSpecializations; ++spec) + { + foreach (uint talentId in GetPvpTalentMap(spec)) + { + var talentInfo = CliDB.PvpTalentStorage.LookupByKey(talentId); + if (talentInfo != null) + RemovePvpTalent(talentInfo, spec); + } + } + } + + public TalentLearnResult LearnPvpTalent(uint talentID, byte slot, ref uint spellOnCooldown) + { + if (slot >= PlayerConst.MaxPvpTalentSlots) + return TalentLearnResult.FailedUnknown; + + if (IsInCombat()) + return TalentLearnResult.FailedAffectingCombat; + + if (IsDead()) + return TalentLearnResult.FailedCantDoThatRightNow; + + PvpTalentRecord talentInfo = CliDB.PvpTalentStorage.LookupByKey(talentID); + if (talentInfo == null) + return TalentLearnResult.FailedUnknown; + + if (talentInfo.SpecID != GetPrimarySpecialization()) + return TalentLearnResult.FailedUnknown; + + if (talentInfo.LevelRequired > GetLevel()) + return TalentLearnResult.FailedUnknown; + + if (Global.DB2Mgr.GetRequiredLevelForPvpTalentSlot(slot, GetClass()) > GetLevel()) + return TalentLearnResult.FailedUnknown; + + PvpTalentCategoryRecord talentCategory = CliDB.PvpTalentCategoryStorage.LookupByKey(talentInfo.PvpTalentCategoryID); + if (talentCategory != null) + if (!Convert.ToBoolean(talentCategory.TalentSlotMask & (1 << slot))) + return TalentLearnResult.FailedUnknown; + + // Check if player doesn't have this talent in other slot + if (HasPvpTalent(talentID, GetActiveTalentGroup())) + return TalentLearnResult.FailedUnknown; + + PvpTalentRecord talent = CliDB.PvpTalentStorage.LookupByKey(GetPvpTalentMap(GetActiveTalentGroup())[slot]); + if (talent != null) + { + if (!HasPlayerFlag(PlayerFlags.Resting) && !HasUnitFlag2(UnitFlags2.AllowChangingTalents)) + return TalentLearnResult.FailedRestArea; + + if (GetSpellHistory().HasCooldown(talent.SpellID)) + { + spellOnCooldown = talent.SpellID; + return TalentLearnResult.FailedCantRemoveTalent; + } + + RemovePvpTalent(talent, GetActiveTalentGroup()); + } + + if (!AddPvpTalent(talentInfo, GetActiveTalentGroup(), slot)) + return TalentLearnResult.FailedUnknown; + + return TalentLearnResult.LearnOk; + } + + bool AddPvpTalent(PvpTalentRecord talent, byte activeTalentGroup, byte slot) + { + //ASSERT(talent); + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); + if (spellInfo == null) + { + Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) does not exist."); + return false; + } + + if (!Global.SpellMgr.IsSpellValid(spellInfo, this, false)) + { + Log.outError(LogFilter.Spells, $"Player.AddPvpTalent: Spell (ID: {talent.SpellID}) is invalid"); + return false; + } + + if (HasPvpRulesEnabled()) + LearnSpell(talent.SpellID, false); + + // Move this to toggle ? + if (talent.OverridesSpellID != 0) + AddOverrideSpell(talent.OverridesSpellID, talent.SpellID); + + GetPvpTalentMap(activeTalentGroup)[slot] = talent.Id; + + return true; + } + + void RemovePvpTalent(PvpTalentRecord talent, byte activeTalentGroup) + { + SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(talent.SpellID, Difficulty.None); + if (spellInfo == null) + return; + + RemoveSpell(talent.SpellID, true); + + // Move this to toggle ? + if (talent.OverridesSpellID != 0) + RemoveOverrideSpell(talent.OverridesSpellID, talent.SpellID); + + // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted + var talents = GetPvpTalentMap(activeTalentGroup); + for (var i = 0; i < PlayerConst.MaxPvpTalentSlots; ++i) + { + if (talents[i] == talent.Id) + talents[i] = 0; + } + } + + public void TogglePvpTalents(bool enable) + { + var pvpTalents = GetPvpTalentMap(GetActiveTalentGroup()); + foreach (uint pvpTalentId in pvpTalents) + { + PvpTalentRecord pvpTalentInfo = CliDB.PvpTalentStorage.LookupByKey(pvpTalentId); + if (pvpTalentInfo != null) + { + if (enable) + LearnSpell(pvpTalentInfo.SpellID, false); + else + RemoveSpell(pvpTalentInfo.SpellID, true); + } + } + } + + bool HasPvpTalent(uint talentID, byte activeTalentGroup) + { + return GetPvpTalentMap(activeTalentGroup).Contains(talentID); + } } } diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 705c8e081..5fc9ead12 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -5379,9 +5379,6 @@ namespace Game.Entities InitTalentForLevel(); InitTaxiNodesForLevel(); - if (level < PlayerConst.LevelMinHonor) - ResetPvpTalents(); - UpdateAllStats(); _ApplyAllLevelScaleItemMods(true); // Moved to above SetFullHealth so player will have full health from Heirlooms