mirror of
https://github.com/mangosfour/server.git
synced 2025-12-13 22:37:03 +00:00
Not store dependent spells in character_spell
* Mark spells learned in result character creating, another spell learning, skill grow, quest reward as dependent and not store its in `character_spell`. * Prevent re-learning known spell in expected state * Prevent re-learning low rank spell as active if higher rank known. * New type of non-stacked ranked spells check: skill dependent spell bonuses. * Activate (show propetly and cast if need) lesser spell rank for non-stackable in spellbooks spells at unlearn high rank
This commit is contained in:
parent
4b5aba18f8
commit
bbf8fd0742
10 changed files with 222 additions and 85 deletions
|
|
@ -3848,7 +3848,7 @@ bool ChatHandler::HandleLearnAllCraftsCommand(const char* /*args*/)
|
||||||
if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
|
if(!spellInfo || !SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_session->GetPlayer()->learnSpell(skillLine->spellId);
|
m_session->GetPlayer()->learnSpell(skillLine->spellId,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3919,7 +3919,7 @@ bool ChatHandler::HandleLearnAllRecipesCommand(const char* args)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !target->HasSpell(spellInfo->Id) )
|
if( !target->HasSpell(spellInfo->Id) )
|
||||||
m_session->GetPlayer()->learnSpell(skillLine->spellId);
|
m_session->GetPlayer()->learnSpell(skillLine->spellId,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id);
|
uint16 maxLevel = target->GetPureMaxSkillValue(skillInfo->id);
|
||||||
|
|
|
||||||
|
|
@ -1638,7 +1638,7 @@ bool ChatHandler::HandleLearnAllCommand(const char* /*args*/)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_session->GetPlayer()->learnSpell(spell);
|
m_session->GetPlayer()->learnSpell(spell,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS);
|
SendSysMessage(LANG_COMMAND_LEARN_MANY_SPELLS);
|
||||||
|
|
@ -1678,7 +1678,7 @@ bool ChatHandler::HandleLearnAllGMCommand(const char* /*args*/)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_session->GetPlayer()->learnSpell(spell);
|
m_session->GetPlayer()->learnSpell(spell,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendSysMessage(LANG_LEARNING_GM_SKILLS);
|
SendSysMessage(LANG_LEARNING_GM_SKILLS);
|
||||||
|
|
@ -1726,7 +1726,7 @@ bool ChatHandler::HandleLearnAllMySpellsCommand(const char* /*args*/)
|
||||||
if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
|
if(!SpellMgr::IsSpellValid(spellInfo,m_session->GetPlayer(),false))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
m_session->GetPlayer()->learnSpell(i);
|
m_session->GetPlayer()->learnSpell(i,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS);
|
SendSysMessage(LANG_COMMAND_LEARN_CLASS_SPELLS);
|
||||||
|
|
@ -1738,7 +1738,7 @@ static void learnAllHighRanks(Player* player, uint32 spellid)
|
||||||
SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext();
|
SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext();
|
||||||
for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr)
|
for(SpellChainMapNext::const_iterator itr = nextMap.lower_bound(spellid); itr != nextMap.upper_bound(spellid); ++itr)
|
||||||
{
|
{
|
||||||
player->learnSpell(itr->second);
|
player->learnSpell(itr->second,false);
|
||||||
learnAllHighRanks(player,itr->second);
|
learnAllHighRanks(player,itr->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1781,7 +1781,7 @@ bool ChatHandler::HandleLearnAllMyTalentsCommand(const char* /*args*/)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// learn highest rank of talent
|
// learn highest rank of talent
|
||||||
player->learnSpell(spellid);
|
player->learnSpell(spellid,false);
|
||||||
|
|
||||||
// and learn all non-talent spell ranks (recursive by tree)
|
// and learn all non-talent spell ranks (recursive by tree)
|
||||||
learnAllHighRanks(player,spellid);
|
learnAllHighRanks(player,spellid);
|
||||||
|
|
@ -1795,7 +1795,7 @@ bool ChatHandler::HandleLearnAllLangCommand(const char* /*args*/)
|
||||||
{
|
{
|
||||||
// skipping UNIVERSAL language (0)
|
// skipping UNIVERSAL language (0)
|
||||||
for(int i = 1; i < LANGUAGES_COUNT; ++i)
|
for(int i = 1; i < LANGUAGES_COUNT; ++i)
|
||||||
m_session->GetPlayer()->learnSpell(lang_description[i].spell_id);
|
m_session->GetPlayer()->learnSpell(lang_description[i].spell_id,false);
|
||||||
|
|
||||||
SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG);
|
SendSysMessage(LANG_COMMAND_LEARN_ALL_LANG);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1869,7 +1869,7 @@ bool ChatHandler::HandleLearnCommand(const char* args)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetPlayer->learnSpell(spell);
|
targetPlayer->learnSpell(spell,false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ void WorldSession::HandleTrainerBuySpellOpcode( WorldPacket & recv_data )
|
||||||
data << uint64(_player->GetGUID()) << uint32(0x016A);
|
data << uint64(_player->GetGUID()) << uint32(0x016A);
|
||||||
SendPacket(&data);
|
SendPacket(&data);
|
||||||
|
|
||||||
_player->learnSpell(spellId);
|
_player->learnSpell(spellId,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12);
|
WorldPacket data(SMSG_TRAINER_BUY_SUCCEEDED, 12);
|
||||||
|
|
|
||||||
|
|
@ -1479,7 +1479,7 @@ void Pet::InitPetCreateSpells()
|
||||||
if(owner->GetTypeId() == TYPEID_PLAYER && !((Player*)owner)->HasSpell(learn_spellproto->Id))
|
if(owner->GetTypeId() == TYPEID_PLAYER && !((Player*)owner)->HasSpell(learn_spellproto->Id))
|
||||||
{
|
{
|
||||||
if(IsPassiveSpell(petspellid)) //learn passive skills when tamed, not sure if thats right
|
if(IsPassiveSpell(petspellid)) //learn passive skills when tamed, not sure if thats right
|
||||||
((Player*)owner)->learnSpell(learn_spellproto->Id);
|
((Player*)owner)->learnSpell(learn_spellproto->Id,false);
|
||||||
else
|
else
|
||||||
AddTeachSpell(learn_spellproto->EffectTriggerSpell[0], learn_spellproto->Id);
|
AddTeachSpell(learn_spellproto->EffectTriggerSpell[0], learn_spellproto->Id);
|
||||||
}
|
}
|
||||||
|
|
@ -1513,7 +1513,7 @@ void Pet::CheckLearning(uint32 spellid)
|
||||||
|
|
||||||
if(urand(0, 100) < 10)
|
if(urand(0, 100) < 10)
|
||||||
{
|
{
|
||||||
((Player*)owner)->learnSpell(itr->second);
|
((Player*)owner)->learnSpell(itr->second,false);
|
||||||
m_teachspells.erase(itr);
|
m_teachspells.erase(itr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2541,7 +2541,7 @@ void Player::AddNewMailDeliverTime(time_t deliver_time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled)
|
bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled)
|
||||||
{
|
{
|
||||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||||
if (!spellInfo)
|
if (!spellInfo)
|
||||||
|
|
@ -2574,29 +2574,78 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
|
|
||||||
PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
|
PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
|
||||||
|
|
||||||
|
bool dependent_set = false;
|
||||||
bool disabled_case = false;
|
bool disabled_case = false;
|
||||||
bool superceded_old = false;
|
bool superceded_old = false;
|
||||||
|
|
||||||
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
|
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
|
||||||
if (itr != m_spells.end())
|
if (itr != m_spells.end())
|
||||||
{
|
{
|
||||||
|
uint32 next_active_spell_id = 0;
|
||||||
|
// fix activate state for non-stackable low rank (and find next spell for !active case)
|
||||||
|
if(!SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
|
||||||
|
{
|
||||||
|
SpellChainMapNext const& nextMap = spellmgr.GetSpellChainNext();
|
||||||
|
for(SpellChainMapNext::const_iterator next_itr = nextMap.lower_bound(spell_id); next_itr != nextMap.upper_bound(spell_id); ++next_itr)
|
||||||
|
{
|
||||||
|
if(HasSpell(next_itr->second))
|
||||||
|
{
|
||||||
|
// high rank already known so this must !active
|
||||||
|
active = false;
|
||||||
|
next_active_spell_id = next_itr->second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// not do anything if already known in expected state
|
||||||
|
if(itr->second->state != PLAYERSPELL_REMOVED && itr->second->active == active &&
|
||||||
|
itr->second->dependent == dependent && itr->second->disabled == disabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// dependent spell known as not dependent, overwrite state
|
||||||
|
if (itr->second->state != PLAYERSPELL_REMOVED && !itr->second->dependent && dependent)
|
||||||
|
{
|
||||||
|
itr->second->dependent = dependent;
|
||||||
|
if (itr->second->state != PLAYERSPELL_NEW)
|
||||||
|
itr->second->state = PLAYERSPELL_CHANGED;
|
||||||
|
dependent_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
// update active state for known spell
|
// update active state for known spell
|
||||||
if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled)
|
if(itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled)
|
||||||
{
|
{
|
||||||
itr->second->active = active;
|
itr->second->active = active;
|
||||||
|
|
||||||
// !IsInWorld() && !learning == explicitly load from DB and then exist in it already and set correctly
|
// !IsInWorld() && !learning == explicitly load from DB and then exist in it already and set correctly
|
||||||
if(!IsInWorld() && !learning)
|
if(!IsInWorld() && !learning && !dependent_set)
|
||||||
itr->second->state = PLAYERSPELL_UNCHANGED;
|
itr->second->state = PLAYERSPELL_UNCHANGED;
|
||||||
else if(itr->second->state != PLAYERSPELL_NEW)
|
else if(itr->second->state != PLAYERSPELL_NEW)
|
||||||
itr->second->state = PLAYERSPELL_CHANGED;
|
itr->second->state = PLAYERSPELL_CHANGED;
|
||||||
|
|
||||||
if(!active)
|
if(active)
|
||||||
|
{
|
||||||
|
if (IsPassiveSpell(spell_id) && IsNeedCastPassiveSpellAtLearn(spellInfo))
|
||||||
|
CastSpell (this,spell_id,true);
|
||||||
|
}
|
||||||
|
else if(IsInWorld())
|
||||||
|
{
|
||||||
|
if(next_active_spell_id)
|
||||||
|
{
|
||||||
|
// update spell ranks in spellbook and action bar
|
||||||
|
WorldPacket data(SMSG_SUPERCEDED_SPELL, (4));
|
||||||
|
data << uint16(spell_id);
|
||||||
|
data << uint16(next_active_spell_id);
|
||||||
|
GetSession()->SendPacket( &data );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
WorldPacket data(SMSG_REMOVED_SPELL, 4);
|
WorldPacket data(SMSG_REMOVED_SPELL, 4);
|
||||||
data << uint16(spell_id);
|
data << uint16(spell_id);
|
||||||
GetSession()->SendPacket(&data);
|
GetSession()->SendPacket(&data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return active; // learn (show in spell book if active now)
|
return active; // learn (show in spell book if active now)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2625,7 +2674,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
default: // known not saved yet spell (new or modified)
|
default: // known not saved yet spell (new or modified)
|
||||||
{
|
{
|
||||||
// can be in case spell loading but learned at some previous spell loading
|
// can be in case spell loading but learned at some previous spell loading
|
||||||
if(!IsInWorld() && !learning)
|
if(!IsInWorld() && !learning && !dependent_set)
|
||||||
itr->second->state = PLAYERSPELL_UNCHANGED;
|
itr->second->state = PLAYERSPELL_UNCHANGED;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -2658,15 +2707,16 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
// non talent spell: learn low ranks (recursive call)
|
// non talent spell: learn low ranks (recursive call)
|
||||||
else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id))
|
else if(uint32 prev_spell = spellmgr.GetPrevSpellInChain(spell_id))
|
||||||
{
|
{
|
||||||
if(!IsInWorld()) // at spells loading, no output, but allow save
|
if(!IsInWorld() || disabled) // at spells loading, no output, but allow save
|
||||||
addSpell(prev_spell,active,true,disabled);
|
addSpell(prev_spell,active,true,true,disabled);
|
||||||
else // at normal learning
|
else // at normal learning
|
||||||
learnSpell(prev_spell);
|
learnSpell(prev_spell,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerSpell *newspell = new PlayerSpell;
|
PlayerSpell *newspell = new PlayerSpell;
|
||||||
newspell->active = active;
|
|
||||||
newspell->state = state;
|
newspell->state = state;
|
||||||
|
newspell->active = active;
|
||||||
|
newspell->dependent = dependent;
|
||||||
newspell->disabled = disabled;
|
newspell->disabled = disabled;
|
||||||
|
|
||||||
// replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible
|
// replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible
|
||||||
|
|
@ -2694,6 +2744,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
|
|
||||||
// mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new)
|
// mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new)
|
||||||
itr->second->active = false;
|
itr->second->active = false;
|
||||||
|
if(itr->second->state != PLAYERSPELL_NEW)
|
||||||
itr->second->state = PLAYERSPELL_CHANGED;
|
itr->second->state = PLAYERSPELL_CHANGED;
|
||||||
superceded_old = true; // new spell replace old in action bars and spell book.
|
superceded_old = true; // new spell replace old in action bars and spell book.
|
||||||
}
|
}
|
||||||
|
|
@ -2736,26 +2787,7 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
// also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
|
// also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
|
||||||
else if (IsPassiveSpell(spell_id))
|
else if (IsPassiveSpell(spell_id))
|
||||||
{
|
{
|
||||||
bool need_cast = false;
|
if(IsNeedCastPassiveSpellAtLearn(spellInfo))
|
||||||
|
|
||||||
switch(spell_id)
|
|
||||||
{
|
|
||||||
// some spells not have stance data expacted cast at form change or present
|
|
||||||
case 5420: need_cast = (m_form == FORM_TREE); break;
|
|
||||||
case 5419: need_cast = (m_form == FORM_TRAVEL); break;
|
|
||||||
case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break;
|
|
||||||
case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break;
|
|
||||||
case 21156: need_cast = (m_form == FORM_BATTLESTANCE); break;
|
|
||||||
case 21178: need_cast = (m_form == FORM_BEAR || m_form == FORM_DIREBEAR); break;
|
|
||||||
case 33948: need_cast = (m_form == FORM_FLIGHT); break;
|
|
||||||
case 34764: need_cast = (m_form == FORM_FLIGHT); break;
|
|
||||||
case 40121: need_cast = (m_form == FORM_FLIGHT_EPIC); break;
|
|
||||||
case 40122: need_cast = (m_form == FORM_FLIGHT_EPIC); break;
|
|
||||||
// another spells have proper stance data
|
|
||||||
default: need_cast = !spellInfo->Stances || m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))); break;
|
|
||||||
}
|
|
||||||
//Check CasterAuraStates
|
|
||||||
if (need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState))))
|
|
||||||
CastSpell(this, spell_id, true);
|
CastSpell(this, spell_id, true);
|
||||||
}
|
}
|
||||||
else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) )
|
else if( IsSpellHaveEffect(spellInfo,SPELL_EFFECT_SKILL_STEP) )
|
||||||
|
|
@ -2840,9 +2872,9 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
if(!itr->second.autoLearned)
|
if(!itr->second.autoLearned)
|
||||||
{
|
{
|
||||||
if(!IsInWorld() || !itr->second.active) // at spells loading, no output, but allow save
|
if(!IsInWorld() || !itr->second.active) // at spells loading, no output, but allow save
|
||||||
addSpell(itr->second.spell,itr->second.active,true,false);
|
addSpell(itr->second.spell,itr->second.active,true,true,false);
|
||||||
else // at normal learning
|
else // at normal learning
|
||||||
learnSpell(itr->second.spell);
|
learnSpell(itr->second.spell,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2856,14 +2888,39 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool disabled
|
||||||
return active && !disabled && !superceded_old;
|
return active && !disabled && !superceded_old;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::learnSpell(uint32 spell_id)
|
bool Player::IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const
|
||||||
|
{
|
||||||
|
bool need_cast = false;
|
||||||
|
|
||||||
|
switch(spellInfo->Id)
|
||||||
|
{
|
||||||
|
// some spells not have stance data expacted cast at form change or present
|
||||||
|
case 5420: need_cast = (m_form == FORM_TREE); break;
|
||||||
|
case 5419: need_cast = (m_form == FORM_TRAVEL); break;
|
||||||
|
case 7376: need_cast = (m_form == FORM_DEFENSIVESTANCE); break;
|
||||||
|
case 7381: need_cast = (m_form == FORM_BERSERKERSTANCE); break;
|
||||||
|
case 21156: need_cast = (m_form == FORM_BATTLESTANCE); break;
|
||||||
|
case 21178: need_cast = (m_form == FORM_BEAR || m_form == FORM_DIREBEAR); break;
|
||||||
|
case 33948: need_cast = (m_form == FORM_FLIGHT); break;
|
||||||
|
case 34764: need_cast = (m_form == FORM_FLIGHT); break;
|
||||||
|
case 40121: need_cast = (m_form == FORM_FLIGHT_EPIC); break;
|
||||||
|
case 40122: need_cast = (m_form == FORM_FLIGHT_EPIC); break;
|
||||||
|
// another spells have proper stance data
|
||||||
|
default: need_cast = !spellInfo->Stances || m_form != 0 && (spellInfo->Stances & (1<<(m_form-1))); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check CasterAuraStates
|
||||||
|
return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraState(spellInfo->CasterAuraState)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::learnSpell(uint32 spell_id, bool dependent)
|
||||||
{
|
{
|
||||||
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
|
PlayerSpellMap::iterator itr = m_spells.find(spell_id);
|
||||||
|
|
||||||
bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false;
|
bool disabled = (itr != m_spells.end()) ? itr->second->disabled : false;
|
||||||
bool active = disabled ? itr->second->active : true;
|
bool active = disabled ? itr->second->active : true;
|
||||||
|
|
||||||
bool learning = addSpell(spell_id,active,true,false);
|
bool learning = addSpell(spell_id,active,true,dependent,false);
|
||||||
|
|
||||||
// learn all disabled higher ranks (recursive)
|
// learn all disabled higher ranks (recursive)
|
||||||
if(disabled)
|
if(disabled)
|
||||||
|
|
@ -2873,7 +2930,7 @@ void Player::learnSpell(uint32 spell_id)
|
||||||
{
|
{
|
||||||
PlayerSpellMap::iterator iter = m_spells.find(i->second);
|
PlayerSpellMap::iterator iter = m_spells.find(i->second);
|
||||||
if (iter != m_spells.end() && iter->second->disabled)
|
if (iter != m_spells.end() && iter->second->disabled)
|
||||||
learnSpell(i->second);
|
learnSpell(i->second,false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2901,10 +2958,8 @@ void Player::removeSpell(uint32 spell_id, bool disabled)
|
||||||
if(HasSpell(itr2->second) && !GetTalentSpellPos(itr2->second))
|
if(HasSpell(itr2->second) && !GetTalentSpellPos(itr2->second))
|
||||||
removeSpell(itr2->second,disabled);
|
removeSpell(itr2->second,disabled);
|
||||||
|
|
||||||
// removing
|
bool cur_active = itr->second->active;
|
||||||
WorldPacket data(SMSG_REMOVED_SPELL, 4);
|
bool cur_dependent = itr->second->dependent;
|
||||||
data << uint16(spell_id);
|
|
||||||
GetSession()->SendPacket(&data);
|
|
||||||
|
|
||||||
if (disabled)
|
if (disabled)
|
||||||
{
|
{
|
||||||
|
|
@ -3017,7 +3072,54 @@ void Player::removeSpell(uint32 spell_id, bool disabled)
|
||||||
for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2)
|
for(SpellLearnSpellMap::const_iterator itr2 = spell_begin; itr2 != spell_end; ++itr2)
|
||||||
removeSpell(itr2->second.spell, disabled);
|
removeSpell(itr2->second.spell, disabled);
|
||||||
|
|
||||||
// TODO: recast if need lesser ranks spell for passive with IsPassiveSpellStackableWithRanks
|
// activate lesser rank in spellbook/action bar, and cast it if need
|
||||||
|
bool prev_activate = false;
|
||||||
|
|
||||||
|
if(uint32 prev_id = spellmgr.GetPrevSpellInChain (spell_id))
|
||||||
|
{
|
||||||
|
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||||
|
|
||||||
|
// if talent then lesser rank also talen and need learn
|
||||||
|
if(talentCosts)
|
||||||
|
learnSpell (prev_id,false);
|
||||||
|
// if ranked non-stackable spell: need activate lesser rank and update dendence state
|
||||||
|
else if(cur_active && !SpellMgr::canStackSpellRanks(spellInfo) && spellmgr.GetSpellRank(spellInfo->Id) != 0)
|
||||||
|
{
|
||||||
|
// need manually update dependence state (learn spell ignore like attempts)
|
||||||
|
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
|
||||||
|
if (prev_itr != m_spells.end())
|
||||||
|
{
|
||||||
|
if(prev_itr->second->dependent != cur_dependent)
|
||||||
|
{
|
||||||
|
prev_itr->second->dependent = cur_dependent;
|
||||||
|
if(prev_itr->second->state != PLAYERSPELL_NEW)
|
||||||
|
prev_itr->second->state = PLAYERSPELL_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now re-learn if need re-activate
|
||||||
|
if(cur_active && !prev_itr->second->active)
|
||||||
|
{
|
||||||
|
if(addSpell(prev_id,true,false,prev_itr->second->dependent,prev_itr->second->disabled))
|
||||||
|
{
|
||||||
|
// downgrade spell ranks in spellbook and action bar
|
||||||
|
WorldPacket data(SMSG_SUPERCEDED_SPELL, (4));
|
||||||
|
data << uint16(spell_id);
|
||||||
|
data << uint16(prev_id);
|
||||||
|
GetSession()->SendPacket( &data );
|
||||||
|
prev_activate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove from spell book if not replaced by lesser rank
|
||||||
|
if(!prev_activate)
|
||||||
|
{
|
||||||
|
WorldPacket data(SMSG_REMOVED_SPELL, 4);
|
||||||
|
data << uint16(spell_id);
|
||||||
|
GetSession()->SendPacket(&data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::RemoveArenaSpellCooldowns()
|
void Player::RemoveArenaSpellCooldowns()
|
||||||
|
|
@ -4708,7 +4810,7 @@ bool Player::UpdateCraftSkill(uint32 spellid)
|
||||||
if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY)
|
if(spellEntry && spellEntry->Mechanic==MECHANIC_DISCOVERY)
|
||||||
{
|
{
|
||||||
if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
|
if(uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->skillId, spellid, this))
|
||||||
learnSpell(discoveredSpell);
|
learnSpell(discoveredSpell,false);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 craft_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_CRAFTING);
|
uint32 craft_skill_gain = sWorld.getConfig(CONFIG_SKILL_GAIN_CRAFTING);
|
||||||
|
|
@ -15148,7 +15250,7 @@ void Player::_LoadSpells(QueryResult *result)
|
||||||
{
|
{
|
||||||
Field *fields = result->Fetch();
|
Field *fields = result->Fetch();
|
||||||
|
|
||||||
addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, fields[2].GetBool());
|
addSpell(fields[0].GetUInt16(), fields[1].GetBool(), false, false, fields[2].GetBool());
|
||||||
}
|
}
|
||||||
while( result->NextRow() );
|
while( result->NextRow() );
|
||||||
|
|
||||||
|
|
@ -15910,7 +16012,9 @@ void Player::_SaveSpells()
|
||||||
++next;
|
++next;
|
||||||
if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED)
|
if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED)
|
||||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first);
|
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first);
|
||||||
if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED)
|
|
||||||
|
// add only changed/new not dependent spells
|
||||||
|
if (!itr->second->dependent && (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED))
|
||||||
CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,active,disabled) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0);
|
CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,active,disabled) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second->active ? 1 : 0,itr->second->disabled ? 1 : 0);
|
||||||
|
|
||||||
if (itr->second->state == PLAYERSPELL_REMOVED)
|
if (itr->second->state == PLAYERSPELL_REMOVED)
|
||||||
|
|
@ -18129,9 +18233,9 @@ void Player::learnDefaultSpells()
|
||||||
uint32 tspell = *itr;
|
uint32 tspell = *itr;
|
||||||
sLog.outDebug("PLAYER (Class: %u Race: %u): Adding initial spell, id = %u",uint32(getClass()),uint32(getRace()), tspell);
|
sLog.outDebug("PLAYER (Class: %u Race: %u): Adding initial spell, id = %u",uint32(getClass()),uint32(getRace()), tspell);
|
||||||
if(!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add
|
if(!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add
|
||||||
addSpell(tspell,true,true,false);
|
addSpell(tspell,true,true,true,false);
|
||||||
else // but send in normal spell in game learn case
|
else // but send in normal spell in game learn case
|
||||||
learnSpell(tspell);
|
learnSpell(tspell,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -18241,8 +18345,8 @@ void Player::learnSkillRewardedSpells(uint32 skill_id )
|
||||||
|
|
||||||
if (sSpellStore.LookupEntry(pAbility->spellId))
|
if (sSpellStore.LookupEntry(pAbility->spellId))
|
||||||
{
|
{
|
||||||
// Ok need learn spell
|
// Ok need learn dependent spell
|
||||||
learnSpell(pAbility->spellId);
|
learnSpell(pAbility->spellId,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,9 @@ enum PlayerSpellState
|
||||||
struct PlayerSpell
|
struct PlayerSpell
|
||||||
{
|
{
|
||||||
PlayerSpellState state : 8;
|
PlayerSpellState state : 8;
|
||||||
bool active : 1;
|
bool active : 1; // show in spellbook
|
||||||
bool disabled : 1;
|
bool dependent : 1; // learned as result another spell learn, skill grow, quest reward, etc
|
||||||
|
bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks
|
||||||
};
|
};
|
||||||
|
|
||||||
// Spell modifier (used for modify other spells)
|
// Spell modifier (used for modify other spells)
|
||||||
|
|
@ -1477,11 +1478,12 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
bool HasSpell(uint32 spell) const;
|
bool HasSpell(uint32 spell) const;
|
||||||
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
|
TrainerSpellState GetTrainerSpellState(TrainerSpell const* trainer_spell) const;
|
||||||
bool IsSpellFitByClassAndRace( uint32 spell_id ) const;
|
bool IsSpellFitByClassAndRace( uint32 spell_id ) const;
|
||||||
|
bool IsNeedCastPassiveSpellAtLearn(SpellEntry const* spellInfo) const;
|
||||||
|
|
||||||
void SendProficiency(uint8 pr1, uint32 pr2);
|
void SendProficiency(uint8 pr1, uint32 pr2);
|
||||||
void SendInitialSpells();
|
void SendInitialSpells();
|
||||||
bool addSpell(uint32 spell_id, bool active, bool learning, bool disabled);
|
bool addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled);
|
||||||
void learnSpell(uint32 spell_id);
|
void learnSpell(uint32 spell_id, bool dependent);
|
||||||
void removeSpell(uint32 spell_id, bool disabled = false);
|
void removeSpell(uint32 spell_id, bool disabled = false);
|
||||||
void resetSpells();
|
void resetSpells();
|
||||||
void learnDefaultSpells();
|
void learnDefaultSpells();
|
||||||
|
|
@ -1768,7 +1770,7 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
int16 GetSkillPermBonusValue(uint32 skill) const;
|
int16 GetSkillPermBonusValue(uint32 skill) const;
|
||||||
int16 GetSkillTempBonusValue(uint32 skill) const;
|
int16 GetSkillTempBonusValue(uint32 skill) const;
|
||||||
bool HasSkill(uint32 skill) const;
|
bool HasSkill(uint32 skill) const;
|
||||||
void learnSkillRewardedSpells( uint32 id );
|
void learnSkillRewardedSpells(uint32 id);
|
||||||
void learnSkillRewardedSpells();
|
void learnSkillRewardedSpells();
|
||||||
|
|
||||||
void SetDontMove(bool dontMove);
|
void SetDontMove(bool dontMove);
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ void WorldSession::HandleLearnTalentOpcode( WorldPacket & recv_data )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// learn! (other talent ranks will unlearned at learning)
|
// learn! (other talent ranks will unlearned at learning)
|
||||||
GetPlayer( )->learnSpell(spellid);
|
GetPlayer( )->learnSpell(spellid,false);
|
||||||
sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid);
|
sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talent_id, requested_rank, spellid);
|
||||||
|
|
||||||
// update free talent points
|
// update free talent points
|
||||||
|
|
|
||||||
|
|
@ -3345,7 +3345,7 @@ void Spell::EffectLearnSpell(uint32 i)
|
||||||
Player *player = (Player*)unitTarget;
|
Player *player = (Player*)unitTarget;
|
||||||
|
|
||||||
uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
|
uint32 spellToLearn = ((m_spellInfo->Id==SPELL_ID_GENERIC_LEARN) || (m_spellInfo->Id==SPELL_ID_GENERIC_LEARN_PET)) ? damage : m_spellInfo->EffectTriggerSpell[i];
|
||||||
player->learnSpell(spellToLearn);
|
player->learnSpell(spellToLearn,false);
|
||||||
|
|
||||||
sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
|
sLog.outDebug( "Spell: Player %u have learned spell %u from NpcGUID=%u", player->GetGUIDLow(), spellToLearn, m_caster->GetGUIDLow() );
|
||||||
}
|
}
|
||||||
|
|
@ -4866,7 +4866,7 @@ void Spell::EffectScriptEffect(uint32 effIndex)
|
||||||
|
|
||||||
// learn random explicit discovery recipe (if any)
|
// learn random explicit discovery recipe (if any)
|
||||||
if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
|
if(uint32 discoveredSpell = GetExplicitDiscoverySpell(m_spellInfo->Id, player))
|
||||||
player->learnSpell(discoveredSpell);
|
player->learnSpell(discoveredSpell,false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1016,29 +1016,39 @@ bool SpellMgr::IsRankSpellDueToSpell(SpellEntry const *spellInfo_1,uint32 spellI
|
||||||
|
|
||||||
bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
|
bool SpellMgr::canStackSpellRanks(SpellEntry const *spellInfo)
|
||||||
{
|
{
|
||||||
|
if(IsPassiveSpell(spellInfo->Id)) // ranked passive spell
|
||||||
|
return false;
|
||||||
if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)
|
if(spellInfo->powerType != POWER_MANA && spellInfo->powerType != POWER_HEALTH)
|
||||||
return false;
|
return false;
|
||||||
if(IsProfessionOrRidingSpell(spellInfo->Id))
|
if(IsProfessionOrRidingSpell(spellInfo->Id))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if(spellmgr.IsSkillBonusSpell(spellInfo->Id))
|
||||||
|
return false;
|
||||||
|
|
||||||
// All stance spells. if any better way, change it.
|
// All stance spells. if any better way, change it.
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
|
switch(spellInfo->SpellFamilyName)
|
||||||
|
{
|
||||||
|
case SPELLFAMILY_PALADIN:
|
||||||
// Paladin aura Spell
|
// Paladin aura Spell
|
||||||
if(spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN
|
if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID)
|
||||||
&& spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AREA_AURA_RAID)
|
|
||||||
return false;
|
return false;
|
||||||
|
break;
|
||||||
|
case SPELLFAMILY_DRUID:
|
||||||
// Druid form Spell
|
// Druid form Spell
|
||||||
if(spellInfo->SpellFamilyName == SPELLFAMILY_DRUID
|
if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA &&
|
||||||
&& spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
|
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
|
||||||
&& spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
|
|
||||||
return false;
|
return false;
|
||||||
|
break;
|
||||||
|
case SPELLFAMILY_ROGUE:
|
||||||
// Rogue Stealth
|
// Rogue Stealth
|
||||||
if(spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE
|
if (spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA &&
|
||||||
&& spellInfo->Effect[i]==SPELL_EFFECT_APPLY_AURA
|
spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
|
||||||
&& spellInfo->EffectApplyAuraName[i] == SPELL_AURA_MOD_SHAPESHIFT)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1450,6 +1460,24 @@ bool SpellMgr::IsPrimaryProfessionFirstRankSpell(uint32 spellId) const
|
||||||
return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;
|
return IsPrimaryProfessionSpell(spellId) && GetSpellRank(spellId)==1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SpellMgr::IsSkillBonusSpell(uint32 spellId) const
|
||||||
|
{
|
||||||
|
SkillLineAbilityMap::const_iterator lower = GetBeginSkillLineAbilityMap(spellId);
|
||||||
|
SkillLineAbilityMap::const_iterator upper = GetEndSkillLineAbilityMap(spellId);
|
||||||
|
|
||||||
|
for(SkillLineAbilityMap::const_iterator _spell_idx = lower; _spell_idx != upper; ++_spell_idx)
|
||||||
|
{
|
||||||
|
SkillLineAbilityEntry const *pAbility = _spell_idx->second;
|
||||||
|
if (!pAbility || pAbility->learnOnGetSkill != ABILITY_LEARNED_ON_GET_PROFESSION_SKILL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(pAbility->req_skill_value > 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const
|
SpellEntry const* SpellMgr::SelectAuraRankForPlayerLevel(SpellEntry const* spellInfo, uint32 playerLevel) const
|
||||||
{
|
{
|
||||||
// ignore passive spells
|
// ignore passive spells
|
||||||
|
|
|
||||||
|
|
@ -897,6 +897,9 @@ class SpellMgr
|
||||||
static bool IsPrimaryProfessionSpell(uint32 spellId);
|
static bool IsPrimaryProfessionSpell(uint32 spellId);
|
||||||
bool IsPrimaryProfessionFirstRankSpell(uint32 spellId) const;
|
bool IsPrimaryProfessionFirstRankSpell(uint32 spellId) const;
|
||||||
|
|
||||||
|
bool IsSkillBonusSpell(uint32 spellId) const;
|
||||||
|
|
||||||
|
|
||||||
// Spell script targets
|
// Spell script targets
|
||||||
SpellScriptTarget::const_iterator GetBeginSpellScriptTarget(uint32 spell_id) const
|
SpellScriptTarget::const_iterator GetBeginSpellScriptTarget(uint32 spell_id) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue