aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2024-08-27 13:50:33 +0200
committerShauren <shauren.trinity@gmail.com>2024-08-27 13:50:33 +0200
commit2c6ddcce3d6374a82214bb0ddb9d7432351982c9 (patch)
tree1e3a74ce1bfbd9213d9209556700cb8af6041ec6 /src
parentd71b414206d1ffc2caed3bf376d9dae387ef5cd4 (diff)
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)
Diffstat (limited to 'src')
-rw-r--r--src/server/game/Entities/Player/Player.cpp12
-rw-r--r--src/server/game/Spells/SpellMgr.cpp12
-rw-r--r--src/server/game/Spells/SpellMgr.h5
3 files changed, 29 insertions, 0 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2a53a6906bb..6ee68e5f7aa 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -3407,6 +3407,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 057a7e2c9e6..3527310f4ec 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<SpellLearnedBySpellMap::const_iterator> 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));
@@ -992,6 +997,7 @@ void SpellMgr::LoadSpellLearnSpells()
{
uint32 oldMSTime = getMSTime();
+ mSpellLearnedBySpells.clear();
mSpellLearnSpells.clear(); // need for reload case
// 0 1 2
@@ -1010,6 +1016,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();
@@ -1054,6 +1061,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;
@@ -1127,6 +1135,7 @@ void SpellMgr::LoadSpellLearnSpells()
continue;
SpellLearnSpellNode dbcLearnNode;
+ dbcLearnNode.SourceSpell = spellLearnSpell->SpellID;
dbcLearnNode.Spell = spellLearnSpell->LearnSpellID;
dbcLearnNode.OverridesSpell = spellLearnSpell->OverridesSpellID;
dbcLearnNode.Active = true;
@@ -1136,6 +1145,9 @@ void SpellMgr::LoadSpellLearnSpells()
++dbc_count;
}
+ for (auto const& [spellId, learnedSpellNode] : mSpellLearnSpells)
+ mSpellLearnedBySpells.emplace(learnedSpellNode.Spell, &learnedSpellNode);
+
TC_LOG_INFO("server.loading", ">> Loaded {} spell learn spells, {} found in Spell.dbc in {} ms", count, dbc_count, GetMSTimeDiffToNow(oldMSTime));
}
diff --git a/src/server/game/Spells/SpellMgr.h b/src/server/game/Spells/SpellMgr.h
index e8a6c2a8b1b..3d638aa61d9 100644
--- a/src/server/game/Spells/SpellMgr.h
+++ b/src/server/game/Spells/SpellMgr.h
@@ -590,6 +590,7 @@ typedef std::unordered_map<uint32, SpellLearnSkillNode> SpellLearnSkillMap;
struct SpellLearnSpellNode
{
+ uint32 SourceSpell;
uint32 Spell;
uint32 OverridesSpell;
bool Active; // show in spellbook or not
@@ -618,6 +619,8 @@ struct CreatureImmunities
typedef std::multimap<uint32, SpellLearnSpellNode> SpellLearnSpellMap;
typedef std::pair<SpellLearnSpellMap::const_iterator, SpellLearnSpellMap::const_iterator> SpellLearnSpellMapBounds;
+typedef std::multimap<uint32, SpellLearnSpellNode const*> SpellLearnedBySpellMap;
+
typedef std::multimap<uint32, SkillLineAbilityEntry const*> SkillLineAbilityMap;
typedef std::pair<SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator> SkillLineAbilityMapBounds;
@@ -725,6 +728,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<SpellLearnedBySpellMap::const_iterator> GetSpellLearnedBySpellMapBounds(uint32 learnedSpellId) const;
// Spell target coordinates
SpellTargetPosition const* GetSpellTargetPosition(uint32 spell_id, SpellEffIndex effIndex) const;
@@ -828,6 +832,7 @@ class TC_GAME_API SpellMgr
SpellRequiredMap mSpellReq;
SpellLearnSkillMap mSpellLearnSkills;
SpellLearnSpellMap mSpellLearnSpells;
+ SpellLearnedBySpellMap mSpellLearnedBySpells;
SpellTargetPositionMap mSpellTargetPositions;
SpellSpellGroupMap mSpellSpellGroup;
SpellGroupSpellMap mSpellGroupSpell;