diff options
| author | Ovahlord <dreadkiller@gmx.de> | 2023-11-21 23:59:42 +0100 |
|---|---|---|
| committer | Ovahlord <dreadkiller@gmx.de> | 2023-11-21 23:59:42 +0100 |
| commit | f08213a005ca651948be417b48cb731e84f01505 (patch) | |
| tree | 7cfa4028ca310dbede2b087e310afa751f5b3f76 /src/server/game | |
| parent | 8605fd8851d22fad908a6998d61ef808458fabd6 (diff) | |
Core/Players: downgraded the glyph system
Diffstat (limited to 'src/server/game')
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 62 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 17 | ||||
| -rw-r--r-- | src/server/game/Handlers/SkillHandler.cpp | 19 | ||||
| -rw-r--r-- | src/server/game/Server/Packets/TalentPackets.cpp | 5 | ||||
| -rw-r--r-- | src/server/game/Server/Packets/TalentPackets.h | 10 | ||||
| -rw-r--r-- | src/server/game/Server/Protocol/Opcodes.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.h | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 51 | ||||
| -rw-r--r-- | src/server/game/Spells/Spell.h | 2 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 70 |
10 files changed, 150 insertions, 90 deletions
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() |
