*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
@@ -0,0 +1,3 @@
ALTER TABLE spell_required
DROP PRIMARY KEY,
ADD PRIMARY KEY (`spell_id`, `req_spell`);
+1 -2
View File
@@ -6668,7 +6668,7 @@ DROP TABLE IF EXISTS `spell_required`;
CREATE TABLE `spell_required` (
`spell_id` mediumint(9) NOT NULL DEFAULT '0',
`req_spell` mediumint(9) NOT NULL DEFAULT '0',
PRIMARY KEY (`spell_id`)
PRIMARY KEY (`spell_id`, `req_spell`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Spell Additinal Data';
/*!40101 SET character_set_client = @saved_cs_client */;
@@ -6678,7 +6678,6 @@ CREATE TABLE `spell_required` (
LOCK TABLES `spell_required` WRITE;
/*!40000 ALTER TABLE `spell_required` DISABLE KEYS */;
INSERT INTO `spell_required` VALUES (9788,9785),(10656,10662),(10658,10662),(10660,10662),(16689,339),(16810,1062),(16811,5195),(16812,5196),(16813,9852),(17039,9787),(17040,9787),(17041,9787),(17329,9853),(20219,12656),(20222,12656),(25782,19838),(25894,19854),(25899,20911),(25916,25291),(25918,25290),(26797,26790),(26798,26790),(26801,26790),(27009,26989),(27141,27140),(27143,27142),(27681,14752),(28672,28596),(28675,28596),(28677,28596),(48933,48931),(48934,48932),(48937,48935),(48938,48936),(53312,53308),(34767,34769),(23214,13819),(23161,5784),(40120,33943);
/*!40000 ALTER TABLE `spell_required` ENABLE KEYS */;
UNLOCK TABLES;
+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
{