*Add error checks at spell_required table loading

*Allow spell_required table to store more than 1 spell learn requirement for a spell
*spell_required table data is removed from world.sql and since this commit the data for it should be maintained by db project you're using.

--HG--
branch : trunk
This commit is contained in:
QAston
2010-01-30 19:25:04 +01:00
parent 6b9914f0d7
commit a331b67244
6 changed files with 96 additions and 42 deletions
+17 -4
View File
@@ -164,7 +164,6 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
bool primary_prof_first_rank = spellmgr.IsPrimaryProfessionFirstRankSpell(tSpell->learnedSpell);
SpellChainNode const* chain_node = spellmgr.GetSpellChainNode(tSpell->learnedSpell);
uint32 req_spell = spellmgr.GetSpellRequired(tSpell->spell);
TrainerSpellState state = _player->GetTrainerSpellState(tSpell);
data << uint32(tSpell->spell); // learned spell (or cast-spell in profession case)
@@ -178,9 +177,23 @@ void WorldSession::SendTrainerList( uint64 guid, const std::string& strTitle )
data << uint32(tSpell->reqSkill);
data << uint32(tSpell->reqSkillValue);
//prev + req or req + 0
data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? chain_node->prev : req_spell);
data << uint32(!tSpell->IsCastable() && chain_node && chain_node->prev ? req_spell : 0);
data << uint32(0);
uint8 maxReq = 0;
if (!tSpell->IsCastable() && chain_node && chain_node->prev)
{
data << uint32(chain_node->prev);
++maxReq;
}
SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(tSpell->spell);
for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second && maxReq < 3; ++itr2)
{
data << uint32(itr2->second);
++maxReq;
}
while (maxReq < 3)
{
data << uint32(0);
++maxReq;
}
++count;
}
+27 -23
View File
@@ -3441,10 +3441,9 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
removeSpell(node->next,disabled, false);
}
//unlearn spells dependent from recently removed spells
SpellsRequiringSpellMap const &reqMap = spellmgr.GetSpellsRequiringSpell();
SpellsRequiringSpellMap::const_iterator itr2 = reqMap.find(spell_id);
for (uint32 i = reqMap.count(spell_id); i > 0; --i, ++itr2)
removeSpell(itr2->second,disabled,false);
SpellsRequiringSpellMapBounds spellsRequiringSpell = spellmgr.GetSpellsRequiringSpellBounds(spell_id);
for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequiringSpell.first; itr2 != spellsRequiringSpell.second; ++itr2)
removeSpell(itr2->second,disabled);
// re-search, it can be corrupted in prev loop
itr = m_spells.find(spell_id);
@@ -4116,10 +4115,11 @@ TrainerSpellState Player::GetTrainerSpellState(TrainerSpell const* trainer_spell
return TRAINER_SPELL_RED;
}
if(uint32 spell_req = spellmgr.GetSpellRequired(trainer_spell->spell))
SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(trainer_spell->spell);
for (SpellsRequiringSpellMap::const_iterator itr = spellsRequired.first; itr != spellsRequired.second; ++itr)
{
// check additional spell requirement
if(!HasSpell(spell_req))
if(!HasSpell(itr->second))
return TRAINER_SPELL_RED;
}
@@ -20404,28 +20404,32 @@ void Player::learnQuestRewardedSpells(Quest const* quest)
if(!learnedInfo)
return;
uint32 profSpell = spellmgr.GetSpellRequired(learned_0);
// specialization
if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0 && profSpell)
SpellsRequiringSpellMapBounds spellsRequired = spellmgr.GetSpellsRequiredForSpellBounds(learned_0);
for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequired.first; itr2 != spellsRequired.second; ++itr2)
{
// search other specialization for same prof
for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
uint32 profSpell = itr2->second;
// specialization
if(learnedInfo->Effect[0]==SPELL_EFFECT_TRADE_SKILL && learnedInfo->Effect[1]==0 && profSpell)
{
if(itr->second->state == PLAYERSPELL_REMOVED || itr->first==learned_0)
continue;
// search other specialization for same prof
for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
{
if(itr->second->state == PLAYERSPELL_REMOVED || itr->first==learned_0)
continue;
SpellEntry const *itrInfo = sSpellStore.LookupEntry(itr->first);
if(!itrInfo)
return;
SpellEntry const *itrInfo = sSpellStore.LookupEntry(itr->first);
if(!itrInfo)
return;
// compare only specializations
if(itrInfo->Effect[0]!=SPELL_EFFECT_TRADE_SKILL || itrInfo->Effect[1]!=0)
continue;
// compare only specializations
if(itrInfo->Effect[0]!=SPELL_EFFECT_TRADE_SKILL || itrInfo->Effect[1]!=0)
continue;
// compare same chain spells
if (spellmgr.GetSpellRequired(itr->first) == profSpell)
return;
// compare same chain spells
if (spellmgr.IsSpellRequiringSpell(itr->first, profSpell))
return;
}
}
}
}
+24 -1
View File
@@ -3221,9 +3221,32 @@ void SpellMgr::LoadSpellRequired()
uint32 spell_id = fields[0].GetUInt32();
uint32 spell_req = fields[1].GetUInt32();
// check if chain is made with valid first spell
SpellEntry const * spell = sSpellStore.LookupEntry(spell_id);
if (!spell)
{
sLog.outErrorDb("spell_id %u in `spell_required` table is not found in dbcs, skipped", spell_id);
continue;
}
SpellEntry const * req_spell = sSpellStore.LookupEntry(spell_req);
if (!req_spell)
{
sLog.outErrorDb("req_spell %u in `spell_required` table is not found in dbcs, skipped", spell_req);
continue;
}
if (GetFirstSpellInChain(spell_id) == GetFirstSpellInChain(spell_req))
{
sLog.outErrorDb("req_spell %u and spell_id %u in `spell_required` table are ranks of the same spell, entry not needed, skipped", spell_req, spell_id);
continue;
}
if (IsSpellRequiringSpell(spell_id, spell_req))
{
sLog.outErrorDb("duplicated entry of req_spell %u and spell_id %u in `spell_required`, skipped", spell_req, spell_id);
continue;
}
mSpellReq.insert (std::pair<uint32, uint32>(spell_id, spell_req));
mSpellsReqSpell.insert (std::pair<uint32, uint32>(spell_req, spell_id));
mSpellReq[spell_id] = spell_req;
++rows;
} while (result->NextRow());
+24 -12
View File
@@ -762,10 +762,13 @@ struct SpellChainNode
typedef UNORDERED_MAP<uint32, SpellChainNode> SpellChainMap;
// spell_id req_spell
typedef UNORDERED_MAP<uint32, uint32> SpellRequiredMap;
// spell_id req_spell
typedef std::multimap<uint32, uint32> SpellRequiredMap;
typedef std::pair<SpellRequiredMap::const_iterator,SpellRequiredMap::const_iterator> SpellRequiredMapBounds;
// req_spell spell_id
typedef std::multimap<uint32, uint32> SpellsRequiringSpellMap;
typedef std::pair<SpellsRequiringSpellMap::const_iterator,SpellsRequiringSpellMap::const_iterator> SpellsRequiringSpellMapBounds;
// Spell learning properties (accessed using SpellMgr functions)
struct SpellLearnSkillNode
@@ -966,15 +969,6 @@ class SpellMgr
return &itr->second;
}
uint32 GetSpellRequired(uint32 spell_id) const
{
SpellRequiredMap::const_iterator itr = mSpellReq.find(spell_id);
if(itr == mSpellReq.end())
return NULL;
return itr->second;
}
uint32 GetFirstSpellInChain(uint32 spell_id) const
{
if(SpellChainNode const* node = GetSpellChainNode(spell_id))
@@ -1009,7 +1003,25 @@ class SpellMgr
return 0;
}
SpellsRequiringSpellMap const& GetSpellsRequiringSpell() const { return mSpellsReqSpell; }
SpellRequiredMapBounds GetSpellsRequiredForSpellBounds(uint32 spell_id) const
{
return SpellRequiredMapBounds(mSpellReq.lower_bound(spell_id),mSpellReq.upper_bound(spell_id));
}
SpellsRequiringSpellMapBounds GetSpellsRequiringSpellBounds(uint32 spell_id) const
{
return SpellsRequiringSpellMapBounds(mSpellsReqSpell.lower_bound(spell_id),mSpellsReqSpell.upper_bound(spell_id));
}
bool IsSpellRequiringSpell(uint32 spellid, uint32 req_spellid) const
{
SpellsRequiringSpellMapBounds spellsRequiringSpell = GetSpellsRequiringSpellBounds(req_spellid);
for (SpellsRequiringSpellMap::const_iterator itr = spellsRequiringSpell.first; itr != spellsRequiringSpell.second; ++itr)
{
if (itr->second == spellid)
return true;
}
return false;
}
uint8 GetSpellRank(uint32 spell_id) const
{