Core/Player: allow players to learn a primary specialization without having to select a talent
* converted CMSG_LEARN_PREVIEW_TALENTS to packet class
This commit is contained in:
1 parent
53df12ae73
commit
c092c6ad00
7 files changed
+147
-59
No files matched your search
@@ -25474,21 +25474,18 @@ void Player::CompletedAchievement(AchievementEntry const* entry)
|
||||
|
||||
bool Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
{
|
||||
uint32 CurTalentPoints = GetFreeTalentPoints();
|
||||
|
||||
if (CurTalentPoints == 0)
|
||||
if (talentId == 0 || talentRank >= MAX_TALENT_RANK)
|
||||
return false;
|
||||
|
||||
if (talentRank >= MAX_TALENT_RANK)
|
||||
uint32 freeTalentPoints = GetFreeTalentPoints();
|
||||
if (freeTalentPoints == 0)
|
||||
return false;
|
||||
|
||||
TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
|
||||
|
||||
if (!talentInfo)
|
||||
return false;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentInfo->TabID);
|
||||
|
||||
if (!talentTabInfo)
|
||||
return false;
|
||||
|
||||
@@ -25512,7 +25509,7 @@ bool Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
return false;
|
||||
|
||||
// check if we have enough talent points
|
||||
if (CurTalentPoints < (talentRank - curtalent_maxrank + 1))
|
||||
if (freeTalentPoints < (talentRank - curtalent_maxrank + 1))
|
||||
return false;
|
||||
|
||||
// Check if it requires another talent
|
||||
@@ -25587,24 +25584,8 @@ bool Player::LearnTalent(uint32 talentId, uint32 talentRank)
|
||||
|
||||
TC_LOG_DEBUG("entities.player", "TalentID: %u Rank: %u Spell: %u Spec: %u\n", talentId, talentRank, spellid, GetActiveSpec());
|
||||
|
||||
// set talent tree for player
|
||||
if (!GetPrimaryTalentTree(GetActiveSpec()))
|
||||
{
|
||||
SetPrimaryTalentTree(GetActiveSpec(), talentInfo->TabID);
|
||||
std::vector<uint32> const* specSpells = sDBCManager.GetTalentTreePrimarySpells(talentInfo->TabID);
|
||||
if (specSpells)
|
||||
for (size_t i = 0; i < specSpells->size(); ++i)
|
||||
LearnSpell(specSpells->at(i), false);
|
||||
|
||||
if (CanUseMastery())
|
||||
for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(talentTabInfo->MasterySpellID[i]))
|
||||
if (masterySpell->IsPassive() && HandlePassiveSpellLearn(masterySpell))
|
||||
CastSpell(this, masterySpell->Id, true);
|
||||
}
|
||||
|
||||
// update free talent points
|
||||
SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
SetFreeTalentPoints(freeTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25743,6 +25724,38 @@ void Player::LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRa
|
||||
pet->SetFreeTalentPoints(CurTalentPoints - (talentRank - curtalent_maxrank + 1));
|
||||
}
|
||||
|
||||
bool Player::LearnPrimaryTalentSpecialization(uint8 talentTabIndex)
|
||||
{
|
||||
if (talentTabIndex >= MAX_TALENT_TABS)
|
||||
return false;
|
||||
|
||||
if (GetPrimaryTalentTree(GetActiveSpec()) != 0)
|
||||
return false;
|
||||
|
||||
uint32 const* talentTabs = sDBCManager.GetTalentTabPages(getClass());
|
||||
if (!talentTabs)
|
||||
return false;
|
||||
|
||||
TalentTabEntry const* talentTabInfo = sTalentTabStore.LookupEntry(talentTabs[talentTabIndex]);
|
||||
if (!talentTabInfo)
|
||||
return false;
|
||||
|
||||
SetPrimaryTalentTree(GetActiveSpec(), talentTabInfo->ID);
|
||||
|
||||
// Learn specialization spells and mastery
|
||||
if (std::vector<uint32> const* specSpells = sDBCManager.GetTalentTreePrimarySpells(talentTabInfo->ID))
|
||||
for (uint32 spellId : *specSpells)
|
||||
LearnSpell(spellId, false);
|
||||
|
||||
if (CanUseMastery())
|
||||
for (uint8 i = 0; i < MAX_MASTERY_SPELLS; ++i)
|
||||
if (SpellInfo const* masterySpell = sSpellMgr->GetSpellInfo(talentTabInfo->MasterySpellID[i]))
|
||||
if (masterySpell->IsPassive() && HandlePassiveSpellLearn(masterySpell))
|
||||
CastSpell(this, masterySpell->Id, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Player::AddKnownCurrency(uint32 itemId)
|
||||
{
|
||||
if (CurrencyTypesEntry const* ctEntry = sCurrencyTypesStore.LookupEntry(itemId))
|
||||
@@ -27793,7 +27806,8 @@ uint32 Player::GetPrimaryTalentTree(uint8 spec) const
|
||||
|
||||
void Player::SetPrimaryTalentTree(uint8 spec, uint32 tree)
|
||||
{
|
||||
_talentMgr->SpecInfo[spec].TalentTree = tree; UpdateArmorSpecialization();
|
||||
_talentMgr->SpecInfo[spec].TalentTree = tree;
|
||||
UpdateArmorSpecialization();
|
||||
}
|
||||
|
||||
uint8 Player::GetActiveSpec() const
|
||||
|
||||
@@ -1583,6 +1583,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
|
||||
void SendTalentsInfoData(bool pet);
|
||||
bool LearnTalent(uint32 talentId, uint32 talentRank);
|
||||
void LearnPetTalent(ObjectGuid petGuid, uint32 talentId, uint32 talentRank);
|
||||
bool LearnPrimaryTalentSpecialization(uint8 talentTabIndex);
|
||||
bool AddTalent(uint32 spellId, uint8 spec, bool learning);
|
||||
bool HasTalent(uint32 spell_id, uint8 spec) const;
|
||||
uint32 CalculateTalentsPoints() const;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "TalentPackets.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
void WorldSession::HandleLearnTalentOpcode(WorldPacket& recvData)
|
||||
@@ -33,48 +34,25 @@ void WorldSession::HandleLearnTalentOpcode(WorldPacket& recvData)
|
||||
_player->SendTalentsInfoData(false);
|
||||
}
|
||||
|
||||
void WorldSession::HandleLearnPreviewTalents(WorldPacket& recvPacket)
|
||||
void WorldSession::HandleLearnPreviewTalents(WorldPackets::Talent::LearnPreviewTalents& packet)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "CMSG_LEARN_PREVIEW_TALENTS");
|
||||
|
||||
int32 tabPage;
|
||||
uint32 talentsCount;
|
||||
recvPacket >> tabPage; // talent tree
|
||||
// Player is attempting to set his primary specialization for his active spec.
|
||||
// This field is doing the same as CMSG_SET_PRIMARY_TALENT_TREE
|
||||
if (packet.TalentTab >= 0)
|
||||
if (!_player->LearnPrimaryTalentSpecialization(packet.TalentTab))
|
||||
return;
|
||||
|
||||
// prevent cheating (selecting new tree with points already in another)
|
||||
if (tabPage >= 0) // -1 if player already has specialization
|
||||
{
|
||||
if (packet.TalentTab >= 0) // -1 if player already has specialization
|
||||
if (TalentTabEntry const* talentTabEntry = sTalentTabStore.LookupEntry(_player->GetPrimaryTalentTree(_player->GetActiveSpec())))
|
||||
{
|
||||
if (talentTabEntry->OrderIndex != uint32(tabPage))
|
||||
{
|
||||
recvPacket.rfinish();
|
||||
if (talentTabEntry->OrderIndex != static_cast<uint32>(packet.TalentTab))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recvPacket >> talentsCount;
|
||||
|
||||
uint32 talentId, talentRank;
|
||||
|
||||
// Client has max 21 talents for tree for 3 trees, rounded up : 70
|
||||
uint32 const MaxTalentsCount = 70;
|
||||
|
||||
for (uint32 i = 0; i < talentsCount && i < MaxTalentsCount; ++i)
|
||||
{
|
||||
recvPacket >> talentId >> talentRank;
|
||||
|
||||
if (!_player->LearnTalent(talentId, talentRank))
|
||||
{
|
||||
recvPacket.rfinish();
|
||||
for (WorldPackets::Talent::TalentInfo const& talent : packet.Talents)
|
||||
if (!_player->LearnTalent(talent.TalentID, talent.Rank))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_player->SendTalentsInfoData(false);
|
||||
|
||||
recvPacket.rfinish();
|
||||
}
|
||||
|
||||
void WorldSession::HandleTalentWipeConfirmOpcode(WorldPacket& recvData)
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "ReforgePackets.h"
|
||||
#include "SpellPackets.h"
|
||||
#include "SystemPackets.h"
|
||||
#include "TalentPackets.h"
|
||||
#include "TicketPackets.h"
|
||||
#include "TotemPackets.h"
|
||||
#include "TradePackets.h"
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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"
|
||||
|
||||
ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Talent::TalentInfo const& talent)
|
||||
{
|
||||
data << uint32(talent.TalentID);
|
||||
data << uint32(talent.Rank);
|
||||
return data;
|
||||
}
|
||||
|
||||
ByteBuffer& operator>>(ByteBuffer& data, WorldPackets::Talent::TalentInfo& talent)
|
||||
{
|
||||
data >> talent.TalentID;
|
||||
data >> talent.Rank;
|
||||
return data;
|
||||
}
|
||||
|
||||
void WorldPackets::Talent::LearnPreviewTalents::Read()
|
||||
{
|
||||
_worldPacket >> TalentTab;
|
||||
Talents.resize(_worldPacket.read<uint32>());
|
||||
|
||||
for (TalentInfo& talent : Talents)
|
||||
_worldPacket >> talent;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 "DBCEnums.h"
|
||||
#include "ObjectGuid.h"
|
||||
#include "PacketUtilities.h"
|
||||
|
||||
namespace WorldPackets
|
||||
{
|
||||
namespace Talent
|
||||
{
|
||||
struct TalentInfo
|
||||
{
|
||||
uint32 TalentID = 0;
|
||||
uint32 Rank = 0;
|
||||
};
|
||||
|
||||
class LearnPreviewTalents final : public ClientPacket
|
||||
{
|
||||
public:
|
||||
LearnPreviewTalents(WorldPacket&& packet) : ClientPacket(CMSG_LEARN_PREVIEW_TALENTS, std::move(packet)) { }
|
||||
|
||||
void Read() override;
|
||||
|
||||
int32 TalentTab = 0;
|
||||
Array<TalentInfo, 70> Talents;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TalentPackets_h__
|
||||
@@ -235,6 +235,10 @@ namespace WorldPackets
|
||||
class UpdateMissileTrajectory;
|
||||
}
|
||||
|
||||
namespace Talent
|
||||
{
|
||||
class LearnPreviewTalents;
|
||||
}
|
||||
namespace Ticket
|
||||
{
|
||||
class Complaint;
|
||||
@@ -988,7 +992,7 @@ class TC_GAME_API WorldSession
|
||||
void HandleCancelAutoRepeatSpellOpcode(WorldPacket& recvPacket);
|
||||
|
||||
void HandleLearnTalentOpcode(WorldPacket& recvPacket);
|
||||
void HandleLearnPreviewTalents(WorldPacket& recvPacket);
|
||||
void HandleLearnPreviewTalents(WorldPackets::Talent::LearnPreviewTalents& packet);
|
||||
void HandleTalentWipeConfirmOpcode(WorldPacket& recvPacket);
|
||||
void HandleUnlearnSkillOpcode(WorldPacket& recvPacket);
|
||||
|
||||
|
||||
Reference in new issue
Block a user