*Add Dual Spec support, original by EnderGT, thanks to Thyros and XTElite1 for helping me test :)
--HG-- branch : trunk
This commit is contained in:
+348
-25
@@ -424,9 +424,17 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
|
||||
m_lastPotionId = 0;
|
||||
|
||||
m_activeSpec = 0;
|
||||
m_specsCount = 1;
|
||||
m_specsCount = 0;
|
||||
|
||||
for (uint8 i = 0; i < BASEMOD_END; ++i)
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
{
|
||||
for (int g = 0; g < MAX_GLYPH_SLOT_INDEX; ++g)
|
||||
m_Glyphs[i][g] = 0;
|
||||
|
||||
m_talents[i] = new PlayerTalentMap();
|
||||
}
|
||||
|
||||
for (int i = 0; i < BASEMOD_END; ++i)
|
||||
{
|
||||
m_auraBaseMod[i][FLAT_MOD] = 0.0f;
|
||||
m_auraBaseMod[i][PCT_MOD] = 1.0f;
|
||||
@@ -492,6 +500,13 @@ Player::~Player ()
|
||||
for (PlayerSpellMap::const_iterator itr = m_spells.begin(); itr != m_spells.end(); ++itr)
|
||||
delete itr->second;
|
||||
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
{
|
||||
for (PlayerTalentMap::const_iterator itr = m_talents[i]->begin(); itr != m_talents[i]->end(); ++itr)
|
||||
delete itr->second;
|
||||
delete m_talents[i];
|
||||
}
|
||||
|
||||
//all mailed items should be deleted, also all mail should be deallocated
|
||||
for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();++itr)
|
||||
delete *itr;
|
||||
@@ -2532,6 +2547,12 @@ void Player::InitTalentForLevel()
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level < 40 || m_specsCount == 0)
|
||||
{
|
||||
m_specsCount = 1;
|
||||
m_activeSpec = 0;
|
||||
}
|
||||
|
||||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
// if used more that have then reset
|
||||
@@ -2847,6 +2868,73 @@ void Player::AddNewMailDeliverTime(time_t deliver_time)
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::AddTalent(uint32 spell_id, uint8 spec, bool learning)
|
||||
{
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
if (!spellInfo)
|
||||
{
|
||||
// do character spell book cleanup (all characters)
|
||||
if(!IsInWorld() && !learning) // spell load case
|
||||
{
|
||||
sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.",spell_id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE spell = '%u'",spell_id);
|
||||
}
|
||||
else
|
||||
sLog.outError("Player::addSpell: Non-existed in SpellStore spell #%u request.",spell_id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!SpellMgr::IsSpellValid(spellInfo,this,false))
|
||||
{
|
||||
// do character spell book cleanup (all characters)
|
||||
if(!IsInWorld() && !learning) // spell load case
|
||||
{
|
||||
sLog.outError("Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.",spell_id);
|
||||
CharacterDatabase.PExecute("DELETE FROM character_talent WHERE spell = '%u'",spell_id);
|
||||
}
|
||||
else
|
||||
sLog.outError("Player::addTalent: Broken spell #%u learning not allowed.",spell_id);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PlayerTalentMap::iterator itr = m_talents[spec]->find(spell_id);
|
||||
if (itr != m_talents[spec]->end())
|
||||
{
|
||||
itr->second->state = PLAYERSPELL_UNCHANGED;
|
||||
}
|
||||
else if(TalentSpellPos const* talentPos = GetTalentSpellPos(spell_id))
|
||||
{
|
||||
if(TalentEntry const *talentInfo = sTalentStore.LookupEntry( talentPos->talent_id ))
|
||||
{
|
||||
for(int i=0; i < MAX_TALENT_RANK; ++i)
|
||||
{
|
||||
// skip learning spell and no rank spell case
|
||||
uint32 rankSpellId = talentInfo->RankID[i];
|
||||
if(!rankSpellId || rankSpellId==spell_id)
|
||||
continue;
|
||||
|
||||
PlayerTalentMap::iterator itr = m_talents[spec]->find(rankSpellId);
|
||||
if (itr != m_talents[spec]->end())
|
||||
{
|
||||
itr->second->state = PLAYERSPELL_REMOVED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlayerSpellState state = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
|
||||
PlayerTalent *newtalent = new PlayerTalent();
|
||||
|
||||
newtalent->state = state;
|
||||
newtalent->spec = spec;
|
||||
|
||||
(*m_talents[spec])[spell_id] = newtalent;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Player::addSpell(uint32 spell_id, bool active, bool learning, bool dependent, bool disabled)
|
||||
{
|
||||
SpellEntry const *spellInfo = sSpellStore.LookupEntry(spell_id);
|
||||
@@ -3681,7 +3769,7 @@ bool Player::resetTalents(bool no_cost)
|
||||
if( (getClassMask() & talentTabInfo->ClassMask) == 0 )
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < MAX_TALENT_RANK; j++)
|
||||
/* for (int j = 0; j < MAX_TALENT_RANK; j++)
|
||||
{
|
||||
for(PlayerSpellMap::iterator itr = GetSpellMap().begin(); itr != GetSpellMap().end();)
|
||||
{
|
||||
@@ -3710,6 +3798,12 @@ bool Player::resetTalents(bool no_cost)
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
} */
|
||||
PlayerTalentMap::iterator itr2 = m_talents[m_activeSpec]->begin();
|
||||
for (; itr2 != m_talents[m_activeSpec]->end(); ++itr2)
|
||||
{
|
||||
removeSpell(itr2->first, !IsPassiveSpell(itr2->first),false);
|
||||
itr2->second->state = PLAYERSPELL_REMOVED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3945,6 +4039,12 @@ bool Player::HasSpell(uint32 spell) const
|
||||
!itr->second->disabled);
|
||||
}
|
||||
|
||||
bool Player::HasTalent(uint32 spell, uint8 spec) const
|
||||
{
|
||||
PlayerTalentMap::const_iterator itr = m_talents[spec]->find(spell);
|
||||
return (itr != m_talents[spec]->end() && itr->second->state != PLAYERSPELL_REMOVED);
|
||||
}
|
||||
|
||||
bool Player::HasActiveSpell(uint32 spell) const
|
||||
{
|
||||
PlayerSpellMap::const_iterator itr = m_spells.find(spell);
|
||||
@@ -5671,12 +5771,12 @@ int16 Player::GetSkillTempBonusValue(uint32 skill) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Player::SendInitialActionButtons() const
|
||||
void Player::SendActionButtons(uint32 spec) const
|
||||
{
|
||||
sLog.outDetail( "Initializing Action Buttons for '%u'", GetGUIDLow() );
|
||||
sLog.outDetail( "Sending Action Buttons for '%u' spec '%u'", GetGUIDLow(), spec );
|
||||
|
||||
WorldPacket data(SMSG_ACTION_BUTTONS, 1+(MAX_ACTION_BUTTONS*4));
|
||||
data << uint8(0); // can be 0, 1, 2 (talent spec)
|
||||
data << uint8(spec); // can be 0, 1, 2 (talent spec)
|
||||
for(int button = 0; button < MAX_ACTION_BUTTONS; ++button)
|
||||
{
|
||||
ActionButtonList::const_iterator itr = m_actionButtons.find(button);
|
||||
@@ -5687,7 +5787,7 @@ void Player::SendInitialActionButtons() const
|
||||
}
|
||||
|
||||
GetSession()->SendPacket( &data );
|
||||
sLog.outDetail( "Action Buttons for '%u' Initialized", GetGUIDLow() );
|
||||
sLog.outDetail( "Action Buttons for '%u' spec '%u' Sent", GetGUIDLow(), spec );
|
||||
}
|
||||
|
||||
ActionButton* Player::addActionButton(uint8 button, uint32 action, uint8 type)
|
||||
@@ -14521,8 +14621,8 @@ float Player::GetFloatValueFromDB(uint16 index, uint64 guid)
|
||||
|
||||
bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
{
|
||||
//// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
||||
//QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points FROM characters WHERE guid = '%u'", guid);
|
||||
//// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
||||
//QueryResult *result = CharacterDatabase.PQuery("SELECT guid, account, data, name, race, class, gender, level, xp, money, playerBytes, playerBytes2, playerFlags, position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, dungeon_difficulty, arena_pending_points, instance_id, speccount, activespec FROM characters WHERE guid = '%u'", guid);
|
||||
QueryResult *result = holder->GetResult(PLAYER_LOGIN_QUERY_LOADFROM);
|
||||
|
||||
if(!result)
|
||||
@@ -14544,6 +14644,13 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
return false;
|
||||
}
|
||||
|
||||
m_specsCount = fields[42].GetUInt32();
|
||||
m_activeSpec = fields[43].GetUInt32();
|
||||
|
||||
// sanity check
|
||||
if (m_specsCount < 2) // Maybe better to check MAX_TALENT_SPECS?
|
||||
m_activeSpec = 0;
|
||||
|
||||
Object::_Create( guid, 0, HIGHGUID_PLAYER );
|
||||
|
||||
m_name = fields[3].GetCppString();
|
||||
@@ -14964,8 +15071,10 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
|
||||
//mails are loaded only when needed ;-) - when player in game click on mailbox.
|
||||
//_LoadMail();
|
||||
|
||||
_LoadTalents(holder->GetResult(PLAYER_LOGIN_QUERY_LOADTALENTS));
|
||||
_LoadSpells(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSPELLS));
|
||||
|
||||
_LoadGlyphs(holder->GetResult(PLAYER_LOGIN_QUERY_LOADGLYPHS));
|
||||
_LoadAuras(holder->GetResult(PLAYER_LOGIN_QUERY_LOADAURAS), time_diff);
|
||||
_LoadGlyphAuras();
|
||||
// add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura)
|
||||
@@ -16124,7 +16233,7 @@ void Player::SaveToDB()
|
||||
"taximask, online, cinematic, "
|
||||
"totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, resettalents_time, "
|
||||
"trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, "
|
||||
"death_expire_time, taxi_path, arena_pending_points, latency) VALUES ("
|
||||
"death_expire_time, taxi_path, arena_pending_points, latency, speccount, activespec) VALUES ("
|
||||
<< GetGUIDLow() << ", "
|
||||
<< GetSession()->GetAccountId() << ", '"
|
||||
<< sql_name << "', "
|
||||
@@ -16207,6 +16316,10 @@ void Player::SaveToDB()
|
||||
ss << m_taxi.SaveTaxiDestinationsToString() << "', ";
|
||||
ss << "'0', "; // arena_pending_points
|
||||
ss << GetSession()->GetLatency();
|
||||
ss << ", ";
|
||||
ss << uint32(m_specsCount);
|
||||
ss << ", ";
|
||||
ss << uint32(m_activeSpec);
|
||||
ss << ")";
|
||||
|
||||
CharacterDatabase.Execute( ss.str().c_str() );
|
||||
@@ -16218,6 +16331,7 @@ void Player::SaveToDB()
|
||||
_SaveInventory();
|
||||
_SaveQuestStatus();
|
||||
_SaveDailyQuestStatus();
|
||||
_SaveTalents();
|
||||
_SaveSpells();
|
||||
_SaveSpellCooldowns();
|
||||
_SaveActions();
|
||||
@@ -16226,6 +16340,7 @@ void Player::SaveToDB()
|
||||
m_reputationMgr.SaveToDB();
|
||||
_SaveEquipmentSets();
|
||||
GetSession()->SaveTutorialsData(); // changed only while character in game
|
||||
_SaveGlyphs();
|
||||
|
||||
CharacterDatabase.CommitTransaction();
|
||||
|
||||
@@ -16253,14 +16368,14 @@ void Player::_SaveActions()
|
||||
switch (itr->second.uState)
|
||||
{
|
||||
case ACTIONBUTTON_NEW:
|
||||
CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type) VALUES ('%u', '%u', '%u', '%u')",
|
||||
GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType() );
|
||||
CharacterDatabase.PExecute("INSERT INTO character_action (guid,spec,button,action,type) VALUES ('%u', '%u', '%u', '%u', '%u')",
|
||||
GetGUIDLow(), (uint32)m_activeSpec, (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType() );
|
||||
itr->second.uState = ACTIONBUTTON_UNCHANGED;
|
||||
++itr;
|
||||
break;
|
||||
case ACTIONBUTTON_CHANGED:
|
||||
CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid= '%u' AND button= '%u' ",
|
||||
(uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first );
|
||||
CharacterDatabase.PExecute("UPDATE character_action SET action = '%u', type = '%u' WHERE guid = '%u' AND button = '%u' AND spec = '%u'",
|
||||
(uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), GetGUIDLow(), (uint32)itr->first, (uint32)m_activeSpec);
|
||||
itr->second.uState = ACTIONBUTTON_UNCHANGED;
|
||||
++itr;
|
||||
break;
|
||||
@@ -20944,7 +21059,9 @@ 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);
|
||||
AddTalent(spellid, m_activeSpec, true);
|
||||
|
||||
sLog.outDetail("TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, m_activeSpec);
|
||||
|
||||
// update free talent points
|
||||
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
@@ -21188,7 +21305,7 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket *data)
|
||||
int32 curtalent_maxrank = -1;
|
||||
for(int32 k = MAX_TALENT_RANK-1; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasSpell(talentInfo->RankID[k]))
|
||||
if(talentInfo->RankID[k] && HasTalent(talentInfo->RankID[k], specIdx))
|
||||
{
|
||||
curtalent_maxrank = k;
|
||||
break;
|
||||
@@ -21211,7 +21328,7 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket *data)
|
||||
*data << uint8(MAX_GLYPH_SLOT_INDEX); // glyphs count
|
||||
|
||||
for(uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
*data << uint16(GetGlyph(i)); // GlyphProperties.dbc
|
||||
*data << uint16(m_Glyphs[specIdx][i]); // GlyphProperties.dbc
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21466,14 +21583,6 @@ void Player::DeleteEquipmentSet(uint64 setGuid)
|
||||
}
|
||||
}
|
||||
|
||||
void Player::ActivateSpec(uint32 specNum)
|
||||
{
|
||||
if(GetActiveSpec() == specNum)
|
||||
return;
|
||||
|
||||
resetTalents(true);
|
||||
}
|
||||
|
||||
void Player::RemoveAtLoginFlag( AtLoginFlags f, bool in_db_also /*= false*/ )
|
||||
{
|
||||
m_atLoginFlags &= ~f;
|
||||
@@ -21507,3 +21616,217 @@ void Player::SetMap(Map * map)
|
||||
Unit::SetMap(map);
|
||||
m_mapRef.link(map, this);
|
||||
}
|
||||
|
||||
void Player::_LoadGlyphs(QueryResult *result)
|
||||
{
|
||||
// SetPQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6 from character_glyphs WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
uint8 spec = fields[0].GetUInt8();
|
||||
if (spec >= m_specsCount)
|
||||
continue;
|
||||
|
||||
m_Glyphs[spec][0] = fields[1].GetUInt32();
|
||||
m_Glyphs[spec][1] = fields[2].GetUInt32();
|
||||
m_Glyphs[spec][2] = fields[3].GetUInt32();
|
||||
m_Glyphs[spec][3] = fields[4].GetUInt32();
|
||||
m_Glyphs[spec][4] = fields[5].GetUInt32();
|
||||
m_Glyphs[spec][5] = fields[6].GetUInt32();
|
||||
|
||||
} while (result->NextRow());
|
||||
|
||||
delete result;
|
||||
}
|
||||
|
||||
void Player::_SaveGlyphs()
|
||||
{
|
||||
CharacterDatabase.PExecute("DELETE FROM character_glyphs WHERE guid='%u'",GetGUIDLow());
|
||||
for (uint8 spec = 0; spec < m_specsCount; ++spec)
|
||||
{
|
||||
CharacterDatabase.PExecute("INSERT INTO character_glyphs VALUES('%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')",
|
||||
GetGUIDLow(), spec, m_Glyphs[spec][0], m_Glyphs[spec][1], m_Glyphs[spec][2], m_Glyphs[spec][3], m_Glyphs[spec][4], m_Glyphs[spec][5]);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::_LoadTalents(QueryResult *result)
|
||||
{
|
||||
// SetPQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, "SELECT spell, spec FROM character_talent WHERE guid = '%u'", GUID_LOPART(m_guid));
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
{
|
||||
Field *fields = result->Fetch();
|
||||
|
||||
AddTalent(fields[0].GetUInt32(), fields[1].GetUInt32(), false);
|
||||
}
|
||||
while( result->NextRow() );
|
||||
|
||||
delete result;
|
||||
}
|
||||
}
|
||||
|
||||
void Player::_SaveTalents()
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
{
|
||||
for (PlayerTalentMap::iterator itr = m_talents[i]->begin(), next = 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 spell = '%u' and spec = '%u'", GetGUIDLow(), itr->first, itr->second->spec);
|
||||
|
||||
if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED)
|
||||
CharacterDatabase.PExecute("INSERT INTO character_talent (guid,spell,spec) VALUES ('%u', '%u', '%u')", GetGUIDLow(), itr->first, itr->second->spec);
|
||||
|
||||
if (itr->second->state == PLAYERSPELL_REMOVED)
|
||||
{
|
||||
delete itr->second;
|
||||
m_talents[i]->erase(itr++);
|
||||
}
|
||||
else
|
||||
{
|
||||
itr->second->state = PLAYERSPELL_UNCHANGED;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateSpecCount(uint8 count)
|
||||
{
|
||||
if(GetSpecsCount() == count)
|
||||
return;
|
||||
|
||||
if(count == 1)
|
||||
{
|
||||
_SaveActions(); // make sure the button list is cleaned up
|
||||
// active spec becomes only spec?
|
||||
CharacterDatabase.PExecute("DELETE FROM character_action WHERE spec<>'%u' AND guid='%u'",m_activeSpec, GetGUIDLow());
|
||||
CharacterDatabase.PExecute("UPDATE character_action SET spec='%u' WHERE guid='%u'", m_activeSpec, GetGUIDLow());
|
||||
}
|
||||
else if (count == 2)
|
||||
{
|
||||
_SaveActions(); // make sure the button list is cleaned up
|
||||
for(ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end(); ++itr)
|
||||
{
|
||||
CharacterDatabase.PExecute("INSERT INTO character_action (guid,button,action,type,spec) VALUES ('%u', '%u', '%u', '%u', '%u')",
|
||||
GetGUIDLow(), (uint32)itr->first, (uint32)itr->second.GetAction(), (uint32)itr->second.GetType(), count );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SetSpecsCount(count);
|
||||
|
||||
SendTalentsInfoData(false);
|
||||
}
|
||||
|
||||
void Player::ActivateSpec(uint8 spec)
|
||||
{
|
||||
if(GetActiveSpec() == spec)
|
||||
return;
|
||||
|
||||
if(GetSpecsCount() != MAX_TALENT_SPECS)
|
||||
return;
|
||||
|
||||
uint32 const* talentTabIds = GetTalentTabPages(getClass());
|
||||
|
||||
for(uint8 i = 0; i < 3; ++i)
|
||||
{
|
||||
uint32 talentTabId = talentTabIds[i];
|
||||
|
||||
for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
{
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
if(!talentInfo)
|
||||
continue;
|
||||
|
||||
// skip another tab talents
|
||||
if(talentInfo->TalentTab != talentTabId)
|
||||
continue;
|
||||
|
||||
// find max talent rank
|
||||
int32 curtalent_maxrank = -1;
|
||||
for(int32 k = 4; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasTalent(talentInfo->RankID[k], m_activeSpec))
|
||||
{
|
||||
removeSpell(talentInfo->RankID[k],true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set glyphs
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
{
|
||||
// remove secondary glyph
|
||||
if(uint32 oldglyph = m_Glyphs[m_activeSpec][slot])
|
||||
{
|
||||
if(GlyphPropertiesEntry const *old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
|
||||
{
|
||||
RemoveAurasDueToSpell(old_gp->SpellId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetActiveSpec(spec);
|
||||
|
||||
for(uint8 i = 0; i < 3; ++i)
|
||||
{
|
||||
uint32 talentTabId = talentTabIds[i];
|
||||
|
||||
for(uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
{
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
if(!talentInfo)
|
||||
continue;
|
||||
|
||||
// skip another tab talents
|
||||
if(talentInfo->TalentTab != talentTabId)
|
||||
continue;
|
||||
|
||||
// find max talent rank
|
||||
int32 curtalent_maxrank = -1;
|
||||
for(int32 k = 4; k > -1; --k)
|
||||
{
|
||||
if(talentInfo->RankID[k] && HasTalent(talentInfo->RankID[k], m_activeSpec))
|
||||
{
|
||||
learnSpell(talentInfo->RankID[k], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set glyphs
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
{
|
||||
uint32 glyph = m_Glyphs[m_activeSpec][slot];
|
||||
// apply primary glyph
|
||||
if (glyph)
|
||||
{
|
||||
if (GlyphPropertiesEntry const *gp = sGlyphPropertiesStore.LookupEntry(glyph))
|
||||
{
|
||||
CastSpell(this, gp->SpellId, true);
|
||||
}
|
||||
}
|
||||
SetGlyph(slot, glyph);
|
||||
}
|
||||
|
||||
InitTalentForLevel();
|
||||
|
||||
QueryResult *result = CharacterDatabase.PQuery("SELECT button,action,type FROM character_action WHERE guid = '%u' AND spec = '%u' ORDER BY button", GetGUIDLow(), m_activeSpec);
|
||||
if (result)
|
||||
{
|
||||
_LoadActions(result);
|
||||
}
|
||||
UnsummonPetTemporaryIfAny();
|
||||
SendActionButtons(m_activeSpec);
|
||||
SetPower(getPowerType(), 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user