Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, int32 fromSkill /*= 0*/)
- {
- SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
- if (!spellInfo)
- {
- // do character spell book cleanup (all characters)
- if (!IsInWorld() && !learning) // spell load case
- {
- TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) does not exist. deleting for all characters in `character_spell`.", spellId);
- DeleteSpellFromAllPlayers(spellId);
- }
- else
- TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) does not exist", spellId);
- return false;
- }
- if (!SpellMgr::IsSpellValid(spellInfo, this, false))
- {
- // do character spell book cleanup (all characters)
- if (!IsInWorld() && !learning) // spell load case
- {
- TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) is invalid. deleting for all characters in `character_spell`.", spellId);
- DeleteSpellFromAllPlayers(spellId);
- }
- else
- TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: %u) is invalid", spellId);
- return false;
- }
- PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
- bool dependent_set = false;
- bool disabled_case = false;
- bool superceded_old = false;
- PlayerSpellMap::iterator itr = m_spells.find(spellId);
- // Remove temporary spell if found to prevent conflicts
- if (itr != m_spells.end() && itr->second->state == PLAYERSPELL_TEMPORARY)
- RemoveTemporarySpell(spellId);
- else 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 (spellInfo->IsRanked())
- {
- if (uint32 next = sSpellMgr->GetNextSpellInChain(spellId))
- {
- if (HasSpell(next))
- {
- // high rank already known so this must !active
- active = false;
- next_active_spell_id = next;
- }
- }
- }
- // 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)
- {
- if (!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly
- itr->second->state = PLAYERSPELL_UNCHANGED;
- 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
- if (itr->second->active != active && itr->second->state != PLAYERSPELL_REMOVED && !itr->second->disabled)
- {
- itr->second->active = active;
- if (!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly
- itr->second->state = PLAYERSPELL_UNCHANGED;
- else if (itr->second->state != PLAYERSPELL_NEW)
- itr->second->state = PLAYERSPELL_CHANGED;
- if (active)
- {
- if (spellInfo->IsPassive() && IsNeedCastPassiveSpellAtLearn(spellInfo))
- CastSpell(this, spellId, true);
- }
- else if (IsInWorld())
- {
- if (next_active_spell_id)
- SendSupercededSpell(spellId, next_active_spell_id);
- else
- {
- WorldPackets::Spells::UnlearnedSpells unlearnedSpells;
- unlearnedSpells.SpellID.push_back(spellId);
- SendDirectMessage(unlearnedSpells.Write());
- }
- }
- return active; // learn (show in spell book if active now)
- }
- if (itr->second->disabled != disabled && itr->second->state != PLAYERSPELL_REMOVED)
- {
- if (itr->second->state != PLAYERSPELL_NEW)
- itr->second->state = PLAYERSPELL_CHANGED;
- itr->second->disabled = disabled;
- if (disabled)
- return false;
- disabled_case = true;
- }
- else switch (itr->second->state)
- {
- case PLAYERSPELL_UNCHANGED: // known saved spell
- return false;
- case PLAYERSPELL_REMOVED: // re-learning removed not saved spell
- {
- delete itr->second;
- m_spells.erase(itr);
- state = PLAYERSPELL_CHANGED;
- break; // need re-add
- }
- default: // known not saved yet spell (new or modified)
- {
- // can be in case spell loading but learned at some previous spell loading
- if (!IsInWorld() && !learning && !dependent_set)
- itr->second->state = PLAYERSPELL_UNCHANGED;
- return false;
- }
- }
- }
- if (!disabled_case) // skip new spell adding if spell already known (disabled spells case)
- {
- // non talent spell: learn low ranks (recursive call)
- if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId))
- {
- if (!IsInWorld() || disabled) // at spells loading, no output, but allow save
- AddSpell(prev_spell, active, true, true, disabled, false, fromSkill);
- else // at normal learning
- LearnSpell(prev_spell, true, fromSkill);
- }
- PlayerSpell* newspell = new PlayerSpell;
- newspell->state = state;
- newspell->active = active;
- newspell->dependent = 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->IsRanked())
- {
- for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
- {
- if (itr2->second->state == PLAYERSPELL_REMOVED)
- continue;
- SpellInfo const* i_spellInfo = sSpellMgr->GetSpellInfo(itr2->first);
- if (!i_spellInfo)
- continue;
- if (spellInfo->IsDifferentRankOf(i_spellInfo))
- {
- if (itr2->second->active)
- {
- if (spellInfo->IsHighRankOf(i_spellInfo))
- {
- if (IsInWorld()) // not send spell (re-/over-)learn packets at loading
- SendSupercededSpell(itr2->first, spellId);
- // mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new)
- 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
- {
- if (IsInWorld()) // not send spell (re-/over-)learn packets at loading
- SendSupercededSpell(spellId, itr2->first);
- // mark new spell as disable (not learned yet for client and will not learned)
- newspell->active = false;
- if (newspell->state != PLAYERSPELL_NEW)
- newspell->state = PLAYERSPELL_CHANGED;
- }
- }
- }
- }
- }
- m_spells[spellId] = newspell;
- // return false if spell disabled
- if (newspell->disabled)
- return false;
- }
- // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
- // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
- if (!loading && spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
- {
- // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
- CastSpell(this, spellId, true);
- }
- // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
- else if (spellInfo->IsPassive())
- {
- if (IsNeedCastPassiveSpellAtLearn(spellInfo))
- CastSpell(this, spellId, true);
- }
- else if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP))
- {
- CastSpell(this, spellId, true);
- return false;
- }
- // update free primary prof.points (if any, can be none in case GM .learn prof. learning)
- if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
- {
- if (spellInfo->IsPrimaryProfessionFirstRank())
- SetFreePrimaryProfessions(freeProfs - 1);
- }
- SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
- if (SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId))
- {
- // add dependent skills if this spell is not learned from adding skill already
- if (spellLearnSkill->skill != fromSkill)
- {
- uint32 skill_value = GetPureSkillValue(spellLearnSkill->skill);
- uint32 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
- if (skill_value < spellLearnSkill->value)
- skill_value = spellLearnSkill->value;
- uint32 new_skill_max_value = spellLearnSkill->maxvalue == 0 ? GetMaxSkillValueForLevel() : spellLearnSkill->maxvalue;
- if (skill_max_value < new_skill_max_value)
- skill_max_value = new_skill_max_value;
- SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value);
- }
- }
- else
- {
- // not ranked skills
- for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
- {
- SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
- if (!pSkill)
- continue;
- if (_spell_idx->second->SkillLine == fromSkill)
- continue;
- // Runeforging special case
- if ((_spell_idx->second->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(_spell_idx->second->SkillLine)) || ((_spell_idx->second->SkillLine == SKILL_RUNEFORGING) && _spell_idx->second->TrivialSkillLineRankHigh == 0))
- if (SkillRaceClassInfoEntry const* rcInfo = sDB2Manager.GetSkillRaceClassInfo(_spell_idx->second->SkillLine, getRace(), getClass()))
- LearnDefaultSkill(rcInfo);
- }
- }
- // learn dependent spells
- SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spellId);
- for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
- {
- if (!itr2->second.AutoLearned)
- {
- if (!IsInWorld() || !itr2->second.Active) // at spells loading, no output, but allow save
- AddSpell(itr2->second.Spell, itr2->second.Active, true, true, false);
- else // at normal learning
- LearnSpell(itr2->second.Spell, true);
- }
- if (itr2->second.OverridesSpell && itr2->second.Active)
- AddOverrideSpell(itr2->second.OverridesSpell, itr2->second.Spell);
- }
- if (!GetSession()->PlayerLoading())
- {
- // not ranked skills
- for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
- {
- UpdateCriteria(CRITERIA_TYPE_LEARN_SKILL_LINE, _spell_idx->second->SkillLine);
- UpdateCriteria(CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS, _spell_idx->second->SkillLine);
- }
- UpdateCriteria(CRITERIA_TYPE_LEARN_SPELL, spellId);
- }
- // needs to be when spell is already learned, to prevent infinite recursion crashes
- if (sDB2Manager.GetMount(spellId))
- GetSession()->GetCollectionMgr()->AddMount(spellId, MOUNT_STATUS_NONE, false, IsInWorld() ? false : true);
- // need to add Battle pets automatically into pet journal
- for (BattlePetSpeciesEntry const* entry : sBattlePetSpeciesStore)
- {
- if (entry->SummonSpellID == int32(spellId) && GetSession()->GetBattlePetMgr()->GetPetCount(entry->ID) == 0)
- {
- GetSession()->GetBattlePetMgr()->AddPet(entry->ID, entry->CreatureID, BattlePetMgr::RollPetBreed(entry->ID), BattlePetMgr::GetDefaultPetQuality(entry->ID));
- UpdateCriteria(CRITERIA_TYPE_OWN_BATTLE_PET_COUNT);
- break;
- }
- }
- // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell
- return active && !disabled && !superceded_old;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement