mirror of
https://github.com/mangosfour/server.git
synced 2025-12-14 16:37:01 +00:00
Merge remote branch 'origin/master' into 330
This commit is contained in:
commit
d131f137cc
44 changed files with 670 additions and 498 deletions
|
|
@ -2533,16 +2533,17 @@ void Player::GiveLevel(uint32 level)
|
|||
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL);
|
||||
}
|
||||
|
||||
void Player::InitTalentForLevel()
|
||||
void Player::UpdateFreeTalentPoints(bool resetIfNeed)
|
||||
{
|
||||
uint32 level = getLevel();
|
||||
// talents base at level diff ( talents = level - 9 but some can be used already)
|
||||
if(level < 10)
|
||||
if (level < 10)
|
||||
{
|
||||
// Remove all talent points
|
||||
if(m_usedTalentCount > 0) // Free any used talents
|
||||
if (m_usedTalentCount > 0) // Free any used talents
|
||||
{
|
||||
resetTalents(true);
|
||||
if (resetIfNeed)
|
||||
resetTalents(true);
|
||||
SetFreeTalentPoints(0);
|
||||
}
|
||||
}
|
||||
|
|
@ -2551,9 +2552,9 @@ void Player::InitTalentForLevel()
|
|||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
// if used more that have then reset
|
||||
if(m_usedTalentCount > talentPointsForLevel)
|
||||
if (m_usedTalentCount > talentPointsForLevel)
|
||||
{
|
||||
if (GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
|
||||
if (resetIfNeed && GetSession()->GetSecurity() < SEC_ADMINISTRATOR)
|
||||
resetTalents(true);
|
||||
else
|
||||
SetFreeTalentPoints(0);
|
||||
|
|
@ -2562,8 +2563,13 @@ void Player::InitTalentForLevel()
|
|||
else
|
||||
SetFreeTalentPoints(talentPointsForLevel-m_usedTalentCount);
|
||||
}
|
||||
}
|
||||
|
||||
if(!GetSession()->PlayerLoading())
|
||||
void Player::InitTalentForLevel()
|
||||
{
|
||||
UpdateFreeTalentPoints();
|
||||
|
||||
if (!GetSession()->PlayerLoading())
|
||||
SendTalentsInfoData(false); // update at client
|
||||
}
|
||||
|
||||
|
|
@ -3011,10 +3017,12 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
|
|||
}
|
||||
}
|
||||
|
||||
TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id);
|
||||
|
||||
if(!disabled_case) // skip new spell adding if spell already known (disabled spells case)
|
||||
{
|
||||
// talent: unlearn all other talent ranks (high and low)
|
||||
if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id))
|
||||
if (talentPos)
|
||||
{
|
||||
if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id ))
|
||||
{
|
||||
|
|
@ -3100,11 +3108,45 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(spell_id);
|
||||
if (talentPos)
|
||||
{
|
||||
// update talent map
|
||||
PlayerTalentMap::iterator iter = m_talents[m_activeSpec].find(talentPos->talent_id);
|
||||
if (iter != m_talents[m_activeSpec].end())
|
||||
{
|
||||
// check if ranks different or removed
|
||||
if ((*iter).second.state == PLAYERSPELL_REMOVED || talentPos->rank != (*iter).second.currentRank)
|
||||
{
|
||||
(*iter).second.currentRank = talentPos->rank;
|
||||
|
||||
if ((*iter).second.state != PLAYERSPELL_NEW)
|
||||
(*iter).second.state = PLAYERSPELL_CHANGED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerTalent talent;
|
||||
talent.currentRank = talentPos->rank;
|
||||
talent.m_talentEntry = sTalentStore.LookupEntry(talentPos->talent_id);
|
||||
talent.state = IsInWorld() ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
|
||||
m_talents[m_activeSpec][talentPos->talent_id] = talent;
|
||||
}
|
||||
|
||||
// update used talent points count
|
||||
m_usedTalentCount += GetTalentSpellCost(talentPos);
|
||||
UpdateFreeTalentPoints(false);
|
||||
}
|
||||
|
||||
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
|
||||
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
|
||||
{
|
||||
if(sSpellMgr.IsPrimaryProfessionFirstRankSpell(spell_id))
|
||||
SetFreePrimaryProfessions(freeProfs-1);
|
||||
}
|
||||
|
||||
// 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 (talentCost > 0 && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL))
|
||||
if (talentPos && IsSpellHaveEffect(spellInfo,SPELL_EFFECT_LEARN_SPELL))
|
||||
{
|
||||
// ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
|
||||
CastSpell(this, spell_id, true);
|
||||
|
|
@ -3121,16 +3163,6 @@ bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependen
|
|||
return false;
|
||||
}
|
||||
|
||||
// update used talent points count
|
||||
m_usedTalentCount += talentCost;
|
||||
|
||||
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
|
||||
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
|
||||
{
|
||||
if(sSpellMgr.IsPrimaryProfessionFirstRankSpell(spell_id))
|
||||
SetFreePrimaryProfessions(freeProfs-1);
|
||||
}
|
||||
|
||||
// add dependent skills
|
||||
uint16 maxskill = GetMaxSkillValueForLevel();
|
||||
|
||||
|
|
@ -3275,7 +3307,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
|
||||
// re-search, it can be corrupted in prev loop
|
||||
itr = m_spells.find(spell_id);
|
||||
if (itr == m_spells.end())
|
||||
if (itr == m_spells.end() || itr->second.state == PLAYERSPELL_REMOVED)
|
||||
return; // already unleared
|
||||
|
||||
bool cur_active = itr->second.active;
|
||||
|
|
@ -3302,14 +3334,30 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
if(PetAura const* petSpell = sSpellMgr.GetPetAura(spell_id, SpellEffectIndex(i)))
|
||||
RemovePetAura(petSpell);
|
||||
|
||||
// free talent points
|
||||
uint32 talentCosts = GetTalentSpellCost(spell_id);
|
||||
if(talentCosts > 0)
|
||||
TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id);
|
||||
if (talentPos)
|
||||
{
|
||||
// update talent map
|
||||
PlayerTalentMap::iterator iter = m_talents[m_activeSpec].find(talentPos->talent_id);
|
||||
if (iter != m_talents[m_activeSpec].end())
|
||||
{
|
||||
if ((*iter).second.state != PLAYERSPELL_NEW)
|
||||
(*iter).second.state = PLAYERSPELL_REMOVED;
|
||||
else
|
||||
m_talents[m_activeSpec].erase(iter);
|
||||
}
|
||||
else
|
||||
sLog.outError("removeSpell: Player (GUID: %u) has talent spell (id: %u) but doesn't have talent",GetGUIDLow(), spell_id );
|
||||
|
||||
// free talent points
|
||||
uint32 talentCosts = GetTalentSpellCost(talentPos);
|
||||
|
||||
if(talentCosts < m_usedTalentCount)
|
||||
m_usedTalentCount -= talentCosts;
|
||||
else
|
||||
m_usedTalentCount = 0;
|
||||
|
||||
UpdateFreeTalentPoints(false);
|
||||
}
|
||||
|
||||
// update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning)
|
||||
|
|
@ -3397,7 +3445,7 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
|
||||
// if talent then lesser rank also talent and need learn
|
||||
if (talentCosts)
|
||||
if (talentPos)
|
||||
{
|
||||
if(learn_low_rank)
|
||||
learnSpell(prev_id, false);
|
||||
|
|
@ -3433,6 +3481,17 @@ void Player::removeSpell(uint32 spell_id, bool disabled, bool learn_low_rank, bo
|
|||
}
|
||||
}
|
||||
|
||||
if (m_canTitanGrip)
|
||||
{
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
if (IsSpellHaveEffect(spellInfo, SPELL_EFFECT_TITAN_GRIP))
|
||||
{
|
||||
m_canTitanGrip = false;
|
||||
if(sWorld.getConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET))
|
||||
AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
}
|
||||
|
||||
// remove from spell book if not replaced by lesser rank
|
||||
if (!prev_activate && sendUpdate)
|
||||
{
|
||||
|
|
@ -3613,11 +3672,9 @@ bool Player::resetTalents(bool no_cost)
|
|||
if(HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
|
||||
RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS,true);
|
||||
|
||||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
if (m_usedTalentCount == 0)
|
||||
{
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
UpdateFreeTalentPoints(false); // for fix if need counter
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -3634,56 +3691,46 @@ bool Player::resetTalents(bool no_cost)
|
|||
}
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
|
||||
for (PlayerTalentMap::iterator iter = m_talents[m_activeSpec].begin(); iter != m_talents[m_activeSpec].end();)
|
||||
{
|
||||
TalentEntry const *talentInfo = sTalentStore.LookupEntry(i);
|
||||
if (iter->second.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!talentInfo) continue;
|
||||
TalentEntry const *talentInfo = (*iter).second.m_talentEntry;
|
||||
if (!talentInfo)
|
||||
{
|
||||
iter = m_talents[m_activeSpec].erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
|
||||
|
||||
if(!talentTabInfo)
|
||||
if (!talentTabInfo)
|
||||
{
|
||||
iter = m_talents[m_activeSpec].erase(iter);
|
||||
continue;
|
||||
}
|
||||
|
||||
// unlearn only talents for character class
|
||||
// some spell learned by one class as normal spells or know at creation but another class learn it as talent,
|
||||
// to prevent unexpected lost normal learned spell skip another class talents
|
||||
if( (getClassMask() & talentTabInfo->ClassMask) == 0 )
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
{
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < MAX_TALENT_RANK; ++j)
|
||||
{
|
||||
for(PlayerSpellMap::iterator itr = GetSpellMap().begin(); itr != GetSpellMap().end();)
|
||||
{
|
||||
if(itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
if (talentInfo->RankID[j])
|
||||
removeSpell(talentInfo->RankID[j],!IsPassiveSpell(talentInfo->RankID[j]),false);
|
||||
|
||||
// remove learned spells (all ranks)
|
||||
uint32 itrFirstId = sSpellMgr.GetFirstSpellInChain(itr->first);
|
||||
|
||||
// unlearn if first rank is talent or learned by talent
|
||||
if (itrFirstId == talentInfo->RankID[j])
|
||||
{
|
||||
removeSpell(itr->first,!IsPassiveSpell(itr->first),false);
|
||||
itr = GetSpellMap().begin();
|
||||
continue;
|
||||
}
|
||||
else if (sSpellMgr.IsSpellLearnToSpell(talentInfo->RankID[j],itrFirstId))
|
||||
{
|
||||
removeSpell(itr->first,!IsPassiveSpell(itr->first));
|
||||
itr = GetSpellMap().begin();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
iter = m_talents[m_activeSpec].begin();
|
||||
}
|
||||
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
UpdateFreeTalentPoints(false);
|
||||
|
||||
if(!no_cost)
|
||||
{
|
||||
|
|
@ -3704,15 +3751,6 @@ bool Player::resetTalents(bool no_cost)
|
|||
RemovePet(NULL,PET_SAVE_NOT_IN_SLOT, true);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
if(m_canTitanGrip)
|
||||
{
|
||||
m_canTitanGrip = false;
|
||||
if(sWorld.getConfig(CONFIG_BOOL_OFFHAND_CHECK_AT_TALENTS_RESET))
|
||||
AutoUnequipOffhandIfNeed();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -4120,6 +4158,7 @@ void Player::DeleteFromDB(uint64 playerguid, uint32 accountId, bool updateRealmC
|
|||
CharacterDatabase.PExecute("DELETE FROM character_skills WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell_cooldown WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_ticket WHERE guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM item_instance WHERE owner_guid = '%u'",guid);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_social WHERE guid = '%u' OR friend='%u'",guid,guid);
|
||||
|
|
@ -4318,7 +4357,7 @@ Corpse* Player::CreateCorpse()
|
|||
Corpse *corpse = new Corpse( (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) ? CORPSE_RESURRECTABLE_PVP : CORPSE_RESURRECTABLE_PVE );
|
||||
SetPvPDeath(false);
|
||||
|
||||
if(!corpse->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_CORPSE), this))
|
||||
if (!corpse->Create(sObjectMgr.GenerateLowGuid(HIGHGUID_CORPSE), this))
|
||||
{
|
||||
delete corpse;
|
||||
return NULL;
|
||||
|
|
@ -4342,11 +4381,11 @@ Corpse* Player::CreateCorpse()
|
|||
corpse->SetUInt32Value( CORPSE_FIELD_BYTES_2, _cfb2 );
|
||||
|
||||
uint32 flags = CORPSE_FLAG_UNK2;
|
||||
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
|
||||
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_HELM))
|
||||
flags |= CORPSE_FLAG_HIDE_HELM;
|
||||
if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
|
||||
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_HIDE_CLOAK))
|
||||
flags |= CORPSE_FLAG_HIDE_CLOAK;
|
||||
if(InBattleGround() && !InArena())
|
||||
if (InBattleGround() && !InArena())
|
||||
flags |= CORPSE_FLAG_LOOTABLE; // to be able to remove insignia
|
||||
corpse->SetUInt32Value( CORPSE_FIELD_FLAGS, flags );
|
||||
|
||||
|
|
@ -4359,7 +4398,7 @@ Corpse* Player::CreateCorpse()
|
|||
uint32 _cfi;
|
||||
for (int i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
if(m_items[i])
|
||||
if (m_items[i])
|
||||
{
|
||||
iDisplayID = m_items[i]->GetProto()->DisplayInfoID;
|
||||
iIventoryType = m_items[i]->GetProto()->InventoryType;
|
||||
|
|
@ -4369,10 +4408,8 @@ Corpse* Player::CreateCorpse()
|
|||
}
|
||||
}
|
||||
|
||||
// we don't SaveToDB for players in battlegrounds so don't do it for corpses either
|
||||
const MapEntry *entry = sMapStore.LookupEntry(corpse->GetMapId());
|
||||
ASSERT(entry);
|
||||
if(entry->map_type != MAP_BATTLEGROUND)
|
||||
// we not need saved corpses for BG/arenas
|
||||
if (!GetMap()->IsBattleGroundOrArena())
|
||||
corpse->SaveToDB();
|
||||
|
||||
// register for player, but not show
|
||||
|
|
@ -5664,10 +5701,10 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const
|
|||
|
||||
void Player::SendInitialActionButtons() const
|
||||
{
|
||||
sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
|
||||
sLog.outDetail( "Initializing Action Buttons for '%u' spec '%u'", GetGUIDLow(), m_activeSpec);
|
||||
|
||||
WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
|
||||
data << uint8(1); // can be 0, 1, 2 (talent spec)
|
||||
data << uint8(1); // talent spec amount (in packet)
|
||||
ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec];
|
||||
for(uint8 button = 0; button < MAX_ACTION_BUTTONS; ++button)
|
||||
{
|
||||
|
|
@ -5679,7 +5716,7 @@ void Player::SendInitialActionButtons() const
|
|||
}
|
||||
|
||||
GetSession()->SendPacket( &data );
|
||||
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
|
||||
sLog.outDetail( "Action Buttons for '%u' spec '%u' Initialized", GetGUIDLow(), m_activeSpec );
|
||||
}
|
||||
|
||||
bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type, Player* player, bool msg)
|
||||
|
|
@ -15114,6 +15151,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
|||
_LoadQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS));
|
||||
_LoadDailyQuestStatus(holder->GetResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS));
|
||||
|
||||
_LoadTalents(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTALENTS));
|
||||
|
||||
// after spell and quest load
|
||||
InitTalentForLevel();
|
||||
learnDefaultSpells();
|
||||
|
|
@ -15906,7 +15945,17 @@ void Player::_LoadSpells(QueryResult *result)
|
|||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
addSpell(fields[0].GetUInt32(), fields[1].GetBool(), false, false, fields[2].GetBool());
|
||||
uint32 spell_id = fields[0].GetUInt32();
|
||||
|
||||
// skip talents & drop unneeded data
|
||||
if(GetTalentSpellPos(spell_id))
|
||||
{
|
||||
sLog.outError("Player::_LoadSpells: Player (GUID: %u) has talent spell in character_spell, removing it.", GetGUIDLow(), spell_id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_spell WHERE spell = '%u'", spell_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
addSpell(spell_id, fields[1].GetBool(), false, false, fields[2].GetBool());
|
||||
}
|
||||
while( result->NextRow() );
|
||||
|
||||
|
|
@ -15914,6 +15963,82 @@ void Player::_LoadSpells(QueryResult *result)
|
|||
}
|
||||
}
|
||||
|
||||
void Player::_LoadTalents(QueryResult *result)
|
||||
{
|
||||
//QueryResult *result = CharacterDatabase.PQuery("SELECT talent_id, current_rank, spec FROM character_talent WHERE guid = '%u'",GetGUIDLow());
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint32 talent_id = fields[0].GetUInt32();
|
||||
TalentEntry const *talentInfo = sTalentStore.LookupEntry( talent_id );
|
||||
|
||||
if (!talentInfo)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent_id: %u , this talent will be deleted from character_talent",GetGUIDLow(), talent_id );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE talent_id = '%u'", talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
TalentTabEntry const *talentTabInfo = sTalentTabStore.LookupEntry( talentInfo->TalentTab );
|
||||
|
||||
if (!talentTabInfo)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talentTabInfo: %u for talentID: %u , this talent will be deleted from character_talent",GetGUIDLow(), talentInfo->TalentTab, talentInfo->TalentID );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE talent_id = '%u'", talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
// prevent load talent for different class (cheating)
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has talent with ClassMask: %u , but Player's ClassMask is: %u , talentID: %u , this talent will be deleted from character_talent",GetGUIDLow(), talentTabInfo->ClassMask, getClassMask() ,talentInfo->TalentID );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' AND talent_id = '%u'", GetGUIDLow(), talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 currentRank = fields[1].GetUInt32();
|
||||
|
||||
if (currentRank > MAX_TALENT_RANK || talentInfo->RankID[currentRank] == 0)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent rank: %u , talentID: %u , this talent will be deleted from character_talent",GetGUIDLow(), currentRank, talentInfo->TalentID );
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' AND talent_id = '%u'", GetGUIDLow(), talent_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32 spec = fields[2].GetUInt32();
|
||||
|
||||
if (spec > MAX_TALENT_SPEC_COUNT)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent spec: %u, spec will be deleted from character_talent", GetGUIDLow(), spec);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE spec = '%u' ", spec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (spec >= m_specsCount)
|
||||
{
|
||||
sLog.outError("Player::_LoadTalents:Player (GUID: %u) has invalid talent spec: %u , this spec will be deleted from character_talent.", GetGUIDLow(), spec);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' AND spec = '%u' ", GetGUIDLow(), spec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_activeSpec == spec)
|
||||
addSpell(talentInfo->RankID[currentRank], true,false,false,false);
|
||||
else
|
||||
{
|
||||
PlayerTalent talent;
|
||||
talent.currentRank = currentRank;
|
||||
talent.m_talentEntry = talentInfo;
|
||||
talent.state = PLAYERSPELL_UNCHANGED;
|
||||
m_talents[spec][talentInfo->TalentID] = talent;
|
||||
}
|
||||
}
|
||||
while (result->NextRow());
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
void Player::_LoadGroup(QueryResult *result)
|
||||
{
|
||||
//QueryResult *result = CharacterDatabase.PQuery("SELECT groupId FROM group_member WHERE memberGuid='%u'", GetGUIDLow());
|
||||
|
|
@ -16405,6 +16530,7 @@ void Player::SaveToDB()
|
|||
_SaveEquipmentSets();
|
||||
GetSession()->SaveTutorialsData(); // changed only while character in game
|
||||
_SaveGlyphs();
|
||||
_SaveTalents();
|
||||
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
|
|
@ -16750,12 +16876,17 @@ void Player::_SaveSpells()
|
|||
{
|
||||
for (PlayerSpellMap::iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end();)
|
||||
{
|
||||
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);
|
||||
uint32 talentCosts = GetTalentSpellCost(itr->first);
|
||||
|
||||
// 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);
|
||||
if (!talentCosts)
|
||||
{
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED)
|
||||
m_spells.erase(itr++);
|
||||
|
|
@ -16768,6 +16899,30 @@ void Player::_SaveSpells()
|
|||
}
|
||||
}
|
||||
|
||||
void Player::_SaveTalents()
|
||||
{
|
||||
for (int32 i = 0; i < MAX_TALENT_SPEC_COUNT; ++i)
|
||||
{
|
||||
for (PlayerTalentMap::iterator itr = m_talents[i].begin(); itr != m_talents[i].end();)
|
||||
{
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE guid = '%u' and talent_id = '%u' and spec = '%u'", GetGUIDLow(),itr->first, i);
|
||||
|
||||
// add only changed/new talents
|
||||
if (itr->second.state == PLAYERSPELL_NEW || itr->second.state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("INSERT INTO character_talent (guid, talent_id, current_rank , spec) VALUES ('%u', '%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second.currentRank, i);
|
||||
|
||||
if (itr->second.state == PLAYERSPELL_REMOVED)
|
||||
m_talents[i].erase(itr++);
|
||||
else
|
||||
{
|
||||
itr->second.state = PLAYERSPELL_UNCHANGED;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::outDebugValues() const
|
||||
{
|
||||
if(!sLog.IsOutDebug()) // optimize disabled debug output
|
||||
|
|
@ -20839,14 +20994,9 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
|
||||
// find current max talent rank
|
||||
uint32 curtalent_maxrank = 0;
|
||||
for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasSpell(talentInfo->RankID[k]))
|
||||
{
|
||||
curtalent_maxrank = k + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
PlayerTalentMap::iterator itr = m_talents[m_activeSpec].find(talentId);
|
||||
if (itr != m_talents[m_activeSpec].end() && itr->second.state != PLAYERSPELL_REMOVED)
|
||||
curtalent_maxrank = itr->second.currentRank + 1;
|
||||
|
||||
// we already have same or higher talent rank learned
|
||||
if(curtalent_maxrank >= (talentRank + 1))
|
||||
|
|
@ -20862,12 +21012,14 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
if(TalentEntry const *depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||
{
|
||||
bool hasEnoughRank = false;
|
||||
for (int i = talentInfo->DependsOnRank; i < MAX_TALENT_RANK; ++i)
|
||||
PlayerTalentMap::iterator dependsOnTalent = m_talents[m_activeSpec].find(depTalentInfo->TalentID);
|
||||
if (dependsOnTalent != m_talents[m_activeSpec].end() && dependsOnTalent->second.state != PLAYERSPELL_REMOVED)
|
||||
{
|
||||
if (depTalentInfo->RankID[i] != 0)
|
||||
if (HasSpell(depTalentInfo->RankID[i]))
|
||||
hasEnoughRank = true;
|
||||
PlayerTalent depTalent = (*dependsOnTalent).second;
|
||||
if (depTalent.currentRank >= talentInfo->DependsOnRank)
|
||||
hasEnoughRank = true;
|
||||
}
|
||||
|
||||
if (!hasEnoughRank)
|
||||
return;
|
||||
}
|
||||
|
|
@ -20879,28 +21031,9 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
uint32 tTab = talentInfo->TalentTab;
|
||||
if (talentInfo->Row > 0)
|
||||
{
|
||||
unsigned int numRows = sTalentStore.GetNumRows();
|
||||
for (unsigned int i = 0; i < numRows; ++i) // Loop through all talents.
|
||||
{
|
||||
// Someday, someone needs to revamp
|
||||
const TalentEntry *tmpTalent = sTalentStore.LookupEntry(i);
|
||||
if (tmpTalent) // the way talents are tracked
|
||||
{
|
||||
if (tmpTalent->TalentTab == tTab)
|
||||
{
|
||||
for (int j = 0; j < MAX_TALENT_RANK; ++j)
|
||||
{
|
||||
if (tmpTalent->RankID[j] != 0)
|
||||
{
|
||||
if (HasSpell(tmpTalent->RankID[j]))
|
||||
{
|
||||
spentPoints += j + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (PlayerTalentMap::const_iterator iter = m_talents[m_activeSpec].begin(); iter != m_talents[m_activeSpec].end(); ++iter)
|
||||
if (iter->second.state != PLAYERSPELL_REMOVED && iter->second.m_talentEntry->TalentTab == tTab)
|
||||
spentPoints += iter->second.currentRank + 1;
|
||||
}
|
||||
|
||||
// not have required min points spent in talent tree
|
||||
|
|
@ -20922,9 +21055,6 @@ void Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
|||
// learn! (other talent ranks will unlearned at learning)
|
||||
learnSpell(spellid, false);
|
||||
sLog.outDetail("TalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
||||
|
||||
// update free talent points
|
||||
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
}
|
||||
|
||||
void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank)
|
||||
|
|
@ -21057,9 +21187,6 @@ void Player::LearnPetTalent(uint64 petGuid, uint32 talentId, uint32 talentRank)
|
|||
// learn! (other talent ranks will unlearned at learning)
|
||||
pet->learnSpell(spellid);
|
||||
sLog.outDetail("PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
||||
|
||||
// update free talent points
|
||||
pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
}
|
||||
|
||||
void Player::UpdateKnownCurrencies(uint32 itemId, bool apply)
|
||||
|
|
@ -21147,34 +21274,19 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket *data)
|
|||
for(uint32 i = 0; i < 3; ++i)
|
||||
{
|
||||
uint32 talentTabId = talentTabIds[i];
|
||||
|
||||
for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
for(PlayerTalentMap::iterator iter = m_talents[specIdx].begin(); iter != m_talents[specIdx].end(); ++iter)
|
||||
{
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
if(!talentInfo)
|
||||
PlayerTalent talent = (*iter).second;
|
||||
|
||||
if (talent.state == PLAYERSPELL_REMOVED)
|
||||
continue;
|
||||
|
||||
// skip another tab talents
|
||||
if(talentInfo->TalentTab != talentTabId)
|
||||
if(talent.m_talentEntry->TalentTab != talentTabId)
|
||||
continue;
|
||||
|
||||
// find max talent rank
|
||||
int32 curtalent_maxrank = -1;
|
||||
for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasSpell(talentInfo->RankID[k]))
|
||||
{
|
||||
curtalent_maxrank = k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not learned talent
|
||||
if(curtalent_maxrank < 0)
|
||||
continue;
|
||||
|
||||
*data << uint32(talentInfo->TalentID); // Talent.dbc
|
||||
*data << uint8(curtalent_maxrank); // talentMaxRank (0-4)
|
||||
*data << uint32(talent.m_talentEntry->TalentID); // Talent.dbc
|
||||
*data << uint8(talent.currentRank); // talentMaxRank (0-4)
|
||||
|
||||
++talentIdCount;
|
||||
}
|
||||
|
|
@ -21449,13 +21561,75 @@ void Player::ActivateSpec(uint8 specNum)
|
|||
if(specNum >= GetSpecsCount())
|
||||
return;
|
||||
|
||||
// unlearn GetActiveSpec() talents (not learned in specNum);
|
||||
// learn specNum talents
|
||||
UnsummonPetTemporaryIfAny();
|
||||
|
||||
ApplyGlyphs(false);
|
||||
|
||||
// copy of new talent spec (we will use it as model for converting current tlanet state to new)
|
||||
PlayerTalentMap tempSpec = m_talents[specNum];
|
||||
|
||||
// copy old spec talents to new one, must be before spec switch to have previous spec num(as m_activeSpec)
|
||||
m_talents[specNum] = m_talents[m_activeSpec];
|
||||
|
||||
SetActiveSpec(specNum);
|
||||
|
||||
// remove all talent spells that don't exist in next spec but exist in old
|
||||
for (PlayerTalentMap::iterator specIter = m_talents[m_activeSpec].begin(); specIter != m_talents[m_activeSpec].end();)
|
||||
{
|
||||
PlayerTalent& talent = (*specIter).second;
|
||||
|
||||
if (talent.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
++specIter;
|
||||
continue;
|
||||
}
|
||||
|
||||
PlayerTalentMap::iterator iterTempSpec = tempSpec.find(specIter->first);
|
||||
|
||||
// remove any talent rank if talent not listed in temp spec
|
||||
if (iterTempSpec == tempSpec.end() || iterTempSpec->second.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
for(int r = 0; r < MAX_TALENT_RANK; ++r)
|
||||
if (talent.m_talentEntry->RankID[r])
|
||||
removeSpell(talent.m_talentEntry->RankID[r],!IsPassiveSpell(talent.m_talentEntry->RankID[r]),false);
|
||||
|
||||
specIter = m_talents[m_activeSpec].begin();
|
||||
}
|
||||
else
|
||||
++specIter;
|
||||
}
|
||||
|
||||
// now new spec data have only talents (maybe different rank) as in temp spec data, sync ranks then.
|
||||
for (PlayerTalentMap::const_iterator tempIter = tempSpec.begin(); tempIter != tempSpec.end(); ++tempIter)
|
||||
{
|
||||
PlayerTalent const& talent = (*tempIter).second;
|
||||
|
||||
// removed state talent already unlearned in prev. loop
|
||||
// but we need restore it if it deleted for finish removed-marked data in DB
|
||||
if (talent.state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
m_talents[m_activeSpec][tempIter->first] = talent;
|
||||
continue;
|
||||
}
|
||||
|
||||
// learn talent spells if they not in new spec (old spec copy)
|
||||
// and if they have different rank
|
||||
PlayerTalentMap::iterator specIter = m_talents[m_activeSpec].find(tempIter->first);
|
||||
if (specIter != m_talents[m_activeSpec].end() && specIter->second.state != PLAYERSPELL_REMOVED)
|
||||
{
|
||||
if ((*specIter).second.currentRank != talent.currentRank)
|
||||
learnSpell(talent.m_talentEntry->RankID[talent.currentRank], false);
|
||||
}
|
||||
else
|
||||
learnSpell(talent.m_talentEntry->RankID[talent.currentRank], false);
|
||||
|
||||
// sync states - original state is changed in addSpell that learnSpell calls
|
||||
specIter = m_talents[m_activeSpec].find(tempIter->first);
|
||||
(*specIter).second.state = talent.state;
|
||||
}
|
||||
|
||||
InitTalentForLevel();
|
||||
|
||||
// recheck action buttons (not checked at loading/spec copy)
|
||||
ActionButtonList const& currentActionButtonList = m_actionButtons[m_activeSpec];
|
||||
for(ActionButtonList::const_iterator itr = currentActionButtonList.begin(); itr != currentActionButtonList.end(); ++itr)
|
||||
|
|
@ -21464,11 +21638,17 @@ void Player::ActivateSpec(uint8 specNum)
|
|||
if (!IsActionButtonDataValid(itr->first,itr->second.GetAction(),itr->second.GetType(), this, false))
|
||||
removeActionButton(m_activeSpec,itr->first);
|
||||
|
||||
ResummonPetTemporaryUnSummonedIfAny();
|
||||
|
||||
ApplyGlyphs(true);
|
||||
|
||||
SendInitialActionButtons();
|
||||
|
||||
InitTalentForLevel();
|
||||
Powers pw = getPowerType();
|
||||
if(pw != POWER_MANA)
|
||||
SetPower(POWER_MANA, 0);
|
||||
|
||||
SetPower(pw, 0);
|
||||
}
|
||||
|
||||
void Player::UpdateSpecCount(uint8 count)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue