mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-20 09:17:36 +01:00
Core/Players: no longer rely on artificially created spell ranks and manually manage talent spell ranks
This commit is contained in:
@@ -2711,34 +2711,18 @@ void DeleteSpellFromAllPlayers(uint32 spellId)
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
bool Player::AddTalent(TalentEntry const* talent, uint16 rank, uint8 talentGroupId, bool learning)
|
||||
bool Player::AddTalent(TalentEntry const* talent, uint8 rank, uint8 talentGroupId, bool learning)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellRank[rank], DIFFICULTY_NONE);
|
||||
if (!spellInfo)
|
||||
{
|
||||
// do character spell book cleanup (all characters)
|
||||
if (!IsInWorld() && !learning) // spell load case
|
||||
{
|
||||
TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) does not exist. Deleting for all characters in `character_spell` and `character_talent`.", talent->SpellRank[rank]);
|
||||
DeleteSpellFromAllPlayers(talent->SpellRank[rank]);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) does not exist", talent->SpellRank[rank]);
|
||||
|
||||
TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) does not exist", talent->SpellRank[rank]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!SpellMgr::IsSpellValid(spellInfo, this, false))
|
||||
{
|
||||
// do character spell book cleanup (all characters)
|
||||
if (!IsInWorld() && !learning) // spell load case
|
||||
{
|
||||
TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) is invalid. Deleting for all characters in `character_spell` and `character_talent`.", talent->SpellRank[rank]);
|
||||
DeleteSpellFromAllPlayers(talent->SpellRank[rank]);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) is invalid", talent->SpellRank[rank]);
|
||||
|
||||
TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) is invalid", talent->SpellRank[rank]);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2746,19 +2730,30 @@ bool Player::AddTalent(TalentEntry const* talent, uint16 rank, uint8 talentGroup
|
||||
auto itr = talentMap.find(talent->ID);
|
||||
if (itr != talentMap.end())
|
||||
{
|
||||
// Remove the previously learned talent
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellRank[itr->second.Rank], DIFFICULTY_NONE))
|
||||
{
|
||||
RemoveSpell(spellInfo->Id, true);
|
||||
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
|
||||
RemoveSpell(spellEffectInfo.TriggerSpell, true);
|
||||
}
|
||||
|
||||
itr->second.State = PLAYERSPELL_UNCHANGED;
|
||||
itr->second.Rank = static_cast<uint8>(rank);
|
||||
}
|
||||
else
|
||||
talentMap[talent->ID] = { PLAYERSPELL_UNCHANGED, static_cast<uint8>(rank) };
|
||||
talentMap[talent->ID] = { PLAYERSPELL_UNCHANGED, rank };
|
||||
|
||||
// Inactive talent groups will only be initialized
|
||||
if (GetActiveTalentGroup() != talentGroupId)
|
||||
return true;
|
||||
|
||||
LearnSpell(spellInfo->Id, false);
|
||||
if (talent->OverridesSpellID)
|
||||
AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
|
||||
if (GetActiveTalentGroup() == talentGroupId)
|
||||
{
|
||||
LearnSpell(spellInfo->Id, true);
|
||||
if (talent->OverridesSpellID)
|
||||
AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
|
||||
}
|
||||
|
||||
if (learning)
|
||||
RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::ChangeTalent);
|
||||
@@ -2774,19 +2769,15 @@ void Player::RemoveTalent(TalentEntry const* talent)
|
||||
return;
|
||||
|
||||
uint32 spellId = talent->SpellRank[itr->second.Rank];
|
||||
if (!spellId)
|
||||
return;
|
||||
if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE))
|
||||
{
|
||||
RemoveSpell(spellId, true);
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE);
|
||||
if (!spellInfo)
|
||||
return;
|
||||
|
||||
RemoveSpell(spellId, true);
|
||||
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
|
||||
RemoveSpell(spellEffectInfo.TriggerSpell, true);
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
|
||||
RemoveSpell(spellEffectInfo.TriggerSpell, true);
|
||||
}
|
||||
|
||||
if (talent->OverridesSpellID)
|
||||
RemoveOverrideSpell(talent->OverridesSpellID, talent->SpellID);
|
||||
@@ -26117,7 +26108,7 @@ bool Player::ModifierTreeSatisfied(uint32 modifierTreeId) const
|
||||
|
||||
static constexpr uint8 NEEDED_TALENT_POINT_PER_TIER = 5;
|
||||
|
||||
bool Player::LearnTalent(uint32 talentId, uint16 requestedRank)
|
||||
bool Player::LearnTalent(uint32 talentId, uint8 requestedRank)
|
||||
{
|
||||
// No talent points left to spend, skip learn request
|
||||
if (!m_activePlayerData->CharacterPoints)
|
||||
@@ -26196,16 +26187,14 @@ bool Player::LearnTalent(uint32 talentId, uint16 requestedRank)
|
||||
return false;
|
||||
}
|
||||
|
||||
// already known
|
||||
if (HasSpell(spellId))
|
||||
if (!AddTalent(talentInfo, requestedRank, GetActiveTalentGroup(), true))
|
||||
return false;
|
||||
|
||||
AddTalent(talentInfo, requestedRank, GetActiveTalentGroup(), true);
|
||||
|
||||
TC_LOG_DEBUG("misc", "Player::LearnTalent: TalentID: {} Spell: {} Group: {}\n", talentId, spellId, uint32(GetActiveTalentGroup()));
|
||||
|
||||
// update free talent points
|
||||
SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::CharacterPoints), static_cast<int32>(CalculateTalentsPoints() - GetSpentTalentPointsCount()));
|
||||
SendTalentsInfoData();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27029,16 +27018,23 @@ void Player::ActivateTalentGroup(uint8 talentGroup)
|
||||
if (!talentEntry)
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentEntry->SpellRank[pair.second.Rank], DIFFICULTY_NONE);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
for (auto it = talentEntry->SpellRank.rbegin(); it != talentEntry->SpellRank.rend(); ++it)
|
||||
{
|
||||
uint32 spellId = *it;
|
||||
if (!spellId)
|
||||
continue;
|
||||
|
||||
RemoveSpell(spellInfo->Id, true);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE);
|
||||
if (!spellInfo)
|
||||
continue;
|
||||
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
|
||||
RemoveSpell(spellEffectInfo.TriggerSpell, true);
|
||||
RemoveSpell(spellInfo->Id, true);
|
||||
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
|
||||
RemoveSpell(spellEffectInfo.TriggerSpell, true);
|
||||
}
|
||||
|
||||
if (talentEntry->OverridesSpellID)
|
||||
RemoveOverrideSpell(talentEntry->OverridesSpellID, talentEntry->SpellID);
|
||||
|
||||
@@ -1826,8 +1826,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void InitTalentForLevel();
|
||||
void SendTalentsInfoData();
|
||||
uint32 CalculateTalentsPoints() const;
|
||||
bool LearnTalent(uint32 talentId, uint16 requestedRank);
|
||||
bool AddTalent(TalentEntry const* talent, uint16 rank, uint8 talentGroupId, bool learning);
|
||||
bool LearnTalent(uint32 talentId, uint8 requestedRank);
|
||||
bool AddTalent(TalentEntry const* talent, uint8 rank, uint8 talentGroupId, bool learning);
|
||||
void RemoveTalent(TalentEntry const* talent);
|
||||
|
||||
void EnablePvpRules(bool dueToCombat = false);
|
||||
|
||||
@@ -32,8 +32,7 @@ void WorldSession::HandleLearnTalentsOpcode(WorldPackets::Talent::LearnTalents&
|
||||
|
||||
void WorldSession::HandleLearnTalentOpcode(WorldPackets::Talent::LearnTalent& packet)
|
||||
{
|
||||
if (_player->LearnTalent(packet.TalentID, packet.RequestedRank))
|
||||
_player->SendTalentsInfoData();
|
||||
_player->LearnTalent(packet.TalentID, packet.RequestedRank);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLearnPvpTalentsOpcode(WorldPackets::Talent::LearnPvpTalents& /*packet*/)
|
||||
|
||||
@@ -809,69 +809,8 @@ void SpellMgr::UnloadSpellInfoChains()
|
||||
mSpellChains.clear();
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellTalentRanks()
|
||||
{
|
||||
// cleanup core data before reload - remove reference to ChainNode from SpellInfo
|
||||
UnloadSpellInfoChains();
|
||||
|
||||
for (TalentEntry const* talentInfo : sTalentStore)
|
||||
{
|
||||
SpellInfo const* lastSpell = nullptr;
|
||||
for (uint8 rank = talentInfo->SpellRank.size() - 1; rank > 0; --rank)
|
||||
{
|
||||
if (talentInfo->SpellRank[rank])
|
||||
{
|
||||
lastSpell = GetSpellInfo(talentInfo->SpellRank[rank], DIFFICULTY_NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lastSpell)
|
||||
continue;
|
||||
|
||||
SpellInfo const* firstSpell = GetSpellInfo(talentInfo->SpellRank[0], DIFFICULTY_NONE);
|
||||
if (!firstSpell)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: First Rank Spell {} for TalentEntry {} does not exist.", talentInfo->SpellRank[0], talentInfo->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
SpellInfo const* prevSpell = nullptr;
|
||||
for (uint8 rank = 0; rank < talentInfo->SpellRank.size(); ++rank)
|
||||
{
|
||||
uint32 spellId = talentInfo->SpellRank[rank];
|
||||
if (!spellId)
|
||||
break;
|
||||
|
||||
SpellInfo const* currentSpell = GetSpellInfo(spellId, DIFFICULTY_NONE);
|
||||
if (!currentSpell)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "SpellMgr::LoadSpellTalentRanks: Spell {} (Rank: {}) for TalentEntry {} does not exist.", spellId, rank + 1, talentInfo->ID);
|
||||
break;
|
||||
}
|
||||
|
||||
SpellChainNode node;
|
||||
node.first = firstSpell;
|
||||
node.last = lastSpell;
|
||||
node.rank = rank + 1;
|
||||
|
||||
node.prev = prevSpell;
|
||||
node.next = node.rank < MAX_TALENT_RANK ? GetSpellInfo(talentInfo->SpellRank[node.rank], DIFFICULTY_NONE) : nullptr;
|
||||
|
||||
mSpellChains[spellId] = node;
|
||||
for (SpellInfo const& difficultyInfo : _GetSpellInfo(spellId))
|
||||
const_cast<SpellInfo&>(difficultyInfo).ChainEntry = &mSpellChains[spellId];
|
||||
|
||||
prevSpell = currentSpell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellRanks()
|
||||
{
|
||||
// cleanup data and load spell ranks for talents from dbc
|
||||
LoadSpellTalentRanks();
|
||||
|
||||
uint32 oldMSTime = getMSTime();
|
||||
|
||||
std::map<uint32 /*spell*/, uint32 /*next*/> chains;
|
||||
|
||||
@@ -768,7 +768,6 @@ class TC_GAME_API SpellMgr
|
||||
|
||||
// Loading data at server startup
|
||||
void UnloadSpellInfoChains();
|
||||
void LoadSpellTalentRanks();
|
||||
void LoadSpellRanks();
|
||||
void LoadSpellRequired();
|
||||
void LoadSpellLearnSkills();
|
||||
|
||||
Reference in New Issue
Block a user