aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/database/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/game/Entities/Player/Player.cpp62
-rw-r--r--src/server/game/Entities/Player/Player.h17
-rw-r--r--src/server/game/Handlers/SkillHandler.cpp19
-rw-r--r--src/server/game/Server/Packets/TalentPackets.cpp5
-rw-r--r--src/server/game/Server/Packets/TalentPackets.h10
-rw-r--r--src/server/game/Server/Protocol/Opcodes.cpp2
-rw-r--r--src/server/game/Server/WorldSession.h2
-rw-r--r--src/server/game/Spells/Spell.cpp51
-rw-r--r--src/server/game/Spells/Spell.h2
-rw-r--r--src/server/game/Spells/SpellEffects.cpp70
11 files changed, 152 insertions, 92 deletions
diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp
index 7cd5bb2a8a7..6b0df5f03e3 100644
--- a/src/server/database/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp
@@ -149,7 +149,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16, "
"appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_BGDATA, "SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell, queueId FROM character_battleground_data WHERE guid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_SEL_CHARACTER_GLYPHS, "SELECT talentGroup, glyphSlot, glyphId FROM character_glyphs WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_TALENTS, "SELECT talentId, talentRank, talentGroup FROM character_talent WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_SKILLS, "SELECT skill, value, max, professionSlot FROM character_skills WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_SEL_CHARACTER_RANDOMBG, "SELECT guid FROM character_battleground_random WHERE guid = ?", CONNECTION_ASYNC);
@@ -657,7 +657,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"attackPower, rangedAttackPower, spellPower, resilience, mastery, versatility) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PETITION_BY_OWNER, "DELETE FROM petition WHERE ownerguid = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_DEL_PETITION_SIGNATURE_BY_OWNER, "DELETE FROM petition_sign WHERE ownerguid = ?", CONNECTION_ASYNC);
- PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs VALUES(?, ?, ?)", CONNECTION_ASYNC);
+ PrepareStatement(CHAR_INS_CHAR_GLYPHS, "INSERT INTO character_glyphs (guid, talentGroup, glyphSlot, glyphId) VALUES(?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_TALENT, "INSERT INTO character_talent (guid, talentId, talentRank, talentGroup) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(CHAR_UPD_CHAR_LIST_SLOT, "UPDATE characters SET slot = ? WHERE guid = ? AND account = ?", CONNECTION_ASYNC);
PrepareStatement(CHAR_INS_CHAR_FISHINGSTEPS, "INSERT INTO character_fishingsteps (guid, fishingSteps) VALUES (?, ?)", CONNECTION_ASYNC);
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 82cbb0ab5af..a36ac7b266d 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -496,6 +496,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
// base stats and related field values
InitStatsForLevel();
InitTaxiNodesForLevel();
+ InitGlyphsForLevel();
InitTalentForLevel();
InitializeSkillFields();
InitPrimaryProfessions(); // to max set before any spell added
@@ -2366,6 +2367,7 @@ void Player::GiveLevel(uint8 level)
SetCreateHealth(0);
SetCreateMana(basemana);
+ InitGlyphsForLevel();
InitTalentForLevel();
InitTaxiNodesForLevel();
@@ -17715,6 +17717,7 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
// reset stats before loading any modifiers
InitStatsForLevel();
+ InitGlyphsForLevel();
InitTaxiNodesForLevel();
InitRunes();
@@ -18195,7 +18198,12 @@ void Player::_LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effe
void Player::_LoadGlyphAuras()
{
for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup()))
+ {
+ if (!glyphId)
+ continue;
+
CastSpell(this, sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID, true);
+ }
}
void Player::LoadCorpse(PreparedQueryResult result)
@@ -25564,6 +25572,36 @@ int64 Player::GetBarberShopCost(Trinity::IteratorPair<UF::ChrCustomizationChoice
return cost;
}
+void Player::InitGlyphsForLevel()
+{
+ for (GlyphSlotEntry const* glyphSlot : sGlyphSlotStore)
+ if (glyphSlot->Tooltip)
+ SetGlyphSlot(glyphSlot->Tooltip - 1, glyphSlot->ID);
+
+ uint8 level = GetLevel();
+ uint32 value = 0;
+
+ // 0x3F = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 for 80 level
+ if (level >= 15)
+ value |= (0x01 | 0x02);
+ if (level >= 30)
+ value |= 0x08;
+ if (level >= 50)
+ value |= 0x04;
+ if (level >= 70)
+ value |= 0x10;
+ if (level >= 80)
+ value |= 0x20;
+
+ SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::GlyphsEnabled), value);
+}
+
+void Player::SetGlyph(uint8 slot, uint32 glyph)
+{
+ GetGlyphs(GetActiveTalentGroup())[slot] = glyph;
+ SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::Glyphs, slot), glyph);
+}
+
bool Player::isTotalImmune() const
{
AuraEffectList const& immune = GetAuraEffectsByType(SPELL_AURA_SCHOOL_IMMUNITY);
@@ -26422,10 +26460,7 @@ void Player::SendTalentsInfoData()
groupInfo.Talents.push_back({ pair.first, pair.second.Rank });
}
- std::vector<uint32> glyphs = GetGlyphs(activeGroup);
- glyphs.resize(MAX_GLYPH_SLOT_INDEX, 0); // Blizzard always sends 6 glyph slots, no matter if they are used or not
- groupInfo.GlyphIDs.reserve(MAX_GLYPH_SLOT_INDEX);
- for (uint32 glyph : glyphs)
+ for (uint32 glyph : GetGlyphs(activeGroup))
groupInfo.GlyphIDs.push_back(glyph);
}
@@ -26651,7 +26686,7 @@ void Player::SetMap(Map* map)
void Player::_LoadGlyphs(PreparedQueryResult result)
{
- // SELECT talentGroup, glyphId from character_glyphs WHERE guid = ?
+ // SELECT talentGroup, glyphSlot, glyphId from character_glyphs WHERE guid = ?
if (!result)
return;
@@ -26659,15 +26694,19 @@ void Player::_LoadGlyphs(PreparedQueryResult result)
{
Field* fields = result->Fetch();
- uint8 spec = fields[0].GetUInt8();
- if (spec >= MAX_SPECIALIZATIONS || !sDB2Manager.GetChrSpecializationByIndex(GetClass(), spec))
+ uint8 talentGroupId = fields[0].GetUInt8();
+ if (talentGroupId >= MAX_SPECIALIZATIONS)
+ continue;
+
+ uint8 glyphSlot = fields[1].GetUInt8();
+ if (glyphSlot >= MAX_GLYPH_SLOT_INDEX)
continue;
- uint16 glyphId = fields[1].GetUInt16();
+ uint16 glyphId = fields[2].GetUInt16();
if (!sGlyphPropertiesStore.LookupEntry(glyphId))
continue;
- GetGlyphs(spec).push_back(glyphId);
+ SetGlyph(glyphSlot, glyphId);
} while (result->NextRow());
}
@@ -26680,13 +26719,14 @@ void Player::_SaveGlyphs(CharacterDatabaseTransaction trans) const
for (uint8 spec = 0; spec < MAX_SPECIALIZATIONS; ++spec)
{
- for (uint32 glyphId : GetGlyphs(spec))
+ for (uint8 i = 0; i < GetGlyphs(spec).size(); ++i)
{
uint8 index = 0;
-
+ uint32 glyphId = GetGlyphs(spec)[i];
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS);
stmt->setUInt64(index++, GetGUID().GetCounter());
stmt->setUInt8(index++, spec);
+ stmt->setUInt8(index++, i);
stmt->setUInt16(index++, uint16(glyphId));
trans->Append(stmt);
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 1a42b8011be..eea3d9a3896 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -1055,10 +1055,13 @@ struct GroupUpdateCounter
struct TC_GAME_API SpecializationInfo
{
- SpecializationInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), BonusGroups(0) { }
+ SpecializationInfo() : ResetTalentsCost(0), ResetTalentsTime(0), ActiveGroup(0), BonusGroups(0)
+ {
+ Glyphs.fill({});
+ }
PlayerTalentMap Talents[MAX_SPECIALIZATIONS];
- std::vector<uint32> Glyphs[MAX_SPECIALIZATIONS];
+ std::array<std::array<uint32, MAX_GLYPH_SLOT_INDEX>, MAX_SPECIALIZATIONS > Glyphs;
uint32 ResetTalentsCost;
time_t ResetTalentsTime;
uint8 ActiveGroup;
@@ -1811,6 +1814,9 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
PlayerTalentMap const& GetPlayerTalentMap(uint8 talentGroupId) const { return _specializationInfo.Talents[talentGroupId]; }
PlayerTalentMap& GetPlayerTalentMap(uint8 talentGroupId) { return _specializationInfo.Talents[talentGroupId]; }
+ std::array<uint32, MAX_GLYPH_SLOT_INDEX>& GetGlyphs(uint8 talentGroupId) { return _specializationInfo.Glyphs[talentGroupId]; }
+ std::array<uint32, MAX_GLYPH_SLOT_INDEX> const& GetGlyphs(uint8 talentGroupId) const { return _specializationInfo.Glyphs[talentGroupId]; }
+
ChrSpecialization GetPrimarySpecialization() const { return ChrSpecialization(*m_playerData->CurrentSpecID); }
void SetPrimarySpecialization(uint32 spec) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::CurrentSpecID), spec); }
uint8 GetActiveTalentGroup() const { return _specializationInfo.ActiveGroup; }
@@ -1824,6 +1830,11 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
bool ResetTalents(bool noCost = false);
uint32 GetNextResetTalentsCost() const;
void InitTalentForLevel();
+ void InitGlyphsForLevel();
+ void SetGlyph(uint8 slot, uint32 glyph);
+ uint32 GetGlyph(uint8 slot) const { return m_activePlayerData->Glyphs[slot]; }
+ void SetGlyphSlot(uint8 slot, uint32 id) { SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData).ModifyValue(&UF::ActivePlayerData::GlyphSlots, slot), id); }
+ uint32 GetGlyphSlot(uint8 slot) const { return m_activePlayerData->GlyphSlots[slot]; }
void SendTalentsInfoData();
uint32 CalculateTalentsPoints() const;
bool LearnTalent(uint32 talentId, uint8 requestedRank);
@@ -1839,8 +1850,6 @@ class TC_GAME_API Player : public Unit, public GridObject<Player>
// Dual Spec
void ActivateTalentGroup(uint8 talentGroup);
- std::vector<uint32> const& GetGlyphs(uint8 spec) const { return _specializationInfo.Glyphs[spec]; }
- std::vector<uint32>& GetGlyphs(uint8 spec) { return _specializationInfo.Glyphs[spec]; }
ActionButtonList const& GetActionButtons() const { return m_actionButtons; }
void StartLoadingActionButtons(std::function<void()>&& callback = nullptr);
void LoadActions(PreparedQueryResult result);
diff --git a/src/server/game/Handlers/SkillHandler.cpp b/src/server/game/Handlers/SkillHandler.cpp
index 77471c3b350..c86725d2a52 100644
--- a/src/server/game/Handlers/SkillHandler.cpp
+++ b/src/server/game/Handlers/SkillHandler.cpp
@@ -84,3 +84,22 @@ void WorldSession::HandleTradeSkillSetFavorite(WorldPackets::Spells::TradeSkillS
_player->SetSpellFavorite(tradeSkillSetFavorite.RecipeID, tradeSkillSetFavorite.IsFavorite);
}
+
+void WorldSession::HandleRemoveGlyphOpcode(WorldPackets::Talent::RemoveGlyph& packet)
+{
+ if (packet.GlyphSlot >= MAX_GLYPH_SLOT_INDEX)
+ {
+ TC_LOG_DEBUG("network", "Client sent wrong glyph slot number in opcode CMSG_REMOVE_GLYPH {}", packet.GlyphSlot);
+ return;
+ }
+
+ if (uint32 glyph = _player->GetGlyph(packet.GlyphSlot))
+ {
+ if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyph))
+ {
+ _player->RemoveAurasDueToSpell(gp->SpellID);
+ _player->SetGlyph(packet.GlyphSlot, 0);
+ _player->SendTalentsInfoData();
+ }
+ }
+}
diff --git a/src/server/game/Server/Packets/TalentPackets.cpp b/src/server/game/Server/Packets/TalentPackets.cpp
index 4237f45f7c7..d223af5f95c 100644
--- a/src/server/game/Server/Packets/TalentPackets.cpp
+++ b/src/server/game/Server/Packets/TalentPackets.cpp
@@ -145,3 +145,8 @@ WorldPacket const* WorldPackets::Talent::LearnPvpTalentFailed::Write()
return &_worldPacket;
}
+
+void WorldPackets::Talent::RemoveGlyph::Read()
+{
+ _worldPacket >> GlyphSlot;
+}
diff --git a/src/server/game/Server/Packets/TalentPackets.h b/src/server/game/Server/Packets/TalentPackets.h
index 9bcd2418ca9..cbee012a09b 100644
--- a/src/server/game/Server/Packets/TalentPackets.h
+++ b/src/server/game/Server/Packets/TalentPackets.h
@@ -154,6 +154,16 @@ namespace WorldPackets
int32 TalentID = 0;
uint16 RequestedRank = 0;
};
+
+ class RemoveGlyph final : public ClientPacket
+ {
+ public:
+ RemoveGlyph(WorldPacket&& packet) : ClientPacket(CMSG_REMOVE_GLYPH, std::move(packet)) { }
+
+ void Read() override;
+
+ uint8 GlyphSlot = 0;
+ };
}
}
diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp
index 82b7ddd7c7f..d6260702863 100644
--- a/src/server/game/Server/Protocol/Opcodes.cpp
+++ b/src/server/game/Server/Protocol/Opcodes.cpp
@@ -802,7 +802,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_READY_CHECK_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleReadyCheckResponseOpcode);
DEFINE_HANDLER(CMSG_READ_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleReadItem);
DEFINE_HANDLER(CMSG_RECLAIM_CORPSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleReclaimCorpse);
- DEFINE_HANDLER(CMSG_REMOVE_GLYPH, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
+ DEFINE_HANDLER(CMSG_REMOVE_GLYPH, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleRemoveGlyphOpcode);
DEFINE_HANDLER(CMSG_REMOVE_NEW_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleRemoveNewItem);
DEFINE_HANDLER(CMSG_REMOVE_RAF_RECRUIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_REORDER_CHARACTERS, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleReorderCharacters);
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index c974768ff78..6c194c64e89 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -737,6 +737,7 @@ namespace WorldPackets
class LearnTalents;
class LearnPvpTalents;
class ConfirmRespecWipe;
+ class RemoveGlyph;
}
namespace Taxi
@@ -1519,6 +1520,7 @@ class TC_GAME_API WorldSession
void HandleConfirmRespecWipeOpcode(WorldPackets::Talent::ConfirmRespecWipe& confirmRespecWipe);
void HandleUnlearnSkillOpcode(WorldPackets::Spells::UnlearnSkill& packet);
void HandleTradeSkillSetFavorite(WorldPackets::Spells::TradeSkillSetFavorite const& tradeSkillSetFavorite);
+ void HandleRemoveGlyphOpcode(WorldPackets::Talent::RemoveGlyph& packet);
void HandleTraitsCommitConfig(WorldPackets::Traits::TraitsCommitConfig const& traitsCommitConfig);
void HandleClassTalentsRequestNewConfig(WorldPackets::Traits::ClassTalentsRequestNewConfig& classTalentsRequestNewConfig);
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 88375d16867..22efe8e516c 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -6073,55 +6073,12 @@ SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32
return SPELL_FAILED_GLYPH_NO_SPEC;
Player* caster = m_caster->ToPlayer();
- if (!caster->HasSpell(m_misc.SpellId))
- return SPELL_FAILED_NOT_KNOWN;
if (uint32 glyphId = spellEffectInfo.MiscValue)
{
GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId);
if (!glyphProperties)
return SPELL_FAILED_INVALID_GLYPH;
-
- std::vector<uint32> const* glyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId);
- if (!glyphBindableSpells)
- return SPELL_FAILED_INVALID_GLYPH;
-
- if (std::find(glyphBindableSpells->begin(), glyphBindableSpells->end(), m_misc.SpellId) == glyphBindableSpells->end())
- return SPELL_FAILED_INVALID_GLYPH;
-
- if (std::vector<ChrSpecialization> const* glyphRequiredSpecs = sDB2Manager.GetGlyphRequiredSpecs(glyphId))
- {
- if (caster->GetPrimarySpecialization() == ChrSpecialization::None)
- return SPELL_FAILED_GLYPH_NO_SPEC;
-
- if (std::find(glyphRequiredSpecs->begin(), glyphRequiredSpecs->end(), caster->GetPrimarySpecialization()) == glyphRequiredSpecs->end())
- return SPELL_FAILED_GLYPH_INVALID_SPEC;
- }
-
- uint32 replacedGlyph = 0;
- for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
- {
- if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(activeGlyphId))
- {
- if (std::find(activeGlyphBindableSpells->begin(), activeGlyphBindableSpells->end(), m_misc.SpellId) != activeGlyphBindableSpells->end())
- {
- replacedGlyph = activeGlyphId;
- break;
- }
- }
- }
-
- for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
- {
- if (activeGlyphId == replacedGlyph)
- continue;
-
- if (activeGlyphId == glyphId)
- return SPELL_FAILED_UNIQUE_GLYPH;
-
- if (sGlyphPropertiesStore.AssertEntry(activeGlyphId)->GlyphExclusiveCategoryID == glyphProperties->GlyphExclusiveCategoryID)
- return SPELL_FAILED_GLYPH_EXCLUSIVE_CATEGORY;
- }
}
break;
}
@@ -7298,10 +7255,10 @@ SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*=
if (!proto)
return SPELL_FAILED_ITEM_NOT_READY;
- for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
- if (itemEffect->LegacySlotIndex < m_CastItem->m_itemData->SpellCharges.size() && itemEffect->Charges)
- if (m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex) == 0)
- return SPELL_FAILED_NO_CHARGES_REMAIN;
+ //for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
+ // if (itemEffect->LegacySlotIndex < m_CastItem->m_itemData->SpellCharges.size() && itemEffect->Charges)
+ // if (m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex) == 0)
+ // return SPELL_FAILED_NO_CHARGES_REMAIN;
// consumable cast item checks
if (proto->GetClass() == ITEM_CLASS_CONSUMABLE && m_targets.GetUnitTarget())
diff --git a/src/server/game/Spells/Spell.h b/src/server/game/Spells/Spell.h
index f8026844fbc..83b6e671e90 100644
--- a/src/server/game/Spells/Spell.h
+++ b/src/server/game/Spells/Spell.h
@@ -567,7 +567,7 @@ class TC_GAME_API Spell
uint32 TalentId;
// SPELL_EFFECT_APPLY_GLYPH
- uint32 SpellId;
+ uint32 GlyphSlot;
// SPELL_EFFECT_TALENT_SPEC_SELECT
uint32 SpecializationId;
diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp
index 56a44e0db6a..98017210f0b 100644
--- a/src/server/game/Spells/SpellEffects.cpp
+++ b/src/server/game/Spells/SpellEffects.cpp
@@ -3325,45 +3325,63 @@ void Spell::EffectApplyGlyph()
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
return;
+ if (m_misc.GlyphSlot >= MAX_GLYPH_SLOT_INDEX)
+ return;
+
Player* player = m_caster->ToPlayer();
if (!player)
return;
- std::vector<uint32>& glyphs = player->GetGlyphs(player->GetActiveTalentGroup());
- std::size_t replacedGlyph = glyphs.size();
- for (std::size_t i = 0; i < glyphs.size(); ++i)
+ // glyph sockets level requirement
+ uint8 minLevel = 0;
+ switch (m_misc.GlyphSlot)
{
- if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphs[i]))
- {
- if (std::find(activeGlyphBindableSpells->begin(), activeGlyphBindableSpells->end(), m_misc.SpellId) != activeGlyphBindableSpells->end())
- {
- replacedGlyph = i;
- player->RemoveAurasDueToSpell(sGlyphPropertiesStore.AssertEntry(glyphs[i])->SpellID);
- break;
- }
- }
+ case 0:
+ case 1: minLevel = 15; break;
+ case 2: minLevel = 50; break;
+ case 3: minLevel = 30; break;
+ case 4: minLevel = 70; break;
+ case 5: minLevel = 80; break;
+ }
+
+ if (minLevel && player->GetLevel() < minLevel)
+ {
+ SendCastResult(SPELL_FAILED_GLYPH_SOCKET_LOCKED);
+ return;
}
uint32 glyphId = effectInfo->MiscValue;
- if (replacedGlyph < glyphs.size())
+ if (!glyphId)
+ return;
+
+ GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId);
+ if (!glyphProperties)
+ return;
+
+ if (GlyphSlotEntry const* glyphSlotEntry = sGlyphSlotStore.LookupEntry(player->GetGlyphSlot(m_misc.GlyphSlot)))
{
- if (glyphId)
- glyphs[replacedGlyph] = glyphId;
- else
- glyphs.erase(glyphs.begin() + replacedGlyph);
+ if (glyphProperties->GlyphSlotFlags != glyphSlotEntry->Type)
+ {
+ SendCastResult(SPELL_FAILED_INVALID_GLYPH);
+ return; // glyph slot mismatch
+ }
}
- else if (glyphId)
- glyphs.push_back(glyphId);
- player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::ChangeGlyph);
+ // remove old glyph
+ if (uint32 oldglyph = player->GetGlyph(m_misc.GlyphSlot))
+ {
+ if (GlyphPropertiesEntry const* oldGp = sGlyphPropertiesStore.LookupEntry(oldglyph))
+ {
+ player->RemoveAurasDueToSpell(oldGp->SpellID);
+ player->SetGlyph(m_misc.GlyphSlot, 0);
+ }
+ }
- if (GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId))
- player->CastSpell(player, glyphProperties->SpellID, this);
+ player->CastSpell(player, glyphProperties->SpellID, this);
+ player->SetGlyph(m_misc.GlyphSlot, glyphId);
+ player->SendTalentsInfoData();
- WorldPackets::Talent::ActiveGlyphs activeGlyphs;
- activeGlyphs.Glyphs.emplace_back(m_misc.SpellId, uint16(glyphId));
- activeGlyphs.IsFullUpdate = false;
- player->SendDirectMessage(activeGlyphs.Write());
+ player->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags2::ChangeGlyph);
}
void Spell::EffectEnchantHeldItem()