@@ -763,7 +763,7 @@ DROP TABLE IF EXISTS `character_glyphs`;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `character_glyphs` (
|
||||
`guid` bigint(20) unsigned NOT NULL,
|
||||
`spec` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`glyph1` smallint(5) unsigned DEFAULT '0',
|
||||
`glyph2` smallint(5) unsigned DEFAULT '0',
|
||||
`glyph3` smallint(5) unsigned DEFAULT '0',
|
||||
@@ -773,7 +773,7 @@ CREATE TABLE `character_glyphs` (
|
||||
`glyph7` smallint(5) unsigned DEFAULT '0',
|
||||
`glyph8` smallint(5) unsigned DEFAULT '0',
|
||||
`glyph9` smallint(5) unsigned DEFAULT '0',
|
||||
PRIMARY KEY (`guid`,`spec`)
|
||||
PRIMARY KEY (`guid`,`talentGroup`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
@@ -1276,8 +1276,8 @@ DROP TABLE IF EXISTS `character_talent`;
|
||||
CREATE TABLE `character_talent` (
|
||||
`guid` bigint(20) unsigned NOT NULL,
|
||||
`spell` mediumint(8) unsigned NOT NULL,
|
||||
`spec` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`guid`,`spell`,`spec`)
|
||||
`talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`guid`,`spell`,`talentGroup`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
@@ -1383,8 +1383,8 @@ CREATE TABLE `characters` (
|
||||
`power4` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`power5` int(10) unsigned NOT NULL DEFAULT '0',
|
||||
`latency` mediumint(8) unsigned NOT NULL DEFAULT '0',
|
||||
`speccount` tinyint(3) unsigned NOT NULL DEFAULT '1',
|
||||
`activespec` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`talentGroupsCount` tinyint(3) unsigned NOT NULL DEFAULT '1',
|
||||
`activeTalentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
||||
`exploredZones` longtext,
|
||||
`equipmentCache` longtext,
|
||||
`knownTitles` longtext,
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ALTER TABLE `character_glyphs` CHANGE `spec` `talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `character_talent` CHANGE `spec` `talentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `characters` CHANGE `speccount` `talentGroupsCount` tinyint(3) unsigned NOT NULL DEFAULT '1';
|
||||
ALTER TABLE `characters` CHANGE `activespec` `activeTalentGroup` tinyint(3) unsigned NOT NULL DEFAULT '0';
|
||||
@@ -1070,7 +1070,7 @@ void Battleground::AddPlayer(Player* player)
|
||||
BattlegroundPlayer bp;
|
||||
bp.OfflineRemoveTime = 0;
|
||||
bp.Team = team;
|
||||
bp.ActiveSpec = player->GetTalentSpec(player->GetActiveSpec());
|
||||
bp.ActiveSpec = player->GetActiveTalentSpec();
|
||||
|
||||
// Add to list/maps
|
||||
m_Players[player->GetGUID()] = bp;
|
||||
|
||||
@@ -163,6 +163,8 @@ DBCStorage <MapEntry> sMapStore(MapEntryfmt);
|
||||
DBCStorage <MapDifficultyEntry> sMapDifficultyStore(MapDifficultyEntryfmt); // only for loading
|
||||
MapDifficultyMap sMapDifficultyMap;
|
||||
|
||||
DBCStorage <MinorTalentEntry> sMinorTalentStore(MinorTalentEntryfmt);
|
||||
|
||||
DBCStorage <MovieEntry> sMovieStore(MovieEntryfmt);
|
||||
DBCStorage <MountCapabilityEntry> sMountCapabilityStore(MountCapabilityfmt);
|
||||
DBCStorage <MountTypeEntry> sMountTypeStore(MountTypefmt);
|
||||
@@ -570,7 +572,7 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftStore, dbcPath, "SpellShapeshift.dbc");//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellShapeshiftFormStore, dbcPath, "SpellShapeshiftForm.dbc");//19116
|
||||
//LoadDBC(availableDbcLocales, bad_dbc_files, sStableSlotPricesStore, dbcPath, "StableSlotPrices.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSummonPropertiesStore, dbcPath, "SummonProperties.dbc");//19116
|
||||
|
||||
// Must be done when sSkillLineAbilityStore, sSpellStore, sSpellLevelsStore and sCreatureFamilyStore are all loaded
|
||||
/* TODO: Requires spells attributes from SpellMisc.db2 is loaded after dbc
|
||||
@@ -608,8 +610,6 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
}
|
||||
*/
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//15595
|
||||
|
||||
// Create Spelldifficulty searcher
|
||||
/* TODO: 6.x update to new spell diffs
|
||||
for (uint32 i = 0; i < sSpellDifficultyStore.GetNumRows(); ++i)
|
||||
@@ -640,6 +640,9 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
sSpellMgr->SetSpellDifficultyId(uint32(newEntry.SpellID[x]), spellDiff->ID);
|
||||
}*/
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sTalentStore, dbcPath, "Talent.dbc");//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sMinorTalentStore, dbcPath, "MinorTalent.dbc");//19116
|
||||
|
||||
for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
|
||||
{
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
|
||||
@@ -649,35 +652,6 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
sTalentBySpellIDMap[talentInfo->SpellID] = talentInfo;
|
||||
}
|
||||
|
||||
// create talent spells set
|
||||
/* TODO: 6.x update to new talent system
|
||||
|
||||
// prepare fast data access to bit pos of talent ranks for use at inspecting
|
||||
{
|
||||
// now have all max ranks (and then bit amount used for store talent ranks in inspect)
|
||||
for (uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId)
|
||||
{
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabId);
|
||||
if (!talentTabInfo)
|
||||
continue;
|
||||
|
||||
// prevent memory corruption; otherwise cls will become 12 below
|
||||
if ((talentTabInfo->ClassMask & CLASSMASK_ALL_PLAYABLE) == 0)
|
||||
continue;
|
||||
|
||||
// store class talent tab pages
|
||||
for (uint32 cls = 1; cls < MAX_CLASSES; ++cls)
|
||||
if (talentTabInfo->ClassMask & (1 << (cls - 1)))
|
||||
sTalentTabPages[cls][talentTabInfo->tabpage] = talentTabId;
|
||||
}
|
||||
}
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sTalentTreePrimarySpellsStore, dbcPath, "TalentTreePrimarySpells.dbc");
|
||||
for (uint32 i = 0; i < sTalentTreePrimarySpellsStore.GetNumRows(); ++i)
|
||||
if (TalentTreePrimarySpellsEntry const* talentSpell = sTalentTreePrimarySpellsStore.LookupEntry(i))
|
||||
sTalentTreePrimarySpellsMap[talentSpell->TalentTree].push_back(talentSpell->SpellId);
|
||||
sTalentTreePrimarySpellsStore.Clear();*/
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiNodesStore, dbcPath, "TaxiNodes.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sTaxiPathStore, dbcPath, "TaxiPath.dbc");//15595
|
||||
for (uint32 i = 1; i < sTaxiPathStore.GetNumRows(); ++i)
|
||||
|
||||
@@ -179,6 +179,7 @@ extern DBCStorage <LiquidTypeEntry> sLiquidTypeStore;
|
||||
extern DBCStorage <LockEntry> sLockStore;
|
||||
extern DBCStorage <MailTemplateEntry> sMailTemplateStore;
|
||||
extern DBCStorage <MapEntry> sMapStore;
|
||||
extern DBCStorage <MinorTalentEntry> sMinorTalentStore;
|
||||
extern DBCStorage <MountCapabilityEntry> sMountCapabilityStore;
|
||||
extern DBCStorage <MountTypeEntry> sMountTypeStore;
|
||||
extern DBCStorage <NameGenEntry> sNameGenStore;
|
||||
|
||||
@@ -1608,6 +1608,14 @@ struct MapDifficultyEntry
|
||||
//char* LockID; // 6
|
||||
};
|
||||
|
||||
struct MinorTalentEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 SpecID; // 1
|
||||
uint32 SpellID; // 2
|
||||
uint32 OrderIndex; // 3
|
||||
};
|
||||
|
||||
struct MountCapabilityEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
|
||||
@@ -107,6 +107,7 @@ char const PhaseGroupfmt[] = "nii";
|
||||
char const MailTemplateEntryfmt[] = "nxs";
|
||||
char const MapEntryfmt[] = "nxiixxsixxixiffxiiiixx";
|
||||
char const MapDifficultyEntryfmt[] = "diisiix";
|
||||
char const MinorTalentEntryfmt[] = "niii";
|
||||
char const MovieEntryfmt[] = "nxxxx";
|
||||
char const MountCapabilityfmt[] = "niiiiiii";
|
||||
char const MountTypefmt[] = "niiiiiiiiiiiiiiiiiiiiiiii";
|
||||
@@ -156,9 +157,7 @@ char const SpellShapeshiftEntryfmt[] = "niiiix";
|
||||
char const SpellShapeshiftFormfmt[] = "nxxiixiiiiiiiiiiiiixx";
|
||||
char const StableSlotPricesfmt[] = "ni";
|
||||
char const SummonPropertiesfmt[] = "niiiii";
|
||||
char const TalentEntryfmt[] = "niiiiiiiiixxixxxxxx";
|
||||
char const TalentTabEntryfmt[] = "nxxiiixxxii";
|
||||
char const TalentTreePrimarySpellsfmt[] = "diix";
|
||||
char const TalentEntryfmt[] = "niiiiiiiiix";
|
||||
char const TaxiNodesEntryfmt[] = "nifffsiiixx";
|
||||
char const TaxiPathEntryfmt[] = "niii";
|
||||
char const TaxiPathNodeEntryfmt[] = "diiifffiiii";
|
||||
|
||||
@@ -341,7 +341,8 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c
|
||||
if (owner->GetGroup())
|
||||
owner->SetGroupUpdateFlag(GROUP_UPDATE_PET);
|
||||
|
||||
owner->SendTalentsInfoData(true);
|
||||
// TODO: 6.x remove/update pet talents
|
||||
//owner->SendTalentsInfoData(true);
|
||||
|
||||
if (getPetType() == HUNTER_PET)
|
||||
{
|
||||
@@ -1735,6 +1736,7 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= NULL*/)
|
||||
|
||||
void Pet::InitTalentForLevel()
|
||||
{
|
||||
/* TODO: 6.x remove/update pet talents
|
||||
uint8 level = getLevel();
|
||||
uint32 talentPointsForLevel = GetMaxTalentPointsForLevel(level);
|
||||
// Reset talents in case low level (on level down) or wrong points for level (hunter can unlearn TP increase talent)
|
||||
@@ -1745,6 +1747,7 @@ void Pet::InitTalentForLevel()
|
||||
|
||||
if (!m_loading)
|
||||
GetOwner()->SendTalentsInfoData(true);
|
||||
*/
|
||||
}
|
||||
|
||||
uint8 Pet::GetMaxTalentPointsForLevel(uint8 level)
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "ChannelMgr.h"
|
||||
#include "CharacterDatabaseCleaner.h"
|
||||
#include "CharacterPackets.h"
|
||||
#include "TalentPackets.h"
|
||||
#include "Chat.h"
|
||||
#include "Common.h"
|
||||
#include "ConditionMgr.h"
|
||||
@@ -2985,7 +2986,7 @@ void Player::GiveLevel(uint8 level)
|
||||
void Player::InitTalentForLevel()
|
||||
{
|
||||
if (!GetSession()->PlayerLoading())
|
||||
SendTalentsInfoData(false); // update at client
|
||||
SendTalentsInfoData(); // update at client
|
||||
}
|
||||
|
||||
void Player::InitStatsForLevel(bool reapplyMods)
|
||||
@@ -3308,20 +3309,29 @@ void DeleteSpellFromAllPlayers(uint32 spellId)
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning)
|
||||
bool Player::AddTalent(uint32 talentId, uint8 spec)
|
||||
{
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
TalentEntry const* talentEntry = sTalentStore.LookupEntry(talentId);
|
||||
|
||||
// Check if talent exists in Talent.dbc
|
||||
if (!talentEntry)
|
||||
{
|
||||
TC_LOG_ERROR("spells", "Player::addTalent: Talent %u not found", talentId);
|
||||
return false;
|
||||
}
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentEntry->SpellID);
|
||||
if (!spellInfo)
|
||||
{
|
||||
// do character spell book cleanup (all characters)
|
||||
if (!IsInWorld() && !learning) // spell load case
|
||||
if (!IsInWorld()) // spell load case
|
||||
{
|
||||
TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", spellId);
|
||||
TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request, deleting for all characters in `character_spell`.", talentEntry->SpellID);
|
||||
|
||||
DeleteSpellFromAllPlayers(spellId);
|
||||
DeleteSpellFromAllPlayers(talentEntry->SpellID);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", spellId);
|
||||
TC_LOG_ERROR("spells", "Player::addSpell: Non-existed in SpellStore spell #%u request.", talentEntry->SpellID);
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -3329,35 +3339,25 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning)
|
||||
if (!SpellMgr::IsSpellValid(spellInfo, this, false))
|
||||
{
|
||||
// do character spell book cleanup (all characters)
|
||||
if (!IsInWorld() && !learning) // spell load case
|
||||
if (!IsInWorld()) // spell load case
|
||||
{
|
||||
TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", spellId);
|
||||
TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed, deleting for all characters in `character_talent`.", talentEntry->SpellID);
|
||||
|
||||
DeleteSpellFromAllPlayers(spellId);
|
||||
DeleteSpellFromAllPlayers(talentEntry->SpellID);
|
||||
}
|
||||
else
|
||||
TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", spellId);
|
||||
TC_LOG_ERROR("spells", "Player::addTalent: Broken spell #%u learning not allowed.", talentEntry->SpellID);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TalentEntry const* talentEntry = GetTalentBySpellID(spellId);
|
||||
|
||||
// Check if talent exists in Talent.dbc
|
||||
if (!talentEntry) {
|
||||
TC_LOG_ERROR("spells", "Player::addTalent: Learning non-talent spell %u not allowed.", spellId);
|
||||
return false;
|
||||
}
|
||||
|
||||
TalentSpecInfo* talentSpecInfo = GetTalentSpecInfo(spec);
|
||||
TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(spec);
|
||||
|
||||
// Check if player already has this talent
|
||||
if (talentSpecInfo->HasTalent(spellId))
|
||||
if (talentGroupInfo->HasTalent(talentId))
|
||||
return false;
|
||||
|
||||
talentSpecInfo->Talents[talentEntry->TierID].SpellID = spellId;
|
||||
if (learning)
|
||||
talentSpecInfo->Talents[talentEntry->TierID].State = PLAYERSPELL_NEW;
|
||||
talentGroupInfo->Talents[talentEntry->TierID] = talentId;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3707,7 +3707,7 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
|
||||
|
||||
bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const
|
||||
{
|
||||
if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec())))
|
||||
if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
|
||||
return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1];
|
||||
|
||||
return false;
|
||||
@@ -4121,7 +4121,8 @@ bool Player::ResetTalents(bool no_cost)
|
||||
|
||||
RemovePet(NULL, PET_SAVE_NOT_IN_SLOT, true);
|
||||
|
||||
uint8 spec = GetActiveSpec();
|
||||
uint8 group = GetActiveTalentGroup();
|
||||
uint32 specID = GetActiveTalentSpec();
|
||||
|
||||
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
{
|
||||
@@ -4147,13 +4148,10 @@ bool Player::ResetTalents(bool no_cost)
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
|
||||
if (_spellEntry->Effects[i].TriggerSpell > 0 && _spellEntry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
RemoveSpell(_spellEntry->Effects[i].TriggerSpell, true);
|
||||
|
||||
// Reset talents store
|
||||
GetTalentSpecInfo(spec)->Reset();
|
||||
}
|
||||
|
||||
// Remove all specialization specific spells and give default ones which were overriden
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(GetActiveSpec()));
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(specID);
|
||||
if (specSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
|
||||
@@ -4168,12 +4166,14 @@ bool Player::ResetTalents(bool no_cost)
|
||||
}
|
||||
|
||||
// Unlearn masteries
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(spec));
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(specID);
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (uint32 mastery = chrSpec->MasterySpellID[i])
|
||||
RemoveAurasDueToSpell(mastery);
|
||||
|
||||
SetTalentSpec(spec, 0);
|
||||
// Reset talents store
|
||||
GetTalentGroupInfo(group)->Reset();
|
||||
SetTalentSpec(group, 0);
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
_SaveTalents(trans);
|
||||
@@ -4265,9 +4265,9 @@ bool Player::HasSpell(uint32 spell) const
|
||||
!itr->second->disabled);
|
||||
}
|
||||
|
||||
bool Player::HasTalent(uint32 spell, uint8 spec)
|
||||
bool Player::HasTalent(uint32 talentId, uint8 group)
|
||||
{
|
||||
return GetTalentSpecInfo(spec)->HasTalent(spell);
|
||||
return GetTalentGroupInfo(group)->HasTalent(talentId);
|
||||
}
|
||||
|
||||
bool Player::HasActiveSpell(uint32 spell) const
|
||||
@@ -6269,7 +6269,7 @@ void Player::SendActionButtons(uint32 state) const
|
||||
|
||||
data << uint8(state);
|
||||
GetSession()->SendPacket(&data);
|
||||
TC_LOG_INFO("network", "Action Buttons for '%s' spec '%u' Sent", GetGUID().ToString().c_str(), GetActiveSpec());
|
||||
TC_LOG_INFO("network", "Action Buttons for '%s' group '%u' Sent", GetGUID().ToString().c_str(), GetActiveTalentGroup());
|
||||
}
|
||||
|
||||
bool Player::IsActionButtonDataValid(uint8 button, uint32 action, uint8 type)
|
||||
@@ -9684,6 +9684,7 @@ void Player::SendTalentWipeConfirm(ObjectGuid guid)
|
||||
|
||||
void Player::ResetPetTalents()
|
||||
{
|
||||
/* TODO: 6.x remove/update pet talents
|
||||
// This needs another gossip option + NPC text as a confirmation.
|
||||
// The confirmation gossip listid has the text: "Yes, please do."
|
||||
Pet* pet = GetPet();
|
||||
@@ -9699,6 +9700,7 @@ void Player::ResetPetTalents()
|
||||
}
|
||||
pet->resetTalents();
|
||||
SendTalentsInfoData(true);
|
||||
*/
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
@@ -14117,7 +14119,7 @@ void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId /*= 0*/, bool
|
||||
break;
|
||||
}
|
||||
case GOSSIP_OPTION_LEARNDUALSPEC:
|
||||
if (!(GetSpecsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
|
||||
if (!(GetTalentGroupsCount() == 1 && creature->isCanTrainingAndResetTalentsOf(this) && !(getLevel() < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))))
|
||||
canTalk = false;
|
||||
break;
|
||||
case GOSSIP_OPTION_UNLEARNTALENTS:
|
||||
@@ -14331,7 +14333,7 @@ void Player::OnGossipSelect(WorldObject* source, uint32 gossipListId, uint32 men
|
||||
GetSession()->SendTrainerList(guid);
|
||||
break;
|
||||
case GOSSIP_OPTION_LEARNDUALSPEC:
|
||||
if (GetSpecsCount() == 1 && getLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))
|
||||
if (GetTalentGroupsCount() == 1 && getLevel() >= sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL))
|
||||
{
|
||||
// Cast spells that teach dual spec
|
||||
// Both are also ImplicitTarget self and must be cast by player
|
||||
@@ -17431,19 +17433,19 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
|
||||
//mails are loaded only when needed ;-) - when player in game click on mailbox.
|
||||
//_LoadMail();
|
||||
|
||||
SetSpecsCount(fields[53].GetUInt8());
|
||||
SetActiveSpec(fields[54].GetUInt8());
|
||||
SetTalentGroupsCount(fields[53].GetUInt8());
|
||||
SetActiveTalentGroup(fields[54].GetUInt8());
|
||||
|
||||
// sanity check
|
||||
if (GetSpecsCount() > MAX_TALENT_SPECS || GetActiveSpec() > MAX_TALENT_SPEC || GetSpecsCount() < MIN_TALENT_SPECS)
|
||||
if (GetTalentGroupsCount() > MAX_TALENT_GROUPS || GetActiveTalentGroup() > MAX_TALENT_GROUP || GetTalentGroupsCount() < MIN_TALENT_GROUPS)
|
||||
{
|
||||
SetActiveSpec(0);
|
||||
TC_LOG_ERROR("entities.player", "Player %s (%s) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().ToString().c_str(), GetSpecsCount(), GetActiveSpec());
|
||||
TC_LOG_ERROR("entities.player", "Player %s (%s) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUID().ToString().c_str(), GetTalentGroupsCount(), GetActiveTalentGroup());
|
||||
SetActiveTalentGroup(0);
|
||||
}
|
||||
|
||||
// Only load selected specializations, learning mastery spells requires this
|
||||
Tokenizer talentSpecs(fields[26].GetString(), ' ', MAX_TALENT_SPECS);
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
Tokenizer talentSpecs(fields[26].GetString(), ' ', MAX_TALENT_GROUPS);
|
||||
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
|
||||
{
|
||||
if (i >= talentSpecs.size())
|
||||
break;
|
||||
@@ -17804,7 +17806,7 @@ void Player::_LoadGlyphAuras()
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
{
|
||||
if (uint32 glyph = GetGlyph(GetActiveSpec(), i))
|
||||
if (uint32 glyph = GetGlyph(GetActiveTalentGroup(), i))
|
||||
{
|
||||
if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph))
|
||||
{
|
||||
@@ -19104,7 +19106,7 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
stmt->setUInt32(index++, GetTalentResetTime());
|
||||
|
||||
ss.str("");
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
|
||||
ss << GetTalentSpec(i) << " ";
|
||||
stmt->setString(index++, ss.str());
|
||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
@@ -19141,8 +19143,8 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
|
||||
stmt->setUInt32(index++, GetSession()->GetLatency());
|
||||
|
||||
stmt->setUInt8(index++, GetSpecsCount());
|
||||
stmt->setUInt8(index++, GetActiveSpec());
|
||||
stmt->setUInt8(index++, GetTalentGroupsCount());
|
||||
stmt->setUInt8(index++, GetActiveTalentGroup());
|
||||
|
||||
ss.str("");
|
||||
for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i)
|
||||
@@ -19233,7 +19235,7 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
stmt->setUInt32(index++, GetTalentResetTime());
|
||||
|
||||
ss.str("");
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
|
||||
ss << GetTalentSpec(i) << " ";
|
||||
stmt->setString(index++, ss.str());
|
||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
@@ -19270,8 +19272,8 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
|
||||
stmt->setUInt32(index++, GetSession()->GetLatency());
|
||||
|
||||
stmt->setUInt8(index++, GetSpecsCount());
|
||||
stmt->setUInt8(index++, GetActiveSpec());
|
||||
stmt->setUInt8(index++, GetTalentGroupsCount());
|
||||
stmt->setUInt8(index++, GetActiveTalentGroup());
|
||||
|
||||
ss.str("");
|
||||
for (uint32 i = 0; i < PLAYER_EXPLORED_ZONES_SIZE; ++i)
|
||||
@@ -19377,7 +19379,7 @@ void Player::_SaveActions(SQLTransaction& trans)
|
||||
case ACTIONBUTTON_NEW:
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACTION);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt8(1, GetActiveSpec());
|
||||
stmt->setUInt8(1, GetActiveTalentGroup());
|
||||
stmt->setUInt8(2, itr->first);
|
||||
stmt->setUInt32(3, itr->second.GetAction());
|
||||
stmt->setUInt8(4, uint8(itr->second.GetType()));
|
||||
@@ -19392,7 +19394,7 @@ void Player::_SaveActions(SQLTransaction& trans)
|
||||
stmt->setUInt8(1, uint8(itr->second.GetType()));
|
||||
stmt->setUInt64(2, GetGUID().GetCounter());
|
||||
stmt->setUInt8(3, itr->first);
|
||||
stmt->setUInt8(4, GetActiveSpec());
|
||||
stmt->setUInt8(4, GetActiveTalentGroup());
|
||||
trans->Append(stmt);
|
||||
|
||||
itr->second.uState = ACTIONBUTTON_UNCHANGED;
|
||||
@@ -19402,7 +19404,7 @@ void Player::_SaveActions(SQLTransaction& trans)
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt8(1, itr->first);
|
||||
stmt->setUInt8(2, GetActiveSpec());
|
||||
stmt->setUInt8(2, GetActiveTalentGroup());
|
||||
trans->Append(stmt);
|
||||
|
||||
m_actionButtons.erase(itr++);
|
||||
@@ -23054,7 +23056,7 @@ void Player::SendInitialPacketsBeforeAddToMap()
|
||||
// SMSG_SET_FLAT_SPELL_MODIFIER
|
||||
// SMSG_UPDATE_AURA_DURATION
|
||||
|
||||
SendTalentsInfoData(false);
|
||||
SendTalentsInfoData();
|
||||
|
||||
data.Initialize(SMSG_WORLD_SERVER_INFO, 1 + 1 + 4 + 4);
|
||||
data.WriteBit(0); // HasRestrictedLevel
|
||||
@@ -24802,7 +24804,7 @@ void Player::InitGlyphsForLevel()
|
||||
|
||||
void Player::SetGlyph(uint8 slot, uint32 glyph)
|
||||
{
|
||||
_talentMgr->SpecInfo[GetActiveSpec()].Glyphs[slot] = glyph;
|
||||
_talentMgr->GroupInfo[GetActiveTalentGroup()].Glyphs[slot] = glyph;
|
||||
SetUInt32Value(PLAYER_FIELD_GLYPHS_1 + slot, glyph);
|
||||
}
|
||||
|
||||
@@ -25487,7 +25489,7 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
|
||||
|
||||
bool Player::LearnTalent(uint32 talentId)
|
||||
{
|
||||
uint8 spec = GetActiveSpec();
|
||||
uint8 group = GetActiveTalentGroup();
|
||||
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
|
||||
@@ -25498,13 +25500,15 @@ bool Player::LearnTalent(uint32 talentId)
|
||||
if (getClass() != talentInfo->ClassID)
|
||||
return false;
|
||||
|
||||
// Check player level.
|
||||
if (getLevel() < (15*talentInfo->TierID + 15))
|
||||
// Check player level
|
||||
// TODO: fix level requirements for deathknights
|
||||
uint8 levelReq = std::min(15*talentInfo->TierID + 15, sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL));
|
||||
if (getLevel() < levelReq)
|
||||
return false;
|
||||
|
||||
// Check if such tier talent hasn't been picked already
|
||||
TalentSpecInfo* talentSpecInfo = GetTalentSpecInfo(spec);
|
||||
if (talentSpecInfo->Talents[talentInfo->TierID].SpellID != 0)
|
||||
TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group);
|
||||
if (talentGroupInfo->Talents[talentInfo->TierID])
|
||||
return false;
|
||||
|
||||
// spell not set in talent.dbc
|
||||
@@ -25519,16 +25523,10 @@ bool Player::LearnTalent(uint32 talentId)
|
||||
if (HasSpell(spellid))
|
||||
return false;
|
||||
|
||||
// learn! (other talent ranks will unlearned at learning)
|
||||
LearnSpell(spellid, false);
|
||||
AddTalent(spellid, spec, true);
|
||||
|
||||
TC_LOG_INFO("misc", "TalentID: %u Spell: %u Spec: %u\n", talentId, spellid, spec);
|
||||
|
||||
// set talent tree for player
|
||||
if (!GetTalentSpec(spec))
|
||||
// set talent spec for player
|
||||
if (!GetTalentSpec(group))
|
||||
{
|
||||
SetTalentSpec(spec, talentInfo->SpecID);
|
||||
SetTalentSpec(group, talentInfo->SpecID);
|
||||
|
||||
// Replace default spells by specialization spells
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(talentInfo->SpecID);
|
||||
@@ -25553,6 +25551,16 @@ bool Player::LearnTalent(uint32 talentId)
|
||||
}
|
||||
}
|
||||
|
||||
// Check talent spec
|
||||
if (talentInfo->SpecID != GetTalentSpec(group))
|
||||
return false;
|
||||
|
||||
// learn! (other talent ranks will unlearned at learning)
|
||||
LearnSpell(spellid, false);
|
||||
AddTalent(talentId, group);
|
||||
|
||||
TC_LOG_INFO("misc", "TalentID: %u Spell: %u Group: %u\n", talentId, spellid, group);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25630,160 +25638,38 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void Player::BuildPlayerTalentsInfoData(WorldPacket* data)
|
||||
void Player::SendTalentsInfoData()
|
||||
{
|
||||
/* TODO: 6.x update with new talent system (and move to packet class)
|
||||
*data << uint32(GetFreeTalentPoints()); // unspentTalentPoints
|
||||
*data << uint8(GetSpecsCount()); // talent group count (0, 1 or 2)
|
||||
*data << uint8(GetActiveSpec()); // talent group index (0 or 1)
|
||||
WorldPackets::Talent::UpdateTalentData packet;
|
||||
|
||||
if (GetSpecsCount())
|
||||
packet.Info.ActiveGroup = GetActiveTalentGroup();
|
||||
|
||||
uint8 groupsCount = GetTalentGroupsCount();
|
||||
|
||||
for (uint8 i = 0; i < groupsCount; ++i)
|
||||
{
|
||||
if (GetSpecsCount() > MAX_TALENT_SPECS)
|
||||
SetSpecsCount(MAX_TALENT_SPECS);
|
||||
|
||||
// loop through all specs (only 1 for now)
|
||||
for (uint8 specIdx = 0; specIdx < GetSpecsCount(); ++specIdx)
|
||||
TalentGroupInfo* groupInfo = GetTalentGroupInfo(i);
|
||||
WorldPackets::Talent::TalentGroupInfo groupInfoPkt;
|
||||
|
||||
groupInfoPkt.SpecID = groupInfo->SpecID;
|
||||
|
||||
groupInfoPkt.TalentIDs.reserve(MAX_TALENT_TIERS);
|
||||
for (uint32 x = 0; x < MAX_TALENT_TIERS; ++x)
|
||||
{
|
||||
*data << uint32(GetPrimaryTalentTree(specIdx));
|
||||
uint8 talentIdCount = 0;
|
||||
size_t pos = data->wpos();
|
||||
*data << uint8(talentIdCount); // [PH], talentIdCount
|
||||
// Do not send empty talents
|
||||
if (!groupInfo->Talents[x])
|
||||
break;
|
||||
|
||||
// find class talent tabs (all players have 3 talent tabs)
|
||||
uint32 const* talentTabIds = GetTalentTabPages(getClass());
|
||||
|
||||
for (uint8 i = 0; i < MAX_TALENT_TABS; ++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 (0~4)
|
||||
int8 curtalent_maxrank = -1;
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
{
|
||||
if (talentInfo->RankID[rank] && HasTalent(talentInfo->RankID[rank], specIdx))
|
||||
{
|
||||
curtalent_maxrank = rank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not learned talent
|
||||
if (curtalent_maxrank < 0)
|
||||
continue;
|
||||
|
||||
*data << uint32(talentInfo->TalentID); // Talent.dbc
|
||||
*data << uint8(curtalent_maxrank); // talentMaxRank (0-4)
|
||||
|
||||
++talentIdCount;
|
||||
}
|
||||
}
|
||||
|
||||
data->put<uint8>(pos, talentIdCount); // put real count
|
||||
|
||||
*data << uint8(MAX_GLYPH_SLOT_INDEX); // glyphs count
|
||||
|
||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
*data << uint16(GetGlyph(specIdx, i)); // GlyphProperties.dbc
|
||||
groupInfoPkt.TalentIDs.push_back(groupInfo->Talents[x]);
|
||||
}
|
||||
|
||||
for (uint32 x = 0; x < MAX_GLYPH_SLOT_INDEX; ++x)
|
||||
groupInfoPkt.GlyphIDs[x] = groupInfo->Glyphs[x];
|
||||
|
||||
packet.Info.TalentGroups.push_back(groupInfoPkt);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Player::BuildPetTalentsInfoData(WorldPacket* data)
|
||||
{
|
||||
/* TODO: 6.x update with new talent system (and move to packet class)
|
||||
uint32 unspentTalentPoints = 0;
|
||||
size_t pointsPos = data->wpos();
|
||||
*data << uint32(unspentTalentPoints); // [PH], unspentTalentPoints
|
||||
|
||||
uint8 talentIdCount = 0;
|
||||
size_t countPos = data->wpos();
|
||||
*data << uint8(talentIdCount); // [PH], talentIdCount
|
||||
|
||||
Pet* pet = GetPet();
|
||||
if (!pet)
|
||||
return;
|
||||
|
||||
unspentTalentPoints = pet->GetFreeTalentPoints();
|
||||
|
||||
data->put<uint32>(pointsPos, unspentTalentPoints); // put real points
|
||||
|
||||
CreatureTemplate const* ci = pet->GetCreatureTemplate();
|
||||
if (!ci)
|
||||
return;
|
||||
|
||||
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
|
||||
if (!pet_family || pet_family->PetTalentType < 0)
|
||||
return;
|
||||
|
||||
for (uint32 talentTabId = 1; talentTabId < sTalentTabStore.GetNumRows(); ++talentTabId)
|
||||
{
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabId);
|
||||
if (!talentTabInfo)
|
||||
continue;
|
||||
|
||||
if (!((1 << pet_family->PetTalentType) & talentTabInfo->petTalentMask))
|
||||
continue;
|
||||
|
||||
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 (0~4)
|
||||
int8 curtalent_maxrank = -1;
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
{
|
||||
if (talentInfo->RankID[rank] && pet->HasSpell(talentInfo->RankID[rank]))
|
||||
{
|
||||
curtalent_maxrank = rank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not learned talent
|
||||
if (curtalent_maxrank < 0)
|
||||
continue;
|
||||
|
||||
*data << uint32(talentInfo->TalentID); // Talent.dbc
|
||||
*data << uint8(curtalent_maxrank); // talentMaxRank (0-4)
|
||||
|
||||
++talentIdCount;
|
||||
}
|
||||
|
||||
data->put<uint8>(countPos, talentIdCount); // put real count
|
||||
|
||||
break;
|
||||
}*/
|
||||
}
|
||||
|
||||
void Player::SendTalentsInfoData(bool pet)
|
||||
{
|
||||
/* TODO: 6.x update with new talent system (and move to packet class)
|
||||
WorldPacket data(SMSG_TALENTS_INFO, 50);
|
||||
data << uint8(pet ? 1 : 0);
|
||||
if (pet)
|
||||
BuildPetTalentsInfoData(&data);
|
||||
else
|
||||
BuildPlayerTalentsInfoData(&data);
|
||||
GetSession()->SendPacket(&data);
|
||||
*/
|
||||
GetSession()->SendPacket(packet.Write());
|
||||
}
|
||||
|
||||
void Player::BuildEnchantmentsInfoData(WorldPacket* data)
|
||||
@@ -26064,7 +25950,7 @@ void Player::SetMap(Map* map)
|
||||
|
||||
void Player::_LoadGlyphs(PreparedQueryResult result)
|
||||
{
|
||||
// SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = '%u'
|
||||
// SELECT group, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = '%u'
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
@@ -26072,12 +25958,12 @@ void Player::_LoadGlyphs(PreparedQueryResult result)
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
uint8 spec = fields[0].GetUInt8();
|
||||
if (spec >= GetSpecsCount())
|
||||
uint8 group = fields[0].GetUInt8();
|
||||
if (group >= GetTalentGroupsCount())
|
||||
continue;
|
||||
|
||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
_talentMgr->SpecInfo[spec].Glyphs[i] = fields[i + 1].GetUInt16();
|
||||
_talentMgr->GroupInfo[group].Glyphs[i] = fields[i + 1].GetUInt16();
|
||||
}
|
||||
while (result->NextRow());
|
||||
}
|
||||
@@ -26089,17 +25975,17 @@ void Player::_SaveGlyphs(SQLTransaction& trans)
|
||||
trans->Append(stmt);
|
||||
|
||||
|
||||
for (uint8 spec = 0; spec < GetSpecsCount(); ++spec)
|
||||
for (uint8 group = 0; group < GetTalentGroupsCount(); ++group)
|
||||
{
|
||||
uint8 index = 0;
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS);
|
||||
stmt->setUInt64(index++, GetGUID().GetCounter());
|
||||
|
||||
stmt->setUInt8(index++, spec);
|
||||
stmt->setUInt8(index++, group);
|
||||
|
||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
stmt->setUInt16(index++, uint16(GetGlyph(spec, i)));
|
||||
stmt->setUInt16(index++, uint16(GetGlyph(group, i)));
|
||||
|
||||
trans->Append(stmt);
|
||||
}
|
||||
@@ -26111,57 +25997,43 @@ void Player::_LoadTalents(PreparedQueryResult result)
|
||||
if (result)
|
||||
{
|
||||
do
|
||||
AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8(), false);
|
||||
AddTalent((*result)[0].GetUInt32(), (*result)[1].GetUInt8());
|
||||
while (result->NextRow());
|
||||
}
|
||||
}
|
||||
|
||||
void Player::_SaveTalents(SQLTransaction& trans)
|
||||
{
|
||||
PreparedStatement* stmt = NULL;
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
trans->Append(stmt);
|
||||
|
||||
for (uint8 spec = 0; spec < MAX_TALENT_SPECS; ++spec)
|
||||
for (uint8 group = 0; group < MAX_TALENT_GROUPS; ++group)
|
||||
{
|
||||
TalentSpecInfo* talentSpecInfo = GetTalentSpecInfo(spec);
|
||||
TalentGroupInfo* talentGroupInfo = GetTalentGroupInfo(group);
|
||||
|
||||
for (uint32 tier = 0; tier < MAX_TALENT_TIERS; ++tier)
|
||||
{
|
||||
PlayerTalent* talent = &talentSpecInfo->Talents[tier];
|
||||
if (!talentGroupInfo->Talents[tier])
|
||||
continue;
|
||||
|
||||
if (talent->State == PLAYERSPELL_REMOVED || talent->State == PLAYERSPELL_CHANGED)
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, talent->SpellID);
|
||||
stmt->setUInt8(2, spec);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
if (talent->State == PLAYERSPELL_NEW || talent->State == PLAYERSPELL_CHANGED)
|
||||
{
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, talent->SpellID);
|
||||
stmt->setUInt8(2, spec);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
if (talent->State == PLAYERSPELL_REMOVED)
|
||||
talent->SpellID = 0;
|
||||
|
||||
talent->State = PLAYERSPELL_UNCHANGED;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt32(1, talentGroupInfo->Talents[tier]);
|
||||
stmt->setUInt8(2, group);
|
||||
trans->Append(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::UpdateSpecCount(uint8 count)
|
||||
void Player::UpdateTalentGroupCount(uint8 count)
|
||||
{
|
||||
uint32 curCount = GetSpecsCount();
|
||||
uint32 curCount = GetTalentGroupsCount();
|
||||
if (curCount == count)
|
||||
return;
|
||||
|
||||
if (GetActiveSpec() >= count)
|
||||
ActivateSpec(0);
|
||||
if (GetActiveTalentGroup() >= count)
|
||||
ActivateTalentGroup(0);
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
PreparedStatement* stmt = NULL;
|
||||
@@ -26187,7 +26059,7 @@ void Player::UpdateSpecCount(uint8 count)
|
||||
_SaveActions(trans);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC);
|
||||
stmt->setUInt8(0, GetActiveSpec());
|
||||
stmt->setUInt8(0, GetActiveTalentGroup());
|
||||
stmt->setUInt64(1, GetGUID().GetCounter());
|
||||
trans->Append(stmt);
|
||||
|
||||
@@ -26195,17 +26067,17 @@ void Player::UpdateSpecCount(uint8 count)
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
SetSpecsCount(count);
|
||||
SetTalentGroupsCount(count);
|
||||
|
||||
SendTalentsInfoData(false);
|
||||
SendTalentsInfoData();
|
||||
}
|
||||
|
||||
void Player::ActivateSpec(uint8 spec)
|
||||
void Player::ActivateTalentGroup(uint8 group)
|
||||
{
|
||||
if (GetActiveSpec() == spec)
|
||||
if (GetActiveTalentGroup() == group)
|
||||
return;
|
||||
|
||||
if (spec > GetSpecsCount())
|
||||
if (group > GetTalentGroupsCount())
|
||||
return;
|
||||
|
||||
if (IsNonMeleeSpellCast(false))
|
||||
@@ -26251,7 +26123,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
}
|
||||
|
||||
// Unlearn specialization specific spells
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(GetActiveSpec()));
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec());
|
||||
if (specSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
|
||||
@@ -26265,7 +26137,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
}
|
||||
|
||||
// Unlearn mastery spells
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec()));
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec());
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (chrSpec->MasterySpellID[i])
|
||||
RemoveSpell(chrSpec->MasterySpellID[i], true);
|
||||
@@ -26273,12 +26145,12 @@ void Player::ActivateSpec(uint8 spec)
|
||||
// set glyphs
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
// remove secondary glyph
|
||||
if (uint32 oldglyph = GetGlyph(GetActiveSpec(), slot))
|
||||
if (uint32 oldglyph = GetGlyph(GetActiveTalentGroup(), slot))
|
||||
if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
|
||||
RemoveAurasDueToSpell(old_gp->SpellID);
|
||||
|
||||
// Activate new spec
|
||||
SetActiveSpec(spec);
|
||||
// Activate new group
|
||||
SetActiveTalentGroup(group);
|
||||
|
||||
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
{
|
||||
@@ -26291,14 +26163,11 @@ void Player::ActivateSpec(uint8 spec)
|
||||
if (getClass() != talentInfo->ClassID)
|
||||
continue;
|
||||
|
||||
if (HasTalent(talentInfo->SpellID, GetActiveSpec()))
|
||||
{
|
||||
LearnSpell(talentInfo->SpellID, false);
|
||||
}
|
||||
LearnSpell(talentInfo->SpellID, false);
|
||||
}
|
||||
|
||||
// Replace default spells with specialization specific spells
|
||||
auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(spec));
|
||||
auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetActiveTalentSpec());
|
||||
if (newSpecSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
for (auto it = newSpecSpells->second.begin(); it != newSpecSpells->second.end(); ++it)
|
||||
@@ -26314,7 +26183,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
}
|
||||
|
||||
if (CanUseMastery())
|
||||
if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(spec)))
|
||||
if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (newChrSpec->MasterySpellID[i])
|
||||
LearnSpell(newChrSpec->MasterySpellID[i], false);
|
||||
@@ -26322,7 +26191,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
// set glyphs
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
{
|
||||
uint32 glyph = GetGlyph(GetActiveSpec(), slot);
|
||||
uint32 glyph = GetGlyph(GetActiveTalentGroup(), slot);
|
||||
|
||||
// apply primary glyph
|
||||
if (glyph)
|
||||
@@ -26337,7 +26206,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC);
|
||||
stmt->setUInt64(0, GetGUID().GetCounter());
|
||||
stmt->setUInt8(1, GetActiveSpec());
|
||||
stmt->setUInt8(1, GetActiveTalentGroup());
|
||||
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
|
||||
_LoadActions(result);
|
||||
}
|
||||
@@ -26350,7 +26219,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
|
||||
SetPower(pw, 0);
|
||||
|
||||
if (!sChrSpecializationStore.LookupEntry(GetTalentSpec(spec)))
|
||||
if (!sChrSpecializationStore.LookupEntry(GetActiveTalentSpec()))
|
||||
ResetTalents(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -115,12 +115,6 @@ struct PlayerSpell
|
||||
bool disabled : 1; // first rank has been learned in result talent learn but currently talent unlearned, save max learned ranks
|
||||
};
|
||||
|
||||
struct PlayerTalent
|
||||
{
|
||||
PlayerSpellState State : 8;
|
||||
uint32 SpellID : 32;
|
||||
};
|
||||
|
||||
extern uint32 const MasterySpells[MAX_CLASSES];
|
||||
|
||||
enum TalentSpecialization // talent tabs
|
||||
@@ -1217,46 +1211,52 @@ private:
|
||||
bool _isPvP;
|
||||
};
|
||||
|
||||
struct TalentSpecInfo
|
||||
struct TalentGroupInfo
|
||||
{
|
||||
PlayerTalent Talents[MAX_TALENT_TIERS];
|
||||
uint32 Talents[MAX_TALENT_TIERS];
|
||||
uint32 Glyphs[MAX_GLYPH_SLOT_INDEX];
|
||||
uint32 TalentSpec;
|
||||
uint32 SpecID;
|
||||
|
||||
bool HasTalent(uint32 spellId)
|
||||
bool HasTalent(uint32 talentId)
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i)
|
||||
if (Talents[i].SpellID == spellId)
|
||||
if (Talents[i] == talentId)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 TalentCount()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i)
|
||||
if (!Talents[i])
|
||||
return i;
|
||||
return MAX_TALENT_TIERS;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i) {
|
||||
Talents[i].State = PLAYERSPELL_REMOVED;
|
||||
Talents[i].SpellID = 0;
|
||||
}
|
||||
for (uint32 i = 0; i < MAX_TALENT_TIERS; ++i)
|
||||
Talents[i] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct PlayerTalentInfo
|
||||
{
|
||||
PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveSpec(0), SpecsCount(1)
|
||||
PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), GroupsCount(1)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
for (uint8 i = 0; i < MAX_TALENT_GROUPS; ++i)
|
||||
{
|
||||
memset(SpecInfo[i].Talents, 0, sizeof(PlayerTalent)*MAX_TALENT_TIERS);
|
||||
memset(SpecInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32));
|
||||
SpecInfo[i].TalentSpec = 0;
|
||||
memset(GroupInfo[i].Talents, 0, sizeof(uint32)*MAX_TALENT_TIERS);
|
||||
memset(GroupInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32));
|
||||
GroupInfo[i].SpecID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
TalentSpecInfo SpecInfo[MAX_TALENT_SPECS];
|
||||
TalentGroupInfo GroupInfo[MAX_TALENT_GROUPS];
|
||||
uint32 ResetTalentsCost;
|
||||
time_t ResetTalentsTime;
|
||||
uint8 ActiveSpec;
|
||||
uint8 SpecsCount;
|
||||
uint8 ActiveGroup;
|
||||
uint8 GroupsCount;
|
||||
|
||||
private:
|
||||
PlayerTalentInfo(PlayerTalentInfo const&);
|
||||
@@ -1825,35 +1825,34 @@ class Player : public Unit, public GridObject<Player>
|
||||
void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; }
|
||||
uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; }
|
||||
void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; }
|
||||
uint8 GetActiveSpec() const { return _talentMgr->ActiveSpec; }
|
||||
void SetActiveSpec(uint8 spec){ _talentMgr->ActiveSpec = spec; }
|
||||
uint8 GetSpecsCount() const { return _talentMgr->SpecsCount; }
|
||||
void SetSpecsCount(uint8 count) { _talentMgr->SpecsCount = count; }
|
||||
uint32 GetTalentSpec(uint8 spec) const { return _talentMgr->SpecInfo[spec].TalentSpec; }
|
||||
void SetTalentSpec(uint8 spec, uint32 talentSpec) const { _talentMgr->SpecInfo[spec].TalentSpec = talentSpec; }
|
||||
uint8 GetActiveTalentGroup() const { return _talentMgr->ActiveGroup; }
|
||||
void SetActiveTalentGroup(uint8 group){ _talentMgr->ActiveGroup = group; }
|
||||
uint8 GetTalentGroupsCount() const { return _talentMgr->GroupsCount; }
|
||||
void SetTalentGroupsCount(uint8 count) { _talentMgr->GroupsCount = count; }
|
||||
uint32 GetTalentSpec(uint8 group) const { return _talentMgr->GroupInfo[group].SpecID; }
|
||||
void SetTalentSpec(uint8 group, uint32 talentSpec) const { _talentMgr->GroupInfo[group].SpecID = talentSpec; }
|
||||
uint32 GetActiveTalentSpec() const { return _talentMgr->GroupInfo[_talentMgr->ActiveGroup].SpecID; }
|
||||
|
||||
bool ResetTalents(bool no_cost = false);
|
||||
uint32 GetNextResetTalentsCost() const;
|
||||
void InitTalentForLevel();
|
||||
void BuildPlayerTalentsInfoData(WorldPacket* data);
|
||||
void BuildPetTalentsInfoData(WorldPacket* data);
|
||||
void SendTalentsInfoData(bool pet);
|
||||
void SendTalentsInfoData();
|
||||
bool LearnTalent(uint32 talentId);
|
||||
bool AddTalent(uint32 spellId, uint8 spec, bool learning);
|
||||
bool HasTalent(uint32 spell_id, uint8 spec);
|
||||
bool AddTalent(uint32 talentId, uint8 spec);
|
||||
bool HasTalent(uint32 talentId, uint8 spec);
|
||||
|
||||
// Dual Spec
|
||||
void UpdateSpecCount(uint8 count);
|
||||
void ActivateSpec(uint8 spec);
|
||||
void UpdateTalentGroupCount(uint8 count);
|
||||
void ActivateTalentGroup(uint8 group);
|
||||
|
||||
void InitGlyphsForLevel();
|
||||
void SetGlyphSlot(uint8 slot, uint32 slottype) { SetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot, slottype); }
|
||||
|
||||
uint32 GetGlyphSlot(uint8 slot) const { return GetUInt32Value(PLAYER_FIELD_GLYPH_SLOTS_1 + slot); }
|
||||
void SetGlyph(uint8 slot, uint32 glyph);
|
||||
uint32 GetGlyph(uint8 spec, uint8 slot) const { return _talentMgr->SpecInfo[spec].Glyphs[slot]; }
|
||||
uint32 GetGlyph(uint8 group, uint8 slot) const { return _talentMgr->GroupInfo[group].Glyphs[slot]; }
|
||||
|
||||
TalentSpecInfo* GetTalentSpecInfo(uint8 spec) { return &_talentMgr->SpecInfo[spec]; }
|
||||
TalentGroupInfo* GetTalentGroupInfo(uint8 group) { return &_talentMgr->GroupInfo[group]; }
|
||||
ActionButtonList const& GetActionButtons() const { return m_actionButtons; }
|
||||
|
||||
uint32 GetFreePrimaryProfessionPoints() const { return GetUInt32Value(PLAYER_CHARACTER_POINTS); }
|
||||
|
||||
@@ -526,7 +526,7 @@ void Player::UpdateMastery()
|
||||
value += GetRatingBonusValue(CR_MASTERY);
|
||||
SetFloatValue(PLAYER_MASTERY, value);
|
||||
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec()));
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetActiveTalentSpec());
|
||||
if (!chrSpec)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1055,7 +1055,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
|
||||
if (pCurrChar->HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
|
||||
{
|
||||
pCurrChar->ResetTalents(true);
|
||||
pCurrChar->SendTalentsInfoData(false); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
|
||||
pCurrChar->SendTalentsInfoData(); // original talents send already in to SendInitialPacketsBeforeAddToMap, resend reset state
|
||||
SendNotification(LANG_RESET_TALENTS);
|
||||
}
|
||||
|
||||
@@ -1416,13 +1416,13 @@ void WorldSession::HandleRemoveGlyph(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
if (uint32 glyph = _player->GetGlyph(_player->GetActiveSpec(), slot))
|
||||
if (uint32 glyph = _player->GetGlyph(_player->GetActiveTalentGroup(), slot))
|
||||
{
|
||||
if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph))
|
||||
{
|
||||
_player->RemoveAurasDueToSpell(gp->SpellID);
|
||||
_player->SetGlyph(slot, 0);
|
||||
_player->SendTalentsInfoData(false);
|
||||
_player->SendTalentsInfoData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,6 +1242,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData)
|
||||
WorldPacket data(SMSG_INSPECT_TALENT, 8 + 4 + 1 + 1 + talent_points + 8 + 4 + 8 + 4);
|
||||
data << player->GetGUID();
|
||||
|
||||
/* TODO: 6.x update packet structure (BuildPlayerTalentsInfoData no longer exists)
|
||||
if (sWorld->getBoolConfig(CONFIG_TALENTS_INSPECTING) || _player->IsGameMaster())
|
||||
player->BuildPlayerTalentsInfoData(&data);
|
||||
else
|
||||
@@ -1250,6 +1251,7 @@ void WorldSession::HandleInspectOpcode(WorldPacket& recvData)
|
||||
data << uint8(0); // talentGroupCount
|
||||
data << uint8(0); // talentGroupIndex
|
||||
}
|
||||
*/
|
||||
|
||||
player->BuildEnchantmentsInfoData(&data);
|
||||
if (Guild* guild = sGuildMgr->GetGuildById(player->GetGuildId()))
|
||||
|
||||
@@ -111,7 +111,7 @@ void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
}
|
||||
|
||||
_player->SendTalentsInfoData(false);
|
||||
_player->SendTalentsInfoData();
|
||||
unit->CastSpell(_player, 14867, true); //spell: "Untalent Visual Effect"
|
||||
}
|
||||
|
||||
|
||||
@@ -815,10 +815,10 @@ enum SpellAttr13
|
||||
SPELL_ATTR13_UNK23 = 0x00800000 // 23
|
||||
};
|
||||
|
||||
#define MIN_TALENT_SPEC 0
|
||||
#define MAX_TALENT_SPEC 1
|
||||
#define MIN_TALENT_SPECS 1
|
||||
#define MAX_TALENT_SPECS 2
|
||||
#define MIN_TALENT_GROUP 0
|
||||
#define MAX_TALENT_GROUP 1
|
||||
#define MIN_TALENT_GROUPS 1
|
||||
#define MAX_TALENT_GROUPS 2
|
||||
#define MAX_GLYPH_SLOT_INDEX 9
|
||||
#define REQ_PRIMARY_TREE_TALENTS 31
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "TalentPackets.h"
|
||||
|
||||
WorldPacket const* WorldPackets::Talent::UpdateTalentData::Write()
|
||||
{
|
||||
_worldPacket << Info.ActiveGroup;
|
||||
_worldPacket << uint32(Info.TalentGroups.size());
|
||||
|
||||
for (auto& talentGroupInfo : Info.TalentGroups)
|
||||
{
|
||||
_worldPacket << talentGroupInfo.SpecID;
|
||||
_worldPacket << uint32(talentGroupInfo.TalentIDs.size());
|
||||
|
||||
for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
_worldPacket << talentGroupInfo.GlyphIDs[i];
|
||||
|
||||
for (uint16 talentID : talentGroupInfo.TalentIDs)
|
||||
_worldPacket << talentID;
|
||||
}
|
||||
|
||||
return &_worldPacket;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TalentPackets_h__
|
||||
#define TalentPackets_h__
|
||||
|
||||
#include "Packet.h"
|
||||
#include "Player.h"
|
||||
#include <vector>
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
namespace Talent
|
||||
{
|
||||
struct TalentGroupInfo
|
||||
{
|
||||
uint32 SpecID;
|
||||
std::vector<uint16> TalentIDs;
|
||||
uint16 GlyphIDs[MAX_GLYPH_SLOT_INDEX];
|
||||
};
|
||||
|
||||
struct TalentInfoUpdate
|
||||
{
|
||||
uint8 ActiveGroup;
|
||||
std::vector<TalentGroupInfo> TalentGroups;
|
||||
};
|
||||
|
||||
class UpdateTalentData final : public ServerPacket
|
||||
{
|
||||
public:
|
||||
UpdateTalentData() : ServerPacket(SMSG_TALENTS_INFO, 2+4+4+4+12) { }
|
||||
|
||||
WorldPacket const* Write() override;
|
||||
|
||||
TalentInfoUpdate Info;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TalentPackets_h__
|
||||
@@ -1246,7 +1246,7 @@ void AuraEffect::HandleShapeshiftBoosts(Unit* target, bool apply) const
|
||||
// Also do it for Glyphs
|
||||
for (uint32 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||
{
|
||||
if (uint32 glyphId = plrTarget->GetGlyph(plrTarget->GetActiveSpec(), i))
|
||||
if (uint32 glyphId = plrTarget->GetGlyph(plrTarget->GetActiveTalentGroup(), i))
|
||||
{
|
||||
if (GlyphPropertiesEntry const* glyph = sGlyphPropertiesStore.LookupEntry(glyphId))
|
||||
{
|
||||
|
||||
@@ -4034,7 +4034,7 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex)
|
||||
}
|
||||
|
||||
// remove old glyph
|
||||
if (uint32 oldGlyph = player->GetGlyph(player->GetActiveSpec(), m_glyphIndex))
|
||||
if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex))
|
||||
{
|
||||
if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph))
|
||||
{
|
||||
@@ -4045,16 +4045,16 @@ void Spell::EffectApplyGlyph(SpellEffIndex effIndex)
|
||||
|
||||
player->CastSpell(m_caster, newGlyphProperties->SpellID, true);
|
||||
player->SetGlyph(m_glyphIndex, newGlyph);
|
||||
player->SendTalentsInfoData(false);
|
||||
player->SendTalentsInfoData();
|
||||
}
|
||||
}
|
||||
else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveSpec(), m_glyphIndex)) // Removing the glyph, get the old one
|
||||
else if (uint32 oldGlyph = player->GetGlyph(player->GetActiveTalentGroup(), m_glyphIndex)) // Removing the glyph, get the old one
|
||||
{
|
||||
if (GlyphPropertiesEntry const* oldGlyphProperties = sGlyphPropertiesStore.LookupEntry(oldGlyph))
|
||||
{
|
||||
player->RemoveAurasDueToSpell(oldGlyphProperties->SpellID);
|
||||
player->SetGlyph(m_glyphIndex, 0);
|
||||
player->SendTalentsInfoData(false);
|
||||
player->SendTalentsInfoData();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5494,7 +5494,7 @@ void Spell::EffectSpecCount(SpellEffIndex /*effIndex*/)
|
||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
unitTarget->ToPlayer()->UpdateSpecCount(damage);
|
||||
unitTarget->ToPlayer()->UpdateTalentGroupCount(damage);
|
||||
}
|
||||
|
||||
void Spell::EffectActivateSpec(SpellEffIndex /*effIndex*/)
|
||||
@@ -5505,7 +5505,7 @@ void Spell::EffectActivateSpec(SpellEffIndex /*effIndex*/)
|
||||
if (!unitTarget || unitTarget->GetTypeId() != TYPEID_PLAYER)
|
||||
return;
|
||||
|
||||
unitTarget->ToPlayer()->ActivateSpec(damage-1); // damage is 1 or 2, spec is 0 or 1
|
||||
unitTarget->ToPlayer()->ActivateTalentGroup(damage-1); // damage is 1 or 2, spec is 0 or 1
|
||||
}
|
||||
|
||||
void Spell::EffectPlaySound(SpellEffIndex effIndex)
|
||||
|
||||
@@ -147,7 +147,7 @@ bool CharacterDatabaseCleaner::TalentCheck(uint32 talent_id)
|
||||
|
||||
void CharacterDatabaseCleaner::CleanCharacterTalent()
|
||||
{
|
||||
CharacterDatabase.DirectPExecute("DELETE FROM character_talent WHERE spec > %u", MAX_TALENT_SPECS);
|
||||
CharacterDatabase.DirectPExecute("DELETE FROM character_talent WHERE spec > %u", MAX_TALENT_GROUPS);
|
||||
CheckUnique("spell", "character_talent", &TalentCheck);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,7 +204,7 @@ public:
|
||||
|
||||
// learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
|
||||
player->LearnSpellHighestRank(talentInfo->SpellID);
|
||||
player->AddTalent(talentInfo->SpellID, player->GetActiveSpec(), true);
|
||||
player->AddTalent(talentInfo->SpellID, player->GetActiveTalentGroup());
|
||||
}
|
||||
|
||||
handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
|
||||
|
||||
@@ -204,6 +204,7 @@ public:
|
||||
Player* target;
|
||||
ObjectGuid targetGuid;
|
||||
std::string targetName;
|
||||
/* TODO: 6.x remove/update pet talents
|
||||
if (!handler->extractPlayerTarget((char*)args, &target, &targetGuid, &targetName))
|
||||
{
|
||||
// Try reset talents as Hunter Pet
|
||||
@@ -227,19 +228,22 @@ public:
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if (target)
|
||||
{
|
||||
target->ResetTalents(true);
|
||||
target->SendTalentsInfoData(false);
|
||||
target->SendTalentsInfoData();
|
||||
ChatHandler(target->GetSession()).SendSysMessage(LANG_RESET_TALENTS);
|
||||
if (!handler->GetSession() || handler->GetSession()->GetPlayer() != target)
|
||||
handler->PSendSysMessage(LANG_RESET_TALENTS_ONLINE, handler->GetNameLink(target).c_str());
|
||||
|
||||
/* TODO: 6.x remove/update pet talents
|
||||
Pet* pet = target->GetPet();
|
||||
Pet::resetTalentsForAllPetsOf(target, pet);
|
||||
if (pet)
|
||||
target->SendTalentsInfoData(true);
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
else if (!targetGuid.IsEmpty())
|
||||
|
||||
@@ -168,7 +168,7 @@ class spell_dru_eclipse_energize : public SpellScriptLoader
|
||||
Player* caster = GetCaster()->ToPlayer();
|
||||
|
||||
// No boomy, no deal.
|
||||
if (caster->GetTalentSpec(caster->GetActiveSpec()) != TALENT_SPEC_DRUID_BALANCE)
|
||||
if (caster->GetActiveTalentSpec() != TALENT_SPEC_DRUID_BALANCE)
|
||||
return;
|
||||
|
||||
switch (GetSpellInfo()->Id)
|
||||
|
||||
@@ -74,7 +74,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
"position_x, position_y, position_z, map, orientation, taximask, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, "
|
||||
"resettalents_time, talentTree, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, stable_slots, at_login, zone, online, death_expire_time, taxi_path, instance_mode_mask, "
|
||||
"totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, "
|
||||
"health, power1, power2, power3, power4, power5, instance_id, speccount, activespec, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels "
|
||||
"health, power1, power2, power3, power4, power5, instance_id, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels "
|
||||
"FROM characters WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
PrepareStatement(CHAR_SEL_GROUP_MEMBER, "SELECT guid FROM group_member WHERE memberGuid = ?", CONNECTION_BOTH);
|
||||
@@ -105,7 +105,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, "
|
||||
"item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activespec AND a.guid = ? ORDER BY button", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_ACTIONS, "SELECT a.button, a.action, a.type FROM character_action as a, characters as c WHERE a.guid = c.guid AND a.spec = c.activeTalentGroup AND a.guid = ? ORDER BY button", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_MAILCOUNT, "SELECT COUNT(id) FROM mail WHERE receiver = ? AND (checked & 1) = 0 AND deliver_time <= ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_MAILDATE, "SELECT MIN(deliver_time) FROM mail WHERE receiver = ? AND (checked & 1) = 0", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_MAIL_COUNT, "SELECT COUNT(*) FROM mail WHERE receiver = ?", CONNECTION_SYNCH);
|
||||
@@ -122,8 +122,8 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, item0, item1, item2, item3, item4, item5, item6, item7, item8, "
|
||||
"item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, spec FROM character_talent WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9 FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT spell, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max FROM character_skills WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CHARACTER_BANNED, "SELECT guid FROM character_banned WHERE guid = ? AND active = 1", CONNECTION_ASYNC);
|
||||
@@ -376,13 +376,13 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
"extra_flags, stable_slots, at_login, zone, "
|
||||
"death_expire_time, taxi_path, totalKills, "
|
||||
"todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, health, power1, power2, power3, "
|
||||
"power4, power5, latency, speccount, activespec, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels) VALUES "
|
||||
"power4, power5, latency, talentGroupsCount, activeTalentGroup, exploredZones, equipmentCache, knownTitles, actionBars, grantableLevels) VALUES "
|
||||
"(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHARACTER, "UPDATE characters SET name=?,race=?,class=?,gender=?,level=?,xp=?,money=?,playerBytes=?,playerBytes2=?,playerFlags=?,"
|
||||
"map=?,instance_id=?,instance_mode_mask=?,position_x=?,position_y=?,position_z=?,orientation=?,trans_x=?,trans_y=?,trans_z=?,trans_o=?,transguid=?,taximask=?,cinematic=?,totaltime=?,leveltime=?,rest_bonus=?,"
|
||||
"logout_time=?,is_logout_resting=?,resettalents_cost=?,resettalents_time=?,talentTree=?,extra_flags=?,stable_slots=?,at_login=?,zone=?,death_expire_time=?,taxi_path=?,"
|
||||
"totalKills=?,todayKills=?,yesterdayKills=?,chosenTitle=?,"
|
||||
"watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,latency=?,speccount=?,activespec=?,exploredZones=?,"
|
||||
"watchedFaction=?,drunk=?,health=?,power1=?,power2=?,power3=?,power4=?,power5=?,latency=?,talentGroupsCount=?,activeTalentGroup=?,exploredZones=?,"
|
||||
"equipmentCache=?,knownTitles=?,actionBars=?,grantableLevels=?,online=? WHERE guid=?", CONNECTION_ASYNC);
|
||||
|
||||
PrepareStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG, "UPDATE characters SET at_login = at_login | ? WHERE guid = ?", CONNECTION_ASYNC);
|
||||
@@ -557,9 +557,9 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_BY_OWNER_AND_TYPE, "DELETE FROM petition WHERE ownerguid = ? AND type = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER_AND_TYPE, "DELETE FROM petition_sign WHERE ownerguid = ? AND type = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs (guid, spec, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC, "DELETE FROM character_talent WHERE guid = ? and spell = ? and spec = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, spell, spec) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs (guid, talentGroup, glyph1, glyph2, glyph3, glyph4, glyph5, glyph6, glyph7, glyph8, glyph9) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL_SPEC, "DELETE FROM character_talent WHERE guid = ? and spell = ? and talentGroup = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, spell, talentGroup) VALUES (?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CHAR_ACTION_EXCEPT_SPEC, "DELETE FROM character_action WHERE spec<>? AND guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user