Core/Spells: Automatically generate spell rank info from SkillLineAbility

* This fixes weird spellbook/talent/glyph/profession ui behavior when knowing multiple spells to remove talent or glyph, or multiple spells to open profession ui
This commit is contained in:
Shauren
2016-06-15 16:20:43 +02:00
parent 8839369fc5
commit 5da217877b
5 changed files with 63 additions and 142 deletions
@@ -0,0 +1 @@
DROP TABLE IF EXISTS `spell_ranks`;
+4 -6
View File
@@ -2905,7 +2905,6 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
bool dependent_set = false;
bool disabled_case = false;
bool superceded_old = false;
PlayerSpellMap::iterator itr = m_spells.find(spellId);
@@ -2916,7 +2915,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
{
uint32 next_active_spell_id = 0;
// fix activate state for non-stackable low rank (and find next spell for !active case)
if (!spellInfo->IsStackableWithRanks() && spellInfo->IsRanked())
if (spellInfo->IsRanked())
{
if (uint32 next = sSpellMgr->GetNextSpellInChain(spellId))
{
@@ -3029,7 +3028,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
newspell->disabled = disabled;
// replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible
if (newspell->active && !newspell->disabled && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked() != 0)
if (newspell->active && !newspell->disabled && spellInfo->IsRanked())
{
for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
{
@@ -3053,7 +3052,6 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
itr2->second->active = false;
if (itr2->second->state != PLAYERSPELL_NEW)
itr2->second->state = PLAYERSPELL_CHANGED;
superceded_old = true; // new spell replace old in action bars and spell book.
}
else
{
@@ -3173,7 +3171,7 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
}
// return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell
return active && !disabled && !superceded_old;
return active && !disabled;
}
void Player::AddTemporarySpell(uint32 spellId)
@@ -3379,7 +3377,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
{
// if ranked non-stackable spell: need activate lesser rank and update dendence state
/// No need to check for spellInfo != NULL here because if cur_active is true, then that means that the spell was already in m_spells, and only valid spells can be pushed there.
if (cur_active && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked())
if (cur_active && spellInfo->IsRanked())
{
// need manually update dependence state (learn spell ignore like attempts)
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
-39
View File
@@ -1257,22 +1257,6 @@ bool SpellInfo::IsQuestTame() const
return effect0 && effect1 && effect0->Effect == SPELL_EFFECT_THREAT && effect1->Effect == SPELL_EFFECT_APPLY_AURA && effect1->ApplyAuraName == SPELL_AURA_DUMMY;
}
bool SpellInfo::IsProfessionOrRiding(uint32 difficulty) const
{
SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty);
for (SpellEffectInfo const* effect : effects)
{
if ((effect && effect->Effect == SPELL_EFFECT_SKILL))
{
uint32 skill = effect->MiscValue;
if (IsProfessionOrRidingSkill(skill))
return true;
}
}
return false;
}
bool SpellInfo::IsProfession(uint32 difficulty) const
{
SpellEffectInfoVector effects = GetEffectsForDifficulty(difficulty);
@@ -1310,23 +1294,6 @@ bool SpellInfo::IsPrimaryProfessionFirstRank(uint32 difficulty) const
return IsPrimaryProfession(difficulty) && GetRank() == 1;
}
bool SpellInfo::IsAbilityLearnedWithProfession() const
{
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id);
for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
{
SkillLineAbilityEntry const* pAbility = _spell_idx->second;
if (!pAbility || pAbility->AquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE)
continue;
if (pAbility->MinSkillLineRank > 0)
return true;
}
return false;
}
bool SpellInfo::IsAbilityOfSkillType(uint32 skillType) const
{
SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(Id);
@@ -1425,12 +1392,6 @@ bool SpellInfo::IsStackableWithRanks() const
if (IsPassive())
return false;
if (IsProfessionOrRiding())
return false;
if (IsAbilityLearnedWithProfession())
return false;
// All stance spells. if any better way, change it.
SpellEffectInfoVector effects = GetEffectsForDifficulty(DIFFICULTY_NONE);
for (SpellEffectInfo const* effect : effects)
-2
View File
@@ -481,11 +481,9 @@ public:
bool IsExplicitDiscovery() const;
bool IsLootCrafting() const;
bool IsQuestTame() const;
bool IsProfessionOrRiding(uint32 difficulty = DIFFICULTY_NONE) const;
bool IsProfession(uint32 difficulty = DIFFICULTY_NONE) const;
bool IsPrimaryProfession(uint32 difficulty = DIFFICULTY_NONE) const;
bool IsPrimaryProfessionFirstRank(uint32 difficulty = DIFFICULTY_NONE) const;
bool IsAbilityLearnedWithProfession() const;
bool IsAbilityOfSkillType(uint32 skillType) const;
bool IsAffectingArea(uint32 difficulty) const;
+58 -95
View File
@@ -1261,113 +1261,76 @@ void SpellMgr::LoadSpellRanks()
{
uint32 oldMSTime = getMSTime();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT first_spell_id, spell_id, rank from spell_ranks ORDER BY first_spell_id, rank");
if (!result)
std::map<uint32 /*spell*/, uint32 /*next*/> chains;
std::set<uint32> hasPrev;
for (SkillLineAbilityEntry const* skillAbility : sSkillLineAbilityStore)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 spell rank records. DB table `spell_ranks` is empty.");
return;
if (!skillAbility->SupercedesSpell)
continue;
if (!GetSpellInfo(skillAbility->SupercedesSpell) || !GetSpellInfo(skillAbility->SpellID))
continue;
chains[skillAbility->SupercedesSpell] = skillAbility->SpellID;
hasPrev.insert(skillAbility->SpellID);
}
uint32 count = 0;
bool finished = false;
do
// each key in chains that isn't present in hasPrev is a first rank
for (auto itr = chains.begin(); itr != chains.end(); ++itr)
{
// spellid, rank
std::list < std::pair < int32, int32 > > rankChain;
int32 currentSpell = -1;
int32 lastSpell = -1;
// fill one chain
while (currentSpell == lastSpell && !finished)
{
Field* fields = result->Fetch();
currentSpell = fields[0].GetUInt32();
if (lastSpell == -1)
lastSpell = currentSpell;
uint32 spell_id = fields[1].GetUInt32();
uint32 rank = fields[2].GetUInt8();
// don't drop the row if we're moving to the next rank
if (currentSpell == lastSpell)
{
rankChain.push_back(std::make_pair(spell_id, rank));
if (!result->NextRow())
finished = true;
}
else
break;
}
// check if chain is made with valid first spell
SpellInfo const* first = GetSpellInfo(lastSpell);
if (!first)
{
TC_LOG_ERROR("sql.sql", "The spell rank identifier(first_spell_id) %u listed in `spell_ranks` does not exist!", lastSpell);
if (hasPrev.count(itr->first))
continue;
}
// check if chain is long enough
if (rankChain.size() < 2)
{
TC_LOG_ERROR("sql.sql", "There is only 1 spell rank for identifier(first_spell_id) %u in `spell_ranks`, entry is not needed!", lastSpell);
SpellInfo const* first = GetSpellInfo(itr->first);
SpellInfo const* next = GetSpellInfo(itr->second);
if (!first || next)
continue;
}
int32 curRank = 0;
bool valid = true;
// check spells in chain
for (std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin(); itr!= rankChain.end(); ++itr)
mSpellChains[itr->first].first = first;
mSpellChains[itr->first].prev = nullptr;
mSpellChains[itr->first].next = next;
mSpellChains[itr->first].last = next;
mSpellChains[itr->first].rank = 1;
mSpellInfoMap[itr->first]->ChainEntry = &mSpellChains[itr->first];
mSpellChains[itr->second].first = first;
mSpellChains[itr->second].prev = first;
mSpellChains[itr->second].next = nullptr;
mSpellChains[itr->second].last = next;
mSpellChains[itr->second].rank = 2;
mSpellInfoMap[itr->second]->ChainEntry = &mSpellChains[itr->second];
uint8 rank = 3;
auto nextItr = chains.find(itr->second);
while (nextItr != chains.end())
{
SpellInfo const* spell = GetSpellInfo(itr->first);
if (!spell)
{
TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not exist!", itr->first, itr->second, lastSpell);
valid = false;
SpellInfo const* prev = GetSpellInfo(nextItr->first); // already checked in previous iteration (or above, in case this is the first one)
SpellInfo const* last = GetSpellInfo(nextItr->second);
if (!last)
break;
}
++curRank;
if (itr->second != curRank)
mSpellChains[nextItr->first].next = last;
mSpellChains[nextItr->second].first = first;
mSpellChains[nextItr->second].prev = prev;
mSpellChains[nextItr->second].next = nullptr;
mSpellChains[nextItr->second].last = last;
mSpellChains[nextItr->second].rank = rank++;
mSpellInfoMap[nextItr->second]->ChainEntry = &mSpellChains[nextItr->second];
// fill 'last'
do
{
TC_LOG_ERROR("sql.sql", "The spell %u (rank %u) listed in `spell_ranks` for chain %u does not have a proper rank value (should be %u)!", itr->first, itr->second, lastSpell, curRank);
valid = false;
break;
}
mSpellChains[prev->Id].last = last;
prev = mSpellChains[prev->Id].prev;
} while (prev);
nextItr = chains.find(nextItr->second);
}
if (!valid)
continue;
int32 prevRank = 0;
// insert the chain
std::list<std::pair<int32, int32> >::iterator itr = rankChain.begin();
do
{
++count;
int32 addedSpell = itr->first;
if (mSpellInfoMap[addedSpell]->ChainEntry)
TC_LOG_ERROR("sql.sql", "The spell %u (rank: %u, first: %u) listed in `spell_ranks` already has ChainEntry from dbc.", addedSpell, itr->second, lastSpell);
mSpellChains[addedSpell].first = GetSpellInfo(lastSpell);
mSpellChains[addedSpell].last = GetSpellInfo(rankChain.back().first);
mSpellChains[addedSpell].rank = itr->second;
mSpellChains[addedSpell].prev = GetSpellInfo(prevRank);
mSpellInfoMap[addedSpell]->ChainEntry = &mSpellChains[addedSpell];
prevRank = addedSpell;
++itr;
if (itr == rankChain.end())
{
mSpellChains[addedSpell].next = NULL;
break;
}
else
mSpellChains[addedSpell].next = GetSpellInfo(itr->first);
}
while (true);
}
while (!finished);
TC_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
TC_LOG_INFO("server.loading", ">> Loaded %u spell rank records in %u ms", uint32(mSpellChains.size()), GetMSTimeDiffToNow(oldMSTime));
}
void SpellMgr::LoadSpellRequired()