Core/Talents: Update talent system, remove talent points
This commit is contained in:
@@ -33,8 +33,9 @@ struct ArenaScore : public BattlegroundScore
|
||||
void AppendToPacket(WorldPacket& data, ByteBuffer& content) final override
|
||||
{
|
||||
uint32 primaryTree = 0;
|
||||
/* TODO: 6.x update to new talent system (and probably rewrite this packet)
|
||||
if (Player* player = ObjectAccessor::FindPlayer(PlayerGuid))
|
||||
primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec());
|
||||
primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec());*/
|
||||
|
||||
data.WriteBit(0); // Unk 1
|
||||
data.WriteBit(0); // Unk 2
|
||||
|
||||
@@ -1066,12 +1066,11 @@ void Battleground::AddPlayer(Player* player)
|
||||
// score struct must be created in inherited class
|
||||
|
||||
uint32 team = player->GetBGTeam();
|
||||
int32 primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec());
|
||||
|
||||
BattlegroundPlayer bp;
|
||||
bp.OfflineRemoveTime = 0;
|
||||
bp.Team = team;
|
||||
bp.PrimaryTree = primaryTree;
|
||||
bp.ActiveSpec = player->GetActiveSpec();
|
||||
|
||||
// Add to list/maps
|
||||
m_Players[player->GetGUID()] = bp;
|
||||
|
||||
@@ -160,7 +160,7 @@ struct BattlegroundPlayer
|
||||
{
|
||||
time_t OfflineRemoveTime; // for tracking and removing offline players from queue after 5 minutes
|
||||
uint32 Team; // Player's team
|
||||
int32 PrimaryTree; // Player's primary tree
|
||||
int32 ActiveSpec; // Player's active spec
|
||||
};
|
||||
|
||||
struct BattlegroundObjectInfo
|
||||
|
||||
@@ -93,8 +93,9 @@ struct BattlegroundScore
|
||||
virtual void AppendToPacket(WorldPacket& data, ByteBuffer& content)
|
||||
{
|
||||
uint32 primaryTree = 0;
|
||||
/* TODO: 6.x update to new talent system (and probably rewrite this packet)
|
||||
if (Player* player = ObjectAccessor::FindPlayer(PlayerGuid))
|
||||
primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec());
|
||||
primaryTree = player->GetPrimaryTalentTree(player->GetActiveSpec());*/
|
||||
|
||||
data.WriteBit(0); // Unk 1
|
||||
data.WriteBit(0); // Unk 2
|
||||
|
||||
@@ -1013,14 +1013,7 @@ uint32 ChatHandler::extractSpellIdFromLink(char* text)
|
||||
if (!talentEntry)
|
||||
return 0;
|
||||
|
||||
int32 rank = param1_str ? (uint32)atol(param1_str) : 0;
|
||||
if (rank >= MAX_TALENT_RANK)
|
||||
return 0;
|
||||
|
||||
if (rank < 0)
|
||||
rank = 0;
|
||||
|
||||
return talentEntry->RankID[rank];
|
||||
return talentEntry->SpellID;
|
||||
}
|
||||
case SPELL_LINK_ENCHANT:
|
||||
case SPELL_LINK_TRADE:
|
||||
|
||||
@@ -451,10 +451,10 @@ bool TalentChatLink::Initialize(std::istringstream& iss)
|
||||
return false;
|
||||
}
|
||||
// Validate talent's spell
|
||||
_spell = sSpellMgr->GetSpellInfo(talentInfo->RankID[0]);
|
||||
_spell = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
|
||||
if (!_spell)
|
||||
{
|
||||
TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), talentInfo->RankID[0]);
|
||||
TC_LOG_TRACE("chat.system", "ChatHandler::isValidChatMessage('%s'): got invalid spell id %u in |trade command", iss.str().c_str(), talentInfo->SpellID);
|
||||
return false;
|
||||
}
|
||||
// Delimiter
|
||||
|
||||
@@ -191,7 +191,7 @@ struct SpellMiscEntry
|
||||
uint32 CastingTimeIndex; // 15
|
||||
uint32 DurationIndex; // 16
|
||||
uint32 RangeIndex; // 17
|
||||
uint32 Speed; // 18
|
||||
float Speed; // 18
|
||||
uint32 SpellVisualID[2]; // 19-20
|
||||
uint32 SpellIconID; // 21
|
||||
uint32 ActiveIconID; // 22
|
||||
|
||||
@@ -74,6 +74,8 @@ DBCStorage <ChatChannelsEntry> sChatChannelsStore(ChatChannelsEntryfmt);
|
||||
DBCStorage <ChrClassesEntry> sChrClassesStore(ChrClassesEntryfmt);
|
||||
DBCStorage <ChrRacesEntry> sChrRacesStore(ChrRacesEntryfmt);
|
||||
DBCStorage <ChrPowerTypesEntry> sChrPowerTypesStore(ChrClassesXPowerTypesfmt);
|
||||
DBCStorage <ChrSpecializationEntry> sChrSpecializationStore(ChrSpecializationEntryfmt);
|
||||
SpecializationSpellsBySpecStore sSpecializationSpellsBySpecStore;
|
||||
DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore(CinematicSequencesEntryfmt);
|
||||
DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore(CreatureDisplayInfofmt);
|
||||
DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore(CreatureDisplayInfoExtrafmt);
|
||||
@@ -188,6 +190,7 @@ DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt);
|
||||
|
||||
DBCStorage <SoundEntriesEntry> sSoundEntriesStore(SoundEntriesfmt);
|
||||
|
||||
DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore(SpecializationSpellsEntryfmt);
|
||||
DBCStorage <SpellItemEnchantmentEntry> sSpellItemEnchantmentStore(SpellItemEnchantmentfmt);
|
||||
DBCStorage <SpellItemEnchantmentConditionEntry> sSpellItemEnchantmentConditionStore(SpellItemEnchantmentConditionfmt);
|
||||
DBCStorage <SpellEntry> sSpellStore(SpellEntryfmt);
|
||||
@@ -217,14 +220,7 @@ DBCStorage <SpellShapeshiftFormEntry> sSpellShapeshiftFormStore(SpellShapeshiftF
|
||||
DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore(StableSlotPricesfmt);
|
||||
DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore(SummonPropertiesfmt);
|
||||
DBCStorage <TalentEntry> sTalentStore(TalentEntryfmt);
|
||||
TalentSpellPosMap sTalentSpellPosMap;
|
||||
DBCStorage <TalentTabEntry> sTalentTabStore(TalentTabEntryfmt);
|
||||
DBCStorage <TalentTreePrimarySpellsEntry> sTalentTreePrimarySpellsStore(TalentTreePrimarySpellsfmt);
|
||||
typedef std::map<uint32, std::vector<uint32> > TalentTreePrimarySpellsMap;
|
||||
TalentTreePrimarySpellsMap sTalentTreePrimarySpellsMap;
|
||||
|
||||
// store absolute bit position for first rank for talent inspect
|
||||
static uint32 sTalentTabPages[MAX_CLASSES][3];
|
||||
TalentBySpellIDMap sTalentBySpellIDMap;
|
||||
|
||||
DBCStorage <TaxiNodesEntry> sTaxiNodesStore(TaxiNodesEntryfmt);
|
||||
TaxiMask sTaxiNodesMask;
|
||||
@@ -375,6 +371,8 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
PowersByClass[power->ClassID][power->PowerType] = index;
|
||||
}
|
||||
}
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sChrSpecializationStore, dbcPath, "ChrSpecialization.dbc");
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sCinematicSequencesStore, dbcPath, "CinematicSequences.dbc");//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sCreatureDisplayInfoStore, dbcPath, "CreatureDisplayInfo.dbc");//19116
|
||||
@@ -529,10 +527,18 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
if (sSkillLineStore.LookupEntry(entry->SkillID))
|
||||
SkillRaceClassInfoBySkill.emplace(entry->SkillID, entry);
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc");//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc"/*, &CustomSpellEntryfmt, &CustomSpellEntryIndex*/);//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath,"SpellCategories.dbc");//19116
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSkillTiersStore, dbcPath, "SkillTiers.dbc");
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSoundEntriesStore, dbcPath, "SoundEntries.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpecializationSpellsStore, dbcPath, "SpecializationSpells.dbc");
|
||||
for (uint32 i = 1; i < sSpecializationSpellsStore.GetNumRows(); ++i)
|
||||
{
|
||||
SpecializationSpellsEntry const* specSpells = sSpecializationSpellsStore.LookupEntry(i);
|
||||
if (!specSpells)
|
||||
continue;
|
||||
sSpecializationSpellsBySpecStore[specSpells->SpecID].insert(specSpells);
|
||||
}
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellStore, dbcPath, "Spell.dbc"/*, &CustomSpellEntryfmt, &CustomSpellEntryIndex*/);
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoriesStore, dbcPath, "SpellCategories.dbc");//15595
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sSpellCategoryStore, dbcPath, "SpellCategory.dbc");
|
||||
for (uint32 i = 1; i < sSpellStore.GetNumRows(); ++i)
|
||||
{
|
||||
@@ -634,19 +640,17 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
sSpellMgr->SetSpellDifficultyId(uint32(newEntry.SpellID[x]), spellDiff->ID);
|
||||
}*/
|
||||
|
||||
// create talent spells set
|
||||
for (unsigned int i = 0; i < sTalentStore.GetNumRows(); ++i)
|
||||
{
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(i);
|
||||
if (!talentInfo)
|
||||
continue;
|
||||
|
||||
for (int j = 0; j < MAX_TALENT_RANK; j++)
|
||||
if (talentInfo->RankID[j])
|
||||
sTalentSpellPosMap[talentInfo->RankID[j]] = TalentSpellPos(i, j);
|
||||
sTalentBySpellIDMap[talentInfo->SpellID] = talentInfo;
|
||||
}
|
||||
|
||||
LoadDBC(availableDbcLocales, bad_dbc_files, sTalentTabStore, dbcPath, "TalentTab.dbc");//15595
|
||||
// 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
|
||||
{
|
||||
@@ -672,8 +676,8 @@ void LoadDBCStores(const std::string& dataPath)
|
||||
for (uint32 i = 0; i < sTalentTreePrimarySpellsStore.GetNumRows(); ++i)
|
||||
if (TalentTreePrimarySpellsEntry const* talentSpell = sTalentTreePrimarySpellsStore.LookupEntry(i))
|
||||
sTalentTreePrimarySpellsMap[talentSpell->TalentTree].push_back(talentSpell->SpellId);
|
||||
sTalentTreePrimarySpellsStore.Clear();
|
||||
|
||||
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)
|
||||
@@ -851,23 +855,6 @@ char const* GetPetName(uint32 petfamily, uint32 /*dbclang*/)
|
||||
return pet_family->Name_lang ? pet_family->Name_lang : NULL;
|
||||
}
|
||||
|
||||
TalentSpellPos const* GetTalentSpellPos(uint32 spellId)
|
||||
{
|
||||
TalentSpellPosMap::const_iterator itr = sTalentSpellPosMap.find(spellId);
|
||||
if (itr == sTalentSpellPosMap.end())
|
||||
return NULL;
|
||||
|
||||
return &itr->second;
|
||||
}
|
||||
|
||||
uint32 GetTalentSpellCost(uint32 spellId)
|
||||
{
|
||||
if (TalentSpellPos const* pos = GetTalentSpellPos(spellId))
|
||||
return pos->rank+1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32 GetAreaFlagByAreaID(uint32 area_id)
|
||||
{
|
||||
AreaFlagByAreaID::iterator i = sAreaFlagByAreaID.find(area_id);
|
||||
@@ -1097,18 +1084,12 @@ PvPDifficultyEntry const* GetBattlegroundBracketById(uint32 mapid, BattlegroundB
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint32 const* GetTalentTabPages(uint8 cls)
|
||||
TalentEntry const* GetTalentBySpellID(uint32 spellID)
|
||||
{
|
||||
return sTalentTabPages[cls];
|
||||
}
|
||||
|
||||
std::vector<uint32> const* GetTalentTreePrimarySpells(uint32 talentTree)
|
||||
{
|
||||
TalentTreePrimarySpellsMap::const_iterator itr = sTalentTreePrimarySpellsMap.find(talentTree);
|
||||
if (itr == sTalentTreePrimarySpellsMap.end())
|
||||
return NULL;
|
||||
|
||||
return &itr->second;
|
||||
auto itr = sTalentBySpellIDMap.find(spellID);
|
||||
if (itr != sTalentBySpellIDMap.end())
|
||||
return itr->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 GetLiquidFlags(uint32 liquidType)
|
||||
|
||||
@@ -29,8 +29,8 @@ typedef std::list<uint32> SimpleFactionsList;
|
||||
SimpleFactionsList const* GetFactionTeamList(uint32 faction);
|
||||
|
||||
char const* GetPetName(uint32 petfamily, uint32 dbclang);
|
||||
uint32 GetTalentSpellCost(uint32 spellId);
|
||||
TalentSpellPos const* GetTalentSpellPos(uint32 spellId);
|
||||
|
||||
TalentEntry const* GetTalentBySpellID(uint32 spellID);
|
||||
|
||||
int32 GetAreaFlagByAreaID(uint32 area_id); // -1 if not found
|
||||
AreaTableEntry const* GetAreaEntryByAreaID(uint32 area_id);
|
||||
@@ -70,9 +70,6 @@ typedef std::map<uint32/*pair32(map, diff)*/, MapDifficulty> MapDifficultyMap;
|
||||
MapDifficulty const* GetMapDifficultyData(uint32 mapId, Difficulty difficulty);
|
||||
MapDifficulty const* GetDownscaledMapDifficultyData(uint32 mapId, Difficulty &difficulty);
|
||||
|
||||
uint32 const* /*[MAX_TALENT_TABS]*/ GetTalentTabPages(uint8 cls);
|
||||
std::vector<uint32> const* GetTalentTreePrimarySpells(uint32 talentTree);
|
||||
|
||||
uint32 GetLiquidFlags(uint32 liquidType);
|
||||
|
||||
PvPDifficultyEntry const* GetBattlegroundBracketByLevel(uint32 mapid, uint32 level);
|
||||
@@ -91,6 +88,10 @@ typedef std::unordered_multimap<uint32, SkillRaceClassInfoEntry const*> SkillRac
|
||||
typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterator> SkillRaceClassInfoBounds;
|
||||
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
|
||||
|
||||
typedef std::set<SpecializationSpellsEntry const*> SpecializationSpellsBySpecEntry;
|
||||
typedef std::unordered_map<uint32, SpecializationSpellsBySpecEntry> SpecializationSpellsBySpecStore;
|
||||
typedef std::unordered_map<uint32, TalentEntry const*> TalentBySpellIDMap;
|
||||
|
||||
extern DBCStorage <AchievementEntry> sAchievementStore;
|
||||
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
|
||||
extern DBCStorage <AreaTableEntry> sAreaStore;// recommend access using functions
|
||||
@@ -108,6 +109,7 @@ extern DBCStorage <CharTitlesEntry> sCharTitlesStore;
|
||||
extern DBCStorage <ChrClassesEntry> sChrClassesStore;
|
||||
extern DBCStorage <ChrRacesEntry> sChrRacesStore;
|
||||
extern DBCStorage <ChrPowerTypesEntry> sChrPowerTypesStore;
|
||||
extern DBCStorage <ChrSpecializationEntry> sChrSpecializationStore;
|
||||
extern DBCStorage <CinematicSequencesEntry> sCinematicSequencesStore;
|
||||
extern DBCStorage <CreatureDisplayInfoEntry> sCreatureDisplayInfoStore;
|
||||
extern DBCStorage <CreatureDisplayInfoExtraEntry> sCreatureDisplayInfoExtraStore;
|
||||
@@ -197,6 +199,8 @@ extern DBCStorage <SkillLineEntry> sSkillLineStore;
|
||||
extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
|
||||
extern DBCStorage <SkillTiersEntry> sSkillTiersStore;
|
||||
extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
|
||||
extern DBCStorage <SpecializationSpellsEntry> sSpecializationSpellsStore;
|
||||
extern SpecializationSpellsBySpecStore sSpecializationSpellsBySpecStore;
|
||||
extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
|
||||
extern DBCStorage <SpellCategoryEntry> sSpellCategoryStore;
|
||||
extern DBCStorage <SpellDurationEntry> sSpellDurationStore;
|
||||
@@ -224,7 +228,7 @@ extern DBCStorage <SpellTotemsEntry> sSpellTotemsStore;
|
||||
//extern DBCStorage <StableSlotPricesEntry> sStableSlotPricesStore;
|
||||
extern DBCStorage <SummonPropertiesEntry> sSummonPropertiesStore;
|
||||
extern DBCStorage <TalentEntry> sTalentStore;
|
||||
extern DBCStorage <TalentTabEntry> sTalentTabStore;
|
||||
extern TalentBySpellIDMap sTalentBySpellIDMap;
|
||||
extern DBCStorage <TaxiNodesEntry> sTaxiNodesStore;
|
||||
extern DBCStorage <TaxiPathEntry> sTaxiPathStore;
|
||||
extern TaxiMask sTaxiNodesMask;
|
||||
|
||||
@@ -776,6 +776,26 @@ struct ChrPowerTypesEntry
|
||||
uint32 PowerType; // 2
|
||||
};
|
||||
|
||||
#define MAX_MASTERY_SPELLS 2
|
||||
|
||||
struct ChrSpecializationEntry
|
||||
{
|
||||
uint32 ID; // 0 Specialization ID
|
||||
//char* BackgroundFile; // 1
|
||||
uint32 ClassID; // 2
|
||||
uint32 MasterySpellID[MAX_MASTERY_SPELLS]; // 3
|
||||
uint32 OrderIndex; // 4
|
||||
uint32 PetTalentType; // 5
|
||||
uint32 Role; // 6 (0 - Tank, 1 - Healer, 2 - DPS)
|
||||
uint32 SpellIconID; // 7
|
||||
uint32 RaidBuffs; // 8
|
||||
uint32 Flags; // 9
|
||||
//char* Name_lang; // 10
|
||||
//char* Name2_lang; // 11 Same as name_lang?
|
||||
//char* Description_lang; // 12
|
||||
uint32 PrimaryStatOrder[2]; // 13-14
|
||||
};
|
||||
|
||||
struct CinematicSequencesEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
@@ -1787,6 +1807,16 @@ struct SoundEntriesEntry
|
||||
//uint32 BusOverwriteID; // 55
|
||||
};
|
||||
|
||||
// SpecializationSpells.dbc
|
||||
struct SpecializationSpellsEntry
|
||||
{
|
||||
uint32 ID; // 0
|
||||
uint32 SpecID; // 1
|
||||
uint32 SpellID; // 2
|
||||
uint32 OverridesSpellID; // 3
|
||||
//char* Description_lang; // 4
|
||||
};
|
||||
|
||||
// SpellEffect.dbc
|
||||
struct SpellEffectEntry
|
||||
{
|
||||
@@ -2091,14 +2121,6 @@ struct SpellItemEnchantmentConditionEntry
|
||||
uint32 RTOperand[5]; // 10-14
|
||||
uint8 Logic[5]; // 15-16
|
||||
//uint8 Padding[3]; // 16
|
||||
|
||||
/*uint32 ID; // 0 m_ID
|
||||
uint8 Color[5]; // 1-5 m_lt_operandType[5]
|
||||
//uint32 LT_Operand[5]; // 6-10 m_lt_operand[5]
|
||||
uint8 Comparator[5]; // 11-15 m_operator[5]
|
||||
uint8 CompareColor[5]; // 15-20 m_rt_operandType[5]
|
||||
uint32 Value[5]; // 21-25 m_rt_operand[5]
|
||||
//uint8 Logic[5] // 25-30 m_logic[5]*/
|
||||
};
|
||||
|
||||
struct StableSlotPricesEntry
|
||||
@@ -2109,56 +2131,28 @@ struct StableSlotPricesEntry
|
||||
|
||||
struct SummonPropertiesEntry
|
||||
{
|
||||
uint32 Id; // 0
|
||||
uint32 Category; // 1, 0 - can't be controlled?, 1 - something guardian?, 2 - pet?, 3 - something controllable?, 4 - taxi/mount?
|
||||
uint32 Faction; // 2, 14 rows > 0
|
||||
uint32 Type; // 3, see enum
|
||||
int32 Slot; // 4, 0-6
|
||||
uint32 Flags; // 5
|
||||
uint32 ID; // 0
|
||||
uint32 Category; // 1, 0 - can't be controlled?, 1 - something guardian?, 2 - pet?, 3 - something controllable?, 4 - taxi/mount?
|
||||
uint32 Faction; // 2, 14 rows > 0
|
||||
uint32 Type; // 3, see enum
|
||||
int32 Slot; // 4, 0-6
|
||||
uint32 Flags; // 5
|
||||
};
|
||||
|
||||
#define MAX_TALENT_RANK 5
|
||||
#define MAX_PET_TALENT_RANK 3 // use in calculations, expected <= MAX_TALENT_RANK
|
||||
#define MAX_TALENT_TABS 3
|
||||
|
||||
struct TalentEntry
|
||||
{
|
||||
uint32 TalentID; // 0
|
||||
uint32 TalentTab; // 1 index in TalentTab.dbc (TalentTabEntry)
|
||||
uint32 Row; // 2
|
||||
uint32 Col; // 3
|
||||
uint32 RankID[MAX_TALENT_RANK]; // 4-8
|
||||
uint32 DependsOn; // 9 m_prereqTalent (Talent.dbc)
|
||||
// 10-11 part of prev field
|
||||
uint32 DependsOnRank; // 12 m_prereqRank
|
||||
// 13-14 part of prev field
|
||||
//uint32 needAddInSpellBook; // 15 m_flags also need disable higest ranks on reset talent tree
|
||||
//uint32 unk2; // 16 m_requiredSpellID
|
||||
//uint64 allowForPet; // 17 m_categoryMask its a 64 bit mask for pet 1<<m_categoryEnumID in CreatureFamily.dbc
|
||||
};
|
||||
|
||||
#define MAX_MASTERY_SPELLS 2
|
||||
|
||||
struct TalentTabEntry
|
||||
{
|
||||
uint32 TalentTabID; // 0
|
||||
//char* name; // 1 m_name_lang
|
||||
//unit32 spellicon; // 2 m_spellIconID
|
||||
uint32 ClassMask; // 3 m_classMask
|
||||
uint32 petTalentMask; // 4 m_petTalentMask
|
||||
uint32 tabpage; // 5 m_orderIndex
|
||||
//char* internalname; // 6 m_backgroundFile
|
||||
//char* description; // 7
|
||||
//uint32 rolesMask; // 8 4.0.0
|
||||
uint32 MasterySpellId[MAX_MASTERY_SPELLS]; // 9-10 passive mastery bonus spells?
|
||||
};
|
||||
|
||||
struct TalentTreePrimarySpellsEntry
|
||||
{
|
||||
//uint32 Id; // 0 index
|
||||
uint32 TalentTree; // 1 entry from TalentTab.dbc
|
||||
uint32 SpellId; // 2 spell id to learn
|
||||
//uint32 Flags; // 3 some kind of flags
|
||||
uint32 ID; // 0
|
||||
uint32 SpecID; // 1 0 - any specialization
|
||||
uint32 TierID; // 2 0-6
|
||||
uint32 ColumnIndex; // 3 0-2
|
||||
uint32 SpellID; // 4
|
||||
uint32 Flags; // 5 All 0
|
||||
uint32 CategoryMask[2]; // 6 All 0
|
||||
uint32 ClassID; // 7
|
||||
uint32 OverridesSpellID; // 8 spellid that is replaced by talent
|
||||
//char* Description_lang
|
||||
};
|
||||
|
||||
struct TaxiNodesEntry
|
||||
@@ -2471,16 +2465,7 @@ struct MapDifficulty
|
||||
bool hasErrorMessage;
|
||||
};
|
||||
|
||||
struct TalentSpellPos
|
||||
{
|
||||
TalentSpellPos() : talent_id(0), rank(0) { }
|
||||
TalentSpellPos(uint16 _talent_id, uint8 _rank) : talent_id(_talent_id), rank(_rank) { }
|
||||
|
||||
uint16 talent_id;
|
||||
uint8 rank;
|
||||
};
|
||||
|
||||
typedef std::map<uint32, TalentSpellPos> TalentSpellPosMap;
|
||||
typedef std::map<uint32, uint32> TalentSpellPosMap;
|
||||
|
||||
struct TaxiPathBySourceAndDestination
|
||||
{
|
||||
|
||||
@@ -41,6 +41,7 @@ char const ChatChannelsEntryfmt[] = "nixsx";
|
||||
char const ChrClassesEntryfmt[] = "nixsxxxixiiiixxxxx";
|
||||
char const ChrRacesEntryfmt[] = "niixiixxxxxxiisxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
char const ChrClassesXPowerTypesfmt[] = "nii";
|
||||
char const ChrSpecializationEntryfmt[] = "nxiiiiiiiiixxxii";
|
||||
char const CinematicSequencesEntryfmt[] = "nxxxxxxxxx";
|
||||
char const CreatureDisplayInfofmt[] = "nixifxxxxxxxxxxxxxxxx";
|
||||
char const CreatureDisplayInfoExtrafmt[] = "dixxxxxxxxxxxxxxxxxxx";
|
||||
@@ -125,6 +126,7 @@ char const SkillLineAbilityfmt[] = "niiiiiiiiiiii";
|
||||
char const SkillRaceClassInfofmt[] = "diiiixxi";
|
||||
char const SkillTiersfmt[] = "niiiiiiiiiiiiiiii";
|
||||
char const SoundEntriesfmt[] = "nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
|
||||
char const SpecializationSpellsEntryfmt[] = "niiix";
|
||||
char const SpellCastTimefmt[] = "nixx";
|
||||
char const SpellCategoriesEntryfmt[] = "diiiiiiiix";
|
||||
char const SpellCategoryfmt[] = "nixxxx";
|
||||
|
||||
@@ -1405,25 +1405,7 @@ bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpel
|
||||
newspell.active = active;
|
||||
|
||||
// talent: unlearn all other talent ranks (high and low)
|
||||
if (TalentSpellPos const* talentPos = GetTalentSpellPos(spellId))
|
||||
{
|
||||
if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_TALENT_RANK; ++i)
|
||||
{
|
||||
// skip learning spell and no rank spell case
|
||||
uint32 rankSpellId = talentInfo->RankID[i];
|
||||
if (!rankSpellId || rankSpellId == spellId)
|
||||
continue;
|
||||
|
||||
// skip unknown ranks
|
||||
if (!HasSpell(rankSpellId))
|
||||
continue;
|
||||
removeSpell(rankSpellId, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (spellInfo->IsRanked())
|
||||
if (spellInfo->IsRanked())
|
||||
{
|
||||
for (PetSpellMap::const_iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
|
||||
{
|
||||
@@ -1465,15 +1447,6 @@ bool Pet::addSpell(uint32 spellId, ActiveStates active /*= ACT_DECIDE*/, PetSpel
|
||||
if (newspell.active == ACT_ENABLED)
|
||||
ToggleAutocast(spellInfo, true);
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(spellId);
|
||||
if (talentCost)
|
||||
{
|
||||
int32 free_points = GetMaxTalentPointsForLevel(getLevel());
|
||||
m_usedTalentCount += talentCost;
|
||||
// update free talent points
|
||||
free_points-=m_usedTalentCount;
|
||||
SetFreeTalentPoints(free_points > 0 ? free_points : 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1563,18 +1536,6 @@ bool Pet::removeSpell(uint32 spell_id, bool learn_prev, bool clear_ab)
|
||||
|
||||
RemoveAurasDueToSpell(spell_id);
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(spell_id);
|
||||
if (talentCost > 0)
|
||||
{
|
||||
if (m_usedTalentCount > talentCost)
|
||||
m_usedTalentCount -= talentCost;
|
||||
else
|
||||
m_usedTalentCount = 0;
|
||||
// update free talent points
|
||||
int32 free_points = GetMaxTalentPointsForLevel(getLevel()) - m_usedTalentCount;
|
||||
SetFreeTalentPoints(free_points > 0 ? free_points : 0);
|
||||
}
|
||||
|
||||
if (learn_prev)
|
||||
{
|
||||
if (uint32 prev_id = sSpellMgr->GetPrevSpellInChain (spell_id))
|
||||
@@ -1622,6 +1583,7 @@ void Pet::InitPetCreateSpells()
|
||||
|
||||
bool Pet::resetTalents()
|
||||
{
|
||||
/* TODO: 6.x remove pet talents
|
||||
Player* player = GetOwner();
|
||||
|
||||
// not need after this call
|
||||
@@ -1689,12 +1651,13 @@ bool Pet::resetTalents()
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
|
||||
if (!m_loading)
|
||||
player->PetSpellInitialize();
|
||||
player->PetSpellInitialize();*/
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= NULL*/)
|
||||
{
|
||||
/* TODO: 6.x remove pet talents
|
||||
// not need after this call
|
||||
if (owner->HasAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS))
|
||||
owner->RemoveAtLoginFlag(AT_LOGIN_RESET_PET_TALENTS, true);
|
||||
@@ -1767,7 +1730,7 @@ void Pet::resetTalentsForAllPetsOf(Player* owner, Pet* onlinePet /*= NULL*/)
|
||||
|
||||
ss << ')';
|
||||
|
||||
CharacterDatabase.Execute(ss.str().c_str());
|
||||
CharacterDatabase.Execute(ss.str().c_str());*/
|
||||
}
|
||||
|
||||
void Pet::InitTalentForLevel()
|
||||
|
||||
@@ -2984,40 +2984,6 @@ void Player::GiveLevel(uint8 level)
|
||||
|
||||
void Player::InitTalentForLevel()
|
||||
{
|
||||
uint8 level = getLevel();
|
||||
// talents base at level diff (talents = level - 9 but some can be used already)
|
||||
if (level < 10)
|
||||
{
|
||||
// Remove all talent points
|
||||
if (GetUsedTalentCount() > 0) // Free any used talents
|
||||
{
|
||||
ResetTalents(true);
|
||||
SetFreeTalentPoints(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (level < sWorld->getIntConfig(CONFIG_MIN_DUALSPEC_LEVEL) || GetSpecsCount() == 0)
|
||||
{
|
||||
SetSpecsCount(1);
|
||||
SetActiveSpec(0);
|
||||
}
|
||||
|
||||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
// if used more that have then reset
|
||||
if (GetUsedTalentCount() > talentPointsForLevel)
|
||||
{
|
||||
if (!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED))
|
||||
ResetTalents(true);
|
||||
else
|
||||
SetFreeTalentPoints(0);
|
||||
}
|
||||
// else update amount of free points
|
||||
else
|
||||
SetFreeTalentPoints(talentPointsForLevel - GetUsedTalentCount());
|
||||
}
|
||||
|
||||
if (!GetSession()->PlayerLoading())
|
||||
SendTalentsInfoData(false); // update at client
|
||||
}
|
||||
@@ -3344,6 +3310,7 @@ void DeleteSpellFromAllPlayers(uint32 spellId)
|
||||
|
||||
bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning)
|
||||
{
|
||||
/* TODO: 6.x update talent system
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
if (!spellInfo)
|
||||
{
|
||||
@@ -3404,6 +3371,7 @@ bool Player::AddTalent(uint32 spellId, uint8 spec, bool learning)
|
||||
(*GetTalentMap(spec))[spellId] = newtalent;
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3552,24 +3520,8 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
|
||||
|
||||
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(spellId))
|
||||
{
|
||||
if (TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentPos->talent_id))
|
||||
{
|
||||
for (uint8 rank = 0; rank < MAX_TALENT_RANK; ++rank)
|
||||
{
|
||||
// skip learning spell and no rank spell case
|
||||
uint32 rankSpellId = talentInfo->RankID[rank];
|
||||
if (!rankSpellId || rankSpellId == spellId)
|
||||
continue;
|
||||
|
||||
RemoveSpell(rankSpellId, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
// non talent spell: learn low ranks (recursive call)
|
||||
else if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId))
|
||||
if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId))
|
||||
{
|
||||
if (!IsInWorld() || disabled) // at spells loading, no output, but allow save
|
||||
AddSpell(prev_spell, active, true, true, disabled, false, fromSkill);
|
||||
@@ -3632,11 +3584,9 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(spellId);
|
||||
|
||||
// cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
|
||||
// note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
|
||||
if (!loading && talentCost > 0 && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
|
||||
if (!loading && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
|
||||
{
|
||||
// ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
|
||||
CastSpell(this, spellId, true);
|
||||
@@ -3653,9 +3603,6 @@ bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent
|
||||
return false;
|
||||
}
|
||||
|
||||
// update used talent points count
|
||||
SetUsedTalentCount(GetUsedTalentCount() + talentCost);
|
||||
|
||||
// update free primary prof.points (if any, can be none in case GM .learn prof. learning)
|
||||
if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
|
||||
{
|
||||
@@ -3773,8 +3720,8 @@ bool Player::IsNeedCastPassiveSpellAtLearn(SpellInfo const* spellInfo) const
|
||||
|
||||
bool Player::IsCurrentSpecMasterySpell(SpellInfo const* spellInfo) const
|
||||
{
|
||||
if (TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec())))
|
||||
return spellInfo->Id == talentTab->MasterySpellId[0] || spellInfo->Id == talentTab->MasterySpellId[1];
|
||||
if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec())))
|
||||
return spellInfo->Id == chrSpec->MasterySpellID[0] || spellInfo->Id == chrSpec->MasterySpellID[1];
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -3829,7 +3776,7 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
|
||||
// unlearn non talent higher ranks (recursive)
|
||||
if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
|
||||
{
|
||||
if (HasSpell(nextSpell) && !GetTalentSpellPos(nextSpell))
|
||||
if (HasSpell(nextSpell) && !GetTalentBySpellID(nextSpell))
|
||||
RemoveSpell(nextSpell, disabled, false);
|
||||
}
|
||||
//unlearn spells dependent from recently removed spells
|
||||
@@ -3842,8 +3789,6 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
|
||||
if (itr == m_spells.end())
|
||||
return; // already unleared
|
||||
|
||||
bool giveTalentPoints = disabled || !itr->second->disabled;
|
||||
|
||||
bool cur_active = itr->second->active;
|
||||
bool cur_dependent = itr->second->dependent;
|
||||
|
||||
@@ -3871,16 +3816,6 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
|
||||
if (PetAura const* petSpell = sSpellMgr->GetPetAura(spell_id, i))
|
||||
RemovePetAura(petSpell);
|
||||
|
||||
// free talent points
|
||||
uint32 talentCosts = GetTalentSpellCost(spell_id);
|
||||
if (talentCosts > 0 && giveTalentPoints)
|
||||
{
|
||||
if (talentCosts < GetUsedTalentCount())
|
||||
SetUsedTalentCount(GetUsedTalentCount() - talentCosts);
|
||||
else
|
||||
SetUsedTalentCount(0);
|
||||
}
|
||||
|
||||
// update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning)
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id);
|
||||
if (spellInfo && spellInfo->IsPrimaryProfessionFirstRank())
|
||||
@@ -3938,16 +3873,9 @@ void Player::RemoveSpell(uint32 spell_id, bool disabled, bool learn_low_rank)
|
||||
|
||||
if (uint32 prev_id = sSpellMgr->GetPrevSpellInChain(spell_id))
|
||||
{
|
||||
// if talent then lesser rank also talent and need learn
|
||||
if (talentCosts)
|
||||
{
|
||||
// I cannot see why mangos has these lines.
|
||||
//if (learn_low_rank)
|
||||
// learnSpell(prev_id, false);
|
||||
}
|
||||
// if ranked non-stackable spell: need activate lesser rank and update dendence state
|
||||
/// No need to check for spellInfo != NULL here because if cur_active is true, then that means that the spell was already in m_spells, and only valid spells can be pushed there.
|
||||
else if (cur_active && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked())
|
||||
if (cur_active && !spellInfo->IsStackableWithRanks() && spellInfo->IsRanked())
|
||||
{
|
||||
// need manually update dependence state (learn spell ignore like attempts)
|
||||
PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
|
||||
@@ -4191,14 +4119,6 @@ bool Player::ResetTalents(bool no_cost)
|
||||
if (HasAtLoginFlag(AT_LOGIN_RESET_TALENTS))
|
||||
RemoveAtLoginFlag(AT_LOGIN_RESET_TALENTS, true);
|
||||
|
||||
uint32 talentPointsForLevel = CalculateTalentsPoints();
|
||||
|
||||
if (!GetUsedTalentCount())
|
||||
{
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 cost = 0;
|
||||
|
||||
if (!no_cost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST))
|
||||
@@ -4221,54 +4141,52 @@ bool Player::ResetTalents(bool no_cost)
|
||||
if (!talentInfo)
|
||||
continue;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||
|
||||
if (!talentTabInfo)
|
||||
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 (getClass() != talentInfo->ClassID)
|
||||
continue;
|
||||
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
|
||||
|
||||
if (!_spellEntry)
|
||||
continue;
|
||||
|
||||
RemoveSpell(talentInfo->SpellID, true);
|
||||
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
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);
|
||||
|
||||
// if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
|
||||
PlayerTalentMap::iterator plrTalent = GetTalentMap(GetActiveSpec())->find(talentInfo->SpellID);
|
||||
if (plrTalent != GetTalentMap(GetActiveSpec())->end())
|
||||
plrTalent->second->state = PLAYERSPELL_REMOVED;
|
||||
}
|
||||
|
||||
// Remove all specialization specific spells and give default ones which were overriden
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(GetActiveSpec()));
|
||||
if (specSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
|
||||
{
|
||||
// skip non-existant talent ranks
|
||||
if (talentInfo->RankID[rank] == 0)
|
||||
continue;
|
||||
const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->RankID[rank]);
|
||||
if (!_spellEntry)
|
||||
continue;
|
||||
RemoveSpell(talentInfo->RankID[rank], true);
|
||||
// search for spells that the talent teaches and unlearn them
|
||||
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);
|
||||
// if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
|
||||
PlayerTalentMap::iterator plrTalent = GetTalentMap(GetActiveSpec())->find(talentInfo->RankID[rank]);
|
||||
if (plrTalent != GetTalentMap(GetActiveSpec())->end())
|
||||
plrTalent->second->state = PLAYERSPELL_REMOVED;
|
||||
SpecializationSpellsEntry const* specSpell = *it;
|
||||
if (HasSpell(specSpell->SpellID)) {
|
||||
RemoveSpell(specSpell->SpellID, true);
|
||||
if (specSpell->OverridesSpellID)
|
||||
LearnSpell(specSpell->OverridesSpellID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove spec specific spells
|
||||
uint32 const* talentTabs = GetTalentTabPages(getClass());
|
||||
for (uint32 i = 0; i < MAX_TALENT_TABS; ++i)
|
||||
{
|
||||
if (std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentTabs[i]))
|
||||
for (size_t j = 0; j < specSpells->size(); ++j)
|
||||
RemoveSpell(specSpells->at(j), true);
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabs[i]);
|
||||
for (uint32 j = 0; j < MAX_MASTERY_SPELLS; ++j)
|
||||
if (uint32 mastery = talentTabInfo->MasterySpellId[j])
|
||||
RemoveAurasDueToSpell(mastery);
|
||||
}
|
||||
|
||||
|
||||
SetPrimaryTalentTree(GetActiveSpec(), 0);
|
||||
SetFreeTalentPoints(talentPointsForLevel);
|
||||
// Unlearn masteries
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec()));
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (uint32 mastery = chrSpec->MasterySpellID[i])
|
||||
RemoveAurasDueToSpell(mastery);
|
||||
|
||||
SetTalentSpec(GetActiveSpec(), 0);
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
_SaveTalents(trans);
|
||||
@@ -15229,12 +15147,6 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
|
||||
SetTitle(titleEntry);
|
||||
}
|
||||
|
||||
if (uint32 talents = quest->GetBonusTalents())
|
||||
{
|
||||
AddQuestRewardedTalentCount(talents);
|
||||
InitTalentForLevel();
|
||||
}
|
||||
|
||||
// Send reward mail
|
||||
if (uint32 mail_template_id = quest->GetRewMailTemplateId())
|
||||
{
|
||||
@@ -17534,15 +17446,17 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
|
||||
}
|
||||
|
||||
// Only load selected specializations, learning mastery spells requires this
|
||||
Tokenizer talentTrees(fields[26].GetString(), ' ', MAX_TALENT_SPECS);
|
||||
Tokenizer talentSpecs(fields[26].GetString(), ' ', MAX_TALENT_SPECS);
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
{
|
||||
if (i >= talentTrees.size())
|
||||
if (i >= talentSpecs.size())
|
||||
break;
|
||||
|
||||
uint32 talentTree = atol(talentTrees[i]);
|
||||
if (sTalentTabStore.LookupEntry(talentTree))
|
||||
SetPrimaryTalentTree(i, talentTree);
|
||||
uint32 talentSpec = atol(talentSpecs[i]);
|
||||
if (sChrSpecializationStore.LookupEntry(talentSpec))
|
||||
SetTalentSpec(i, talentSpec);
|
||||
else
|
||||
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS);
|
||||
}
|
||||
|
||||
_LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
|
||||
@@ -17632,17 +17546,6 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
|
||||
|
||||
SetPower(POWER_ECLIPSE, 0);
|
||||
|
||||
// Verify loaded talent specializations
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
{
|
||||
if (i >= talentTrees.size())
|
||||
break;
|
||||
|
||||
uint32 talentTree = atol(talentTrees[i]);
|
||||
if (talentTree != 0 && !sTalentTabStore.LookupEntry(talentTree) && i == GetActiveSpec())
|
||||
SetAtLoginFlag(AT_LOGIN_RESET_TALENTS); // invalid tree, reset talents
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("entities.player.loading", "The value of player %s after load item and aura is: ", m_name.c_str());
|
||||
outDebugValues();
|
||||
|
||||
@@ -18494,9 +18397,6 @@ void Player::_LoadQuestStatusRewarded(PreparedQueryResult result)
|
||||
if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetCharTitleId()))
|
||||
SetTitle(titleEntry);
|
||||
}
|
||||
|
||||
if (uint32 talents = quest->GetBonusTalents())
|
||||
AddQuestRewardedTalentCount(talents);
|
||||
}
|
||||
|
||||
m_RewardedQuests.insert(quest_id);
|
||||
@@ -19209,7 +19109,7 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
|
||||
ss.str("");
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
ss << GetPrimaryTalentTree(i) << " ";
|
||||
ss << GetTalentSpec(i) << " ";
|
||||
stmt->setString(index++, ss.str());
|
||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
stmt->setUInt8(index++, m_stableSlots);
|
||||
@@ -19338,7 +19238,7 @@ void Player::SaveToDB(bool create /*=false*/)
|
||||
|
||||
ss.str("");
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
ss << GetPrimaryTalentTree(i) << " ";
|
||||
ss << GetTalentSpec(i) << " ";
|
||||
stmt->setString(index++, ss.str());
|
||||
stmt->setUInt16(index++, (uint16)m_ExtraFlags);
|
||||
stmt->setUInt8(index++, m_stableSlots);
|
||||
@@ -23404,11 +23304,6 @@ void Player::ResetSpells(bool myClassOnly)
|
||||
if (spellInfo->SpellFamilyName != family)
|
||||
continue;
|
||||
|
||||
// skip spells with first rank learned as talent (and all talents then also)
|
||||
uint32 firstRank = spellInfo->GetFirstRankSpell()->Id;
|
||||
if (GetTalentSpellCost(firstRank) > 0)
|
||||
continue;
|
||||
|
||||
// skip broken spells
|
||||
if (!SpellMgr::IsSpellValid(spellInfo, this, false))
|
||||
continue;
|
||||
@@ -25314,38 +25209,6 @@ void Player::StoreLootItem(uint8 lootSlot, Loot* loot)
|
||||
SendEquipError(msg, NULL, NULL, item->itemid);
|
||||
}
|
||||
|
||||
// 6.x - removeme
|
||||
uint32 Player::CalculateTalentsPoints() const
|
||||
{
|
||||
// this dbc file has entries only up to level 100
|
||||
/*NumTalentsAtLevelEntry const* count = sNumTalentsAtLevelStore.LookupEntry(std::min<uint32>(getLevel(), 100));
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
float baseForLevel = count->Talents;
|
||||
|
||||
if (getClass() != CLASS_DEATH_KNIGHT || GetMapId() != 609)
|
||||
return uint32(baseForLevel * sWorld->getRate(RATE_TALENT));
|
||||
|
||||
// Death Knight starting level
|
||||
// hardcoded here - number of quest awarded talents is equal to number of talents any other class would have at level 55
|
||||
if (getLevel() < 55)
|
||||
return 0;
|
||||
|
||||
NumTalentsAtLevelEntry const* dkBase = sNumTalentsAtLevelStore.LookupEntry(55);
|
||||
if (!dkBase)
|
||||
return 0;
|
||||
|
||||
float talentPointsForLevel = count->Talents - dkBase->Talents;
|
||||
talentPointsForLevel += float(GetQuestRewardedTalentCount());
|
||||
|
||||
if (talentPointsForLevel > baseForLevel)
|
||||
talentPointsForLevel = baseForLevel;
|
||||
|
||||
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Player::IsKnowHowFlyIn(uint32 mapid, uint32 zone) const
|
||||
{
|
||||
// continent checked in SpellInfo::CheckLocation at cast and area update
|
||||
@@ -25651,108 +25514,26 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
|
||||
m_achievementMgr->CompletedAchievement(entry, this);
|
||||
}
|
||||
|
||||
bool Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
bool Player::LearnTalent(uint32 talentId)
|
||||
{
|
||||
uint32 CurTalentPoints = GetFreeTalentPoints();
|
||||
|
||||
if (CurTalentPoints == 0)
|
||||
return false;
|
||||
|
||||
if (talentRank >= MAX_TALENT_RANK)
|
||||
return false;
|
||||
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
|
||||
if (!talentInfo)
|
||||
return false;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||
|
||||
if (!talentTabInfo)
|
||||
return false;
|
||||
|
||||
// prevent learn talent for different class (cheating)
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
if (getClass() != talentInfo->ClassID)
|
||||
return false;
|
||||
|
||||
// find current max talent rank (0~5)
|
||||
uint8 curtalent_maxrank = 0; // 0 = not learned any rank
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
{
|
||||
if (talentInfo->RankID[rank] && HasSpell(talentInfo->RankID[rank]))
|
||||
{
|
||||
curtalent_maxrank = (rank + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we already have same or higher talent rank learned
|
||||
if (curtalent_maxrank >= (talentRank + 1))
|
||||
return false;
|
||||
|
||||
// check if we have enough talent points
|
||||
if (CurTalentPoints < (talentRank - curtalent_maxrank + 1))
|
||||
return false;
|
||||
|
||||
// Check if it requires another talent
|
||||
if (talentInfo->DependsOn > 0)
|
||||
{
|
||||
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||
{
|
||||
bool hasEnoughRank = false;
|
||||
for (uint8 rank = talentInfo->DependsOnRank; rank < MAX_TALENT_RANK; rank++)
|
||||
{
|
||||
if (depTalentInfo->RankID[rank] != 0)
|
||||
if (HasSpell(depTalentInfo->RankID[rank]))
|
||||
hasEnoughRank = true;
|
||||
}
|
||||
if (!hasEnoughRank)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find out how many points we have in this field
|
||||
uint32 spentPoints = 0;
|
||||
uint32 primaryTreeTalents = 0;
|
||||
uint32 tTab = talentInfo->TalentTab;
|
||||
bool isMainTree = GetPrimaryTalentTree(GetActiveSpec()) == tTab || !GetPrimaryTalentTree(GetActiveSpec());
|
||||
|
||||
if (talentInfo->Row > 0 || !isMainTree)
|
||||
{
|
||||
for (uint32 i = 0; i < sTalentStore.GetNumRows(); i++) // Loop through all talents.
|
||||
{
|
||||
if (TalentEntry const* tmpTalent = sTalentStore.LookupEntry(i)) // Someday, someone needs to revamp the way talents are tracked
|
||||
{
|
||||
for (uint8 rank = 0; rank < MAX_TALENT_RANK; rank++)
|
||||
{
|
||||
if (tmpTalent->RankID[rank] != 0)
|
||||
{
|
||||
if (HasSpell(tmpTalent->RankID[rank]))
|
||||
{
|
||||
if (tmpTalent->TalentTab == tTab)
|
||||
spentPoints += (rank + 1);
|
||||
if (tmpTalent->TalentTab == GetPrimaryTalentTree(GetActiveSpec()))
|
||||
primaryTreeTalents += (rank + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not have required min points spent in talent tree
|
||||
if (spentPoints < (talentInfo->Row * MAX_TALENT_RANK))
|
||||
return false;
|
||||
|
||||
// player has not spent 31 talents in main tree before attempting to learn other tree's talents
|
||||
if (!isMainTree && primaryTreeTalents < REQ_PRIMARY_TREE_TALENTS)
|
||||
// Check player level.
|
||||
if (getLevel() < (15*talentInfo->TierID + 15))
|
||||
return false;
|
||||
|
||||
// spell not set in talent.dbc
|
||||
uint32 spellid = talentInfo->RankID[talentRank];
|
||||
uint32 spellid = talentInfo->SpellID;
|
||||
if (spellid == 0)
|
||||
{
|
||||
TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank);
|
||||
TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u spell id = 0", talentId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -25764,162 +25545,37 @@ bool Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
LearnSpell(spellid, false);
|
||||
AddTalent(spellid, GetActiveSpec(), true);
|
||||
|
||||
TC_LOG_INFO("misc", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, GetActiveSpec());
|
||||
TC_LOG_INFO("misc", "TalentID: %u Spell: %u Spec: %u\n", talentId, spellid, GetActiveSpec());
|
||||
|
||||
// set talent tree for player
|
||||
if (!GetPrimaryTalentTree(GetActiveSpec()))
|
||||
if (!GetTalentSpec(GetActiveSpec()))
|
||||
{
|
||||
SetPrimaryTalentTree(GetActiveSpec(), talentInfo->TalentTab);
|
||||
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentInfo->TalentTab);
|
||||
if (specSpells)
|
||||
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||
LearnSpell(specSpells->at(i), false);
|
||||
SetTalentSpec(GetActiveSpec(), talentInfo->SpecID);
|
||||
|
||||
if (CanUseMastery())
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(talentTabInfo->MasterySpellId[i]))
|
||||
if (masterySpell->IsPassive() && IsNeedCastPassiveSpellAtLearn(masterySpell))
|
||||
CastSpell(this, masterySpell->Id, true);
|
||||
}
|
||||
|
||||
// update free talent points
|
||||
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank)
|
||||
{
|
||||
Pet* pet = GetPet();
|
||||
|
||||
if (!pet)
|
||||
return;
|
||||
|
||||
if (petGuid != pet->GetGUID())
|
||||
return;
|
||||
|
||||
uint32 CurTalentPoints = pet->GetFreeTalentPoints();
|
||||
|
||||
if (CurTalentPoints == 0)
|
||||
return;
|
||||
|
||||
if (talentRank >= MAX_PET_TALENT_RANK)
|
||||
return;
|
||||
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
|
||||
if (!talentInfo)
|
||||
return;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||
|
||||
if (!talentTabInfo)
|
||||
return;
|
||||
|
||||
CreatureTemplate const* ci = pet->GetCreatureTemplate();
|
||||
|
||||
if (!ci)
|
||||
return;
|
||||
|
||||
CreatureFamilyEntry const* pet_family = sCreatureFamilyStore.LookupEntry(ci->family);
|
||||
|
||||
if (!pet_family)
|
||||
return;
|
||||
|
||||
if (pet_family->PetTalentType < 0) // not hunter pet
|
||||
return;
|
||||
|
||||
// prevent learn talent for different family (cheating)
|
||||
if (!((1 << pet_family->PetTalentType) & talentTabInfo->petTalentMask))
|
||||
return;
|
||||
|
||||
// find current max talent rank (0~5)
|
||||
uint8 curtalent_maxrank = 0; // 0 = not learned any rank
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
{
|
||||
if (talentInfo->RankID[rank] && pet->HasSpell(talentInfo->RankID[rank]))
|
||||
// Replace default spells by specialization spells
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(talentInfo->SpecID);
|
||||
if (specSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
curtalent_maxrank = (rank + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we already have same or higher talent rank learned
|
||||
if (curtalent_maxrank >= (talentRank + 1))
|
||||
return;
|
||||
|
||||
// check if we have enough talent points
|
||||
if (CurTalentPoints < (talentRank - curtalent_maxrank + 1))
|
||||
return;
|
||||
|
||||
// Check if it requires another talent
|
||||
if (talentInfo->DependsOn > 0)
|
||||
{
|
||||
if (TalentEntry const* depTalentInfo = sTalentStore.LookupEntry(talentInfo->DependsOn))
|
||||
{
|
||||
bool hasEnoughRank = false;
|
||||
for (uint8 rank = talentInfo->DependsOnRank; rank < MAX_TALENT_RANK; rank++)
|
||||
for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
|
||||
{
|
||||
if (depTalentInfo->RankID[rank] != 0)
|
||||
if (pet->HasSpell(depTalentInfo->RankID[rank]))
|
||||
hasEnoughRank = true;
|
||||
}
|
||||
if (!hasEnoughRank)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Find out how many points we have in this field
|
||||
uint32 spentPoints = 0;
|
||||
|
||||
uint32 tTab = talentInfo->TalentTab;
|
||||
if (talentInfo->Row > 0)
|
||||
{
|
||||
uint32 numRows = sTalentStore.GetNumRows();
|
||||
for (uint32 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 (uint8 rank = 0; rank < MAX_TALENT_RANK; rank++)
|
||||
{
|
||||
if (tmpTalent->RankID[rank] != 0)
|
||||
{
|
||||
if (pet->HasSpell(tmpTalent->RankID[rank]))
|
||||
{
|
||||
spentPoints += (rank + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
SpecializationSpellsEntry const* specSpell = *it;
|
||||
if (HasSpell(specSpell->OverridesSpellID)) {
|
||||
RemoveSpell(specSpell->OverridesSpellID, true);
|
||||
LearnSpell(specSpell->SpellID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CanUseMastery()) {
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(talentInfo->SpecID);
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(chrSpec->MasterySpellID[i]))
|
||||
if (masterySpell->IsPassive() && IsNeedCastPassiveSpellAtLearn(masterySpell))
|
||||
CastSpell(this, masterySpell->Id, true);
|
||||
}
|
||||
}
|
||||
|
||||
// not have required min points spent in talent tree
|
||||
if (spentPoints < (talentInfo->Row * MAX_PET_TALENT_RANK))
|
||||
return;
|
||||
|
||||
// spell not set in talent.dbc
|
||||
uint32 spellid = talentInfo->RankID[talentRank];
|
||||
if (spellid == 0)
|
||||
{
|
||||
TC_LOG_ERROR("entities.player", "Talent.dbc have for talent: %u Rank: %u spell id = 0", talentId, talentRank);
|
||||
return;
|
||||
}
|
||||
|
||||
// already known
|
||||
if (pet->HasSpell(spellid))
|
||||
return;
|
||||
|
||||
// learn! (other talent ranks will unlearned at learning)
|
||||
pet->learnSpell(spellid);
|
||||
TC_LOG_INFO("entities.player", "PetTalentID: %u Rank: %u Spell: %u\n", talentId, talentRank, spellid);
|
||||
|
||||
// update free talent points
|
||||
pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::AddKnownCurrency(uint32 itemId)
|
||||
@@ -25998,6 +25654,7 @@ bool Player::CanSeeSpellClickOn(Creature const* c) const
|
||||
|
||||
void Player::BuildPlayerTalentsInfoData(WorldPacket* data)
|
||||
{
|
||||
/* 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)
|
||||
@@ -26062,10 +25719,12 @@ void Player::BuildPlayerTalentsInfoData(WorldPacket* data)
|
||||
*data << uint16(GetGlyph(specIdx, i)); // GlyphProperties.dbc
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
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
|
||||
@@ -26133,11 +25792,12 @@ void Player::BuildPetTalentsInfoData(WorldPacket* data)
|
||||
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)
|
||||
@@ -26145,6 +25805,7 @@ void Player::SendTalentsInfoData(bool pet)
|
||||
else
|
||||
BuildPlayerTalentsInfoData(&data);
|
||||
GetSession()->SendPacket(&data);
|
||||
*/
|
||||
}
|
||||
|
||||
void Player::BuildEnchantmentsInfoData(WorldPacket* data)
|
||||
@@ -26604,48 +26265,34 @@ void Player::ActivateSpec(uint8 spec)
|
||||
if (!talentInfo)
|
||||
continue;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||
|
||||
if (!talentTabInfo)
|
||||
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 (getClass() != talentInfo->ClassID)
|
||||
continue;
|
||||
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
RemoveSpell(talentInfo->SpellID, true);
|
||||
}
|
||||
|
||||
// Unlearn specialization specific spells
|
||||
auto specSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(GetActiveSpec()));
|
||||
if (specSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
for (auto it = specSpells->second.begin(); it != specSpells->second.end(); ++it)
|
||||
{
|
||||
// skip non-existant talent ranks
|
||||
if (talentInfo->RankID[rank] == 0)
|
||||
continue;
|
||||
RemoveSpell(talentInfo->RankID[rank], true); // removes the talent, and all dependant, learned, and chained spells..
|
||||
if (const SpellInfo* _spellEntry = sSpellMgr->GetSpellInfo(talentInfo->RankID[rank]))
|
||||
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i) // search through the SpellInfo for valid trigger spells
|
||||
if (_spellEntry->Effects[i].TriggerSpell > 0 && _spellEntry->Effects[i].Effect == SPELL_EFFECT_LEARN_SPELL)
|
||||
RemoveSpell(_spellEntry->Effects[i].TriggerSpell, true); // and remove any spells that the talent teaches
|
||||
// if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
|
||||
//PlayerTalentMap::iterator plrTalent = m_talents[m_activeSpec]->find(talentInfo->RankID[rank]);
|
||||
//if (plrTalent != m_talents[m_activeSpec]->end())
|
||||
// plrTalent->second->state = PLAYERSPELL_REMOVED;
|
||||
SpecializationSpellsEntry const* specSpell = *it;
|
||||
if (HasSpell(specSpell->SpellID)) {
|
||||
RemoveSpell(specSpell->SpellID, true);
|
||||
LearnSpell(specSpell->OverridesSpellID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove spec specific spells
|
||||
for (uint32 i = 0; i < MAX_TALENT_TABS; ++i)
|
||||
{
|
||||
uint32 const* talentTabs = GetTalentTabPages(getClass());
|
||||
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(talentTabs[i]);
|
||||
if (specSpells)
|
||||
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||
RemoveSpell(specSpells->at(i), true);
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabs[i]);
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (uint32 mastery = talentTabInfo->MasterySpellId[i])
|
||||
RemoveSpell(mastery, true);
|
||||
}
|
||||
// Unlearn mastery spells
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec()));
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (chrSpec->MasterySpellID[i])
|
||||
RemoveSpell(chrSpec->MasterySpellID[i], true);
|
||||
|
||||
// set glyphs
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
@@ -26654,8 +26301,8 @@ void Player::ActivateSpec(uint8 spec)
|
||||
if (GlyphPropertiesEntry const* old_gp = sGlyphPropertiesStore.LookupEntry(oldglyph))
|
||||
RemoveAurasDueToSpell(old_gp->SpellID);
|
||||
|
||||
// Activate new spec
|
||||
SetActiveSpec(spec);
|
||||
uint32 spentTalents = 0;
|
||||
|
||||
for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
|
||||
{
|
||||
@@ -26664,40 +26311,37 @@ void Player::ActivateSpec(uint8 spec)
|
||||
if (!talentInfo)
|
||||
continue;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||
|
||||
if (!talentTabInfo)
|
||||
continue;
|
||||
|
||||
// learn only talents for character class
|
||||
if ((getClassMask() & talentTabInfo->ClassMask) == 0)
|
||||
if (getClass() != talentInfo->ClassID)
|
||||
continue;
|
||||
|
||||
// learn highest talent rank that exists in newly activated spec
|
||||
for (int8 rank = MAX_TALENT_RANK-1; rank >= 0; --rank)
|
||||
if (HasTalent(talentInfo->SpellID, GetActiveSpec()))
|
||||
{
|
||||
// skip non-existant talent ranks
|
||||
if (talentInfo->RankID[rank] == 0)
|
||||
continue;
|
||||
// if the talent can be found in the newly activated PlayerTalentMap
|
||||
if (HasTalent(talentInfo->RankID[rank], GetActiveSpec()))
|
||||
{
|
||||
LearnSpell(talentInfo->RankID[rank], false); // add the talent to the PlayerSpellMap
|
||||
spentTalents += (rank + 1); // increment the spentTalents count
|
||||
LearnSpell(talentInfo->SpellID, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace default spells with specialization specific spells
|
||||
auto newSpecSpells = sSpecializationSpellsBySpecStore.find(GetTalentSpec(spec));
|
||||
if (newSpecSpells != sSpecializationSpellsBySpecStore.end())
|
||||
{
|
||||
for (auto it = newSpecSpells->second.begin(); it != newSpecSpells->second.end(); ++it)
|
||||
{
|
||||
SpecializationSpellsEntry const* specSpell = *it;
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID);
|
||||
if (getLevel() >= spellInfo->BaseLevel) {
|
||||
if (specSpell->OverridesSpellID)
|
||||
RemoveSpell(specSpell->OverridesSpellID, true);
|
||||
LearnSpell(specSpell->SpellID, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32> const* specSpells = GetTalentTreePrimarySpells(GetPrimaryTalentTree(GetActiveSpec()));
|
||||
if (specSpells)
|
||||
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||
LearnSpell(specSpells->at(i), false);
|
||||
|
||||
if (CanUseMastery())
|
||||
if (TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec())))
|
||||
if (ChrSpecializationEntry const* newChrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(spec)))
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (uint32 mastery = talentTabInfo->MasterySpellId[i])
|
||||
LearnSpell(mastery, false);
|
||||
if (newChrSpec->MasterySpellID[i])
|
||||
LearnSpell(newChrSpec->MasterySpellID[i], false);
|
||||
|
||||
// set glyphs
|
||||
for (uint8 slot = 0; slot < MAX_GLYPH_SLOT_INDEX; ++slot)
|
||||
@@ -26712,7 +26356,6 @@ void Player::ActivateSpec(uint8 spec)
|
||||
SetGlyph(slot, glyph);
|
||||
}
|
||||
|
||||
SetUsedTalentCount(spentTalents);
|
||||
InitTalentForLevel();
|
||||
|
||||
{
|
||||
@@ -26731,7 +26374,7 @@ void Player::ActivateSpec(uint8 spec)
|
||||
|
||||
SetPower(pw, 0);
|
||||
|
||||
if (!sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec())))
|
||||
if (!sChrSpecializationStore.LookupEntry(GetTalentSpec(spec)))
|
||||
ResetTalents(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -123,38 +123,42 @@ struct PlayerTalent
|
||||
|
||||
extern uint32 const MasterySpells[MAX_CLASSES];
|
||||
|
||||
enum TalentTree // talent tabs
|
||||
enum TalentSpecialization // talent tabs
|
||||
{
|
||||
TALENT_TREE_WARRIOR_ARMS = 746,
|
||||
TALENT_TREE_WARRIOR_FURY = 815,
|
||||
TALENT_TREE_WARRIOR_PROTECTION = 845,
|
||||
TALENT_TREE_PALADIN_HOLY = 831,
|
||||
TALENT_TREE_PALADIN_PROTECTION = 839,
|
||||
TALENT_TREE_PALADIN_RETRIBUTION = 855,
|
||||
TALENT_TREE_HUNTER_BEAST_MASTERY = 811,
|
||||
TALENT_TREE_HUNTER_MARKSMANSHIP = 807,
|
||||
TALENT_TREE_HUNTER_SURVIVAL = 809,
|
||||
TALENT_TREE_ROGUE_ASSASSINATION = 182,
|
||||
TALENT_TREE_ROGUE_COMBAT = 181,
|
||||
TALENT_TREE_ROGUE_SUBTLETY = 183,
|
||||
TALENT_TREE_PRIEST_DISCIPLINE = 760,
|
||||
TALENT_TREE_PRIEST_HOLY = 813,
|
||||
TALENT_TREE_PRIEST_SHADOW = 795,
|
||||
TALENT_TREE_DEATH_KNIGHT_BLOOD = 398,
|
||||
TALENT_TREE_DEATH_KNIGHT_FROST = 399,
|
||||
TALENT_TREE_DEATH_KNIGHT_UNHOLY = 400,
|
||||
TALENT_TREE_SHAMAN_ELEMENTAL = 261,
|
||||
TALENT_TREE_SHAMAN_ENHANCEMENT = 263,
|
||||
TALENT_TREE_SHAMAN_RESTORATION = 262,
|
||||
TALENT_TREE_MAGE_ARCANE = 799,
|
||||
TALENT_TREE_MAGE_FIRE = 851,
|
||||
TALENT_TREE_MAGE_FROST = 823,
|
||||
TALENT_TREE_WARLOCK_AFFLICTION = 871,
|
||||
TALENT_TREE_WARLOCK_DEMONOLOGY = 867,
|
||||
TALENT_TREE_WARLOCK_DESTRUCTION = 865,
|
||||
TALENT_TREE_DRUID_BALANCE = 752,
|
||||
TALENT_TREE_DRUID_FERAL_COMBAT = 750,
|
||||
TALENT_TREE_DRUID_RESTORATION = 748
|
||||
TALENT_SPEC_MAGE_ARCANE = 62,
|
||||
TALENT_SPEC_MAGE_FIRE = 63,
|
||||
TALENT_SPEC_MAGE_FROST = 64,
|
||||
TALENT_SPEC_PALADIN_HOLY = 65,
|
||||
TALENT_SPEC_PALADIN_PROTECTION = 66,
|
||||
TALENT_SPEC_PALADIN_RETRIBUTION = 70,
|
||||
TALENT_SPEC_WARRIOR_ARMS = 71,
|
||||
TALENT_SPEC_WARRIOR_FURY = 72,
|
||||
TALENT_SPEC_WARRIOR_PROTECTION = 73,
|
||||
TALENT_SPEC_DRUID_BALANCE = 102,
|
||||
TALENT_SPEC_DRUID_CAT = 103,
|
||||
TALENT_SPEC_DRUID_BEAR = 104,
|
||||
TALENT_SPEC_DRUID_RESTORATION = 105,
|
||||
TALENT_SPEC_DEATHKNIGHT_BLOOD = 250,
|
||||
TALENT_SPEC_DEATHKNIGHT_FROST = 251,
|
||||
TALENT_SPEC_DEATHKNIGHT_UNHOLY = 252,
|
||||
TALENT_SPEC_HUNTER_BEASTMASTER = 253,
|
||||
TALENT_SPEC_HUNTER_MARKSMAN = 254,
|
||||
TALENT_SPEC_HUNTER_SURVIVAL = 255,
|
||||
TALENT_SPEC_PRIEST_DISCIPLINE = 256,
|
||||
TALENT_SPEC_PRIEST_HOLY = 257,
|
||||
TALENT_SPEC_PRIEST_SHADOW = 258,
|
||||
TALENT_SPEC_ROGUE_ASSASSINATION = 259,
|
||||
TALENT_SPEC_ROGUE_COMBAT = 260,
|
||||
TALENT_SPEC_ROGUE_SUBTLETY = 261,
|
||||
TALENT_SPEC_SHAMAN_ELEMENTAL = 262,
|
||||
TALENT_SPEC_SHAMAN_ENCHANCEMENT = 263,
|
||||
TALENT_SPEC_SHAMAN_RESTORATION = 264,
|
||||
TALENT_SPEC_WARLOCK_AFFLICTION = 265,
|
||||
TALENT_SPEC_WARLOCK_DEMONOLOGY = 266,
|
||||
TALENT_SPEC_WARLOCK_DESTRUCTION = 267,
|
||||
TALENT_SPEC_MONK_BREWMASTER = 268,
|
||||
TALENT_SPEC_MONK_BATTLEDANCER = 269,
|
||||
TALENT_SPEC_MONK_MISTWEAVER = 270
|
||||
};
|
||||
|
||||
// Spell modifier (used for modify other spells)
|
||||
@@ -1216,16 +1220,13 @@ private:
|
||||
|
||||
struct PlayerTalentInfo
|
||||
{
|
||||
PlayerTalentInfo() :
|
||||
FreeTalentPoints(0), UsedTalentCount(0), QuestRewardedTalentCount(0),
|
||||
ResetTalentsCost(0), ResetTalentsTime(0),
|
||||
ActiveSpec(0), SpecsCount(1)
|
||||
PlayerTalentInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveSpec(0), SpecsCount(1)
|
||||
{
|
||||
for (uint8 i = 0; i < MAX_TALENT_SPECS; ++i)
|
||||
{
|
||||
SpecInfo[i].Talents = new PlayerTalentMap();
|
||||
memset(SpecInfo[i].Glyphs, 0, MAX_GLYPH_SLOT_INDEX * sizeof(uint32));
|
||||
SpecInfo[i].TalentTree = 0;
|
||||
SpecInfo[i].TalentSpec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,12 +1244,9 @@ struct PlayerTalentInfo
|
||||
{
|
||||
PlayerTalentMap* Talents;
|
||||
uint32 Glyphs[MAX_GLYPH_SLOT_INDEX];
|
||||
uint32 TalentTree;
|
||||
uint32 TalentSpec;
|
||||
} SpecInfo[MAX_TALENT_SPECS];
|
||||
|
||||
uint32 FreeTalentPoints;
|
||||
uint32 UsedTalentCount;
|
||||
uint32 QuestRewardedTalentCount;
|
||||
uint32 ResetTalentsCost;
|
||||
time_t ResetTalentsTime;
|
||||
uint8 ActiveSpec;
|
||||
@@ -1818,22 +1816,16 @@ class Player : public Unit, public GridObject<Player>
|
||||
std::string GetGuildName();
|
||||
|
||||
// Talents
|
||||
uint32 GetFreeTalentPoints() const { return _talentMgr->FreeTalentPoints; }
|
||||
void SetFreeTalentPoints(uint32 points) { _talentMgr->FreeTalentPoints = points; }
|
||||
uint32 GetUsedTalentCount() const { return _talentMgr->UsedTalentCount; }
|
||||
void SetUsedTalentCount(uint32 talents) { _talentMgr->UsedTalentCount = talents; }
|
||||
uint32 GetQuestRewardedTalentCount() const { return _talentMgr->QuestRewardedTalentCount; }
|
||||
void AddQuestRewardedTalentCount(uint32 points) { _talentMgr->QuestRewardedTalentCount += points; }
|
||||
uint32 GetTalentResetCost() const { return _talentMgr->ResetTalentsCost; }
|
||||
void SetTalentResetCost(uint32 cost) { _talentMgr->ResetTalentsCost = cost; }
|
||||
uint32 GetTalentResetTime() const { return _talentMgr->ResetTalentsTime; }
|
||||
void SetTalentResetTime(time_t time_) { _talentMgr->ResetTalentsTime = time_; }
|
||||
uint32 GetPrimaryTalentTree(uint8 spec) const { return _talentMgr->SpecInfo[spec].TalentTree; }
|
||||
void SetPrimaryTalentTree(uint8 spec, uint32 tree) { _talentMgr->SpecInfo[spec].TalentTree = tree; }
|
||||
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; }
|
||||
|
||||
bool ResetTalents(bool no_cost = false);
|
||||
uint32 GetNextResetTalentsCost() const;
|
||||
@@ -1841,11 +1833,9 @@ class Player : public Unit, public GridObject<Player>
|
||||
void BuildPlayerTalentsInfoData(WorldPacket* data);
|
||||
void BuildPetTalentsInfoData(WorldPacket* data);
|
||||
void SendTalentsInfoData(bool pet);
|
||||
bool LearnTalent(uint32 talentId, uint32 talentRank);
|
||||
void LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank);
|
||||
bool LearnTalent(uint32 talentId);
|
||||
bool AddTalent(uint32 spellId, uint8 spec, bool learning);
|
||||
bool HasTalent(uint32 spell_id, uint8 spec) const;
|
||||
uint32 CalculateTalentsPoints() const;
|
||||
|
||||
// Dual Spec
|
||||
void UpdateSpecCount(uint8 count);
|
||||
|
||||
@@ -67,7 +67,7 @@ void Totem::InitStats(uint32 duration)
|
||||
GetOwner()->ToPlayer()->SendDirectMessage(&data);
|
||||
|
||||
// set display id depending on caster's race
|
||||
SetDisplayId(GetOwner()->GetModelForTotem(PlayerTotemType(m_Properties->Id)));
|
||||
SetDisplayId(GetOwner()->GetModelForTotem(PlayerTotemType(m_Properties->ID)));
|
||||
}
|
||||
|
||||
Minion::InitStats(duration);
|
||||
@@ -91,7 +91,7 @@ void Totem::InitSummon()
|
||||
if (GetSpell(1))
|
||||
CastSpell(this, GetSpell(1), true);
|
||||
|
||||
if (m_Properties->Id == SUMMON_TYPE_TOTEM_FIRE && GetOwner()->HasAura(SPELL_TOTEMIC_WRATH_TALENT))
|
||||
if (m_Properties->ID == SUMMON_TYPE_TOTEM_FIRE && GetOwner()->HasAura(SPELL_TOTEMIC_WRATH_TALENT))
|
||||
CastSpell(this, SPELL_TOTEMIC_WRATH, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -526,16 +526,16 @@ void Player::UpdateMastery()
|
||||
value += GetRatingBonusValue(CR_MASTERY);
|
||||
SetFloatValue(PLAYER_MASTERY, value);
|
||||
|
||||
TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(GetPrimaryTalentTree(GetActiveSpec()));
|
||||
if (!talentTab)
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(GetTalentSpec(GetActiveSpec()));
|
||||
if (!chrSpec)
|
||||
return;
|
||||
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
{
|
||||
if (!talentTab->MasterySpellId[i])
|
||||
if (!chrSpec->MasterySpellID[i])
|
||||
continue;
|
||||
|
||||
if (Aura* aura = GetAura(talentTab->MasterySpellId[i]))
|
||||
if (Aura* aura = GetAura(chrSpec->MasterySpellID[i]))
|
||||
{
|
||||
for (uint32 j = 0; j < MAX_SPELL_EFFECTS; ++j)
|
||||
{
|
||||
|
||||
@@ -4301,13 +4301,6 @@ void ObjectMgr::LoadQuests()
|
||||
qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
|
||||
qinfo->RewardSpell = 0; // no spell reward will display for this quest
|
||||
}
|
||||
|
||||
else if (GetTalentSpellCost(qinfo->RewardSpell))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.",
|
||||
qinfo->GetQuestId(), qinfo->RewardSpell, qinfo->RewardSpell);
|
||||
qinfo->RewardSpell = 0; // no spell reward will display for this quest
|
||||
}
|
||||
}
|
||||
|
||||
if (qinfo->RewardSpellCast > 0)
|
||||
@@ -4327,13 +4320,6 @@ void ObjectMgr::LoadQuests()
|
||||
qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
|
||||
qinfo->RewardSpellCast = 0; // no spell will be cast on player
|
||||
}
|
||||
|
||||
else if (GetTalentSpellCost(qinfo->RewardSpellCast))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Quest %u has `RewardSpell` = %u but spell %u is talent, quest will not have a spell reward.",
|
||||
qinfo->GetQuestId(), qinfo->RewardSpellCast, qinfo->RewardSpellCast);
|
||||
qinfo->RewardSpellCast = 0; // no spell will be cast on player
|
||||
}
|
||||
}
|
||||
|
||||
if (qinfo->RewardMailTemplateId)
|
||||
@@ -8134,12 +8120,6 @@ void ObjectMgr::AddSpellToTrainer(uint32 ID, uint32 SpellID, uint32 MoneyCost, u
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetTalentSpellCost(SpellID))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Table `npc_trainer` contains an ID (%u) for a non-existing spell (Spell: %u) which is a talent, ignoring", ID, SpellID);
|
||||
return;
|
||||
}
|
||||
|
||||
TrainerSpellData& data = _cacheTrainerSpellStore[ID];
|
||||
|
||||
TrainerSpell& trainerSpell = data.spellList[SpellID];
|
||||
|
||||
@@ -853,6 +853,7 @@ void WorldSession::SendPetNameInvalid(uint32 error, const std::string& name, Dec
|
||||
|
||||
void WorldSession::HandlePetLearnTalent(WorldPacket& recvData)
|
||||
{
|
||||
/* TODO: 6.x remove pet talents (add pet specializations)
|
||||
TC_LOG_DEBUG("network", "WORLD: CMSG_PET_LEARN_TALENT");
|
||||
|
||||
ObjectGuid guid;
|
||||
@@ -860,11 +861,12 @@ void WorldSession::HandlePetLearnTalent(WorldPacket& recvData)
|
||||
recvData >> guid >> talentId >> requestedRank;
|
||||
|
||||
_player->LearnPetTalent(guid, talentId, requestedRank);
|
||||
_player->SendTalentsInfoData(true);
|
||||
_player->SendTalentsInfoData(true);*/
|
||||
}
|
||||
|
||||
void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket& recvData)
|
||||
{
|
||||
/* TODO: 6.x remove pet talents (add pet specializations)
|
||||
TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS_PET");
|
||||
|
||||
ObjectGuid guid;
|
||||
@@ -887,5 +889,5 @@ void WorldSession::HandleLearnPreviewTalentsPet(WorldPacket& recvData)
|
||||
|
||||
_player->SendTalentsInfoData(true);
|
||||
|
||||
recvData.rfinish();
|
||||
recvData.rfinish();*/
|
||||
}
|
||||
|
||||
@@ -29,15 +29,17 @@
|
||||
|
||||
void WorldSession::HandleLearnTalentOpcode(WorldPacket& recvData)
|
||||
{
|
||||
/* TODO: 6.x update packet struct (note: LearnTalent no longer has rank argument)
|
||||
uint32 talentId, requestedRank;
|
||||
recvData >> talentId >> requestedRank;
|
||||
|
||||
if (_player->LearnTalent(talentId, requestedRank))
|
||||
_player->SendTalentsInfoData(false);
|
||||
_player->SendTalentsInfoData(false);*/
|
||||
}
|
||||
|
||||
void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
|
||||
{
|
||||
/* TODO: 6.x update packet struct
|
||||
TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS");
|
||||
|
||||
int32 tabPage;
|
||||
@@ -77,7 +79,7 @@ void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
|
||||
|
||||
_player->SendTalentsInfoData(false);
|
||||
|
||||
recvPacket.rfinish();
|
||||
recvPacket.rfinish();*/
|
||||
}
|
||||
|
||||
void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData)
|
||||
|
||||
@@ -2049,7 +2049,7 @@ void Spell::EffectSummonType(SpellEffIndex effIndex)
|
||||
// however so far noone found a generic check to find all of those (there's no related data in summonproperties.dbc
|
||||
// and in spell attributes, possibly we need to add a table for those)
|
||||
// so here's a list of MiscValueB values, which is currently most generic check
|
||||
switch (properties->Id)
|
||||
switch (properties->ID)
|
||||
{
|
||||
case 64:
|
||||
case 61:
|
||||
|
||||
@@ -1478,9 +1478,10 @@ SpellCastResult SpellInfo::CheckShapeshift(uint32 form) const
|
||||
{
|
||||
// talents that learn spells can have stance requirements that need ignore
|
||||
// (this requirement only for client-side stance show in talent description)
|
||||
/* TODO: 6.x fix this in proper way (probably spell flags/attributes?)
|
||||
if (GetTalentSpellCost(Id) > 0 &&
|
||||
(Effects[0].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[1].Effect == SPELL_EFFECT_LEARN_SPELL || Effects[2].Effect == SPELL_EFFECT_LEARN_SPELL))
|
||||
return SPELL_CAST_OK;
|
||||
return SPELL_CAST_OK;*/
|
||||
|
||||
uint32 stanceMask = (form ? 1 << (form - 1) : 0);
|
||||
|
||||
|
||||
@@ -1227,6 +1227,7 @@ void SpellMgr::UnloadSpellInfoChains()
|
||||
|
||||
void SpellMgr::LoadSpellTalentRanks()
|
||||
{
|
||||
/* TODO: 6.x remove this
|
||||
// cleanup core data before reload - remove reference to ChainNode from SpellInfo
|
||||
UnloadSpellInfoChains();
|
||||
|
||||
@@ -1283,7 +1284,7 @@ void SpellMgr::LoadSpellTalentRanks()
|
||||
|
||||
prevSpell = currentSpell;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void SpellMgr::LoadSpellRanks()
|
||||
@@ -1538,7 +1539,7 @@ void SpellMgr::LoadSpellLearnSpells()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (GetTalentSpellCost(node.spell))
|
||||
if (GetTalentBySpellID(node.spell))
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "Spell %u listed in `spell_learn_spell` attempt learning talent spell %u, skipped", spell_id, node.spell);
|
||||
continue;
|
||||
@@ -1576,7 +1577,7 @@ void SpellMgr::LoadSpellLearnSpells()
|
||||
// talent or passive spells or skill-step spells auto-cast and not need dependent learning,
|
||||
// pet teaching spells must not be dependent learning (cast)
|
||||
// other required explicit dependent learning
|
||||
dbc_node.autoLearned = entry->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentSpellCost(spell) > 0 || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
|
||||
dbc_node.autoLearned = entry->Effects[i].TargetA.GetTarget() == TARGET_UNIT_PET || GetTalentBySpellID(spell) || entry->IsPassive() || entry->HasEffect(SPELL_EFFECT_SKILL_STEP);
|
||||
|
||||
SpellLearnSpellMapBounds db_node_bounds = dbSpellLearnSpells.equal_range(spell);
|
||||
|
||||
@@ -1602,22 +1603,22 @@ void SpellMgr::LoadSpellLearnSpells()
|
||||
}
|
||||
|
||||
uint32 mastery_count = 0;
|
||||
for (uint32 i = 0; i < sTalentTabStore.GetNumRows(); ++i)
|
||||
for (uint32 i = 0; i < sChrSpecializationStore.GetNumRows(); ++i)
|
||||
{
|
||||
TalentTabEntry const* talentTab = sTalentTabStore.LookupEntry(i);
|
||||
if (!talentTab)
|
||||
ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(i);
|
||||
if (!chrSpec)
|
||||
continue;
|
||||
|
||||
for (uint32 c = CLASS_WARRIOR; c < MAX_CLASSES; ++c)
|
||||
{
|
||||
if (!(talentTab->ClassMask & (1 << (c - 1))))
|
||||
if (chrSpec->ClassID != c)
|
||||
continue;
|
||||
|
||||
uint32 masteryMainSpell = MasterySpells[c];
|
||||
|
||||
for (uint32 m = 0; m < MAX_MASTERY_SPELLS; ++m)
|
||||
{
|
||||
uint32 mastery = talentTab->MasterySpellId[m];
|
||||
uint32 mastery = chrSpec->MasterySpellID[m];
|
||||
if (!mastery)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ void CharacterDatabaseCleaner::CleanCharacterSkills()
|
||||
|
||||
bool CharacterDatabaseCleaner::SpellCheck(uint32 spell_id)
|
||||
{
|
||||
return sSpellMgr->GetSpellInfo(spell_id) && !GetTalentSpellPos(spell_id);
|
||||
return sSpellMgr->GetSpellInfo(spell_id) && GetTalentBySpellID(spell_id) != nullptr;
|
||||
}
|
||||
|
||||
void CharacterDatabaseCleaner::CleanCharacterSpell()
|
||||
@@ -142,7 +142,7 @@ bool CharacterDatabaseCleaner::TalentCheck(uint32 talent_id)
|
||||
if (!talentInfo)
|
||||
return false;
|
||||
|
||||
return sTalentTabStore.LookupEntry(talentInfo->TalentTab) != nullptr;
|
||||
return sChrSpecializationStore.LookupEntry(talentInfo->SpecID) != nullptr;
|
||||
}
|
||||
|
||||
void CharacterDatabaseCleaner::CleanCharacterTalent()
|
||||
|
||||
@@ -116,9 +116,6 @@ public:
|
||||
else
|
||||
targetPlayer->LearnSpell(spell, false);
|
||||
|
||||
if (GetTalentSpellCost(spellInfo->GetFirstRankSpell()->Id))
|
||||
targetPlayer->SendTalentsInfoData(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -176,10 +173,6 @@ public:
|
||||
if (spellInfo->SpellFamilyName != family)
|
||||
continue;
|
||||
|
||||
// skip spells with first rank learned as talent (and all talents then also)
|
||||
if (GetTalentSpellCost(spellInfo->GetFirstRankSpell()->Id) > 0)
|
||||
continue;
|
||||
|
||||
// skip broken spells
|
||||
if (!SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false))
|
||||
continue;
|
||||
@@ -194,7 +187,7 @@ public:
|
||||
static bool HandleLearnAllMyTalentsCommand(ChatHandler* handler, char const* /*args*/)
|
||||
{
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
uint32 classMask = player->getClassMask();
|
||||
uint32 playerClass = player->getClass();
|
||||
|
||||
for (uint32 i = 0; i < sTalentStore.GetNumRows(); ++i)
|
||||
{
|
||||
@@ -202,44 +195,25 @@ public:
|
||||
if (!talentInfo)
|
||||
continue;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TalentTab);
|
||||
if (!talentTabInfo)
|
||||
if (playerClass != talentInfo->ClassID)
|
||||
continue;
|
||||
|
||||
if ((classMask & talentTabInfo->ClassMask) == 0)
|
||||
continue;
|
||||
|
||||
// search highest talent rank
|
||||
uint32 spellId = 0;
|
||||
for (int8 rank = MAX_TALENT_RANK - 1; rank >= 0; --rank)
|
||||
{
|
||||
if (talentInfo->RankID[rank] != 0)
|
||||
{
|
||||
spellId = talentInfo->RankID[rank];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!spellId) // ??? none spells in talent
|
||||
continue;
|
||||
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId);
|
||||
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID);
|
||||
if (!spellInfo || !SpellMgr::IsSpellValid(spellInfo, handler->GetSession()->GetPlayer(), false))
|
||||
continue;
|
||||
|
||||
// learn highest rank of talent and learn all non-talent spell ranks (recursive by tree)
|
||||
player->LearnSpellHighestRank(spellId);
|
||||
player->AddTalent(spellId, player->GetActiveSpec(), true);
|
||||
player->LearnSpellHighestRank(talentInfo->SpellID);
|
||||
player->AddTalent(talentInfo->SpellID, player->GetActiveSpec(), true);
|
||||
}
|
||||
|
||||
player->SetFreeTalentPoints(0);
|
||||
|
||||
handler->SendSysMessage(LANG_COMMAND_LEARN_CLASS_TALENTS);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool HandleLearnAllMyPetTalentsCommand(ChatHandler* handler, char const* /*args*/)
|
||||
{
|
||||
/* TODO: 6.x remove pet talents
|
||||
Player* player = handler->GetSession()->GetPlayer();
|
||||
|
||||
Pet* pet = player->GetPet();
|
||||
@@ -312,7 +286,7 @@ public:
|
||||
|
||||
pet->SetFreeTalentPoints(0);
|
||||
|
||||
handler->SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS);
|
||||
handler->SendSysMessage(LANG_COMMAND_LEARN_PET_TALENTS);*/
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -484,9 +458,6 @@ public:
|
||||
else
|
||||
handler->SendSysMessage(LANG_FORGET_SPELL);
|
||||
|
||||
if (GetTalentSpellCost(spellId))
|
||||
target->SendTalentsInfoData(false);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -435,7 +435,7 @@ public:
|
||||
handler->PSendSysMessage(LANG_COMMAND_TARGET_LISTAURAS, auras.size());
|
||||
for (Unit::AuraApplicationMap::const_iterator itr = auras.begin(); itr != auras.end(); ++itr)
|
||||
{
|
||||
bool talent = GetTalentSpellCost(itr->second->GetBase()->GetId()) > 0;
|
||||
bool talent = (GetTalentBySpellID(itr->second->GetBase()->GetId()) != nullptr);
|
||||
|
||||
AuraApplication const* aurApp = itr->second;
|
||||
Aura const* aura = aurApp->GetBase();
|
||||
|
||||
@@ -812,15 +812,13 @@ public:
|
||||
|
||||
SpellInfo const* learnSpellInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[0].TriggerSpell);
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(id);
|
||||
|
||||
bool talent = (talentCost > 0);
|
||||
bool talent = (GetTalentBySpellID(id) != nullptr);
|
||||
bool passive = spellInfo->IsPassive();
|
||||
bool active = target && target->HasAura(id);
|
||||
|
||||
// unit32 used to prevent interpreting uint8 as char at output
|
||||
// find rank of learned spell for learning spell, or talent rank
|
||||
uint32 rank = talentCost ? talentCost : learn && learnSpellInfo ? learnSpellInfo->GetRank() : spellInfo->GetRank();
|
||||
uint32 rank = learn && learnSpellInfo ? learnSpellInfo->GetRank() : spellInfo->GetRank();
|
||||
|
||||
// send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format
|
||||
std::ostringstream ss;
|
||||
@@ -884,15 +882,13 @@ public:
|
||||
|
||||
SpellInfo const* learnSpellInfo = sSpellMgr->GetSpellInfo(spellInfo->Effects[0].TriggerSpell);
|
||||
|
||||
uint32 talentCost = GetTalentSpellCost(id);
|
||||
|
||||
bool talent = (talentCost > 0);
|
||||
bool talent = (GetTalentBySpellID(id) != nullptr);
|
||||
bool passive = spellInfo->IsPassive();
|
||||
bool active = target && target->HasAura(id);
|
||||
|
||||
// unit32 used to prevent interpreting uint8 as char at output
|
||||
// find rank of learned spell for learning spell, or talent rank
|
||||
uint32 rank = talentCost ? talentCost : learn && learnSpellInfo ? learnSpellInfo->GetRank() : spellInfo->GetRank();
|
||||
uint32 rank = learn && learnSpellInfo ? learnSpellInfo->GetRank() : spellInfo->GetRank();
|
||||
|
||||
// send spell in "id - [name, rank N] [talent] [passive] [learn] [known]" format
|
||||
std::ostringstream ss;
|
||||
|
||||
@@ -419,6 +419,7 @@ public:
|
||||
//Edit Player TP
|
||||
static bool HandleModifyTalentCommand (ChatHandler* handler, const char* args)
|
||||
{
|
||||
/* TODO: 6.x remove this
|
||||
if (!*args)
|
||||
return false;
|
||||
|
||||
@@ -459,7 +460,7 @@ public:
|
||||
|
||||
handler->SendSysMessage(LANG_NO_CHAR_SELECTED);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
return false;*/
|
||||
}
|
||||
|
||||
//Edit Player Aspeed
|
||||
|
||||
@@ -168,7 +168,7 @@ class spell_dru_eclipse_energize : public SpellScriptLoader
|
||||
Player* caster = GetCaster()->ToPlayer();
|
||||
|
||||
// No boomy, no deal.
|
||||
if (caster->GetPrimaryTalentTree(caster->GetActiveSpec()) != TALENT_TREE_DRUID_BALANCE)
|
||||
if (caster->GetTalentSpec(caster->GetActiveSpec()) != TALENT_SPEC_DRUID_BALANCE)
|
||||
return;
|
||||
|
||||
switch (GetSpellInfo()->Id)
|
||||
|
||||
Reference in New Issue
Block a user