From ab0d7ac8f35543bea2d3073a2f337c30dddf3a0d Mon Sep 17 00:00:00 2001 From: Shauren Date: Tue, 27 Aug 2024 13:50:33 +0200 Subject: Core/Players: Fixed spells being unintentionally removed by talent swaps when they are learned from more than one spell (affects balance druid Celesial Alignment and Incarnation) (cherry picked from commit 2c6ddcce3d6374a82214bb0ddb9d7432351982c9) # Conflicts: # src/server/game/Spells/SpellMgr.cpp --- src/server/game/Entities/Player/Player.cpp | 12 ++++++++++++ src/server/game/Spells/SpellMgr.cpp | 12 ++++++++++++ src/server/game/Spells/SpellMgr.h | 5 +++++ 3 files changed, 29 insertions(+) (limited to 'src') diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 432700be071..b6b7ea4b836 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -3107,6 +3107,18 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_ for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2) { + bool hasOtherSpellTeachingThis = std::ranges::any_of(sSpellMgr->GetSpellLearnedBySpellMapBounds(itr2->second.Spell), [&](SpellLearnSpellNode const* learnNode) + { + if (learnNode->SourceSpell == spell_id) + return false; + if (!learnNode->Active) + return false; + return HasSpell(learnNode->SourceSpell); + }, &SpellLearnedBySpellMap::value_type::second); + + if (hasOtherSpellTeachingThis) + continue; + RemoveSpell(itr2->second.Spell, disabled); if (itr2->second.OverridesSpell) RemoveOverrideSpell(itr2->second.OverridesSpell, itr2->second.Spell); diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp index b27f7db6dbd..ba212cb04b8 100644 --- a/src/server/game/Spells/SpellMgr.cpp +++ b/src/server/game/Spells/SpellMgr.cpp @@ -342,6 +342,11 @@ bool SpellMgr::IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const return false; } +Trinity::IteratorPair SpellMgr::GetSpellLearnedBySpellMapBounds(uint32 learnedSpellId) const +{ + return Trinity::Containers::MapEqualRange(mSpellLearnedBySpells, learnedSpellId); +} + SpellTargetPosition const* SpellMgr::GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const { SpellTargetPositionMap::const_iterator itr = mSpellTargetPositions.find(std::make_pair(spell_id, effIndex)); @@ -1053,6 +1058,7 @@ void SpellMgr::LoadSpellLearnSpells() { uint32 oldMSTime = getMSTime(); + mSpellLearnedBySpells.clear(); mSpellLearnSpells.clear(); // need for reload case // 0 1 2 @@ -1071,6 +1077,7 @@ void SpellMgr::LoadSpellLearnSpells() uint32 spell_id = fields[0].GetUInt32(); SpellLearnSpellNode node; + node.SourceSpell = spell_id; node.Spell = fields[1].GetUInt32(); node.OverridesSpell = 0; node.Active = fields[2].GetBool(); @@ -1115,6 +1122,7 @@ void SpellMgr::LoadSpellLearnSpells() if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL)) { SpellLearnSpellNode dbc_node; + dbc_node.SourceSpell = entry.Id; dbc_node.Spell = spellEffectInfo.TriggerSpell; dbc_node.Active = true; // all dbc based learned spells is active (show in spell book or hide by client itself) dbc_node.OverridesSpell = 0; @@ -1188,6 +1196,7 @@ void SpellMgr::LoadSpellLearnSpells() continue; SpellLearnSpellNode dbcLearnNode; + dbcLearnNode.SourceSpell = spellLearnSpell->SpellID; dbcLearnNode.Spell = spellLearnSpell->LearnSpellID; dbcLearnNode.OverridesSpell = spellLearnSpell->OverridesSpellID; dbcLearnNode.Active = true; @@ -1254,6 +1263,9 @@ void SpellMgr::LoadSpellLearnSpells() } } + for (auto const& [spellId, learnedSpellNode] : mSpellLearnSpells) + mSpellLearnedBySpells.emplace(learnedSpellNode.Spell, &learnedSpellNode); + TC_LOG_INFO("server.loading", ">> Loaded {} spell learn spells, {} found in Spell.dbc and {} found in TalentTab.db2 in {} ms", count, dbc_count, mastery_count, GetMSTimeDiffToNow(oldMSTime)); } diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h index 91470991901..b681dcbf5cd 100644 --- a/src/server/game/Spells/SpellMgr.h +++ b/src/server/game/Spells/SpellMgr.h @@ -589,6 +589,7 @@ typedef std::unordered_map SpellLearnSkillMap; struct SpellLearnSpellNode { + uint32 SourceSpell; uint32 Spell; uint32 OverridesSpell; bool Active; // show in spellbook or not @@ -617,6 +618,8 @@ struct CreatureImmunities typedef std::multimap SpellLearnSpellMap; typedef std::pair SpellLearnSpellMapBounds; +typedef std::multimap SpellLearnedBySpellMap; + typedef std::multimap SkillLineAbilityMap; typedef std::pair SkillLineAbilityMapBounds; @@ -723,6 +726,7 @@ class TC_GAME_API SpellMgr SpellLearnSpellMapBounds GetSpellLearnSpellMapBounds(uint32 spell_id) const; bool IsSpellLearnSpell(uint32 spell_id) const; bool IsSpellLearnToSpell(uint32 spell_id1, uint32 spell_id2) const; + Trinity::IteratorPair GetSpellLearnedBySpellMapBounds(uint32 learnedSpellId) const; // Spell target coordinates SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const; @@ -827,6 +831,7 @@ class TC_GAME_API SpellMgr SpellRequiredMap mSpellReq; SpellLearnSkillMap mSpellLearnSkills; SpellLearnSpellMap mSpellLearnSpells; + SpellLearnedBySpellMap mSpellLearnedBySpells; SpellTargetPositionMap mSpellTargetPositions; SpellSpellGroupMap mSpellSpellGroup; SpellGroupSpellMap mSpellGroupSpell; -- cgit v1.2.3