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:
VladimirMangos 2009-01-24 07:18:02 +03:00
parent 4b5aba18f8
commit bbf8fd0742
10 changed files with 222 additions and 85 deletions

View file

@ -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);

View file

@ -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;
} }

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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);
} }
} }
} }

View file

@ -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();

View file

@ -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

View file

@ -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;
} }
} }

View file

@ -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

View file

@ -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
{ {