TrinityCore
Player.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "Player.h"
19#include "AreaTrigger.h"
20#include "AccountMgr.h"
21#include "AchievementMgr.h"
22#include "ArenaTeam.h"
23#include "ArenaTeamMgr.h"
25#include "AzeriteItem.h"
26#include "Bag.h"
27#include "Battlefield.h"
28#include "BattlefieldMgr.h"
29#include "Battleground.h"
30#include "BattlegroundMgr.h"
31#include "BattlegroundPackets.h"
32#include "BattlegroundScore.h"
33#include "BattlePetMgr.h"
34#include "CellImpl.h"
35#include "Channel.h"
36#include "ChannelMgr.h"
37#include "CharacterCache.h"
40#include "CharacterPackets.h"
41#include "CharmInfo.h"
42#include "Chat.h"
43#include "ChatPackets.h"
44#include "ChatTextBuilder.h"
45#include "CinematicMgr.h"
46#include "ClubUtils.h"
47#include "CombatLogPackets.h"
48#include "CombatPackets.h"
49#include "Common.h"
50#include "ConditionMgr.h"
51#include "Containers.h"
52#include "CreatureAI.h"
53#include "DB2Stores.h"
54#include "DatabaseEnv.h"
55#include "DisableMgr.h"
56#include "DuelPackets.h"
57#include "EquipmentSetPackets.h"
58#include "Formulas.h"
59#include "GameEventMgr.h"
60#include "GameEventSender.h"
61#include "GameObjectAI.h"
62#include "Garrison.h"
63#include "GarrisonMgr.h"
64#include "GitRevision.h"
65#include "GossipDef.h"
66#include "GridNotifiers.h"
67#include "GridNotifiersImpl.h"
68#include "Group.h"
69#include "GroupMgr.h"
70#include "GameTables.h"
71#include "GameTime.h"
72#include "Guild.h"
73#include "GuildMgr.h"
74#include "InstanceLockMgr.h"
75#include "InstancePackets.h"
76#include "InstanceScript.h"
77#include "ItemPackets.h"
78#include "Language.h"
79#include "LanguageMgr.h"
80#include "LFGMgr.h"
81#include "Log.h"
82#include "Loot.h"
83#include "LootItemStorage.h"
84#include "LootMgr.h"
85#include "LootPackets.h"
86#include "Mail.h"
87#include "MailPackets.h"
88#include "MapManager.h"
89#include "MiscPackets.h"
90#include "MotionMaster.h"
91#include "MovementPackets.h"
92#include "ObjectAccessor.h"
93#include "ObjectMgr.h"
94#include "Opcodes.h"
95#include "OutdoorPvP.h"
96#include "OutdoorPvPMgr.h"
97#include "PartyPackets.h"
98#include "Pet.h"
99#include "PetPackets.h"
100#include "PoolMgr.h"
101#include "PetitionMgr.h"
102#include "PhasingHandler.h"
103#include "QueryCallback.h"
104#include "QueryHolder.h"
105#include "QuestDef.h"
107#include "QuestPackets.h"
108#include "RealmList.h"
109#include "ReputationMgr.h"
110#include "RestMgr.h"
111#include "Scenario.h"
112#include "SkillDiscovery.h"
113#include "SocialMgr.h"
114#include "Spell.h"
115#include "SpellAuraEffects.h"
116#include "SpellAuras.h"
117#include "SpellCastRequest.h"
118#include "SpellHistory.h"
119#include "SpellMgr.h"
120#include "SpellPackets.h"
121#include "StringConvert.h"
122#include "TalentPackets.h"
123#include "TerrainMgr.h"
124#include "ToyPackets.h"
125#include "TradeData.h"
126#include "TraitMgr.h"
127#include "TraitPacketsCommon.h"
128#include "Transport.h"
129#include "UpdateData.h"
130#include "Util.h"
131#include "Vehicle.h"
132#include "VehiclePackets.h"
133#include "Vignette.h"
134#include "VignettePackets.h"
135#include "World.h"
136#include "WorldPacket.h"
137#include "WorldSession.h"
138#include "WorldStateMgr.h"
139#include "WorldStatePackets.h"
140#include <G3D/g3dmath.h>
141#include <sstream>
142
143#define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS)
144
145// corpse reclaim times
146#define DEATH_EXPIRE_STEP (5*MINUTE)
147#define MAX_DEATH_COUNT 3
148
150{
155
156static uint32 copseReclaimDelay[MAX_DEATH_COUNT] = { 30, 60, 120 };
157
158uint64 const MAX_MONEY_AMOUNT = 99999999999ULL;
159
160Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this)
161{
164
165 m_session = session;
166
167 m_modMeleeHitChance = 7.5f;
169 m_modSpellHitChance = 15.0f;
170
171 m_ingametime = 0;
172 m_sharedQuestId = 0;
173
174 m_ExtraFlags = 0;
175
176 m_spellModTakingSpell = nullptr;
177
178 // players always accept
179 if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS))
180 SetAcceptWhispers(true);
181
183 m_regenTimer = 0;
187
190
191 m_areaUpdateId = 0;
193
194 m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE);
196
197 memset(m_items, 0, sizeof(Item*)*PLAYER_SLOTS_COUNT);
198
199 m_social = nullptr;
200
201 // group is initialized in the reference constructor
202 SetGroupInvite(nullptr);
204 m_bPassOnGroupLoot = false;
205
208
210
213
215 m_bCanDelayTeleport = false;
216 m_bHasDelayedTeleport = false;
218
219 m_trade = nullptr;
220
221 m_createTime = 0;
223 m_cinematic = 0;
224
225 m_movie = 0;
226
227 PlayerTalkClass = std::make_unique<PlayerMenu>(GetSession());
229
230 m_DailyQuestChanged = false;
232
236
238 m_drunkTimer = 0;
239 m_deathTimer = 0;
241
242 for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j)
243 {
247 }
248
251 m_Played_time = { };
254 m_canParry = false;
255 m_canBlock = false;
256 m_canTitanGrip = false;
258
260 //cache for CreatedBySpell to allow
261 //returning reagents for temporarily removed pets
262 //when dying/logging out
263 m_oldpetspell = 0;
264 m_lastpetnumber = 0;
265
266 m_mailsUpdated = false;
267 unReadMails = 0;
269
271
273
275
277
278 m_HomebindTimer = 0;
279 m_InstanceValid = true;
283
284 m_lastPotionId = 0;
285
286 m_auraBaseFlatMod.fill(0.0f);
287 m_auraBasePctMod.fill(1.0f);
288 m_baseRatingValue = { };
289
291 m_baseManaRegen = 0;
294
295 // Honor System
297
298 m_IsBGRandomWinner = false;
299
300 // Player summoning
301 m_summon_expire = 0;
303
305
306 m_unitMovedByMe = this;
307 m_playerMovingMe = this;
308 m_seer = this;
309
311
313
314 m_isActive = true;
315
316 m_lastFallTime = 0;
317 m_lastFallZ = 0;
318
319 m_fishingSteps = 0;
320
322
323 sWorld->IncreasePlayerCount();
324
326
327 m_powerFraction.fill(0.0f);
328
329 isDebugAreaTriggers = false;
330
331 m_WeeklyQuestChanged = false;
332 m_MonthlyQuestChanged = false;
334
335 SetPendingBind(0, 0);
336
339 manaBeforeDuel = 0;
340
342
343 _cinematicMgr = std::make_unique<CinematicMgr>(this);
344
345 m_achievementMgr = std::make_unique<PlayerAchievementMgr>(this);
346 m_reputationMgr = std::make_unique<ReputationMgr>(this);
347 m_questObjectiveCriteriaMgr = std::make_unique<QuestObjectiveCriteriaMgr>(this);
348
349 for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i)
350 _CUFProfiles[i] = nullptr;
351
353
355
356 _restMgr = std::make_unique<RestMgr>(this);
357
358 _usePvpItemLevels = false;
359}
360
362{
363 // it must be unloaded already in PlayerLogout and accessed only for logged in player
364 //m_social = nullptr;
365
366 // Note: buy back item already deleted from DB when player was saved
367 for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; ++i)
368 delete m_items[i];
369
370 //all mailed items should be deleted, also all mail should be deallocated
371 for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
372 delete *itr;
373
374 for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
375 delete iter->second; //if item is duplicated... then server may crash ... but that item should be deallocated
376
377 for (size_t x = 0; x < ItemSetEff.size(); x++)
378 delete ItemSetEff[x];
379
380 for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
381 delete _voidStorageItems[i];
382
383 sWorld->DecreasePlayerCount();
384}
385
386void Player::CleanupsBeforeDelete(bool finalCleanup)
387{
388 TradeCancel(false);
390
391 Unit::CleanupsBeforeDelete(finalCleanup);
392}
393
395{
396 //FIXME: outfitId not used in player creating
398
399 Object::_Create(ObjectGuid::Create<HighGuid::Player>(guidlow));
400
401 m_name = createInfo->Name;
402
403 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(createInfo->Race, createInfo->Class);
404 if (!info)
405 {
406 TC_LOG_ERROR("entities.player.cheat", "Player::Create: Possible hacking attempt: Account {} tried to create a character named '{}' with an invalid race/class pair ({}/{}) - refusing to do so.",
407 GetSession()->GetAccountId(), m_name, createInfo->Race, createInfo->Class);
408 return false;
409 }
410
411 for (uint8 i = 0; i < PLAYER_SLOTS_COUNT; i++)
412 m_items[i] = nullptr;
413
414 ChrClassesEntry const* cEntry = sChrClassesStore.LookupEntry(createInfo->Class);
415 if (!cEntry)
416 {
417 TC_LOG_ERROR("entities.player.cheat", "Player::Create: Possible hacking attempt: Account {} tried to create a character named '{}' with an invalid character class ({}) - refusing to do so (wrong DBC-files?)",
418 GetSession()->GetAccountId(), m_name, createInfo->Class);
419 return false;
420 }
421
422 if (!GetSession()->ValidateAppearance(Races(createInfo->Race), Classes(createInfo->Class), Gender(createInfo->Sex), MakeChrCustomizationChoiceRange(createInfo->Customizations)))
423 {
424 TC_LOG_ERROR("entities.player.cheat", "Player::Create: Possible hacking-attempt: Account {} tried creating a character named '{}' with invalid appearance attributes - refusing to do so",
425 GetSession()->GetAccountId(), m_name);
426 return false;
427 }
428
429 PlayerInfo::CreatePosition const& position = createInfo->UseNPE && info->createPositionNPE ? *info->createPositionNPE : info->createPosition;
430
433
434 Relocate(position.Loc);
435
436 SetMap(sMapMgr->CreateMap(position.Loc.GetMapId(), this));
437
438 if (position.TransportGuid)
439 {
440 if (Transport* transport = ObjectAccessor::GetTransport(*this, ObjectGuid::Create<HighGuid::Transport>(*position.TransportGuid)))
441 {
442 transport->AddPassenger(this);
444 float x, y, z, o;
445 position.Loc.GetPosition(x, y, z, o);
446 transport->CalculatePassengerPosition(x, y, z, &o);
447 Relocate(x, y, z, o);
448 }
449 }
450
451 // set initial homebind position
452 SetHomebind(*this, GetAreaId());
453
454 uint8 powertype = cEntry->DisplayPower;
455
456 SetObjectScale(1.0f);
457
458 SetFactionForRace(createInfo->Race);
459
460 if (!IsValidGender(createInfo->Sex))
461 {
462 TC_LOG_ERROR("entities.player.cheat", "Player::Create: Possible hacking attempt: Account {} tried to create a character named '{}' with an invalid gender ({}) - refusing to do so",
463 GetSession()->GetAccountId(), m_name, createInfo->Sex);
464 return false;
465 }
466
467 SetRace(createInfo->Race);
468 SetClass(createInfo->Class);
469 SetGender(Gender(createInfo->Sex));
470 SetPowerType(Powers(powertype), false);
472 if (sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_PVP || sWorld->getIntConfig(CONFIG_GAME_TYPE) == REALM_TYPE_RPPVP)
473 {
476 }
477
479
481
483 SetRestState(REST_TYPE_XP, (GetSession()->IsARecruiter() || GetSession()->GetRecruiterId() != 0) ? REST_STATE_RAF_LINKED : REST_STATE_NORMAL);
485 SetNativeGender(Gender(createInfo->Sex));
487
488 // set starting level
489 SetLevel(GetStartLevel(createInfo->Race, createInfo->Class, createInfo->TemplateSet));
490
491 InitRunes();
492
494
495 // Played time
499
500 // base stats and related field values
505 InitPrimaryProfessions(); // to max set before any spell added
506
507 // apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
508 UpdateMaxHealth(); // Update max Health (for add bonus from stamina)
511
512 // original spells
515
516 // Original action bar. Do not use Player::AddActionButton because we do not have skill spells loaded at this time
517 // but checks will still be performed later when loading character from db in Player::_LoadActions
518 for (PlayerCreateInfoActions::const_iterator action_itr = info->action.begin(); action_itr != info->action.end(); ++action_itr)
519 {
520 // create new button
521 ActionButton& ab = m_actionButtons[action_itr->button];
522
523 // set data
524 ab.SetActionAndType(action_itr->action, ActionButtonType(action_itr->type));
525 }
526
527 // original items
528 for (PlayerCreateInfoItem initialItem : info->item)
529 StoreNewItemInBestSlots(initialItem.item_id, initialItem.item_amount, info->itemContext);
530
531 // bags and main-hand weapon must equipped at this moment
532 // now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon)
533 // or ammo not equipped in special bag
535 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; i++)
536 {
537 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
538 {
539 uint16 eDest;
540 // equip offhand weapon/shield if it attempt equipped before main-hand weapon
541 InventoryResult msg = CanEquipItem(NULL_SLOT, eDest, pItem, false);
542 if (msg == EQUIP_ERR_OK)
543 {
545 EquipItem(eDest, pItem, true);
546 }
547 // move other items to more appropriate slots
548 else
549 {
550 ItemPosCountVec sDest;
551 msg = CanStoreItem(NULL_BAG, NULL_SLOT, sDest, pItem, false);
552 if (msg == EQUIP_ERR_OK)
553 {
555 StoreItem(sDest, pItem, true);
556 }
557 }
558 }
559 }
560 // all item positions resolved
561
562 if (ChrSpecializationEntry const* defaultSpec = sDB2Manager.GetDefaultChrSpecializationForClass(GetClass()))
563 {
564 SetActiveTalentGroup(defaultSpec->OrderIndex);
565 SetPrimarySpecialization(defaultSpec->ID);
566 }
567
569
570 return true;
571}
572
574{
575 TC_LOG_DEBUG("entities.player.items", "Player::StoreNewItemInBestSlots: Player '{}' ({}) creates initial item (ItemID: {}, Count: {})",
576 GetName(), GetGUID().ToString(), itemId, amount);
577
578 // attempt equip by one
579 while (amount > 0)
580 {
581 uint16 eDest;
582 InventoryResult msg = CanEquipNewItem(NULL_SLOT, eDest, itemId, false);
583 if (msg != EQUIP_ERR_OK)
584 break;
585
586 EquipNewItem(eDest, itemId, context, true);
588 --amount;
589 }
590
591 if (amount == 0)
592 return true; // equipped
593
594 // attempt store
595 ItemPosCountVec sDest;
596 // store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
597 InventoryResult msg = CanStoreNewItem(INVENTORY_SLOT_BAG_0, NULL_SLOT, sDest, itemId, amount);
598 if (msg == EQUIP_ERR_OK)
599 {
600 StoreNewItem(sDest, itemId, true, GenerateItemRandomBonusListId(itemId), GuidSet(), context);
601 return true; // stored
602 }
603
604 // item can't be added
605 TC_LOG_ERROR("entities.player.items", "Player::StoreNewItemInBestSlots: Player '{}' ({}) can't equip or store initial item (ItemID: {}, Race: {}, Class: {}, InventoryResult: {})",
606 GetName(), GetGUID().ToString(), itemId, GetRace(), GetClass(), msg);
607 return false;
608}
609
610void Player::SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen)
611{
612 if (int(MaxValue) == DISABLED_MIRROR_TIMER)
613 {
614 if (int(CurrentValue) != DISABLED_MIRROR_TIMER)
616 return;
617 }
618
619 SendDirectMessage(WorldPackets::Misc::StartMirrorTimer(Type, CurrentValue, MaxValue, Regen, 0, false).Write());
620}
621
623{
626}
627
629{
630 // check for GM and death state included in isAttackableByAOE
631 return !isTargetableForAttack(false);
632}
633
635{
637 return 0;
638
640
641 // Absorb, resist some environmental damage type
642 uint32 absorb = 0;
643 uint32 resist = 0;
644 switch (type)
645 {
646 case DAMAGE_LAVA:
647 case DAMAGE_SLIME:
648 {
649 DamageInfo dmgInfo(this, this, damage, nullptr, type == DAMAGE_LAVA ? SPELL_SCHOOL_MASK_FIRE : SPELL_SCHOOL_MASK_NATURE, DIRECT_DAMAGE, BASE_ATTACK);
650 Unit::CalcAbsorbResist(dmgInfo);
651 absorb = dmgInfo.GetAbsorb();
652 resist = dmgInfo.GetResist();
653 damage = dmgInfo.GetDamage();
654 break;
655 }
656 default:
657 break;
658 }
659
660 Unit::DealDamageMods(nullptr, this, damage, &absorb);
661
663 packet.Victim = GetGUID();
664 packet.Type = type != DAMAGE_FALL_TO_VOID ? type : DAMAGE_FALL;
665 packet.Amount = damage;
666 packet.Absorbed = absorb;
667 packet.Resisted = resist;
668
669 uint32 final_damage = Unit::DealDamage(this, this, damage, nullptr, SELF_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, nullptr, false);
670
671 packet.LogData.Initialize(this);
672 SendCombatLogMessage(&packet);
673
674 if (!IsAlive())
675 {
676 if (type == DAMAGE_FALL) // DealDamage does not apply item durability loss from self-induced damage.
677 {
678 TC_LOG_DEBUG("entities.player", "Player::EnvironmentalDamage: Player '{}' ({}) fall to death, losing {}% durability",
681 // durability lost message
683 }
684
686 }
687
688 return final_damage;
689}
690
692{
693 switch (timer)
694 {
695 case FATIGUE_TIMER:
696 return MINUTE * IN_MILLISECONDS;
697 case BREATH_TIMER:
698 {
701
702 int32 UnderWaterTime = 3 * MINUTE * IN_MILLISECONDS;
704 return UnderWaterTime;
705 }
706 case FIRE_TIMER:
707 {
708 if (!IsAlive())
710 return 1 * IN_MILLISECONDS;
711 }
712 default:
713 return 0;
714 }
715}
716
718{
719 // Desync flags for update on next HandleDrowning
721 m_MirrorTimerFlagsLast = ~m_MirrorTimerFlags;
722}
723
725{
729}
730
732{
733 return m_MirrorTimer[type] == getMaxTimer(type);
734}
735
737{
739 return;
740
741 auto getEnvironmentalDamage = [&](EnviromentalDamage damageType)
742 {
743 uint8 damagePercent = 10;
744 if (damageType == DAMAGE_DROWNING || damageType == DAMAGE_EXHAUSTED)
745 damagePercent *= 2;
746
747 uint32 damage = GetMaxHealth() * damagePercent / 100;
748
749 // Randomize damage
750 damage += urand(0, pow(10, std::max(0, (int32)log10(damage) - 1)));
751
752 return damage;
753 };
754
755 // In water
757 {
758 // Breath timer not activated - activate it
760 {
763 }
764 else // If activated - do tick
765 {
766 m_MirrorTimer[BREATH_TIMER] -= time_diff;
767 // Timer limit - need deal damage
769 {
771 // Calculate and deal damage
772 uint32 damage = getEnvironmentalDamage(DAMAGE_DROWNING);
774 }
775 else if (!(m_MirrorTimerFlagsLast & UNDERWATER_INWATER)) // Update time in client if need
777 }
778 }
779 else if (m_MirrorTimer[BREATH_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
780 {
781 int32 UnderWaterTime = getMaxTimer(BREATH_TIMER);
782 // Need breath regen
783 m_MirrorTimer[BREATH_TIMER] += 10 * time_diff;
784 if (m_MirrorTimer[BREATH_TIMER] >= UnderWaterTime || !IsAlive())
788 }
789
790 // In dark water
792 {
793 // Fatigue timer not activated - activate it
795 {
798 }
799 else
800 {
801 m_MirrorTimer[FATIGUE_TIMER] -= time_diff;
802 // Timer limit - need deal damage or teleport ghost to graveyard
804 {
806 if (IsAlive()) // Calculate and deal damage
807 {
808 uint32 damage = getEnvironmentalDamage(DAMAGE_EXHAUSTED);
810 }
811 else if (HasPlayerFlag(PLAYER_FLAGS_GHOST)) // Teleport ghost to graveyard
813 }
816 }
817 }
818 else if (m_MirrorTimer[FATIGUE_TIMER] != DISABLED_MIRROR_TIMER) // Regen timer
819 {
820 int32 DarkWaterTime = getMaxTimer(FATIGUE_TIMER);
821 m_MirrorTimer[FATIGUE_TIMER] += 10 * time_diff;
822 if (m_MirrorTimer[FATIGUE_TIMER] >= DarkWaterTime || !IsAlive())
826 }
827
828 if (m_MirrorTimerFlags & (UNDERWATER_INLAVA /*| UNDERWATER_INSLIME*/) && !(_lastLiquid && _lastLiquid->SpellID))
829 {
830 // Breath timer not activated - activate it
833 else
834 {
835 m_MirrorTimer[FIRE_TIMER] -= time_diff;
836 if (m_MirrorTimer[FIRE_TIMER] < 0)
837 {
839 // Calculate and deal damage
840 uint32 damage = getEnvironmentalDamage(DAMAGE_LAVA);
843 // need to skip Slime damage in Undercity,
844 // maybe someone can find better way to handle environmental damage
845 //else if (m_zoneUpdateId != 1497)
846 // EnvironmentalDamage(DAMAGE_SLIME, damage);
847 }
848 }
849 }
850 else
852
853 // Recheck timers flag
854 m_MirrorTimerFlags &= ~UNDERWATER_EXIST_TIMERS;
855 for (uint8 i = 0; i < MAX_TIMERS; ++i)
856 {
858 {
860 break;
861 }
862 }
864}
865
868{
869 m_drunkTimer = 0;
870
871 uint8 currentDrunkValue = GetDrunkValue();
872 uint8 drunk = currentDrunkValue ? --currentDrunkValue : 0;
873 SetDrunkValue(drunk);
874}
875
877{
878 if (value >= 90)
879 return DRUNKEN_SMASHED;
880 if (value >= 50)
881 return DRUNKEN_DRUNK;
882 if (value)
883 return DRUNKEN_TIPSY;
884 return DRUNKEN_SOBER;
885}
886
887void Player::SetDrunkValue(uint8 newDrunkValue, uint32 itemId /*= 0*/)
888{
889 bool isSobering = newDrunkValue < GetDrunkValue();
891 if (newDrunkValue > 100)
892 newDrunkValue = 100;
893
894 // select drunk percent or total SPELL_AURA_MOD_FAKE_INEBRIATE amount, whichever is higher for visibility updates
895 int32 drunkPercent = std::max<int32>(newDrunkValue, GetTotalAuraModifier(SPELL_AURA_MOD_FAKE_INEBRIATE));
896 if (drunkPercent)
897 {
900 }
901 else if (!HasAuraType(SPELL_AURA_MOD_FAKE_INEBRIATE) && !newDrunkValue)
903
904 uint32 newDrunkenState = Player::GetDrunkenstateByValue(newDrunkValue);
907
908 if (!isSobering)
909 m_drunkTimer = 0; // reset sobering timer
910
911 if (newDrunkenState == oldDrunkenState)
912 return;
913
915 data.Guid = GetGUID();
916 data.Threshold = newDrunkenState;
917 data.ItemID = itemId;
918
919 SendMessageToSet(data.Write(), true);
920}
921
923{
924 if (!IsInWorld())
925 return;
926
927 // undelivered mail
929 {
930 SendNewMail();
931 ++unReadMails;
932
933 // It will be recalculate at mailbox open (for unReadMails important non-0 until mailbox open, it also will be recalculated)
935 }
936
937 // Update cinematic location, if 500ms have passed and we're doing a cinematic now.
938 _cinematicMgr->m_cinematicDiff += p_time;
939 if (_cinematicMgr->m_cinematicCamera && _cinematicMgr->m_activeCinematic && GetMSTimeDiffToNow(_cinematicMgr->m_lastCinematicCheck) > CINEMATIC_UPDATEDIFF)
940 {
941 _cinematicMgr->m_lastCinematicCheck = GameTime::GetGameTimeMS();
942 _cinematicMgr->UpdateCinematicLocation(p_time);
943 }
944
945 //used to implement delayed far teleport
947 Unit::Update(p_time);
948 SetCanDelayTeleport(false);
949
950 // Unit::Update updates the spell history and spell states. We can now check if we can launch another pending cast.
953
954 time_t now = GameTime::GetGameTime();
955
956 UpdatePvPFlag(now);
957
958 UpdateContestedPvP(p_time);
959
960 UpdateDuelFlag(now);
961
963
964 UpdateAfkReport(now);
965
966 if (GetCombatManager().HasPvPCombat())
968 if (!aura->IsPermanent())
969 aura->SetDuration(aura->GetSpellInfo()->GetMaxDuration());
970
971 Unit::AIUpdateTick(p_time);
972
973 // Update items that have just a limited lifetime
974 if (now > m_Last_tick)
976
977 // check every second
978 if (now > m_Last_tick + 1)
980
981 // If mute expired, remove it from the DB
982 if (GetSession()->m_muteTime && GetSession()->m_muteTime < now)
983 {
984 GetSession()->m_muteTime = 0;
986 stmt->setInt64(0, 0); // Set the mute time to 0
987 stmt->setString(1, "");
988 stmt->setString(2, "");
989 stmt->setUInt32(3, GetSession()->GetAccountId());
990 LoginDatabase.Execute(stmt);
991 }
992
993 if (!m_timedquests.empty())
994 {
995 QuestSet::iterator iter = m_timedquests.begin();
996 while (iter != m_timedquests.end())
997 {
998 QuestStatusData& q_status = m_QuestStatus[*iter];
999 if (q_status.Timer <= p_time)
1000 {
1001 uint32 quest_id = *iter;
1002 ++iter; // current iter will be removed in FailQuest
1003 FailQuest(quest_id);
1004 }
1005 else
1006 {
1007 q_status.Timer -= p_time;
1009 ++iter;
1010 }
1011 }
1012 }
1013
1014 m_achievementMgr->UpdateTimedCriteria(Milliseconds(p_time));
1015
1017
1019 _restMgr->Update(now);
1020
1021 if (m_weaponChangeTimer > 0)
1022 {
1023 if (p_time >= m_weaponChangeTimer)
1025 else
1026 m_weaponChangeTimer -= p_time;
1027 }
1028
1029 if (m_zoneUpdateTimer > 0)
1030 {
1031 if (p_time >= m_zoneUpdateTimer)
1032 {
1033 // On zone update tick check if we are still in an inn if we are supposed to be in one
1034 if (_restMgr->HasRestFlag(REST_FLAG_IN_TAVERN))
1035 {
1036 AreaTriggerEntry const* atEntry = sAreaTriggerStore.LookupEntry(_restMgr->GetInnTriggerID());
1037 if (!atEntry || !IsInAreaTriggerRadius(atEntry))
1038 _restMgr->RemoveRestFlag(REST_FLAG_IN_TAVERN);
1039 }
1040
1041 uint32 newzone, newarea;
1042 GetZoneAndAreaId(newzone, newarea);
1043
1044 if (m_zoneUpdateId != newzone)
1045 UpdateZone(newzone, newarea); // also update area
1046 else
1047 {
1048 // use area updates as well
1049 // needed for free far all arenas for example
1050 if (m_areaUpdateId != newarea)
1051 UpdateArea(newarea);
1052
1054 }
1055 }
1056 else
1057 m_zoneUpdateTimer -= p_time;
1058 }
1059
1060 if (IsAlive())
1061 {
1062 m_regenTimer += p_time;
1063 RegenerateAll();
1064 }
1065
1066 if (m_deathState == JUST_DIED)
1067 KillPlayer();
1068
1069 if (m_nextSave > 0)
1070 {
1071 if (p_time >= m_nextSave)
1072 {
1073 // m_nextSave reset in SaveToDB call
1074 SaveToDB();
1075 TC_LOG_DEBUG("entities.player", "Player::Update: Player '{}' ({}) saved", GetName(), GetGUID().ToString());
1076 }
1077 else
1078 m_nextSave -= p_time;
1079 }
1080
1081 //Handle Water/drowning
1082 HandleDrowning(p_time);
1083
1084 // Played time
1085 if (now > m_Last_tick)
1086 {
1087 uint32 elapsed = uint32(now - m_Last_tick);
1088 m_Played_time[PLAYED_TIME_TOTAL] += elapsed; // Total played time
1089 m_Played_time[PLAYED_TIME_LEVEL] += elapsed; // Level played time
1090 m_Last_tick = now;
1091 }
1092
1093 if (GetDrunkValue())
1094 {
1095 m_drunkTimer += p_time;
1096 if (m_drunkTimer > 9 * IN_MILLISECONDS)
1098 }
1099
1100 if (HasPendingBind())
1101 {
1102 if (_pendingBindTimer <= p_time)
1103 {
1104 // Player left the instance
1107 SetPendingBind(0, 0);
1108 }
1109 else
1110 _pendingBindTimer -= p_time;
1111 }
1112
1113 // not auto-free ghost from body in instances
1114 if (m_deathTimer > 0 && !GetMap()->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
1115 {
1116 if (p_time >= m_deathTimer)
1117 {
1118 m_deathTimer = 0;
1121 }
1122 else
1123 m_deathTimer -= p_time;
1124 }
1125
1126 UpdateEnchantTime(p_time);
1127 UpdateHomebindTime(p_time);
1128
1129 if (!_instanceResetTimes.empty())
1130 {
1131 for (InstanceTimeMap::iterator itr = _instanceResetTimes.begin(); itr != _instanceResetTimes.end();)
1132 {
1133 if (itr->second < now)
1134 _instanceResetTimes.erase(itr++);
1135 else
1136 ++itr;
1137 }
1138 }
1139
1140 // group update
1141 m_groupUpdateTimer.Update(p_time);
1143 {
1146 }
1147
1148 Pet* pet = GetPet();
1149 if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityRange()) && !pet->isPossessed())
1150 //if (pet && !pet->IsWithinDistInMap(this, GetMap()->GetVisibilityDistance()) && (GetCharmGUID() && (pet->GetGUID() != GetCharmGUID())))
1151 RemovePet(pet, PET_SAVE_NOT_IN_SLOT, true);
1152
1153 if (IsAlive())
1154 {
1155 if (m_hostileReferenceCheckTimer <= p_time)
1156 {
1158 if (!GetMap()->IsDungeon())
1160 }
1161 else
1163 }
1164
1165 //we should execute delayed teleports only for alive(!) players
1166 //because we don't want player's ghost teleported from graveyard
1167 if (IsHasDelayedTeleport() && IsAlive())
1169}
1170
1172{
1173 bool oldIsAlive = IsAlive();
1174
1175 if (s == JUST_DIED)
1176 {
1177 if (!oldIsAlive)
1178 {
1179 TC_LOG_ERROR("entities.player", "Player::setDeathState: Attempted to kill a dead player '{}' ({})", GetName(), GetGUID().ToString());
1180 return;
1181 }
1182
1183 // clear all pending spell cast requests when dying
1185
1186 // drunken state is cleared on death
1187 SetDrunkValue(0);
1189
1191
1192 //FIXME: is pet dismissed at dying or releasing spirit? if second, add setDeathState(DEAD) to HandleRepopRequest and define pet unsummon here with (s == DEAD)
1193 RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT, true);
1194
1196
1198
1202
1203 // reset all death criterias
1205 }
1206
1208
1209 if (IsAlive() && !oldIsAlive)
1210 //clear aura case after resurrection by another way (spells will be applied before next death)
1212}
1213
1215{
1216 if (isAFK())
1218 else
1220
1221 // afk player not allowed in battleground
1222 if (!IsGameMaster() && isAFK() && InBattleground() && !InArena())
1224}
1225
1227{
1228 if (isDND())
1230 else
1232}
1233
1235{
1236 uint16 tag = CHAT_FLAG_NONE;
1237
1238 if (isGMChat())
1239 tag |= CHAT_FLAG_GM;
1240 if (isDND())
1241 tag |= CHAT_FLAG_DND;
1242 if (isAFK())
1243 tag |= CHAT_FLAG_AFK;
1244 if (IsDeveloper())
1245 tag |= CHAT_FLAG_DEV;
1246
1247 return tag;
1248}
1249
1250bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options /*= TELE_TO_NONE*/, Optional<uint32> instanceId /*= {}*/)
1251{
1252 if (!MapManager::IsValidMapCoord(mapid, x, y, z, orientation))
1253 {
1254 TC_LOG_ERROR("maps", "Player::TeleportTo: Invalid map ({}) or invalid coordinates (X: {}, Y: {}, Z: {}, O: {}) given when teleporting player '{}' ({}, MapID: {}, X: {}, Y: {}, Z: {}, O: {}).",
1255 mapid, x, y, z, orientation, GetGUID().ToString(), GetName(), GetMapId(), GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation());
1256 return false;
1257 }
1258
1260 {
1261 TC_LOG_ERROR("entities.player.cheat", "Player::TeleportTo: Player '{}' ({}) tried to enter a forbidden map (MapID: {})", GetGUID().ToString(), GetName(), mapid);
1263 return false;
1264 }
1265
1266 // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later)
1267 Pet* pet = GetPet();
1268
1269 MapEntry const* mEntry = sMapStore.LookupEntry(mapid);
1270
1271 // don't let enter battlegrounds without assigned battleground id (for example through areatrigger)...
1272 // don't let gm level > 1 either
1273 if (!InBattleground() && mEntry->IsBattlegroundOrArena())
1274 return false;
1275
1276 // client without expansion support
1277 if (GetSession()->GetExpansion() < mEntry->Expansion())
1278 {
1279 TC_LOG_DEBUG("maps", "Player '{}' ({}) using client without required expansion tried teleporting to non accessible map (MapID: {})",
1280 GetName(), GetGUID().ToString(), mapid);
1281
1282 if (TransportBase* transport = GetTransport())
1283 {
1284 transport->RemovePassenger(this);
1285 RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
1286 }
1287
1289
1290 return false; // normal client can't teleport to this map...
1291 }
1292 else
1293 TC_LOG_DEBUG("maps", "Player {} ({}) is being teleported to map (MapID: {})", GetName(), GetGUID().ToString(), mapid);
1294
1295 if (m_vehicle)
1296 ExitVehicle();
1297
1298 // reset movement flags at teleport, because player will continue move with these flags after teleport
1301 DisableSpline();
1303
1304 if (TransportBase* transport = GetTransport())
1305 {
1306 if (!(options & TELE_TO_NOT_LEAVE_TRANSPORT))
1307 transport->RemovePassenger(this);
1308 }
1309
1310 // The player was ported to another map and loses the duel immediately.
1311 // We have to perform this check before the teleport, otherwise the
1312 // ObjectAccessor won't find the flag.
1313 if (duel && GetMapId() != mapid && GetMap()->GetGameObject(m_playerData->DuelArbiter))
1315
1316 if (GetMapId() == mapid && (!instanceId || GetInstanceId() == instanceId))
1317 {
1318 //lets reset far teleport flag if it wasn't reset during chained teleport
1320 //setup delayed teleport flag
1322 //if teleport spell is cast in Unit::Update() func
1323 //then we need to delay it until update process will be finished
1325 {
1327 //lets save teleport destination for player
1328 m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
1330 m_teleport_options = options;
1331 return true;
1332 }
1333
1334 if (!(options & TELE_TO_NOT_UNSUMMON_PET))
1335 {
1336 //same map, only remove pet if out of range for new position
1337 if (pet && !pet->IsWithinDist3d(x, y, z, GetMap()->GetVisibilityRange()))
1339 }
1340
1341 if (!IsAlive() && options & TELE_REVIVE_AT_TELEPORT)
1342 ResurrectPlayer(0.5f);
1343
1344 if (!(options & TELE_TO_NOT_LEAVE_COMBAT))
1345 CombatStop();
1346
1347 // this will be used instead of the current location in SaveToDB
1348 m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
1350 m_teleport_options = options;
1352
1353 // code for finish transfer called in WorldSession::HandleMovementOpcodes()
1354 // at client packet CMSG_MOVE_TELEPORT_ACK
1356 // near teleport, triggering send CMSG_MOVE_TELEPORT_ACK from client at landing
1357 if (!GetSession()->PlayerLogout())
1359 }
1360 else
1361 {
1362 if (GetClass() == CLASS_DEATH_KNIGHT && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977))
1363 {
1365 return false;
1366 }
1367
1368 // far teleport to another map
1369 Map* oldmap = IsInWorld() ? GetMap() : nullptr;
1370 // check if we can enter before stopping combat / removing pet / totems / interrupting spells
1371
1372 // Check enter rights before map getting to avoid creating instance copy for player
1373 // this check not dependent from map instance copy and same for all instance copies of selected map
1374 if (TransferAbortParams abortParams = Map::PlayerCannotEnter(mapid, this))
1375 {
1376 SendTransferAborted(mapid, abortParams.Reason, abortParams.Arg, abortParams.MapDifficultyXConditionId);
1377 return false;
1378 }
1379
1380 // Seamless teleport can happen only if cosmetic maps match
1381 if (!oldmap ||
1382 (oldmap->GetEntry()->CosmeticParentMapID != int32(mapid) && int32(GetMapId()) != mEntry->CosmeticParentMapID &&
1383 !((oldmap->GetEntry()->CosmeticParentMapID != -1) ^ (oldmap->GetEntry()->CosmeticParentMapID != mEntry->CosmeticParentMapID))))
1384 options &= ~TELE_TO_SEAMLESS;
1385
1386 //lets reset near teleport flag if it wasn't reset during chained teleports
1388 //setup delayed teleport flag
1390 //if teleport spell is cast in Unit::Update() func
1391 //then we need to delay it until update process will be finished
1393 {
1395 //lets save teleport destination for player
1396 m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
1397 m_teleport_instanceId = instanceId;
1398 m_teleport_options = options;
1399 return true;
1400 }
1401
1403
1404 CombatStop();
1405
1407
1408 // remove player from battleground on far teleport (when changing maps)
1409 if (Battleground const* bg = GetBattleground())
1410 {
1411 // Note: at battleground join battleground id set before teleport
1412 // and we already will found "current" battleground
1413 // just need check that this is targeted map or leave
1414 if (bg->GetMapId() != mapid)
1415 LeaveBattleground(false); // don't teleport to entry point
1416 }
1417
1418 // remove arena spell coldowns/buffs now to also remove pet's cooldowns before it's temporarily unsummoned
1419 if (mEntry->IsBattleArena() && !IsGameMaster())
1420 {
1423 if (pet)
1424 pet->RemoveArenaAuras();
1425 }
1426
1427 // remove pet on map change
1428 if (pet)
1430
1431 // remove all dyn objects
1433
1434 // remove all areatriggers entities
1436
1437 // stop spellcasting
1438 // not attempt interrupt teleportation spell at caster teleport
1439 if (!(options & TELE_TO_SPELL))
1440 if (IsNonMeleeSpellCast(true))
1442
1443 //remove auras before removing from map...
1445
1446 if (!GetSession()->PlayerLogout() && !(options & TELE_TO_SEAMLESS))
1447 {
1448 // send transfer packets
1450 transferPending.MapID = mapid;
1451 transferPending.OldMapPosition = GetPosition();
1452 if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
1453 {
1454 transferPending.Ship.emplace();
1455 transferPending.Ship->ID = transport->GetEntry();
1456 transferPending.Ship->OriginMapID = GetMapId();
1457 }
1458
1459 SendDirectMessage(transferPending.Write());
1460
1463 }
1464
1465 // remove from old map now
1466 if (oldmap)
1467 oldmap->RemovePlayerFromMap(this, false);
1468
1469 m_teleport_dest = WorldLocation(mapid, x, y, z, orientation);
1470 m_teleport_instanceId = instanceId;
1471 m_teleport_options = options;
1473 // if the player is saved before worldportack (at logout for example)
1474 // this will be used instead of the current location in SaveToDB
1475
1476 if (!GetSession()->PlayerLogout())
1477 {
1479 suspendToken.SequenceIndex = m_movementCounter; // not incrementing
1480 suspendToken.Reason = options & TELE_TO_SEAMLESS ? 2 : 1;
1481 SendDirectMessage(suspendToken.Write());
1482 }
1483
1484 // move packet sent by client always after far teleport
1485 // code for finish transfer to new map called in WorldSession::HandleMoveWorldportAckOpcode at client packet
1487 }
1488 return true;
1489}
1490
1491bool Player::TeleportTo(WorldLocation const& loc, TeleportToOptions options /*= TELE_TO_NONE*/, Optional<uint32> instanceId /*= {}*/)
1492{
1493 return TeleportTo(loc.GetMapId(), loc.GetPositionX(), loc.GetPositionY(), loc.GetPositionZ(), loc.GetOrientation(), options, instanceId);
1494}
1495
1497{
1499 return false;
1500
1504 return TeleportTo(m_bgData.joinPos);
1505}
1506
1508{
1509 if (m_DelayedOperations == 0)
1510 return;
1511
1514
1516 SaveToDB();
1517
1519 CastSpell(this, 26013, true); // Deserter
1520
1522 {
1523 if (m_bgData.mountSpell)
1524 {
1525 CastSpell(this, m_bgData.mountSpell, true);
1526 m_bgData.mountSpell = 0;
1527 }
1528 }
1529
1531 {
1532 if (m_bgData.HasTaxiPath())
1533 {
1537
1539 }
1540 }
1541
1543 {
1544 if (Group* g = GetGroup())
1545 g->SendUpdateToPlayer(GetGUID());
1546 }
1547
1548 //we have executed ALL delayed ops, so clear the flag
1550}
1551
1553{
1558
1559 for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
1560 if (m_items[i])
1561 m_items[i]->AddToWorld();
1562}
1563
1565{
1566 // cleanup
1567 if (IsInWorld())
1568 {
1576 m_lootRolls.clear();
1577 sOutdoorPvPMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
1578 sBattlefieldMgr->HandlePlayerLeaveZone(this, m_zoneUpdateId);
1579 }
1580
1581 // Remove items from world before self - player must be found in Item::RemoveFromObjectUpdate
1582 for (uint8 i = PLAYER_SLOT_START; i < PLAYER_SLOT_END; ++i)
1583 if (m_items[i])
1585
1590
1591 for (ItemMap::iterator iter = mMitems.begin(); iter != mMitems.end(); ++iter)
1592 iter->second->RemoveFromWorld();
1593
1594 if (WorldObject* viewpoint = GetViewpoint())
1595 {
1596 TC_LOG_ERROR("entities.player", "Player::RemoveFromWorld: Player '{}' ({}) has viewpoint (Entry:{}, Type: {}) when removed from world",
1597 GetName(), GetGUID().ToString(), viewpoint->GetEntry(), viewpoint->GetTypeId());
1598 SetViewpoint(viewpoint, false);
1599 }
1600}
1601
1602void Player::SetObjectScale(float scale)
1603{
1604 Unit::SetObjectScale(scale);
1607 if (IsInWorld())
1609}
1610
1611bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, WorldObject const* caster,
1612 bool requireImmunityPurgesEffectAttribute /*= false*/) const
1613{
1614 // players are immune to taunt (the aura and the spell effect).
1615 if (spellEffectInfo.IsAura(SPELL_AURA_MOD_TAUNT))
1616 return true;
1617 if (spellEffectInfo.IsEffect(SPELL_EFFECT_ATTACK_ME))
1618 return true;
1619
1620 return Unit::IsImmunedToSpellEffect(spellInfo, spellEffectInfo, caster, requireImmunityPurgesEffectAttribute);
1621}
1622
1624{
1627
1628 for (Powers power = POWER_MANA; power < MAX_POWERS; power = Powers(power + 1))
1629 if (power != POWER_RUNES)
1630 Regenerate(power);
1631
1632 // Runes act as cooldowns, and they don't need to send any data
1634 {
1635 uint32 regeneratedRunes = 0;
1636 uint32 regenIndex = 0;
1637 while (regeneratedRunes < MAX_RECHARGING_RUNES && m_runes->CooldownOrder.size() > regenIndex)
1638 {
1639 uint8 runeToRegen = m_runes->CooldownOrder[regenIndex];
1640 uint32 runeCooldown = GetRuneCooldown(runeToRegen);
1641 if (runeCooldown > m_regenTimer)
1642 {
1643 SetRuneCooldown(runeToRegen, runeCooldown - m_regenTimer);
1644 ++regenIndex;
1645 }
1646 else
1647 SetRuneCooldown(runeToRegen, 0);
1648
1649 ++regeneratedRunes;
1650 }
1651 }
1652
1653 if (m_regenTimerCount >= 2000)
1654 {
1655 // Not in combat or they have regeneration
1658
1659 m_regenTimerCount -= 2000;
1660 }
1661
1662 m_regenTimer = 0;
1663
1664 // Handles the emotes for drinking and eating.
1665 // According to sniffs there is a background timer going on that repeats independed from the time window where the aura applies.
1666 // That's why we dont need to reset the timer on apply. In sniffs I have seen that the first call for the spell visual is totally random, then after
1667 // 5 seconds over and over again which confirms my theory that we have a independed timer.
1668 if (m_foodEmoteTimerCount >= 5000)
1669 {
1670 auto findInterruptibleEffect = [](AuraEffect const* aurEff)
1671 {
1672 return aurEff->GetSpellInfo()->HasAuraInterruptFlag(SpellAuraInterruptFlags::Standing);
1673 };
1674
1675 // Food emote comes above drinking emote if we have to decide (mage regen food for example)
1677 auto itr = std::find_if(ModRegenAuras.cbegin(), ModRegenAuras.cend(), findInterruptibleEffect);
1678 if (itr != ModRegenAuras.end())
1679 {
1681 }
1682 else
1683 {
1685 itr = std::find_if(ModPowerRegenAuras.cbegin(), ModPowerRegenAuras.cend(), findInterruptibleEffect);
1686 if (itr != ModPowerRegenAuras.end())
1688 }
1689
1690 m_foodEmoteTimerCount -= 5000;
1691 }
1692}
1693
1695{
1696 // Skip regeneration for power type we cannot have
1697 uint32 powerIndex = GetPowerIndex(power);
1698 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
1699 return;
1700
1703 return;
1704
1705 int32 curValue = GetPower(power);
1706
1707 // TODO: updating haste should update UnitData::PowerRegenFlatModifier for certain power types
1708 PowerTypeEntry const* powerType = sDB2Manager.GetPowerTypeEntry(power);
1709 if (!powerType)
1710 return;
1711
1712 float addvalue = 0.0f;
1713 if (!IsInCombat())
1714 {
1716 return;
1717
1718 addvalue = (powerType->RegenPeace + m_unitData->PowerRegenFlatModifier[powerIndex]) * 0.001f * m_regenTimer;
1719 }
1720 else
1721 addvalue = (powerType->RegenCombat + m_unitData->PowerRegenInterruptedFlatModifier[powerIndex]) * 0.001f * m_regenTimer;
1722
1723 static Rates const RatesForPower[MAX_POWERS] =
1724 {
1730 MAX_RATES, // runes
1735 MAX_RATES, // alternate
1739 MAX_RATES, // burning embers, unused
1740 MAX_RATES, // demonic fury, unused
1745 MAX_RATES, // runes
1746 MAX_RATES, // runes
1747 MAX_RATES, // runes
1748 MAX_RATES, // alternate
1749 MAX_RATES, // alternate
1750 MAX_RATES, // alternate
1751 };
1752
1753 if (RatesForPower[power] != MAX_RATES)
1754 addvalue *= sWorld->getRate(RatesForPower[power]);
1755
1756 // Mana regen calculated in Player::UpdateManaRegen()
1757 if (power != POWER_MANA)
1758 {
1760
1762 }
1763
1764 int32 minPower = powerType->MinPower;
1765 int32 maxPower = GetMaxPower(power);
1766
1767 if (powerType->CenterPower)
1768 {
1769 if (curValue > powerType->CenterPower)
1770 {
1771 addvalue = -std::abs(addvalue);
1772 minPower = powerType->CenterPower;
1773 }
1774 else if (curValue < powerType->CenterPower)
1775 {
1776 addvalue = std::abs(addvalue);
1777 maxPower = powerType->CenterPower;
1778 }
1779 else
1780 return;
1781 }
1782
1783 addvalue += m_powerFraction[powerIndex];
1784 int32 integerValue = int32(std::fabs(addvalue));
1785
1786 if (addvalue < 0.0f)
1787 {
1788 if (curValue <= minPower)
1789 return;
1790 }
1791 else if (addvalue > 0.0f)
1792 {
1793 if (curValue >= maxPower)
1794 return;
1795 }
1796 else
1797 return;
1798
1799 bool forcesSetPower = false;
1800 if (addvalue < 0.0f)
1801 {
1802 if (curValue > minPower + integerValue)
1803 {
1804 curValue -= integerValue;
1805 m_powerFraction[powerIndex] = addvalue + integerValue;
1806 }
1807 else
1808 {
1809 curValue = minPower;
1810 m_powerFraction[powerIndex] = 0;
1811 forcesSetPower = true;
1812 }
1813 }
1814 else
1815 {
1816 if (curValue + integerValue <= maxPower)
1817 {
1818 curValue += integerValue;
1819 m_powerFraction[powerIndex] = addvalue - integerValue;
1820 }
1821 else
1822 {
1823 curValue = maxPower;
1824 m_powerFraction[powerIndex] = 0;
1825 forcesSetPower = true;
1826 }
1827 }
1828
1830 curValue = maxPower;
1831
1832 if (m_regenTimerCount >= 2000 || forcesSetPower)
1833 SetPower(power, curValue);
1834 else
1835 {
1836 // throttle packet sending
1838 {
1839 SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::Power, powerIndex), curValue);
1840 const_cast<UF::UnitData&>(*m_unitData).ClearChanged(&UF::UnitData::Power, powerIndex);
1841 });
1842 }
1843}
1844
1846{
1847 uint32 powerIndex = GetPowerIndex(power);
1848 if (powerIndex == MAX_POWERS || powerIndex >= MAX_POWERS_PER_CLASS)
1849 return;
1850
1852 m_powerFraction[powerIndex] = 0.0f;
1854}
1855
1857{
1858 uint32 curValue = GetHealth();
1859 uint32 maxValue = GetMaxHealth();
1860
1861 if (curValue >= maxValue)
1862 return;
1863
1864 float HealthIncreaseRate = sWorld->getRate(RATE_HEALTH);
1865 float addValue = 0.0f;
1866
1867 // polymorphed case
1868 if (IsPolymorphed())
1869 addValue = float(GetMaxHealth()) / 3.0f;
1870 // normal regen case (maybe partly in combat case)
1872 {
1873 addValue = HealthIncreaseRate;
1874
1875 if (!IsInCombat())
1876 {
1877 if (GetLevel() < 15)
1878 addValue = (0.20f * ((float)GetMaxHealth()) / GetLevel() * HealthIncreaseRate);
1879 else
1880 addValue = 0.015f * ((float)GetMaxHealth()) * HealthIncreaseRate;
1881
1883
1884 addValue += GetTotalAuraModifier(SPELL_AURA_MOD_REGEN) * 0.4f;
1885 }
1888
1889 if (!IsStandState())
1890 addValue *= 1.5f;
1891 }
1892
1893 // always regeneration bonus (including combat)
1895 addValue += m_baseHealthRegen / 2.5f;
1896
1897 if (addValue < 0.0f)
1898 addValue = 0.0f;
1899
1900 ModifyHealth(int32(addValue));
1901}
1902
1904{
1905 SetFullHealth();
1906
1907 switch (GetPowerType())
1908 {
1909 case POWER_MANA:
1911 break;
1912 case POWER_RAGE:
1913 SetPower(POWER_RAGE, 0);
1914 break;
1915 case POWER_ENERGY:
1917 break;
1918 case POWER_RUNIC_POWER:
1920 break;
1921 case POWER_LUNAR_POWER:
1923 break;
1924 default:
1925 break;
1926 }
1927}
1928
1930{
1931 switch (questGiver->GetTypeId())
1932 {
1933 case TYPEID_UNIT:
1935 case TYPEID_GAMEOBJECT:
1936 return GetGameObjectIfCanInteractWith(questGiver->GetGUID(), GAMEOBJECT_TYPE_QUESTGIVER) != nullptr;
1937 case TYPEID_PLAYER:
1938 return IsAlive() && questGiver->ToPlayer()->IsAlive();
1939 case TYPEID_ITEM:
1940 return IsAlive();
1941 default:
1942 break;
1943 }
1944 return false;
1945}
1946
1948{
1949 // unit checks
1950 if (!guid)
1951 return nullptr;
1952
1953 if (!IsInWorld())
1954 return nullptr;
1955
1956 if (IsInFlight())
1957 return nullptr;
1958
1959 // exist (we need look pets also for some interaction (quest/etc)
1960 Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid);
1961 if (!creature)
1962 return nullptr;
1963
1964 // Deathstate checks
1966 return nullptr;
1967
1968 // alive or spirit healer
1970 return nullptr;
1971
1972 // appropriate npc type
1973 auto hasNpcFlags = [&]()
1974 {
1975 if (!npcFlags && !npcFlags2)
1976 return true;
1977 if (creature->HasNpcFlag(npcFlags))
1978 return true;
1979 if (creature->HasNpcFlag2(npcFlags2))
1980 return true;
1981 return false;
1982 };
1983 if (!hasNpcFlags())
1984 return nullptr;
1985
1986 // not allow interaction under control, but allow with own pets
1987 if (!creature->GetCharmerGUID().IsEmpty())
1988 return nullptr;
1989
1990 // not unfriendly/hostile
1991 if (!creature->IsInteractionAllowedWhileHostile() && creature->GetReactionTo(this) <= REP_UNFRIENDLY)
1992 return nullptr;
1993
1994 if (creature->IsInCombat() && !creature->IsInteractionAllowedInCombat())
1995 return nullptr;
1996
1997 // not too far, taken from CGGameUI::SetInteractTarget
1998 if (!creature->IsWithinDistInMap(this, creature->GetCombatReach() + 4.0f))
1999 return nullptr;
2000
2001 return creature;
2002}
2003
2005{
2006 if (!guid)
2007 return nullptr;
2008
2009 if (!IsInWorld())
2010 return nullptr;
2011
2012 if (IsInFlight())
2013 return nullptr;
2014
2015 // exist
2016 GameObject* go = ObjectAccessor::GetGameObject(*this, guid);
2017 if (!go)
2018 return nullptr;
2019
2020 // Players cannot interact with gameobjects that use the "Point" icon
2021 if (go->GetGOInfo()->IconName == "Point")
2022 return nullptr;
2023
2024 if (!go->IsWithinDistInMap(this))
2025 return nullptr;
2026
2027 return go;
2028}
2029
2031{
2033 if (!go)
2034 return nullptr;
2035
2036 if (go->GetGoType() != type)
2037 return nullptr;
2038
2039 return go;
2040}
2041
2043{
2044 if (!trigger)
2045 return false;
2046
2047 if (int32(GetMapId()) != trigger->ContinentID && !GetPhaseShift().HasVisibleMapId(trigger->ContinentID))
2048 return false;
2049
2050 if (trigger->PhaseID || trigger->PhaseGroupID || trigger->PhaseUseFlags)
2051 if (!PhasingHandler::InDbPhaseShift(this, trigger->PhaseUseFlags, trigger->PhaseID, trigger->PhaseGroupID))
2052 return false;
2053
2054 if (trigger->Radius > 0.f)
2055 {
2056 // if we have radius check it
2057 float dist = GetDistance(trigger->Pos.X, trigger->Pos.Y, trigger->Pos.Z);
2058 if (dist > trigger->Radius)
2059 return false;
2060 }
2061 else
2062 {
2063 Position center(trigger->Pos.X, trigger->Pos.Y, trigger->Pos.Z, trigger->BoxYaw);
2064 if (!IsWithinBox(center, trigger->BoxLength / 2.f, trigger->BoxWidth / 2.f, trigger->BoxHeight / 2.f))
2065 return false;
2066 }
2067
2068 return true;
2069}
2070
2072{
2073 if (on)
2074 {
2079
2080 if (Pet* pet = GetPet())
2081 pet->SetFaction(FACTION_FRIENDLY);
2082
2085
2087
2088 PhasingHandler::SetAlwaysVisible(this, true, false);
2090 }
2091 else
2092 {
2094
2095 m_ExtraFlags &= ~ PLAYER_EXTRA_GM_ON;
2099
2100 if (Pet* pet = GetPet())
2101 pet->SetFaction(GetFaction());
2102
2103 // restore FFA PvP Server state
2104 if (sWorld->IsFFAPvPRealm())
2106
2107 // restore FFA PvP area state, remove not allowed for GM mounts
2109
2111 }
2112
2114}
2115
2117{
2119}
2120
2122{
2123 if (on)
2124 {
2125 m_ExtraFlags &= ~PLAYER_EXTRA_GM_INVISIBLE; //remove flag
2127 }
2128 else
2129 {
2131
2132 SetAcceptWhispers(false);
2133 SetGameMaster(true);
2134
2136 }
2137
2138 for (Channel* channel : m_channels)
2139 channel->SetInvisible(this, !on);
2140}
2141
2143{
2144 switch (sWorld->getIntConfig(CONFIG_GROUP_VISIBILITY))
2145 {
2146 default: return IsInSameGroupWith(p);
2147 case 1: return IsInSameRaidWith(p);
2148 case 2: return GetTeam() == p->GetTeam();
2149 case 3: return false;
2150 }
2151}
2152
2154{
2155 return p == this || (GetGroup() != nullptr &&
2156 GetGroup() == p->GetGroup() &&
2157 GetGroup()->SameSubGroup(this, p));
2158}
2159
2161{
2162 return p == this || (GetGroup() != nullptr && GetGroup() == p->GetGroup());
2163}
2164
2167{
2168 Group* group = GetGroupInvite();
2169 if (!group)
2170 return;
2171
2172 group->RemoveInvite(this);
2173
2174 if (group->IsCreated())
2175 {
2176 if (group->GetMembersCount() <= 1) // group has just 1 member => disband
2177 group->Disband(true);
2178 }
2179 else
2180 {
2181 if (group->GetInviteeCount() <= 1)
2182 {
2183 group->RemoveAllInvites();
2184 delete group;
2185 }
2186 }
2187}
2188
2189void Player::RemoveFromGroup(Group* group, ObjectGuid guid, RemoveMethod method /* = GROUP_REMOVEMETHOD_DEFAULT*/, ObjectGuid kicker /* = ObjectGuid::Empty */, char const* reason /* = nullptr */)
2190{
2191 if (!group)
2192 return;
2193
2194 group->RemoveMember(guid, method, kicker, reason);
2195}
2196
2198{
2200
2201 int32 playerLevelDelta = 0;
2202
2203 // If XP < 50%, player should see scaling creature with -1 level except for level max
2204 if (GetLevel() < MAX_LEVEL && xp < uint32(*m_activePlayerData->NextLevelXP / 2))
2205 playerLevelDelta = -1;
2206
2208}
2209
2210void Player::GiveXP(uint32 xp, Unit* victim, float group_rate)
2211{
2212 if (xp < 1)
2213 return;
2214
2215 if (!IsAlive() && !GetBattlegroundId())
2216 return;
2217
2219 return;
2220
2221 if (victim && victim->GetTypeId() == TYPEID_UNIT && !victim->ToCreature()->hasLootRecipient())
2222 return;
2223
2224 uint8 level = GetLevel();
2225
2226 sScriptMgr->OnGivePlayerXP(this, xp, victim);
2227
2228 // XP to money conversion processed in Player::RewardQuest
2229 if (IsMaxLevel())
2230 return;
2231
2232 uint32 bonus_xp;
2233 bool recruitAFriend = GetsRecruitAFriendBonus(true);
2234
2235 // RaF does NOT stack with rested experience
2236 if (recruitAFriend)
2237 bonus_xp = 2 * xp; // xp + bonus_xp must add up to 3 * xp for RaF; calculation for quests done client-side
2238 else
2239 bonus_xp = victim ? _restMgr->GetRestBonusFor(REST_TYPE_XP, xp) : 0; // XP resting bonus
2240
2242 packet.Victim = victim ? victim->GetGUID() : ObjectGuid::Empty;
2243 packet.Original = xp + bonus_xp;
2245 packet.Amount = xp;
2246 packet.GroupBonus = group_rate;
2247 SendDirectMessage(packet.Write());
2248
2249 uint32 nextLvlXP = GetXPForNextLevel();
2250 uint32 newXP = GetXP() + xp + bonus_xp;
2251
2252 while (newXP >= nextLvlXP && !IsMaxLevel())
2253 {
2254 newXP -= nextLvlXP;
2255
2256 if (!IsMaxLevel())
2257 GiveLevel(level + 1);
2258
2259 level = GetLevel();
2260 nextLvlXP = GetXPForNextLevel();
2261 }
2262
2263 SetXP(newXP);
2264}
2265
2266// Update player to next level
2267// Current player experience not update (must be update by caller)
2269{
2270 uint8 oldLevel = GetLevel();
2271 if (level == oldLevel)
2272 return;
2273
2274 if (Guild* guild = GetGuild())
2275 guild->UpdateMemberData(this, GUILD_MEMBER_DATA_LEVEL, level);
2276
2277 PlayerLevelInfo info;
2278 sObjectMgr->GetPlayerLevelInfo(GetRace(), GetClass(), level, &info);
2279
2280 uint32 basemana = 0;
2281 sObjectMgr->GetPlayerClassLevelInfo(GetClass(), level, basemana);
2282
2284 packet.Level = level;
2285 packet.HealthDelta = 0;
2286
2288 // for (int i = 0; i < MAX_STORED_POWERS; ++i)
2289 packet.PowerDelta[0] = int32(basemana) - int32(GetCreateMana());
2290 packet.PowerDelta[1] = 0;
2291 packet.PowerDelta[2] = 0;
2292 packet.PowerDelta[3] = 0;
2293 packet.PowerDelta[4] = 0;
2294 packet.PowerDelta[5] = 0;
2295 packet.PowerDelta[6] = 0;
2296
2297 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
2298 packet.StatDelta[i] = int32(info.stats[i]) - GetCreateStat(Stats(i));
2299
2301 packet.NumNewPvpTalentSlots = sDB2Manager.GetPvpTalentNumSlotsAtLevel(level, Classes(GetClass())) - sDB2Manager.GetPvpTalentNumSlotsAtLevel(oldLevel, Classes(GetClass()));
2302
2303 SendDirectMessage(packet.Write());
2304
2306
2307 //update level, max level of skills
2308 m_Played_time[PLAYED_TIME_LEVEL] = 0; // Level Played Time reset
2309
2311
2312 SetLevel(level);
2313
2317
2318 // save base values (bonuses already included in stored stats
2319 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
2320 SetCreateStat(Stats(i), info.stats[i]);
2321
2322 SetCreateHealth(0);
2323 SetCreateMana(basemana);
2324
2327
2329
2330 _ApplyAllLevelScaleItemMods(true); // Moved to above SetFullHealth so player will have full health from Heirlooms
2331
2333 if (Item* artifact = GetItemByGuid(artifactAura->GetCastItemGUID()))
2334 artifact->CheckArtifactRelicSlotUnlock(this);
2335
2336 // Only health and mana are set to maximum.
2337 SetFullHealth();
2338 for (PowerTypeEntry const* powerType : sPowerTypeStore)
2339 if (powerType->GetFlags().HasFlag(PowerTypeFlags::SetToMaxOnLevelUp))
2340 SetFullPower(Powers(powerType->PowerTypeEnum));
2341
2342 // update level to hunter/summon pet
2343 if (Pet* pet = GetPet())
2344 pet->SynchronizeLevelWithOwner();
2345
2346 if (MailLevelReward const* mailReward = sObjectMgr->GetMailLevelReward(level, GetRace()))
2347 {
2349 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
2350 MailDraft(mailReward->mailTemplateId).SendMailTo(trans, this, MailSender(MAIL_CREATURE, uint64(mailReward->senderEntry)));
2351 CharacterDatabase.CommitTransaction(trans);
2352 }
2353
2357 if (level > oldLevel)
2358 UpdateCriteria(CriteriaType::GainLevels, level - oldLevel);
2359
2360 PushQuests();
2361
2362 sScriptMgr->OnPlayerLevelChanged(this, oldLevel);
2363}
2364
2366{
2367 return GetLevel() >= m_activePlayerData->MaxLevel;
2368}
2369
2371{
2372 uint8 level = GetLevel();
2373 // talents base at level diff (talents = level - 9 but some can be used already)
2374 if (level < MIN_SPECIALIZATION_LEVEL)
2376
2377 int32 talentTiers = DB2Manager::GetNumTalentsAtLevel(level, Classes(GetClass()));
2378 if (level < 15)
2379 {
2380 // Remove all talent points
2381 ResetTalents(true);
2382 }
2383 else
2384 {
2386 for (int32 t = talentTiers; t < MAX_TALENT_TIERS; ++t)
2387 for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
2388 for (TalentEntry const* talent : sDB2Manager.GetTalentsByPosition(GetClass(), t, c))
2389 RemoveTalent(talent);
2390 }
2391
2393
2395 for (uint8 spec = 0; spec < MAX_SPECIALIZATIONS; ++spec)
2396 for (size_t slot = sDB2Manager.GetPvpTalentNumSlotsAtLevel(level, Classes(GetClass())); slot < MAX_PVP_TALENT_SLOTS; ++slot)
2397 if (PvpTalentEntry const* pvpTalent = sPvpTalentStore.LookupEntry(GetPvpTalentMap(spec)[slot]))
2398 RemovePvpTalent(pvpTalent, spec);
2399
2400 if (!GetSession()->PlayerLoading())
2401 SendTalentsInfoData(); // update at client
2402}
2403
2404void Player::InitStatsForLevel(bool reapplyMods)
2405{
2406 if (reapplyMods) //reapply stats values only on .reset stats (level) command
2408
2409 uint32 basemana = 0;
2410 sObjectMgr->GetPlayerClassLevelInfo(GetClass(), GetLevel(), basemana);
2411
2412 PlayerLevelInfo info;
2413 sObjectMgr->GetPlayerLevelInfo(GetRace(), GetClass(), GetLevel(), &info);
2414
2415 uint8 exp_max_lvl = GetMaxLevelForExpansion(GetSession()->GetExpansion());
2416 uint8 conf_max_lvl = sWorld->getIntConfig(CONFIG_MAX_PLAYER_LEVEL);
2417 if (exp_max_lvl == DEFAULT_MAX_LEVEL || exp_max_lvl >= conf_max_lvl)
2419 else
2422 if (m_activePlayerData->XP >= m_activePlayerData->NextLevelXP)
2424
2425 // reset before any aura state sources (health set/aura apply)
2427
2429
2430 // set default cast time multiplier
2431 SetModCastingSpeed(1.0f);
2432 SetModSpellHaste(1.0f);
2433 SetModHaste(1.0f);
2434 SetModRangedHaste(1.0f);
2435 SetModHasteRegen(1.0f);
2436 SetModTimeRate(1.0f);
2437
2438 // reset size before reapply auras
2439 SetObjectScale(1.0f);
2440
2441 // save base values (bonuses already included in stored stats
2442 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
2443 SetCreateStat(Stats(i), info.stats[i]);
2444
2445 for (uint8 i = STAT_STRENGTH; i < MAX_STATS; ++i)
2446 SetStat(Stats(i), info.stats[i]);
2447
2448 SetCreateHealth(0);
2449
2450 //set create powers
2451 SetCreateMana(basemana);
2452
2454
2456
2457 //reset rating fields values
2458 for (uint16 index = 0; index < MAX_COMBAT_RATING; ++index)
2460
2464 for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
2465 {
2470 }
2471
2473
2474 //reset attack power, damage and attack speed fields
2475 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
2477
2484 for (uint16 i = 0; i < 3; ++i)
2485 {
2488 }
2489
2490 SetAttackPower(0);
2494
2495 // Base crit values (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset
2499
2500 // Init spell schools (will be recalculated in UpdateAllStats() at loading and in _ApplyAllStatBonuses() at reset
2502
2505
2507
2508 // Dodge percentage
2510
2511 // set armor (resistance 0) to original value (create_agility*2)
2514 // set other resistance to original value (0)
2515 for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
2516 {
2519 }
2520
2523 for (uint8 i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i)
2525
2526 // Reset no reagent cost field
2528
2529 // Init data for form but skip reapply item mods for form
2530 InitDataForForm(reapplyMods);
2531
2532 // save new stats
2533 for (uint8 i = POWER_MANA; i < MAX_POWERS; ++i)
2535
2536 SetMaxHealth(0); // stamina bonus will applied later
2537
2538 // cleanup mounted state (it will set correctly at aura loading if player saved at mount.
2540
2541 // cleanup unit flags (will be re-applied if need at aura load).
2550
2552
2553 // cleanup player flags (will be re-applied if need at aura load), to avoid have ghost flag without ghost aura, for example.
2555
2556 RemoveVisFlag(UNIT_VIS_FLAGS_ALL); // one form stealth modified bytes
2558
2559 // restore if need some important flags
2562
2563 if (reapplyMods) // reapply stats values only on .reset stats (level) command
2565
2566 // set current level health and mana/energy to maximum after applying all mods.
2567 SetFullHealth();
2574
2575 // update level to hunter/summon pet
2576 if (Pet* pet = GetPet())
2577 pet->SynchronizeLevelWithOwner();
2578}
2579
2581{
2583 knownSpells.InitialLogin = IsLoading();
2584
2585 knownSpells.KnownSpells.reserve(m_spells.size());
2586 for (PlayerSpellMap::value_type const& spell : m_spells)
2587 {
2588 if (spell.second.state == PLAYERSPELL_REMOVED)
2589 continue;
2590
2591 if (!spell.second.active || spell.second.disabled)
2592 continue;
2593
2594 knownSpells.KnownSpells.push_back(spell.first);
2595 if (spell.second.favorite)
2596 knownSpells.FavoriteSpells.push_back(spell.first);
2597 }
2598
2599 SendDirectMessage(knownSpells.Write());
2600}
2601
2603{
2605 SendDirectMessage(sendUnlearnSpells.Write());
2606}
2607
2609{
2610 for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
2611 {
2612 if ((*itr)->messageID == id)
2613 {
2614 //do not delete item, because Player::removeMail() is called when returning mail to sender.
2615 m_mail.erase(itr);
2616 return;
2617 }
2618 }
2619}
2620
2621void Player::SendMailResult(uint64 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError, ObjectGuid::LowType itemGuid, uint32 itemCount) const
2622{
2624
2625 result.MailID = mailId;
2626 result.Command = mailAction;
2627 result.ErrorCode = mailError;
2628
2629 if (mailError == MAIL_ERR_EQUIP_ERROR)
2630 result.BagResult = equipError;
2631 else if (mailAction == MAIL_ITEM_TAKEN)
2632 {
2633 result.AttachID = itemGuid;
2634 result.QtyInInventory = itemCount;
2635 }
2636 SendDirectMessage(result.Write());
2637}
2638
2640{
2641 // deliver undelivered mail
2643 notify.Delay = 0.0f;
2644
2645 SendDirectMessage(notify.Write());
2646}
2647
2649{
2650 // calculate next delivery time (min. from non-delivered mails
2651 // and recalculate unReadMail
2652 time_t cTime = GameTime::GetGameTime();
2654 unReadMails = 0;
2655 for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
2656 {
2657 if ((*itr)->deliver_time > cTime)
2658 {
2659 if (!m_nextMailDelivereTime || m_nextMailDelivereTime > (*itr)->deliver_time)
2660 m_nextMailDelivereTime = (*itr)->deliver_time;
2661 }
2662 else if (((*itr)->checked & MAIL_CHECK_MASK_READ) == 0)
2663 ++unReadMails;
2664 }
2665}
2666
2667void Player::AddNewMailDeliverTime(time_t deliver_time)
2668{
2669 if (deliver_time <= GameTime::GetGameTime()) // ready now
2670 {
2671 ++unReadMails;
2672 SendNewMail();
2673 }
2674 else // not ready and no have ready mails
2675 {
2676 if (!m_nextMailDelivereTime || m_nextMailDelivereTime > deliver_time)
2677 m_nextMailDelivereTime = deliver_time;
2678 }
2679}
2680
2682{
2684 stmt->setUInt32(0, spellId);
2685 CharacterDatabase.Execute(stmt);
2686}
2687
2688bool Player::AddTalent(TalentEntry const* talent, uint8 spec, bool learning)
2689{
2690 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE);
2691 if (!spellInfo)
2692 {
2693 TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) does not exist.", talent->SpellID);
2694 return false;
2695 }
2696
2697 if (!SpellMgr::IsSpellValid(spellInfo, this, false))
2698 {
2699 TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) is invalid", talent->SpellID);
2700 return false;
2701 }
2702
2703 PlayerTalentMap::iterator itr = GetTalentMap(spec)->find(talent->ID);
2704 if (itr != GetTalentMap(spec)->end())
2705 itr->second = PLAYERSPELL_UNCHANGED;
2706 else
2707 (*GetTalentMap(spec))[talent->ID] = learning ? PLAYERSPELL_NEW : PLAYERSPELL_UNCHANGED;
2708
2709 if (spec == GetActiveTalentGroup())
2710 {
2711 LearnSpell(talent->SpellID, true);
2712 if (talent->OverridesSpellID)
2713 AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
2714 }
2715
2716 if (learning)
2718
2719 return true;
2720}
2721
2723{
2724 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE);
2725 if (!spellInfo)
2726 return;
2727
2728 RemoveSpell(talent->SpellID, true);
2729
2730 // search for spells that the talent teaches and unlearn them
2731 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
2732 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
2733 RemoveSpell(spellEffectInfo.TriggerSpell, true);
2734
2735 if (talent->OverridesSpellID)
2737
2738 // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
2739 PlayerTalentMap::iterator plrTalent = GetTalentMap(GetActiveTalentGroup())->find(talent->ID);
2740 if (plrTalent != GetTalentMap(GetActiveTalentGroup())->end())
2741 plrTalent->second = PLAYERSPELL_REMOVED;
2742}
2743
2745{
2747 storedLocation.Loc.WorldRelocate(this);
2749}
2750
2752{
2754 storedLocation->State = StoredAuraTeleportLocation::DELETED;
2755}
2756
2758{
2760 return &auraLocation->Loc;
2761
2762 return nullptr;
2763}
2764
2765bool Player::AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading /*= false*/, int32 fromSkill /*= 0*/, bool favorite /*= false*/, Optional<int32> traitDefinitionId /*= {}*/)
2766{
2767 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE);
2768 if (!spellInfo)
2769 {
2770 // do character spell book cleanup (all characters)
2771 if (!IsInWorld() && !learning) // spell load case
2772 {
2773 TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: {}) does not exist. deleting for all characters in `character_spell`.", spellId);
2774
2776 }
2777 else
2778 TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: {}) does not exist", spellId);
2779
2780 return false;
2781 }
2782
2783 if (!SpellMgr::IsSpellValid(spellInfo, this, false))
2784 {
2785 // do character spell book cleanup (all characters)
2786 if (!IsInWorld() && !learning) // spell load case
2787 {
2788 TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: {}) is invalid. deleting for all characters in `character_spell`.", spellId);
2789
2791 }
2792 else
2793 TC_LOG_ERROR("spells", "Player::AddSpell: Spell (ID: {}) is invalid", spellId);
2794
2795 return false;
2796 }
2797
2799
2800 bool dependent_set = false;
2801 bool disabled_case = false;
2802 bool superceded_old = false;
2803
2804 PlayerSpellMap::iterator itr = m_spells.find(spellId);
2805
2806 // Remove temporary spell if found to prevent conflicts
2807 if (itr != m_spells.end() && itr->second.state == PLAYERSPELL_TEMPORARY)
2808 RemoveTemporarySpell(spellId);
2809 else if (itr != m_spells.end())
2810 {
2811 uint32 next_active_spell_id = 0;
2812 // fix activate state for non-stackable low rank (and find next spell for !active case)
2813 if (spellInfo->IsRanked())
2814 {
2815 if (uint32 next = sSpellMgr->GetNextSpellInChain(spellId))
2816 {
2817 if (HasSpell(next))
2818 {
2819 // high rank already known so this must !active
2820 active = false;
2821 next_active_spell_id = next;
2822 }
2823 }
2824 }
2825
2826 // not do anything if already known in expected state
2827 if (itr->second.state != PLAYERSPELL_REMOVED && itr->second.active == active &&
2828 itr->second.dependent == dependent && itr->second.disabled == disabled)
2829 {
2830 if (!IsInWorld() && !learning) // explicitly load from DB and then exist in it already and set correctly
2831 itr->second.state = PLAYERSPELL_UNCHANGED;
2832
2833 return false;
2834 }
2835
2836 // dependent spell known as not dependent, overwrite state
2837 if (itr->second.state != PLAYERSPELL_REMOVED && !itr->second.dependent && dependent)
2838 {
2839 itr->second.dependent = dependent;
2840 if (itr->second.state != PLAYERSPELL_NEW)
2841 itr->second.state = PLAYERSPELL_CHANGED;
2842 dependent_set = true;
2843 }
2844
2845 if (itr->second.TraitDefinitionId != traitDefinitionId)
2846 {
2847 if (itr->second.TraitDefinitionId)
2848 if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(*itr->second.TraitDefinitionId))
2849 RemoveOverrideSpell(traitDefinition->OverridesSpellID, spellId);
2850
2851 itr->second.TraitDefinitionId = traitDefinitionId;
2852 }
2853
2854 itr->second.favorite = favorite;
2855
2856 // update active state for known spell
2857 if (itr->second.active != active && itr->second.state != PLAYERSPELL_REMOVED && !itr->second.disabled)
2858 {
2859 itr->second.active = active;
2860
2861 if (!IsInWorld() && !learning && !dependent_set) // explicitly load from DB and then exist in it already and set correctly
2862 itr->second.state = PLAYERSPELL_UNCHANGED;
2863 else if (itr->second.state != PLAYERSPELL_NEW)
2864 itr->second.state = PLAYERSPELL_CHANGED;
2865
2866 if (active)
2867 {
2868 if (spellInfo->IsPassive() && HandlePassiveSpellLearn(spellInfo))
2869 CastSpell(this, spellId, true);
2870 }
2871 else if (IsInWorld())
2872 {
2873 if (next_active_spell_id)
2874 SendSupercededSpell(spellId, next_active_spell_id);
2875 else
2876 {
2878 unlearnedSpells.SpellID.push_back(spellId);
2879 SendDirectMessage(unlearnedSpells.Write());
2880 }
2881 }
2882
2883 return active; // learn (show in spell book if active now)
2884 }
2885
2886 if (itr->second.disabled != disabled && itr->second.state != PLAYERSPELL_REMOVED)
2887 {
2888 if (itr->second.state != PLAYERSPELL_NEW)
2889 itr->second.state = PLAYERSPELL_CHANGED;
2890 itr->second.disabled = disabled;
2891
2892 if (disabled)
2893 return false;
2894
2895 disabled_case = true;
2896 }
2897 else switch (itr->second.state)
2898 {
2899 case PLAYERSPELL_UNCHANGED: // known saved spell
2900 return false;
2901 case PLAYERSPELL_REMOVED: // re-learning removed not saved spell
2902 {
2903 m_spells.erase(itr);
2904 state = PLAYERSPELL_CHANGED;
2905 break; // need re-add
2906 }
2907 default: // known not saved yet spell (new or modified)
2908 {
2909 // can be in case spell loading but learned at some previous spell loading
2910 if (!IsInWorld() && !learning && !dependent_set)
2911 itr->second.state = PLAYERSPELL_UNCHANGED;
2912
2913 return false;
2914 }
2915 }
2916 }
2917
2918 if (!disabled_case) // skip new spell adding if spell already known (disabled spells case)
2919 {
2920 // non talent spell: learn low ranks (recursive call)
2921 if (uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spellId))
2922 {
2923 if (!IsInWorld() || disabled) // at spells loading, no output, but allow save
2924 AddSpell(prev_spell, active, true, true, disabled, false, fromSkill);
2925 else // at normal learning
2926 LearnSpell(prev_spell, true, fromSkill);
2927 }
2928
2929 std::pair<PlayerSpellMap::iterator, bool> inserted = m_spells.emplace(std::piecewise_construct, std::forward_as_tuple(spellId), std::forward_as_tuple());
2930 PlayerSpell& newspell = inserted.first->second;
2931 // learning a previous rank might have given us this spell already from a skill autolearn, most likely with PLAYERSPELL_NEW state
2932 // we dont want to do double insert if this happened during load from db so we force state to CHANGED, just in case
2933 newspell.state = inserted.second ? state : PLAYERSPELL_CHANGED;
2934 newspell.active = active;
2935 newspell.dependent = dependent;
2936 newspell.disabled = disabled;
2937 newspell.favorite = favorite;
2938 if (traitDefinitionId)
2939 newspell.TraitDefinitionId = *traitDefinitionId;
2940
2941 // replace spells in action bars and spellbook to bigger rank if only one spell rank must be accessible
2942 if (newspell.active && !newspell.disabled && spellInfo->IsRanked())
2943 {
2944 for (PlayerSpellMap::iterator itr2 = m_spells.begin(); itr2 != m_spells.end(); ++itr2)
2945 {
2946 if (itr2->second.state == PLAYERSPELL_REMOVED)
2947 continue;
2948
2949 SpellInfo const* i_spellInfo = sSpellMgr->GetSpellInfo(itr2->first, DIFFICULTY_NONE);
2950 if (!i_spellInfo)
2951 continue;
2952
2953 if (spellInfo->IsDifferentRankOf(i_spellInfo))
2954 {
2955 if (itr2->second.active)
2956 {
2957 if (spellInfo->IsHighRankOf(i_spellInfo))
2958 {
2959 if (IsInWorld()) // not send spell (re-/over-)learn packets at loading
2960 SendSupercededSpell(itr2->first, spellId);
2961
2962 // mark old spell as disable (SMSG_SUPERCEDED_SPELL replace it in client by new)
2963 itr2->second.active = false;
2964 if (itr2->second.state != PLAYERSPELL_NEW)
2965 itr2->second.state = PLAYERSPELL_CHANGED;
2966 superceded_old = true; // new spell replace old in action bars and spell book.
2967 }
2968 else
2969 {
2970 if (IsInWorld()) // not send spell (re-/over-)learn packets at loading
2971 SendSupercededSpell(spellId, itr2->first);
2972
2973 // mark new spell as disable (not learned yet for client and will not learned)
2974 newspell.active = false;
2975 if (newspell.state != PLAYERSPELL_NEW)
2976 newspell.state = PLAYERSPELL_CHANGED;
2977 }
2978 }
2979 }
2980 }
2981 }
2982
2983 // return false if spell disabled
2984 if (newspell.disabled)
2985 return false;
2986 }
2987
2988 bool castSpell = false;
2989
2990 // cast talents with SPELL_EFFECT_LEARN_SPELL (other dependent spells will learned later as not auto-learned)
2991 // note: all spells with SPELL_EFFECT_LEARN_SPELL isn't passive
2992 if (!loading && spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT) && spellInfo->HasEffect(SPELL_EFFECT_LEARN_SPELL))
2993 // ignore stance requirement for talent learn spell (stance set for spell only for client spell description show)
2994 castSpell = true;
2995 // also cast passive spells (including all talents without SPELL_EFFECT_LEARN_SPELL) with additional checks
2996 else if (spellInfo->IsPassive())
2997 castSpell = HandlePassiveSpellLearn(spellInfo);
2998 else if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP))
2999 castSpell = true;
3000 else if (spellInfo->HasAttribute(SPELL_ATTR1_CAST_WHEN_LEARNED))
3001 castSpell = true;
3002
3003 if (castSpell)
3004 {
3005 CastSpellExtraArgs args;
3007
3008 if (traitDefinitionId)
3009 {
3010 if (UF::TraitConfig const* traitConfig = GetTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID))
3011 {
3012 int32 traitEntryIndex = traitConfig->Entries.FindIndexIf([traitDefinitionId](UF::TraitEntry const& traitEntry)
3013 {
3014 return sTraitNodeEntryStore.AssertEntry(traitEntry.TraitNodeEntryID)->TraitDefinitionID == traitDefinitionId;
3015 });
3016 int32 rank = 0;
3017 if (traitEntryIndex >= 0)
3018 rank = traitConfig->Entries[traitEntryIndex].Rank + traitConfig->Entries[traitEntryIndex].GrantedRanks;
3019
3020 if (rank > 0)
3021 {
3022 if (std::vector<TraitDefinitionEffectPointsEntry const*> const* traitDefinitionEffectPoints = TraitMgr::GetTraitDefinitionEffectPointModifiers(*traitDefinitionId))
3023 {
3024 for (TraitDefinitionEffectPointsEntry const* traitDefinitionEffectPoint : *traitDefinitionEffectPoints)
3025 {
3026 if (traitDefinitionEffectPoint->EffectIndex >= int32(spellInfo->GetEffects().size()))
3027 continue;
3028
3029 float basePoints = sDB2Manager.GetCurveValueAt(traitDefinitionEffectPoint->CurveID, rank);
3030 if (traitDefinitionEffectPoint->GetOperationType() == TraitPointsOperationType::Multiply)
3031 basePoints *= spellInfo->GetEffect(SpellEffIndex(traitDefinitionEffectPoint->EffectIndex)).CalcBaseValue(this, nullptr, 0, -1);
3032
3033 args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + traitDefinitionEffectPoint->EffectIndex), basePoints);
3034 }
3035 }
3036 }
3037 }
3038 }
3039
3040 CastSpell(this, spellId, args);
3041 if (spellInfo->HasEffect(SPELL_EFFECT_SKILL_STEP))
3042 return false;
3043 }
3044
3045 if (traitDefinitionId)
3046 if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(*traitDefinitionId))
3047 AddOverrideSpell(traitDefinition->OverridesSpellID, spellId);
3048
3049 // update free primary prof.points (if any, can be none in case GM .learn prof. learning)
3050 if (uint32 freeProfs = GetFreePrimaryProfessionPoints())
3051 {
3052 if (spellInfo->IsPrimaryProfessionFirstRank())
3053 SetFreePrimaryProfessions(freeProfs - 1);
3054 }
3055
3056 SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
3057
3058 if (SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spellId))
3059 {
3060 // add dependent skills if this spell is not learned from adding skill already
3061 if (spellLearnSkill->skill != fromSkill)
3062 {
3063 uint16 skill_value = GetPureSkillValue(spellLearnSkill->skill);
3064 uint16 skill_max_value = GetPureMaxSkillValue(spellLearnSkill->skill);
3065
3066 if (skill_value < spellLearnSkill->value)
3067 skill_value = spellLearnSkill->value;
3068
3069 uint16 new_skill_max_value = spellLearnSkill->maxvalue;
3070
3071 if (new_skill_max_value == 0)
3072 {
3073 if (SkillRaceClassInfoEntry const* rcInfo = sDB2Manager.GetSkillRaceClassInfo(spellLearnSkill->skill, GetRace(), GetClass()))
3074 {
3075 switch (GetSkillRangeType(rcInfo))
3076 {
3078 skill_value = 300;
3079 new_skill_max_value = 300;
3080 break;
3081 case SKILL_RANGE_LEVEL:
3082 new_skill_max_value = GetMaxSkillValueForLevel();
3083 break;
3084 case SKILL_RANGE_MONO:
3085 new_skill_max_value = 1;
3086 break;
3087 case SKILL_RANGE_RANK:
3088 {
3089 SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcInfo->SkillTierID);
3090 new_skill_max_value = tier->GetValueForTierIndex(spellLearnSkill->step - 1);
3091 break;
3092 }
3093 default:
3094 break;
3095 }
3096
3097 if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
3098 skill_value = new_skill_max_value;
3099 }
3100 }
3101
3102 if (skill_max_value < new_skill_max_value)
3103 skill_max_value = new_skill_max_value;
3104
3105 SetSkill(spellLearnSkill->skill, spellLearnSkill->step, skill_value, skill_max_value);
3106 }
3107 }
3108 else
3109 {
3110 // not ranked skills
3111 for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
3112 {
3113 SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
3114 if (!pSkill)
3115 continue;
3116
3117 if (_spell_idx->second->SkillLine == fromSkill)
3118 continue;
3119
3120 // Runeforging special case
3121 if ((_spell_idx->second->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(_spell_idx->second->SkillLine)) || ((_spell_idx->second->SkillLine == SKILL_RUNEFORGING) && _spell_idx->second->TrivialSkillLineRankHigh == 0))
3122 if (SkillRaceClassInfoEntry const* rcInfo = sDB2Manager.GetSkillRaceClassInfo(_spell_idx->second->SkillLine, GetRace(), GetClass()))
3123 LearnDefaultSkill(rcInfo);
3124 }
3125 }
3126
3127 // learn dependent spells
3128 SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spellId);
3129
3130 for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
3131 {
3132 if (!itr2->second.AutoLearned)
3133 {
3134 if (!IsInWorld() || !itr2->second.Active) // at spells loading, no output, but allow save
3135 AddSpell(itr2->second.Spell, itr2->second.Active, true, true, false);
3136 else // at normal learning
3137 LearnSpell(itr2->second.Spell, true);
3138 }
3139
3140 if (itr2->second.OverridesSpell && itr2->second.Active)
3141 AddOverrideSpell(itr2->second.OverridesSpell, itr2->second.Spell);
3142 }
3143
3144 if (!GetSession()->PlayerLoading())
3145 {
3146 // not ranked skills
3147 for (SkillLineAbilityMap::const_iterator _spell_idx = skill_bounds.first; _spell_idx != skill_bounds.second; ++_spell_idx)
3148 {
3149 UpdateCriteria(CriteriaType::LearnTradeskillSkillLine, _spell_idx->second->SkillLine);
3150 UpdateCriteria(CriteriaType::LearnSpellFromSkillLine, _spell_idx->second->SkillLine);
3151 }
3152
3154 }
3155
3156 // needs to be when spell is already learned, to prevent infinite recursion crashes
3157 if (sDB2Manager.GetMount(spellId))
3158 GetSession()->GetCollectionMgr()->AddMount(spellId, MOUNT_STATUS_NONE, false, IsInWorld() ? false : true);
3159
3160 // return true (for send learn packet) only if spell active (in case ranked spells) and not replace old spell
3161 return active && !disabled && !superceded_old;
3162}
3163
3165{
3166 PlayerSpellMap::iterator itr = m_spells.find(spellId);
3167 // spell already added - do not do anything
3168 if (itr != m_spells.end())
3169 return;
3170 PlayerSpell* newspell = &m_spells[spellId];
3171 newspell->state = PLAYERSPELL_TEMPORARY;
3172 newspell->active = true;
3173 newspell->dependent = false;
3174 newspell->disabled = false;
3175}
3176
3178{
3179 PlayerSpellMap::iterator itr = m_spells.find(spellId);
3180 // spell already not in list - do not do anything
3181 if (itr == m_spells.end())
3182 return;
3183 // spell has other state than temporary - do not change it
3184 if (itr->second.state != PLAYERSPELL_TEMPORARY)
3185 return;
3186 m_spells.erase(itr);
3187}
3188
3190{
3191 // note: form passives activated with shapeshift spells be implemented by HandleShapeshiftBoosts instead of spell_learn_spell
3192 // talent dependent passives activated at form apply have proper stance data
3194 bool need_cast = (!spellInfo->Stances || (form && (spellInfo->Stances & (UI64LIT(1) << (form - 1)))) ||
3196
3197 // Check EquippedItemClass
3198 // passive spells which apply aura and have an item requirement are to be added manually, instead of casted
3199 if (spellInfo->EquippedItemClass >= 0)
3200 {
3201 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
3202 {
3203 if (spellEffectInfo.IsAura())
3204 {
3205 if (!HasAura(spellInfo->Id) && HasItemFitToSpellRequirements(spellInfo))
3206 AddAura(spellInfo->Id, this);
3207 return false;
3208 }
3209 }
3210 }
3211
3212 //Check CasterAuraStates
3213 return need_cast && (!spellInfo->CasterAuraState || HasAuraState(AuraStateType(spellInfo->CasterAuraState)));
3214}
3215
3216void Player::LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill /*= 0*/, bool suppressMessaging /*= false*/, Optional<int32> traitDefinitionId /*= {}*/)
3217{
3218 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
3219
3220 bool disabled = (itr != m_spells.end()) ? itr->second.disabled : false;
3221 bool active = disabled ? itr->second.active : true;
3222 bool favorite = itr != m_spells.end() ? itr->second.favorite : false;
3223
3224 bool learning = AddSpell(spell_id, active, true, dependent, false, false, fromSkill, favorite, traitDefinitionId);
3225
3226 // prevent duplicated entires in spell book, also not send if not in world (loading)
3227 if (learning && IsInWorld())
3228 {
3230 WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = learnedSpells.ClientLearnedSpellData.emplace_back();
3231 learnedSpellInfo.SpellID = spell_id;
3232 learnedSpellInfo.IsFavorite = favorite;
3233 learnedSpellInfo.TraitDefinitionID = traitDefinitionId;
3234 learnedSpells.SuppressMessaging = suppressMessaging;
3235 SendDirectMessage(learnedSpells.Write());
3236 }
3237
3238 // learn all disabled higher ranks and required spells (recursive)
3239 if (disabled)
3240 {
3241 if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
3242 {
3243 PlayerSpellMap::iterator iter = m_spells.find(nextSpell);
3244 if (iter != m_spells.end() && iter->second.disabled)
3245 LearnSpell(nextSpell, false, fromSkill);
3246 }
3247
3248 SpellsRequiringSpellMapBounds spellsRequiringSpell = sSpellMgr->GetSpellsRequiringSpellBounds(spell_id);
3249 for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequiringSpell.first; itr2 != spellsRequiringSpell.second; ++itr2)
3250 {
3251 PlayerSpellMap::iterator iter2 = m_spells.find(itr2->second);
3252 if (iter2 != m_spells.end() && iter2->second.disabled)
3253 LearnSpell(itr2->second, false, fromSkill);
3254 }
3255 }
3256 else
3258}
3259
3260void Player::RemoveSpell(uint32 spell_id, bool disabled /*= false*/, bool learn_low_rank /*= true*/, bool suppressMessaging /*= false*/)
3261{
3262 PlayerSpellMap::iterator itr = m_spells.find(spell_id);
3263 if (itr == m_spells.end())
3264 return;
3265
3266 if (itr->second.state == PLAYERSPELL_REMOVED || (disabled && itr->second.disabled) || itr->second.state == PLAYERSPELL_TEMPORARY)
3267 return;
3268
3269 // unlearn non talent higher ranks (recursive)
3270 if (uint32 nextSpell = sSpellMgr->GetNextSpellInChain(spell_id))
3271 {
3272 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(nextSpell, DIFFICULTY_NONE);
3273 if (HasSpell(nextSpell) && !spellInfo->HasAttribute(SPELL_ATTR0_CU_IS_TALENT))
3274 RemoveSpell(nextSpell, disabled, false);
3275 }
3276 //unlearn spells dependent from recently removed spells
3277 SpellsRequiringSpellMapBounds spellsRequiringSpell = sSpellMgr->GetSpellsRequiringSpellBounds(spell_id);
3278 for (SpellsRequiringSpellMap::const_iterator itr2 = spellsRequiringSpell.first; itr2 != spellsRequiringSpell.second; ++itr2)
3279 RemoveSpell(itr2->second, disabled);
3280
3281 // re-search, it can be corrupted in prev loop
3282 itr = m_spells.find(spell_id);
3283 if (itr == m_spells.end())
3284 return; // already unleared
3285
3286 bool cur_active = itr->second.active;
3287 bool cur_dependent = itr->second.dependent;
3288 Optional<int32> traitDefinitionId = itr->second.TraitDefinitionId;
3289
3290 if (disabled)
3291 {
3292 itr->second.disabled = disabled;
3293 if (itr->second.state != PLAYERSPELL_NEW)
3294 itr->second.state = PLAYERSPELL_CHANGED;
3295 }
3296 else
3297 {
3298 if (itr->second.state == PLAYERSPELL_NEW)
3299 m_spells.erase(itr);
3300 else
3301 itr->second.state = PLAYERSPELL_REMOVED;
3302 }
3303
3304 RemoveOwnedAura(spell_id, GetGUID());
3305
3306 // remove pet auras
3307 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
3308 if (PetAura const* petSpell = sSpellMgr->GetPetAura(spell_id, i))
3309 RemovePetAura(petSpell);
3310
3311 // update free primary prof.points (if not overflow setting, can be in case GM use before .learn prof. learning)
3312 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, DIFFICULTY_NONE);
3313 if (spellInfo && spellInfo->IsPrimaryProfessionFirstRank())
3314 {
3315 uint32 freeProfs = GetFreePrimaryProfessionPoints()+1;
3316 if (freeProfs <= sWorld->getIntConfig(CONFIG_MAX_PRIMARY_TRADE_SKILL))
3317 SetFreePrimaryProfessions(freeProfs);
3318 }
3319
3320 // remove dependent skill
3321 SpellLearnSkillNode const* spellLearnSkill = sSpellMgr->GetSpellLearnSkill(spell_id);
3322 if (spellLearnSkill)
3323 {
3324 uint32 prev_spell = sSpellMgr->GetPrevSpellInChain(spell_id);
3325 if (!prev_spell) // first rank, remove skill
3326 SetSkill(spellLearnSkill->skill, 0, 0, 0);
3327 else
3328 {
3329 // search prev. skill setting by spell ranks chain
3330 SpellLearnSkillNode const* prevSkill = sSpellMgr->GetSpellLearnSkill(prev_spell);
3331 while (!prevSkill && prev_spell)
3332 {
3333 prev_spell = sSpellMgr->GetPrevSpellInChain(prev_spell);
3334 prevSkill = sSpellMgr->GetSpellLearnSkill(sSpellMgr->GetFirstSpellInChain(prev_spell));
3335 }
3336
3337 if (!prevSkill) // not found prev skill setting, remove skill
3338 SetSkill(spellLearnSkill->skill, 0, 0, 0);
3339 else // set to prev. skill setting values
3340 {
3341 uint16 skill_value = GetPureSkillValue(prevSkill->skill);
3342 uint16 skill_max_value = GetPureMaxSkillValue(prevSkill->skill);
3343
3344 uint16 new_skill_max_value = prevSkill->maxvalue;
3345
3346 if (new_skill_max_value == 0)
3347 {
3348 if (SkillRaceClassInfoEntry const* rcInfo = sDB2Manager.GetSkillRaceClassInfo(prevSkill->skill, GetRace(), GetClass()))
3349 {
3350 switch (GetSkillRangeType(rcInfo))
3351 {
3353 skill_value = 300;
3354 new_skill_max_value = 300;
3355 break;
3356 case SKILL_RANGE_LEVEL:
3357 new_skill_max_value = GetMaxSkillValueForLevel();
3358 break;
3359 case SKILL_RANGE_MONO:
3360 new_skill_max_value = 1;
3361 break;
3362 case SKILL_RANGE_RANK:
3363 {
3364 SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcInfo->SkillTierID);
3365 new_skill_max_value = tier->GetValueForTierIndex(prevSkill->step - 1);
3366 break;
3367 }
3368 default:
3369 break;
3370 }
3371
3372 if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
3373 skill_value = new_skill_max_value;
3374 }
3375 }
3376 else if (skill_value > prevSkill->value)
3377 skill_value = prevSkill->value;
3378
3379 if (skill_max_value > new_skill_max_value)
3380 skill_max_value = new_skill_max_value;
3381
3382 if (skill_value > new_skill_max_value)
3383 skill_value = new_skill_max_value;
3384
3385 SetSkill(prevSkill->skill, prevSkill->step, skill_value, skill_max_value);
3386 }
3387 }
3388 }
3389
3390 // remove dependent spells
3391 SpellLearnSpellMapBounds spell_bounds = sSpellMgr->GetSpellLearnSpellMapBounds(spell_id);
3392
3393 for (SpellLearnSpellMap::const_iterator itr2 = spell_bounds.first; itr2 != spell_bounds.second; ++itr2)
3394 {
3395 RemoveSpell(itr2->second.Spell, disabled);
3396 if (itr2->second.OverridesSpell)
3397 RemoveOverrideSpell(itr2->second.OverridesSpell, itr2->second.Spell);
3398 }
3399
3400 // activate lesser rank in spellbook/action bar, and cast it if need
3401 bool prev_activate = false;
3402
3403 if (uint32 prev_id = sSpellMgr->GetPrevSpellInChain(spell_id))
3404 {
3405 // if ranked non-stackable spell: need activate lesser rank and update dendence state
3407 if (cur_active && spellInfo->IsRanked())
3408 {
3409 // need manually update dependence state (learn spell ignore like attempts)
3410 PlayerSpellMap::iterator prev_itr = m_spells.find(prev_id);
3411 if (prev_itr != m_spells.end())
3412 {
3413 if (prev_itr->second.dependent != cur_dependent)
3414 {
3415 prev_itr->second.dependent = cur_dependent;
3416 if (prev_itr->second.state != PLAYERSPELL_NEW)
3417 prev_itr->second.state = PLAYERSPELL_CHANGED;
3418 }
3419
3420 // now re-learn if need re-activate
3421 if (!prev_itr->second.active && learn_low_rank)
3422 {
3423 if (AddSpell(prev_id, true, false, prev_itr->second.dependent, prev_itr->second.disabled))
3424 {
3425 // downgrade spell ranks in spellbook and action bar
3426 SendSupercededSpell(spell_id, prev_id);
3427 prev_activate = true;
3428 }
3429 }
3430 }
3431 }
3432 }
3433
3434 if (traitDefinitionId)
3435 if (TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(*traitDefinitionId))
3436 RemoveOverrideSpell(traitDefinition->OverridesSpellID, spell_id);
3437
3438 m_overrideSpells.erase(spell_id);
3439
3440 if (m_canTitanGrip)
3441 {
3442 if (spellInfo && spellInfo->IsPassive() && spellInfo->HasEffect(SPELL_EFFECT_TITAN_GRIP))
3443 {
3445 SetCanTitanGrip(false);
3446 }
3447 }
3448
3449 if (m_canDualWield)
3450 {
3451 if (spellInfo && spellInfo->IsPassive() && spellInfo->HasEffect(SPELL_EFFECT_DUAL_WIELD))
3452 SetCanDualWield(false);
3453 }
3454
3457
3458 // remove from spell book if not replaced by lesser rank
3459 if (!prev_activate)
3460 {
3462 unlearnedSpells.SpellID.push_back(spell_id);
3463 unlearnedSpells.SuppressMessaging = suppressMessaging;
3464 SendDirectMessage(unlearnedSpells.Write());
3465 }
3466}
3467
3468void Player::SetSpellFavorite(uint32 spellId, bool favorite)
3469{
3470 auto itr = m_spells.find(spellId);
3471 if (itr == m_spells.end())
3472 return;
3473
3474 itr->second.favorite = favorite;
3475 if (itr->second.state == PLAYERSPELL_UNCHANGED)
3476 itr->second.state = PLAYERSPELL_CHANGED;
3477}
3478
3479void Player::RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
3480{
3481 // remove cooldowns on spells that have < 10 min CD
3482 GetSpellHistory()->ResetCooldowns([](SpellHistory::CooldownStorageType::iterator itr)
3483 {
3484 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itr->first, DIFFICULTY_NONE);
3485 return spellInfo->RecoveryTime < 10 * MINUTE * IN_MILLISECONDS
3486 && spellInfo->CategoryRecoveryTime < 10 * MINUTE * IN_MILLISECONDS
3488 }, true);
3489
3490 // pet cooldowns
3491 if (removeActivePetCooldowns)
3492 if (Pet* pet = GetPet())
3493 pet->GetSpellHistory()->ResetAllCooldowns();
3494}
3495
3497{
3498 // The first time reset costs 1 gold
3499 if (GetTalentResetCost() < 1*GOLD)
3500 return 1*GOLD;
3501 // then 5 gold
3502 else if (GetTalentResetCost() < 5*GOLD)
3503 return 5*GOLD;
3504 // After that it increases in increments of 5 gold
3505 else if (GetTalentResetCost() < 10*GOLD)
3506 return 10*GOLD;
3507 else
3508 {
3510 if (months > 0)
3511 {
3512 // This cost will be reduced by a rate of 5 gold per month
3513 int32 new_cost = int32(GetTalentResetCost() - 5*GOLD*months);
3514 // to a minimum of 10 gold.
3515 return (new_cost < 10*GOLD ? 10*GOLD : new_cost);
3516 }
3517 else
3518 {
3519 // After that it increases in increments of 5 gold
3520 int32 new_cost = GetTalentResetCost() + 5*GOLD;
3521 // until it hits a cap of 50 gold.
3522 if (new_cost > 50*GOLD)
3523 new_cost = 50*GOLD;
3524 return new_cost;
3525 }
3526 }
3527}
3528
3529bool Player::ResetTalents(bool noCost)
3530{
3531 sScriptMgr->OnPlayerTalentsReset(this, noCost);
3532
3533 // not need after this call
3536
3537 uint32 cost = 0;
3538
3539 if (!noCost && !sWorld->getBoolConfig(CONFIG_NO_RESET_TALENT_COST))
3540 {
3541 cost = GetNextResetTalentsCost();
3542
3543 if (!HasEnoughMoney(uint64(cost)))
3544 {
3546 return false;
3547 }
3548 }
3549
3550 RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT, true);
3551
3552 for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
3553 {
3554 TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
3555 if (!talentInfo)
3556 continue;
3557
3558 // unlearn only talents for character class
3559 // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
3560 // to prevent unexpected lost normal learned spell skip another class talents
3561 if (talentInfo->ClassID != GetClass())
3562 continue;
3563
3564 // skip non-existent talent ranks
3565 if (talentInfo->SpellID == 0)
3566 continue;
3567
3568 RemoveTalent(talentInfo);
3569 }
3570
3571 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3572 _SaveTalents(trans);
3573 _SaveSpells(trans);
3574 CharacterDatabase.CommitTransaction(trans);
3575
3576 if (!noCost)
3577 {
3578 ModifyMoney(-(int64)cost);
3581
3582 SetTalentResetCost(cost);
3584 }
3585
3586 /* when prev line will dropped use next line
3587 if (Pet* pet = GetPet())
3588 {
3589 if (pet->getPetType() == HUNTER_PET && !pet->GetCreatureTemplate()->IsTameable(CanTameExoticPets()))
3590 RemovePet(nullptr, PET_SAVE_NOT_IN_SLOT, true);
3591 }
3592 */
3593
3594 return true;
3595}
3596
3598{
3599 for (uint8 spec = 0; spec < MAX_SPECIALIZATIONS; ++spec)
3600 for (uint32 talentId : GetPvpTalentMap(spec))
3601 if (PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(talentId))
3602 RemovePvpTalent(talentInfo, spec);
3603}
3604
3606{
3607 for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
3608 if ((*itr)->messageID == id)
3609 return (*itr);
3610
3611 return nullptr;
3612}
3613
3615{
3616 if (target == this)
3617 {
3618 for (uint8 i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; ++i)
3619 {
3620 if (m_items[i] == nullptr)
3621 continue;
3622
3623 m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
3624 }
3625
3627 {
3628 if (m_items[i] == nullptr)
3629 continue;
3630
3631 m_items[i]->BuildCreateUpdateBlockForPlayer(data, target);
3632 }
3633 }
3634
3636}
3637
3639{
3641 if (IsInSameRaidWith(target))
3643
3644 return flags;
3645}
3646
3647void Player::BuildValuesCreate(ByteBuffer* data, Player const* target) const
3648{
3650 std::size_t sizePos = data->wpos();
3651 *data << uint32(0);
3652 *data << uint8(flags);
3653 m_objectData->WriteCreate(*data, flags, this, target);
3654 m_unitData->WriteCreate(*data, flags, this, target);
3655 m_playerData->WriteCreate(*data, flags, this, target);
3656 if (target == this)
3657 m_activePlayerData->WriteCreate(*data, flags, this, target);
3658
3659 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
3660}
3661
3662void Player::BuildValuesUpdate(ByteBuffer* data, Player const* target) const
3663{
3665 std::size_t sizePos = data->wpos();
3666 *data << uint32(0);
3667 *data << uint32(m_values.GetChangedObjectTypeMask() & ~(uint32(target != this) << TYPEID_ACTIVE_PLAYER));
3668
3670 m_objectData->WriteUpdate(*data, flags, this, target);
3671
3673 m_unitData->WriteUpdate(*data, flags, this, target);
3674
3676 m_playerData->WriteUpdate(*data, flags, this, target);
3677
3678 if (target == this && m_values.HasChanged(TYPEID_ACTIVE_PLAYER))
3679 m_activePlayerData->WriteUpdate(*data, flags, this, target);
3680
3681 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
3682}
3683
3685{
3687 valuesMask.Set(TYPEID_UNIT);
3688 valuesMask.Set(TYPEID_PLAYER);
3689
3690 std::size_t sizePos = data->wpos();
3691 *data << uint32(0);
3692 *data << uint32(valuesMask.GetBlock(0));
3693
3694 UF::UnitData::Mask mask;
3695 m_unitData->AppendAllowedFieldsMaskForFlag(mask, flags);
3696 m_unitData->WriteUpdate(*data, mask, true, this, target);
3697
3699 m_playerData->AppendAllowedFieldsMaskForFlag(mask2, flags);
3700 m_playerData->WriteUpdate(*data, mask2, true, this, target);
3701
3702 data->put<uint32>(sizePos, data->wpos() - sizePos - 4);
3703}
3704
3706 UF::UnitData::Mask const& requestedUnitMask, UF::PlayerData::Mask const& requestedPlayerMask,
3707 UF::ActivePlayerData::Mask const& requestedActivePlayerMask, Player const* target) const
3708{
3711 if (requestedObjectMask.IsAnySet())
3712 valuesMask.Set(TYPEID_OBJECT);
3713
3714 UF::UnitData::Mask unitMask = requestedUnitMask;
3715 m_unitData->FilterDisallowedFieldsMaskForFlag(unitMask, flags);
3716 if (unitMask.IsAnySet())
3717 valuesMask.Set(TYPEID_UNIT);
3718
3719 UF::PlayerData::Mask playerMask = requestedPlayerMask;
3720 m_playerData->FilterDisallowedFieldsMaskForFlag(playerMask, flags);
3721 if (playerMask.IsAnySet())
3722 valuesMask.Set(TYPEID_PLAYER);
3723
3724 if (target == this && requestedActivePlayerMask.IsAnySet())
3725 valuesMask.Set(TYPEID_ACTIVE_PLAYER);
3726
3727 ByteBuffer& buffer = PrepareValuesUpdateBuffer(data);
3728 std::size_t sizePos = buffer.wpos();
3729 buffer << uint32(0);
3730 buffer << uint32(valuesMask.GetBlock(0));
3731
3732 if (valuesMask[TYPEID_OBJECT])
3733 m_objectData->WriteUpdate(buffer, requestedObjectMask, true, this, target);
3734
3735 if (valuesMask[TYPEID_UNIT])
3736 m_unitData->WriteUpdate(buffer, unitMask, true, this, target);
3737
3738 if (valuesMask[TYPEID_PLAYER])
3739 m_playerData->WriteUpdate(buffer, playerMask, true, this, target);
3740
3741 if (valuesMask[TYPEID_ACTIVE_PLAYER])
3742 m_activePlayerData->WriteUpdate(buffer, requestedActivePlayerMask, true, this, target);
3743
3744 buffer.put<uint32>(sizePos, buffer.wpos() - sizePos - 4);
3745
3746 data->AddUpdateBlock();
3747}
3748
3750{
3751 UpdateData udata(Owner->GetMapId());
3752 WorldPacket packet;
3753
3756
3757 udata.BuildPacket(&packet);
3758 player->SendDirectMessage(&packet);
3759}
3760
3762{
3763 Unit::DestroyForPlayer(target);
3764
3765 if (target == this)
3766 {
3767 for (uint8 i = EQUIPMENT_SLOT_START; i < BANK_SLOT_BAG_END; ++i)
3768 {
3769 if (m_items[i] == nullptr)
3770 continue;
3771
3772 m_items[i]->DestroyForPlayer(target);
3773 }
3774
3776 {
3777 if (m_items[i] == nullptr)
3778 continue;
3779
3780 m_items[i]->DestroyForPlayer(target);
3781 }
3782 }
3783}
3784
3786{
3789 Unit::ClearUpdateMask(remove);
3790}
3791
3792bool Player::HasSpell(uint32 spell) const
3793{
3794 PlayerSpellMap::const_iterator itr = m_spells.find(spell);
3795 return (itr != m_spells.end() && itr->second.state != PLAYERSPELL_REMOVED &&
3796 !itr->second.disabled);
3797}
3798
3799bool Player::HasTalent(uint32 talentId, uint8 group) const
3800{
3801 PlayerTalentMap::const_iterator itr = GetTalentMap(group)->find(talentId);
3802 return (itr != GetTalentMap(group)->end() && itr->second != PLAYERSPELL_REMOVED);
3803}
3804
3806{
3807 PlayerSpellMap::const_iterator itr = m_spells.find(spell);
3808 return (itr != m_spells.end() && itr->second.state != PLAYERSPELL_REMOVED &&
3809 itr->second.active && !itr->second.disabled);
3810}
3811
3824void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars, bool deleteFinally)
3825{
3826 // Avoid realm-update for non-existing account
3827 if (accountId == 0)
3828 updateRealmChars = false;
3829
3830 // Convert guid to low GUID for CharacterNameData, but also other methods on success
3831 ObjectGuid::LowType guid = playerguid.GetCounter();
3832 uint32 charDeleteMethod = sWorld->getIntConfig(CONFIG_CHARDELETE_METHOD);
3833 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(playerguid);
3834 std::string name;
3835 if (characterInfo)
3836 name = characterInfo->Name;
3837
3838 if (deleteFinally)
3839 charDeleteMethod = CHAR_DELETE_REMOVE;
3840 else if (characterInfo) // To avoid a query, we select loaded data. If it doesn't exist, return.
3841 {
3842 // Define the required variables
3843 uint32 charDeleteMinLvl;
3844
3845 if (characterInfo->Class == CLASS_DEATH_KNIGHT)
3846 charDeleteMinLvl = sWorld->getIntConfig(CONFIG_CHARDELETE_DEATH_KNIGHT_MIN_LEVEL);
3847 else if (characterInfo->Class == CLASS_DEMON_HUNTER)
3848 charDeleteMinLvl = sWorld->getIntConfig(CONFIG_CHARDELETE_DEMON_HUNTER_MIN_LEVEL);
3849 else
3850 charDeleteMinLvl = sWorld->getIntConfig(CONFIG_CHARDELETE_MIN_LEVEL);
3851
3852 // if we want to finalize the character removal or the character does not meet the level requirement of either heroic or non-heroic settings,
3853 // we set it to mode CHAR_DELETE_REMOVE
3854 if (characterInfo->Level < charDeleteMinLvl)
3855 charDeleteMethod = CHAR_DELETE_REMOVE;
3856 }
3857
3858 LoginDatabaseTransaction loginTransaction = LoginDatabase.BeginTransaction();
3859 LoginDatabasePreparedStatement* loginStmt = nullptr;
3860
3861 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
3862 if (ObjectGuid::LowType guildId = sCharacterCache->GetCharacterGuildIdByGuid(playerguid))
3863 if (Guild* guild = sGuildMgr->GetGuildById(guildId))
3864 guild->DeleteMember(trans, playerguid, false, false);
3865
3866 // remove from arena teams
3867 LeaveAllArenaTeams(playerguid);
3868
3869 // the player was uninvited already on logout so just remove from group
3871 stmt->setUInt64(0, guid);
3872 PreparedQueryResult resultGroup = CharacterDatabase.Query(stmt);
3873
3874 if (resultGroup)
3875 if (Group* group = sGroupMgr->GetGroupByDbStoreId((*resultGroup)[0].GetUInt32()))
3876 RemoveFromGroup(group, playerguid);
3877
3878 // Remove signs from petitions (also remove petitions if owner);
3879 RemovePetitionsAndSigns(playerguid);
3880
3881 switch (charDeleteMethod)
3882 {
3883 // Completely remove from the database
3884 case CHAR_DELETE_REMOVE:
3885 {
3886 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_COD_ITEM_MAIL);
3887 stmt->setUInt64(0, guid);
3888 PreparedQueryResult resultMail = CharacterDatabase.Query(stmt);
3889
3890 if (resultMail)
3891 {
3892 std::unordered_map<uint64, std::vector<Item*>> itemsByMail;
3893
3894 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
3895 stmt->setUInt64(0, guid);
3896 PreparedQueryResult resultItems = CharacterDatabase.Query(stmt);
3897
3898 if (resultItems)
3899 {
3900 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_ARTIFACT);
3901 stmt->setUInt64(0, guid);
3902 PreparedQueryResult artifactResult = CharacterDatabase.Query(stmt);
3903
3904 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE);
3905 stmt->setUInt64(0, guid);
3906 PreparedQueryResult azeriteResult = CharacterDatabase.Query(stmt);
3907
3909 stmt->setUInt64(0, guid);
3910 PreparedQueryResult azeriteItemMilestonePowersResult = CharacterDatabase.Query(stmt);
3911
3913 stmt->setUInt64(0, guid);
3914 PreparedQueryResult azeriteItemUnlockedEssencesResult = CharacterDatabase.Query(stmt);
3915
3916 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS_AZERITE_EMPOWERED);
3917 stmt->setUInt64(0, guid);
3918 PreparedQueryResult azeriteEmpoweredItemResult = CharacterDatabase.Query(stmt);
3919
3920 std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo> additionalData;
3921 ItemAdditionalLoadInfo::Init(&additionalData, artifactResult, azeriteResult, azeriteItemMilestonePowersResult,
3922 azeriteItemUnlockedEssencesResult, azeriteEmpoweredItemResult);
3923
3924 do
3925 {
3926 Field* fields = resultItems->Fetch();
3927 uint64 mailId = fields[44].GetUInt64();
3928 if (Item* mailItem = _LoadMailedItem(playerguid, nullptr, mailId, nullptr, fields, Trinity::Containers::MapGetValuePtr(additionalData, fields[0].GetUInt64())))
3929 itemsByMail[mailId].push_back(mailItem);
3930
3931 } while (resultItems->NextRow());
3932 }
3933
3934 do
3935 {
3936 Field* mailFields = resultMail->Fetch();
3937
3938 uint64 mail_id = mailFields[0].GetUInt64();
3939 uint8 mailType = mailFields[1].GetUInt8();
3940 uint16 mailTemplateId= mailFields[2].GetUInt16();
3941 ObjectGuid::LowType sender = mailFields[3].GetUInt64();
3942 std::string subject = mailFields[4].GetString();
3943 std::string body = mailFields[5].GetString();
3944 uint64 money = mailFields[6].GetUInt64();
3945 bool has_items = mailFields[7].GetBool();
3946
3947 // We can return mail now
3948 // So firstly delete the old one
3949 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
3950 stmt->setUInt64(0, mail_id);
3951 trans->Append(stmt);
3952
3953 // Mail is not from player
3954 if (mailType != MAIL_NORMAL)
3955 {
3956 if (has_items)
3957 {
3958 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
3959 stmt->setUInt64(0, mail_id);
3960 trans->Append(stmt);
3961 }
3962 continue;
3963 }
3964
3965 MailDraft draft(subject, body);
3966 if (mailTemplateId)
3967 draft = MailDraft(mailTemplateId, false); // items are already included
3968
3969 auto itemsItr = itemsByMail.find(mail_id);
3970 if (itemsItr != itemsByMail.end())
3971 {
3972 for (Item* item : itemsItr->second)
3973 draft.AddItem(item);
3974
3975 // MailDraft will take care of freeing memory
3976 itemsByMail.erase(itemsItr);
3977 }
3978
3979 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
3980 stmt->setUInt64(0, mail_id);
3981 trans->Append(stmt);
3982
3983 uint32 pl_account = sCharacterCache->GetCharacterAccountIdByGuid(playerguid);
3984
3985 draft.AddMoney(money).SendReturnToSender(pl_account, guid, sender, trans);
3986 }
3987 while (resultMail->NextRow());
3988
3989 // Free remaining items
3990 for (auto&& kvp : itemsByMail)
3991 for (Item* item : kvp.second)
3992 delete item;
3993 }
3994
3995 // Unsummon and delete for pets in world is not required: player deleted from CLI or character list with not loaded pet.
3996 // NOW we can finally clear other DB data related to character
3997 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PET_IDS);
3998 stmt->setUInt64(0, guid);
3999 PreparedQueryResult resultPets = CharacterDatabase.Query(stmt);
4000
4001 if (resultPets)
4002 {
4003 do
4004 {
4005 uint32 petguidlow = (*resultPets)[0].GetUInt32();
4006 Pet::DeleteFromDB(petguidlow);
4007 } while (resultPets->NextRow());
4008 }
4009
4010 // Delete char from social list of online chars
4011 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SOCIAL);
4012 stmt->setUInt64(0, guid);
4013
4014 if (PreparedQueryResult resultFriends = CharacterDatabase.Query(stmt))
4015 {
4016 do
4017 {
4018 if (Player* playerFriend = ObjectAccessor::FindPlayer(ObjectGuid::Create<HighGuid::Player>((*resultFriends)[0].GetUInt64())))
4019 {
4020 playerFriend->GetSocial()->RemoveFromSocialList(playerguid, SOCIAL_FLAG_ALL);
4021 sSocialMgr->SendFriendStatus(playerFriend, FRIEND_REMOVED, playerguid);
4022 }
4023 } while (resultFriends->NextRow());
4024 }
4025
4026 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER);
4027 stmt->setUInt64(0, guid);
4028 trans->Append(stmt);
4029
4030 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_CUSTOMIZATIONS);
4031 stmt->setUInt64(0, guid);
4032 trans->Append(stmt);
4033
4034 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_ACCOUNT_DATA);
4035 stmt->setUInt64(0, guid);
4036 trans->Append(stmt);
4037
4038 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_DECLINED_NAME);
4039 stmt->setUInt64(0, guid);
4040 trans->Append(stmt);
4041
4042 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION);
4043 stmt->setUInt64(0, guid);
4044 trans->Append(stmt);
4045
4046 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_ARENA_STATS);
4047 stmt->setUInt64(0, guid);
4048 trans->Append(stmt);
4049
4050 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA_EFFECT);
4051 stmt->setUInt64(0, guid);
4052 trans->Append(stmt);
4053
4054 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
4055 stmt->setUInt64(0, guid);
4056 trans->Append(stmt);
4057
4058 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_BGDATA);
4059 stmt->setUInt64(0, guid);
4060 trans->Append(stmt);
4061
4062 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_BATTLEGROUND_RANDOM);
4063 stmt->setUInt64(0, guid);
4064 trans->Append(stmt);
4065
4066 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_CUF_PROFILES);
4067 stmt->setUInt64(0, guid);
4068 trans->Append(stmt);
4069
4070 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_CURRENCY);
4071 stmt->setUInt64(0, guid);
4072 trans->Append(stmt);
4073
4074 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GIFT);
4075 stmt->setUInt64(0, guid);
4076 trans->Append(stmt);
4077
4078 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
4079 stmt->setUInt64(0, guid);
4080 trans->Append(stmt);
4081
4083 stmt->setUInt64(0, guid);
4084 trans->Append(stmt);
4085
4086 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY);
4087 stmt->setUInt64(0, guid);
4088 trans->Append(stmt);
4089
4090 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS);
4091 stmt->setUInt64(0, guid);
4092 trans->Append(stmt);
4093
4094 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES);
4095 stmt->setUInt64(0, guid);
4096 trans->Append(stmt);
4097
4098 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED);
4099 stmt->setUInt64(0, guid);
4100 trans->Append(stmt);
4101
4102 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_REPUTATION);
4103 stmt->setUInt64(0, guid);
4104 trans->Append(stmt);
4105
4106 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL);
4107 stmt->setUInt64(0, guid);
4108 trans->Append(stmt);
4109
4110 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWNS);
4111 stmt->setUInt64(0, guid);
4112 trans->Append(stmt);
4113
4114 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_CHARGES);
4115 stmt->setUInt64(0, guid);
4116 trans->Append(stmt);
4117
4118 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_GEMS_BY_OWNER);
4119 stmt->setUInt64(0, guid);
4120 trans->Append(stmt);
4121
4123 stmt->setUInt64(0, guid);
4124 trans->Append(stmt);
4125
4127 stmt->setUInt64(0, guid);
4128 trans->Append(stmt);
4129
4131 stmt->setUInt64(0, guid);
4132 trans->Append(stmt);
4133
4135 stmt->setUInt64(0, guid);
4136 trans->Append(stmt);
4137
4139 stmt->setUInt64(0, guid);
4140 trans->Append(stmt);
4141
4143 stmt->setUInt64(0, guid);
4144 trans->Append(stmt);
4145
4147 stmt->setUInt64(0, guid);
4148 trans->Append(stmt);
4149
4151 stmt->setUInt64(0, guid);
4152 trans->Append(stmt);
4153
4154 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE_BY_OWNER);
4155 stmt->setUInt64(0, guid);
4156 trans->Append(stmt);
4157
4158 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_FRIEND);
4159 stmt->setUInt64(0, guid);
4160 trans->Append(stmt);
4161
4162 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SOCIAL_BY_GUID);
4163 stmt->setUInt64(0, guid);
4164 trans->Append(stmt);
4165
4166 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL);
4167 stmt->setUInt64(0, guid);
4168 trans->Append(stmt);
4169
4170 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEMS);
4171 stmt->setUInt64(0, guid);
4172 trans->Append(stmt);
4173
4174 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PET_BY_OWNER);
4175 stmt->setUInt64(0, guid);
4176 trans->Append(stmt);
4177
4179 stmt->setUInt64(0, guid);
4180 trans->Append(stmt);
4181
4182 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENTS);
4183 stmt->setUInt64(0, guid);
4184 trans->Append(stmt);
4185
4186 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS);
4187 stmt->setUInt64(0, guid);
4188 trans->Append(stmt);
4189
4190 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_EQUIPMENTSETS);
4191 stmt->setUInt64(0, guid);
4192 trans->Append(stmt);
4193
4194 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRANSMOG_OUTFITS);
4195 stmt->setUInt64(0, guid);
4196 trans->Append(stmt);
4197
4198 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER);
4199 stmt->setUInt64(0, guid);
4200 stmt->setUInt64(1, guid);
4201 trans->Append(stmt);
4202
4203 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER);
4204 stmt->setUInt64(0, guid);
4205 trans->Append(stmt);
4206
4207 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS);
4208 stmt->setUInt64(0, guid);
4209 trans->Append(stmt);
4210
4211 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY);
4212 stmt->setUInt64(0, guid);
4213 trans->Append(stmt);
4214
4215 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY);
4216 stmt->setUInt64(0, guid);
4217 trans->Append(stmt);
4218
4219 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY);
4220 stmt->setUInt64(0, guid);
4221 trans->Append(stmt);
4222
4224 stmt->setUInt64(0, guid);
4225 trans->Append(stmt);
4226
4227 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT);
4228 stmt->setUInt64(0, guid);
4229 trans->Append(stmt);
4230
4231 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILLS);
4232 stmt->setUInt64(0, guid);
4233 trans->Append(stmt);
4234
4235 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS);
4236 stmt->setUInt64(0, guid);
4237 trans->Append(stmt);
4238
4240 stmt->setUInt64(0, guid);
4241 trans->Append(stmt);
4242
4243 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_FISHINGSTEPS);
4244 stmt->setUInt64(0, guid);
4245 trans->Append(stmt);
4246
4248 stmt->setUInt64(0, guid);
4249 trans->Append(stmt);
4250
4252 stmt->setUInt64(0, guid);
4253 trans->Append(stmt);
4254
4255 loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BATTLE_PET_DECLINED_NAME_BY_OWNER);
4256 loginStmt->setInt64(0, guid);
4257 loginStmt->setInt32(1, realm.Id.Realm);
4258 loginTransaction->Append(loginStmt);
4259
4260 loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_DEL_BATTLE_PETS_BY_OWNER);
4261 loginStmt->setInt64(0, guid);
4262 loginStmt->setInt32(1, realm.Id.Realm);
4263 loginTransaction->Append(loginStmt);
4264
4265 Corpse::DeleteFromDB(playerguid, trans);
4266
4267 Garrison::DeleteFromDB(guid, trans);
4268
4269 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRAIT_ENTRIES_BY_CHAR);
4270 stmt->setUInt64(0, guid);
4271 trans->Append(stmt);
4272
4273 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRAIT_CONFIGS_BY_CHAR);
4274 stmt->setUInt64(0, guid);
4275 trans->Append(stmt);
4276
4277 sCharacterCache->DeleteCharacterCacheEntry(playerguid, name);
4278 break;
4279 }
4280 // The character gets unlinked from the account, the name gets freed up and appears as deleted ingame
4281 case CHAR_DELETE_UNLINK:
4282 {
4283 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_DELETE_INFO);
4284 stmt->setUInt64(0, guid);
4285 trans->Append(stmt);
4286 sCharacterCache->UpdateCharacterInfoDeleted(playerguid, true, "");
4287 break;
4288 }
4289 default:
4290 TC_LOG_ERROR("entities.player.cheat", "Player::DeleteFromDB: Tried to delete player ({}) with unsupported delete method ({}).",
4291 playerguid.ToString(), charDeleteMethod);
4292
4293 if (trans->GetSize() > 0)
4294 CharacterDatabase.CommitTransaction(trans);
4295 return;
4296 }
4297
4298 LoginDatabase.CommitTransaction(loginTransaction);
4299 CharacterDatabase.CommitTransaction(trans);
4300
4301 if (updateRealmChars)
4302 sWorld->UpdateRealmCharCount(accountId);
4303}
4304
4311{
4312 uint32 keepDays = sWorld->getIntConfig(CONFIG_CHARDELETE_KEEP_DAYS);
4313 if (!keepDays)
4314 return;
4315
4317}
4318
4327{
4328 TC_LOG_INFO("entities.player", "Player::DeleteOldCharacters: Deleting all characters which have been deleted {} days before...", keepDays);
4329
4331 stmt->setUInt32(0, static_cast<uint32>(GameTime::GetGameTime() - static_cast<time_t>(keepDays) * DAY));
4332 PreparedQueryResult result = CharacterDatabase.Query(stmt);
4333
4334 if (result)
4335 {
4336 TC_LOG_DEBUG("entities.player", "Player::DeleteOldCharacters: Found {} character(s) to delete", result->GetRowCount());
4337 do
4338 {
4339 Field* fields = result->Fetch();
4340 Player::DeleteFromDB(ObjectGuid::Create<HighGuid::Player>(fields[0].GetUInt64()), fields[1].GetUInt32(), true, true);
4341 }
4342 while (result->NextRow());
4343 }
4344}
4345
4346/* Preconditions:
4347 - a resurrectable corpse must not be loaded for the player (only bones)
4348 - the player must be in world
4349*/
4351{
4353 packet.PlayerGUID = GetGUID();
4354 SendDirectMessage(packet.Write());
4355
4356 // If the player has the Wisp racial then cast the Wisp aura on them
4357 if (HasSpell(20585))
4358 CastSpell(this, 20584, true);
4359 CastSpell(this, 8326, true);
4360
4362
4363 // there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_SET_WATER_WALK
4364 // there must be SMSG.STOP_MIRROR_TIMER
4365
4366 // the player cannot have a corpse already on current map, only bones which are not returned by GetCorpse
4367 WorldLocation corpseLocation = GetCorpseLocation();
4368 if (corpseLocation.GetMapId() == GetMapId())
4369 {
4370 TC_LOG_ERROR("entities.player", "Player::BuildPlayerRepop: Player '{}' ({}) already has a corpse", GetName(), GetGUID().ToString());
4371 return;
4372 }
4373
4374 // create a corpse and place it at the player's location
4375 Corpse* corpse = CreateCorpse();
4376 if (!corpse)
4377 {
4378 TC_LOG_ERROR("entities.player", "Player::BuildPlayerRepop: Error creating corpse for player '{}' ({})", GetName(), GetGUID().ToString());
4379 return;
4380 }
4381 GetMap()->AddToMap(corpse);
4382
4383 // convert player body to ghost
4385 SetHealth(1);
4386
4387 SetWaterWalking(true);
4388 if (!GetSession()->isLogingOut() && !HasUnitState(UNIT_STATE_STUNNED))
4389 SetRooted(false);
4390
4391 // BG - remove insignia related
4393
4394 int32 corpseReclaimDelay = CalculateCorpseReclaimDelay();
4395
4396 if (corpseReclaimDelay >= 0)
4397 SendCorpseReclaimDelay(corpseReclaimDelay);
4398
4399 // to prevent cheating
4400 corpse->ResetGhostTime();
4401
4402 StopMirrorTimers(); //disable timers(bars)
4403
4404 // OnPlayerRepop hook
4405 sScriptMgr->OnPlayerRepop(this);
4406}
4407
4408void Player::ResurrectPlayer(float restore_percent, bool applySickness)
4409{
4410 SetAreaSpiritHealer(nullptr);
4411
4413 packet.MapID = -1;
4414 SendDirectMessage(packet.Write());
4415
4416 // speed change, land walk
4417
4418 // remove death flag + set aura
4420
4421 // This must be called always even on Players with race != RACE_NIGHTELF in case of faction change
4422 RemoveAurasDueToSpell(20584); // RACE_NIGHTELF speed bonuses
4423 RemoveAurasDueToSpell(8326); // SPELL_AURA_GHOST
4424
4425 if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0))
4427
4429
4430 // add the flag to make sure opcode is always sent
4432 SetWaterWalking(false);
4434 SetRooted(false);
4435
4436 m_deathTimer = 0;
4437
4438 // set health/powers (0- will be set in caller)
4439 if (restore_percent > 0.0f)
4440 {
4441 SetHealth(GetMaxHealth() * restore_percent);
4442 SetPower(POWER_MANA, GetMaxPower(POWER_MANA) * restore_percent);
4443 SetPower(POWER_RAGE, 0);
4444 SetPower(POWER_ENERGY, GetMaxPower(POWER_ENERGY) * restore_percent);
4445 SetPower(POWER_FOCUS, GetMaxPower(POWER_FOCUS) * restore_percent);
4447 }
4448
4449 // trigger update zone for alive state zone updates
4450 uint32 newzone, newarea;
4451 GetZoneAndAreaId(newzone, newarea);
4452 UpdateZone(newzone, newarea);
4453 sOutdoorPvPMgr->HandlePlayerResurrects(this, newzone);
4454
4455 if (InBattleground())
4456 {
4457 if (Battleground* bg = GetBattleground())
4458 bg->HandlePlayerResurrect(this);
4459 }
4460
4461 // update visibility
4463
4464 // recast lost by death auras of any items held in the inventory
4466
4467 if (!applySickness)
4468 return;
4469
4470 //Characters from level 1-10 are not affected by resurrection sickness.
4471 //Characters from level 11-19 will suffer from one minute of sickness
4472 //for each level they are above 10.
4473 //Characters level 20 and up suffer from ten minutes of sickness.
4474 int32 startLevel = sWorld->getIntConfig(CONFIG_DEATH_SICKNESS_LEVEL);
4475 ChrRacesEntry const* raceEntry = sChrRacesStore.AssertEntry(GetRace());
4476
4477 if (int32(GetLevel()) >= startLevel)
4478 {
4479 // set resurrection sickness
4480 CastSpell(this, raceEntry->ResSicknessSpellID, true);
4481
4482 // not full duration
4483 if (int32(GetLevel()) < startLevel+9)
4484 {
4485 int32 delta = (int32(GetLevel()) - startLevel + 1)*MINUTE;
4486
4487 if (Aura* aur = GetAura(raceEntry->ResSicknessSpellID, GetGUID()))
4488 {
4489 aur->SetDuration(delta*IN_MILLISECONDS);
4490 }
4491 }
4492 }
4493}
4494
4496{
4497 if (IsFlying() && !GetTransport())
4499
4500 SetRooted(true);
4501
4502 StopMirrorTimers(); //disable timers(bars)
4503
4505 //SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_IN_PVP);
4506
4508 if (!sMapStore.LookupEntry(GetMapId())->Instanceable() && !HasAuraType(SPELL_AURA_PREVENT_RESURRECTION))
4510 else
4512
4513 // 6 minutes until repop at graveyard
4515
4516 UpdateCorpseReclaimDelay(); // dependent at use SetDeathPvP() call before kill
4517
4518 int32 corpseReclaimDelay = CalculateCorpseReclaimDelay();
4519
4520 if (corpseReclaimDelay >= 0)
4521 SendCorpseReclaimDelay(corpseReclaimDelay);
4522
4523 // don't create corpse at this moment, player might be falling
4524
4525 // update visibility
4527}
4528
4530{
4531 Corpse::DeleteFromDB(guid, trans);
4534 stmt->setUInt64(1, guid.GetCounter());
4535 CharacterDatabase.ExecuteOrAppend(trans, stmt);
4536}
4537
4539{
4540 // prevent the existence of 2 corpses for one player
4542
4544 SetPvPDeath(false);
4545
4546 if (!corpse->Create(GetMap()->GenerateLowGuid<HighGuid::Corpse>(), this))
4547 {
4548 delete corpse;
4549 return nullptr;
4550 }
4551
4553
4554 uint32 flags = 0;
4555 if (*m_unitData->PvpFlags & UNIT_BYTE2_FLAG_PVP)
4557 if (InBattleground() && !InArena())
4558 flags |= CORPSE_FLAG_SKINNABLE; // to be able to remove insignia
4559 if (*m_unitData->PvpFlags & UNIT_BYTE2_FLAG_FFA_PVP)
4561
4562 corpse->SetRace(GetRace());
4563 corpse->SetSex(GetNativeGender());
4564 corpse->SetClass(GetClass());
4565 corpse->SetCustomizations(Trinity::Containers::MakeIteratorPair(m_playerData->Customizations.begin(), m_playerData->Customizations.end()));
4566 corpse->ReplaceAllFlags(flags);
4568 corpse->SetFactionTemplate(sChrRacesStore.AssertEntry(GetRace())->FactionID);
4569
4571 {
4572 if (m_items[i])
4573 {
4574 uint32 itemDisplayId = m_items[i]->GetDisplayId(this);
4575 uint32 itemInventoryType;
4576 if (ItemEntry const* itemEntry = sItemStore.LookupEntry(m_items[i]->GetVisibleEntry(this)))
4577 itemInventoryType = itemEntry->InventoryType;
4578 else
4579 itemInventoryType = m_items[i]->GetTemplate()->GetInventoryType();
4580
4581 corpse->SetItem(i, itemDisplayId | (itemInventoryType << 24));
4582 }
4583 }
4584
4585 // register for player, but not show
4586 GetMap()->AddCorpse(corpse);
4587
4588 corpse->UpdatePositionData();
4589 corpse->SetZoneScript();
4590
4591 // we do not need to save corpses for instances
4592 if (!GetMap()->Instanceable())
4593 corpse->SaveToDB();
4594
4595 return corpse;
4596}
4597
4598void Player::SpawnCorpseBones(bool triggerSave /*= true*/)
4599{
4601 if (GetMap()->ConvertCorpseToBones(GetGUID()))
4602 if (triggerSave && !GetSession()->PlayerLogoutWithSave()) // at logout we will already store the player
4603 SaveToDB(); // prevent loading as ghost without corpse
4604}
4605
4607{
4608 return GetMap()->GetCorpseByPlayer(GetGUID());
4609}
4610
4611void Player::DurabilityLossAll(double percent, bool inventory)
4612{
4614 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
4615 DurabilityLoss(pItem, percent);
4616
4617 if (inventory)
4618 {
4619 // bags not have durability
4620 // for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
4621
4623 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; i++)
4624 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
4625 DurabilityLoss(pItem, percent);
4626
4628 if (Bag* pBag = GetBagByPos(i))
4629 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
4630 if (Item* pItem = GetItemByPos(i, j))
4631 DurabilityLoss(pItem, percent);
4632 }
4633}
4634
4635void Player::DurabilityLoss(Item* item, double percent)
4636{
4637 if (!item)
4638 return;
4639
4640 uint32 pMaxDurability = item->m_itemData->MaxDurability;
4641
4642 if (!pMaxDurability)
4643 return;
4644
4646
4647 uint32 pDurabilityLoss = uint32(pMaxDurability*percent);
4648
4649 if (pDurabilityLoss < 1)
4650 pDurabilityLoss = 1;
4651
4652 DurabilityPointsLoss(item, pDurabilityLoss);
4653}
4654
4655void Player::DurabilityPointsLossAll(int32 points, bool inventory)
4656{
4658 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
4659 DurabilityPointsLoss(pItem, points);
4660
4661 if (inventory)
4662 {
4663 // bags not have durability
4664 // for (int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)
4665
4667 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; i++)
4668 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
4669 DurabilityPointsLoss(pItem, points);
4670
4672 if (Bag* pBag = static_cast<Bag*>(GetItemByPos(INVENTORY_SLOT_BAG_0, i)))
4673 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
4674 if (Item* pItem = GetItemByPos(i, j))
4675 DurabilityPointsLoss(pItem, points);
4676 }
4677}
4678
4680{
4682 return;
4683
4684 int32 pMaxDurability = item->m_itemData->MaxDurability;
4685 int32 pOldDurability = item->m_itemData->Durability;
4686 int32 pNewDurability = pOldDurability - points;
4687
4688 if (pNewDurability < 0)
4689 pNewDurability = 0;
4690 else if (pNewDurability > pMaxDurability)
4691 pNewDurability = pMaxDurability;
4692
4693 if (pOldDurability != pNewDurability)
4694 {
4695 // modify item stats _before_ Durability set to 0 to pass _ApplyItemMods internal check
4696 if (pNewDurability == 0 && pOldDurability > 0 && item->IsEquipped())
4697 _ApplyItemMods(item, item->GetSlot(), false);
4698
4699 item->SetDurability(pNewDurability);
4700
4701 // modify item stats _after_ restore durability to pass _ApplyItemMods internal check
4702 if (pNewDurability > 0 && pOldDurability == 0 && item->IsEquipped())
4703 _ApplyItemMods(item, item->GetSlot(), true);
4704
4705 item->SetState(ITEM_CHANGED, this);
4706 }
4707}
4708
4710{
4712 return;
4713
4714 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
4715 DurabilityPointsLoss(pItem, 1);
4716}
4717
4718void Player::DurabilityRepairAll(bool takeCost, float discountMod, bool guildBank)
4719{
4720 // Collecting all items that can be repaired and repair costs
4721 std::list<std::pair<Item*, uint64>> itemRepairCostStore;
4722
4723 // equipped, backpack, bags itself
4725 for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; i++)
4726 if (Item* item = GetItemByPos(((INVENTORY_SLOT_BAG_0 << 8) | i)))
4727 if (uint64 cost = item->CalculateDurabilityRepairCost(discountMod))
4728 itemRepairCostStore.push_back(std::make_pair(item, cost));
4729
4730 // bank, buyback and keys not repaired
4731
4732 // items in inventory bags
4734 for (uint8 i = 0; i < MAX_BAG_SIZE; i++)
4735 if (Item* item = GetItemByPos(((j << 8) | i)))
4736 if (uint64 cost = item->CalculateDurabilityRepairCost(discountMod))
4737 itemRepairCostStore.push_back(std::make_pair(item, cost));
4738
4739 // Handling a free repair case - just repair every item without taking cost.
4740 if (!takeCost)
4741 {
4742 for (auto const& [item, cost] : itemRepairCostStore)
4743 DurabilityRepair(item->GetPos(), false, 0.f);
4744
4745 return;
4746 }
4747
4748 if (guildBank)
4749 {
4750 // Handling a repair for guild money case.
4751 // We have to repair items one by one until the guild bank has enough money available for withdrawal or until all items are repaired.
4752
4753 Guild* guild = GetGuild();
4754 if (!guild)
4755 return; // silent return, client shouldn't display this button for players without guild.
4756
4757 uint64 const availableGuildMoney = guild->GetMemberAvailableMoneyForRepairItems(GetGUID());
4758 if (availableGuildMoney == 0)
4759 return;
4760
4761 // Sort the items by repair cost from lowest to highest
4762 itemRepairCostStore.sort([](auto const& a, auto const& b) -> bool { return a.second < b.second; });
4763
4764 // We must calculate total repair cost and take money once to avoid spam in the guild bank log and reduce number of transactions in the database
4765 uint64 totalCost = 0;
4766
4767 for (auto const& [item, cost] : itemRepairCostStore)
4768 {
4769 uint64 newTotalCost = totalCost + cost;
4770 if (newTotalCost > availableGuildMoney || newTotalCost > MAX_MONEY_AMOUNT)
4771 break;
4772
4773 totalCost = newTotalCost;
4774
4775 // Repair item without taking cost. We'll do it later.
4776 DurabilityRepair(item->GetPos(), false, 0.f);
4777 }
4778
4779 // Take money for repairs from the guild bank
4780 guild->HandleMemberWithdrawMoney(GetSession(), totalCost, true);
4781 }
4782 else
4783 {
4784 // Handling a repair for player's money case.
4785 // Unlike repairing for guild money, in this case we must first check if player has enough money to repair all the items at once.
4786
4787 uint64 totalCost = 0;
4788 for (auto const& [item, cost] : itemRepairCostStore)
4789 totalCost += cost;
4790
4791 if (!HasEnoughMoney(totalCost))
4792 return; // silent return, client should display error by itself and not send opcode.
4793
4794 ModifyMoney(-int32(totalCost));
4795
4796 // Payment for repair has already been taken, so just repair every item without taking cost.
4797 for (auto const& [item, cost] : itemRepairCostStore)
4798 DurabilityRepair(item->GetPos(), false, 0.f);
4799 }
4800}
4801
4802void Player::DurabilityRepair(uint16 pos, bool takeCost, float discountMod)
4803{
4804 Item* item = GetItemByPos(pos);
4805 if (!item)
4806 return;
4807
4808 if (takeCost)
4809 {
4810 uint64 cost = item->CalculateDurabilityRepairCost(discountMod);
4811
4812 if (!HasEnoughMoney(cost))
4813 {
4814 TC_LOG_DEBUG("entities.player.items", "Player::DurabilityRepair: Player '{}' ({}) has not enough money to repair item",
4815 GetName(), GetGUID().ToString());
4816 return;
4817 }
4818
4819 ModifyMoney(-int32(cost));
4820 }
4821
4822 bool isBroken = item->IsBroken();
4823
4824 item->SetDurability(item->m_itemData->MaxDurability);
4825 item->SetState(ITEM_CHANGED, this);
4826
4827 // reapply mods for total broken and repaired item if equipped
4828 if (IsEquipmentPos(pos) && isBroken)
4829 _ApplyItemMods(item, pos & 255, true);
4830}
4831
4833{
4834 // note: this can be called also when the player is alive
4835 // for example from WorldSession::HandleMovementOpcodes
4836
4837 AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
4838
4839 bool shouldResurrect = false;
4840 // Such zones are considered unreachable as a ghost and the player must be automatically revived
4841 if ((!IsAlive() && zone && zone->GetFlags().HasFlag(AreaFlags::NoGhostOnRelease)) || GetMap()->IsNonRaidDungeon() || GetMap()->IsRaid() || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPhaseShift(), GetPositionX(), GetPositionY()))
4842 {
4843 shouldResurrect = true;
4845 }
4846
4847 WorldSafeLocsEntry const* closestGrave = nullptr;
4848 if (Battleground* bg = GetBattleground())
4849 closestGrave = bg->GetClosestGraveyard(this);
4850 else if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(GetMap(), GetZoneId()))
4851 closestGrave = bf->GetClosestGraveyard(this);
4852 else if (InstanceScript* instance = GetInstanceScript())
4853 closestGrave = sObjectMgr->GetWorldSafeLoc(instance->GetEntranceLocation());
4854
4855 if (!closestGrave)
4856 closestGrave = sObjectMgr->GetClosestGraveyard(*this, GetTeam(), this);
4857
4858 // stop countdown until repop
4859 m_deathTimer = 0;
4860
4861 // if no grave found, stay at the current location
4862 // and don't show spirit healer location
4863 if (closestGrave)
4864 {
4865 TeleportTo(closestGrave->Loc, shouldResurrect ? TELE_REVIVE_AT_TELEPORT : TELE_TO_NONE);
4866 if (isDead()) // not send if alive, because it used in TeleportTo()
4867 {
4869 packet.MapID = closestGrave->Loc.GetMapId();
4870 packet.Loc = closestGrave->Loc;
4871 SendDirectMessage(packet.Write());
4872 }
4873 }
4874 else if (GetPositionZ() < GetMap()->GetMinHeight(GetPhaseShift(), GetPositionX(), GetPositionY()))
4876
4878}
4879
4881{
4882 if (channel->GetFlags().HasFlag(ChatChannelFlags::ZoneBased) && zone->GetFlags().HasFlag(AreaFlags::NoChatChannels))
4883 return false;
4884
4885 if (channel->GetFlags().HasFlag(ChatChannelFlags::OnlyInCities) && !zone->GetFlags().HasFlag(AreaFlags::AllowTradeChannel))
4886 return false;
4887
4888 if (channel->GetFlags().HasFlag(ChatChannelFlags::GuildRecruitment) && GetGuildId())
4889 return false;
4890
4891 if (channel->GetRuleset() == ChatChannelRuleset::Disabled)
4892 return false;
4893
4894 if (channel->GetFlags().HasFlag(ChatChannelFlags::Regional))
4895 return false;
4896
4897 return true;
4898}
4899
4901{
4902 m_channels.push_back(c);
4903}
4904
4906{
4907 m_channels.remove(c);
4908}
4909
4911{
4912 while (!m_channels.empty())
4913 {
4914 Channel* ch = *m_channels.begin();
4915 m_channels.erase(m_channels.begin()); // remove from player's channel list
4916 ch->LeaveChannel(this, false); // not send to client, not remove from player's channel list
4917
4918 // delete channel if empty
4919 if (ChannelMgr* cMgr = ChannelMgr::ForTeam(GetTeam()))
4920 if (ch->IsConstant())
4921 cMgr->LeftChannel(ch->GetChannelId(), ch->GetZoneEntry());
4922 }
4923 TC_LOG_DEBUG("chat.system", "Player::CleanupChannels: Channels of player '{}' ({}) cleaned up.", GetName(), GetGUID().ToString());
4924}
4925
4927{
4928 if (GetSession()->PlayerLoading() && !IsBeingTeleportedFar())
4929 return; // The client handles it automatically after loading, but not after teleporting
4930
4931 AreaTableEntry const* current_zone = sAreaTableStore.LookupEntry(newZone);
4932 if (!current_zone)
4933 return;
4934
4936 if (!cMgr)
4937 return;
4938
4939 for (ChatChannelsEntry const* channelEntry : sChatChannelsStore)
4940 {
4941 if (!channelEntry->GetFlags().HasFlag(ChatChannelFlags::AutoJoin))
4942 continue;
4943
4944 Channel* usedChannel = nullptr;
4945 for (Channel* channel : m_channels)
4946 {
4947 if (channel->GetChannelId() == channelEntry->ID)
4948 {
4949 usedChannel = channel;
4950 break;
4951 }
4952 }
4953
4954 Channel* removeChannel = nullptr;
4955 Channel* joinChannel = nullptr;
4956 bool sendRemove = true;
4957
4958 if (CanJoinConstantChannelInZone(channelEntry, current_zone))
4959 {
4960 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::ZoneBased))
4961 {
4962 if (channelEntry->GetFlags().HasFlag(ChatChannelFlags::LinkedChannel) && usedChannel)
4963 continue; // Already on the channel, as city channel names are not changing
4964
4965 joinChannel = cMgr->GetSystemChannel(channelEntry->ID, current_zone);
4966 if (usedChannel)
4967 {
4968 if (joinChannel != usedChannel)
4969 {
4970 removeChannel = usedChannel;
4971 sendRemove = false; // Do not send leave channel, it already replaced at client
4972 }
4973 else
4974 joinChannel = nullptr;
4975 }
4976 }
4977 else
4978 joinChannel = cMgr->GetSystemChannel(channelEntry->ID);
4979 }
4980 else
4981 removeChannel = usedChannel;
4982
4983 if (joinChannel)
4984 joinChannel->JoinChannel(this); // Changed Channel: ... or Joined Channel: ...
4985
4986 if (removeChannel)
4987 {
4988 removeChannel->LeaveChannel(this, sendRemove, true); // Leave old channel
4989
4990 LeftChannel(removeChannel); // Remove from player's channel list
4991 cMgr->LeftChannel(removeChannel->GetChannelId(), removeChannel->GetZoneEntry()); // Delete if empty
4992 }
4993 }
4994}
4995
4997{
4998 for (JoinedChannelsList::iterator i = m_channels.begin(); i != m_channels.end(); ++i)
4999 {
5000 if ((*i)->IsLFG())
5001 {
5002 (*i)->LeaveChannel(this);
5003 break;
5004 }
5005 }
5006}
5007
5008void Player::HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply)
5009{
5010 if (modGroup >= BASEMOD_END)
5011 {
5012 TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
5013 modGroup, FLAT_MOD, GetName(), GetGUID().ToString());
5014 return;
5015 }
5016
5017 m_auraBaseFlatMod[modGroup] += apply ? amount : -amount;
5018 UpdateBaseModGroup(modGroup);
5019}
5020
5022{
5023 if (modGroup >= BASEMOD_END)
5024 {
5025 TC_LOG_ERROR("spells", "Player::HandleBaseModValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
5026 modGroup, FLAT_MOD, GetName(), GetGUID().ToString());
5027 return;
5028 }
5029
5030 AddPct(m_auraBasePctMod[modGroup], pct);
5031 UpdateBaseModGroup(modGroup);
5032}
5033
5035{
5036 if (m_auraBaseFlatMod[modGroup] == val)
5037 return;
5038
5039 m_auraBaseFlatMod[modGroup] = val;
5040 UpdateBaseModGroup(modGroup);
5041}
5042
5044{
5045 if (m_auraBasePctMod[modGroup] == val)
5046 return;
5047
5048 m_auraBasePctMod[modGroup] = val;
5049 UpdateBaseModGroup(modGroup);
5050}
5051
5052void Player::UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot /*= -1*/)
5053{
5054 Unit::UpdateDamageDoneMods(attackType, skipEnchantSlot);
5055
5056 UnitMods unitMod;
5057 switch (attackType)
5058 {
5059 case BASE_ATTACK:
5060 unitMod = UNIT_MOD_DAMAGE_MAINHAND;
5061 break;
5062 case OFF_ATTACK:
5063 unitMod = UNIT_MOD_DAMAGE_OFFHAND;
5064 break;
5065 case RANGED_ATTACK:
5066 unitMod = UNIT_MOD_DAMAGE_RANGED;
5067 break;
5068 default:
5069 ABORT();
5070 break;
5071 }
5072
5073 float amount = 0.0f;
5074 Item* item = GetWeaponForAttack(attackType, true);
5075 if (!item)
5076 return;
5077
5078 for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot)
5079 {
5080 if (skipEnchantSlot == slot)
5081 continue;
5082
5083 SpellItemEnchantmentEntry const* enchantmentEntry = sSpellItemEnchantmentStore.LookupEntry(item->GetEnchantmentId(EnchantmentSlot(slot)));
5084 if (!enchantmentEntry)
5085 continue;
5086
5087 for (uint8 i = 0; i < MAX_ITEM_ENCHANTMENT_EFFECTS; ++i)
5088 {
5089 switch (enchantmentEntry->Effect[i])
5090 {
5092 amount += enchantmentEntry->EffectScalingPoints[i];
5093 break;
5095 if (GetClass() == CLASS_SHAMAN)
5096 amount += enchantmentEntry->EffectScalingPoints[i] * item->GetTemplate()->GetDelay() / 1000.0f;
5097 break;
5098 default:
5099 break;
5100 }
5101 }
5102 }
5103
5104 HandleStatFlatModifier(unitMod, TOTAL_VALUE, amount, true);
5105}
5106
5108{
5109 if (!CanModifyStats())
5110 return;
5111
5112 switch (modGroup)
5113 {
5117 default: break;
5118 }
5119}
5120
5122{
5123 if (modGroup >= BASEMOD_END || modType >= MOD_END)
5124 {
5125 TC_LOG_ERROR("spells", "Player::GetBaseModValue: Invalid BaseModGroup/BaseModType ({}/{}) for player '{}' ({})",
5126 modGroup, modType, GetName(), GetGUID().ToString());
5127 return 0.0f;
5128 }
5129
5130 return (modType == FLAT_MOD ? m_auraBaseFlatMod[modGroup] : m_auraBasePctMod[modGroup]);
5131}
5132
5134{
5135 if (modGroup >= BASEMOD_END)
5136 {
5137 TC_LOG_ERROR("spells", "Player::GetTotalBaseModValue: Invalid BaseModGroup ({}) for player '{}' ({})",
5138 modGroup, GetName(), GetGUID().ToString());
5139 return 0.0f;
5140 }
5141
5142 return m_auraBaseFlatMod[modGroup] * m_auraBasePctMod[modGroup];
5143}
5144
5145void Player::GetDodgeFromAgility(float &/*diminishing*/, float &/*nondiminishing*/) const
5146{
5148 //const float dodge_base[MAX_CLASSES] =
5149 //{
5150 // 0.037580f, // Warrior
5151 // 0.036520f, // Paladin
5152 // -0.054500f, // Hunter
5153 // -0.005900f, // Rogue
5154 // 0.031830f, // Priest
5155 // 0.036640f, // DK
5156 // 0.016750f, // Shaman
5157 // 0.034575f, // Mage
5158 // 0.020350f, // Warlock
5159 // 0.0f, // ??
5160 // 0.049510f // Druid
5161 //};
5163 //const float crit_to_dodge[MAX_CLASSES] =
5164 //{
5165 // 0.85f/1.15f, // Warrior
5166 // 1.00f/1.15f, // Paladin
5167 // 1.11f/1.15f, // Hunter
5168 // 2.00f/1.15f, // Rogue
5169 // 1.00f/1.15f, // Priest
5170 // 0.85f/1.15f, // DK
5171 // 1.60f/1.15f, // Shaman
5172 // 1.00f/1.15f, // Mage
5173 // 0.97f/1.15f, // Warlock (?)
5174 // 0.0f, // ??
5175 // 2.00f/1.15f // Druid
5176 //};
5177
5178 //uint8 level = getLevel();
5179 //uint32 pclass = getClass();
5180
5181 //if (level >= sGtChanceToMeleeCritStore.GetTableRowCount())
5182 // level = sGtChanceToMeleeCritStore.GetTableRowCount() - 1;
5183
5185 //GtChanceToMeleeCritEntry const* dodgeRatio = sGtChanceToMeleeCritStore.EvaluateTable(level - 1, pclass - 1);
5186 //if (dodgeRatio == nullptr || pclass > MAX_CLASSES)
5187 // return;
5188
5190 //float base_agility = GetCreateStat(STAT_AGILITY) * GetPctModifierValue(UnitMods(UNIT_MOD_STAT_START + STAT_AGILITY), BASE_PCT);
5191 //float bonus_agility = GetStat(STAT_AGILITY) - base_agility;
5192
5194 //diminishing = 100.0f * bonus_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1];
5195 //nondiminishing = 100.0f * (dodge_base[pclass-1] + base_agility * dodgeRatio->ratio * crit_to_dodge[pclass-1]);
5196}
5197
5199{
5200 switch (rating)
5201 {
5202 case CR_AMPLIFY:
5203 return row->Amplify;
5204 case CR_DEFENSE_SKILL:
5205 return row->DefenseSkill;
5206 case CR_DODGE:
5207 return row->Dodge;
5208 case CR_PARRY:
5209 return row->Parry;
5210 case CR_BLOCK:
5211 return row->Block;
5212 case CR_HIT_MELEE:
5213 return row->HitMelee;
5214 case CR_HIT_RANGED:
5215 return row->HitRanged;
5216 case CR_HIT_SPELL:
5217 return row->HitSpell;
5218 case CR_CRIT_MELEE:
5219 return row->CritMelee;
5220 case CR_CRIT_RANGED:
5221 return row->CritRanged;
5222 case CR_CRIT_SPELL:
5223 return row->CritSpell;
5224 case CR_CORRUPTION:
5225 return row->Corruption;
5227 return row->CorruptionResistance;
5228 case CR_SPEED:
5229 return row->Speed;
5231 return row->ResilienceCritTaken;
5233 return row->ResiliencePlayerDamage;
5234 case CR_LIFESTEAL:
5235 return row->Lifesteal;
5236 case CR_HASTE_MELEE:
5237 return row->HasteMelee;
5238 case CR_HASTE_RANGED:
5239 return row->HasteRanged;
5240 case CR_HASTE_SPELL:
5241 return row->HasteSpell;
5242 case CR_AVOIDANCE:
5243 return row->Avoidance;
5244 case CR_STURDINESS:
5245 return row->Sturdiness;
5246 case CR_UNUSED_7:
5247 return row->Unused7;
5248 case CR_EXPERTISE:
5249 return row->Expertise;
5251 return row->ArmorPenetration;
5252 case CR_MASTERY:
5253 return row->Mastery;
5254 case CR_PVP_POWER:
5255 return row->PvPPower;
5256 case CR_CLEAVE:
5257 return row->Cleave;
5259 return row->VersatilityDamageDone;
5261 return row->VersatilityHealingDone;
5263 return row->VersatilityDamageTaken;
5264 case CR_UNUSED_12:
5265 return row->Unused12;
5266 default:
5267 break;
5268 }
5269
5270 return 1.0f;
5271}
5272
5274{
5275 GtCombatRatingsEntry const* Rating = sCombatRatingsGameTable.GetRow(GetLevel());
5276 if (!Rating)
5277 return 1.0f;
5278
5279 float value = GetGameTableColumnForCombatRating(Rating, cr);
5280 if (!value)
5281 return 1.0f; // By default use minimum coefficient (not must be called)
5282
5283 return 1.0f / value;
5284}
5285
5287{
5288 float baseResult = ApplyRatingDiminishing(cr, float(m_activePlayerData->CombatRatings[cr]) * GetRatingMultiplier(cr));
5290 return baseResult;
5291 return float(1.0f - pow(0.99f, baseResult)) * 100.0f;
5292}
5293
5294float Player::ApplyRatingDiminishing(CombatRating cr, float bonusValue) const
5295{
5296 uint32 diminishingCurveId = 0;
5297 switch (cr)
5298 {
5299 case CR_DODGE:
5300 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::DodgeDiminishing);
5301 break;
5302 case CR_PARRY:
5303 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::ParryDiminishing);
5304 break;
5305 case CR_BLOCK:
5306 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::BlockDiminishing);
5307 break;
5308 case CR_CRIT_MELEE:
5309 case CR_CRIT_RANGED:
5310 case CR_CRIT_SPELL:
5311 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::CritDiminishing);
5312 break;
5313 case CR_SPEED:
5314 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::SpeedDiminishing);
5315 break;
5316 case CR_LIFESTEAL:
5317 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::LifestealDiminishing);
5318 break;
5319 case CR_HASTE_MELEE:
5320 case CR_HASTE_RANGED:
5321 case CR_HASTE_SPELL:
5322 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::HasteDiminishing);
5323 break;
5324 case CR_AVOIDANCE:
5325 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::AvoidanceDiminishing);
5326 break;
5327 case CR_MASTERY:
5328 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::MasteryDiminishing);
5329 break;
5332 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::VersatilityDoneDiminishing);
5333 break;
5335 diminishingCurveId = sDB2Manager.GetGlobalCurveId(GlobalCurve::VersatilityTakenDiminishing);
5336 break;
5337 default:
5338 break;
5339 }
5340
5341 if (diminishingCurveId)
5342 return sDB2Manager.GetCurveValueAt(diminishingCurveId, bonusValue);
5343
5344 return bonusValue;
5345}
5346
5348{
5349 float baseExpertise = 7.5f;
5350 switch (attType)
5351 {
5352 case BASE_ATTACK:
5353 return baseExpertise + m_activePlayerData->MainhandExpertise / 4.0f;
5354 case OFF_ATTACK:
5355 return baseExpertise + m_activePlayerData->OffhandExpertise / 4.0f;
5356 default:
5357 break;
5358 }
5359 return 0.0f;
5360}
5361
5362void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
5363{
5364 m_baseRatingValue[combatRating] += (apply ? value : -value);
5365 UpdateRating(combatRating);
5366}
5367
5369{
5370 int32 amount = m_baseRatingValue[cr];
5372 {
5373 if (aurEff->GetMiscValueB() & (1 << cr))
5374 {
5375 Optional<int16> highestRating;
5376 for (uint8 dependentRating = 0; dependentRating < MAX_COMBAT_RATING; ++dependentRating)
5377 if (aurEff->GetMiscValue() & (1 << dependentRating))
5378 highestRating = std::max(highestRating.value_or(m_baseRatingValue[dependentRating]), m_baseRatingValue[dependentRating]);
5379
5380 if (highestRating)
5381 amount += int32(CalculatePct(*highestRating, aurEff->GetAmount()));
5382 }
5383 }
5384
5386 if (aurEff->GetMiscValue() & (1 << cr))
5387 amount += int32(CalculatePct(amount, aurEff->GetAmount()));
5388
5389 if (amount < 0)
5390 amount = 0;
5391
5392 uint32 oldRating = m_activePlayerData->CombatRatings[cr];
5394
5395 bool affectStats = CanModifyStats();
5396
5397 switch (cr)
5398 {
5399 case CR_AMPLIFY:
5400 case CR_DEFENSE_SKILL:
5401 break;
5402 case CR_DODGE:
5404 break;
5405 case CR_PARRY:
5407 break;
5408 case CR_BLOCK:
5410 break;
5411 case CR_HIT_MELEE:
5413 break;
5414 case CR_HIT_RANGED:
5416 break;
5417 case CR_HIT_SPELL:
5419 break;
5420 case CR_CRIT_MELEE:
5421 if (affectStats)
5422 {
5425 }
5426 break;
5427 case CR_CRIT_RANGED:
5428 if (affectStats)
5430 break;
5431 case CR_CRIT_SPELL:
5432 if (affectStats)
5434 break;
5435 case CR_CORRUPTION:
5438 break;
5439 case CR_SPEED:
5442 case CR_LIFESTEAL:
5443 break;
5444 case CR_HASTE_MELEE:
5445 case CR_HASTE_RANGED:
5446 case CR_HASTE_SPELL:
5447 {
5448 // explicit affected values
5449 float const multiplier = GetRatingMultiplier(cr);
5450 float const oldVal = ApplyRatingDiminishing(cr, oldRating * multiplier);
5451 float const newVal = ApplyRatingDiminishing(cr, amount * multiplier);
5452 switch (cr)
5453 {
5454 case CR_HASTE_MELEE:
5455 ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false);
5456 ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false);
5461 break;
5462 case CR_HASTE_RANGED:
5465 break;
5466 case CR_HASTE_SPELL:
5467 ApplyCastTimePercentMod(oldVal, false);
5468 ApplyCastTimePercentMod(newVal, true);
5469 break;
5470 default:
5471 break;
5472 }
5473 break;
5474 }
5475 case CR_AVOIDANCE:
5476 case CR_STURDINESS:
5477 case CR_UNUSED_7:
5478 break;
5479 case CR_EXPERTISE:
5480 if (affectStats)
5481 {
5484 }
5485 break;
5487 if (affectStats)
5488 UpdateArmorPenetration(amount);
5489 break;
5490 case CR_MASTERY:
5491 UpdateMastery();
5492 break;
5493 case CR_PVP_POWER:
5494 case CR_CLEAVE:
5495 break;
5498 break;
5501 break;
5503 case CR_UNUSED_12:
5504 break;
5505 }
5506}
5507
5509{
5510 for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
5512}
5513
5515{
5516 for (uint8 i = 0; i < MAX_ATTACK; ++i)
5517 {
5518 Item* tmpitem = GetWeaponForAttack(WeaponAttackType(i), true);
5519 if (tmpitem && !tmpitem->IsBroken())
5520 {
5521 ItemTemplate const* proto = tmpitem->GetTemplate();
5522 if (proto->GetDelay())
5524 }
5525 else
5526 SetBaseAttackTime(WeaponAttackType(i), BASE_ATTACK_TIME); // If there is no weapon reset attack time to base (might have been changed from forms)
5527 }
5528}
5529
5530inline int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLevel, uint32 YellowLevel)
5531{
5532 if (SkillValue >= GrayLevel)
5533 return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_GREY)*10;
5534 if (SkillValue >= GreenLevel)
5535 return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_GREEN)*10;
5536 if (SkillValue >= YellowLevel)
5537 return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_YELLOW)*10;
5538 return sWorld->getIntConfig(CONFIG_SKILL_CHANCE_ORANGE)*10;
5539}
5540
5542{
5544 return false;
5545
5546 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateCraftSkill: Player '{}' ({}), SpellID: {}",
5547 GetName(), GetGUID().ToString(), spellInfo->Id);
5548
5549 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellInfo->Id);
5550
5551 for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
5552 {
5553 if (_spell_idx->second->SkillupSkillLineID)
5554 {
5555 uint32 SkillValue = GetPureSkillValue(_spell_idx->second->SkillupSkillLineID);
5556
5557 // Alchemy Discoveries here
5558 if (spellInfo->Mechanic == MECHANIC_DISCOVERY)
5559 {
5560 if (uint32 discoveredSpell = GetSkillDiscoverySpell(_spell_idx->second->SkillupSkillLineID, spellInfo->Id, this))
5561 LearnSpell(discoveredSpell, false);
5562 }
5563
5564 uint32 craft_skill_gain = _spell_idx->second->NumSkillUps * sWorld->getIntConfig(CONFIG_SKILL_GAIN_CRAFTING);
5565
5566 return UpdateSkillPro(_spell_idx->second->SkillupSkillLineID, SkillGainChance(SkillValue,
5567 _spell_idx->second->TrivialSkillLineRankHigh,
5568 (_spell_idx->second->TrivialSkillLineRankHigh + _spell_idx->second->TrivialSkillLineRankLow)/2,
5569 _spell_idx->second->TrivialSkillLineRankLow),
5570 craft_skill_gain);
5571 }
5572 }
5573 return false;
5574}
5575
5576bool Player::UpdateGatherSkill(uint32 skillId, uint32 skillValue, uint32 redLevel, uint32 multiplicator /*= 1*/, WorldObject const* object /*= nullptr*/)
5577{
5578 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateGatherSkill: Player '{}' ({}), SkillID: {}, SkillLevel: {}, RedLevel: {})",
5579 GetName(), GetGUID().ToString(), skillId, skillValue, redLevel);
5580
5581 SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(skillId);
5582 if (!skillEntry)
5583 return false;
5584
5585 uint32 gatheringSkillGain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING);
5586
5587 uint32 baseSkillLevelStep = 30;
5588 uint32 yellowLevel = redLevel + baseSkillLevelStep;
5589 uint32 greenLevel = yellowLevel + baseSkillLevelStep;
5590 uint32 grayLevel = greenLevel + baseSkillLevelStep;
5591
5592 if (GameObject const* go = Object::ToGameObject(object))
5593 {
5594 if (go->GetGOInfo()->GetTrivialSkillLow())
5595 yellowLevel = go->GetGOInfo()->GetTrivialSkillLow();
5596
5597 if (go->GetGOInfo()->GetTrivialSkillHigh())
5598 grayLevel = go->GetGOInfo()->GetTrivialSkillHigh();
5599
5600 greenLevel = (yellowLevel + grayLevel) / 2;
5601 }
5602
5603 // For skinning and Mining chance decrease with level. 1-74 - no decrease, 75-149 - 2 times, 225-299 - 8 times
5604 switch (skillEntry->ParentSkillLineID)
5605 {
5606 case SKILL_HERBALISM:
5607 return UpdateSkillPro(skillId, SkillGainChance(skillValue, grayLevel, greenLevel, yellowLevel) * multiplicator, gatheringSkillGain);
5608 case SKILL_SKINNING:
5609 if (sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS) == 0)
5610 return UpdateSkillPro(skillId, SkillGainChance(skillValue, grayLevel, greenLevel, yellowLevel) * multiplicator, gatheringSkillGain);
5611 else
5612 return UpdateSkillPro(skillId, (SkillGainChance(skillValue, grayLevel, greenLevel, yellowLevel) * multiplicator) >> (skillValue / sWorld->getIntConfig(CONFIG_SKILL_CHANCE_SKINNING_STEPS)), gatheringSkillGain);
5613 case SKILL_MINING:
5614 if (sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS) == 0)
5615 return UpdateSkillPro(skillId, SkillGainChance(skillValue, grayLevel, greenLevel, yellowLevel) * multiplicator, gatheringSkillGain);
5616 else
5617 return UpdateSkillPro(skillId, (SkillGainChance(skillValue, grayLevel, greenLevel, yellowLevel) * multiplicator) >> (skillValue / sWorld->getIntConfig(CONFIG_SKILL_CHANCE_MINING_STEPS)), gatheringSkillGain);
5618 }
5619 return false;
5620}
5621
5623{
5624 // These formulas are guessed to be as close as possible to how the skill difficulty curve for fishing was on Retail.
5625 if (SkillValue < 75)
5626 return 1;
5627
5628 if (SkillValue <= 300)
5629 return SkillValue / 44;
5630
5631 return SkillValue / 31;
5632}
5633
5635{
5636 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateFishingSkill: Player '{}' ({}) Expansion: {}", GetName(), GetGUID().ToString(), expansion);
5637
5638 uint32 fishingSkill = GetProfessionSkillForExp(SKILL_FISHING, expansion);
5639 if (!fishingSkill || !HasSkill(fishingSkill))
5640 return false;
5641
5642 uint32 skillValue = GetPureSkillValue(fishingSkill);
5643
5644 if (skillValue >= GetMaxSkillValue(fishingSkill))
5645 return false;
5646
5647 uint8 stepsNeededToLevelUp = GetFishingStepsNeededToLevelUp(skillValue);
5649
5650 if (m_fishingSteps >= stepsNeededToLevelUp)
5651 {
5652 m_fishingSteps = 0;
5653
5654 uint32 gatheringSkillGain = sWorld->getIntConfig(CONFIG_SKILL_GAIN_GATHERING);
5655 return UpdateSkillPro(fishingSkill, 100*10, gatheringSkillGain);
5656 }
5657
5658 return false;
5659}
5660
5661bool Player::UpdateSkillPro(uint16 skillId, int32 chance, uint32 step)
5662{
5663 // levels sync. with spell requirement for skill levels to learn
5664 // bonus abilities in sSkillLineAbilityStore
5665 // Used only to avoid scan DBC at each skill grow
5666 uint32 const bonusSkillLevels[] = { 75, 150, 225, 300, 375, 450, 525, 600, 700, 850 };
5667
5668 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '{}' ({}), SkillID: {}, Chance: {:3.1f}%)",
5669 GetName(), GetGUID().ToString(), skillId, chance / 10.0f);
5670 if (!skillId)
5671 return false;
5672
5673 if (chance <= 0) // speedup in 0 chance case
5674 {
5675 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '{}' ({}), SkillID: {}, Chance: {:3.1f}% missed",
5676 GetName(), GetGUID().ToString(), skillId, chance / 10.0f);
5677 return false;
5678 }
5679
5680 SkillStatusMap::iterator itr = mSkillStatus.find(skillId);
5681 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED)
5682 return false;
5683
5684 uint16 value = m_activePlayerData->Skill->SkillRank[itr->second.pos];
5685 uint16 max = m_activePlayerData->Skill->SkillMaxRank[itr->second.pos];
5686
5687 if (!max || !value || value >= max)
5688 return false;
5689
5690 if (irand(1, 1000) > chance)
5691 {
5692 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '{}' ({}), SkillID: {}, Chance: {:3.1f}% missed",
5693 GetName(), GetGUID().ToString(), skillId, chance / 10.0f);
5694 return false;
5695 }
5696
5697 uint16 new_value = value + step;
5698 if (new_value > max)
5699 new_value = max;
5700
5701 SetSkillRank(itr->second.pos, new_value);
5702 if (itr->second.uState != SKILL_NEW)
5703 itr->second.uState = SKILL_CHANGED;
5704
5705 for (uint32 bsl : bonusSkillLevels)
5706 {
5707 if (value < bsl && new_value >= bsl)
5708 {
5709 LearnSkillRewardedSpells(skillId, new_value, Races(GetRace()));
5710 break;
5711 }
5712 }
5713
5714 UpdateSkillEnchantments(skillId, value, new_value);
5716 TC_LOG_DEBUG("entities.player.skills", "Player::UpdateSkillPro: Player '{}' ({}), SkillID: {}, Chance: {:3.1f}% taken",
5717 GetName(), GetGUID().ToString(), skillId, chance / 10.0f);
5718 return true;
5719}
5720
5721void Player::ModifySkillBonus(uint32 skillid, int32 val, bool talent)
5722{
5723 SkillStatusMap::const_iterator itr = mSkillStatus.find(skillid);
5724 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
5725 return;
5726
5727 if (talent)
5728 SetSkillPermBonus(itr->second.pos, m_activePlayerData->Skill->SkillPermBonus[itr->second.pos] + val);
5729 else
5730 SetSkillTempBonus(itr->second.pos, m_activePlayerData->Skill->SkillTempBonus[itr->second.pos] + val);
5731
5732 // Apply/Remove bonus to child skill lines
5733 if (std::vector<SkillLineEntry const*> const* childSkillLines = sDB2Manager.GetSkillLinesForParentSkill(skillid))
5734 for (SkillLineEntry const* childSkillLine : *childSkillLines)
5735 ModifySkillBonus(childSkillLine->ID, val, talent);
5736}
5737
5739{
5740 Races race = Races(GetRace());
5741 uint32 maxSkill = GetMaxSkillValueForLevel();
5742
5743 for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end(); ++itr)
5744 {
5745 if (itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
5746 continue;
5747
5748 uint32 pskill = itr->first;
5749 SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(pskill, GetRace(), GetClass());
5750 if (!rcEntry)
5751 continue;
5752
5753 if (GetSkillRangeType(rcEntry) == SKILL_RANGE_LEVEL)
5754 {
5755 if (rcEntry->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
5756 SetSkillRank(itr->second.pos, maxSkill);
5757
5758 SetSkillMaxRank(itr->second.pos, maxSkill);
5759 if (itr->second.uState != SKILL_NEW)
5760 itr->second.uState = SKILL_CHANGED;
5761 }
5762
5763 // Update level dependent skillline spells
5764 LearnSkillRewardedSpells(rcEntry->SkillID, m_activePlayerData->Skill->SkillRank[itr->second.pos], race);
5765 }
5766}
5767
5769{
5770 uint32 i = 0;
5771 for (SkillLineEntry const* skillLine : sSkillLineStore)
5772 {
5773 if (sDB2Manager.GetSkillRaceClassInfo(skillLine->ID, GetRace(), GetClass()))
5774 {
5775 SetSkillLineId(i, skillLine->ID);
5777 mSkillStatus.insert(SkillStatusMap::value_type(skillLine->ID, SkillStatusData(i, SKILL_UNCHANGED)));
5778 if (++i >= PLAYER_MAX_SKILLS)
5779 break;
5780 }
5781 }
5782}
5783
5784// This functions sets a skill line value (and adds if doesn't exist yet)
5785// To "remove" a skill line, set it's values to zero
5786void Player::SetSkill(uint32 id, uint16 step, uint16 newVal, uint16 maxVal)
5787{
5788 SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(id);
5789 if (!skillEntry)
5790 {
5791 TC_LOG_ERROR("misc", "Player::SetSkill: Skill (SkillID: {}) not found in SkillLineStore for player '{}' ({})",
5792 id, GetName(), GetGUID().ToString());
5793 return;
5794 }
5795
5796 uint16 currVal;
5797 SkillStatusMap::iterator itr = mSkillStatus.find(id);
5798
5799 auto refreshSkillBonusAuras = [&]
5800 {
5801 // Temporary bonuses
5803 if (effect->GetMiscValue() == int32(id))
5804 effect->HandleEffect(this, AURA_EFFECT_HANDLE_SKILL, true);
5805
5807 if (effect->GetMiscValue() == int32(id))
5808 effect->HandleEffect(this, AURA_EFFECT_HANDLE_SKILL, true);
5809
5810 // Permanent bonuses
5812 if (effect->GetMiscValue() == int32(id))
5813 effect->HandleEffect(this, AURA_EFFECT_HANDLE_SKILL, true);
5814 };
5815
5816 // Handle already stored skills
5817 if (itr != mSkillStatus.end())
5818 {
5819 currVal = m_activePlayerData->Skill->SkillRank[itr->second.pos];
5820
5821 // Activate and update skill line
5822 if (newVal)
5823 {
5824 // enable parent skill line if missing
5825 if (skillEntry->ParentSkillLineID && skillEntry->ParentTierIndex > 0 && GetSkillStep(skillEntry->ParentSkillLineID) < skillEntry->ParentTierIndex)
5826 if (SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(skillEntry->ParentSkillLineID, GetRace(), GetClass()))
5827 if (SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcEntry->SkillTierID))
5828 SetSkill(skillEntry->ParentSkillLineID, skillEntry->ParentTierIndex, std::max<uint16>(GetPureSkillValue(skillEntry->ParentSkillLineID), 1), tier->GetValueForTierIndex(skillEntry->ParentTierIndex - 1));
5829
5830 // if skill value is going down, update enchantments before setting the new value
5831 if (newVal < currVal)
5832 UpdateSkillEnchantments(id, currVal, newVal);
5833
5834 // update step
5835 SetSkillStep(itr->second.pos, step);
5836 // update value
5837 SetSkillRank(itr->second.pos, newVal);
5838 SetSkillMaxRank(itr->second.pos, maxVal);
5839
5840 LearnSkillRewardedSpells(id, newVal, Races(GetRace()));
5841 // if skill value is going up, update enchantments after setting the new value
5842 if (newVal > currVal)
5843 {
5844 UpdateSkillEnchantments(id, currVal, newVal);
5845 if (id == SKILL_RIDING)
5847 }
5848
5851
5852 // update skill state
5853 if (itr->second.uState == SKILL_UNCHANGED || itr->second.uState == SKILL_DELETED)
5854 {
5855 if (currVal == 0) // activated skill, mark as new to save into database
5856 {
5857 itr->second.uState = itr->second.uState != SKILL_DELETED
5858 ? SKILL_NEW
5859 : SKILL_CHANGED; // skills marked as SKILL_DELETED already exist in database, mark as changed instead of new
5860
5861 // Set profession line
5862 int32 freeProfessionSlot = FindEmptyProfessionSlotFor(id);
5863 if (freeProfessionSlot != -1)
5865
5866 refreshSkillBonusAuras();
5867 }
5868 else // updated skill, mark as changed to save into database
5869 itr->second.uState = SKILL_CHANGED;
5870 }
5871 }
5872 else if (currVal && !newVal) // Deactivate skill line
5873 {
5874 // Try to store profession tools and accessories into the bag
5875 // If we can't, we can't unlearn the profession
5876 int32 professionSlot = GetProfessionSlotFor(id);
5877 if (professionSlot != -1)
5878 {
5879 uint8 professionSlotStart = PROFESSION_SLOT_PROFESSION1_TOOL + professionSlot * PROFESSION_SLOT_MAX_COUNT;
5880
5881 // Get all profession items equipped
5882 for (uint8 slotOffset = 0; slotOffset < PROFESSION_SLOT_MAX_COUNT; ++slotOffset)
5883 {
5884 if (Item* professionItem = GetItemByPos(INVENTORY_SLOT_BAG_0, professionSlotStart + slotOffset))
5885 {
5886 // Store item in bag
5887 ItemPosCountVec professionItemDest;
5888
5889 if (CanStoreItem(NULL_BAG, NULL_SLOT, professionItemDest, professionItem, false) != EQUIP_ERR_OK)
5890 {
5892 return;
5893 }
5894
5895 RemoveItem(INVENTORY_SLOT_BAG_0, professionItem->GetSlot(), true);
5896 StoreItem(professionItemDest, professionItem, true);
5897 }
5898 }
5899
5900 // Clear profession lines
5902 }
5903
5904 //remove enchantments needing this skill
5905 UpdateSkillEnchantments(id, currVal, 0);
5906 // clear skill fields
5907 SetSkillStep(itr->second.pos, 0);
5908 SetSkillRank(itr->second.pos, 0);
5909 SetSkillStartingRank(itr->second.pos, 1);
5910 SetSkillMaxRank(itr->second.pos, 0);
5911 SetSkillTempBonus(itr->second.pos, 0);
5912 SetSkillPermBonus(itr->second.pos, 0);
5913
5914 // mark as deleted so the next save will delete the data from the database
5915 itr->second.uState = itr->second.uState != SKILL_NEW
5917 : SKILL_UNCHANGED; // skills marked as SKILL_NEW don't exist in database (this distinction is not neccessary for deletion but for re-learning the same skill before save to db happens)
5918
5919 // remove all spells that related to this skill
5920 if (std::vector<SkillLineAbilityEntry const*> const* skillLineAbilities = sDB2Manager.GetSkillLineAbilitiesBySkill(id))
5921 for (SkillLineAbilityEntry const* skillLineAbility : *skillLineAbilities)
5922 RemoveSpell(sSpellMgr->GetFirstSpellInChain(skillLineAbility->Spell));
5923
5924 if (std::vector<SkillLineEntry const*> const* childSkillLines = sDB2Manager.GetSkillLinesForParentSkill(id))
5925 for (SkillLineEntry const* childSkillLine : *childSkillLines)
5926 SetSkill(childSkillLine->ID, 0, 0, 0);
5927 }
5928 }
5929 else
5930 {
5931 // We are about to learn a skill that has been added outside of normal circumstances (Game Master command, scripts etc.)
5932 uint8 skillSlot = 0;
5933
5934 // Find a free skill slot
5935 for (uint32 i = 0; i < PLAYER_MAX_SKILLS; ++i)
5936 {
5937 if (!m_activePlayerData->Skill->SkillLineID[i])
5938 {
5939 skillSlot = i;
5940 break;
5941 }
5942 }
5943
5944 if (!skillSlot)
5945 {
5946 TC_LOG_ERROR("misc", "Tried to add skill {} but player {} ({}) cannot have additional skills", id, GetName(), GetGUID().ToString());
5947 return;
5948 }
5949
5950 if (skillEntry->ParentSkillLineID)
5951 {
5952 if (skillEntry->ParentTierIndex > 0)
5953 {
5954 if (SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(skillEntry->ParentSkillLineID, GetRace(), GetClass()))
5955 {
5956 if (SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcEntry->SkillTierID))
5957 {
5958 uint16 skillval = GetPureSkillValue(skillEntry->ParentSkillLineID);
5959 SetSkill(skillEntry->ParentSkillLineID, skillEntry->ParentTierIndex, std::max<uint16>(skillval, 1), tier->GetValueForTierIndex(skillEntry->ParentTierIndex - 1));
5960 }
5961 }
5962 }
5963 }
5964 else
5965 {
5966 // also learn missing child skills at 0 value
5967 if (std::vector<SkillLineEntry const*> const* childSkillLines = sDB2Manager.GetSkillLinesForParentSkill(id))
5968 for (SkillLineEntry const* childSkillLine : *childSkillLines)
5969 if (!HasSkill(childSkillLine->ID))
5970 SetSkill(childSkillLine->ID, 0, 0, 0);
5971
5972 int32 freeProfessionSlot = FindEmptyProfessionSlotFor(id);
5973 if (freeProfessionSlot != -1)
5975 }
5976
5977 if (itr == mSkillStatus.end())
5978 SetSkillLineId(skillSlot, id);
5979
5980 SetSkillStep(skillSlot, step);
5981 SetSkillRank(skillSlot, newVal);
5982 SetSkillStartingRank(skillSlot, 1);
5983 SetSkillMaxRank(skillSlot, maxVal);
5984
5985 // apply skill bonuses
5986 SetSkillTempBonus(skillSlot, 0);
5987 SetSkillPermBonus(skillSlot, 0);
5988
5989 UpdateSkillEnchantments(id, 0, newVal);
5990
5991 mSkillStatus.insert(SkillStatusMap::value_type(id, SkillStatusData(skillSlot, SKILL_NEW)));
5992
5993 if (newVal)
5994 {
5995 refreshSkillBonusAuras();
5996
5997 // Learn all spells for skill
5998 LearnSkillRewardedSpells(id, newVal, Races(GetRace()));
6001 }
6002 }
6003}
6004
6006{
6007 SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(skill);
6008 if (!skillEntry)
6009 return 0;
6010
6011 if (skillEntry->ParentSkillLineID || (skillEntry->CategoryID != SKILL_CATEGORY_PROFESSION && skillEntry->CategoryID != SKILL_CATEGORY_SECONDARY))
6012 return 0;
6013
6014 // The value -3 from ContentTuning refers to the current expansion
6015 if (expansion < 0)
6016 expansion = CURRENT_EXPANSION;
6017
6018 if (std::vector<SkillLineEntry const*> const* childSkillLines = sDB2Manager.GetSkillLinesForParentSkill(skillEntry->ID))
6019 for (SkillLineEntry const* childSkillLine : *childSkillLines)
6020 {
6021 // Values of ParentTierIndex in SkillLine.db2 start at 4 (Classic) and increase by one for each expansion skillLine
6022 // Subtract 4 (BASE_PARENT_TIER_INDEX) from this value to obtain the expansion of the skillLine
6023 int32 skillLineExpansion = childSkillLine->ParentTierIndex - BASE_PARENT_TIER_INDEX;
6024 if (expansion == skillLineExpansion)
6025 return childSkillLine->ID;
6026 }
6027
6028 return 0;
6029}
6030
6031bool Player::HasSkill(uint32 skill) const
6032{
6033 if (!skill)
6034 return false;
6035
6036 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6037 return (itr != mSkillStatus.end() && itr->second.uState != SKILL_DELETED && m_activePlayerData->Skill->SkillRank[itr->second.pos]);
6038}
6039
6041{
6042 if (!skill)
6043 return 0;
6044
6045 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6046 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6047 return 0;
6048
6049 return m_activePlayerData->Skill->SkillStep[itr->second.pos];
6050}
6051
6053{
6054 if (!skill)
6055 return 0;
6056
6057 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6058 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6059 return 0;
6060
6061 int32 result = int32(m_activePlayerData->Skill->SkillRank[itr->second.pos]);
6062 result += int32(m_activePlayerData->Skill->SkillTempBonus[itr->second.pos]);
6063 result += int32(m_activePlayerData->Skill->SkillPermBonus[itr->second.pos]);
6064 return result < 0 ? 0 : result;
6065}
6066
6068{
6069 if (!skill)
6070 return 0;
6071
6072 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6073 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6074 return 0;
6075
6076 int32 result = int32(m_activePlayerData->Skill->SkillMaxRank[itr->second.pos]);
6077 result += int32(m_activePlayerData->Skill->SkillTempBonus[itr->second.pos]);
6078 result += int32(m_activePlayerData->Skill->SkillPermBonus[itr->second.pos]);
6079 return result < 0 ? 0 : result;
6080}
6081
6083{
6084 if (!skill)
6085 return 0;
6086
6087 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6088 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6089 return 0;
6090
6091 return m_activePlayerData->Skill->SkillMaxRank[itr->second.pos];
6092}
6093
6095{
6096 if (!skill)
6097 return 0;
6098
6099 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6100 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6101 return 0;
6102
6103 int32 result = int32(m_activePlayerData->Skill->SkillRank[itr->second.pos]);
6104 result += int32(m_activePlayerData->Skill->SkillPermBonus[itr->second.pos]);
6105 return result < 0 ? 0 : result;
6106}
6107
6109{
6110 if (!skill)
6111 return 0;
6112
6113 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6114 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6115 return 0;
6116
6117 return m_activePlayerData->Skill->SkillRank[itr->second.pos];
6118}
6119
6121{
6122 if (!skill)
6123 return 0;
6124
6125 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6126 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6127 return 0;
6128
6129 return m_activePlayerData->Skill->SkillPermBonus[itr->second.pos];
6130}
6131
6133{
6134 if (!skill)
6135 return 0;
6136
6137 SkillStatusMap::const_iterator itr = mSkillStatus.find(skill);
6138 if (itr == mSkillStatus.end() || itr->second.uState == SKILL_DELETED || !m_activePlayerData->Skill->SkillRank[itr->second.pos])
6139 return 0;
6140
6141 return m_activePlayerData->Skill->SkillTempBonus[itr->second.pos];
6142}
6143
6145{
6147
6148 for (auto itr = m_actionButtons.begin(); itr != m_actionButtons.end(); ++itr)
6149 if (itr->second.uState != ACTIONBUTTON_DELETED && itr->first < packet.ActionButtons.size())
6150 packet.ActionButtons[itr->first] = itr->second.packedData;
6151
6152 packet.Reason = state;
6153
6154 SendDirectMessage(packet.Write());
6155}
6156
6157bool Player::IsActionButtonDataValid(uint8 button, uint64 action, uint8 type) const
6158{
6159 if (button >= MAX_ACTION_BUTTONS)
6160 {
6161 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Action {} not added into button {} for player {} ({}): button must be < {}",
6162 action, button, GetName(), GetGUID().ToString(), MAX_ACTION_BUTTONS);
6163 return false;
6164 }
6165
6166 if (action >= MAX_ACTION_BUTTON_ACTION_VALUE)
6167 {
6168 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Action {} not added into button {} for player {} ({}): action must be < " UI64FMTD,
6169 action, button, GetName(), GetGUID().ToString(), MAX_ACTION_BUTTON_ACTION_VALUE);
6170 return false;
6171 }
6172
6173 switch (type)
6174 {
6176 if (!sSpellMgr->GetSpellInfo(action, DIFFICULTY_NONE))
6177 {
6178 TC_LOG_DEBUG("entities.player", "Player::IsActionButtonDataValid: Spell action {} not added into button {} for player {} ({}): spell does not exist. This can be due to a character imported from a different expansion",
6179 action, button, GetName(), GetGUID().ToString());
6180 return false;
6181 }
6182 break;
6183 case ACTION_BUTTON_ITEM:
6184 if (!sObjectMgr->GetItemTemplate(action))
6185 {
6186 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Item action {} not added into button {} for player {} ({}): item not exist",
6187 action, button, GetName(), GetGUID().ToString());
6188 return false;
6189 }
6190 break;
6192 {
6193 if (!GetSession()->GetBattlePetMgr()->GetPet(ObjectGuid::Create<HighGuid::BattlePet>(action)))
6194 {
6195 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Companion action {} not added into button {} for player {} ({}): companion does not exist",
6196 action, button, GetName(), GetGUID().ToString());
6197 return false;
6198 }
6199 break;
6200 }
6202 {
6203 MountEntry const* mount = sDB2Manager.GetMountById(action);
6204 if (!mount)
6205 {
6206 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Mount action {} not added into button {} for player {} ({}): mount does not exist",
6207 action, button, GetName(), GetGUID().ToString());
6208 return false;
6209 }
6210
6211 if (!HasSpell(mount->SourceSpellID))
6212 {
6213 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Mount action {} not added into button {} for player {} ({}): Player does not know this mount",
6214 action, button, GetName(), GetGUID().ToString());
6215 return false;
6216 }
6217 break;
6218 }
6219 case ACTION_BUTTON_C:
6224 break;
6225 default:
6226 TC_LOG_ERROR("entities.player", "Player::IsActionButtonDataValid: Unknown action type {}", type);
6227 return false; // other cases not checked at this moment
6228 }
6229
6230 return true;
6231}
6232
6234{
6235 if (!IsActionButtonDataValid(button, action, type))
6236 return nullptr;
6237
6238 // it create new button (NEW state) if need or return existing
6239 ActionButton& ab = m_actionButtons[button];
6240
6241 // set data and update to CHANGED if not NEW
6242 ab.SetActionAndType(action, ActionButtonType(type));
6243
6244 TC_LOG_DEBUG("entities.player", "Player::AddActionButton: Player '{}' ({}) added action '{}' (type {}) to button '{}'",
6245 GetName(), GetGUID().ToString(), action, type, button);
6246 return &ab;
6247}
6248
6250{
6251 ActionButtonList::iterator buttonItr = m_actionButtons.find(button);
6252 if (buttonItr == m_actionButtons.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED)
6253 return;
6254
6255 if (buttonItr->second.uState == ACTIONBUTTON_NEW)
6256 m_actionButtons.erase(buttonItr); // new and not saved
6257 else
6258 buttonItr->second.uState = ACTIONBUTTON_DELETED; // saved, will deleted at next save
6259
6260 TC_LOG_DEBUG("entities.player", "Player::RemoveActionButton: Player '{}' ({}) removed action button '{}'",
6261 GetName(), GetGUID().ToString(), button);
6262}
6263
6265{
6266 ActionButtonList::iterator buttonItr = m_actionButtons.find(button);
6267 if (buttonItr == m_actionButtons.end() || buttonItr->second.uState == ACTIONBUTTON_DELETED)
6268 return nullptr;
6269
6270 return &buttonItr->second;
6271}
6272
6273bool Player::UpdatePosition(float x, float y, float z, float orientation, bool teleport)
6274{
6275 if (!Unit::UpdatePosition(x, y, z, orientation, teleport))
6276 return false;
6277
6278 //if (movementInfo.flags & MOVEMENTFLAG_MOVING)
6279 // mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Moving);
6280 //if (movementInfo.flags & MOVEMENTFLAG_TURNING)
6281 // mover->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Turning);
6282
6283 // group update
6284 if (GetGroup())
6286
6288
6289 return true;
6290}
6291
6292void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self) const
6293{
6294 if (self)
6295 SendDirectMessage(data);
6296
6297 Trinity::PacketSenderRef sender(data);
6299 Cell::VisitWorldObjects(this, notifier, dist);
6300}
6301
6302void Player::SendMessageToSetInRange(WorldPacket const* data, float dist, bool self, bool own_team_only, bool required3dDist /*= false*/) const
6303{
6304 if (self)
6305 SendDirectMessage(data);
6306
6307 Trinity::PacketSenderRef sender(data);
6308 Trinity::MessageDistDeliverer<Trinity::PacketSenderRef> notifier(this, sender, dist, own_team_only, nullptr, required3dDist);
6309 Cell::VisitWorldObjects(this, notifier, dist);
6310}
6311
6312void Player::SendMessageToSet(WorldPacket const* data, Player const* skipped_rcvr) const
6313{
6314 if (skipped_rcvr != this)
6315 SendDirectMessage(data);
6316
6317 // we use World::GetMaxVisibleDistance() because i cannot see why not use a distance
6318 // update: replaced by GetMap()->GetVisibilityDistance()
6319 Trinity::PacketSenderRef sender(data);
6320 Trinity::MessageDistDeliverer<Trinity::PacketSenderRef> notifier(this, sender, GetVisibilityRange(), false, skipped_rcvr);
6322}
6323
6325{
6326 m_session->SendPacket(data);
6327}
6328
6329void Player::SendCinematicStart(uint32 CinematicSequenceId) const
6330{
6332 packet.CinematicID = CinematicSequenceId;
6333 SendDirectMessage(packet.Write());
6334 if (CinematicSequencesEntry const* sequence = sCinematicSequencesStore.LookupEntry(CinematicSequenceId))
6335 _cinematicMgr->BeginCinematic(sequence);
6336}
6337
6339{
6340 SetMovie(movieId);
6342 packet.MovieID = movieId;
6343 SendDirectMessage(packet.Write());
6344}
6345
6347{
6348 if (!IsAlive())
6349 return;
6350
6351 if (IsInFlight())
6352 return;
6353
6354 if (sWorld->getBoolConfig(CONFIG_VMAP_INDOOR_CHECK))
6356
6357 uint32 const areaId = GetAreaId();
6358 if (!areaId)
6359 return;
6360
6361 AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
6362 if (!areaEntry)
6363 {
6364 TC_LOG_ERROR("entities.player", "Player '{}' ({}) discovered unknown area (x: {} y: {} z: {} map: {})",
6366 return;
6367 }
6368
6369 uint32 offset = areaEntry->AreaBit / PLAYER_EXPLORED_ZONES_BITS;
6370 uint64 val = UI64LIT(1) << (areaEntry->AreaBit % PLAYER_EXPLORED_ZONES_BITS);
6371
6372 if (offset >= m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size()
6373 || !(m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][offset] & val))
6374 {
6375 AddExploredZones(offset, val);
6376
6378
6379 if (Optional<ContentTuningLevels> areaLevels = sDB2Manager.GetContentTuningData(areaEntry->ContentTuningID, m_playerData->CtrOptions->ContentTuningConditionMask))
6380 {
6381 if (IsMaxLevel())
6382 {
6383 SendExplorationExperience(areaId, 0);
6384 }
6385 else
6386 {
6387 int16 areaLevel = std::min(std::max(int16(GetLevel()), areaLevels->MinLevel), areaLevels->MaxLevel);
6388 int32 diff = int32(GetLevel()) - areaLevel;
6389 uint32 XP;
6390 if (diff < -5)
6391 {
6392 XP = uint32(sObjectMgr->GetBaseXP(GetLevel() + 5) * sWorld->getRate(RATE_XP_EXPLORE));
6393 }
6394 else if (diff > 5)
6395 {
6396 int32 exploration_percent = 100 - ((diff - 5) * 5);
6397 if (exploration_percent < 0)
6398 exploration_percent = 0;
6399
6400 XP = uint32(sObjectMgr->GetBaseXP(areaLevel) * exploration_percent / 100 * sWorld->getRate(RATE_XP_EXPLORE));
6401 }
6402 else
6403 {
6404 XP = uint32(sObjectMgr->GetBaseXP(areaLevel) * sWorld->getRate(RATE_XP_EXPLORE));
6405 }
6406
6408 {
6409 uint32 minScaledXP = uint32(sObjectMgr->GetBaseXP(areaLevel)*sWorld->getRate(RATE_XP_EXPLORE)) * sWorld->getIntConfig(CONFIG_MIN_DISCOVERED_SCALED_XP_RATIO) / 100;
6410 XP = std::max(minScaledXP, XP);
6411 }
6412
6413 GiveXP(XP, nullptr);
6414 SendExplorationExperience(areaId, XP);
6415 }
6416 TC_LOG_DEBUG("entities.player", "Player '{}' ({}) discovered a new area: {}", GetName(),GetGUID().ToString(), areaId);
6417 }
6418 }
6419}
6420
6422{
6424 .ModifyValue(&Player::m_activePlayerData)
6426 .ModifyValue(pos), mask);
6427}
6428
6430{
6432 .ModifyValue(&Player::m_activePlayerData)
6434 .ModifyValue(pos), mask);
6435}
6436
6438{
6439 AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId);
6440 if (!area)
6441 return false;
6442
6443 if (area->AreaBit < 0)
6444 return false;
6445
6446 size_t playerIndexOffset = size_t(area->AreaBit) / PLAYER_EXPLORED_ZONES_BITS;
6447 if (playerIndexOffset >= m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size())
6448 return false;
6449
6450 uint64 mask = uint64(1) << (area->AreaBit % PLAYER_EXPLORED_ZONES_BITS);
6451 return (m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][playerIndexOffset] & mask) != 0;
6452}
6453
6455{
6456 if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race))
6457 {
6458 switch (rEntry->Alliance)
6459 {
6460 case 0: return ALLIANCE;
6461 case 1: return HORDE;
6462 }
6463 TC_LOG_ERROR("entities.player", "Race ({}) has wrong teamid ({}) in DBC: wrong DBC files?", uint32(race), rEntry->Alliance);
6464 }
6465 else
6466 TC_LOG_ERROR("entities.player", "Race ({}) not found in DBC: wrong DBC files?", uint32(race));
6467
6468 return ALLIANCE;
6469}
6470
6472{
6473 if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race))
6474 return TeamId(rEntry->Alliance);
6475
6476 TC_LOG_ERROR("entities.player", "Race ({}) not found in DBC: wrong DBC files?", race);
6477 return TEAM_NEUTRAL;
6478}
6479
6481{
6482 if (ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race))
6483 if (FactionTemplateEntry const* faction = sFactionTemplateStore.LookupEntry(rEntry->FactionID))
6484 return faction->FactionGroup;
6485
6486 return 1;
6487}
6488
6490{
6491 m_team = TeamForRace(race);
6492
6493 ChrRacesEntry const* rEntry = sChrRacesStore.LookupEntry(race);
6494 SetFaction(rEntry ? rEntry->FactionID : 0);
6495}
6496
6498{
6499 FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction);
6500 return GetReputationMgr().GetRank(factionEntry);
6501}
6502
6503// Calculate total reputation percent player gain with quest/creature level
6504int32 Player::CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool noQuestBonus)
6505{
6506 bool noBonuses = false;
6507 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction))
6508 if (FriendshipReputationEntry const* friendshipReputation = sFriendshipReputationStore.LookupEntry(factionEntry->FriendshipRepID))
6509 if (friendshipReputation->GetFlags().HasFlag(FriendshipReputationFlags::NoRepGainModifiers))
6510 noBonuses = true;
6511
6512 float percent = 100.0f;
6513
6514 if (!noBonuses)
6515 {
6516 float repMod = noQuestBonus ? 0.0f : float(GetTotalAuraModifier(SPELL_AURA_MOD_REPUTATION_GAIN));
6517
6518 // faction specific auras only seem to apply to kills
6519 if (source == REPUTATION_SOURCE_KILL)
6521
6522 percent += rep > 0 ? repMod : -repMod;
6523 }
6524
6525 float rate;
6526 switch (source)
6527 {
6529 rate = sWorld->getRate(RATE_REPUTATION_LOWLEVEL_KILL);
6530 break;
6536 rate = sWorld->getRate(RATE_REPUTATION_LOWLEVEL_QUEST);
6537 break;
6539 default:
6540 rate = 1.0f;
6541 break;
6542 }
6543
6544 if (rate != 1.0f && creatureOrQuestLevel < Trinity::XP::GetGrayLevel(GetLevel()))
6545 percent *= rate;
6546
6547 if (percent <= 0.0f)
6548 return 0;
6549
6550 // Multiply result with the faction specific rate
6551 if (RepRewardRate const* repData = sObjectMgr->GetRepRewardRate(faction))
6552 {
6553 float repRate = 0.0f;
6554 switch (source)
6555 {
6557 repRate = repData->creatureRate;
6558 break;
6560 repRate = repData->questRate;
6561 break;
6563 repRate = repData->questDailyRate;
6564 break;
6566 repRate = repData->questWeeklyRate;
6567 break;
6569 repRate = repData->questMonthlyRate;
6570 break;
6572 repRate = repData->questRepeatableRate;
6573 break;
6575 repRate = repData->spellRate;
6576 break;
6577 }
6578
6579 // for custom, a rate of 0.0 will totally disable reputation gain for this faction/type
6580 if (repRate <= 0.0f)
6581 return 0;
6582
6583 percent *= repRate;
6584 }
6585
6586 if (source != REPUTATION_SOURCE_SPELL && GetsRecruitAFriendBonus(false))
6587 percent *= 1.0f + sWorld->getRate(RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS);
6588
6589 return CalculatePct(rep, percent);
6590}
6591
6592// Calculates how many reputation points player gains in victim's enemy factions
6593void Player::RewardReputation(Unit* victim, float rate)
6594{
6595 if (!victim || victim->GetTypeId() == TYPEID_PLAYER)
6596 return;
6597
6598 if (victim->ToCreature()->IsReputationGainDisabled())
6599 return;
6600
6601 ReputationOnKillEntry const* Rep = sObjectMgr->GetReputationOnKilEntry(victim->ToCreature()->GetCreatureTemplate()->Entry);
6602 if (!Rep)
6603 return;
6604
6605 uint32 ChampioningFaction = 0;
6606
6608 {
6609 // support for: Championing - http://www.wowwiki.com/Championing
6610 Map const* map = GetMap();
6611 if (map->IsNonRaidDungeon())
6612 if (LFGDungeonsEntry const* dungeon = DB2Manager::GetLfgDungeon(map->GetId(), map->GetDifficultyID()))
6613 if (Optional<ContentTuningLevels> dungeonLevels = sDB2Manager.GetContentTuningData(dungeon->ContentTuningID, m_playerData->CtrOptions->ContentTuningConditionMask))
6614 if (dungeonLevels->TargetLevelMax == int16(GetMaxLevelForExpansion(EXPANSION_WRATH_OF_THE_LICH_KING)))
6615 ChampioningFaction = GetChampioningFaction();
6616 }
6617
6618 uint32 team = GetTeam();
6619
6620 if (Rep->RepFaction1 && (!Rep->TeamDependent || team == ALLIANCE))
6621 {
6622 int32 donerep1 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->GetLevelForTarget(this), Rep->RepValue1, ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
6623 donerep1 = int32(donerep1 * rate);
6624
6625 FactionEntry const* factionEntry1 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction1);
6626 uint32 current_reputation_rank1 = GetReputationMgr().GetRank(factionEntry1);
6627 if (factionEntry1)
6628 GetReputationMgr().ModifyReputation(factionEntry1, donerep1, current_reputation_rank1 > Rep->ReputationMaxCap1);
6629 }
6630
6631 if (Rep->RepFaction2 && (!Rep->TeamDependent || team == HORDE))
6632 {
6633 int32 donerep2 = CalculateReputationGain(REPUTATION_SOURCE_KILL, victim->GetLevelForTarget(this), Rep->RepValue2, ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
6634 donerep2 = int32(donerep2 * rate);
6635
6636 FactionEntry const* factionEntry2 = sFactionStore.LookupEntry(ChampioningFaction ? ChampioningFaction : Rep->RepFaction2);
6637 uint32 current_reputation_rank2 = GetReputationMgr().GetRank(factionEntry2);
6638 if (factionEntry2)
6639 GetReputationMgr().ModifyReputation(factionEntry2, donerep2, current_reputation_rank2 > Rep->ReputationMaxCap2);
6640 }
6641}
6642
6643// Calculate how many reputation points player gain with the quest
6645{
6646 for (uint8 i = 0; i < QUEST_REWARD_REPUTATIONS_COUNT; ++i)
6647 {
6648 if (!quest->RewardFactionId[i])
6649 continue;
6650
6651 FactionEntry const* factionEntry = sFactionStore.LookupEntry(quest->RewardFactionId[i]);
6652 if (!factionEntry)
6653 continue;
6654
6655 int32 rep = 0;
6656 bool noQuestBonus = false;
6657
6658 if (quest->RewardFactionOverride[i])
6659 {
6660 rep = quest->RewardFactionOverride[i] / 100;
6661 noQuestBonus = true;
6662 }
6663 else
6664 {
6665 uint32 row = ((quest->RewardFactionValue[i] < 0) ? 1 : 0) + 1;
6666 if (QuestFactionRewardEntry const* questFactionRewEntry = sQuestFactionRewardStore.LookupEntry(row))
6667 {
6668 uint32 field = abs(quest->RewardFactionValue[i]);
6669 rep = questFactionRewEntry->Difficulty[field];
6670 }
6671 }
6672
6673 if (!rep)
6674 continue;
6675
6676 if (quest->RewardFactionCapIn[i] && rep > 0 && GetReputationMgr().GetRank(factionEntry) >= quest->RewardFactionCapIn[i])
6677 continue;
6678
6679 if (quest->IsDaily())
6680 rep = CalculateReputationGain(REPUTATION_SOURCE_DAILY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus);
6681 else if (quest->IsWeekly())
6682 rep = CalculateReputationGain(REPUTATION_SOURCE_WEEKLY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus);
6683 else if (quest->IsMonthly())
6684 rep = CalculateReputationGain(REPUTATION_SOURCE_MONTHLY_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus);
6685 else if (quest->IsRepeatable())
6687 else
6688 rep = CalculateReputationGain(REPUTATION_SOURCE_QUEST, GetQuestLevel(quest), rep, quest->RewardFactionId[i], noQuestBonus);
6689
6690 bool noSpillover = (quest->GetRewardReputationMask() & (1 << i)) != 0;
6691 GetReputationMgr().ModifyReputation(factionEntry, rep, false, noSpillover);
6692 }
6693}
6694
6696{
6698 time_t now = GameTime::GetGameTime();
6699 time_t today = GameTime::GetGameTime() / DAY * DAY;
6700
6701 if (m_lastHonorUpdateTime < today)
6702 {
6703 time_t yesterday = today - DAY;
6704
6705 // update yesterday's contribution
6706 if (m_lastHonorUpdateTime >= yesterday)
6707 {
6708 // this is the first update today, reset today's contribution
6710 }
6711 else
6712 {
6713 // no honor/kills yesterday or today, reset
6715 }
6716
6718 }
6719
6721}
6722
6726bool Player::RewardHonor(Unit* victim, uint32 groupsize, int32 honor, bool pvptoken)
6727{
6728 // do not reward honor in arenas, but enable onkill spellproc
6729 if (InArena())
6730 {
6731 if (!victim || victim == this || victim->GetTypeId() != TYPEID_PLAYER)
6732 return false;
6733
6734 if (GetBGTeam() == victim->ToPlayer()->GetBGTeam())
6735 return false;
6736
6737 return true;
6738 }
6739
6740 // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
6742 return false;
6743
6744 ObjectGuid victim_guid;
6745 uint32 victim_rank = 0;
6746
6747 // need call before fields update to have chance move yesterday data to appropriate fields before today data change.
6749
6750 // do not reward honor in arenas, but return true to enable onkill spellproc
6751 if (InBattleground() && GetBattleground() && GetBattleground()->isArena())
6752 return true;
6753
6754 // Promote to float for calculations
6755 float honor_f = (float)honor;
6756
6757 if (honor_f <= 0)
6758 {
6759 if (!victim || victim == this || victim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT))
6760 return false;
6761
6762 victim_guid = victim->GetGUID();
6763
6764 if (Player* plrVictim = victim->ToPlayer())
6765 {
6766 if (GetEffectiveTeam() == plrVictim->GetEffectiveTeam() && !sWorld->IsFFAPvPRealm())
6767 return false;
6768
6769 uint8 k_level = GetLevel();
6770 uint8 k_grey = Trinity::XP::GetGrayLevel(k_level);
6771 uint8 v_level = victim->GetLevelForTarget(this);
6772
6773 if (v_level <= k_grey)
6774 return false;
6775
6776 // PLAYER_CHOSEN_TITLE VALUES DESCRIPTION
6777 // [0] Just name
6778 // [1..14] Alliance honor titles and player name
6779 // [15..28] Horde honor titles and player name
6780 // [29..38] Other title and player name
6781 // [39+] Nothing
6782 // this is all wrong, should be going off PvpTitle, not PlayerTitle
6783 uint32 victim_title = plrVictim->m_playerData->PlayerTitle;
6784 // Get Killer titles, CharTitlesEntry::MaskID
6785 // Ranks:
6786 // title[1..14] -> rank[5..18]
6787 // title[15..28] -> rank[5..18]
6788 // title[other] -> 0
6789 if (victim_title == 0)
6790 victim_guid.Clear(); // Don't show HK: <rank> message, only log.
6791 else if (victim_title < 15)
6792 victim_rank = victim_title + 4;
6793 else if (victim_title < 29)
6794 victim_rank = victim_title - 14 + 4;
6795 else
6796 victim_guid.Clear(); // Don't show HK: <rank> message, only log.
6797
6798 honor_f = std::ceil(Trinity::Honor::hk_honor_at_level_f(k_level) * (v_level - k_grey) / (k_level - k_grey));
6799
6800 // count the number of playerkills in one day
6802 // and those in a lifetime
6809 UpdateCriteria(CriteriaType::KillPlayer, 1, 0, 0, victim);
6810 }
6811 else
6812 {
6813 if (!victim->ToCreature()->IsRacialLeader())
6814 return false;
6815
6816 honor_f = 100.0f; // ??? need more info
6817 victim_rank = 19; // HK: Leader
6818 }
6819 }
6820
6821 if (victim != nullptr)
6822 {
6823 if (groupsize > 1)
6824 honor_f /= groupsize;
6825
6826 // apply honor multiplier from aura (not stacking-get highest)
6828 honor_f += _restMgr->GetRestBonusFor(REST_TYPE_HONOR, honor_f);
6829 }
6830
6831 honor_f *= sWorld->getRate(RATE_HONOR);
6832 // Back to int now
6833 honor = int32(honor_f);
6834 // honor - for show honor points in log
6835 // victim_guid - for show victim name in log
6836 // victim_rank [1..4] HK: <dishonored rank>
6837 // victim_rank [5..19] HK: <alliance\horde rank>
6838 // victim_rank [0, 20+] HK: <>
6840 data.Honor = honor;
6841 data.OriginalHonor = honor;
6842 data.Target = victim_guid;
6843 data.Rank = victim_rank;
6844
6845 SendDirectMessage(data.Write());
6846
6847 AddHonorXP(honor);
6848
6849 if (InBattleground() && honor > 0)
6850 {
6851 if (Battleground* bg = GetBattleground())
6852 {
6853 bg->UpdatePlayerScore(this, SCORE_BONUS_HONOR, honor, false); //false: prevent looping
6854 }
6855 }
6856
6857 if (sWorld->getBoolConfig(CONFIG_PVP_TOKEN_ENABLE) && pvptoken)
6858 {
6859 if (!victim || victim == this || victim->HasAuraType(SPELL_AURA_NO_PVP_CREDIT))
6860 return true;
6861
6862 if (victim->GetTypeId() == TYPEID_PLAYER)
6863 {
6864 // Check if allowed to receive it in current map
6866 if ((MapType == 1 && !InBattleground() && !IsFFAPvP())
6867 || (MapType == 2 && !IsFFAPvP())
6868 || (MapType == 3 && !InBattleground()))
6869 return true;
6870
6871 uint32 itemId = sWorld->getIntConfig(CONFIG_PVP_TOKEN_ID);
6872 int32 count = sWorld->getIntConfig(CONFIG_PVP_TOKEN_COUNT);
6873
6874 if (AddItem(itemId, count))
6875 ChatHandler(GetSession()).PSendSysMessage("You have been awarded a token for slaying another player.");
6876 }
6877 }
6878
6879 return true;
6880}
6881
6883{
6887}
6888
6890{
6893
6894 AddHonorXP(honor);
6895}
6896
6898{
6899 RewardPlayerWithRewardPack(sRewardPackStore.LookupEntry(rewardPackID));
6900}
6901
6903{
6904 if (!rewardPackEntry)
6905 return;
6906
6907 if (CharTitlesEntry const* charTitlesEntry = sCharTitlesStore.LookupEntry(rewardPackEntry->CharTitleID))
6908 SetTitle(charTitlesEntry);
6909
6910 ModifyMoney(rewardPackEntry->Money);
6911
6912 if (std::vector<RewardPackXCurrencyTypeEntry const*> const* rewardCurrencyTypes = sDB2Manager.GetRewardPackCurrencyTypesByRewardID(rewardPackEntry->ID))
6913 for (RewardPackXCurrencyTypeEntry const* currency : *rewardCurrencyTypes)
6914 AddCurrency(currency->CurrencyTypeID, currency->Quantity /* TODO: CurrencyGainSource */);
6915
6916 if (std::vector<RewardPackXItemEntry const*> const* rewardPackXItems = sDB2Manager.GetRewardPackItemsByRewardID(rewardPackEntry->ID))
6917 for (RewardPackXItemEntry const* rewardPackXItem : *rewardPackXItems)
6918 AddItem(rewardPackXItem->ItemID, rewardPackXItem->ItemQuantity);
6919}
6920
6922{
6923 uint32 currentHonorXP = m_activePlayerData->Honor;
6924 uint32 nextHonorLevelXP = m_activePlayerData->HonorNextLevel;
6925 uint32 newHonorXP = currentHonorXP + xp;
6926 uint32 honorLevel = GetHonorLevel();
6927
6928 if (xp < 1 || GetLevel() < PLAYER_LEVEL_MIN_HONOR || IsMaxHonorLevel())
6929 return;
6930
6931 while (newHonorXP >= nextHonorLevelXP)
6932 {
6933 newHonorXP -= nextHonorLevelXP;
6934
6935 if (honorLevel < PLAYER_MAX_HONOR_LEVEL)
6936 SetHonorLevel(honorLevel + 1);
6937
6938 honorLevel = GetHonorLevel();
6939 nextHonorLevelXP = m_activePlayerData->HonorNextLevel;
6940 }
6941
6943}
6944
6946{
6947 uint8 oldHonorLevel = GetHonorLevel();
6948 if (level == oldHonorLevel)
6949 return;
6950
6953
6955}
6956
6958{
6959 // 5500 at honor level 1
6960 // no idea what between here
6961 // 8800 at honor level ~14 (never goes above 8800)
6963}
6964
6966{
6967 if (!result)
6968 return;
6969
6970 do
6971 {
6972 Field* fields = result->Fetch();
6973
6974 uint16 currencyID = fields[0].GetUInt16();
6975
6976 CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(currencyID);
6977 if (!currency)
6978 continue;
6979
6980 PlayerCurrency cur;
6982 cur.Quantity = fields[1].GetUInt32();
6983 cur.WeeklyQuantity = fields[2].GetUInt32();
6984 cur.TrackedQuantity = fields[3].GetUInt32();
6985 cur.IncreasedCapQuantity = fields[4].GetUInt32();
6986 cur.EarnedQuantity = fields[5].GetUInt32();
6987 cur.Flags = CurrencyDbFlags(fields[6].GetUInt8());
6988
6989 _currencyStorage.insert(PlayerCurrenciesMap::value_type(currencyID, cur));
6990
6991 } while (result->NextRow());
6992}
6993
6995{
6997 for (PlayerCurrenciesMap::iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr)
6998 {
6999 CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(itr->first);
7000 if (!entry) // should never happen
7001 continue;
7002
7003 switch (itr->second.state)
7004 {
7005 case PLAYERCURRENCY_NEW:
7006 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_PLAYER_CURRENCY);
7007 stmt->setUInt64(0, GetGUID().GetCounter());
7008 stmt->setUInt16(1, itr->first);
7009 stmt->setUInt32(2, itr->second.Quantity);
7010 stmt->setUInt32(3, itr->second.WeeklyQuantity);
7011 stmt->setUInt32(4, itr->second.TrackedQuantity);
7012 stmt->setUInt32(5, itr->second.IncreasedCapQuantity);
7013 stmt->setUInt32(6, itr->second.EarnedQuantity);
7014 stmt->setUInt8(7, AsUnderlyingType(itr->second.Flags));
7015 trans->Append(stmt);
7016 break;
7018 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_PLAYER_CURRENCY);
7019 stmt->setUInt32(0, itr->second.Quantity);
7020 stmt->setUInt32(1, itr->second.WeeklyQuantity);
7021 stmt->setUInt32(2, itr->second.TrackedQuantity);
7022 stmt->setUInt32(3, itr->second.IncreasedCapQuantity);
7023 stmt->setUInt32(4, itr->second.EarnedQuantity);
7024 stmt->setUInt8(5, AsUnderlyingType(itr->second.Flags));
7025 stmt->setUInt64(6, GetGUID().GetCounter());
7026 stmt->setUInt16(7, itr->first);
7027 trans->Append(stmt);
7028 break;
7029 default:
7030 break;
7031 }
7032
7033 itr->second.state = PLAYERCURRENCY_UNCHANGED;
7034 }
7035}
7036
7038{
7040 packet.Data.reserve(_currencyStorage.size());
7041
7042 for (PlayerCurrenciesMap::const_iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr)
7043 {
7044 CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(itr->first);
7045
7046 if (!currency)
7047 continue;
7048
7049 // Check faction
7050 if ((currency->IsAlliance() && GetTeam() != ALLIANCE) ||
7051 (currency->IsHorde() && GetTeam() != HORDE))
7052 continue;
7053
7054 // Check award condition
7055 if (currency->AwardConditionID)
7056 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(currency->AwardConditionID))
7057 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
7058 continue;
7059
7061 record.Type = currency->ID;
7062 record.Quantity = itr->second.Quantity;
7063
7064 if ((itr->second.WeeklyQuantity / currency->GetScaler()) > 0)
7065 record.WeeklyQuantity = itr->second.WeeklyQuantity;
7066
7067 if (currency->HasMaxEarnablePerWeek())
7068 record.MaxWeeklyQuantity = GetCurrencyWeeklyCap(currency);
7069
7070 if (currency->IsTrackingQuantity())
7071 record.TrackedQuantity = itr->second.TrackedQuantity;
7072
7073 if (currency->HasTotalEarned())
7074 record.TotalEarned = itr->second.EarnedQuantity;
7075
7076 if (currency->HasMaxQuantity(true))
7077 record.MaxQuantity = GetCurrencyMaxQuantity(currency, true);
7078
7079 record.Flags = AsUnderlyingType(itr->second.Flags);
7080 record.Flags &= ~AsUnderlyingType(CurrencyDbFlags::UnusedFlags);
7081
7082 packet.Data.push_back(record);
7083 }
7084
7085 SendDirectMessage(packet.Write());
7086}
7087
7089{
7090 //WorldPacket packet(SMSG_REQUEST_PVP_REWARDS_RESPONSE, 24);
7091 //GetSession()->SendPacket(&packet);
7092}
7093
7095{
7096 PlayerCurrenciesMap::iterator itr = _currencyStorage.find(id);
7097 if (itr == _currencyStorage.end())
7098 {
7099 itr = _currencyStorage.emplace(id, PlayerCurrency{}).first;
7100 itr->second.state = PLAYERCURRENCY_NEW;
7101 itr->second.Quantity = amount;
7102 itr->second.WeeklyQuantity = 0;
7103 itr->second.TrackedQuantity = 0;
7104 itr->second.IncreasedCapQuantity = 0;
7105 itr->second.EarnedQuantity = 0;
7106 itr->second.Flags = CurrencyDbFlags(0);
7107 }
7108}
7109
7110void Player::ModifyCurrency(uint32 id, int32 amount, CurrencyGainSource gainSource/* = CurrencyGainSource::Cheat*/, CurrencyDestroyReason destroyReason/* = CurrencyDestroyReason::Cheat*/)
7111{
7112 if (!amount)
7113 return;
7114
7115 CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id);
7116 ASSERT(currency);
7117
7118 // Check faction
7119 if ((currency->IsAlliance() && GetTeam() != ALLIANCE) ||
7120 (currency->IsHorde() && GetTeam() != HORDE))
7121 return;
7122
7123 // Check award condition
7124 if (currency->AwardConditionID)
7125 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(currency->AwardConditionID))
7126 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
7127 return;
7128
7129 bool isGainOnRefund = [&]() -> bool
7130 {
7131 if (gainSource == CurrencyGainSource::ItemRefund ||
7134 return true;
7135
7136 return false;
7137 }();
7138
7139 bool ignoreCaps = isGainOnRefund || gainSource == CurrencyGainSource::QuestRewardIgnoreCaps || gainSource == CurrencyGainSource::WorldQuestRewardIgnoreCaps;
7140
7141 if (amount > 0 && !isGainOnRefund && gainSource != CurrencyGainSource::Vendor)
7142 {
7145 }
7146
7147 int32 scaler = currency->GetScaler();
7148
7149 // Currency that is immediately converted into reputation with that faction instead
7150 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(currency->FactionID))
7151 {
7152 amount /= scaler;
7153 GetReputationMgr().ModifyReputation(factionEntry, amount, false, true);
7154 return;
7155 }
7156
7157 // Azerite
7158 if (id == CURRENCY_TYPE_AZERITE)
7159 {
7160 if (amount > 0)
7162 heartOfAzeroth->ToAzeriteItem()->GiveXP(uint64(amount));
7163 return;
7164 }
7165
7166 PlayerCurrenciesMap::iterator itr = _currencyStorage.find(id);
7167 if (itr == _currencyStorage.end())
7168 {
7169 itr = _currencyStorage.emplace(id, PlayerCurrency{}).first;
7170 itr->second.state = PLAYERCURRENCY_NEW;
7171 itr->second.Quantity = 0;
7172 itr->second.WeeklyQuantity = 0;
7173 itr->second.TrackedQuantity = 0;
7174 itr->second.IncreasedCapQuantity = 0;
7175 itr->second.EarnedQuantity = 0;
7176 itr->second.Flags = CurrencyDbFlags(0);
7177 }
7178
7179 uint32 weeklyCap = GetCurrencyWeeklyCap(currency);
7180 if (!ignoreCaps) // Ignore weekly cap for refund
7181 {
7182 // Weekly cap
7183 if (weeklyCap && amount > 0 && (itr->second.WeeklyQuantity + amount) > weeklyCap)
7184 amount = weeklyCap - itr->second.WeeklyQuantity;
7185
7186 // Max cap
7187 uint32 maxCap = GetCurrencyMaxQuantity(currency, false, gainSource == CurrencyGainSource::UpdatingVersion);
7188 if (maxCap && amount > 0 && (itr->second.Quantity + amount) > maxCap)
7189 amount = maxCap - itr->second.Quantity;
7190 }
7191
7192 // Underflow protection
7193 if (amount < 0 && uint32(std::abs(amount)) > itr->second.Quantity)
7194 amount = itr->second.Quantity * -1;
7195
7196 if (!amount)
7197 return;
7198
7199 if (itr->second.state != PLAYERCURRENCY_NEW)
7200 itr->second.state = PLAYERCURRENCY_CHANGED;
7201
7202 itr->second.Quantity += amount;
7203
7204 if (amount > 0 && !ignoreCaps) // Ignore total values update for refund
7205 {
7206 if (weeklyCap)
7207 itr->second.WeeklyQuantity += amount;
7208
7209 if (currency->IsTrackingQuantity())
7210 itr->second.TrackedQuantity += amount;
7211
7212 if (currency->HasTotalEarned())
7213 itr->second.EarnedQuantity += amount;
7214
7215 if (!isGainOnRefund)
7217 }
7218
7219 CurrencyChanged(id, amount);
7220
7222 packet.Type = currency->ID;
7223 packet.Quantity = itr->second.Quantity;
7224 packet.Flags = CurrencyGainFlags::None; // TODO: Check when flags are applied
7225
7226 if ((itr->second.WeeklyQuantity / currency->GetScaler()) > 0)
7227 packet.WeeklyQuantity = itr->second.WeeklyQuantity;
7228
7229 if (currency->HasMaxQuantity(false, gainSource == CurrencyGainSource::UpdatingVersion))
7230 packet.MaxQuantity = GetCurrencyMaxQuantity(currency);
7231
7232 if (currency->HasTotalEarned())
7233 packet.TotalEarned = itr->second.EarnedQuantity;
7234
7236 packet.QuantityChange = amount;
7237
7238 if (amount > 0)
7239 packet.QuantityGainSource = gainSource;
7240 else
7241 packet.QuantityLostSource = destroyReason;
7242
7243 // TODO: FirstCraftOperationID, LastSpendTime & Toasts
7244
7245 SendDirectMessage(packet.Write());
7246}
7247
7248void Player::AddCurrency(uint32 id, uint32 amount, CurrencyGainSource gainSource/* = CurrencyGainSource::Cheat*/)
7249{
7250 ModifyCurrency(id, amount, gainSource);
7251}
7252
7253void Player::RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason/* = CurrencyDestroyReason::Cheat*/)
7254{
7255 ModifyCurrency(id, -amount, {}, destroyReason);
7256}
7257
7259{
7260 if (!amount)
7261 return;
7262
7263 CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id);
7264 ASSERT(currency);
7265
7266 // Check faction
7267 if ((currency->IsAlliance() && GetTeam() != ALLIANCE) ||
7268 (currency->IsHorde() && GetTeam() != HORDE))
7269 return;
7270
7271 // Check dynamic maximum flag
7272 if (!currency->GetFlags().HasFlag(CurrencyTypesFlags::DynamicMaximum))
7273 return;
7274
7275 // Ancient mana maximum cap
7277 {
7278 uint32 maxQuantity = GetCurrencyMaxQuantity(currency);
7279
7280 if ((maxQuantity + amount) > CURRENCY_MAX_CAP_ANCIENT_MANA)
7281 amount = CURRENCY_MAX_CAP_ANCIENT_MANA - maxQuantity;
7282 }
7283
7284 PlayerCurrenciesMap::iterator itr = _currencyStorage.find(id);
7285 if (itr == _currencyStorage.end())
7286 {
7287 PlayerCurrency cur;
7289 cur.Quantity = 0;
7290 cur.WeeklyQuantity = 0;
7291 cur.TrackedQuantity = 0;
7292 cur.IncreasedCapQuantity = amount;
7293 cur.EarnedQuantity = 0;
7294 cur.Flags = CurrencyDbFlags(0);
7295 _currencyStorage[id] = cur;
7296 itr = _currencyStorage.find(id);
7297 }
7298 else
7299 {
7300 itr->second.IncreasedCapQuantity += amount;
7301 }
7302
7303 if (itr->second.state != PLAYERCURRENCY_NEW)
7304 itr->second.state = PLAYERCURRENCY_CHANGED;
7305
7307 packet.Type = currency->ID;
7308 packet.Quantity = itr->second.Quantity;
7310
7311 if ((itr->second.WeeklyQuantity / currency->GetScaler()) > 0)
7312 packet.WeeklyQuantity = itr->second.WeeklyQuantity;
7313
7314 if (currency->IsTrackingQuantity())
7315 packet.TrackedQuantity = itr->second.TrackedQuantity;
7316
7317 packet.MaxQuantity = GetCurrencyMaxQuantity(currency);
7318 packet.SuppressChatLog = currency->IsSuppressingChatLog();
7319
7320 SendDirectMessage(packet.Write());
7321}
7322
7324{
7325 for (uint32 arenaSlot = 0; arenaSlot < MAX_ARENA_SLOT; arenaSlot++)
7326 {
7327 if (uint32 arenaTeamId = GetArenaTeamId(arenaSlot))
7328 {
7329 ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId);
7330 ASSERT(arenaTeam);
7331 arenaTeam->FinishWeek(); // set played this week etc values to 0 in memory, too
7332 arenaTeam->SaveToDB(); // save changes
7333 arenaTeam->NotifyStatsChanged(); // notify the players of the changes
7334 }
7335 }
7336
7337 for (PlayerCurrenciesMap::iterator itr = _currencyStorage.begin(); itr != _currencyStorage.end(); ++itr)
7338 {
7339 itr->second.WeeklyQuantity = 0;
7340 itr->second.state = PLAYERCURRENCY_CHANGED;
7341 }
7342
7344}
7345
7347{
7348 PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
7349 if (itr == _currencyStorage.end())
7350 return 0;
7351
7352 return itr->second.Quantity;
7353}
7354
7356{
7357 PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
7358 if (itr == _currencyStorage.end())
7359 return 0;
7360
7361 return itr->second.WeeklyQuantity;
7362}
7363
7365{
7366 PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
7367 if (itr == _currencyStorage.end())
7368 return 0;
7369
7370 return itr->second.TrackedQuantity;
7371}
7372
7374{
7375 PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
7376 if (itr == _currencyStorage.end())
7377 return 0;
7378
7379 return itr->second.IncreasedCapQuantity;
7380}
7381
7382uint32 Player::GetCurrencyMaxQuantity(CurrencyTypesEntry const* currency, bool onLoad/* = false*/, bool onUpdateVersion/* = false*/) const
7383{
7384 if (!currency->HasMaxQuantity(onLoad, onUpdateVersion))
7385 return 0;
7386
7387 uint32 maxQuantity = currency->MaxQty;
7388 if (currency->MaxQtyWorldStateID)
7389 maxQuantity = sWorldStateMgr->GetValue(currency->MaxQtyWorldStateID, GetMap());
7390
7391 uint32 increasedCap = 0;
7392 if (currency->GetFlags().HasFlag(CurrencyTypesFlags::DynamicMaximum))
7393 increasedCap = GetCurrencyIncreasedCapQuantity(currency->ID);
7394
7395 return maxQuantity + increasedCap;
7396}
7397
7399{
7400 CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(id);
7401 if (!currency)
7402 return 0;
7403
7404 return GetCurrencyWeeklyCap(currency);
7405}
7406
7408{
7409 // TODO: CurrencyTypeFlags::ComputedWeeklyMaximum
7410 return currency->MaxEarnablePerWeek;
7411}
7412
7413bool Player::HasCurrency(uint32 id, uint32 amount) const
7414{
7415 PlayerCurrenciesMap::const_iterator itr = _currencyStorage.find(id);
7416 return itr != _currencyStorage.end() && itr->second.Quantity >= amount;
7417}
7418
7420{
7421 if (guildId)
7422 {
7423 SetUpdateFieldValue(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::GuildGUID), ObjectGuid::Create<HighGuid::Guild>(guildId));
7425 }
7426 else
7427 {
7430 }
7431
7432 sCharacterCache->UpdateCharacterGuildId(GetGUID(), guildId);
7433}
7434
7436{
7437}
7438
7439void Player::SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type)
7440{
7441 SetArenaTeamInfoField(slot, ARENA_TEAM_ID, ArenaTeamId);
7443}
7444
7446{
7447 ObjectGuid::LowType guidLow = guid.GetCounter();
7449 stmt->setUInt64(0, guidLow);
7450 PreparedQueryResult result = CharacterDatabase.Query(stmt);
7451
7452 if (!result)
7453 return 0;
7454 Field* fields = result->Fetch();
7455 uint32 zone = fields[0].GetUInt16();
7456
7457 if (!zone)
7458 {
7459 // stored zone is zero, use generic and slow zone detection
7460 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_POSITION_XYZ);
7461 stmt->setUInt64(0, guidLow);
7462 result = CharacterDatabase.Query(stmt);
7463
7464 if (!result)
7465 return 0;
7466 fields = result->Fetch();
7467 uint32 map = fields[0].GetUInt16();
7468 float posx = fields[1].GetFloat();
7469 float posy = fields[2].GetFloat();
7470 float posz = fields[3].GetFloat();
7471
7472 if (!sMapStore.LookupEntry(map))
7473 return 0;
7474
7475 zone = sTerrainMgr.GetZoneId(PhasingHandler::GetEmptyPhaseShift(), map, posx, posy, posz);
7476
7477 if (zone > 0)
7478 {
7479 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ZONE);
7480
7481 stmt->setUInt16(0, uint16(zone));
7482 stmt->setUInt64(1, guidLow);
7483
7484 CharacterDatabase.Execute(stmt);
7485 }
7486 }
7487
7488 return zone;
7489}
7490
7492{
7493 // FFA_PVP flags are area and not zone id dependent
7494 // so apply them accordingly
7495 uint32 const oldArea = m_areaUpdateId;
7496 m_areaUpdateId = newArea;
7497
7498 AreaTableEntry const* oldAreaEntry = sAreaTableStore.LookupEntry(oldArea);
7499 AreaTableEntry const* area = sAreaTableStore.LookupEntry(newArea);
7500 bool oldFFAPvPArea = pvpInfo.IsInFFAPvPArea;
7501 pvpInfo.IsInFFAPvPArea = area && (area->GetFlags().HasFlag(AreaFlags::FreeForAllPvP));
7502 UpdatePvPState(true);
7503
7504 // check if we were in ffa arena and we left
7505 if (oldFFAPvPArea && !pvpInfo.IsInFFAPvPArea)
7507
7509 UpdateAreaDependentAuras(newArea);
7510
7511 if (IsAreaThatActivatesPvpTalents(newArea))
7513 else
7515
7516 // previously this was in UpdateZone (but after UpdateArea) so nothing will break
7517 pvpInfo.IsInNoPvPArea = false;
7518 if (area && area->IsSanctuary()) // in sanctuary
7519 {
7521 pvpInfo.IsInNoPvPArea = true;
7522 if (!duel && GetCombatManager().HasPvPCombat())
7524 }
7525 else
7527
7529 if (area && area->GetFlags().HasFlag(areaRestFlag))
7530 _restMgr->SetRestFlag(REST_FLAG_IN_FACTION_AREA);
7531 else
7532 _restMgr->RemoveRestFlag(REST_FLAG_IN_FACTION_AREA);
7533
7534 PushQuests();
7535
7537
7538 if ((oldAreaEntry && oldAreaEntry->GetFlags2().HasFlag(AreaFlags2::UseSubzoneForChatChannel))
7539 || (area && area->GetFlags2().HasFlag(AreaFlags2::UseSubzoneForChatChannel)))
7540 UpdateLocalChannels(newArea);
7541
7542 if (oldArea != newArea)
7543 {
7546 }
7547}
7548
7549void Player::UpdateZone(uint32 newZone, uint32 newArea)
7550{
7551 if (!IsInWorld())
7552 return;
7553
7554 uint32 const oldZone = m_zoneUpdateId;
7555 m_zoneUpdateId = newZone;
7557
7558 GetMap()->UpdatePlayerZoneStats(oldZone, newZone);
7559
7560 // call leave script hooks immedately (before updating flags)
7561 if (oldZone != newZone)
7562 {
7563 sOutdoorPvPMgr->HandlePlayerLeaveZone(this, oldZone);
7564 sBattlefieldMgr->HandlePlayerLeaveZone(this, oldZone);
7565 }
7566
7567 // group update
7568 if (GetGroup())
7569 {
7571 if (Pet* pet = GetPet())
7572 pet->SetGroupUpdateFlag(GROUP_UPDATE_PET_FULL);
7573 }
7574
7575 // zone changed, so area changed as well, update it.
7576 UpdateArea(newArea);
7577
7578 AreaTableEntry const* zone = sAreaTableStore.LookupEntry(newZone);
7579 if (!zone)
7580 return;
7581
7582 if (sWorld->getBoolConfig(CONFIG_WEATHER))
7584
7585 GetMap()->SendZoneDynamicInfo(newZone, this);
7586
7588
7590
7591 if (zone->GetFlags().HasFlag(AreaFlags::LinkedChat)) // Is in a capital city
7592 {
7593 if (!pvpInfo.IsHostile || zone->IsSanctuary())
7594 _restMgr->SetRestFlag(REST_FLAG_IN_CITY);
7595 pvpInfo.IsInNoPvPArea = true;
7596 }
7597 else
7598 _restMgr->RemoveRestFlag(REST_FLAG_IN_CITY);
7599
7601
7602 // remove items with area/map limitations (delete only for alive player to allow back in ghost mode)
7603 // if player resurrected at teleport this will be applied in resurrect code
7604 if (IsAlive())
7605 DestroyZoneLimitedItem(true, newZone);
7606
7607 // check some item equip limitations (in result lost CanTitanGrip at talent reset, for example)
7609
7610 // recent client version not send leave/join channel packets for built-in local channels
7611 AreaTableEntry const* newAreaEntry = sAreaTableStore.LookupEntry(newArea);
7612 if (!newAreaEntry || !newAreaEntry->GetFlags2().HasFlag(AreaFlags2::UseSubzoneForChatChannel))
7613 UpdateLocalChannels(newZone);
7614
7615 UpdateZoneDependentAuras(newZone);
7616
7617 // call enter script hooks after everyting else has processed
7618 sScriptMgr->OnPlayerUpdateZone(this, newZone, newArea);
7619 if (oldZone != newZone)
7620 {
7621 sOutdoorPvPMgr->HandlePlayerEnterZone(this, newZone);
7622 sBattlefieldMgr->HandlePlayerEnterZone(this, newZone);
7623 SendInitWorldStates(newZone, newArea); // only if really enters to new zone, not just area change, works strange...
7624 if (Guild* guild = GetGuild())
7625 guild->UpdateMemberData(this, GUILD_MEMBER_DATA_ZONEID, newZone);
7628
7629 {
7631
7632 for (Vignettes::VignetteData const* vignette : GetMap()->GetInfiniteAOIVignettes())
7633 {
7634 if (!vignette->Data->GetFlags().HasFlag(VignetteFlags::ZoneInfiniteAOI))
7635 continue;
7636
7637 if (vignette->ZoneID == newZone && Vignettes::CanSee(this, *vignette))
7638 vignette->FillPacket(vignetteUpdate.Added);
7639 else if (vignette->ZoneID == oldZone)
7640 vignetteUpdate.Removed.push_back(vignette->Guid);
7641 }
7642
7643 if (!vignetteUpdate.Added.IDs.empty() || !vignetteUpdate.Removed.empty())
7644 SendDirectMessage(vignetteUpdate.Write());
7645 }
7646 }
7647}
7648
7650{
7651 ZonePVPTypeOverride overrideZonePvpType = GetOverrideZonePVPType();
7652
7653 pvpInfo.IsInHostileArea = false;
7654
7655 if (area->IsSanctuary()) // sanctuary and arena cannot be overriden
7656 pvpInfo.IsInHostileArea = false;
7657 else if (area->GetFlags().HasFlag(AreaFlags::FreeForAllPvP))
7658 pvpInfo.IsInHostileArea = true;
7659 else if (overrideZonePvpType == ZonePVPTypeOverride::None)
7660 {
7661 if (area)
7662 {
7663 if (InBattleground() || area->GetFlags().HasFlag(AreaFlags::CombatZone) || (area->PvpCombatWorldStateID != -1 && sWorldStateMgr->GetValue(area->PvpCombatWorldStateID, GetMap()) != 0))
7664 pvpInfo.IsInHostileArea = true;
7665 else if (IsWarModeLocalActive() || (area->GetFlags().HasFlag(AreaFlags::EnemiesPvPFlagged)))
7666 {
7667 if (area->GetFlags().HasFlag(AreaFlags::Contested))
7669 else
7670 {
7671 FactionTemplateEntry const* factionTemplate = GetFactionTemplateEntry();
7672 if (!factionTemplate || factionTemplate->FriendGroup & area->FactionGroupMask)
7673 pvpInfo.IsInHostileArea = false; // friend area are considered hostile if war mode is active
7674 else if (factionTemplate->EnemyGroup & area->FactionGroupMask)
7675 pvpInfo.IsInHostileArea = true;
7676 else
7677 pvpInfo.IsInHostileArea = sWorld->IsPvPRealm();
7678 }
7679 }
7680 }
7681 }
7682 else
7683 {
7684 switch (overrideZonePvpType)
7685 {
7687 pvpInfo.IsInHostileArea = false;
7688 break;
7692 pvpInfo.IsInHostileArea = true;
7693 break;
7694 default:
7695 break;
7696 }
7697 }
7698
7699 // Treat players having a quest flagging for PvP as always in hostile area
7701}
7702
7703//If players are too far away from the duel flag... they lose the duel
7704void Player::CheckDuelDistance(time_t currTime)
7705{
7706 if (!duel)
7707 return;
7708
7709 ObjectGuid duelFlagGUID = m_playerData->DuelArbiter;
7710 GameObject* obj = GetMap()->GetGameObject(duelFlagGUID);
7711 if (!obj)
7712 return;
7713
7714 if (!duel->OutOfBoundsTime)
7715 {
7716 if (!IsWithinDistInMap(obj, 50))
7717 {
7718 duel->OutOfBoundsTime = currTime + 10;
7719
7721 }
7722 }
7723 else
7724 {
7725 if (IsWithinDistInMap(obj, 40))
7726 {
7727 duel->OutOfBoundsTime = 0;
7728
7730 }
7731 else if (currTime >= duel->OutOfBoundsTime)
7733 }
7734}
7735
7737{
7739}
7740
7742{
7743 // duel not requested
7744 if (!duel)
7745 return;
7746
7747 // Check if DuelComplete() has been called already up in the stack and in that case don't do anything else here
7748 if (duel->State == DUEL_STATE_COMPLETED)
7749 return;
7750
7751 Player* opponent = duel->Opponent;
7752 duel->State = DUEL_STATE_COMPLETED;
7753 opponent->duel->State = DUEL_STATE_COMPLETED;
7754
7755 TC_LOG_DEBUG("entities.unit", "Player::DuelComplete: Player '{}' ({}), Opponent: '{}' ({})",
7756 GetName(), GetGUID().ToString(), opponent->GetName(), opponent->GetGUID().ToString());
7757
7759 duelCompleted.Started = type != DUEL_INTERRUPTED;
7760 SendDirectMessage(duelCompleted.Write());
7761 if (opponent->GetSession())
7762 opponent->SendDirectMessage(duelCompleted.GetRawPacket());
7763
7764 if (type != DUEL_INTERRUPTED)
7765 {
7767 duelWinner.BeatenName = (type == DUEL_WON ? opponent->GetName() : GetName());
7768 duelWinner.WinnerName = (type == DUEL_WON ? GetName() : opponent->GetName());
7771 duelWinner.Fled = type != DUEL_WON;
7772
7773 SendMessageToSet(duelWinner.Write(), true);
7774 }
7775
7776 opponent->DisablePvpRules();
7778
7779 sScriptMgr->OnPlayerDuelEnd(opponent, this, type);
7780
7781 switch (type)
7782 {
7783 case DUEL_FLED:
7784 // if initiator and opponent are on the same team
7785 // or initiator and opponent are not PvP enabled, forcibly stop attacking
7786 if (GetTeam() == opponent->GetTeam())
7787 {
7788 AttackStop();
7789 opponent->AttackStop();
7790 }
7791 else
7792 {
7793 if (!IsPvP())
7794 AttackStop();
7795 if (!opponent->IsPvP())
7796 opponent->AttackStop();
7797 }
7798 break;
7799 case DUEL_WON:
7802
7803 // Credit for quest Death's Challenge
7804 if (GetClass() == CLASS_DEATH_KNIGHT && opponent->GetQuestStatus(12733) == QUEST_STATUS_INCOMPLETE)
7805 opponent->CastSpell(opponent, 52994, true);
7806
7807 // Honor points after duel (the winner) - ImpConfig
7808 if (uint32 amount = sWorld->getIntConfig(CONFIG_HONOR_AFTER_DUEL))
7809 opponent->RewardHonor(nullptr, 1, amount);
7810
7811 break;
7812 default:
7813 break;
7814 }
7815
7816 // Victory emote spell
7817 if (type != DUEL_INTERRUPTED)
7818 opponent->CastSpell(opponent, 52852, true);
7819
7820 //Remove Duel Flag object
7821 GameObject* obj = GetMap()->GetGameObject(m_playerData->DuelArbiter);
7822 if (obj)
7823 duel->Initiator->RemoveGameObject(obj, true);
7824
7825 /* remove auras */
7826 AuraApplicationMap &itsAuras = opponent->GetAppliedAuras();
7827 for (AuraApplicationMap::iterator i = itsAuras.begin(); i != itsAuras.end();)
7828 {
7829 Aura const* aura = i->second->GetBase();
7830 if (!i->second->IsPositive() && aura->GetCasterGUID() == GetGUID() && aura->GetApplyTime() >= duel->StartTime)
7831 opponent->RemoveAura(i);
7832 else
7833 ++i;
7834 }
7835
7837 for (AuraApplicationMap::iterator i = myAuras.begin(); i != myAuras.end();)
7838 {
7839 Aura const* aura = i->second->GetBase();
7840 if (!i->second->IsPositive() && aura->GetCasterGUID() == opponent->GetGUID() && aura->GetApplyTime() >= duel->StartTime)
7841 RemoveAura(i);
7842 else
7843 ++i;
7844 }
7845
7848
7849 // cleanup combo points
7851 opponent->SetPower(POWER_COMBO_POINTS, 0);
7852
7853 //cleanups
7855 SetDuelTeam(0);
7857 opponent->SetDuelTeam(0);
7858
7859 opponent->duel.reset(nullptr);
7860 duel.reset(nullptr);
7861}
7862
7863//---------------------------------------------------------//
7864
7865void Player::_ApplyItemMods(Item* item, uint8 slot, bool apply, bool updateItemAuras /*= true*/)
7866{
7867 if (slot >= INVENTORY_SLOT_BAG_END || !item)
7868 return;
7869
7870 ItemTemplate const* proto = item->GetTemplate();
7871 if (!proto)
7872 return;
7873
7874 // not apply/remove mods for broken item
7875 if (item->IsBroken())
7876 return;
7877
7878 TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: Applying mods for item {}", item->GetGUID().ToString());
7879
7880 if (item->GetSocketColor(0)) //only (un)equipping of items with sockets can influence metagems, so no need to waste time with normal items
7882
7883 _ApplyItemBonuses(item, slot, apply);
7885 if (updateItemAuras)
7886 {
7888
7889 WeaponAttackType const attackType = Player::GetAttackBySlot(slot, item->GetTemplate()->GetInventoryType());
7890 if (attackType != MAX_ATTACK)
7891 UpdateWeaponDependentAuras(attackType);
7892 }
7895 ApplyEnchantment(item, apply);
7896
7897 TC_LOG_DEBUG("entities.player.items", "Player::_ApplyItemMods: completed");
7898}
7899
7901{
7902 ItemTemplate const* proto = item->GetTemplate();
7903 if (slot >= INVENTORY_SLOT_BAG_END || !proto)
7904 return;
7905
7906 uint32 itemLevel = item->GetItemLevel(this);
7907 float combatRatingMultiplier = 1.0f;
7908 if (GtCombatRatingsMultByILvl const* ratingMult = sCombatRatingsMultByILvlGameTable.GetRow(itemLevel))
7909 combatRatingMultiplier = GetIlvlStatMultiplier(ratingMult, proto->GetInventoryType());
7910
7911 for (uint8 i = 0; i < MAX_ITEM_PROTO_STATS; ++i)
7912 {
7913 int32 statType = item->GetItemStatType(i);
7914 if (statType == -1)
7915 continue;
7916
7917 float val = item->GetItemStatValue(i, this);
7918 if (val == 0)
7919 continue;
7920
7921 switch (statType)
7922 {
7923 case ITEM_MOD_MANA:
7925 break;
7926 case ITEM_MOD_HEALTH: // modify HP
7928 break;
7929 case ITEM_MOD_AGILITY: // modify agility
7932 break;
7933 case ITEM_MOD_STRENGTH: //modify strength
7936 break;
7937 case ITEM_MOD_INTELLECT: //modify intellect
7940 break;
7941 // case ITEM_MOD_SPIRIT: //modify spirit
7942 // HandleStatModifier(UNIT_MOD_STAT_SPIRIT, BASE_VALUE, float(val), apply);
7943 // ApplyStatBuffMod(STAT_SPIRIT, CalculatePct(val, GetModifierValue(UNIT_MOD_STAT_SPIRIT, BASE_PCT_EXCLUDE_CREATE)), apply);
7944 // break;
7945 case ITEM_MOD_STAMINA: //modify stamina
7946 {
7947 if (GtStaminaMultByILvl const* staminaMult = sStaminaMultByILvlGameTable.GetRow(itemLevel))
7948 val = int32(val * GetIlvlStatMultiplier(staminaMult, proto->GetInventoryType()));
7951 break;
7952 }
7954 ApplyRatingMod(CR_DEFENSE_SKILL, int32(val * combatRatingMultiplier), apply);
7955 break;
7957 ApplyRatingMod(CR_DODGE, int32(val * combatRatingMultiplier), apply);
7958 break;
7960 ApplyRatingMod(CR_PARRY, int32(val * combatRatingMultiplier), apply);
7961 break;
7963 ApplyRatingMod(CR_BLOCK, int32(val * combatRatingMultiplier), apply);
7964 break;
7966 ApplyRatingMod(CR_HIT_MELEE, int32(val * combatRatingMultiplier), apply);
7967 break;
7969 ApplyRatingMod(CR_HIT_RANGED, int32(val * combatRatingMultiplier), apply);
7970 break;
7972 ApplyRatingMod(CR_HIT_SPELL, int32(val * combatRatingMultiplier), apply);
7973 break;
7975 ApplyRatingMod(CR_CRIT_MELEE, int32(val * combatRatingMultiplier), apply);
7976 break;
7978 ApplyRatingMod(CR_CRIT_RANGED, int32(val * combatRatingMultiplier), apply);
7979 break;
7981 ApplyRatingMod(CR_CRIT_SPELL, int32(val * combatRatingMultiplier), apply);
7982 break;
7983 // case ITEM_MOD_HIT_TAKEN_MELEE_RATING:
7984 // ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply);
7985 // break;
7986 // case ITEM_MOD_HIT_TAKEN_RANGED_RATING:
7987 // ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply);
7988 // break;
7989 // case ITEM_MOD_HIT_TAKEN_SPELL_RATING:
7990 // ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply);
7991 // break;
7992 // case ITEM_MOD_CRIT_TAKEN_MELEE_RATING:
7993 // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply);
7994 // break;
7997 break;
7998 // case ITEM_MOD_CRIT_TAKEN_SPELL_RATING:
7999 // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply);
8000 // break;
8003 break;
8006 break;
8009 break;
8011 ApplyRatingMod(CR_HIT_MELEE, int32(val * combatRatingMultiplier), apply);
8012 ApplyRatingMod(CR_HIT_RANGED, int32(val * combatRatingMultiplier), apply);
8013 ApplyRatingMod(CR_HIT_SPELL, int32(val * combatRatingMultiplier), apply);
8014 break;
8016 ApplyRatingMod(CR_CRIT_MELEE, int32(val * combatRatingMultiplier), apply);
8017 ApplyRatingMod(CR_CRIT_RANGED, int32(val * combatRatingMultiplier), apply);
8018 ApplyRatingMod(CR_CRIT_SPELL, int32(val * combatRatingMultiplier), apply);
8019 break;
8020 // case ITEM_MOD_HIT_TAKEN_RATING: // Unused since 3.3.5
8021 // ApplyRatingMod(CR_HIT_TAKEN_MELEE, int32(val), apply);
8022 // ApplyRatingMod(CR_HIT_TAKEN_RANGED, int32(val), apply);
8023 // ApplyRatingMod(CR_HIT_TAKEN_SPELL, int32(val), apply);
8024 // break;
8025 // case ITEM_MOD_CRIT_TAKEN_RATING: // Unused since 3.3.5
8026 // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, int32(val), apply);
8027 // ApplyRatingMod(CR_CRIT_TAKEN_RANGED, int32(val), apply);
8028 // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, int32(val), apply);
8029 // break;
8031 ApplyRatingMod(CR_RESILIENCE_PLAYER_DAMAGE, int32(val * combatRatingMultiplier), apply);
8032 break;
8034 ApplyRatingMod(CR_HASTE_MELEE, int32(val * combatRatingMultiplier), apply);
8035 ApplyRatingMod(CR_HASTE_RANGED, int32(val * combatRatingMultiplier), apply);
8036 ApplyRatingMod(CR_HASTE_SPELL, int32(val * combatRatingMultiplier), apply);
8037 break;
8039 ApplyRatingMod(CR_EXPERTISE, int32(val * combatRatingMultiplier), apply);
8040 break;
8044 break;
8047 break;
8049 ApplyRatingMod(CR_VERSATILITY_DAMAGE_DONE, int32(val * combatRatingMultiplier), apply);
8050 ApplyRatingMod(CR_VERSATILITY_DAMAGE_TAKEN, int32(val * combatRatingMultiplier), apply);
8051 ApplyRatingMod(CR_VERSATILITY_HEALING_DONE, int32(val * combatRatingMultiplier), apply);
8052 break;
8055 break;
8058 break;
8061 break;
8064 break;
8067 break;
8069 ApplyRatingMod(CR_MASTERY, int32(val * combatRatingMultiplier), apply);
8070 break;
8073 break;
8076 break;
8079 break;
8082 break;
8085 break;
8088 break;
8091 break;
8092 case ITEM_MOD_PVP_POWER:
8094 break;
8097 break;
8100 break;
8101 case ITEM_MOD_CR_SPEED:
8102 ApplyRatingMod(CR_SPEED, int32(val * combatRatingMultiplier), apply);
8103 break;
8105 ApplyRatingMod(CR_LIFESTEAL, int32(val * combatRatingMultiplier), apply);
8106 break;
8108 ApplyRatingMod(CR_AVOIDANCE, int32(val * combatRatingMultiplier), apply);
8109 break;
8111 ApplyRatingMod(CR_STURDINESS, int32(val * combatRatingMultiplier), apply);
8112 break;
8120 break;
8121 case ITEM_MOD_AGI_STR:
8126 break;
8127 case ITEM_MOD_AGI_INT:
8132 break;
8133 case ITEM_MOD_STR_INT:
8138 break;
8139 }
8140 }
8141
8142 if (uint32 armor = proto->GetArmor(itemLevel))
8143 {
8145 if (proto->GetClass() == ITEM_CLASS_ARMOR && proto->GetSubClass() == ITEM_SUBCLASS_ARMOR_SHIELD)
8147 }
8148
8150 if (attType != MAX_ATTACK)
8151 _ApplyWeaponDamage(slot, item, apply);
8152}
8153
8155{
8156 ItemTemplate const* proto = item->GetTemplate();
8158 if (!IsInFeralForm() && apply && !CanUseAttackType(attType))
8159 return;
8160
8161 float damage = 0.0f;
8162 uint32 itemLevel = item->GetItemLevel(this);
8163 float minDamage, maxDamage;
8164 proto->GetDamage(itemLevel, minDamage, maxDamage);
8165
8166 if (minDamage > 0)
8167 {
8168 damage = apply ? minDamage : BASE_MINDAMAGE;
8169 SetBaseWeaponDamage(attType, MINDAMAGE, damage);
8170 }
8171
8172 if (maxDamage > 0)
8173 {
8174 damage = apply ? maxDamage : BASE_MAXDAMAGE;
8175 SetBaseWeaponDamage(attType, MAXDAMAGE, damage);
8176 }
8177
8178 SpellShapeshiftFormEntry const* shapeshift = sSpellShapeshiftFormStore.LookupEntry(GetShapeshiftForm());
8179 if (proto->GetDelay() && !(shapeshift && shapeshift->CombatRoundTime))
8180 SetBaseAttackTime(attType, apply ? proto->GetDelay() : BASE_ATTACK_TIME);
8181
8182 int32 weaponBasedAttackPower = apply ? int32(proto->GetDPS(itemLevel) * 6.0f) : 0;
8183 switch (attType)
8184 {
8185 case BASE_ATTACK:
8186 SetMainHandWeaponAttackPower(weaponBasedAttackPower);
8187 break;
8188 case OFF_ATTACK:
8189 SetOffHandWeaponAttackPower(weaponBasedAttackPower);
8190 break;
8191 case RANGED_ATTACK:
8192 SetRangedWeaponAttackPower(weaponBasedAttackPower);
8193 break;
8194 default:
8195 break;
8196 }
8197
8198 if (CanModifyStats() && (damage || proto->GetDelay()))
8199 UpdateDamagePhysical(attType);
8200}
8201
8203{
8204 if (Item const* weapon = GetWeaponForAttack(attackType, true))
8205 return SpellSchoolMask(1 << weapon->GetTemplate()->GetDamageType());
8206
8208}
8209
8211{
8213 for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < inventoryEnd; ++slot)
8214 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
8215 ApplyItemObtainSpells(item, true);
8216
8218 {
8219 Bag* bag = GetBagByPos(i);
8220 if (!bag)
8221 continue;
8222
8223 for (uint32 slot = 0; slot < bag->GetBagSize(); ++slot)
8224 if (Item* item = bag->GetItemByPos(slot))
8225 ApplyItemObtainSpells(item, true);
8226 }
8227}
8228
8230{
8231 if (item->GetTemplate()->HasFlag(ITEM_FLAG_LEGACY))
8232 return;
8233
8234 for (ItemEffectEntry const* effect : item->GetEffects())
8235 {
8236 if (effect->TriggerType != ITEM_SPELLTRIGGER_ON_PICKUP) // On obtain trigger
8237 continue;
8238
8239 int32 const spellId = effect->SpellID;
8240 if (spellId <= 0)
8241 continue;
8242
8243 if (apply)
8244 {
8245 if (!HasAura(spellId))
8246 CastSpell(this, spellId, CastSpellExtraArgs().SetCastItem(item));
8247 }
8248 else
8249 RemoveAurasDueToSpell(spellId);
8250 }
8251}
8252
8253// this one rechecks weapon auras and stores them in BaseModGroup container
8254// needed for things like axe specialization applying only to axe weapons in case of dual-wield
8256{
8257 BaseModGroup modGroup;
8258 switch (attackType)
8259 {
8260 case BASE_ATTACK:
8261 modGroup = CRIT_PERCENTAGE;
8262 break;
8263 case OFF_ATTACK:
8264 modGroup = OFFHAND_CRIT_PERCENTAGE;
8265 break;
8266 case RANGED_ATTACK:
8267 modGroup = RANGED_CRIT_PERCENTAGE;
8268 break;
8269 default:
8270 ABORT();
8271 break;
8272 }
8273
8274 float amount = 0.0f;
8275 amount += GetTotalAuraModifier(SPELL_AURA_MOD_WEAPON_CRIT_PERCENT, [this, attackType](AuraEffect const* aurEff)
8276 {
8277 return CheckAttackFitToAuraRequirement(attackType, aurEff);
8278 });
8279
8280 // these auras don't have item requirement (only Combat Expertise in 3.3.5a)
8282
8283 SetBaseModFlatValue(modGroup, amount);
8284}
8285
8287{
8288 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
8290}
8291
8293{
8295 UpdateDamageDoneMods(attackType);
8296 UpdateDamagePctDoneMods(attackType);
8297}
8298
8300{
8301 if (apply)
8302 {
8303 PlayerSpellMap const& spells = GetSpellMap();
8304 for (auto itr = spells.begin(); itr != spells.end(); ++itr)
8305 {
8306 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.disabled)
8307 continue;
8308
8309 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(itr->first, DIFFICULTY_NONE);
8310 if (!spellInfo || !spellInfo->IsPassive() || spellInfo->EquippedItemClass < 0)
8311 continue;
8312
8313 if (!HasAura(itr->first) && HasItemFitToSpellRequirements(spellInfo))
8314 AddAura(itr->first, this); // no SMSG_SPELL_GO in sniff found
8315 }
8316 }
8317 else
8319}
8320
8322{
8323 SpellInfo const* spellInfo = aurEff->GetSpellInfo();
8324 if (spellInfo->EquippedItemClass == -1)
8325 return true;
8326
8327 Item* item = GetWeaponForAttack(attackType, true);
8328 if (!item || !item->IsFitToSpellRequirements(spellInfo))
8329 return false;
8330
8331 return true;
8332}
8333
8334void Player::ApplyItemEquipSpell(Item* item, bool apply, bool formChange /*= false*/)
8335{
8336 if (!item || item->GetTemplate()->HasFlag(ITEM_FLAG_LEGACY))
8337 return;
8338
8339 for (ItemEffectEntry const* effectData : item->GetEffects())
8340 {
8341 // wrong triggering type
8342 if (apply && effectData->TriggerType != ITEM_SPELLTRIGGER_ON_EQUIP)
8343 continue;
8344
8345 // check if it is valid spell
8346 SpellInfo const* spellproto = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE);
8347 if (!spellproto)
8348 continue;
8349
8350 if (effectData->ChrSpecializationID && ChrSpecialization(effectData->ChrSpecializationID) != GetPrimarySpecialization())
8351 continue;
8352
8353 ApplyEquipSpell(spellproto, item, apply, formChange);
8354 }
8355}
8356
8357void Player::ApplyEquipSpell(SpellInfo const* spellInfo, Item* item, bool apply, bool formChange /*= false*/)
8358{
8359 if (apply)
8360 {
8361 // Cannot be used in this stance/form
8362 if (spellInfo->CheckShapeshift(GetShapeshiftForm()) != SPELL_CAST_OK)
8363 return;
8364
8365 if (formChange) // check aura active state from other form
8366 {
8367 AuraApplicationMapBounds range = GetAppliedAuras().equal_range(spellInfo->Id);
8368 for (AuraApplicationMap::const_iterator itr = range.first; itr != range.second; ++itr)
8369 if (!item || itr->second->GetBase()->GetCastItemGUID() == item->GetGUID())
8370 return;
8371 }
8372
8373 TC_LOG_DEBUG("entities.player", "Player::ApplyEquipSpell: Player '{}' ({}) cast {} equip spell (ID: {})",
8374 GetName(), GetGUID().ToString(), (item ? "item" : "itemset"), spellInfo->Id);
8375
8376 CastSpell(this, spellInfo->Id, item);
8377 }
8378 else
8379 {
8380 if (formChange) // check aura compatibility
8381 {
8382 // Cannot be used in this stance/form
8383 if (spellInfo->CheckShapeshift(GetShapeshiftForm()) == SPELL_CAST_OK)
8384 return; // and remove only not compatible at form change
8385 }
8386
8387 if (item)
8388 RemoveAurasDueToItemSpell(spellInfo->Id, item->GetGUID()); // un-apply all spells, not only at-equipped
8389 else
8390 RemoveAurasDueToSpell(spellInfo->Id); // un-apply spell (item set case)
8391 }
8392}
8393
8395{
8396 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
8397 {
8398 if (m_items[i] && !m_items[i]->IsBroken() && CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
8399 {
8400 ApplyItemEquipSpell(m_items[i], false, true); // remove spells that not fit to form
8401 ApplyItemEquipSpell(m_items[i], true, true); // add spells that fit form but not active
8402 }
8403 }
8404
8405 UpdateItemSetAuras(true);
8406}
8407
8408void Player::UpdateItemSetAuras(bool formChange /*= false*/)
8409{
8410 // item set bonuses not dependent from item broken state
8411 for (size_t setindex = 0; setindex < ItemSetEff.size(); ++setindex)
8412 {
8413 ItemSetEffect* eff = ItemSetEff[setindex];
8414 if (!eff)
8415 continue;
8416
8417 for (ItemSetSpellEntry const* itemSetSpell : eff->SetBonuses)
8418 {
8419 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(itemSetSpell->SpellID, DIFFICULTY_NONE);
8420
8421 if (itemSetSpell->ChrSpecID && ChrSpecialization(itemSetSpell->ChrSpecID) != GetPrimarySpecialization())
8422 ApplyEquipSpell(spellInfo, nullptr, false, false); // item set aura is not for current spec
8423 else
8424 {
8425 ApplyEquipSpell(spellInfo, nullptr, false, formChange); // remove spells that not fit to form - removal is skipped if shapeshift condition is satisfied
8426 ApplyEquipSpell(spellInfo, nullptr, true, formChange); // add spells that fit form but not active
8427 }
8428 }
8429 }
8430}
8431
8433{
8434 if (item->IsArtifactDisabled())
8435 return;
8436
8437 for (UF::ArtifactPower const& artifactPower : item->m_itemData->ArtifactPowers)
8438 {
8439 uint8 rank = artifactPower.CurrentRankWithBonus;
8440 if (!rank)
8441 continue;
8442
8444 rank = 1;
8445
8446 ArtifactPowerRankEntry const* artifactPowerRank = sDB2Manager.GetArtifactPowerRank(artifactPower.ArtifactPowerID, rank - 1);
8447 if (!artifactPowerRank)
8448 continue;
8449
8450 ApplyArtifactPowerRank(item, artifactPowerRank, apply);
8451 }
8452
8454 if (artifactAppearance->OverrideShapeshiftDisplayID && GetShapeshiftForm() == ShapeshiftForm(artifactAppearance->OverrideShapeshiftFormID))
8456}
8457
8458void Player::ApplyArtifactPowerRank(Item* artifact, ArtifactPowerRankEntry const* artifactPowerRank, bool apply)
8459{
8460 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(artifactPowerRank->SpellID, DIFFICULTY_NONE);
8461 if (!spellInfo)
8462 return;
8463
8464 if (spellInfo->IsPassive())
8465 {
8466 AuraApplication* powerAura = GetAuraApplication(artifactPowerRank->SpellID, ObjectGuid::Empty, artifact->GetGUID());
8467 if (powerAura)
8468 {
8469 if (apply)
8470 {
8471 for (AuraEffect* auraEffect : powerAura->GetBase()->GetAuraEffects())
8472 {
8473 if (!auraEffect)
8474 continue;
8475
8476 if (powerAura->HasEffect(auraEffect->GetEffIndex()))
8477 auraEffect->ChangeAmount(artifactPowerRank->AuraPointsOverride ? artifactPowerRank->AuraPointsOverride : auraEffect->GetSpellEffectInfo().CalcValue());
8478 }
8479 }
8480 else
8481 RemoveAura(powerAura);
8482 }
8483 else if (apply)
8484 {
8485 CastSpellExtraArgs args;
8487 args.SetCastItem(artifact);
8488 if (artifactPowerRank->AuraPointsOverride)
8489 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
8490 args.AddSpellMod(SpellValueMod(SPELLVALUE_BASE_POINT0 + AsUnderlyingType(spellEffectInfo.EffectIndex)), artifactPowerRank->AuraPointsOverride);
8491
8492 CastSpell(this, artifactPowerRank->SpellID, args);
8493 }
8494 }
8495 else
8496 {
8497 if (apply && !HasSpell(artifactPowerRank->SpellID))
8498 {
8499 AddTemporarySpell(artifactPowerRank->SpellID);
8501 WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = learnedSpells.ClientLearnedSpellData.emplace_back();
8502 learnedSpellInfo.SpellID = artifactPowerRank->SpellID;
8503 learnedSpells.SuppressMessaging = true;
8504 SendDirectMessage(learnedSpells.Write());
8505 }
8506 else if (!apply)
8507 {
8508 RemoveTemporarySpell(artifactPowerRank->SpellID);
8510 unlearnedSpells.SuppressMessaging = true;
8511 unlearnedSpells.SpellID.push_back(artifactPowerRank->SpellID);
8512 SendDirectMessage(unlearnedSpells.Write());
8513 }
8514 }
8515
8516}
8517
8519{
8520 if (AzeriteItem* azeriteItem = item->ToAzeriteItem())
8521 {
8522 // milestone powers
8523 for (uint32 azeriteItemMilestonePowerId : azeriteItem->m_azeriteItemData->UnlockedEssenceMilestones)
8524 ApplyAzeriteItemMilestonePower(azeriteItem, sAzeriteItemMilestonePowerStore.AssertEntry(azeriteItemMilestonePowerId), apply);
8525
8526 // essences
8527 if (UF::SelectedAzeriteEssences const* selectedEssences = azeriteItem->GetSelectedAzeriteEssences())
8528 for (uint8 slot = 0; slot < MAX_AZERITE_ESSENCE_SLOT; ++slot)
8529 if (selectedEssences->AzeriteEssenceID[slot])
8530 ApplyAzeriteEssence(azeriteItem, selectedEssences->AzeriteEssenceID[slot], azeriteItem->GetEssenceRank(selectedEssences->AzeriteEssenceID[slot]),
8531 AzeriteItemMilestoneType(sDB2Manager.GetAzeriteItemMilestonePower(slot)->Type) == AzeriteItemMilestoneType::MajorEssence, apply);
8532 }
8533 else if (AzeriteEmpoweredItem* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem())
8534 {
8536 for (int32 i = 0; i < MAX_AZERITE_EMPOWERED_TIER; ++i)
8537 if (AzeritePowerEntry const* azeritePower = sAzeritePowerStore.LookupEntry(azeriteEmpoweredItem->GetSelectedAzeritePower(i)))
8538 ApplyAzeritePower(azeriteEmpoweredItem, azeritePower, apply);
8539 }
8540}
8541
8543{
8544 AzeriteItemMilestoneType type = AzeriteItemMilestoneType(azeriteItemMilestonePower->Type);
8546 {
8547 if (AzeritePowerEntry const* azeritePower = sAzeritePowerStore.LookupEntry(azeriteItemMilestonePower->AzeritePowerID))
8548 {
8549 if (apply)
8550 CastSpell(this, azeritePower->SpellID, item);
8551 else
8552 RemoveAurasDueToItemSpell(azeritePower->SpellID, item->GetGUID());
8553 }
8554 }
8555}
8556
8557void Player::ApplyAzeriteEssence(AzeriteItem* item, uint32 azeriteEssenceId, uint32 rank, bool major, bool apply)
8558{
8559 for (uint32 currentRank = 1; currentRank <= rank; ++currentRank)
8560 {
8561 if (AzeriteEssencePowerEntry const* azeriteEssencePower = sDB2Manager.GetAzeriteEssencePower(azeriteEssenceId, currentRank))
8562 {
8563 ApplyAzeriteEssencePower(item, azeriteEssencePower, major, apply);
8564 if (major && currentRank == 1)
8565 {
8566 if (apply)
8567 {
8569 args.AddSpellMod(SPELLVALUE_BASE_POINT0, azeriteEssencePower->MajorPowerDescription);
8571 }
8572 else
8574 }
8575 }
8576 }
8577}
8578
8579void Player::ApplyAzeriteEssencePower(AzeriteItem* item, AzeriteEssencePowerEntry const* azeriteEssencePower, bool major, bool apply)
8580{
8581 if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MinorPowerDescription, DIFFICULTY_NONE))
8582 {
8583 if (apply)
8584 CastSpell(this, powerSpell->Id, item);
8585 else
8586 RemoveAurasDueToItemSpell(powerSpell->Id, item->GetGUID());
8587 }
8588
8589 if (major)
8590 {
8591 if (SpellInfo const* powerSpell = sSpellMgr->GetSpellInfo(azeriteEssencePower->MajorPowerDescription, DIFFICULTY_NONE))
8592 {
8593 if (powerSpell->IsPassive())
8594 {
8595 if (apply)
8596 CastSpell(this, powerSpell->Id, item);
8597 else
8598 RemoveAurasDueToItemSpell(powerSpell->Id, item->GetGUID());
8599 }
8600 else
8601 {
8602 if (apply)
8603 LearnSpell(powerSpell->Id, true, 0, true);
8604 else
8605 RemoveSpell(powerSpell->Id, false, false, true);
8606 }
8607 }
8608 }
8609}
8610
8612{
8613 if (apply)
8614 {
8615 if (!azeritePower->SpecSetID || sDB2Manager.IsSpecSetMember(azeritePower->SpecSetID, AsUnderlyingType(GetPrimarySpecialization())))
8616 CastSpell(this, azeritePower->SpellID, item);
8617 }
8618 else
8619 RemoveAurasDueToItemSpell(azeritePower->SpellID, item->GetGUID());
8620}
8621
8623{
8624 Unit* target = damageInfo.GetVictim();
8625 if (!target || !target->IsAlive() || target == this)
8626 return;
8627
8629 {
8630 // If usable, try to cast item spell
8631 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
8632 {
8633 if (!item->IsBroken() && CanUseAttackType(damageInfo.GetAttackType()))
8634 {
8635 if (ItemTemplate const* proto = item->GetTemplate())
8636 {
8637 // Additional check for weapons
8638 if (proto->GetClass() == ITEM_CLASS_WEAPON)
8639 {
8640 // offhand item cannot proc from main hand hit etc
8641 EquipmentSlots slot;
8642 switch (damageInfo.GetAttackType())
8643 {
8644 case BASE_ATTACK:
8646 break;
8647 case OFF_ATTACK:
8649 break;
8650 case RANGED_ATTACK:
8652 break;
8653 default:
8654 slot = EQUIPMENT_SLOT_END;
8655 break;
8656 }
8657 if (slot != i)
8658 continue;
8659 // Check if item is useable (forms or disarm)
8660 if (damageInfo.GetAttackType() == BASE_ATTACK)
8661 if (!IsUseEquipedWeapon(true) && !IsInFeralForm())
8662 continue;
8663 }
8664
8665 CastItemCombatSpell(damageInfo, item, proto);
8666 }
8667 }
8668 }
8669 }
8670}
8671
8672void Player::CastItemCombatSpell(DamageInfo const& damageInfo, Item* item, ItemTemplate const* proto)
8673{
8674 // Can do effect if any damage done to target
8675 // for done procs allow normal + critical + absorbs by default
8676 bool canTrigger = (damageInfo.GetHitMask() & (PROC_HIT_NORMAL | PROC_HIT_CRITICAL | PROC_HIT_ABSORB)) != 0;
8677 if (canTrigger)
8678 {
8679 if (!item->GetTemplate()->HasFlag(ITEM_FLAG_LEGACY))
8680 {
8681 for (ItemEffectEntry const* effectData : item->GetEffects())
8682 {
8683 // wrong triggering type
8684 if (effectData->TriggerType != ITEM_SPELLTRIGGER_ON_PROC)
8685 continue;
8686
8687 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE);
8688 if (!spellInfo)
8689 {
8690 TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell: Player '{}' ({}) cast unknown item spell (ID: {})",
8691 GetName(), GetGUID().ToString(), effectData->SpellID);
8692 continue;
8693 }
8694
8695 float chance = (float)spellInfo->ProcChance;
8696
8697 if (proto->SpellPPMRate)
8698 {
8699 uint32 WeaponSpeed = GetBaseAttackTime(damageInfo.GetAttackType());
8700 chance = GetPPMProcChance(WeaponSpeed, proto->SpellPPMRate, spellInfo);
8701 }
8702 else if (chance > 100.0f)
8703 chance = GetWeaponProcChance();
8704
8705 if (roll_chance_f(chance) && sScriptMgr->OnCastItemCombatSpell(this, damageInfo.GetVictim(), spellInfo, item))
8706 CastSpell(damageInfo.GetVictim(), spellInfo->Id, item);
8707 }
8708 }
8709 }
8710
8711 // item combat enchantments
8712 for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot)
8713 {
8714 uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot));
8715 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
8716 if (!pEnchant)
8717 continue;
8718
8719 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
8720 {
8721 if (pEnchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL)
8722 continue;
8723
8724 SpellEnchantProcEntry const* entry = sSpellMgr->GetSpellEnchantProcEvent(enchant_id);
8725 if (entry && entry->HitMask)
8726 {
8727 // Check hit/crit/dodge/parry requirement
8728 if ((entry->HitMask & damageInfo.GetHitMask()) == 0)
8729 continue;
8730 }
8731 else
8732 {
8733 // Can do effect if any damage done to target
8734 // for done procs allow normal + critical + absorbs by default
8735 if (!canTrigger)
8736 continue;
8737 }
8738
8739 // check if enchant procs only on white hits
8740 if (entry && (entry->AttributesMask & ENCHANT_PROC_ATTR_WHITE_HIT) && damageInfo.GetSpellInfo())
8741 continue;
8742
8743 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->EffectArg[s], DIFFICULTY_NONE);
8744 if (!spellInfo)
8745 {
8746 TC_LOG_ERROR("entities.player.items", "Player::CastItemCombatSpell: Player '{}' ({}) cast unknown spell (EnchantID: {}, SpellID: {}), ignoring",
8747 GetName(), GetGUID().ToString(), pEnchant->ID, pEnchant->EffectArg[s]);
8748 continue;
8749 }
8750
8751 float chance = pEnchant->EffectPointsMin[s] != 0 ? float(pEnchant->EffectPointsMin[s]) : GetWeaponProcChance();
8752
8753 if (entry)
8754 {
8755 if (entry->ProcsPerMinute)
8756 chance = GetPPMProcChance(proto->GetDelay(), entry->ProcsPerMinute, spellInfo);
8757 else if (entry->Chance)
8758 chance = (float)entry->Chance;
8759 }
8760
8761 // Apply spell mods
8762 ApplySpellMod(spellInfo, SpellModOp::ProcChance, chance);
8763
8764 // Shiv has 100% chance to apply the poison
8765 if (FindCurrentSpellBySpellId(5938) && e_slot == TEMP_ENCHANTMENT_SLOT)
8766 chance = 100.0f;
8767
8768 if (roll_chance_f(chance))
8769 {
8770 if (spellInfo->IsPositive())
8771 CastSpell(this, spellInfo->Id, item);
8772 else
8773 CastSpell(damageInfo.GetVictim(), spellInfo->Id, item);
8774 }
8775
8776 if (roll_chance_f(chance))
8777 {
8778 Unit* target = spellInfo->IsPositive() ? this : damageInfo.GetVictim();
8779
8780 CastSpellExtraArgs args(item);
8781 // reduce effect values if enchant is limited
8782 if (entry && (entry->AttributesMask & ENCHANT_PROC_ATTR_LIMIT_60) && target->GetLevelForTarget(this) > 60)
8783 {
8784 int32 const lvlDifference = target->GetLevelForTarget(this) - 60;
8785 int32 const lvlPenaltyFactor = 4; // 4% lost effectiveness per level
8786
8787 int32 const effectPct = std::max(0, 100 - (lvlDifference * lvlPenaltyFactor));
8788
8789 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
8790 if (spellEffectInfo.IsEffect())
8791 args.AddSpellMod(static_cast<SpellValueMod>(SPELLVALUE_BASE_POINT0 + AsUnderlyingType(spellEffectInfo.EffectIndex)), CalculatePct(spellEffectInfo.CalcValue(this), effectPct));
8792 }
8793 CastSpell(target, spellInfo->Id, args);
8794 }
8795 }
8796 }
8797}
8798
8799void Player::CastItemUseSpell(Item* item, SpellCastTargets const& targets, ObjectGuid castCount, int32* misc)
8800{
8801 if (!item->GetTemplate()->HasFlag(ITEM_FLAG_LEGACY))
8802 {
8803 // item spells cast at use
8804 for (ItemEffectEntry const* effectData : item->GetEffects())
8805 {
8806 // wrong triggering type
8807 if (effectData->TriggerType != ITEM_SPELLTRIGGER_ON_USE)
8808 continue;
8809
8810 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE);
8811 if (!spellInfo)
8812 {
8813 TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Item (Entry: {}) has wrong spell id {}, ignoring", item->GetEntry(), effectData->SpellID);
8814 continue;
8815 }
8816
8817 Spell* spell = new Spell(this, spellInfo, TRIGGERED_NONE);
8818
8820 spellPrepare.ClientCastID = castCount;
8821 spellPrepare.ServerCastID = spell->m_castId;
8822 SendDirectMessage(spellPrepare.Write());
8823
8824 spell->m_fromClient = true;
8825 spell->m_CastItem = item;
8826 spell->m_misc.Raw.Data[0] = misc[0];
8827 spell->m_misc.Raw.Data[1] = misc[1];
8828 spell->prepare(targets);
8829 return;
8830 }
8831 }
8832
8833 // Item enchantments spells cast at use
8834 for (uint8 e_slot = 0; e_slot < MAX_ENCHANTMENT_SLOT; ++e_slot)
8835 {
8836 uint32 enchant_id = item->GetEnchantmentId(EnchantmentSlot(e_slot));
8837 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
8838 if (!pEnchant)
8839 continue;
8840 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
8841 {
8842 if (pEnchant->Effect[s] != ITEM_ENCHANTMENT_TYPE_USE_SPELL)
8843 continue;
8844
8845 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pEnchant->EffectArg[s], DIFFICULTY_NONE);
8846 if (!spellInfo)
8847 {
8848 TC_LOG_ERROR("entities.player", "Player::CastItemUseSpell: Enchant {}, cast unknown spell {}", pEnchant->ID, pEnchant->EffectArg[s]);
8849 continue;
8850 }
8851
8852 Spell* spell = new Spell(this, spellInfo, TRIGGERED_NONE);
8853
8855 spellPrepare.ClientCastID = castCount;
8856 spellPrepare.ServerCastID = spell->m_castId;
8857 SendDirectMessage(spellPrepare.Write());
8858
8859 spell->m_fromClient = true;
8860 spell->m_CastItem = item;
8861 spell->m_misc.Raw.Data[0] = misc[0];
8862 spell->m_misc.Raw.Data[1] = misc[1];
8863 spell->prepare(targets);
8864 return;
8865 }
8866 }
8867}
8868
8870{
8871 if (item->GetTemplate()->HasFlag(ITEM_FLAG_LEGACY))
8872 return;
8873
8874 auto lootedEffectItr = std::find_if(item->GetEffects().begin(), item->GetEffects().end(), [](ItemEffectEntry const* effectData)
8875 {
8876 return effectData->TriggerType == ITEM_SPELLTRIGGER_ON_LOOTED;
8877 });
8878
8879 if (lootedEffectItr != item->GetEffects().end())
8880 {
8881 if (apply)
8882 CastSpell(this, (*lootedEffectItr)->SpellID, item);
8883 else
8884 RemoveAurasDueToItemSpell((*lootedEffectItr)->SpellID, item->GetGUID());
8885 }
8886}
8887
8889{
8890 if (itemTemplate->HasFlag(ITEM_FLAG_LEGACY))
8891 return;
8892
8893 for (ItemEffectEntry const* effect : itemTemplate->Effects)
8894 {
8896 continue;
8897
8898 CastSpell(this, effect->SpellID, true);
8899 }
8900}
8901
8903{
8904 TC_LOG_DEBUG("entities.player.items", "_RemoveAllItemMods start.");
8905
8906 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
8907 {
8908 if (m_items[i])
8909 {
8910 ItemTemplate const* proto = m_items[i]->GetTemplate();
8911 if (!proto)
8912 continue;
8913
8914 // item set bonuses not dependent from item broken state
8915 if (proto->GetItemSet())
8916 RemoveItemsSetItem(this, m_items[i]);
8917
8918 if (m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
8919 continue;
8920
8921 ApplyItemEquipSpell(m_items[i], false);
8922 ApplyEnchantment(m_items[i], false);
8923 ApplyArtifactPowers(m_items[i], false);
8924 }
8925 }
8926
8927 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
8928 {
8929 if (m_items[i])
8930 {
8931 if (m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
8932 continue;
8933
8935 _ApplyItemBonuses(m_items[i], i, false);
8936 }
8937 }
8938
8939 TC_LOG_DEBUG("entities.player.items", "_RemoveAllItemMods complete.");
8940}
8941
8943{
8944 TC_LOG_DEBUG("entities.player.items", "_ApplyAllItemMods start.");
8945
8946 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
8947 {
8948 if (m_items[i])
8949 {
8950 if (m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
8951 continue;
8952
8954 _ApplyItemBonuses(m_items[i], i, true);
8955
8956 WeaponAttackType const attackType = Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType());
8957 if (attackType != MAX_ATTACK)
8958 UpdateWeaponDependentAuras(attackType);
8959 }
8960 }
8961
8962 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
8963 {
8964 if (m_items[i])
8965 {
8966 ItemTemplate const* proto = m_items[i]->GetTemplate();
8967 if (!proto)
8968 continue;
8969
8970 // item set bonuses not dependent from item broken state
8971 if (proto->GetItemSet())
8972 AddItemsSetItem(this, m_items[i]);
8973
8974 if (m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
8975 continue;
8976
8977 ApplyItemEquipSpell(m_items[i], true);
8978 ApplyArtifactPowers(m_items[i], true);
8979 ApplyEnchantment(m_items[i], true);
8980 }
8981 }
8982
8983 TC_LOG_DEBUG("entities.player.items", "_ApplyAllItemMods complete.");
8984}
8985
8987{
8988 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
8989 {
8990 if (m_items[i])
8991 {
8992 if (!CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
8993 continue;
8994
8996
8997 // Update item sets for heirlooms
8998 if (sDB2Manager.GetHeirloomByItemId(m_items[i]->GetEntry()) && m_items[i]->GetTemplate()->GetItemSet())
8999 {
9000 if (apply)
9001 AddItemsSetItem(this, m_items[i]);
9002 else
9003 RemoveItemsSetItem(this, m_items[i]);
9004 }
9005 }
9006 }
9007}
9008
9010{
9011 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
9012 {
9013 if (m_items[i])
9014 {
9015 if (!m_items[i]->IsAzeriteItem() || m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
9016 continue;
9017
9019 }
9020 }
9021}
9022
9024{
9025 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
9026 {
9027 if (m_items[i])
9028 {
9029 if (!m_items[i]->IsAzeriteEmpoweredItem() || m_items[i]->IsBroken() || !CanUseAttackType(Player::GetAttackBySlot(i, m_items[i]->GetTemplate()->GetInventoryType())))
9030 continue;
9031
9033 }
9034 }
9035}
9036
9037Loot* Player::GetLootByWorldObjectGUID(ObjectGuid const& lootWorldObjectGuid) const
9038{
9039 auto itr = std::find_if(m_AELootView.begin(), m_AELootView.end(), [&lootWorldObjectGuid](std::pair<ObjectGuid const, Loot*> const& lootView)
9040 {
9041 return lootView.second->GetOwnerGUID() == lootWorldObjectGuid;
9042 });
9043 return itr != m_AELootView.end() ? itr->second : nullptr;
9044}
9045
9046LootRoll* Player::GetLootRoll(ObjectGuid const& lootObjectGuid, uint8 lootListId)
9047{
9048 auto itr = std::find_if(m_lootRolls.begin(), m_lootRolls.end(), [&](LootRoll const* roll)
9049 {
9050 return roll->IsLootItem(lootObjectGuid, lootListId);
9051 });
9052 return itr != m_lootRolls.end() ? *itr : nullptr;
9053}
9054
9056{
9057 m_lootRolls.erase(std::remove(m_lootRolls.begin(), m_lootRolls.end(), roll), m_lootRolls.end());
9058}
9059
9060/* If in a battleground a player dies, and an enemy removes the insignia, the player's bones is lootable
9061 Called by remove insignia spell effect */
9063{
9064 // If player is not in battleground and not in worldpvpzone
9066 return;
9067
9068 // If not released spirit, do it !
9069 if (m_deathTimer > 0)
9070 {
9071 m_deathTimer = 0;
9074 }
9075
9077
9078 // We have to convert player corpse to bones, not to be able to resurrect there
9079 // SpawnCorpseBones isn't handy, 'cos it saves player while he in BG
9080 Corpse* bones = GetMap()->ConvertCorpseToBones(GetGUID(), true);
9081 if (!bones)
9082 return;
9083
9084 // Now we must make bones lootable, and send player loot
9086
9087 bones->m_loot.reset(new Loot(GetMap(), bones->GetGUID(), LOOT_INSIGNIA, looterPlr->GetGroup()));
9088
9089 // For AV Achievement
9090 if (Battleground* bg = GetBattleground())
9091 {
9092 if (bg->GetTypeID() == BATTLEGROUND_AV)
9093 bones->m_loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true);
9094 }
9095 // For wintergrasp Quests
9096 else if (GetZoneId() == AREA_WINTERGRASP)
9097 bones->m_loot->FillLoot(PLAYER_CORPSE_LOOT_ENTRY, LootTemplates_Creature, this, true);
9098
9099 // It may need a better formula
9100 // Now it works like this: lvl10: ~6copper, lvl70: ~9silver
9101 bones->m_loot->gold = uint32(urand(50, 150) * 0.016f * std::pow(float(GetLevel()) / 5.76f, 2.5f) * sWorld->getRate(RATE_DROP_MONEY));
9102 bones->lootRecipient = looterPlr;
9103 looterPlr->SendLoot(*bones->m_loot);
9104}
9105
9107{
9109 packet.LootObj = guid;
9110 packet.Owner = GetGUID();
9111 SendDirectMessage(packet.Write());
9112}
9113
9115{
9117}
9118
9119void Player::SendLoot(Loot& loot, bool aeLooting)
9120{
9121 if (!GetLootGUID().IsEmpty() && !aeLooting)
9123
9124 TC_LOG_DEBUG("loot", "Player::SendLoot: Player: '{}' ({}), Loot: {}",
9125 GetName(), GetGUID().ToString(), loot.GetOwnerGUID().ToString());
9126
9127 if (!loot.GetOwnerGUID().IsItem() && !aeLooting)
9128 SetLootGUID(loot.GetOwnerGUID());
9129
9131 packet.Owner = loot.GetOwnerGUID();
9132 packet.LootObj = loot.GetGUID();
9133 packet._LootMethod = loot.GetLootMethod();
9135 packet.Acquired = true; // false == No Loot (this too^^)
9136 packet.AELooting = aeLooting;
9137 loot.BuildLootResponse(packet, this);
9138 SendDirectMessage(packet.Write());
9139
9140 // add 'this' player as one of the players that are looting 'loot'
9141 loot.OnLootOpened(GetMap(), GetGUID());
9142 m_AELootView[loot.GetGUID()] = &loot;
9143
9144 if (loot.loot_type == LOOT_CORPSE && !loot.GetOwnerGUID().IsItem())
9146}
9147
9148void Player::SendLootError(ObjectGuid const& lootObj, ObjectGuid const& owner, LootError error) const
9149{
9151 lootResponse.LootObj = lootObj;
9152 lootResponse.Owner = owner;
9153 lootResponse.Acquired = false;
9154 lootResponse.FailureReason = error;
9155 SendDirectMessage(lootResponse.Write());
9156}
9157
9159{
9161 packet.LootObj = lootObj;
9162 SendDirectMessage(packet.Write());
9163}
9164
9165void Player::SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, uint8 lootListId) const
9166{
9168 packet.LootObj = lootObj;
9169 packet.Owner = owner;
9170 packet.LootListID = lootListId;
9171 SendDirectMessage(packet.Write());
9172}
9173
9174void Player::SendUpdateWorldState(uint32 variable, uint32 value, bool hidden /*= false*/) const
9175{
9177 worldstate.VariableID = variable;
9178 worldstate.Value = value;
9179 worldstate.Hidden = hidden;
9180 SendDirectMessage(worldstate.Write());
9181}
9182
9183// TODO - InitWorldStates should NOT always send the same states
9184// Some should keep the same value between different zoneIds and areaIds on the same map
9186{
9187 uint32 mapId = GetMapId();
9188
9189 TC_LOG_DEBUG("network", "Player::SendInitWorldStates: Sending SMSG_INIT_WORLD_STATES for Map: {}, Zone: {}", mapId, zoneId);
9190
9192 packet.MapID = mapId;
9193 packet.AreaID = zoneId;
9194 packet.SubareaID = areaId;
9195
9196 sWorldStateMgr->FillInitialWorldStates(packet, GetMap(), areaId);
9197
9198 SendDirectMessage(packet.Write());
9199}
9200
9202{
9204 npcInteraction.Npc = guid;
9206 npcInteraction.Success = true;
9207 SendDirectMessage(npcInteraction.Write());
9208}
9209
9210void Player::SendRespecWipeConfirm(ObjectGuid const& guid, uint32 cost, SpecResetType respecType) const
9211{
9213 respecWipeConfirm.RespecMaster = guid;
9214 respecWipeConfirm.Cost = cost;
9215 respecWipeConfirm.RespecType = respecType;
9216 SendDirectMessage(respecWipeConfirm.Write());
9217}
9218
9219/*********************************************************/
9220/*** STORAGE SYSTEM ***/
9221/*********************************************************/
9222
9223uint8 Player::FindEquipSlot(Item const* item, uint32 slot, bool swap) const
9224{
9225 uint8 slots[4];
9226 slots[0] = NULL_SLOT;
9227 slots[1] = NULL_SLOT;
9228 slots[2] = NULL_SLOT;
9229 slots[3] = NULL_SLOT;
9230 switch (item->GetTemplate()->GetInventoryType())
9231 {
9232 case INVTYPE_HEAD:
9233 slots[0] = EQUIPMENT_SLOT_HEAD;
9234 break;
9235 case INVTYPE_NECK:
9236 slots[0] = EQUIPMENT_SLOT_NECK;
9237 break;
9238 case INVTYPE_SHOULDERS:
9239 slots[0] = EQUIPMENT_SLOT_SHOULDERS;
9240 break;
9241 case INVTYPE_BODY:
9242 slots[0] = EQUIPMENT_SLOT_BODY;
9243 break;
9244 case INVTYPE_CHEST:
9245 slots[0] = EQUIPMENT_SLOT_CHEST;
9246 break;
9247 case INVTYPE_ROBE:
9248 slots[0] = EQUIPMENT_SLOT_CHEST;
9249 break;
9250 case INVTYPE_WAIST:
9251 slots[0] = EQUIPMENT_SLOT_WAIST;
9252 break;
9253 case INVTYPE_LEGS:
9254 slots[0] = EQUIPMENT_SLOT_LEGS;
9255 break;
9256 case INVTYPE_FEET:
9257 slots[0] = EQUIPMENT_SLOT_FEET;
9258 break;
9259 case INVTYPE_WRISTS:
9260 slots[0] = EQUIPMENT_SLOT_WRISTS;
9261 break;
9262 case INVTYPE_HANDS:
9263 slots[0] = EQUIPMENT_SLOT_HANDS;
9264 break;
9265 case INVTYPE_FINGER:
9266 slots[0] = EQUIPMENT_SLOT_FINGER1;
9267 slots[1] = EQUIPMENT_SLOT_FINGER2;
9268 break;
9269 case INVTYPE_TRINKET:
9270 slots[0] = EQUIPMENT_SLOT_TRINKET1;
9271 slots[1] = EQUIPMENT_SLOT_TRINKET2;
9272 break;
9273 case INVTYPE_CLOAK:
9274 slots[0] = EQUIPMENT_SLOT_BACK;
9275 break;
9276 case INVTYPE_WEAPON:
9277 {
9278 slots[0] = EQUIPMENT_SLOT_MAINHAND;
9279
9280 // suggest offhand slot only if know dual wielding
9281 // (this will be replace mainhand weapon at auto equip instead unwonted "you don't known dual wielding" ...
9282 if (CanDualWield())
9283 slots[1] = EQUIPMENT_SLOT_OFFHAND;
9284 break;
9285 }
9286 case INVTYPE_SHIELD:
9287 slots[0] = EQUIPMENT_SLOT_OFFHAND;
9288 break;
9289 case INVTYPE_RANGED:
9290 slots[0] = EQUIPMENT_SLOT_MAINHAND;
9291 break;
9292 case INVTYPE_2HWEAPON:
9293 slots[0] = EQUIPMENT_SLOT_MAINHAND;
9294 if (CanDualWield() && CanTitanGrip())
9295 slots[1] = EQUIPMENT_SLOT_OFFHAND;
9296 break;
9297 case INVTYPE_TABARD:
9298 slots[0] = EQUIPMENT_SLOT_TABARD;
9299 break;
9301 slots[0] = EQUIPMENT_SLOT_MAINHAND;
9302 break;
9304 slots[0] = EQUIPMENT_SLOT_OFFHAND;
9305 break;
9306 case INVTYPE_HOLDABLE:
9307 slots[0] = EQUIPMENT_SLOT_OFFHAND;
9308 break;
9310 slots[0] = EQUIPMENT_SLOT_MAINHAND;
9311 break;
9312 case INVTYPE_BAG:
9313 slots[0] = INVENTORY_SLOT_BAG_START + 0;
9314 slots[1] = INVENTORY_SLOT_BAG_START + 1;
9315 slots[2] = INVENTORY_SLOT_BAG_START + 2;
9316 slots[3] = INVENTORY_SLOT_BAG_START + 3;
9317 break;
9320 {
9321 bool isProfessionTool = item->GetTemplate()->GetInventoryType() == INVTYPE_PROFESSION_TOOL;
9322
9323 // Validate item class
9324 if (!(item->GetTemplate()->GetClass() == ITEM_CLASS_PROFESSION))
9325 return NULL_SLOT;
9326
9327 // Check if player has profession skill
9328 uint32 itemSkill = item->GetTemplate()->GetSkill();
9329 if (!HasSkill(itemSkill))
9330 return NULL_SLOT;
9331
9332 switch (item->GetTemplate()->GetSubClass())
9333 {
9335 slots[0] = isProfessionTool ? PROFESSION_SLOT_COOKING_TOOL : PROFESSION_SLOT_COOKING_GEAR1;
9336 break;
9338 {
9339 // Fishing doesn't make use of gear slots (clientside)
9340 if (!isProfessionTool)
9341 return NULL_SLOT;
9342
9344 break;
9345 }
9357 {
9358 int32 professionSlot = GetProfessionSlotFor(itemSkill);
9359 if (professionSlot == -1)
9360 return NULL_SLOT;
9361
9362 if (isProfessionTool)
9363 slots[0] = PROFESSION_SLOT_PROFESSION1_TOOL + professionSlot * PROFESSION_SLOT_MAX_COUNT;
9364 else
9365 {
9368 }
9369
9370 break;
9371 }
9372 default:
9373 return NULL_SLOT;
9374 }
9375 break;
9376 }
9377 default:
9378 return NULL_SLOT;
9379 }
9380
9381 if (slot != NULL_SLOT)
9382 {
9383 if (swap || !GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
9384 for (uint8 i = 0; i < 4; ++i)
9385 if (slots[i] == slot)
9386 return slot;
9387 }
9388 else
9389 {
9390 // search free slot at first
9391 for (uint8 i = 0; i < 4; ++i)
9392 if (slots[i] != NULL_SLOT && !GetItemByPos(INVENTORY_SLOT_BAG_0, slots[i]))
9393 // in case 2hand equipped weapon (without titan grip) offhand slot empty but not free
9394 if (slots[i] != EQUIPMENT_SLOT_OFFHAND || !IsTwoHandUsed())
9395 return slots[i];
9396
9397 // if not found free and can swap return slot with lower item level equipped
9398 if (swap)
9399 {
9400 uint32 minItemLevel = std::numeric_limits<uint32>::max();
9401 uint8 minItemLevelIndex = 0;
9402 for (uint8 i = 0; i < 4; ++i)
9403 {
9404 if (slots[i] != NULL_SLOT)
9405 {
9406 if (Item const* equipped = GetItemByPos(INVENTORY_SLOT_BAG_0, slots[i]))
9407 {
9408 uint32 itemLevel = equipped->GetItemLevel(this);
9409 if (itemLevel < minItemLevel)
9410 {
9411 minItemLevel = itemLevel;
9412 minItemLevelIndex = i;
9413 }
9414 }
9415 }
9416 }
9417
9418 return slots[minItemLevelIndex];
9419 }
9420 }
9421
9422 // no free position
9423 return NULL_SLOT;
9424}
9425
9426uint32 Player::GetFreeInventorySlotCount(EnumFlag<ItemSearchLocation> location /*= ItemSearchLocation::Inventory*/) const
9427{
9428 uint32 freeSlotCount = 0;
9429
9431 {
9434 ++freeSlotCount;
9435
9438 ++freeSlotCount;
9439 }
9440
9442 {
9444 for (uint8 i = INVENTORY_SLOT_BAG_START; i < inventoryEnd; ++i)
9446 ++freeSlotCount;
9447
9449 if (Bag* bag = GetBagByPos(i))
9450 for (uint32 j = 0; j < GetBagSize(bag); ++j)
9451 if (!GetItemInBag(bag, j))
9452 ++freeSlotCount;
9453 }
9454
9455 if (location.HasFlag(ItemSearchLocation::Bank))
9456 {
9457 for (uint8 i = BANK_SLOT_ITEM_START; i < BANK_SLOT_BAG_END; ++i)
9459 ++freeSlotCount;
9460
9461 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; ++i)
9462 if (Bag* bag = GetBagByPos(i))
9463 for (uint32 j = 0; j < GetBagSize(bag); ++j)
9464 if (!GetItemInBag(bag, j))
9465 ++freeSlotCount;
9466 }
9467
9469 {
9471 if (Bag* bag = GetBagByPos(i))
9472 for (uint32 j = 0; j < GetBagSize(bag); ++j)
9473 if (!GetItemInBag(bag, j))
9474 ++freeSlotCount;
9475
9476 for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
9478 ++freeSlotCount;
9479 }
9480
9481 return freeSlotCount;
9482}
9483
9485{
9487 uint32 tempcount = 0;
9488 bool result = ForEachItem(ItemSearchLocation::Equipment, [this, item, &res, &tempcount, count](Item* pItem)
9489 {
9490 if (pItem->GetEntry() == item)
9491 {
9492 InventoryResult ires = CanUnequipItem(pItem->GetPos(), false);
9493 if (ires == EQUIP_ERR_OK)
9494 {
9495 tempcount += pItem->GetCount();
9496 if (tempcount >= count)
9497 return ItemSearchCallbackResult::Stop;
9498 }
9499 else
9500 res = ires;
9501 }
9503 });
9504
9505 if (!result) // we stopped early due to a sucess
9506 return EQUIP_ERR_OK;
9507
9508 return res; // return latest error if any
9509}
9510
9511uint32 Player::GetItemCount(uint32 item, bool inBankAlso, Item* skipItem) const
9512{
9513 bool countGems = skipItem && skipItem->GetTemplate()->GetGemProperties();
9514
9516 if (inBankAlso)
9517 location |= ItemSearchLocation::Bank;
9518
9519 uint32 count = 0;
9520 ForEachItem(location, [&count, item, skipItem, countGems](Item* pItem)
9521 {
9522 if (pItem != skipItem)
9523 {
9524 if (pItem->GetEntry() == item)
9525 count += pItem->GetCount();
9526
9527 if (countGems)
9528 count += pItem->GetGemCountWithID(item);
9529 }
9530
9532 });
9533
9534 return count;
9535}
9536
9538{
9539 uint32 count = 0;
9540 ForEachItem(ItemSearchLocation::Everywhere, [&count, limitCategory, skipItem](Item* item)
9541 {
9542 if (item != skipItem)
9543 if (ItemTemplate const* pProto = item->GetTemplate())
9544 if (pProto->GetItemLimitCategory() == limitCategory)
9545 count += item->GetCount();
9546
9548 });
9549 return count;
9550}
9551
9553{
9554 std::vector<Item*> itemList = std::vector<Item*>();
9556 {
9557 if (item->GetTemplate()->IsCraftingReagent())
9558 itemList.push_back(item);
9559
9561 });
9562
9563 return itemList;
9564}
9565
9567{
9568 Item* result = nullptr;
9569 ForEachItem(ItemSearchLocation::Everywhere, [&result, guid](Item* item)
9570 {
9571 if (item->GetGUID() == guid)
9572 {
9573 result = item;
9574 return ItemSearchCallbackResult::Stop;
9575 }
9576
9578 });
9579 return result;
9580}
9581
9583{
9584 uint8 bag = pos >> 8;
9585 uint8 slot = pos & 255;
9586 return GetItemByPos(bag, slot);
9587}
9588
9590{
9591 if (bag == INVENTORY_SLOT_BAG_0 && slot < PLAYER_SLOT_END && (slot < BUYBACK_SLOT_START || slot >= BUYBACK_SLOT_END))
9592 return m_items[slot];
9593 if (Bag* pBag = GetBagByPos(bag))
9594 return pBag->GetItemByPos(slot);
9595 return nullptr;
9596}
9597
9598//Does additional check for disarmed weapons
9600{
9601 Item* item = GetItemByPos(bag, slot);
9602 if (!item)
9603 return nullptr;
9604
9606 return nullptr;
9607
9608 return item;
9609}
9610
9612{
9614 || (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)
9615 || (bag >= REAGENT_BAG_SLOT_START && bag < REAGENT_BAG_SLOT_END))
9616 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, bag))
9617 return item->ToBag();
9618 return nullptr;
9619}
9620
9622{
9623 uint32 freeSpace = 0;
9624
9625 // Check backpack
9626 for (uint8 slot = INVENTORY_SLOT_ITEM_START; slot < INVENTORY_SLOT_ITEM_END; ++slot)
9627 {
9628 Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
9629 if (!item)
9630 freeSpace += 1;
9631 }
9632
9633 // Check bags
9635 {
9636 if (Bag* bag = GetBagByPos(i))
9637 freeSpace += bag->GetFreeSlots();
9638 }
9639
9640 return freeSpace;
9641}
9642
9643Item* Player::GetWeaponForAttack(WeaponAttackType attackType, bool useable /*= false*/) const
9644{
9645 uint8 slot;
9646 switch (attackType)
9647 {
9648 case BASE_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
9649 case OFF_ATTACK: slot = EQUIPMENT_SLOT_OFFHAND; break;
9650 case RANGED_ATTACK: slot = EQUIPMENT_SLOT_MAINHAND; break;
9651 default: return nullptr;
9652 }
9653
9654 Item* item;
9655 if (useable)
9657 else
9658 item = GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
9659
9660 if (!item || item->GetTemplate()->GetClass() != ITEM_CLASS_WEAPON)
9661 return nullptr;
9662
9663 if ((attackType == RANGED_ATTACK) != item->GetTemplate()->IsRangedWeapon())
9664 return nullptr;
9665
9666 if (!useable)
9667 return item;
9668
9669 if (item->IsBroken())
9670 return nullptr;
9671
9672 return item;
9673}
9674
9675Item* Player::GetShield(bool useable) const
9676{
9677 Item* item;
9678 if (useable)
9680 else
9682
9683 if (!item || item->GetTemplate()->GetClass() != ITEM_CLASS_ARMOR)
9684 return nullptr;
9685
9686 if (!useable)
9687 return item;
9688
9689 if (item->IsBroken())
9690 return nullptr;
9691
9692 return item;
9693}
9694
9696{
9697 Item* result = nullptr;
9699 {
9700 if (item->GetGUID() == guid)
9701 {
9702 result = item;
9703 return ItemSearchCallbackResult::Stop;
9704 }
9706 });
9707 return result;
9708}
9709
9711{
9712 switch (slot)
9713 {
9714 case EQUIPMENT_SLOT_MAINHAND: return inventoryType != INVTYPE_RANGED && inventoryType != INVTYPE_RANGEDRIGHT ? BASE_ATTACK : RANGED_ATTACK;
9716 default: return MAX_ATTACK;
9717 }
9718}
9719
9721{
9722 if (bag == INVENTORY_SLOT_BAG_0 && slot == NULL_SLOT)
9723 return true;
9725 return true;
9727 return true;
9729 return true;
9730 return false;
9731}
9732
9734{
9735 if (bag == INVENTORY_SLOT_BAG_0 && (slot < EQUIPMENT_SLOT_END))
9736 return true;
9737 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= PROFESSION_SLOT_START && slot < PROFESSION_SLOT_END))
9738 return true;
9740 return true;
9741 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_BAG_SLOT_START && slot < REAGENT_BAG_SLOT_END))
9742 return true;
9743 return false;
9744}
9745
9747{
9748 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END))
9749 return true;
9750 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END))
9751 return true;
9752 if (bag >= BANK_SLOT_BAG_START && bag < BANK_SLOT_BAG_END)
9753 return true;
9754 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END))
9755 return true;
9756 return false;
9757}
9758
9760{
9761 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END))
9762 return true;
9763 return false;
9764}
9765
9767{
9768 uint8 bag = pos >> 8;
9769 uint8 slot = pos & 255;
9771 return true;
9772 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END))
9773 return true;
9774 if (bag == INVENTORY_SLOT_BAG_0 && (slot >= REAGENT_BAG_SLOT_START && slot < REAGENT_BAG_SLOT_END))
9775 return true;
9776 return false;
9777}
9778
9780{
9782}
9783
9784bool Player::IsValidPos(uint8 bag, uint8 slot, bool explicit_pos) const
9785{
9786 // post selected
9787 if (bag == NULL_BAG && !explicit_pos)
9788 return true;
9789
9790 if (bag == INVENTORY_SLOT_BAG_0)
9791 {
9792 // any post selected
9793 if (slot == NULL_SLOT && !explicit_pos)
9794 return true;
9795
9796 // equipment
9797 if (slot < EQUIPMENT_SLOT_END)
9798 return true;
9799
9800 // profession equipment
9801 if (slot >= PROFESSION_SLOT_START && slot < PROFESSION_SLOT_END)
9802 return true;
9803
9804 // bag equip slots
9806 return true;
9807
9808 // reagent bag equip slots
9809 if (slot >= REAGENT_BAG_SLOT_START && slot < REAGENT_BAG_SLOT_END)
9810 return true;
9811
9812 // backpack slots
9814 return true;
9815
9816 // bank main slots
9817 if (slot >= BANK_SLOT_ITEM_START && slot < BANK_SLOT_ITEM_END)
9818 return true;
9819
9820 // bank bag slots
9821 if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
9822 return true;
9823
9824 // reagent bank bag slots
9825 if (slot >= REAGENT_SLOT_START && slot < REAGENT_SLOT_END)
9826 return true;
9827
9828 return false;
9829 }
9830
9831 // bag content slots
9832 // bank bag content slots
9833 if (Bag* pBag = GetBagByPos(bag))
9834 {
9835 // any post selected
9836 if (slot == NULL_SLOT && !explicit_pos)
9837 return true;
9838
9839 return slot < pBag->GetBagSize();
9840 }
9841
9842 // where this?
9843 return false;
9844}
9845
9847{
9849
9850 if (slots < GetInventorySlotCount())
9851 {
9852 std::vector<Item*> unstorableItems;
9853
9854 for (uint8 slot = INVENTORY_SLOT_ITEM_START + slots; slot < INVENTORY_SLOT_ITEM_END; ++slot)
9855 if (Item* unstorableItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot))
9856 unstorableItems.push_back(unstorableItem);
9857
9858 if (!unstorableItems.empty())
9859 {
9860 std::size_t fullBatches = unstorableItems.size() / MAX_MAIL_ITEMS;
9861 std::size_t remainder = unstorableItems.size() % MAX_MAIL_ITEMS;
9862 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
9863
9864 auto sendItemsBatch = [this, &trans, &unstorableItems](std::size_t batchNumber, std::size_t batchSize)
9865 {
9866 MailDraft draft(GetSession()->GetTrinityString(LANG_NOT_EQUIPPED_ITEM), "There were problems with equipping item(s).");
9867 for (std::size_t j = 0; j < batchSize; ++j)
9868 draft.AddItem(unstorableItems[batchNumber * MAX_MAIL_ITEMS + j]);
9869
9871 };
9872
9873 for (std::size_t batch = 0; batch < fullBatches; ++batch)
9874 sendItemsBatch(batch, MAX_MAIL_ITEMS);
9875
9876 if (remainder)
9877 sendItemsBatch(fullBatches, remainder);
9878
9879 CharacterDatabase.CommitTransaction(trans);
9880
9882 }
9883 }
9884
9886}
9887
9888bool Player::HasItemCount(uint32 item, uint32 count, bool inBankAlso) const
9889{
9891 if (inBankAlso)
9892 location |= ItemSearchLocation::Bank;
9893
9894 uint32 currentCount = 0;
9895 return !ForEachItem(location, [item, count, &currentCount](Item* pItem)
9896 {
9897 if (pItem->GetEntry() == item && !pItem->IsInTrade())
9898 {
9899 currentCount += pItem->GetCount();
9900 if (currentCount >= count)
9901 return ItemSearchCallbackResult::Stop;
9902 }
9904 });
9905}
9906
9907bool Player::HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot) const
9908{
9909 uint32 tempcount = 0;
9910
9911 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
9912 bool includeGems = pProto && pProto->GetGemProperties();
9913 return !ForEachItem(ItemSearchLocation::Equipment, [item, &tempcount, count, except_slot, includeGems](Item* pItem)
9914 {
9915 if (pItem->GetSlot() != except_slot)
9916 {
9917 if (pItem->GetEntry() == item)
9918 tempcount += pItem->GetCount();
9919
9920 if (includeGems)
9921 tempcount += pItem->GetGemCountWithID(item);
9922
9923 if (tempcount >= count)
9924 return ItemSearchCallbackResult::Stop;
9925 }
9926
9928 });
9929}
9930
9931bool Player::HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
9932{
9933 uint32 tempcount = 0;
9934 return !ForEachItem(ItemSearchLocation::Equipment, [&tempcount, limitCategory, count, except_slot](Item* pItem)
9935 {
9936 if (pItem->GetSlot() == except_slot)
9938
9939 if (pItem->GetTemplate()->GetItemLimitCategory() != limitCategory)
9941
9942 tempcount += pItem->GetCount();
9943 if (tempcount >= count)
9945
9947 });
9948}
9949
9950bool Player::HasGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot) const
9951{
9952 uint32 tempcount = 0;
9953 return !ForEachItem(ItemSearchLocation::Equipment, [&tempcount, limitCategory, count, except_slot](Item* pItem)
9954 {
9955 if (pItem->GetSlot() == except_slot)
9957
9958 ItemTemplate const* pProto = pItem->GetTemplate();
9959 if (!pProto)
9961
9962 tempcount += pItem->GetGemCountWithLimitCategory(limitCategory);
9963 if (tempcount >= count)
9965
9967 });
9968}
9969
9970InventoryResult Player::CanTakeMoreSimilarItems(uint32 entry, uint32 count, Item* pItem, uint32* no_space_count /*= nullptr*/, uint32* offendingItemId /*= nullptr*/) const
9971{
9972 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
9973 if (!pProto)
9974 {
9975 if (no_space_count)
9976 *no_space_count = count;
9978 }
9979
9980 if (pItem && pItem->m_lootGenerated)
9981 return EQUIP_ERR_LOOT_GONE;
9982
9983 // no maximum
9984 if ((pProto->GetMaxCount() <= 0 && pProto->GetItemLimitCategory() == 0) || pProto->GetMaxCount() == 2147483647)
9985 return EQUIP_ERR_OK;
9986
9987 if (pProto->GetMaxCount() > 0)
9988 {
9989 uint32 curcount = GetItemCount(pProto->GetId(), true, pItem);
9990 if (curcount + count > uint32(pProto->GetMaxCount()))
9991 {
9992 if (no_space_count)
9993 *no_space_count = count + curcount - pProto->GetMaxCount();
9995 }
9996 }
9997
9998 // check unique-equipped limit
9999 if (pProto->GetItemLimitCategory())
10000 {
10001 ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(pProto->GetItemLimitCategory());
10002 if (!limitEntry)
10003 {
10004 if (no_space_count)
10005 *no_space_count = count;
10007 }
10008
10009 if (limitEntry->Flags == ITEM_LIMIT_CATEGORY_MODE_HAVE)
10010 {
10011 uint8 limitQuantity = GetItemLimitCategoryQuantity(limitEntry);
10012 uint32 curcount = GetItemCountWithLimitCategory(pProto->GetItemLimitCategory(), pItem);
10013 if (curcount + count > uint32(limitQuantity))
10014 {
10015 if (no_space_count)
10016 *no_space_count = count + curcount - limitQuantity;
10017 if (offendingItemId)
10018 *offendingItemId = pProto->GetId();
10020 }
10021 }
10022 }
10023
10024 return EQUIP_ERR_OK;
10025}
10026
10027InventoryResult Player::CanTakeMoreSimilarItems(Item* pItem, uint32* offendingItemId /*= nullptr*/) const
10028{
10029 return CanTakeMoreSimilarItems(pItem->GetEntry(), pItem->GetCount(), pItem, nullptr, offendingItemId);
10030}
10031
10032InventoryResult Player::CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, uint32 item, uint32 count, uint32* no_space_count /*= nullptr*/) const
10033{
10034 return CanStoreItem(bag, slot, dest, item, count, nullptr, false, no_space_count);
10035}
10036
10037InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap /*= false*/) const
10038{
10039 if (!pItem)
10041 uint32 count = pItem->GetCount();
10042 return CanStoreItem(bag, slot, dest, pItem->GetEntry(), count, pItem, swap, nullptr);
10043}
10044
10046{
10047 for (AuraEffect const* providedTotemCategory : GetAuraEffectsByType(SPELL_AURA_PROVIDE_TOTEM_CATEGORY))
10048 if (DB2Manager::IsTotemCategoryCompatibleWith(providedTotemCategory->GetMiscValueB(), TotemCategory))
10049 return true;
10050
10051 Item* item;
10053 for (uint8 i = EQUIPMENT_SLOT_START; i < inventoryEnd; ++i)
10054 {
10057 return true;
10058 }
10059
10060 Bag* bag;
10062 {
10063 bag = GetBagByPos(i);
10064 if (bag)
10065 {
10066 for (uint32 j = 0; j < bag->GetBagSize(); ++j)
10067 {
10068 item = GetUseableItemByPos(i, j);
10070 return true;
10071 }
10072 }
10073 }
10074
10076 {
10079 return true;
10080 }
10081
10082 return false;
10083}
10084
10085InventoryResult Player::CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool swap, Item* pSrcItem) const
10086{
10087 Item* pItem2 = GetItemByPos(bag, slot);
10088
10089 // ignore move item (this slot will be empty at move)
10090 if (pItem2 == pSrcItem)
10091 pItem2 = nullptr;
10092
10093 uint32 need_space;
10094
10095 if (pSrcItem)
10096 {
10097 if (pSrcItem->IsNotEmptyBag() && !IsBagPos(uint16(bag) << 8 | slot))
10099
10100 if (pSrcItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD) && !IsEquipmentPos(bag, slot) && !IsChildEquipmentPos(bag, slot))
10102
10103 if (!pSrcItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD) && IsChildEquipmentPos(bag, slot))
10105 }
10106
10107 // empty specific slot - check item fit to slot
10108 if (!pItem2 || swap)
10109 {
10110 if (bag == INVENTORY_SLOT_BAG_0)
10111 {
10112 // prevent cheating
10113 if ((slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END) || slot >= PLAYER_SLOT_END)
10115
10116 // can't store anything else than crafting reagents in Reagent Bank
10117 if (IsReagentBankPos(bag, slot) && (!IsReagentBankUnlocked() || !pProto->IsCraftingReagent()))
10119 }
10120 else
10121 {
10122 Bag* pBag = GetBagByPos(bag);
10123 if (!pBag)
10125
10126 ItemTemplate const* pBagProto = pBag->GetTemplate();
10127 if (!pBagProto)
10129
10130 if (slot >= pBagProto->GetContainerSlots())
10132
10133 if (!ItemCanGoIntoBag(pProto, pBagProto))
10135 }
10136
10137 // non empty stack with space
10138 need_space = pProto->GetMaxStackSize();
10139 }
10140 // non empty slot, check item type
10141 else
10142 {
10143 // can be merged at least partly
10144 InventoryResult res = pItem2->CanBeMergedPartlyWith(pProto);
10145 if (res != EQUIP_ERR_OK)
10146 return res;
10147
10148 // free stack space or infinity
10149 need_space = pProto->GetMaxStackSize() - pItem2->GetCount();
10150 }
10151
10152 if (need_space > count)
10153 need_space = count;
10154
10155 ItemPosCount newPosition = ItemPosCount((bag << 8) | slot, need_space);
10156 if (!newPosition.isContainedIn(dest))
10157 {
10158 dest.push_back(newPosition);
10159 count -= need_space;
10160 }
10161 return EQUIP_ERR_OK;
10162}
10163
10164InventoryResult Player::CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool merge, bool non_specialized, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
10165{
10166 // skip specific bag already processed in first called CanStoreItem_InBag
10167 if (bag == skip_bag)
10169
10170 // skip non-existing bag or self targeted bag
10171 Bag* pBag = GetBagByPos(bag);
10172 if (!pBag || pBag == pSrcItem)
10174
10175 if (pSrcItem)
10176 {
10177 if (pSrcItem->IsNotEmptyBag())
10179
10180 if (pSrcItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
10182 }
10183
10184 ItemTemplate const* pBagProto = pBag->GetTemplate();
10185 if (!pBagProto)
10187
10188 // specialized bag mode or non-specialized
10189 if (non_specialized != (pBagProto->GetClass() == ITEM_CLASS_CONTAINER && pBagProto->GetSubClass() == ITEM_SUBCLASS_CONTAINER))
10191
10192 if (!ItemCanGoIntoBag(pProto, pBagProto))
10194
10195 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
10196 {
10197 // skip specific slot already processed in first called CanStoreItem_InSpecificSlot
10198 if (j == skip_slot)
10199 continue;
10200
10201 Item* pItem2 = GetItemByPos(bag, j);
10202
10203 // ignore move item (this slot will be empty at move)
10204 if (pItem2 == pSrcItem)
10205 pItem2 = nullptr;
10206
10207 // if merge skip empty, if !merge skip non-empty
10208 if ((pItem2 != nullptr) != merge)
10209 continue;
10210
10211 uint32 need_space = pProto->GetMaxStackSize();
10212
10213 if (pItem2)
10214 {
10215 // can be merged at least partly
10216 if (pItem2->CanBeMergedPartlyWith(pProto) != EQUIP_ERR_OK)
10217 continue;
10218
10219 // descrease at current stacksize
10220 need_space -= pItem2->GetCount();
10221 }
10222
10223 if (need_space > count)
10224 need_space = count;
10225
10226 ItemPosCount newPosition = ItemPosCount((bag << 8) | j, need_space);
10227 if (!newPosition.isContainedIn(dest))
10228 {
10229 dest.push_back(newPosition);
10230 count -= need_space;
10231
10232 if (count==0)
10233 return EQUIP_ERR_OK;
10234 }
10235 }
10236 return EQUIP_ERR_OK;
10237}
10238
10239InventoryResult Player::CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemTemplate const* pProto, uint32& count, bool merge, Item* pSrcItem, uint8 skip_bag, uint8 skip_slot) const
10240{
10241 //this is never called for non-bag slots so we can do this
10242 if (pSrcItem && pSrcItem->IsNotEmptyBag())
10244
10245 for (uint32 j = slot_begin; j < slot_end; j++)
10246 {
10247 // skip specific slot already processed in first called CanStoreItem_InSpecificSlot
10248 if (INVENTORY_SLOT_BAG_0 == skip_bag && j == skip_slot)
10249 continue;
10250
10252
10253 // ignore move item (this slot will be empty at move)
10254 if (pItem2 == pSrcItem)
10255 pItem2 = nullptr;
10256
10257 // if merge skip empty, if !merge skip non-empty
10258 if ((pItem2 != nullptr) != merge)
10259 continue;
10260
10261 uint32 need_space = pProto->GetMaxStackSize();
10262
10263 if (pItem2)
10264 {
10265 // can be merged at least partly
10266 if (pItem2->CanBeMergedPartlyWith(pProto) != EQUIP_ERR_OK)
10267 continue;
10268
10269 // descrease at current stacksize
10270 need_space -= pItem2->GetCount();
10271 }
10272
10273 if (need_space > count)
10274 need_space = count;
10275
10276 ItemPosCount newPosition = ItemPosCount((INVENTORY_SLOT_BAG_0 << 8) | j, need_space);
10277 if (!newPosition.isContainedIn(dest))
10278 {
10279 dest.push_back(newPosition);
10280 count -= need_space;
10281
10282 if (count==0)
10283 return EQUIP_ERR_OK;
10284 }
10285 }
10286 return EQUIP_ERR_OK;
10287}
10288
10289InventoryResult Player::CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 entry, uint32 count, Item* pItem, bool swap, uint32* no_space_count) const
10290{
10291 TC_LOG_DEBUG("entities.player.items", "Player::CanStoreItem: Bag: {}, Slot: {}, Item: {}, Count: {}", bag, slot, entry, count);
10292
10293 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(entry);
10294 if (!pProto)
10295 {
10296 if (no_space_count)
10297 *no_space_count = count;
10299 }
10300
10301 if (pItem)
10302 {
10303 // item used
10304 if (pItem->m_lootGenerated)
10305 {
10306 if (no_space_count)
10307 *no_space_count = count;
10308 return EQUIP_ERR_LOOT_GONE;
10309 }
10310
10311 if (pItem->IsBindedNotWith(this))
10312 {
10313 if (no_space_count)
10314 *no_space_count = count;
10315 return EQUIP_ERR_NOT_OWNER;
10316 }
10317 }
10318
10319 // check count of items (skip for auto move for same player from bank)
10320 uint32 no_similar_count = 0; // can't store this amount similar items
10321 InventoryResult res = CanTakeMoreSimilarItems(entry, count, pItem, &no_similar_count);
10322 if (res != EQUIP_ERR_OK)
10323 {
10324 if (count == no_similar_count)
10325 {
10326 if (no_space_count)
10327 *no_space_count = no_similar_count;
10328 return res;
10329 }
10330 count -= no_similar_count;
10331 }
10332
10333 // in specific slot
10334 if (bag != NULL_BAG && slot != NULL_SLOT)
10335 {
10336 res = CanStoreItem_InSpecificSlot(bag, slot, dest, pProto, count, swap, pItem);
10337 if (res != EQUIP_ERR_OK)
10338 {
10339 if (no_space_count)
10340 *no_space_count = count + no_similar_count;
10341 return res;
10342 }
10343
10344 if (count == 0)
10345 {
10346 if (no_similar_count == 0)
10347 return EQUIP_ERR_OK;
10348
10349 if (no_space_count)
10350 *no_space_count = count + no_similar_count;
10352 }
10353 }
10354
10355 // not specific slot or have space for partly store only in specific slot
10357
10358 // in specific bag
10359 if (bag != NULL_BAG)
10360 {
10361 // search stack in bag for merge to
10362 if (pProto->GetMaxStackSize() != 1)
10363 {
10364 if (bag == INVENTORY_SLOT_BAG_0) // inventory
10365 {
10366 res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
10367 if (res != EQUIP_ERR_OK)
10368 {
10369 if (no_space_count)
10370 *no_space_count = count + no_similar_count;
10371 return res;
10372 }
10373
10374 if (count == 0)
10375 {
10376 if (no_similar_count == 0)
10377 return EQUIP_ERR_OK;
10378
10379 if (no_space_count)
10380 *no_space_count = count + no_similar_count;
10382 }
10383
10384 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, inventoryEnd, dest, pProto, count, true, pItem, bag, slot);
10385 if (res != EQUIP_ERR_OK)
10386 {
10387 if (no_space_count)
10388 *no_space_count = count + no_similar_count;
10389 return res;
10390 }
10391
10392 if (count == 0)
10393 {
10394 if (no_similar_count == 0)
10395 return EQUIP_ERR_OK;
10396
10397 if (no_space_count)
10398 *no_space_count = count + no_similar_count;
10400 }
10401 }
10402 else // equipped bag
10403 {
10404 // we need check 2 time (specialized/non_specialized), use NULL_BAG to prevent skipping bag
10405 res = CanStoreItem_InBag(bag, dest, pProto, count, true, false, pItem, NULL_BAG, slot);
10406 if (res != EQUIP_ERR_OK)
10407 res = CanStoreItem_InBag(bag, dest, pProto, count, true, true, pItem, NULL_BAG, slot);
10408
10409 if (res != EQUIP_ERR_OK)
10410 {
10411 if (no_space_count)
10412 *no_space_count = count + no_similar_count;
10413 return res;
10414 }
10415
10416 if (count == 0)
10417 {
10418 if (no_similar_count == 0)
10419 return EQUIP_ERR_OK;
10420
10421 if (no_space_count)
10422 *no_space_count = count + no_similar_count;
10424 }
10425 }
10426 }
10427
10428 // search free slot in bag for place to
10429 if (bag == INVENTORY_SLOT_BAG_0) // inventory
10430 {
10431 if (pItem && pItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
10432 {
10433 res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
10434 if (res != EQUIP_ERR_OK)
10435 {
10436 if (no_space_count)
10437 *no_space_count = count + no_similar_count;
10438 return res;
10439 }
10440
10441 if (count == 0)
10442 {
10443 if (no_similar_count == 0)
10444 return EQUIP_ERR_OK;
10445
10446 if (no_space_count)
10447 *no_space_count = count + no_similar_count;
10449 }
10450 }
10451
10452 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, inventoryEnd, dest, pProto, count, false, pItem, bag, slot);
10453 if (res != EQUIP_ERR_OK)
10454 {
10455 if (no_space_count)
10456 *no_space_count = count + no_similar_count;
10457 return res;
10458 }
10459
10460 if (count == 0)
10461 {
10462 if (no_similar_count == 0)
10463 return EQUIP_ERR_OK;
10464
10465 if (no_space_count)
10466 *no_space_count = count + no_similar_count;
10468 }
10469 }
10470 else // equipped bag
10471 {
10472 res = CanStoreItem_InBag(bag, dest, pProto, count, false, false, pItem, NULL_BAG, slot);
10473 if (res != EQUIP_ERR_OK)
10474 res = CanStoreItem_InBag(bag, dest, pProto, count, false, true, pItem, NULL_BAG, slot);
10475
10476 if (res != EQUIP_ERR_OK)
10477 {
10478 if (no_space_count)
10479 *no_space_count = count + no_similar_count;
10480 return res;
10481 }
10482
10483 if (count == 0)
10484 {
10485 if (no_similar_count == 0)
10486 return EQUIP_ERR_OK;
10487
10488 if (no_space_count)
10489 *no_space_count = count + no_similar_count;
10491 }
10492 }
10493 }
10494
10495 // not specific bag or have space for partly store only in specific bag
10496
10497 // search stack for merge to
10498 if (pProto->GetMaxStackSize() != 1)
10499 {
10500 res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, true, pItem, bag, slot);
10501 if (res != EQUIP_ERR_OK)
10502 {
10503 if (no_space_count)
10504 *no_space_count = count + no_similar_count;
10505 return res;
10506 }
10507
10508 if (count == 0)
10509 {
10510 if (no_similar_count == 0)
10511 return EQUIP_ERR_OK;
10512
10513 if (no_space_count)
10514 *no_space_count = count + no_similar_count;
10516 }
10517
10518 res = CanStoreItem_InInventorySlots(INVENTORY_SLOT_ITEM_START, inventoryEnd, dest, pProto, count, true, pItem, bag, slot);
10519 if (res != EQUIP_ERR_OK)
10520 {
10521 if (no_space_count)
10522 *no_space_count = count + no_similar_count;
10523 return res;
10524 }
10525
10526 if (count == 0)
10527 {
10528 if (no_similar_count == 0)
10529 return EQUIP_ERR_OK;
10530
10531 if (no_space_count)
10532 *no_space_count = count + no_similar_count;
10534 }
10535
10536 if (pProto->GetBagFamily())
10537 {
10539 {
10540 res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot);
10541 if (res != EQUIP_ERR_OK)
10542 continue;
10543
10544 if (count == 0)
10545 {
10546 if (no_similar_count == 0)
10547 return EQUIP_ERR_OK;
10548
10549 if (no_space_count)
10550 *no_space_count = count + no_similar_count;
10552 }
10553 }
10554 }
10555
10557 {
10558 res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot);
10559 if (res != EQUIP_ERR_OK)
10560 continue;
10561
10562 if (count == 0)
10563 {
10564 if (no_similar_count == 0)
10565 return EQUIP_ERR_OK;
10566
10567 if (no_space_count)
10568 *no_space_count = count + no_similar_count;
10570 }
10571 }
10572 }
10573
10574 // search free slot - special bag case
10575 if (pProto->GetBagFamily())
10576 {
10578 {
10579 res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot);
10580 if (res != EQUIP_ERR_OK)
10581 continue;
10582
10583 if (count == 0)
10584 {
10585 if (no_similar_count == 0)
10586 return EQUIP_ERR_OK;
10587
10588 if (no_space_count)
10589 *no_space_count = count + no_similar_count;
10591 }
10592 }
10593 }
10594
10595 if (pItem && pItem->IsNotEmptyBag())
10596 return EQUIP_ERR_BAG_IN_BAG;
10597
10598 if (pItem && pItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
10599 {
10600 res = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, pProto, count, false, pItem, bag, slot);
10601 if (res != EQUIP_ERR_OK)
10602 {
10603 if (no_space_count)
10604 *no_space_count = count + no_similar_count;
10605 return res;
10606 }
10607
10608 if (count == 0)
10609 {
10610 if (no_similar_count == 0)
10611 return EQUIP_ERR_OK;
10612
10613 if (no_space_count)
10614 *no_space_count = count + no_similar_count;
10616 }
10617 }
10618
10619 // search free slot
10620 uint8 searchSlotStart = INVENTORY_SLOT_ITEM_START;
10621 // new bags can be directly equipped
10622 if (!pItem && pProto->GetClass() == ITEM_CLASS_CONTAINER && pProto->GetSubClass() == ITEM_SUBCLASS_CONTAINER &&
10623 (pProto->GetBonding() == BIND_NONE || pProto->GetBonding() == BIND_ON_ACQUIRE))
10624 searchSlotStart = INVENTORY_SLOT_BAG_START;
10625
10626 res = CanStoreItem_InInventorySlots(searchSlotStart, inventoryEnd, dest, pProto, count, false, pItem, bag, slot);
10627 if (res != EQUIP_ERR_OK)
10628 {
10629 if (no_space_count)
10630 *no_space_count = count + no_similar_count;
10631 return res;
10632 }
10633
10634 if (count == 0)
10635 {
10636 if (no_similar_count == 0)
10637 return EQUIP_ERR_OK;
10638
10639 if (no_space_count)
10640 *no_space_count = count + no_similar_count;
10642 }
10643
10645 {
10646 res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot);
10647 if (res != EQUIP_ERR_OK)
10648 continue;
10649
10650 if (count == 0)
10651 {
10652 if (no_similar_count == 0)
10653 return EQUIP_ERR_OK;
10654
10655 if (no_space_count)
10656 *no_space_count = count + no_similar_count;
10658 }
10659 }
10660
10661 if (no_space_count)
10662 *no_space_count = count + no_similar_count;
10663
10664 return EQUIP_ERR_INV_FULL;
10665}
10666
10668InventoryResult Player::CanStoreItems(Item** items, int count, uint32* offendingItemId) const
10669{
10670 Item* item2;
10671
10672 // fill space tables, creating a mock-up of the player's inventory
10673
10674 // counts
10677
10678 // Item pointers
10679 Item* inventoryPointers[INVENTORY_SLOT_ITEM_END - INVENTORY_SLOT_ITEM_START] = {};
10681
10683
10684 // filling inventory
10685 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; i++)
10686 {
10687 // build items in stock backpack
10689 if (item2 && !item2->IsInTrade())
10690 {
10691 inventoryCounts[i - INVENTORY_SLOT_ITEM_START] = item2->GetCount();
10692 inventoryPointers[i - INVENTORY_SLOT_ITEM_START] = item2;
10693 }
10694 }
10695
10697 if (Bag* pBag = GetBagByPos(i))
10698 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
10699 {
10700 // build item counts in equippable bags
10701 item2 = GetItemByPos(i, j);
10702 if (item2 && !item2->IsInTrade())
10703 {
10704 bagCounts[i - INVENTORY_SLOT_BAG_START][j] = item2->GetCount();
10705 bagPointers[i - INVENTORY_SLOT_BAG_START][j] = item2;
10706 }
10707 }
10708
10709 // check free space for all items that we wish to add
10710 for (int k = 0; k < count; ++k)
10711 {
10712 // Incoming item
10713 Item* item = items[k];
10714
10715 // no item
10716 if (!item)
10717 continue;
10718
10719 uint32_t remaining_count = item->GetCount();
10720
10721 TC_LOG_DEBUG("entities.player.items", "Player::CanStoreItems: Player '{}' ({}), Index: {} ItemID: {}, Count: {}",
10722 GetName(), GetGUID().ToString(), k + 1, item->GetEntry(), remaining_count);
10723 ItemTemplate const* pProto = item->GetTemplate();
10724
10725 // strange item
10726 if (!pProto)
10728
10729 // item used
10730 if (item->m_lootGenerated)
10731 return EQUIP_ERR_LOOT_GONE;
10732
10733 // item it 'bind'
10734 if (item->IsBindedNotWith(this))
10735 return EQUIP_ERR_NOT_OWNER;
10736
10737 ItemTemplate const* pBagProto;
10738
10739 // item is 'one item only'
10740 InventoryResult res = CanTakeMoreSimilarItems(item, offendingItemId);
10741 if (res != EQUIP_ERR_OK)
10742 return res;
10743
10744 // search stack for merge to
10745 if (pProto->GetMaxStackSize() != 1)
10746 {
10747 bool b_found = false;
10748
10749 for (int t = INVENTORY_SLOT_ITEM_START; t < inventoryEnd; ++t)
10750 {
10751 item2 = inventoryPointers[t-INVENTORY_SLOT_ITEM_START];
10752 if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && inventoryCounts[t-INVENTORY_SLOT_ITEM_START] < pProto->GetMaxStackSize())
10753 {
10754 inventoryCounts[t-INVENTORY_SLOT_ITEM_START] += remaining_count;
10755 remaining_count = inventoryCounts[t-INVENTORY_SLOT_ITEM_START] < pProto->GetMaxStackSize() ? 0 : inventoryCounts[t-INVENTORY_SLOT_ITEM_START] - pProto->GetMaxStackSize();
10756
10757 b_found = remaining_count == 0;
10758 // if no pieces of the stack remain, then stop checking stock bag
10759 if (b_found)
10760 break;
10761 }
10762 }
10763
10764 if (b_found)
10765 continue;
10766
10767 for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
10768 {
10769 if (Bag* bag = GetBagByPos(t))
10770 {
10771 if (!ItemCanGoIntoBag(item->GetTemplate(), bag->GetTemplate()))
10772 continue;
10773
10774 for (uint32 j = 0; j < bag->GetBagSize(); j++)
10775 {
10776 item2 = bagPointers[t-INVENTORY_SLOT_BAG_START][j];
10777 if (item2 && item2->CanBeMergedPartlyWith(pProto) == EQUIP_ERR_OK && bagCounts[t-INVENTORY_SLOT_BAG_START][j] < pProto->GetMaxStackSize())
10778 {
10779 // add count to stack so that later items in the list do not double-book
10780 bagCounts[t-INVENTORY_SLOT_BAG_START][j] += remaining_count;
10781 remaining_count = bagCounts[t-INVENTORY_SLOT_BAG_START][j] < pProto->GetMaxStackSize() ? 0 : bagCounts[t-INVENTORY_SLOT_BAG_START][j] - pProto->GetMaxStackSize();
10782
10783 b_found = remaining_count == 0;
10784
10785 // if no pieces of the stack remain, then stop checking equippable bags
10786 if (b_found)
10787 break;
10788 }
10789 }
10790 }
10791 }
10792
10793 if (b_found)
10794 continue;
10795 }
10796
10797 // special bag case
10798 if (pProto->GetBagFamily())
10799 {
10800 bool b_found = false;
10801
10802 for (int t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
10803 {
10804 if (Bag* bag = GetBagByPos(t))
10805 {
10806 pBagProto = bag->GetTemplate();
10807
10808 // not plain container check
10809 if (pBagProto && (pBagProto->GetClass() != ITEM_CLASS_CONTAINER || pBagProto->GetSubClass() != ITEM_SUBCLASS_CONTAINER) &&
10810 ItemCanGoIntoBag(pProto, pBagProto))
10811 {
10812 for (uint32 j = 0; j < bag->GetBagSize(); j++)
10813 {
10814 if (bagCounts[t-INVENTORY_SLOT_BAG_START][j] == 0)
10815 {
10816 bagCounts[t-INVENTORY_SLOT_BAG_START][j] = remaining_count;
10817 bagPointers[t-INVENTORY_SLOT_BAG_START][j] = item;
10818
10819 b_found = true;
10820 break;
10821 }
10822 }
10823 }
10824 }
10825 }
10826
10827 if (b_found)
10828 continue;
10829 }
10830
10831 // search free slot
10832 bool b_found = false;
10833 for (int t = INVENTORY_SLOT_ITEM_START; t < inventoryEnd; ++t)
10834 {
10835 if (inventoryCounts[t-INVENTORY_SLOT_ITEM_START] == 0)
10836 {
10837 inventoryCounts[t-INVENTORY_SLOT_ITEM_START] = remaining_count;
10838 inventoryPointers[t-INVENTORY_SLOT_ITEM_START] = item;
10839
10840 b_found = true;
10841 break;
10842 }
10843 }
10844
10845 if (b_found)
10846 continue;
10847
10848 // search free slot in bags
10849 for (uint8 t = INVENTORY_SLOT_BAG_START; !b_found && t < INVENTORY_SLOT_BAG_END; ++t)
10850 {
10851 if (Bag* bag = GetBagByPos(t))
10852 {
10853 pBagProto = bag->GetTemplate();
10854
10855 // special bag already checked
10856 if (pBagProto && (pBagProto->GetClass() != ITEM_CLASS_CONTAINER || pBagProto->GetSubClass() != ITEM_SUBCLASS_CONTAINER))
10857 continue;
10858
10859 for (uint32 j = 0; j < bag->GetBagSize(); j++)
10860 {
10861 if (bagCounts[t - INVENTORY_SLOT_BAG_START][j] == 0)
10862 {
10863 bagCounts[t-INVENTORY_SLOT_BAG_START][j] = remaining_count;
10864 bagPointers[t-INVENTORY_SLOT_BAG_START][j] = item;
10865
10866 b_found = true;
10867 break;
10868 }
10869 }
10870 }
10871 }
10872
10873 // if no free slot found for all pieces of the item, then return an error
10874 if (!b_found)
10875 return EQUIP_ERR_BAG_FULL;
10876 }
10877
10878 return EQUIP_ERR_OK;
10879}
10880
10882InventoryResult Player::CanEquipNewItem(uint8 slot, uint16 &dest, uint32 item, bool swap) const
10883{
10884 dest = 0;
10885 Item* pItem = Item::CreateItem(item, 1, ItemContext::NONE, this);
10886 if (pItem)
10887 {
10888 InventoryResult result = CanEquipItem(slot, dest, pItem, swap);
10889 delete pItem;
10890 return result;
10891 }
10892
10894}
10895
10896InventoryResult Player::CanEquipItem(uint8 slot, uint16 &dest, Item* pItem, bool swap, bool not_loading) const
10897{
10898 dest = 0;
10899 if (pItem)
10900 {
10901 TC_LOG_DEBUG("entities.player.items", "Player::CanEquipItem: Player '{}' ({}), Slot: {}, Item: {}, Count: {}",
10902 GetName(), GetGUID().ToString(), slot, pItem->GetEntry(), pItem->GetCount());
10903 ItemTemplate const* pProto = pItem->GetTemplate();
10904 if (pProto)
10905 {
10906 // item used
10907 if (pItem->m_lootGenerated)
10908 return EQUIP_ERR_LOOT_GONE;
10909
10910 if (pItem->IsBindedNotWith(this))
10911 return EQUIP_ERR_NOT_OWNER;
10912
10913 // check count of items (skip for auto move for same player from bank)
10915 if (res != EQUIP_ERR_OK)
10916 return res;
10917
10918 // check this only in game
10919 if (not_loading)
10920 {
10921 // May be here should be more stronger checks; STUNNED checked
10922 // ROOT, CONFUSED, DISTRACTED, FLEEING this needs to be checked.
10925
10926 if (IsCharmed())
10927 return EQUIP_ERR_CLIENT_LOCKED_OUT; // @todo is this the correct error?
10928
10929 // do not allow equipping gear except weapons, offhands, projectiles, relics in
10930 // - combat
10931 // - in-progress arenas
10932 if (!pProto->CanChangeEquipStateInCombat())
10933 {
10934 if (IsInCombat())
10936
10937 if (Battleground* bg = GetBattleground())
10938 if (bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS)
10940 }
10941
10942 if (IsInCombat() && (pProto->GetClass() == ITEM_CLASS_WEAPON || pProto->GetInventoryType() == INVTYPE_RELIC) && m_weaponChangeTimer != 0)
10944
10945 if (Spell* currentGenericSpell = GetCurrentSpell(CURRENT_GENERIC_SPELL))
10946 if (!currentGenericSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR6_ALLOW_EQUIP_WHILE_CASTING))
10948
10949 if (Spell* currentChanneledSpell = GetCurrentSpell(CURRENT_CHANNELED_SPELL))
10950 if (!currentChanneledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR6_ALLOW_EQUIP_WHILE_CASTING))
10952 }
10953
10954 Optional<ContentTuningLevels> requiredLevels;
10955 // check allowed level (extend range to upper values if MaxLevel more or equal max player level, this let GM set high level with 1...max range items)
10956 if (pItem->GetQuality() == ITEM_QUALITY_HEIRLOOM)
10957 requiredLevels = sDB2Manager.GetContentTuningData(pItem->GetScalingContentTuningId(), 0, true);
10958
10959 if (requiredLevels && requiredLevels->MaxLevel < DEFAULT_MAX_LEVEL && requiredLevels->MaxLevel < GetLevel() && !sDB2Manager.GetHeirloomByItemId(pProto->GetId()))
10961
10962 uint8 eslot = FindEquipSlot(pItem, slot, swap);
10963 if (eslot == NULL_SLOT)
10965
10966 res = CanUseItem(pItem, not_loading);
10967 if (res != EQUIP_ERR_OK)
10968 return res;
10969
10970 if (!swap && GetItemByPos(INVENTORY_SLOT_BAG_0, eslot))
10972
10973 // if we are swapping 2 equiped items, CanEquipUniqueItem check
10974 // should ignore the item we are trying to swap, and not the
10975 // destination item. CanEquipUniqueItem should ignore destination
10976 // item only when we are swapping weapon from bag
10977 uint8 ignore = uint8(NULL_SLOT);
10978 switch (eslot)
10979 {
10981 ignore = EQUIPMENT_SLOT_OFFHAND;
10982 break;
10984 ignore = EQUIPMENT_SLOT_MAINHAND;
10985 break;
10987 ignore = EQUIPMENT_SLOT_FINGER2;
10988 break;
10990 ignore = EQUIPMENT_SLOT_FINGER1;
10991 break;
10993 ignore = EQUIPMENT_SLOT_TRINKET2;
10994 break;
10996 ignore = EQUIPMENT_SLOT_TRINKET1;
10997 break;
11000 break;
11003 break;
11006 break;
11009 break;
11010 }
11011
11012 if (ignore == uint8(NULL_SLOT) || pItem != GetItemByPos(INVENTORY_SLOT_BAG_0, ignore))
11013 ignore = eslot;
11014
11015 InventoryResult res2 = CanEquipUniqueItem(pItem, swap ? ignore : uint8(NULL_SLOT));
11016 if (res2 != EQUIP_ERR_OK)
11017 return res2;
11018
11019 // check unique-equipped special item classes
11020 if (pProto->GetClass() == ITEM_CLASS_QUIVER)
11022 if (Item* pBag = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
11023 if (pBag != pItem)
11024 if (ItemTemplate const* pBagProto = pBag->GetTemplate())
11025 if (pBagProto->GetClass() == pProto->GetClass() && (!swap || pBag->GetSlot() != eslot))
11026 return (pBagProto->GetSubClass() == ITEM_SUBCLASS_AMMO_POUCH)
11029
11030 uint32 type = pProto->GetInventoryType();
11031
11032 if (eslot == EQUIPMENT_SLOT_OFFHAND)
11033 {
11034 // Do not allow polearm to be equipped in the offhand (rare case for the only 1h polearm 41750)
11035 if (type == INVTYPE_WEAPON && pProto->GetSubClass() == ITEM_SUBCLASS_WEAPON_POLEARM)
11037 else if (type == INVTYPE_WEAPON)
11038 {
11039 if (!CanDualWield())
11041 }
11042 else if (type == INVTYPE_WEAPONOFFHAND)
11043 {
11046 }
11047 else if (type == INVTYPE_2HWEAPON)
11048 {
11049 if (!CanDualWield() || !CanTitanGrip())
11051 }
11052
11053 if (IsTwoHandUsed())
11055 }
11056
11057 // equip two-hand weapon case (with possible unequip 2 items)
11058 if (type == INVTYPE_2HWEAPON)
11059 {
11060 if (eslot == EQUIPMENT_SLOT_OFFHAND)
11061 {
11062 if (!CanTitanGrip())
11064 }
11065 else if (eslot != EQUIPMENT_SLOT_MAINHAND)
11067
11068 if (!CanTitanGrip())
11069 {
11070 // offhand item must can be stored in inventory for offhand item and it also must be unequipped
11072 ItemPosCountVec off_dest;
11073 if (offItem && (!not_loading ||
11075 CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) != EQUIP_ERR_OK))
11077 }
11078 }
11079 dest = ((INVENTORY_SLOT_BAG_0 << 8) | eslot);
11080 return EQUIP_ERR_OK;
11081 }
11082 }
11083
11085}
11086
11088{
11089 Item* childItem = GetChildItemByGuid(parentItem->GetChildItem());
11090 if (!childItem)
11091 return EQUIP_ERR_OK;
11092
11093 ItemChildEquipmentEntry const* childEquipement = sDB2Manager.GetItemChildEquipment(parentItem->GetEntry());
11094 if (!childEquipement)
11095 return EQUIP_ERR_OK;
11096
11097 Item* dstItem = GetItemByPos(INVENTORY_SLOT_BAG_0, childEquipement->ChildItemEquipSlot);
11098 if (!dstItem)
11099 return EQUIP_ERR_OK;
11100
11101 uint16 childDest = (INVENTORY_SLOT_BAG_0 << 8) | childEquipement->ChildItemEquipSlot;
11102 InventoryResult msg = CanUnequipItem(childDest, !childItem->IsBag());
11103 if (msg != EQUIP_ERR_OK)
11104 return msg;
11105
11106 // check dest->src move possibility
11107 uint16 src = parentItem->GetPos();
11108 ItemPosCountVec dest;
11109 if (IsInventoryPos(src))
11110 {
11111 msg = CanStoreItem(parentItem->GetBagSlot(), NULL_SLOT, dest, dstItem, true);
11112 if (msg != EQUIP_ERR_OK)
11113 msg = CanStoreItem(NULL_BAG, NULL_SLOT, dest, dstItem, true);
11114 }
11115 else if (IsBankPos(src))
11116 {
11117 msg = CanBankItem(parentItem->GetBagSlot(), NULL_SLOT, dest, dstItem, true);
11118 if (msg != EQUIP_ERR_OK)
11119 msg = CanBankItem(NULL_BAG, NULL_SLOT, dest, dstItem, true);
11120 }
11121 else if (IsEquipmentPos(src))
11122 return EQUIP_ERR_CANT_SWAP;
11123
11124 return msg;
11125}
11126
11128{
11129 // Applied only to equipped items and bank bags
11130 if (!IsEquipmentPos(pos) && !IsBagPos(pos))
11131 return EQUIP_ERR_OK;
11132
11133 Item* pItem = GetItemByPos(pos);
11134
11135 // Applied only to existing equipped item
11136 if (!pItem)
11137 return EQUIP_ERR_OK;
11138
11139 TC_LOG_DEBUG("entities.player.items", "Player::CanUnequipItem: Player '{}' ({}), Slot: {}, Item: {}, Count: {}",
11140 GetName(), GetGUID().ToString(), pos, pItem->GetEntry(), pItem->GetCount());
11141
11142 ItemTemplate const* pProto = pItem->GetTemplate();
11143 if (!pProto)
11145
11146 // item used
11147 if (pItem->m_lootGenerated)
11148 return EQUIP_ERR_LOOT_GONE;
11149
11150 if (IsCharmed())
11151 return EQUIP_ERR_CLIENT_LOCKED_OUT; // @todo is this the correct error?
11152
11153 // do not allow unequipping gear except weapons, offhands, projectiles, relics in
11154 // - combat
11155 // - in-progress arenas
11156 if (!pProto->CanChangeEquipStateInCombat())
11157 {
11158 if (IsInCombat())
11160
11161 if (Battleground* bg = GetBattleground())
11162 if (bg->isArena() && bg->GetStatus() == STATUS_IN_PROGRESS)
11164 }
11165
11166 if (!swap && pItem->IsNotEmptyBag())
11168
11169 return EQUIP_ERR_OK;
11170}
11171
11172InventoryResult Player::CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec& dest, Item* pItem, bool swap, bool not_loading /*= true*/, bool reagentBankOnly /*= false*/) const
11173{
11174 if (!pItem)
11176
11177 // different slots range if we're trying to store item in Reagent Bank
11178 if (reagentBankOnly)
11179 {
11180 ASSERT(bag == NULL_BAG && slot == NULL_SLOT); // when reagentBankOnly is true then bag & slot must be hardcoded constants, not client input
11181 }
11182
11183 if ((IsReagentBankPos(bag, slot) || reagentBankOnly) && !IsReagentBankUnlocked())
11185
11186 uint8 slotStart = reagentBankOnly ? uint8(REAGENT_SLOT_START) : uint8(BANK_SLOT_ITEM_START);
11187 uint8 slotEnd = reagentBankOnly ? uint8(REAGENT_SLOT_END) : uint8(BANK_SLOT_ITEM_END);
11188
11189 uint32 count = pItem->GetCount();
11190
11191 TC_LOG_DEBUG("entities.player.items", "Player::CanBankItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {}, Count: {}",
11192 GetName(), GetGUID().ToString(), bag, slot, pItem->GetEntry(), pItem->GetCount());
11193 ItemTemplate const* pProto = pItem->GetTemplate();
11194 if (!pProto)
11196
11197 // item used
11198 if (pItem->m_lootGenerated)
11199 return EQUIP_ERR_LOOT_GONE;
11200
11201 if (pItem->IsBindedNotWith(this))
11202 return EQUIP_ERR_NOT_OWNER;
11203
11204 // Currency Tokenizer are not supposed to be swapped out of their hidden bag
11205 if (pItem->IsCurrencyToken())
11206 {
11207 TC_LOG_ERROR("entities.player.cheat", "Possible hacking attempt: Player {} ({}) tried to move token [{} entry: {}] out of the currency bag!",
11208 GetName(), GetGUID().ToString(), pItem->GetGUID().ToString(), pProto->GetId());
11209 return EQUIP_ERR_CANT_SWAP;
11210 }
11211
11212 // check count of items (skip for auto move for same player from bank)
11214 if (res != EQUIP_ERR_OK)
11215 return res;
11216
11217 // in specific slot
11218 if (bag != NULL_BAG && slot != NULL_SLOT)
11219 {
11220 if (slot >= BANK_SLOT_BAG_START && slot < BANK_SLOT_BAG_END)
11221 {
11222 if (!pItem->IsBag())
11223 return EQUIP_ERR_WRONG_SLOT;
11224
11227
11228 res = CanUseItem(pItem, not_loading);
11229 if (res != EQUIP_ERR_OK)
11230 return res;
11231 }
11232
11233 res = CanStoreItem_InSpecificSlot(bag, slot, dest, pProto, count, swap, pItem);
11234 if (res != EQUIP_ERR_OK)
11235 return res;
11236
11237 if (count == 0)
11238 return EQUIP_ERR_OK;
11239 }
11240
11241 // not specific slot or have space for partly store only in specific slot
11242
11243 // in specific bag
11244 if (bag != NULL_BAG)
11245 {
11246 if (pItem->IsNotEmptyBag())
11247 return EQUIP_ERR_BAG_IN_BAG;
11248
11249 // search stack in bag for merge to
11250 if (pProto->GetMaxStackSize() != 1)
11251 {
11252 if (bag == INVENTORY_SLOT_BAG_0)
11253 {
11254 res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, true, pItem, bag, slot);
11255 if (res != EQUIP_ERR_OK)
11256 return res;
11257
11258 if (count == 0)
11259 return EQUIP_ERR_OK;
11260 }
11261 else
11262 {
11263 res = CanStoreItem_InBag(bag, dest, pProto, count, true, false, pItem, NULL_BAG, slot);
11264 if (res != EQUIP_ERR_OK)
11265 res = CanStoreItem_InBag(bag, dest, pProto, count, true, true, pItem, NULL_BAG, slot);
11266
11267 if (res != EQUIP_ERR_OK)
11268 return res;
11269
11270 if (count == 0)
11271 return EQUIP_ERR_OK;
11272 }
11273 }
11274
11275 // search free slot in bag
11276 if (bag == INVENTORY_SLOT_BAG_0)
11277 {
11278 res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, false, pItem, bag, slot);
11279 if (res != EQUIP_ERR_OK)
11280 return res;
11281
11282 if (count == 0)
11283 return EQUIP_ERR_OK;
11284 }
11285 else
11286 {
11287 res = CanStoreItem_InBag(bag, dest, pProto, count, false, false, pItem, NULL_BAG, slot);
11288 if (res != EQUIP_ERR_OK)
11289 res = CanStoreItem_InBag(bag, dest, pProto, count, false, true, pItem, NULL_BAG, slot);
11290
11291 if (res != EQUIP_ERR_OK)
11292 return res;
11293
11294 if (count == 0)
11295 return EQUIP_ERR_OK;
11296 }
11297 }
11298
11299 // not specific bag or have space for partly store only in specific bag
11300
11301 // search stack for merge to
11302 if (pProto->GetMaxStackSize() != 1)
11303 {
11304 // in slots
11305 res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, true, pItem, bag, slot);
11306 if (res != EQUIP_ERR_OK)
11307 return res;
11308
11309 if (count == 0)
11310 return EQUIP_ERR_OK;
11311
11312 // don't try to store reagents anywhere else than in Reagent Bank if we're on it
11313 if (!reagentBankOnly)
11314 {
11315 // in special bags
11316 if (pProto->GetBagFamily())
11317 {
11318 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
11319 {
11320 res = CanStoreItem_InBag(i, dest, pProto, count, true, false, pItem, bag, slot);
11321 if (res != EQUIP_ERR_OK)
11322 continue;
11323
11324 if (count == 0)
11325 return EQUIP_ERR_OK;
11326 }
11327 }
11328
11329 // in regular bags
11330 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
11331 {
11332 res = CanStoreItem_InBag(i, dest, pProto, count, true, true, pItem, bag, slot);
11333 if (res != EQUIP_ERR_OK)
11334 continue;
11335
11336 if (count == 0)
11337 return EQUIP_ERR_OK;
11338 }
11339 }
11340 }
11341
11342 // search free space in special bags (don't try to store reagents anywhere else than in Reagent Bank if we're on it)
11343 if (!reagentBankOnly && pProto->GetBagFamily())
11344 {
11345 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
11346 {
11347 res = CanStoreItem_InBag(i, dest, pProto, count, false, false, pItem, bag, slot);
11348 if (res != EQUIP_ERR_OK)
11349 continue;
11350
11351 if (count == 0)
11352 return EQUIP_ERR_OK;
11353 }
11354 }
11355
11356 // search free space
11357 res = CanStoreItem_InInventorySlots(slotStart, slotEnd, dest, pProto, count, false, pItem, bag, slot);
11358 if (res != EQUIP_ERR_OK)
11359 return res;
11360
11361 if (count == 0)
11362 return EQUIP_ERR_OK;
11363
11364 // search free space in regular bags (don't try to store reagents anywhere else than in Reagent Bank if we're on it)
11365 if (!reagentBankOnly)
11366 {
11367 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
11368 {
11369 res = CanStoreItem_InBag(i, dest, pProto, count, false, true, pItem, bag, slot);
11370 if (res != EQUIP_ERR_OK)
11371 continue;
11372
11373 if (count == 0)
11374 return EQUIP_ERR_OK;
11375 }
11376 }
11377
11378 return reagentBankOnly ? EQUIP_ERR_REAGENT_BANK_FULL : EQUIP_ERR_BANK_FULL;
11379}
11380
11381InventoryResult Player::CanUseItem(Item* pItem, bool not_loading) const
11382{
11383 if (pItem)
11384 {
11385 TC_LOG_DEBUG("entities.player.items", "Player::CanUseItem: Player '{}' ({}), Item: {}",
11386 GetName(), GetGUID().ToString(), pItem->GetEntry());
11387
11388 if (!IsAlive() && not_loading)
11389 return EQUIP_ERR_PLAYER_DEAD;
11390
11391 //if (isStunned())
11392 // return EQUIP_ERR_GENERIC_STUNNED;
11393
11394 ItemTemplate const* pProto = pItem->GetTemplate();
11395 if (pProto)
11396 {
11397 if (pItem->IsBindedNotWith(this))
11398 return EQUIP_ERR_NOT_OWNER;
11399
11400 if (GetLevel() < pItem->GetRequiredLevel())
11402
11403 InventoryResult res = CanUseItem(pProto, true);
11404 if (res != EQUIP_ERR_OK)
11405 return res;
11406
11407 if (pItem->GetSkill() != 0)
11408 {
11409 bool allowEquip = false;
11410 uint32 itemSkill = pItem->GetSkill();
11411 // Armor that is binded to account can "morph" from plate to mail, etc. if skill is not learned yet.
11412 if (pProto->GetQuality() == ITEM_QUALITY_HEIRLOOM && pProto->GetClass() == ITEM_CLASS_ARMOR && !HasSkill(itemSkill))
11413 {
11415 // In fact it's a visual bug, everything works properly... I need sniffs of operations with
11416 // binded to account items from off server.
11417
11418 switch (GetClass())
11419 {
11420 case CLASS_HUNTER:
11421 case CLASS_SHAMAN:
11422 allowEquip = (itemSkill == SKILL_MAIL);
11423 break;
11424 case CLASS_PALADIN:
11425 case CLASS_WARRIOR:
11426 allowEquip = (itemSkill == SKILL_PLATE_MAIL);
11427 break;
11428 }
11429 }
11430 if (!allowEquip && GetSkillValue(itemSkill) == 0)
11432 }
11433
11434 return EQUIP_ERR_OK;
11435 }
11436 }
11438}
11439
11440InventoryResult Player::CanUseItem(ItemTemplate const* proto, bool skipRequiredLevelCheck /*= false*/) const
11441{
11442 // Used by group, function GroupLoot, to know if a prototype can be used by a player
11443
11444 if (!proto)
11446
11449
11450 if (proto->HasFlag(ITEM_FLAG2_FACTION_HORDE) && GetTeam() != HORDE)
11452
11455
11456 if ((proto->GetAllowableClass() & GetClassMask()) == 0 || !proto->GetAllowableRace().HasRace(GetRace()))
11458
11459 if (proto->GetRequiredSkill() != 0)
11460 {
11461 if (GetSkillValue(proto->GetRequiredSkill()) == 0)
11463 else if (GetSkillValue(proto->GetRequiredSkill()) < proto->GetRequiredSkillRank())
11465 }
11466
11467 if (proto->GetRequiredSpell() != 0 && !HasSpell(proto->GetRequiredSpell()))
11469
11470 if (!skipRequiredLevelCheck && GetLevel() < proto->GetBaseRequiredLevel())
11472
11473 // If World Event is not active, prevent using event dependant items
11474 if (proto->GetHolidayID() && !IsHolidayActive(proto->GetHolidayID()))
11476
11479
11480 // learning (recipes, mounts, pets, etc.)
11481 if (proto->Effects.size() >= 2)
11482 if (proto->Effects[0]->SpellID == 483 || proto->Effects[0]->SpellID == 55884)
11483 if (HasSpell(proto->Effects[1]->SpellID))
11485
11486 if (ArtifactEntry const* artifact = sArtifactStore.LookupEntry(proto->GetArtifactID()))
11487 if (ChrSpecialization(artifact->ChrSpecializationID) != GetPrimarySpecialization())
11489
11490 return EQUIP_ERR_OK;
11491}
11492
11493InventoryResult Player::CanRollNeedForItem(ItemTemplate const* proto, Map const* map, bool restrictOnlyLfg) const
11494{
11495 if (restrictOnlyLfg)
11496 {
11497 if (!GetGroup() || !GetGroup()->isLFGGroup())
11498 return EQUIP_ERR_OK; // not in LFG group
11499
11500 // check if looted object is inside the lfg dungeon
11501 if (!sLFGMgr->inLfgDungeonMap(GetGroup()->GetGUID(), map->GetId(), map->GetDifficultyID()))
11502 return EQUIP_ERR_OK;
11503 }
11504
11505 if (!proto)
11507
11508 // Used by group, function GroupLoot, to know if a prototype can be used by a player
11509 if ((proto->GetAllowableClass() & GetClassMask()) == 0 || !proto->GetAllowableRace().HasRace(GetRace()))
11511
11512 if (proto->GetRequiredSpell() != 0 && !HasSpell(proto->GetRequiredSpell()))
11514
11515 if (proto->GetRequiredSkill() != 0)
11516 {
11517 if (!GetSkillValue(proto->GetRequiredSkill()))
11519 else if (GetSkillValue(proto->GetRequiredSkill()) < proto->GetRequiredSkillRank())
11521 }
11522
11523 if (proto->GetClass() == ITEM_CLASS_WEAPON && GetSkillValue(proto->GetSkill()) == 0)
11525
11526 if (proto->GetClass() == ITEM_CLASS_ARMOR && proto->GetInventoryType() != INVTYPE_CLOAK)
11527 {
11528 ChrClassesEntry const* classesEntry = sChrClassesStore.AssertEntry(GetClass());
11529 if (!(classesEntry->ArmorTypeMask & 1 << proto->GetSubClass()))
11531 }
11532
11533 return EQUIP_ERR_OK;
11534}
11535
11536// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
11537Item* Player::StoreNewItem(ItemPosCountVec const& pos, uint32 itemId, bool update, ItemRandomBonusListId randomBonusListId /*= 0*/,
11538 GuidSet const& allowedLooters /*= GuidSet()*/, ItemContext context /*= ItemContext::NONE*/,
11539 std::vector<int32> const* bonusListIDs /*= std::vector<int32>()*/, bool addToCollection /*= true*/)
11540{
11541 uint32 count = 0;
11542 for (ItemPosCountVec::const_iterator itr = pos.begin(); itr != pos.end(); ++itr)
11543 count += itr->count;
11544
11545 // quest objectives must be processed twice - QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM prevents item creation
11546 bool hadBoundItemObjective = false;
11547 ItemAddedQuestCheck(itemId, count, true, &hadBoundItemObjective);
11548 if (hadBoundItemObjective)
11549 return nullptr;
11550
11551 Item* item = Item::CreateItem(itemId, count, context, this, bonusListIDs == nullptr);
11552 if (item)
11553 {
11555
11556 if (bonusListIDs)
11557 item->SetBonuses(*bonusListIDs);
11558
11559 item = StoreItem(pos, item, update);
11560
11561 ItemAddedQuestCheck(itemId, count, false);
11564
11565 item->SetFixedLevel(GetLevel());
11566 item->SetItemRandomBonusList(randomBonusListId);
11567
11568 if (allowedLooters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound())
11569 {
11570 item->SetSoulboundTradeable(allowedLooters);
11572 AddTradeableItem(item);
11573
11574 // save data
11575 std::ostringstream ss;
11576 GuidSet::const_iterator itr = allowedLooters.begin();
11577 ss << itr->GetCounter();
11578 for (++itr; itr != allowedLooters.end(); ++itr)
11579 ss << ' ' << itr->GetCounter();
11580
11582 stmt->setUInt64(0, item->GetGUID().GetCounter());
11583 stmt->setString(1, ss.str());
11584 CharacterDatabase.Execute(stmt);
11585 }
11586
11587 if (addToCollection)
11589
11590 if (ItemChildEquipmentEntry const* childItemEntry = sDB2Manager.GetItemChildEquipment(itemId))
11591 {
11592 if (ItemTemplate const* childTemplate = sObjectMgr->GetItemTemplate(childItemEntry->ChildItemID))
11593 {
11594 ItemPosCountVec childDest;
11595 CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, childDest, childTemplate, count, false, nullptr, NULL_BAG, NULL_SLOT);
11596 if (Item* childItem = StoreNewItem(childDest, childTemplate->GetId(), update, {}, {}, context, nullptr, addToCollection))
11597 {
11598 childItem->SetCreator(item->GetGUID());
11599 childItem->SetItemFlag(ITEM_FIELD_FLAG_CHILD);
11600 item->SetChildItem(childItem->GetGUID());
11601 }
11602 }
11603 }
11604
11607 }
11608
11609 return item;
11610}
11611
11612Item* Player::StoreItem(ItemPosCountVec const& dest, Item* pItem, bool update)
11613{
11614 if (!pItem)
11615 return nullptr;
11616
11617 Item* lastItem = pItem;
11618 for (ItemPosCountVec::const_iterator itr = dest.begin(); itr != dest.end();)
11619 {
11620 uint16 pos = itr->pos;
11621 uint32 count = itr->count;
11622
11623 ++itr;
11624
11625 if (itr == dest.end())
11626 {
11627 lastItem = _StoreItem(pos, pItem, count, false, update);
11628 break;
11629 }
11630
11631 lastItem = _StoreItem(pos, pItem, count, true, update);
11632 }
11633
11634 AutoUnequipChildItem(lastItem);
11635
11636 return lastItem;
11637}
11638
11639// Return stored item (if stored to stack, it can diff. from pItem). And pItem ca be deleted in this case.
11640Item* Player::_StoreItem(uint16 pos, Item* pItem, uint32 count, bool clone, bool update)
11641{
11642 if (!pItem)
11643 return nullptr;
11644
11645 uint8 bag = pos >> 8;
11646 uint8 slot = pos & 255;
11647
11648 TC_LOG_DEBUG("entities.player.items", "Player::_StoreItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {} ({}), Count: {}",
11649 GetName(), GetGUID().ToString(), bag, slot, pItem->GetEntry(), pItem->GetGUID().ToString(), count);
11650
11651 Item* pItem2 = GetItemByPos(bag, slot);
11652
11653 if (!pItem2)
11654 {
11655 if (clone)
11656 pItem = pItem->CloneItem(count, this);
11657 else
11658 pItem->SetCount(count);
11659
11660 if (!pItem)
11661 return nullptr;
11662
11663 if (pItem->GetBonding() == BIND_ON_ACQUIRE ||
11664 pItem->GetBonding() == BIND_QUEST ||
11665 (pItem->GetBonding() == BIND_ON_EQUIP && IsBagPos(pos)))
11666 pItem->SetBinding(true);
11667
11668 Bag* pBag = (bag == INVENTORY_SLOT_BAG_0) ? nullptr : GetBagByPos(bag);
11669 if (!pBag)
11670 {
11671 m_items[slot] = pItem;
11672 SetInvSlot(slot, pItem->GetGUID());
11673 pItem->SetContainedIn(GetGUID());
11674 pItem->SetOwnerGUID(GetGUID());
11675
11676 pItem->SetSlot(slot);
11677 pItem->SetContainer(nullptr);
11678 }
11679 else
11680 pBag->StoreItem(slot, pItem, update);
11681
11682 if (IsInWorld() && update)
11683 {
11684 pItem->AddToWorld();
11685 pItem->SendUpdateToPlayer(this);
11686 }
11687
11688 pItem->SetState(ITEM_CHANGED, this);
11689 if (pBag)
11690 pBag->SetState(ITEM_CHANGED, this);
11691
11693 AddItemDurations(pItem);
11694
11696 ApplyItemObtainSpells(pItem, true);
11697
11698 return pItem;
11699 }
11700 else
11701 {
11702 if (pItem2->GetBonding() == BIND_ON_ACQUIRE ||
11703 pItem2->GetBonding() == BIND_QUEST ||
11704 (pItem2->GetBonding() == BIND_ON_EQUIP && IsBagPos(pos)))
11705 pItem2->SetBinding(true);
11706
11707 pItem2->SetCount(pItem2->GetCount() + count);
11708 if (IsInWorld() && update)
11709 pItem2->SendUpdateToPlayer(this);
11710
11711 if (!clone)
11712 {
11713 // delete item (it not in any slot currently)
11714 if (IsInWorld() && update)
11715 {
11716 pItem->RemoveFromWorld();
11717 pItem->DestroyForPlayer(this);
11718 }
11719
11721 RemoveItemDurations(pItem);
11722
11723 pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
11724 pItem->SetNotRefundable(this);
11725 pItem->ClearSoulboundTradeable(this);
11726 RemoveTradeableItem(pItem);
11727 pItem->SetState(ITEM_REMOVED, this);
11728 }
11729
11731
11732 pItem2->SetState(ITEM_CHANGED, this);
11733
11735 ApplyItemObtainSpells(pItem2, true);
11736
11737 return pItem2;
11738 }
11739}
11740
11741Item* Player::EquipNewItem(uint16 pos, uint32 item, ItemContext context, bool update)
11742{
11743 if (Item* pItem = Item::CreateItem(item, 1, context, this))
11744 {
11746 Item* equippedItem = EquipItem(pos, pItem, update);
11747 ItemAddedQuestCheck(item, 1);
11748 return equippedItem;
11749 }
11750
11751 return nullptr;
11752}
11753
11754Item* Player::EquipItem(uint16 pos, Item* pItem, bool update)
11755{
11757 AddItemDurations(pItem);
11758
11759 uint8 bag = pos >> 8;
11760 uint8 slot = pos & 255;
11761
11762 Item* pItem2 = GetItemByPos(bag, slot);
11763
11764 if (!pItem2)
11765 {
11766 VisualizeItem(slot, pItem);
11767
11768 if (IsAlive())
11769 {
11770 ItemTemplate const* pProto = pItem->GetTemplate();
11771
11772 // item set bonuses applied only at equip and removed at unequip, and still active for broken items
11773 if (pProto && pProto->GetItemSet())
11774 AddItemsSetItem(this, pItem);
11775
11776 _ApplyItemMods(pItem, slot, true);
11777
11778 if (pProto && IsInCombat() && (pProto->GetClass() == ITEM_CLASS_WEAPON || pProto->GetInventoryType() == INVTYPE_RELIC) && m_weaponChangeTimer == 0)
11779 {
11780 uint32 cooldownSpell = GetClass() == CLASS_ROGUE ? 6123 : 6119;
11781 SpellInfo const* spellProto = sSpellMgr->GetSpellInfo(cooldownSpell, DIFFICULTY_NONE);
11782
11783 if (!spellProto)
11784 TC_LOG_ERROR("entities.player", "Player::EquipItem: Weapon switch cooldown spell {} for player '{}' ({}) couldn't be found in Spell.dbc",
11785 cooldownSpell, GetName(), GetGUID().ToString());
11786 else
11787 {
11789
11791
11793 spellCooldown.Caster = GetGUID();
11794 spellCooldown.Flags = SPELL_COOLDOWN_FLAG_INCLUDE_GCD;
11795 spellCooldown.SpellCooldowns.emplace_back(cooldownSpell, 0);
11796 SendDirectMessage(spellCooldown.Write());
11797 }
11798 }
11799 }
11800
11802
11803 if (IsInWorld() && update)
11804 {
11805 pItem->AddToWorld();
11806 pItem->SendUpdateToPlayer(this);
11807 }
11808
11809 ApplyEquipCooldown(pItem);
11810
11811 // update expertise and armor penetration - passive auras may need it
11812
11813 if (slot == EQUIPMENT_SLOT_MAINHAND)
11815
11816 else if (slot == EQUIPMENT_SLOT_OFFHAND)
11818
11819 switch (slot)
11820 {
11824 break;
11825 default:
11826 break;
11827 }
11828 }
11829 else
11830 {
11831 pItem2->SetCount(pItem2->GetCount() + pItem->GetCount());
11832 if (IsInWorld() && update)
11833 pItem2->SendUpdateToPlayer(this);
11834
11835 // delete item (it not in any slot currently)
11836 //pItem->DeleteFromDB();
11837 if (IsInWorld() && update)
11838 {
11839 pItem->RemoveFromWorld();
11840 pItem->DestroyForPlayer(this);
11841 }
11842
11844 RemoveItemDurations(pItem);
11845
11846 pItem->SetOwnerGUID(GetGUID()); // prevent error at next SetState in case trade/mail/buy from vendor
11847 pItem->SetNotRefundable(this);
11848 pItem->ClearSoulboundTradeable(this);
11849 RemoveTradeableItem(pItem);
11850 pItem->SetState(ITEM_REMOVED, this);
11851 pItem2->SetState(ITEM_CHANGED, this);
11852
11853 ApplyEquipCooldown(pItem2);
11854
11855 return pItem2;
11856 }
11857
11858 if (slot == EQUIPMENT_SLOT_MAINHAND || slot == EQUIPMENT_SLOT_OFFHAND)
11860
11861 // only for full equip instead adding to stack
11864
11866
11867 return pItem;
11868}
11869
11870void Player::EquipChildItem(uint8 parentBag, uint8 parentSlot, Item* parentItem)
11871{
11872 if (ItemChildEquipmentEntry const* itemChildEquipment = sDB2Manager.GetItemChildEquipment(parentItem->GetEntry()))
11873 {
11874 if (Item* childItem = GetChildItemByGuid(parentItem->GetChildItem()))
11875 {
11876 uint16 childDest = (INVENTORY_SLOT_BAG_0 << 8) | itemChildEquipment->ChildItemEquipSlot;
11877 if (childItem->GetPos() != childDest)
11878 {
11879 Item* dstItem = GetItemByPos(childDest);
11880 if (!dstItem) // empty slot, simple case
11881 {
11882 RemoveItem(childItem->GetBagSlot(), childItem->GetSlot(), true);
11883 EquipItem(childDest, childItem, true);
11885 }
11886 else // have currently equipped item, not simple case
11887 {
11888 uint8 dstbag = dstItem->GetBagSlot();
11889 uint8 dstslot = dstItem->GetSlot();
11890
11891 InventoryResult msg = CanUnequipItem(childDest, !childItem->IsBag());
11892 if (msg != EQUIP_ERR_OK)
11893 {
11894 SendEquipError(msg, dstItem);
11895 return;
11896 }
11897
11898 // check dest->src move possibility but try to store currently equipped item in the bag where the parent item is
11899 ItemPosCountVec sSrc;
11900 uint16 eSrc = 0;
11901 if (IsInventoryPos(parentBag, parentSlot))
11902 {
11903 msg = CanStoreItem(parentBag, NULL_SLOT, sSrc, dstItem, true);
11904 if (msg != EQUIP_ERR_OK)
11905 msg = CanStoreItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
11906 }
11907 else if (IsBankPos(parentBag, parentSlot))
11908 {
11909 msg = CanBankItem(parentBag, NULL_SLOT, sSrc, dstItem, true);
11910 if (msg != EQUIP_ERR_OK)
11911 msg = CanBankItem(NULL_BAG, NULL_SLOT, sSrc, dstItem, true);
11912 }
11913 else if (IsEquipmentPos(parentBag, parentSlot))
11914 {
11915 msg = CanEquipItem(parentSlot, eSrc, dstItem, true);
11916 if (msg == EQUIP_ERR_OK)
11917 msg = CanUnequipItem(eSrc, true);
11918 }
11919
11920 if (msg != EQUIP_ERR_OK)
11921 {
11922 SendEquipError(msg, dstItem, childItem);
11923 return;
11924 }
11925
11926 // now do moves, remove...
11927 RemoveItem(dstbag, dstslot, false);
11928 RemoveItem(childItem->GetBagSlot(), childItem->GetSlot(), false);
11929
11930 // add to dest
11931 EquipItem(childDest, childItem, true);
11932
11933 // add to src
11934 if (IsInventoryPos(parentBag, parentSlot))
11935 StoreItem(sSrc, dstItem, true);
11936 else if (IsBankPos(parentBag, parentSlot))
11937 BankItem(sSrc, dstItem, true);
11938 else if (IsEquipmentPos(parentBag, parentSlot))
11939 EquipItem(eSrc, dstItem, true);
11940
11942 }
11943 }
11944 }
11945 }
11946}
11947
11949{
11950 if (sDB2Manager.GetItemChildEquipment(parentItem->GetEntry()))
11951 {
11952 if (Item* childItem = GetChildItemByGuid(parentItem->GetChildItem()))
11953 {
11954 if (IsChildEquipmentPos(childItem->GetPos()))
11955 return;
11956
11957 ItemPosCountVec dest;
11958 uint32 count = childItem->GetCount();
11959 InventoryResult result = CanStoreItem_InInventorySlots(CHILD_EQUIPMENT_SLOT_START, CHILD_EQUIPMENT_SLOT_END, dest, childItem->GetTemplate(), count, false, childItem, NULL_BAG, NULL_SLOT);
11960 if (result != EQUIP_ERR_OK)
11961 return;
11962
11963 RemoveItem(childItem->GetBagSlot(), childItem->GetSlot(), true);
11964 StoreItem(dest, childItem, true);
11965 }
11966 }
11967}
11968
11970{
11971 if (pItem)
11972 {
11974 AddItemDurations(pItem);
11975
11976 uint8 slot = pos & 255;
11977 VisualizeItem(slot, pItem);
11978
11980
11981 if (IsInWorld())
11982 {
11983 pItem->AddToWorld();
11984 pItem->SendUpdateToPlayer(this);
11985 }
11986
11987 if (slot == EQUIPMENT_SLOT_MAINHAND || slot == EQUIPMENT_SLOT_OFFHAND)
11989
11992 }
11993}
11994
11996{
11997 auto itemField = m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::VisibleItems, slot);
11998 if (pItem)
11999 {
12000 SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemID), pItem->GetVisibleEntry(this));
12003 SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemVisual), pItem->GetVisibleItemVisual(this));
12004 }
12005 else
12006 {
12007 SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemID), 0);
12010 SetUpdateFieldValue(itemField.ModifyValue(&UF::VisibleItem::ItemVisual), 0);
12011 }
12012}
12013
12015{
12016 if (!pItem)
12017 return;
12018
12019 // check also BIND_ON_ACQUIRE and BIND_QUEST for .additem or .additemset case by GM (not binded at adding to inventory)
12020 if (pItem->GetBonding() == BIND_ON_EQUIP || pItem->GetBonding() == BIND_ON_ACQUIRE || pItem->GetBonding() == BIND_QUEST)
12021 {
12022 pItem->SetBinding(true);
12023 if (IsInWorld())
12025 }
12026
12027 TC_LOG_DEBUG("entities.player.items", "Player::SetVisibleItemSlot: Player '{}' ({}), Slot: {}, Item: {}",
12028 GetName(), GetGUID().ToString(), slot, pItem->GetEntry());
12029
12030 m_items[slot] = pItem;
12031 SetInvSlot(slot, pItem->GetGUID());
12032 pItem->SetContainedIn(GetGUID());
12033 pItem->SetOwnerGUID(GetGUID());
12034 pItem->SetSlot(slot);
12035 pItem->SetContainer(nullptr);
12036
12037 if (slot < EQUIPMENT_SLOT_END)
12038 SetVisibleItemSlot(slot, pItem);
12039
12040 pItem->SetState(ITEM_CHANGED, this);
12041}
12042
12043Item* Player::BankItem(ItemPosCountVec const& dest, Item* pItem, bool update)
12044{
12045 return StoreItem(dest, pItem, update);
12046}
12047
12048void Player::RemoveItem(uint8 bag, uint8 slot, bool update)
12049{
12050 // note: removeitem does not actually change the item
12051 // it only takes the item out of storage temporarily
12052 // note2: if removeitem is to be used for delinking
12053 // the item must be removed from the player's updatequeue
12054
12055 Item* pItem = GetItemByPos(bag, slot);
12056 if (pItem)
12057 {
12058 TC_LOG_DEBUG("entities.player.items", "Player::RemoveItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {}",
12059 GetName(), GetGUID().ToString(), bag, slot, pItem->GetEntry());
12060
12062 RemoveItemDurations(pItem);
12063 RemoveTradeableItem(pItem);
12064
12065 if (bag == INVENTORY_SLOT_BAG_0)
12066 {
12067 if (slot < INVENTORY_SLOT_BAG_END)
12068 {
12069 // item set bonuses applied only at equip and removed at unequip, and still active for broken items
12070 ItemTemplate const* pProto = ASSERT_NOTNULL(pItem->GetTemplate());
12071 if (pProto->GetItemSet())
12072 RemoveItemsSetItem(this, pItem);
12073
12074 _ApplyItemMods(pItem, slot, false, update);
12075
12077
12078 // remove item dependent auras and casts (only weapon and armor slots)
12079 if (slot < PROFESSION_SLOT_END)
12080 {
12081 // update expertise
12082 if (slot == EQUIPMENT_SLOT_MAINHAND)
12083 {
12084 // clear main hand only enchantments
12085 for (uint32 enchantSlot = 0; enchantSlot < MAX_ENCHANTMENT_SLOT; ++enchantSlot)
12086 if (SpellItemEnchantmentEntry const* enchantment = sSpellItemEnchantmentStore.LookupEntry(pItem->GetEnchantmentId(EnchantmentSlot(enchantSlot))))
12087 if (enchantment->GetFlags().HasFlag(SpellItemEnchantmentFlags::MainhandOnly))
12088 pItem->ClearEnchantment(EnchantmentSlot(enchantSlot));
12089
12091 }
12092 else if (slot == EQUIPMENT_SLOT_OFFHAND)
12094 // update armor penetration - passive auras may need it
12095 switch (slot)
12096 {
12100 break;
12101 default:
12102 break;
12103 }
12104 }
12105 }
12106
12107 m_items[slot] = nullptr;
12109
12110 if (slot < EQUIPMENT_SLOT_END)
12111 {
12112 SetVisibleItemSlot(slot, nullptr);
12113 if (slot == EQUIPMENT_SLOT_MAINHAND || slot == EQUIPMENT_SLOT_OFFHAND)
12115 }
12116 }
12117 else if (Bag* pBag = GetBagByPos(bag))
12118 pBag->RemoveItem(slot, update);
12119
12121 // pItem->SetUInt64Value(ITEM_FIELD_OWNER, 0); not clear owner at remove (it will be set at store). This used in mail and auction code
12122 pItem->SetSlot(NULL_SLOT);
12123 if (IsInWorld() && update)
12124 pItem->SendUpdateToPlayer(this);
12125
12126 AutoUnequipChildItem(pItem);
12127
12128 if (bag == INVENTORY_SLOT_BAG_0)
12130 }
12131}
12132
12133// Common operation need to remove item from inventory without delete in trade, auction, guild bank, mail....
12134void Player::MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
12135{
12136 if (Item* it = GetItemByPos(bag, slot))
12137 {
12138 RemoveItem(bag, slot, update);
12139 ItemRemovedQuestCheck(it->GetEntry(), it->GetCount());
12140 it->SetNotRefundable(this, false, nullptr, false);
12143 if (it->IsInWorld())
12144 {
12145 it->RemoveFromWorld();
12146 it->DestroyForPlayer(this);
12147 }
12148 }
12149}
12150
12151// Common operation need to add item from inventory without delete in trade, guild bank, mail....
12152void Player::MoveItemToInventory(ItemPosCountVec const& dest, Item* pItem, bool update, bool in_characterInventoryDB)
12153{
12154 uint32 itemId = pItem->GetEntry();
12155 uint32 count = pItem->GetCount();
12156
12157 // store item
12158 Item* pLastItem = StoreItem(dest, pItem, update);
12159
12160 // only set if not merged to existing stack (pItem can be deleted already but we can compare pointers any way)
12161 if (pLastItem == pItem)
12162 {
12163 // update owner for last item (this can be original item with wrong owner
12164 if (pLastItem->GetOwnerGUID() != GetGUID())
12165 pLastItem->SetOwnerGUID(GetGUID());
12166
12167 // if this original item then it need create record in inventory
12168 // in case trade we already have item in other player inventory
12169 pLastItem->SetState(in_characterInventoryDB ? ITEM_CHANGED : ITEM_NEW, this);
12170
12171 if (pLastItem->IsBOPTradeable())
12172 AddTradeableItem(pLastItem);
12173 }
12174
12175 // update quest counters
12176 ItemAddedQuestCheck(itemId, count);
12178}
12179
12180void Player::DestroyItem(uint8 bag, uint8 slot, bool update)
12181{
12182 Item* pItem = GetItemByPos(bag, slot);
12183 if (pItem)
12184 {
12185 TC_LOG_DEBUG("entities.player.items", "Player::DestroyItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {}",
12186 GetName(), GetGUID().ToString(), bag, slot, pItem->GetEntry());
12187 // Also remove all contained items if the item is a bag.
12188 // This if () prevents item saving crashes if the condition for a bag to be empty before being destroyed was bypassed somehow.
12189 if (pItem->IsNotEmptyBag())
12190 for (uint8 i = 0; i < MAX_BAG_SIZE; ++i)
12191 DestroyItem(slot, i, update);
12192
12193 if (pItem->IsWrapped())
12194 {
12196
12197 stmt->setUInt64(0, pItem->GetGUID().GetCounter());
12198
12199 CharacterDatabase.Execute(stmt);
12200 }
12201
12203 RemoveItemDurations(pItem);
12204
12205 pItem->SetNotRefundable(this);
12206 pItem->ClearSoulboundTradeable(this);
12207 RemoveTradeableItem(pItem);
12208
12209 ApplyItemObtainSpells(pItem, false);
12210 ApplyItemLootedSpell(pItem, false);
12211
12212 sScriptMgr->OnItemRemove(this, pItem);
12213
12214 ItemTemplate const* pProto = pItem->GetTemplate();
12215 if (bag == INVENTORY_SLOT_BAG_0)
12216 {
12218
12219 // equipment and equipped bags can have applied bonuses
12220 if (slot < INVENTORY_SLOT_BAG_END)
12221 {
12222 // item set bonuses applied only at equip and removed at unequip, and still active for broken items
12223 if (pProto->GetItemSet())
12224 RemoveItemsSetItem(this, pItem);
12225
12226 _ApplyItemMods(pItem, slot, false);
12227 }
12228
12229 if (slot < EQUIPMENT_SLOT_END)
12230 {
12231 // update expertise and armor penetration - passive auras may need it
12232 switch (slot)
12233 {
12237 break;
12238 default:
12239 break;
12240 }
12241
12242 if (slot == EQUIPMENT_SLOT_MAINHAND)
12244 else if (slot == EQUIPMENT_SLOT_OFFHAND)
12246
12247 // equipment visual show
12248 SetVisibleItemSlot(slot, nullptr);
12249 }
12250
12251 m_items[slot] = nullptr;
12252 }
12253 else if (Bag* pBag = GetBagByPos(bag))
12254 pBag->RemoveItem(slot, update);
12255
12256 // Delete rolled money / loot from db.
12257 // MUST be done before RemoveFromWorld() or GetTemplate() fails
12258 if (pProto->HasFlag(ITEM_FLAG_HAS_LOOT))
12259 sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
12260
12261 ItemRemovedQuestCheck(pItem->GetEntry(), pItem->GetCount());
12262
12263 if (IsInWorld() && update)
12264 {
12265 pItem->RemoveFromWorld();
12266 pItem->DestroyForPlayer(this);
12267 }
12268
12269 //pItem->SetOwnerGUID(0);
12271 pItem->SetSlot(NULL_SLOT);
12272 pItem->SetState(ITEM_REMOVED, this);
12273
12274 if (pProto->GetInventoryType() != INVTYPE_NON_EQUIP)
12276 if (bag == INVENTORY_SLOT_BAG_0)
12278 }
12279}
12280
12281uint32 Player::DestroyItemCount(uint32 itemEntry, uint32 count, bool update, bool unequip_check)
12282{
12283 TC_LOG_DEBUG("entities.player.items", "Player::DestroyItemCount: Player '{}' ({}), Item: {}, Count: {}",
12284 GetName(), GetGUID().ToString(), itemEntry, count);
12285 uint32 remcount = 0;
12286
12287 // in inventory
12289 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; ++i)
12290 {
12291 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12292 {
12293 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12294 {
12295 if (item->GetCount() + remcount <= count)
12296 {
12297 // all items in inventory can unequipped
12298 remcount += item->GetCount();
12300
12301 if (remcount >= count)
12302 return remcount;
12303 }
12304 else
12305 {
12306 item->SetCount(item->GetCount() - count + remcount);
12307 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12308 if (IsInWorld() && update)
12309 item->SendUpdateToPlayer(this);
12310 item->SetState(ITEM_CHANGED, this);
12311 return count;
12312 }
12313 }
12314 }
12315 }
12316
12317 // in inventory bags
12319 {
12320 if (Bag* bag = GetBagByPos(i))
12321 {
12322 for (uint32 j = 0; j < bag->GetBagSize(); j++)
12323 {
12324 if (Item* item = bag->GetItemByPos(j))
12325 {
12326 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12327 {
12328 // all items in bags can be unequipped
12329 if (item->GetCount() + remcount <= count)
12330 {
12331 remcount += item->GetCount();
12332 DestroyItem(i, j, update);
12333
12334 if (remcount >= count)
12335 return remcount;
12336 }
12337 else
12338 {
12339 item->SetCount(item->GetCount() - count + remcount);
12340 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12341 if (IsInWorld() && update)
12342 item->SendUpdateToPlayer(this);
12343 item->SetState(ITEM_CHANGED, this);
12344 return count;
12345 }
12346 }
12347 }
12348 }
12349 }
12350 }
12351
12352 // in equipment and bag list
12354 {
12355 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12356 {
12357 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12358 {
12359 if (item->GetCount() + remcount <= count)
12360 {
12361 if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false) == EQUIP_ERR_OK)
12362 {
12363 remcount += item->GetCount();
12365
12366 if (remcount >= count)
12367 return remcount;
12368 }
12369 }
12370 else
12371 {
12372 item->SetCount(item->GetCount() - count + remcount);
12373 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12374 if (IsInWorld() && update)
12375 item->SendUpdateToPlayer(this);
12376 item->SetState(ITEM_CHANGED, this);
12377 return count;
12378 }
12379 }
12380 }
12381 }
12382
12383 // in bank
12385 {
12386 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12387 {
12388 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12389 {
12390 if (item->GetCount() + remcount <= count)
12391 {
12392 remcount += item->GetCount();
12394 if (remcount >= count)
12395 return remcount;
12396 }
12397 else
12398 {
12399 item->SetCount(item->GetCount() - count + remcount);
12400 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12401 if (IsInWorld() && update)
12402 item->SendUpdateToPlayer(this);
12403 item->SetState(ITEM_CHANGED, this);
12404 return count;
12405 }
12406 }
12407 }
12408 }
12409
12410 // in bank bags
12411 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
12412 {
12413 if (Bag* bag = GetBagByPos(i))
12414 {
12415 for (uint32 j = 0; j < bag->GetBagSize(); j++)
12416 {
12417 if (Item* item = bag->GetItemByPos(j))
12418 {
12419 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12420 {
12421 // all items in bags can be unequipped
12422 if (item->GetCount() + remcount <= count)
12423 {
12424 remcount += item->GetCount();
12425 DestroyItem(i, j, update);
12426
12427 if (remcount >= count)
12428 return remcount;
12429 }
12430 else
12431 {
12432 item->SetCount(item->GetCount() - count + remcount);
12433 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12434 if (IsInWorld() && update)
12435 item->SendUpdateToPlayer(this);
12436 item->SetState(ITEM_CHANGED, this);
12437 return count;
12438 }
12439 }
12440 }
12441 }
12442 }
12443 }
12444
12445 // in bank bag list
12446 for (uint8 i = BANK_SLOT_BAG_START; i < BANK_SLOT_BAG_END; i++)
12447 {
12448 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12449 {
12450 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12451 {
12452 if (item->GetCount() + remcount <= count)
12453 {
12454 if (!unequip_check || CanUnequipItem(INVENTORY_SLOT_BAG_0 << 8 | i, false) == EQUIP_ERR_OK)
12455 {
12456 remcount += item->GetCount();
12458 if (remcount >= count)
12459 return remcount;
12460 }
12461 }
12462 else
12463 {
12464 item->SetCount(item->GetCount() - count + remcount);
12465 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12466 if (IsInWorld() && update)
12467 item->SendUpdateToPlayer(this);
12468 item->SetState(ITEM_CHANGED, this);
12469 return count;
12470 }
12471 }
12472 }
12473 }
12474
12475 for (uint8 i = REAGENT_SLOT_START; i < REAGENT_SLOT_END; ++i)
12476 {
12477 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12478 {
12479 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12480 {
12481 if (item->GetCount() + remcount <= count)
12482 {
12483 // all keys can be unequipped
12484 remcount += item->GetCount();
12486
12487 if (remcount >= count)
12488 return remcount;
12489 }
12490 else
12491 {
12492 item->SetCount(item->GetCount() - count + remcount);
12493 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12494 if (IsInWorld() && update)
12495 item->SendUpdateToPlayer(this);
12496 item->SetState(ITEM_CHANGED, this);
12497 return count;
12498 }
12499 }
12500 }
12501 }
12502
12504 {
12505 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12506 {
12507 if (item->GetEntry() == itemEntry && !item->IsInTrade())
12508 {
12509 if (item->GetCount() + remcount <= count)
12510 {
12511 // all keys can be unequipped
12512 remcount += item->GetCount();
12514
12515 if (remcount >= count)
12516 return remcount;
12517 }
12518 else
12519 {
12520 item->SetCount(item->GetCount() - count + remcount);
12521 ItemRemovedQuestCheck(item->GetEntry(), count - remcount);
12522 if (IsInWorld() && update)
12523 item->SendUpdateToPlayer(this);
12524 item->SetState(ITEM_CHANGED, this);
12525 return count;
12526 }
12527 }
12528 }
12529 }
12530 return remcount;
12531}
12532
12533void Player::DestroyZoneLimitedItem(bool update, uint32 new_zone)
12534{
12535 TC_LOG_DEBUG("entities.player.items", "Player::DestroyZoneLimitedItem: In map {} and area {} for player '{}' ({})",
12536 GetMapId(), new_zone, GetName(), GetGUID().ToString());
12537
12538 // in inventory
12540 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; i++)
12541 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12542 if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone))
12544
12545 // in inventory bags
12547 if (Bag* pBag = GetBagByPos(i))
12548 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
12549 if (Item* pItem = pBag->GetItemByPos(j))
12550 if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone))
12551 DestroyItem(i, j, update);
12552
12553 // in equipment and bag list
12555 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12556 if (pItem->IsLimitedToAnotherMapOrZone(GetMapId(), new_zone))
12558}
12559
12561{
12562 // used when entering arena
12563 // destroys all conjured items
12564 TC_LOG_DEBUG("entities.player.items", "Player::DestroyConjuredItems: Player '{}' ({})",
12565 GetName(), GetGUID().ToString());
12566
12567 // in inventory
12569 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; i++)
12570 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12571 if (pItem->IsConjuredConsumable())
12573
12574 // in inventory bags
12576 if (Bag* pBag = GetBagByPos(i))
12577 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
12578 if (Item* pItem = pBag->GetItemByPos(j))
12579 if (pItem->IsConjuredConsumable())
12580 DestroyItem(i, j, update);
12581
12582 // in equipment and bag list
12584 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
12585 if (pItem->IsConjuredConsumable())
12587}
12588
12589Item* Player::GetItemByEntry(uint32 entry, ItemSearchLocation where /*= ItemSearchLocation::Default */) const
12590{
12591 Item* result = nullptr;
12592 ForEachItem(where, [&result, entry](Item* item)
12593 {
12594 if (item->GetEntry() == entry)
12595 {
12596 result = item;
12597 return ItemSearchCallbackResult::Stop;
12598 }
12599
12601 });
12602 return result;
12603}
12604
12605std::vector<Item*> Player::GetItemListByEntry(uint32 entry, bool inBankAlso) const
12606{
12608 if (inBankAlso)
12609 location |= ItemSearchLocation::Bank;
12610
12611 std::vector<Item*> itemList = std::vector<Item*>();
12612 ForEachItem(location, [&itemList, entry](Item* item)
12613 {
12614 if (item->GetEntry() == entry)
12615 itemList.push_back(item);
12616
12618 });
12619 return itemList;
12620}
12621
12622void Player::DestroyItemCount(Item* pItem, uint32 &count, bool update)
12623{
12624 if (!pItem)
12625 return;
12626
12627 TC_LOG_DEBUG("entities.player.items", "Player::DestroyItemCount: Player '{}' ({}), Item ({}, Entry: {}), Count: {}",
12628 GetName(), GetGUID().ToString(), pItem->GetGUID().ToString(), pItem->GetEntry(), count);
12629
12630 if (pItem->GetCount() <= count)
12631 {
12632 count -= pItem->GetCount();
12633
12634 DestroyItem(pItem->GetBagSlot(), pItem->GetSlot(), update);
12635 }
12636 else
12637 {
12638 pItem->SetCount(pItem->GetCount() - count);
12639 ItemRemovedQuestCheck(pItem->GetEntry(), count);
12640 count = 0;
12641 if (IsInWorld() && update)
12642 pItem->SendUpdateToPlayer(this);
12643 pItem->SetState(ITEM_CHANGED, this);
12644 }
12645}
12646
12648{
12649 uint8 srcbag = src >> 8;
12650 uint8 srcslot = src & 255;
12651
12652 uint8 dstbag = dst >> 8;
12653 uint8 dstslot = dst & 255;
12654
12655 Item* pSrcItem = GetItemByPos(srcbag, srcslot);
12656 if (!pSrcItem)
12657 {
12658 SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, nullptr);
12659 return;
12660 }
12661
12662 if (pSrcItem->m_lootGenerated) // prevent split looting item (item
12663 {
12664 //best error message found for attempting to split while looting
12665 SendEquipError(EQUIP_ERR_SPLIT_FAILED, pSrcItem, nullptr);
12666 return;
12667 }
12668
12669 // not let split all items (can be only at cheating)
12670 if (pSrcItem->GetCount() == count)
12671 {
12672 SendEquipError(EQUIP_ERR_SPLIT_FAILED, pSrcItem, nullptr);
12673 return;
12674 }
12675
12676 // not let split more existing items (can be only at cheating)
12677 if (pSrcItem->GetCount() < count)
12678 {
12679 SendEquipError(EQUIP_ERR_TOO_FEW_TO_SPLIT, pSrcItem, nullptr);
12680 return;
12681 }
12682
12684 if (TradeData* tradeData = GetTradeData())
12685 {
12687 if (tradeData->GetTradeSlotForItem(pSrcItem->GetGUID()) != TRADE_SLOT_INVALID)
12688 return;
12689 }
12690
12691 TC_LOG_DEBUG("entities.player.items", "Player::SplitItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {}, Count: {}",
12692 GetName(), GetGUID().ToString(), dstbag, dstslot, pSrcItem->GetEntry(), count);
12693 Item* pNewItem = pSrcItem->CloneItem(count, this);
12694 if (!pNewItem)
12695 {
12696 SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, pSrcItem, nullptr);
12697 return;
12698 }
12699
12700 if (IsInventoryPos(dst))
12701 {
12702 // change item amount before check (for unique max count check)
12703 pSrcItem->SetCount(pSrcItem->GetCount() - count);
12704
12705 ItemPosCountVec dest;
12706 InventoryResult msg = CanStoreItem(dstbag, dstslot, dest, pNewItem, false);
12707 if (msg != EQUIP_ERR_OK)
12708 {
12709 delete pNewItem;
12710 pSrcItem->SetCount(pSrcItem->GetCount() + count);
12711 SendEquipError(msg, pSrcItem, nullptr);
12712 return;
12713 }
12714
12715 if (IsInWorld())
12716 pSrcItem->SendUpdateToPlayer(this);
12717 pSrcItem->SetState(ITEM_CHANGED, this);
12718 StoreItem(dest, pNewItem, true);
12719 }
12720 else if (IsBankPos(dst))
12721 {
12722 // change item amount before check (for unique max count check)
12723 pSrcItem->SetCount(pSrcItem->GetCount() - count);
12724
12725 ItemPosCountVec dest;
12726 InventoryResult msg = CanBankItem(dstbag, dstslot, dest, pNewItem, false);
12727 if (msg != EQUIP_ERR_OK)
12728 {
12729 delete pNewItem;
12730 pSrcItem->SetCount(pSrcItem->GetCount() + count);
12731 SendEquipError(msg, pSrcItem, nullptr);
12732 return;
12733 }
12734
12735 if (IsInWorld())
12736 pSrcItem->SendUpdateToPlayer(this);
12737 pSrcItem->SetState(ITEM_CHANGED, this);
12738 BankItem(dest, pNewItem, true);
12739 }
12740 else if (IsEquipmentPos(dst))
12741 {
12742 // change item amount before check (for unique max count check), provide space for splitted items
12743 pSrcItem->SetCount(pSrcItem->GetCount() - count);
12744
12745 uint16 dest;
12746 InventoryResult msg = CanEquipItem(dstslot, dest, pNewItem, false);
12747 if (msg != EQUIP_ERR_OK)
12748 {
12749 delete pNewItem;
12750 pSrcItem->SetCount(pSrcItem->GetCount() + count);
12751 SendEquipError(msg, pSrcItem, nullptr);
12752 return;
12753 }
12754
12755 if (IsInWorld())
12756 pSrcItem->SendUpdateToPlayer(this);
12757 pSrcItem->SetState(ITEM_CHANGED, this);
12758 EquipItem(dest, pNewItem, true);
12760 }
12761}
12762
12764{
12765 uint8 srcbag = src >> 8;
12766 uint8 srcslot = src & 255;
12767
12768 uint8 dstbag = dst >> 8;
12769 uint8 dstslot = dst & 255;
12770
12771 Item* pSrcItem = GetItemByPos(srcbag, srcslot);
12772 Item* pDstItem = GetItemByPos(dstbag, dstslot);
12773
12774 if (!pSrcItem)
12775 return;
12776
12777 if (pSrcItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
12778 {
12779 if (Item* parentItem = GetItemByGuid(pSrcItem->m_itemData->Creator))
12780 {
12781 if (IsEquipmentPos(src))
12782 {
12783 AutoUnequipChildItem(parentItem); // we need to unequip child first since it cannot go into whatever is going to happen next
12784 SwapItem(dst, src); // src is now empty
12785 SwapItem(parentItem->GetPos(), dst);// dst is now empty
12786 return;
12787 }
12788 }
12789 }
12790 else if (pDstItem && pDstItem->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
12791 {
12792 if (Item* parentItem = GetItemByGuid(pDstItem->m_itemData->Creator))
12793 {
12794 if (IsEquipmentPos(dst))
12795 {
12796 AutoUnequipChildItem(parentItem); // we need to unequip child first since it cannot go into whatever is going to happen next
12797 SwapItem(src, dst); // dst is now empty
12798 SwapItem(parentItem->GetPos(), src);// src is now empty
12799 return;
12800 }
12801 }
12802 }
12803
12804 TC_LOG_DEBUG("entities.player.items", "Player::SwapItem: Player '{}' ({}), Bag: {}, Slot: {}, Item: {}",
12805 GetName(), GetGUID().ToString(), dstbag, dstslot, pSrcItem->GetEntry());
12806
12807 if (!IsAlive())
12808 {
12809 SendEquipError(EQUIP_ERR_PLAYER_DEAD, pSrcItem, pDstItem);
12810 return;
12811 }
12812
12813 // SRC checks
12814
12815 // check unequip potability for equipped items and bank bags
12816 if (IsEquipmentPos(src) || IsBagPos(src))
12817 {
12818 // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
12819 InventoryResult msg = CanUnequipItem(src, !IsBagPos(src) || IsBagPos(dst) || (pDstItem && pDstItem->ToBag() && pDstItem->ToBag()->IsEmpty()));
12820 if (msg != EQUIP_ERR_OK)
12821 {
12822 SendEquipError(msg, pSrcItem, pDstItem);
12823 return;
12824 }
12825 }
12826
12827 // prevent put equipped/bank bag in self
12828 if (IsBagPos(src) && srcslot == dstbag)
12829 {
12830 SendEquipError(EQUIP_ERR_BAG_IN_BAG, pSrcItem, pDstItem);
12831 return;
12832 }
12833
12834 // prevent equipping bag in the same slot from its inside
12835 if (IsBagPos(dst) && srcbag == dstslot)
12836 {
12837 SendEquipError(EQUIP_ERR_CANT_SWAP, pSrcItem, pDstItem);
12838 return;
12839 }
12840
12841 // DST checks
12842 if (pDstItem)
12843 {
12844 // check unequip potability for equipped items and bank bags
12845 if (IsEquipmentPos(dst) || IsBagPos(dst))
12846 {
12847 // bags can be swapped with empty bag slots, or with empty bag (items move possibility checked later)
12848 InventoryResult msg = CanUnequipItem(dst, !IsBagPos(dst) || IsBagPos(src) || (pSrcItem->ToBag() && pSrcItem->ToBag()->IsEmpty()));
12849 if (msg != EQUIP_ERR_OK)
12850 {
12851 SendEquipError(msg, pSrcItem, pDstItem);
12852 return;
12853 }
12854 }
12855 }
12856
12858 {
12859 SendEquipError(EQUIP_ERR_REAGENT_BANK_LOCKED, pSrcItem, pDstItem);
12860 return;
12861 }
12862
12863 // NOW this is or item move (swap with empty), or swap with another item (including bags in bag possitions)
12864 // or swap empty bag with another empty or not empty bag (with items exchange)
12865
12866 // Move case
12867 if (!pDstItem)
12868 {
12869 if (IsInventoryPos(dst))
12870 {
12871 ItemPosCountVec dest;
12872 InventoryResult msg = CanStoreItem(dstbag, dstslot, dest, pSrcItem, false);
12873 if (msg != EQUIP_ERR_OK)
12874 {
12875 SendEquipError(msg, pSrcItem, nullptr);
12876 return;
12877 }
12878
12879 RemoveItem(srcbag, srcslot, true);
12880 StoreItem(dest, pSrcItem, true);
12881 if (IsBankPos(src))
12882 ItemAddedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount());
12883 }
12884 else if (IsBankPos(dst))
12885 {
12886 ItemPosCountVec dest;
12887 InventoryResult msg = CanBankItem(dstbag, dstslot, dest, pSrcItem, false);
12888 if (msg != EQUIP_ERR_OK)
12889 {
12890 SendEquipError(msg, pSrcItem, nullptr);
12891 return;
12892 }
12893
12894 RemoveItem(srcbag, srcslot, true);
12895 BankItem(dest, pSrcItem, true);
12896 if (!IsReagentBankPos(dst))
12897 ItemRemovedQuestCheck(pSrcItem->GetEntry(), pSrcItem->GetCount());
12898 }
12899 else if (IsEquipmentPos(dst))
12900 {
12901 uint16 dest;
12902 InventoryResult msg = CanEquipItem(dstslot, dest, pSrcItem, false);
12903 if (msg != EQUIP_ERR_OK)
12904 {
12905 SendEquipError(msg, pSrcItem, nullptr);
12906 return;
12907 }
12908
12909 RemoveItem(srcbag, srcslot, true);
12910 EquipItem(dest, pSrcItem, true);
12912 }
12913
12914 return;
12915 }
12916
12917 // attempt merge to / fill target item
12918 if (!pSrcItem->IsBag() && !pDstItem->IsBag())
12919 {
12920 InventoryResult msg;
12921 ItemPosCountVec sDest;
12922 uint16 eDest = 0;
12923 if (IsInventoryPos(dst))
12924 msg = CanStoreItem(dstbag, dstslot, sDest, pSrcItem, false);
12925 else if (IsBankPos(dst))
12926 msg = CanBankItem(dstbag, dstslot, sDest, pSrcItem, false);
12927 else if (IsEquipmentPos(dst))
12928 msg = CanEquipItem(dstslot, eDest, pSrcItem, false);
12929 else
12930 return;
12931
12932 if (msg == EQUIP_ERR_OK && IsEquipmentPos(dst) && !pSrcItem->GetChildItem().IsEmpty())
12933 msg = CanEquipChildItem(pSrcItem);
12934
12935 // can be merge/fill
12936 if (msg == EQUIP_ERR_OK)
12937 {
12938 if (pSrcItem->GetCount() + pDstItem->GetCount() <= pSrcItem->GetTemplate()->GetMaxStackSize())
12939 {
12940 RemoveItem(srcbag, srcslot, true);
12941
12942 if (IsInventoryPos(dst))
12943 StoreItem(sDest, pSrcItem, true);
12944 else if (IsBankPos(dst))
12945 BankItem(sDest, pSrcItem, true);
12946 else if (IsEquipmentPos(dst))
12947 {
12948 EquipItem(eDest, pSrcItem, true);
12949 if (!pSrcItem->GetChildItem().IsEmpty())
12950 EquipChildItem(srcbag, srcslot, pSrcItem);
12951
12953 }
12954 }
12955 else
12956 {
12957 pSrcItem->SetCount(pSrcItem->GetCount() + pDstItem->GetCount() - pSrcItem->GetTemplate()->GetMaxStackSize());
12958 pDstItem->SetCount(pSrcItem->GetTemplate()->GetMaxStackSize());
12959 pSrcItem->SetState(ITEM_CHANGED, this);
12960 pDstItem->SetState(ITEM_CHANGED, this);
12961 if (IsInWorld())
12962 {
12963 pSrcItem->SendUpdateToPlayer(this);
12964 pDstItem->SendUpdateToPlayer(this);
12965 }
12966 }
12967 SendRefundInfo(pDstItem);
12968 return;
12969 }
12970 }
12971
12972 // impossible merge/fill, do real swap
12974
12975 // check src->dest move possibility
12976 ItemPosCountVec sDest;
12977 uint16 eDest = 0;
12978 if (IsInventoryPos(dst))
12979 msg = CanStoreItem(dstbag, dstslot, sDest, pSrcItem, true);
12980 else if (IsBankPos(dst))
12981 msg = CanBankItem(dstbag, dstslot, sDest, pSrcItem, true);
12982 else if (IsEquipmentPos(dst))
12983 {
12984 msg = CanEquipItem(dstslot, eDest, pSrcItem, true);
12985 if (msg == EQUIP_ERR_OK)
12986 msg = CanUnequipItem(eDest, true);
12987 }
12988
12989 if (msg != EQUIP_ERR_OK)
12990 {
12991 SendEquipError(msg, pSrcItem, pDstItem);
12992 return;
12993 }
12994
12995 // check dest->src move possibility
12996 ItemPosCountVec sDest2;
12997 uint16 eDest2 = 0;
12998 if (IsInventoryPos(src))
12999 msg = CanStoreItem(srcbag, srcslot, sDest2, pDstItem, true);
13000 else if (IsBankPos(src))
13001 msg = CanBankItem(srcbag, srcslot, sDest2, pDstItem, true);
13002 else if (IsEquipmentPos(src))
13003 {
13004 msg = CanEquipItem(srcslot, eDest2, pDstItem, true);
13005 if (msg == EQUIP_ERR_OK)
13006 msg = CanUnequipItem(eDest2, true);
13007 }
13008
13009 if (msg == EQUIP_ERR_OK && IsEquipmentPos(dst) && !pSrcItem->GetChildItem().IsEmpty())
13010 msg = CanEquipChildItem(pSrcItem);
13011
13012 if (msg != EQUIP_ERR_OK)
13013 {
13014 SendEquipError(msg, pDstItem, pSrcItem);
13015 return;
13016 }
13017
13018 // Check bag swap with item exchange (one from empty in not bag possition (equipped (not possible in fact) or store)
13019 if (Bag* srcBag = pSrcItem->ToBag())
13020 {
13021 if (Bag* dstBag = pDstItem->ToBag())
13022 {
13023 Bag* emptyBag = nullptr;
13024 Bag* fullBag = nullptr;
13025 if (srcBag->IsEmpty() && !IsBagPos(src))
13026 {
13027 emptyBag = srcBag;
13028 fullBag = dstBag;
13029 }
13030 else if (dstBag->IsEmpty() && !IsBagPos(dst))
13031 {
13032 emptyBag = dstBag;
13033 fullBag = srcBag;
13034 }
13035
13036 // bag swap (with items exchange) case
13037 if (emptyBag && fullBag)
13038 {
13039 ItemTemplate const* emptyProto = emptyBag->GetTemplate();
13040
13041 uint32 count = 0;
13042
13043 for (uint32 i=0; i < fullBag->GetBagSize(); ++i)
13044 {
13045 Item* bagItem = fullBag->GetItemByPos(i);
13046 if (!bagItem)
13047 continue;
13048
13049 ItemTemplate const* bagItemProto = bagItem->GetTemplate();
13050 if (!bagItemProto || !ItemCanGoIntoBag(bagItemProto, emptyProto))
13051 {
13052 // one from items not go to empty target bag
13053 SendEquipError(EQUIP_ERR_BAG_IN_BAG, pSrcItem, pDstItem);
13054 return;
13055 }
13056
13057 ++count;
13058 }
13059
13060 if (count > emptyBag->GetBagSize())
13061 {
13062 // too small targeted bag
13063 SendEquipError(EQUIP_ERR_CANT_SWAP, pSrcItem, pDstItem);
13064 return;
13065 }
13066
13067 // Items swap
13068 count = 0; // will pos in new bag
13069 for (uint32 i = 0; i< fullBag->GetBagSize(); ++i)
13070 {
13071 Item* bagItem = fullBag->GetItemByPos(i);
13072 if (!bagItem)
13073 continue;
13074
13075 fullBag->RemoveItem(i, true);
13076 emptyBag->StoreItem(count, bagItem, true);
13077 bagItem->SetState(ITEM_CHANGED, this);
13078
13079 ++count;
13080 }
13081 }
13082 }
13083 }
13084
13085 // now do moves, remove...
13086 RemoveItem(dstbag, dstslot, false);
13087 RemoveItem(srcbag, srcslot, false);
13088
13089 // add to dest
13090 if (IsInventoryPos(dst))
13091 StoreItem(sDest, pSrcItem, true);
13092 else if (IsBankPos(dst))
13093 BankItem(sDest, pSrcItem, true);
13094 else if (IsEquipmentPos(dst))
13095 {
13096 EquipItem(eDest, pSrcItem, true);
13097 if (!pSrcItem->GetChildItem().IsEmpty())
13098 EquipChildItem(srcbag, srcslot, pSrcItem);
13099 }
13100
13101 // add to src
13102 if (IsInventoryPos(src))
13103 StoreItem(sDest2, pDstItem, true);
13104 else if (IsBankPos(src))
13105 BankItem(sDest2, pDstItem, true);
13106 else if (IsEquipmentPos(src))
13107 EquipItem(eDest2, pDstItem, true);
13108
13109 // if inventory item was moved, check if we can remove dependent auras, because they were not removed in Player::RemoveItem (update was set to false)
13110 // do this after swaps are done, we pass nullptr because both weapons could be swapped and none of them should be ignored
13111 if ((srcbag == INVENTORY_SLOT_BAG_0 && srcslot < INVENTORY_SLOT_BAG_END) || (dstbag == INVENTORY_SLOT_BAG_0 && dstslot < INVENTORY_SLOT_BAG_END))
13112 ApplyItemDependentAuras((Item*)nullptr, false);
13113
13114 // if player is moving bags and is looting an item inside this bag
13115 // release the loot
13116 if (!GetAELootView().empty())
13117 {
13118 bool released = false;
13119 if (IsBagPos(src))
13120 {
13121 Bag* bag = pSrcItem->ToBag();
13122 for (uint32 i = 0; i < bag->GetBagSize(); ++i)
13123 {
13124 if (Item* bagItem = bag->GetItemByPos(i))
13125 {
13126 if (GetLootByWorldObjectGUID(bagItem->GetGUID()))
13127 {
13129 released = true; // so we don't need to look at dstBag
13130 break;
13131 }
13132 }
13133 }
13134 }
13135
13136 if (!released && IsBagPos(dst))
13137 {
13138 Bag* bag = pDstItem->ToBag();
13139 for (uint32 i = 0; i < bag->GetBagSize(); ++i)
13140 {
13141 if (Item* bagItem = bag->GetItemByPos(i))
13142 {
13143 if (GetLootByWorldObjectGUID(bagItem->GetGUID()))
13144 {
13146 break;
13147 }
13148 }
13149 }
13150 }
13151 }
13152
13154}
13155
13157{
13158 if (pItem)
13159 {
13161 // if current back slot non-empty search oldest or free
13162 if (m_items[slot])
13163 {
13164 time_t oldest_time = m_activePlayerData->BuybackTimestamp[0];
13165 uint32 oldest_slot = BUYBACK_SLOT_START;
13166
13167 for (uint32 i = BUYBACK_SLOT_START + 1; i < BUYBACK_SLOT_END; ++i)
13168 {
13169 // found empty
13170 if (!m_items[i])
13171 {
13172 oldest_slot = i;
13173 break;
13174 }
13175
13176 time_t i_time = m_activePlayerData->BuybackTimestamp[i - BUYBACK_SLOT_START];
13177
13178 if (oldest_time > i_time)
13179 {
13180 oldest_time = i_time;
13181 oldest_slot = i;
13182 }
13183 }
13184
13185 // find oldest
13186 slot = oldest_slot;
13187 }
13188
13189 RemoveItemFromBuyBackSlot(slot, true);
13190 TC_LOG_DEBUG("entities.player.items", "Player::AddItemToBuyBackSlot: Player '{}' ({}), Item: {}, Slot: {}",
13191 GetName(), GetGUID().ToString(), pItem->GetEntry(), slot);
13192
13193 m_items[slot] = pItem;
13194 time_t base = GameTime::GetGameTime();
13195 uint32 etime = uint32(base - m_logintime + (30 * 3600));
13196 uint32 eslot = slot - BUYBACK_SLOT_START;
13197
13198 SetInvSlot(slot, pItem->GetGUID());
13199 if (ItemTemplate const* proto = pItem->GetTemplate())
13200 SetBuybackPrice(eslot, proto->GetSellPrice() * pItem->GetCount());
13201 else
13202 SetBuybackPrice(eslot, 0);
13203
13204 SetBuybackTimestamp(eslot, (uint32)etime);
13205
13206 // move to next (for non filled list is move most optimized choice)
13209 }
13210}
13211
13213{
13214 TC_LOG_DEBUG("entities.player.items", "Player::GetItemFromBuyBackSlot: Player '{}' ({}), Slot: {}",
13215 GetName(), GetGUID().ToString(), slot);
13216 if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END)
13217 return m_items[slot];
13218 return nullptr;
13219}
13220
13222{
13223 TC_LOG_DEBUG("entities.player.items", "Player::RemoveItemFromBuyBackSlot: Player '{}' ({}), Slot: {}",
13224 GetName(), GetGUID().ToString(), slot);
13225 if (slot >= BUYBACK_SLOT_START && slot < BUYBACK_SLOT_END)
13226 {
13227 Item* pItem = m_items[slot];
13228 if (pItem)
13229 {
13230 pItem->RemoveFromWorld();
13231 if (del)
13232 {
13233 if (ItemTemplate const* itemTemplate = pItem->GetTemplate())
13234 if (itemTemplate->HasFlag(ITEM_FLAG_HAS_LOOT))
13235 sLootItemStorage->RemoveStoredLootForContainer(pItem->GetGUID().GetCounter());
13236
13237 pItem->SetState(ITEM_REMOVED, this);
13238 }
13239 }
13240
13241 m_items[slot] = nullptr;
13242
13243 uint32 eslot = slot - BUYBACK_SLOT_START;
13245 SetBuybackPrice(eslot, 0);
13246 SetBuybackTimestamp(eslot, 0);
13247
13248 // if current backslot is filled set to now free slot
13250 m_currentBuybackSlot = slot;
13251 }
13252}
13253
13254void Player::SendEquipError(InventoryResult msg, Item const* item1 /*= nullptr*/, Item const* item2 /*= nullptr*/, uint32 itemId /*= 0*/) const
13255{
13257 failure.BagResult = msg;
13258
13259 if (msg != EQUIP_ERR_OK)
13260 {
13261 if (item1)
13262 failure.Item[0] = item1->GetGUID();
13263
13264 if (item2)
13265 failure.Item[1] = item2->GetGUID();
13266
13267 failure.ContainerBSlot = 0; // bag equip slot, used with EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM and EQUIP_ERR_ITEM_DOESNT_GO_INTO_BAG2
13268
13269 switch (msg)
13270 {
13273 {
13274 failure.Level = uint32(item1 ? item1->GetRequiredLevel() : 0);
13275 break;
13276 }
13277 case EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM: // no idea about this one...
13278 {
13279 //failure.SrcContainer
13280 //failure.SrcSlot
13281 //failure.DstContainer
13282 break;
13283 }
13287 {
13288 ItemTemplate const* proto = item1 ? item1->GetTemplate() : sObjectMgr->GetItemTemplate(itemId);
13289 failure.LimitCategory = proto ? proto->GetItemLimitCategory() : 0;
13290 break;
13291 }
13292 default:
13293 break;
13294 }
13295 }
13296
13297 SendDirectMessage(failure.Write());
13298}
13299
13300void Player::SendBuyError(BuyResult msg, Creature* creature, uint32 item, uint32 /*param*/) const
13301{
13303 packet.VendorGUID = creature ? creature->GetGUID() : ObjectGuid::Empty;
13304 packet.Muid = item;
13305 packet.Reason = msg;
13306 SendDirectMessage(packet.Write());
13307}
13308
13309void Player::SendSellError(SellResult msg, Creature* creature, ObjectGuid guid) const
13310{
13312 sellResponse.VendorGUID = creature ? creature->GetGUID() : ObjectGuid::Empty;
13313 sellResponse.ItemGUIDs.push_back(guid);
13314 sellResponse.Reason = msg;
13315 SendDirectMessage(sellResponse.Write());
13316}
13317
13318bool Player::IsUseEquipedWeapon(bool mainhand) const
13319{
13320 // disarm applied only to mainhand weapon
13321 return !IsInFeralForm() && (!mainhand || !HasUnitFlag(UNIT_FLAG_DISARMED));
13322}
13323
13324void Player::SetCanTitanGrip(bool value, uint32 penaltySpellId /*= 0*/)
13325{
13326 if (value == m_canTitanGrip)
13327 return;
13328
13329 m_canTitanGrip = value;
13330 m_titanGripPenaltySpellId = penaltySpellId;
13331}
13332
13334{
13335 if (!CanTitanGrip())
13336 return;
13337
13339 if (apply)
13340 {
13342 CastSpell(nullptr, m_titanGripPenaltySpellId, true);
13343 }
13344 else
13346}
13347
13349{
13351 if (!mainItem)
13352 return false;
13353
13354 ItemTemplate const* itemTemplate = mainItem->GetTemplate();
13355 return (itemTemplate->GetInventoryType() == INVTYPE_2HWEAPON && !CanTitanGrip()) ||
13356 itemTemplate->GetInventoryType() == INVTYPE_RANGED ||
13357 (itemTemplate->GetInventoryType() == INVTYPE_RANGEDRIGHT && itemTemplate->GetClass() == ITEM_CLASS_WEAPON && itemTemplate->GetSubClass() != ITEM_SUBCLASS_WEAPON_WAND);
13358}
13359
13361{
13363 if (offItem && offItem->GetTemplate()->GetInventoryType() == INVTYPE_2HWEAPON)
13364 return true;
13365
13367 if (!mainItem || mainItem->GetTemplate()->GetInventoryType() != INVTYPE_2HWEAPON)
13368 return false;
13369
13370 if (!offItem)
13371 return false;
13372
13373 return true;
13374}
13375
13376void Player::TradeCancel(bool sendback)
13377{
13378 if (m_trade)
13379 {
13380 Player* trader = m_trade->GetTrader();
13381
13382 // send yellow "Trade canceled" message to both traders
13383 if (sendback)
13385
13386 trader->GetSession()->SendCancelTrade();
13387
13388 // cleanup
13389 delete m_trade;
13390 m_trade = nullptr;
13391 delete trader->m_trade;
13392 trader->m_trade = nullptr;
13393 }
13394}
13395
13397{
13398 // also checks for garbage data
13399 for (GuidUnorderedSet::iterator itr = m_itemSoulboundTradeable.begin(); itr != m_itemSoulboundTradeable.end();)
13400 {
13401 Item* item = GetItemByGuid(*itr);
13402 if (!item || item->GetOwnerGUID() != GetGUID() || item->CheckSoulboundTradeExpire())
13403 itr = m_itemSoulboundTradeable.erase(itr);
13404 else
13405 ++itr;
13406 }
13407}
13408
13410{
13411 m_itemSoulboundTradeable.insert(item->GetGUID());
13412}
13413
13415{
13416 m_itemSoulboundTradeable.erase(item->GetGUID());
13417}
13418
13419void Player::UpdateItemDuration(uint32 time, bool realtimeonly)
13420{
13421 if (m_itemDuration.empty())
13422 return;
13423
13424 TC_LOG_DEBUG("entities.player.items", "Player::UpdateItemDuration: Player '{}' ({}), Time: {}, RealTimeOnly: {}",
13425 GetName(), GetGUID().ToString(), time, realtimeonly);
13426
13427 for (ItemDurationList::const_iterator itr = m_itemDuration.begin(); itr != m_itemDuration.end();)
13428 {
13429 Item* item = *itr;
13430 ++itr; // current element can be erased in UpdateDuration
13431
13432 if (!realtimeonly || item->GetTemplate()->HasFlag(ITEM_FLAG_REAL_DURATION))
13433 item->UpdateDuration(this, time);
13434 }
13435}
13436
13438{
13439 for (EnchantDurationList::iterator itr = m_enchantDuration.begin(), next; itr != m_enchantDuration.end(); itr = next)
13440 {
13441 ASSERT(itr->item);
13442 next = itr;
13443 if (!itr->item->GetEnchantmentId(itr->slot))
13444 {
13445 next = m_enchantDuration.erase(itr);
13446 }
13447 else if (itr->leftduration <= time)
13448 {
13449 ApplyEnchantment(itr->item, itr->slot, false, false);
13450 itr->item->ClearEnchantment(itr->slot);
13451 next = m_enchantDuration.erase(itr);
13452 }
13453 else if (itr->leftduration > time)
13454 {
13455 itr->leftduration -= time;
13456 ++next;
13457 }
13458 }
13459}
13460
13462{
13463 for (int x = 0; x < MAX_ENCHANTMENT_SLOT; ++x)
13464 {
13465 if (!item->GetEnchantmentId(EnchantmentSlot(x)))
13466 continue;
13467
13468 uint32 duration = item->GetEnchantmentDuration(EnchantmentSlot(x));
13469 if (duration > 0)
13470 AddEnchantmentDuration(item, EnchantmentSlot(x), duration);
13471 }
13472}
13473
13475{
13476 for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end();)
13477 {
13478 if (itr->item == item)
13479 {
13480 // save duration in item
13481 item->SetEnchantmentDuration(EnchantmentSlot(itr->slot), itr->leftduration, this);
13482 itr = m_enchantDuration.erase(itr);
13483 }
13484 else
13485 ++itr;
13486 }
13487}
13488
13490{
13491 for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end();)
13492 {
13493 if (itr->item == item)
13494 itr = m_enchantDuration.erase(itr);
13495 else
13496 ++itr;
13497 }
13498}
13499
13501{
13502 // remove enchantments from equipped items first to clean up the m_enchantDuration list
13503 for (EnchantDurationList::iterator itr = m_enchantDuration.begin(), next; itr != m_enchantDuration.end(); itr = next)
13504 {
13505 next = itr;
13506 if (itr->slot == slot)
13507 {
13508 if (itr->item && itr->item->GetEnchantmentId(slot))
13509 {
13510 // Poisons and DK runes are enchants which are allowed on arenas
13511 if (sSpellMgr->IsArenaAllowedEnchancment(itr->item->GetEnchantmentId(slot)))
13512 {
13513 ++next;
13514 continue;
13515 }
13516 // remove from stats
13517 ApplyEnchantment(itr->item, slot, false, false);
13518 // remove visual
13519 itr->item->ClearEnchantment(slot);
13520 }
13521 // remove from update list
13522 next = m_enchantDuration.erase(itr);
13523 }
13524 else
13525 ++next;
13526 }
13527
13528 // remove enchants from inventory items
13529 // NOTE: no need to remove these from stats, since these aren't equipped
13530 // in inventory
13532 for (uint8 i = INVENTORY_SLOT_ITEM_START; i < inventoryEnd; ++i)
13533 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
13534 if (!sSpellMgr->IsArenaAllowedEnchancment(pItem->GetEnchantmentId(slot)))
13535 pItem->ClearEnchantment(slot);
13536
13537 // in inventory bags
13539 if (Bag* pBag = GetBagByPos(i))
13540 for (uint32 j = 0; j < pBag->GetBagSize(); j++)
13541 if (Item* pItem = pBag->GetItemByPos(j))
13542 if (!sSpellMgr->IsArenaAllowedEnchancment(pItem->GetEnchantmentId(slot)))
13543 pItem->ClearEnchantment(slot);
13544}
13545
13546// duration == 0 will remove item enchant
13548{
13549 if (!item)
13550 return;
13551
13552 if (slot >= MAX_ENCHANTMENT_SLOT)
13553 return;
13554
13555 for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end(); ++itr)
13556 {
13557 if (itr->item == item && itr->slot == slot)
13558 {
13559 itr->item->SetEnchantmentDuration(itr->slot, itr->leftduration, this);
13560 m_enchantDuration.erase(itr);
13561 break;
13562 }
13563 }
13564 if (duration > 0)
13565 {
13566 GetSession()->SendItemEnchantTimeUpdate(GetGUID(), item->GetGUID(), slot, uint32(duration/1000));
13567 m_enchantDuration.push_back(EnchantDuration(item, slot, duration));
13568 }
13569}
13570
13572{
13573 for (uint32 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot)
13575}
13576
13577void Player::ApplyEnchantment(Item* item, EnchantmentSlot slot, bool apply, bool apply_dur, bool ignore_condition)
13578{
13579 if (!item || !item->IsEquipped())
13580 return;
13581
13582 if (slot >= MAX_ENCHANTMENT_SLOT)
13583 return;
13584
13585 uint32 enchant_id = item->GetEnchantmentId(slot);
13586 if (!enchant_id)
13587 return;
13588
13589 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
13590 if (!pEnchant)
13591 return;
13592
13593 if (!ignore_condition && pEnchant->ConditionID && !EnchantmentFitsRequirements(pEnchant->ConditionID, -1))
13594 return;
13595
13596 if (pEnchant->MinLevel > GetLevel())
13597 return;
13598
13599 if (pEnchant->RequiredSkillID > 0 && pEnchant->RequiredSkillRank > GetSkillValue(pEnchant->RequiredSkillID))
13600 return;
13601
13602 // If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements
13603 // rather than the gem requirements itself. If the socket has no color it is a prismatic socket.
13604 if ((slot == SOCK_ENCHANTMENT_SLOT || slot == SOCK_ENCHANTMENT_SLOT_2 || slot == SOCK_ENCHANTMENT_SLOT_3))
13605 {
13606 if (!item->GetSocketColor(slot - SOCK_ENCHANTMENT_SLOT))
13607 {
13608 // Check if the requirements for the prismatic socket are met before applying the gem stats
13610 if (!pPrismaticEnchant || (pPrismaticEnchant->RequiredSkillID > 0 && pPrismaticEnchant->RequiredSkillRank > GetSkillValue(pPrismaticEnchant->RequiredSkillID)))
13611 return;
13612 }
13613
13614 // Cogwheel gems dont have requirement data set in SpellItemEnchantment.dbc, but they do have it in Item-sparse.db2
13615 if (UF::SocketedGem const* gem = item->GetGem(uint16(slot - SOCK_ENCHANTMENT_SLOT)))
13616 if (ItemTemplate const* gemTemplate = sObjectMgr->GetItemTemplate(gem->ItemID))
13617 if (gemTemplate->GetRequiredSkill() && GetSkillValue(gemTemplate->GetRequiredSkill()) < gemTemplate->GetRequiredSkillRank())
13618 return;
13619 }
13620
13621 if (!item->IsBroken())
13622 {
13623 for (int s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
13624 {
13625 uint32 enchant_display_type = pEnchant->Effect[s];
13626 uint32 enchant_amount = pEnchant->EffectPointsMin[s];
13627 uint32 enchant_spell_id = pEnchant->EffectArg[s];
13628
13629 switch (enchant_display_type)
13630 {
13632 break;
13634 // processed in Player::CastItemCombatSpell
13635 break;
13637 {
13638 WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot(), item->GetTemplate()->GetInventoryType());
13639 if (attackType != MAX_ATTACK)
13640 UpdateDamageDoneMods(attackType, apply ? -1 : slot);
13641 break;
13642 }
13644 if (enchant_spell_id)
13645 {
13646 if (apply)
13647 CastSpell(this, enchant_spell_id, item);
13648 else
13649 RemoveAurasDueToItemSpell(enchant_spell_id, item->GetGUID());
13650 }
13651 break;
13653 if (pEnchant->ScalingClass)
13654 {
13655 int32 scalingClass = pEnchant->ScalingClass;
13656 if ((*m_unitData->MinItemLevel || *m_unitData->MaxItemLevel) && pEnchant->ScalingClassRestricted)
13657 scalingClass = pEnchant->ScalingClassRestricted;
13658
13659 uint8 minLevel = pEnchant->GetFlags().HasFlag(SpellItemEnchantmentFlags::ScaleAsAGem) ? 1 : 60;
13660 uint8 scalingLevel = GetLevel();
13661 uint8 maxLevel = uint8(pEnchant->MaxLevel ? pEnchant->MaxLevel : sSpellScalingGameTable.GetTableRowCount() - 1);
13662
13663 if (minLevel > GetLevel())
13664 scalingLevel = minLevel;
13665 else if (maxLevel < GetLevel())
13666 scalingLevel = maxLevel;
13667
13668 if (GtSpellScalingEntry const* spellScaling = sSpellScalingGameTable.GetRow(scalingLevel))
13669 enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass));
13670 }
13671 enchant_amount = std::max(enchant_amount, 1u);
13672 HandleStatFlatModifier(UnitMods(UNIT_MOD_RESISTANCE_START + enchant_spell_id), TOTAL_VALUE, float(enchant_amount), apply);
13673 break;
13675 {
13676 if (pEnchant->ScalingClass)
13677 {
13678 int32 scalingClass = pEnchant->ScalingClass;
13679 if ((*m_unitData->MinItemLevel || *m_unitData->MaxItemLevel) && pEnchant->ScalingClassRestricted)
13680 scalingClass = pEnchant->ScalingClassRestricted;
13681
13682 uint8 minLevel = pEnchant->GetFlags().HasFlag(SpellItemEnchantmentFlags::ScaleAsAGem) ? 1 : 60;
13683 uint8 scalingLevel = GetLevel();
13684 uint8 maxLevel = uint8(pEnchant->MaxLevel ? pEnchant->MaxLevel : sSpellScalingGameTable.GetTableRowCount() - 1);
13685
13686 if (minLevel > GetLevel())
13687 scalingLevel = minLevel;
13688 else if (maxLevel < GetLevel())
13689 scalingLevel = maxLevel;
13690
13691 if (GtSpellScalingEntry const* spellScaling = sSpellScalingGameTable.GetRow(scalingLevel))
13692 enchant_amount = uint32(pEnchant->EffectScalingPoints[s] * GetSpellScalingColumnForClass(spellScaling, scalingClass));
13693 }
13694
13695 enchant_amount = std::max(enchant_amount, 1u);
13696
13697 TC_LOG_DEBUG("entities.player.items", "Adding {} to stat nb {}", enchant_amount, enchant_spell_id);
13698 switch (enchant_spell_id)
13699 {
13700 case ITEM_MOD_MANA:
13701 TC_LOG_DEBUG("entities.player.items", "+ {} MANA", enchant_amount);
13702 HandleStatFlatModifier(UNIT_MOD_MANA, BASE_VALUE, float(enchant_amount), apply);
13703 break;
13704 case ITEM_MOD_HEALTH:
13705 TC_LOG_DEBUG("entities.player.items", "+ {} HEALTH", enchant_amount);
13706 HandleStatFlatModifier(UNIT_MOD_HEALTH, BASE_VALUE, float(enchant_amount), apply);
13707 break;
13708 case ITEM_MOD_AGILITY:
13709 TC_LOG_DEBUG("entities.player.items", "+ {} AGILITY", enchant_amount);
13712 break;
13713 case ITEM_MOD_STRENGTH:
13714 TC_LOG_DEBUG("entities.player.items", "+ {} STRENGTH", enchant_amount);
13717 break;
13718 case ITEM_MOD_INTELLECT:
13719 TC_LOG_DEBUG("entities.player.items", "+ {} INTELLECT", enchant_amount);
13722 break;
13723 // case ITEM_MOD_SPIRIT:
13724 // TC_LOG_DEBUG("entities.player.items", "+ {} SPIRIT", enchant_amount);
13725 // HandleStatModifier(UNIT_MOD_STAT_SPIRIT, TOTAL_VALUE, float(enchant_amount), apply);
13726 // ApplyStatBuffMod(STAT_SPIRIT, (float)enchant_amount, apply);
13727 // break;
13728 case ITEM_MOD_STAMINA:
13729 TC_LOG_DEBUG("entities.player.items", "+ {} STAMINA", enchant_amount);
13732 break;
13734 ApplyRatingMod(CR_DEFENSE_SKILL, enchant_amount, apply);
13735 TC_LOG_DEBUG("entities.player.items", "+ {} DEFENSE", enchant_amount);
13736 break;
13738 ApplyRatingMod(CR_DODGE, enchant_amount, apply);
13739 TC_LOG_DEBUG("entities.player.items", "+ {} DODGE", enchant_amount);
13740 break;
13742 ApplyRatingMod(CR_PARRY, enchant_amount, apply);
13743 TC_LOG_DEBUG("entities.player.items", "+ {} PARRY", enchant_amount);
13744 break;
13746 ApplyRatingMod(CR_BLOCK, enchant_amount, apply);
13747 TC_LOG_DEBUG("entities.player.items", "+ {} SHIELD_BLOCK", enchant_amount);
13748 break;
13750 ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply);
13751 TC_LOG_DEBUG("entities.player.items", "+ {} MELEE_HIT", enchant_amount);
13752 break;
13754 ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply);
13755 TC_LOG_DEBUG("entities.player.items", "+ {} RANGED_HIT", enchant_amount);
13756 break;
13758 ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply);
13759 TC_LOG_DEBUG("entities.player.items", "+ {} SPELL_HIT", enchant_amount);
13760 break;
13762 ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply);
13763 TC_LOG_DEBUG("entities.player.items", "+ {} MELEE_CRIT", enchant_amount);
13764 break;
13766 ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply);
13767 TC_LOG_DEBUG("entities.player.items", "+ {} RANGED_CRIT", enchant_amount);
13768 break;
13770 ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply);
13771 TC_LOG_DEBUG("entities.player.items", "+ {} SPELL_CRIT", enchant_amount);
13772 break;
13773 // Values from ITEM_STAT_MELEE_HA_RATING to ITEM_MOD_HASTE_RANGED_RATING are never used
13774 // in Enchantments
13775 // case ITEM_MOD_HIT_TAKEN_MELEE_RATING:
13776 // ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply);
13777 // break;
13778 // case ITEM_MOD_HIT_TAKEN_RANGED_RATING:
13779 // ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply);
13780 // break;
13781 // case ITEM_MOD_HIT_TAKEN_SPELL_RATING:
13782 // ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply);
13783 // break;
13784 // case ITEM_MOD_CRIT_TAKEN_MELEE_RATING:
13785 // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
13786 // break;
13787 // case ITEM_MOD_CRIT_TAKEN_RANGED_RATING:
13788 // ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
13789 // break;
13790 // case ITEM_MOD_CRIT_TAKEN_SPELL_RATING:
13791 // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
13792 // break;
13793 // case ITEM_MOD_HASTE_MELEE_RATING:
13794 // ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply);
13795 // break;
13796 // case ITEM_MOD_HASTE_RANGED_RATING:
13797 // ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply);
13798 // break;
13800 ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply);
13801 break;
13803 ApplyRatingMod(CR_HIT_MELEE, enchant_amount, apply);
13804 ApplyRatingMod(CR_HIT_RANGED, enchant_amount, apply);
13805 ApplyRatingMod(CR_HIT_SPELL, enchant_amount, apply);
13806 TC_LOG_DEBUG("entities.player.items", "+ {} HIT", enchant_amount);
13807 break;
13809 ApplyRatingMod(CR_CRIT_MELEE, enchant_amount, apply);
13810 ApplyRatingMod(CR_CRIT_RANGED, enchant_amount, apply);
13811 ApplyRatingMod(CR_CRIT_SPELL, enchant_amount, apply);
13812 TC_LOG_DEBUG("entities.player.items", "+ {} CRITICAL", enchant_amount);
13813 break;
13814 // case ITEM_MOD_HIT_TAKEN_RATING: // Unused since 3.3.5
13815 // ApplyRatingMod(CR_HIT_TAKEN_MELEE, enchant_amount, apply);
13816 // ApplyRatingMod(CR_HIT_TAKEN_RANGED, enchant_amount, apply);
13817 // ApplyRatingMod(CR_HIT_TAKEN_SPELL, enchant_amount, apply);
13818 // break;
13819 // case ITEM_MOD_CRIT_TAKEN_RATING: // Unused since 3.3.5
13820 // ApplyRatingMod(CR_CRIT_TAKEN_MELEE, enchant_amount, apply);
13821 // ApplyRatingMod(CR_CRIT_TAKEN_RANGED, enchant_amount, apply);
13822 // ApplyRatingMod(CR_CRIT_TAKEN_SPELL, enchant_amount, apply);
13823 // break;
13826 TC_LOG_DEBUG("entities.player.items", "+ {} RESILIENCE", enchant_amount);
13827 break;
13829 ApplyRatingMod(CR_HASTE_MELEE, enchant_amount, apply);
13830 ApplyRatingMod(CR_HASTE_RANGED, enchant_amount, apply);
13831 ApplyRatingMod(CR_HASTE_SPELL, enchant_amount, apply);
13832 TC_LOG_DEBUG("entities.player.items", "+ {} HASTE", enchant_amount);
13833 break;
13835 ApplyRatingMod(CR_EXPERTISE, enchant_amount, apply);
13836 TC_LOG_DEBUG("entities.player.items", "+ {} EXPERTISE", enchant_amount);
13837 break;
13841 TC_LOG_DEBUG("entities.player.items", "+ {} ATTACK_POWER", enchant_amount);
13842 break;
13845 TC_LOG_DEBUG("entities.player.items", "+ {} RANGED_ATTACK_POWER", enchant_amount);
13846 break;
13848 ApplyManaRegenBonus(enchant_amount, apply);
13849 TC_LOG_DEBUG("entities.player.items", "+ {} MANA_REGENERATION", enchant_amount);
13850 break;
13852 ApplyRatingMod(CR_ARMOR_PENETRATION, enchant_amount, apply);
13853 TC_LOG_DEBUG("entities.player.items", "+ {} ARMOR PENETRATION", enchant_amount);
13854 break;
13856 ApplySpellPowerBonus(enchant_amount, apply);
13857 TC_LOG_DEBUG("entities.player.items", "+ {} SPELL_POWER", enchant_amount);
13858 break;
13860 ApplyHealthRegenBonus(enchant_amount, apply);
13861 TC_LOG_DEBUG("entities.player.items", "+ {} HEALTH_REGENERATION", enchant_amount);
13862 break;
13864 ApplySpellPenetrationBonus(enchant_amount, apply);
13865 TC_LOG_DEBUG("entities.player.items", "+ {} SPELL_PENETRATION", enchant_amount);
13866 break;
13868 HandleBaseModFlatValue(SHIELD_BLOCK_VALUE, float(enchant_amount), apply);
13869 TC_LOG_DEBUG("entities.player.items", "+ {} BLOCK_VALUE", enchant_amount);
13870 break;
13872 ApplyRatingMod(CR_MASTERY, enchant_amount, apply);
13873 TC_LOG_DEBUG("entities.player.items", "+ {} MASTERY", enchant_amount);
13874 break;
13879 TC_LOG_DEBUG("entities.player.items", "+ {} VERSATILITY", enchant_amount);
13880 break;
13881 default:
13882 break;
13883 }
13884 break;
13885 }
13886 case ITEM_ENCHANTMENT_TYPE_TOTEM: // Shaman Rockbiter Weapon
13887 {
13888 WeaponAttackType const attackType = Player::GetAttackBySlot(item->GetSlot(), item->GetTemplate()->GetInventoryType());
13889 if (attackType != MAX_ATTACK)
13890 UpdateDamageDoneMods(attackType, apply ? -1 : slot);
13891 break;
13892 }
13894 // processed in Player::CastItemUseSpell
13895 break;
13902 // nothing do..
13903 break;
13904 default:
13905 TC_LOG_ERROR("entities.player", "Player::ApplyEnchantment: Unknown item enchantment (ID: {}, DisplayType: {}) for player '{}' ({})",
13906 enchant_id, enchant_display_type, GetName(), GetGUID().ToString());
13907 break;
13908 }
13909 }
13910 }
13911
13912 // visualize enchantment at player and equipped items
13913 if (slot == PERM_ENCHANTMENT_SLOT && item->GetSlot() < m_playerData->VisibleItems.size())
13915
13916 if (apply_dur)
13917 {
13918 if (apply)
13919 {
13920 // set duration
13921 uint32 duration = item->GetEnchantmentDuration(slot);
13922 if (duration > 0)
13923 AddEnchantmentDuration(item, slot, duration);
13924 }
13925 else
13926 {
13927 // duration == 0 will remove EnchantDuration
13928 AddEnchantmentDuration(item, slot, 0);
13929 }
13930 }
13931}
13932
13933void Player::UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 new_value)
13934{
13935 for (uint8 i = 0; i < INVENTORY_SLOT_BAG_END; ++i)
13936 {
13937 if (m_items[i])
13938 {
13939 for (uint8 slot = 0; slot < MAX_ENCHANTMENT_SLOT; ++slot)
13940 {
13941 uint32 ench_id = m_items[i]->GetEnchantmentId(EnchantmentSlot(slot));
13942 if (!ench_id)
13943 continue;
13944
13945 SpellItemEnchantmentEntry const* Enchant = sSpellItemEnchantmentStore.LookupEntry(ench_id);
13946 if (!Enchant)
13947 return;
13948
13949 if (Enchant->RequiredSkillID == skill_id)
13950 {
13951 // Checks if the enchantment needs to be applied or removed
13952 if (curr_value < Enchant->RequiredSkillRank && new_value >= Enchant->RequiredSkillRank)
13953 ApplyEnchantment(m_items[i], EnchantmentSlot(slot), true);
13954 else if (new_value < Enchant->RequiredSkillRank && curr_value >= Enchant->RequiredSkillRank)
13955 ApplyEnchantment(m_items[i], EnchantmentSlot(slot), false);
13956 }
13957
13958 // If we're dealing with a gem inside a prismatic socket we need to check the prismatic socket requirements
13959 // rather than the gem requirements itself. If the socket has no color it is a prismatic socket.
13961 && !m_items[i]->GetSocketColor(slot - SOCK_ENCHANTMENT_SLOT))
13962 {
13963 SpellItemEnchantmentEntry const* pPrismaticEnchant = sSpellItemEnchantmentStore.LookupEntry(m_items[i]->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT));
13964
13965 if (pPrismaticEnchant && pPrismaticEnchant->RequiredSkillID == skill_id)
13966 {
13967 if (curr_value < pPrismaticEnchant->RequiredSkillRank && new_value >= pPrismaticEnchant->RequiredSkillRank)
13968 ApplyEnchantment(m_items[i], EnchantmentSlot(slot), true);
13969 else if (new_value < pPrismaticEnchant->RequiredSkillRank && curr_value >= pPrismaticEnchant->RequiredSkillRank)
13970 ApplyEnchantment(m_items[i], EnchantmentSlot(slot), false);
13971 }
13972 }
13973 }
13974 }
13975 }
13976}
13977
13979{
13980 for (EnchantDurationList::const_iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end(); ++itr)
13981 GetSession()->SendItemEnchantTimeUpdate(GetGUID(), itr->item->GetGUID(), itr->slot, uint32(itr->leftduration) / 1000);
13982}
13983
13985{
13986 for (ItemDurationList::const_iterator itr = m_itemDuration.begin(); itr != m_itemDuration.end(); ++itr)
13987 (*itr)->SendTimeUpdate(this);
13988}
13989
13990void Player::SendNewItem(Item* item, uint32 quantity, bool pushed, bool created, bool broadcast /*= false*/, uint32 dungeonEncounterId /*= 0*/)
13991{
13992 if (!item) // prevent crash
13993 return;
13994
13996
13997 packet.PlayerGUID = GetGUID();
13998
13999 packet.Slot = item->GetBagSlot();
14000 packet.SlotInBag = item->GetCount() == quantity ? item->GetSlot() : -1;
14001
14002 packet.Item.Initialize(item);
14003
14004 packet.QuestLogItemID = item->GetTemplate()->QuestLogItemId;
14005 packet.Quantity = quantity;
14006 packet.QuantityInInventory = GetItemCount(item->GetEntry());
14011
14012 packet.ItemGUID = item->GetGUID();
14013
14014 packet.Pushed = pushed;
14016 packet.Created = created;
14017 //packet.IsBonusRoll;
14018
14019 if (dungeonEncounterId)
14020 {
14022 packet.DungeonEncounterID = dungeonEncounterId;
14023 packet.IsEncounterLoot = true;
14024 }
14025
14027 GetGroup()->BroadcastPacket(packet.Write(), true);
14028 else
14029 SendDirectMessage(packet.Write());
14030}
14031
14032/*********************************************************/
14033/*** GOSSIP SYSTEM ***/
14034/*********************************************************/
14035
14036void Player::PrepareGossipMenu(WorldObject* source, uint32 menuId, bool showQuests /*= false*/)
14037{
14038 PlayerTalkClass->ClearMenus();
14039 PlayerTalkClass->GetGossipMenu().SetMenuId(menuId);
14040
14041 Trinity::IteratorPair menuItemBounds = sObjectMgr->GetGossipMenuItemsMapBounds(menuId);
14042
14043 if (source->GetTypeId() == TYPEID_UNIT)
14044 {
14045 if (showQuests && source->ToUnit()->IsQuestGiver())
14046 PrepareQuestMenu(source->GetGUID());
14047 }
14048 else if (source->GetTypeId() == TYPEID_GAMEOBJECT)
14049 if (showQuests && source->ToGameObject()->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
14050 PrepareQuestMenu(source->GetGUID());
14051
14052 for (auto const& [_, gossipMenuItem] : menuItemBounds)
14053 {
14054 if (!gossipMenuItem.Conditions.Meets(this, source))
14055 continue;
14056
14057 bool canTalk = true;
14058 if (Creature* creature = source->ToCreature())
14059 {
14060 switch (gossipMenuItem.OptionNpc)
14061 {
14063 if (GetSession()->SendLearnNewTaxiNode(creature))
14064 return;
14065 break;
14067 if (!isDead())
14068 canTalk = false;
14069 break;
14071 if (!creature->isCanInteractWithBattleMaster(this, false))
14072 canTalk = false;
14073 break;
14077 if (!creature->CanResetTalents(this))
14078 canTalk = false;
14079 break;
14082 if (GetClass() != CLASS_HUNTER)
14083 canTalk = false;
14084 break;
14087 canTalk = false;
14088 break;
14091 canTalk = false;
14092 break;
14105 break; // No checks
14107 canTalk = false; // Deprecated
14108 break;
14109 default:
14110 if (gossipMenuItem.OptionNpc >= GossipOptionNpc::Count)
14111 {
14112 TC_LOG_ERROR("sql.sql", "Creature entry {} has an unknown gossip option icon {} for menu {}.", creature->GetEntry(), AsUnderlyingType(gossipMenuItem.OptionNpc), gossipMenuItem.MenuID);
14113 canTalk = false;
14114 }
14115 break; // NYI
14116 }
14117 }
14118 else if (GameObject* go = source->ToGameObject())
14119 {
14120 switch (gossipMenuItem.OptionNpc)
14121 {
14123 if (go->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER && go->GetGoType() != GAMEOBJECT_TYPE_GOOBER)
14124 canTalk = false;
14125 break;
14126 default:
14127 canTalk = false;
14128 break;
14129 }
14130 }
14131
14132 if (canTalk)
14133 PlayerTalkClass->GetGossipMenu().AddMenuItem(gossipMenuItem, gossipMenuItem.MenuID, gossipMenuItem.OrderIndex);
14134 }
14135}
14136
14138{
14139 if (!source)
14140 return;
14141
14142 if (source->GetTypeId() == TYPEID_UNIT || source->GetTypeId() == TYPEID_GAMEOBJECT)
14143 {
14144 if (PlayerTalkClass->GetGossipMenu().Empty() && !PlayerTalkClass->GetQuestMenu().Empty())
14145 {
14146 SendPreparedQuest(source);
14147 return;
14148 }
14149 }
14150
14151 // in case non empty gossip menu (that not included quests list size) show it
14152 // (quest entries from quest menu will be included in list)
14153
14154 uint32 textId = GetGossipTextId(source);
14155
14156 if (uint32 menuId = PlayerTalkClass->GetGossipMenu().GetMenuId())
14157 textId = GetGossipTextId(menuId, source);
14158
14159 PlayerTalkClass->SendGossipMenu(textId, source->GetGUID());
14160}
14161
14162void Player::OnGossipSelect(WorldObject* source, int32 gossipOptionId, uint32 menuId)
14163{
14164 GossipMenu& gossipMenu = PlayerTalkClass->GetGossipMenu();
14165
14166 // if not same, then something funky is going on
14167 if (menuId != gossipMenu.GetMenuId())
14168 return;
14169
14170 GossipMenuItem const* item = gossipMenu.GetItem(gossipOptionId);
14171 if (!item)
14172 return;
14173
14174 GossipOptionNpc gossipOptionNpc = item->OptionNpc;
14175 ObjectGuid guid = source->GetGUID();
14176
14177 if (source->GetTypeId() == TYPEID_GAMEOBJECT)
14178 {
14179 if (gossipOptionNpc != GossipOptionNpc::None)
14180 {
14181 TC_LOG_ERROR("entities.player", "Player '{}' ({}) requests invalid gossip option for GameObject (Entry: {})",
14182 GetName(), GetGUID().ToString(), source->GetEntry());
14183 return;
14184 }
14185 }
14186
14187 int64 cost = int64(item->BoxMoney);
14188 if (!HasEnoughMoney(cost))
14189 {
14191 PlayerTalkClass->SendCloseGossip();
14192 return;
14193 }
14194
14195 if (item->ActionPoiID)
14196 PlayerTalkClass->SendPointOfInterest(item->ActionPoiID);
14197
14198 if (item->ActionMenuID)
14199 {
14200 PrepareGossipMenu(source, item->ActionMenuID);
14201 SendPreparedGossip(source);
14202 }
14203
14204 // types that have their dedicated open opcode dont send WorldPackets::NPC::GossipOptionNPCInteraction
14205 bool handled = true;
14206 switch (gossipOptionNpc)
14207 {
14209 break;
14212 break;
14214 GetSession()->SendTaxiMenu(source->ToCreature());
14215 break;
14217 GetSession()->SendTrainerList(source->ToCreature(), sObjectMgr->GetCreatureTrainerForGossipOption(source->GetEntry(), menuId, item->OrderIndex));
14218 break;
14220 source->CastSpell(source->ToCreature(), 17251, CastSpellExtraArgs(TRIGGERED_FULL_MASK).SetOriginalCaster(GetGUID()));
14221 handled = false;
14222 break;
14224 PlayerTalkClass->SendCloseGossip();
14226 break;
14228 {
14229 BattlegroundTypeId bgTypeId = sBattlegroundMgr->GetBattleMasterBG(source->GetEntry());
14230
14231 if (bgTypeId == BATTLEGROUND_TYPE_NONE)
14232 {
14233 TC_LOG_ERROR("entities.player", "Player '{}' ({}) requested battlegroundlist from an invalid creature ({})",
14234 GetName(), GetGUID().ToString(), source->GetGUID().ToString());
14235 return;
14236 }
14237
14238 sBattlegroundMgr->SendBattlegroundList(this, guid, bgTypeId);
14239 break;
14240 }
14242 GetSession()->SendAuctionHello(guid, source->ToCreature());
14243 break;
14245 PlayerTalkClass->SendCloseGossip();
14247 break;
14249 SetStableMaster(guid);
14250 handled = false;
14251 break;
14253 PlayerTalkClass->SendCloseGossip();
14255 break;
14257 if (Guild* const guild = GetGuild())
14258 guild->SendBankList(GetSession(), 0, true);
14259 else
14261 break;
14263 if (Unit* sourceUnit = source->ToUnit())
14264 sourceUnit->HandleSpellClick(this);
14265 break;
14267 PlayerTalkClass->SendCloseGossip();
14268 CastSpell(nullptr, SPELL_EXPERIENCE_ELIMINATED, true);
14270 break;
14272 PlayerTalkClass->SendCloseGossip();
14275 break;
14277 PlayerTalkClass->SendCloseGossip();
14279 break;
14281 PlayerTalkClass->SendCloseGossip();
14283 break;
14285 break;
14287 break;
14289 break;
14291 break;
14293 break;
14295 break;
14297 break;
14298 case GossipOptionNpc::BarbersChoice: // NYI - unknown if needs sending
14299 break;
14300 default:
14301 handled = false;
14302 break;
14303 }
14304
14305 if (!handled)
14306 {
14307 if (item->GossipNpcOptionID)
14308 {
14309 GossipMenuAddon const* addon = sObjectMgr->GetGossipMenuAddon(menuId);
14310
14312 npcInteraction.GossipGUID = source->GetGUID();
14313 npcInteraction.GossipNpcOptionID = *item->GossipNpcOptionID;
14314 if (addon && addon->FriendshipFactionID)
14315 npcInteraction.FriendshipFactionID = addon->FriendshipFactionID;
14316
14317 SendDirectMessage(npcInteraction.Write());
14318 }
14319 else
14320 {
14321 static constexpr std::array<PlayerInteractionType, AsUnderlyingType(GossipOptionNpc::Count)> GossipOptionNpcToInteractionType =
14322 {
14342 };
14343
14344 PlayerInteractionType interactionType = GossipOptionNpcToInteractionType[AsUnderlyingType(gossipOptionNpc)];
14345 if (interactionType != PlayerInteractionType::None)
14346 {
14348 npcInteraction.Npc = source->GetGUID();
14349 npcInteraction.InteractionType = interactionType;
14350 npcInteraction.Success = true;
14351 SendDirectMessage(npcInteraction.Write());
14352 }
14353 }
14354 }
14355
14356 ModifyMoney(-cost);
14357}
14358
14360{
14361 if (!source)
14363
14364 return GetGossipTextId(GetGossipMenuForSource(source), source);
14365}
14366
14368{
14370
14371 if (!menuId)
14372 return textId;
14373
14374 GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(menuId);
14375
14376 for (GossipMenusContainer::const_iterator itr = menuBounds.first; itr != menuBounds.second; ++itr)
14377 {
14378 // continue if only checks menuid instead of text
14379 if (!itr->second.TextID)
14380 continue;
14381
14382 if (itr->second.Conditions.Meets(this, source))
14383 textId = itr->second.TextID;
14384 }
14385
14386 return textId;
14387}
14388
14390{
14391 switch (source->GetTypeId())
14392 {
14393 case TYPEID_UNIT:
14394 {
14395 uint32 menuIdToShow = source->ToCreature()->GetGossipMenuId();
14396
14397 // if menu id is set by script
14398 if (menuIdToShow)
14399 return menuIdToShow;
14400
14401 // otherwise pick from db based on conditions
14402 for (uint32 menuId : source->ToCreature()->GetCreatureTemplate()->GossipMenuIds)
14403 {
14404 GossipMenusMapBounds menuBounds = sObjectMgr->GetGossipMenusMapBounds(menuId);
14405
14406 for (GossipMenusContainer::const_iterator itr = menuBounds.first; itr != menuBounds.second; ++itr)
14407 {
14408 if (!itr->second.Conditions.Meets(this, source))
14409 continue;
14410
14411 menuIdToShow = menuId;
14412 }
14413 }
14414 return menuIdToShow;
14415 }
14416 case TYPEID_GAMEOBJECT:
14417 return source->ToGameObject()->GetGOInfo()->GetGossipMenuId();
14418 default:
14419 break;
14420 }
14421
14422 return 0;
14423}
14424
14425/*********************************************************/
14426/*** QUEST SYSTEM ***/
14427/*********************************************************/
14428
14430{
14431 return GetQuestMinLevel(quest->GetContentTuningId());
14432}
14433
14435{
14436 if (Optional<ContentTuningLevels> questLevels = sDB2Manager.GetContentTuningData(contentTuningId, m_playerData->CtrOptions->ContentTuningConditionMask))
14437 {
14438 ChrRacesEntry const* race = sChrRacesStore.AssertEntry(GetRace());
14439 FactionTemplateEntry const* raceFaction = sFactionTemplateStore.AssertEntry(race->FactionID);
14440 int32 questFactionGroup = sContentTuningStore.AssertEntry(contentTuningId)->GetScalingFactionGroup();
14441 if (questFactionGroup && raceFaction->FactionGroup != questFactionGroup)
14442 return questLevels->MaxLevel;
14443
14444 return questLevels->MinLevelWithDelta;
14445 }
14446
14447 return 0;
14448}
14449
14451{
14452 if (!quest)
14453 return 0;
14454
14455 return GetQuestLevel(quest->GetContentTuningId());
14456}
14457
14458int32 Player::GetQuestLevel(uint32 contentTuningId) const
14459{
14460 if (Optional<ContentTuningLevels> questLevels = sDB2Manager.GetContentTuningData(contentTuningId, m_playerData->CtrOptions->ContentTuningConditionMask))
14461 {
14462 int32 minLevel = GetQuestMinLevel(contentTuningId);
14463 int32 maxLevel = questLevels->MaxLevel;
14464 int32 level = GetLevel();
14465 if (level >= minLevel)
14466 return std::min(level, maxLevel);
14467
14468 return minLevel;
14469 }
14470
14471 return 0;
14472}
14473
14475{
14476 QuestRelationResult objectQR;
14477 QuestRelationResult objectQIR;
14478
14479 // pets also can have quests
14480 Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, guid);
14481 if (creature)
14482 {
14483 objectQR = sObjectMgr->GetCreatureQuestRelations(creature->GetEntry());
14484 objectQIR = sObjectMgr->GetCreatureQuestInvolvedRelations(creature->GetEntry());
14485 }
14486 else
14487 {
14488 //we should obtain map pointer from GetMap() in 99% of cases. Special case
14489 //only for quests which cast teleport spells on player
14490 Map* _map = IsInWorld() ? GetMap() : sMapMgr->FindMap(GetMapId(), GetInstanceId());
14491 ASSERT(_map);
14492 GameObject* gameObject = _map->GetGameObject(guid);
14493 if (gameObject)
14494 {
14495 objectQR = sObjectMgr->GetGOQuestRelations(gameObject->GetEntry());
14496 objectQIR = sObjectMgr->GetGOQuestInvolvedRelations(gameObject->GetEntry());
14497 }
14498 else
14499 return;
14500 }
14501
14502 QuestMenu &qm = PlayerTalkClass->GetQuestMenu();
14503 qm.ClearMenu();
14504
14505 for (uint32 quest_id : objectQIR)
14506 {
14507 QuestStatus status = GetQuestStatus(quest_id);
14508 if (status == QUEST_STATUS_COMPLETE)
14509 qm.AddMenuItem(quest_id, 4);
14510 else if (status == QUEST_STATUS_INCOMPLETE)
14511 qm.AddMenuItem(quest_id, 4);
14512 //else if (status == QUEST_STATUS_AVAILABLE)
14513 // qm.AddMenuItem(quest_id, 2);
14514 }
14515
14516 for (uint32 quest_id : objectQR)
14517 {
14518 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
14519 if (!quest)
14520 continue;
14521
14522 if (!CanTakeQuest(quest, false))
14523 continue;
14524
14525 if (quest->IsTurnIn() && (!quest->IsRepeatable() || quest->IsDaily() || quest->IsWeekly() || quest->IsMonthly()))
14526 qm.AddMenuItem(quest_id, 0);
14527 else if (quest->IsTurnIn())
14528 qm.AddMenuItem(quest_id, 4);
14529 else if (GetQuestStatus(quest_id) == QUEST_STATUS_NONE)
14530 qm.AddMenuItem(quest_id, 2);
14531 }
14532}
14533
14535{
14536 QuestMenu& questMenu = PlayerTalkClass->GetQuestMenu();
14537 if (questMenu.Empty())
14538 return;
14539
14540 // single element case
14541 if (questMenu.GetMenuItemCount() == 1)
14542 {
14543 QuestMenuItem const& qmi0 = questMenu.GetItem(0);
14544 uint32 questId = qmi0.QuestId;
14545
14546 // Auto open
14547 if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
14548 {
14549 if (qmi0.QuestIcon == 4)
14550 PlayerTalkClass->SendQuestGiverRequestItems(quest, source->GetGUID(), CanRewardQuest(quest, false), true);
14551 // Send completable on repeatable and autoCompletable quest if player don't have quest
14553 else if (!source->hasQuest(questId) && !source->hasInvolvedQuest(questId))
14554 PlayerTalkClass->SendCloseGossip();
14555 else
14556 {
14557 if (quest->IsAutoAccept() && CanAddQuest(quest, true) && CanTakeQuest(quest, true))
14558 AddQuestAndCheckCompletion(quest, source);
14559
14560 if (quest->IsTurnIn() && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly())
14561 PlayerTalkClass->SendQuestGiverRequestItems(quest, source->GetGUID(), CanCompleteRepeatableQuest(quest), true);
14562 else if (quest->IsTurnIn() && !quest->IsDailyOrWeekly() && !quest->IsMonthly())
14563 PlayerTalkClass->SendQuestGiverRequestItems(quest, source->GetGUID(), CanRewardQuest(quest, false), true);
14564 else
14565 PlayerTalkClass->SendQuestGiverQuestDetails(quest, source->GetGUID(), true, false);
14566 }
14567
14568 return;
14569 }
14570 }
14571
14572 PlayerTalkClass->SendQuestGiverQuestListMessage(source);
14573}
14574
14575bool Player::IsActiveQuest(uint32 quest_id) const
14576{
14577 return m_QuestStatus.find(quest_id) != m_QuestStatus.end();
14578}
14579
14580Quest const* Player::GetNextQuest(Object const* questGiver, Quest const* quest) const
14581{
14582 uint32 nextQuestID = quest->GetNextQuestInChain();
14583 if (!nextQuestID)
14584 return nullptr;
14585
14586 if (questGiver == this)
14587 {
14589 return nullptr;
14590
14591 return sObjectMgr->GetQuestTemplate(nextQuestID);
14592 }
14593
14594 //we should obtain map pointer from GetMap() in 99% of cases. Special case
14595 //only for quests which cast teleport spells on player
14596 if (WorldObject const* worldObjectQuestGiver = dynamic_cast<WorldObject const*>(questGiver))
14597 if (!IsInMap(worldObjectQuestGiver))
14598 return nullptr;
14599
14600 if (!questGiver->hasQuest(nextQuestID))
14601 return nullptr;
14602
14603 return sObjectMgr->GetQuestTemplate(nextQuestID);
14604}
14605
14606bool Player::CanSeeStartQuest(Quest const* quest) const
14607{
14608 if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) &&
14609 SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
14610 SatisfyQuestDependentQuests(quest, false) &&
14611 SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
14612 SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false) && SatisfyQuestExpansion(quest, false))
14613 {
14614 return int32(GetLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF)) >= GetQuestMinLevel(quest);
14615 }
14616
14617 return false;
14618}
14619
14620bool Player::CanTakeQuest(Quest const* quest, bool msg) const
14621{
14623 && SatisfyQuestStatus(quest, msg) && SatisfyQuestExclusiveGroup(quest, msg)
14624 && SatisfyQuestClass(quest, msg) && SatisfyQuestRace(quest, msg) && SatisfyQuestLevel(quest, msg)
14625 && SatisfyQuestSkill(quest, msg) && SatisfyQuestReputation(quest, msg)
14626 && SatisfyQuestDependentQuests(quest, msg) && SatisfyQuestTimed(quest, msg)
14627 && SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg)
14628 && SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg)
14629 && SatisfyQuestConditions(quest, msg) && SatisfyQuestExpansion(quest, msg);
14630}
14631
14632bool Player::CanAddQuest(Quest const* quest, bool msg) const
14633{
14634 if (!SatisfyQuestLog(msg))
14635 return false;
14636
14637 uint32 srcitem = quest->GetSrcItemId();
14638 if (srcitem > 0)
14639 {
14640 uint32 count = quest->GetSrcItemCount();
14641 ItemPosCountVec dest;
14642 InventoryResult msg2 = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, srcitem, count);
14643
14644 // player already have max number (in most case 1) source item, no additional item needed and quest can be added.
14645 if (msg2 == EQUIP_ERR_ITEM_MAX_COUNT)
14646 return true;
14647 if (msg2 != EQUIP_ERR_OK)
14648 {
14649 SendEquipError(msg2, nullptr, nullptr, srcitem);
14650 return false;
14651 }
14652 }
14653 return true;
14654}
14655
14656bool Player::CanCompleteQuest(uint32 quest_id, uint32 ignoredQuestObjectiveId /*= 0*/)
14657{
14658 if (quest_id)
14659 {
14660 Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id);
14661 if (!qInfo)
14662 return false;
14663
14664 if (!qInfo->IsRepeatable() && GetQuestRewardStatus(quest_id))
14665 return false; // not allow re-complete quest
14666
14667 // auto complete quest
14668 if (qInfo->IsTurnIn() && CanTakeQuest(qInfo, false))
14669 return true;
14670
14671 QuestStatusMap::iterator itr = m_QuestStatus.find(quest_id);
14672 if (itr == m_QuestStatus.end())
14673 return false;
14674
14675 QuestStatusData &q_status = itr->second;
14676
14677 if (q_status.Status == QUEST_STATUS_INCOMPLETE)
14678 {
14679 for (QuestObjective const& obj : qInfo->GetObjectives())
14680 {
14681 if (ignoredQuestObjectiveId && obj.ID == ignoredQuestObjectiveId)
14682 continue;
14683
14685 {
14686 if (!IsQuestObjectiveComplete(q_status.Slot, qInfo, obj))
14687 return false;
14688 }
14689 }
14690
14692 return false;
14693
14694 if (qInfo->GetLimitTime() && q_status.Timer == 0)
14695 return false;
14696
14697 return true;
14698 }
14699 }
14700 return false;
14701}
14702
14704{
14705 // Solve problem that player don't have the quest and try complete it.
14706 // if repeatable she must be able to complete event if player don't have it.
14707 // Seem that all repeatable quest are DELIVER Flag so, no need to add more.
14708 if (!CanTakeQuest(quest, false))
14709 return false;
14710
14711 if (!CanRewardQuest(quest, false))
14712 return false;
14713
14714 return true;
14715}
14716
14717bool Player::CanRewardQuest(Quest const* quest, bool msg) const
14718{
14719 // quest is disabled
14721 return false;
14722
14723 // not auto complete quest and not completed quest (only cheating case, then ignore without message)
14724 if (!quest->IsDFQuest() && !quest->IsTurnIn() && GetQuestStatus(quest->GetQuestId()) != QUEST_STATUS_COMPLETE)
14725 return false;
14726
14727 // daily quest can't be rewarded (25 daily quest already completed)
14728 if (!SatisfyQuestDay(quest, msg) || !SatisfyQuestWeek(quest, msg) || !SatisfyQuestMonth(quest, msg) || !SatisfyQuestSeasonal(quest, msg))
14729 return false;
14730
14731 // player no longer satisfies the quest's requirements (skill level etc.)
14732 if (!SatisfyQuestLevel(quest, msg) || !SatisfyQuestSkill(quest, msg) || !SatisfyQuestReputation(quest, msg))
14733 return false;
14734
14735 // rewarded and not repeatable quest (only cheating case, then ignore without message)
14736 if (GetQuestRewardStatus(quest->GetQuestId()))
14737 return false;
14738
14739 // prevent receive reward with quest items in bank
14741 {
14742 for (QuestObjective const& obj : quest->GetObjectives())
14743 {
14744 if (obj.Type != QUEST_OBJECTIVE_ITEM || obj.Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM)
14745 continue;
14746
14747 if (GetItemCount(obj.ObjectID) < uint32(obj.Amount))
14748 {
14749 if (msg)
14750 SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr, obj.ObjectID);
14751 return false;
14752 }
14753 }
14754 }
14755
14756 for (QuestObjective const& obj : quest->GetObjectives())
14757 {
14758 switch (obj.Type)
14759 {
14761 if (!HasCurrency(obj.ObjectID, obj.Amount))
14762 return false;
14763 break;
14765 if (!HasEnoughMoney(uint64(obj.Amount)))
14766 return false;
14767 break;
14768 }
14769 }
14770
14771 return true;
14772}
14773
14774void Player::AddQuestAndCheckCompletion(Quest const* quest, Object* questGiver)
14775{
14776 AddQuest(quest, questGiver);
14777
14778 if (CanCompleteQuest(quest->GetQuestId()))
14779 CompleteQuest(quest->GetQuestId());
14780
14781 if (!questGiver)
14782 return;
14783
14784 switch (questGiver->GetTypeId())
14785 {
14786 case TYPEID_UNIT:
14787 PlayerTalkClass->ClearMenus();
14788 questGiver->ToCreature()->AI()->OnQuestAccept(this, quest);
14789 break;
14790 case TYPEID_ITEM:
14791 case TYPEID_CONTAINER:
14794 {
14795 Item* item = static_cast<Item*>(questGiver);
14796 sScriptMgr->OnQuestAccept(this, item, quest);
14797
14798 // There are two cases where the source item is not destroyed when the quest is accepted:
14799 // - It is required to finish the quest, and is an unique item
14800 // - It is the same item present in the source item field (item that would be given on quest accept)
14801 bool destroyItem = true;
14802
14803 for (QuestObjective const& obj : quest->GetObjectives())
14804 {
14805 if (obj.Type == QUEST_OBJECTIVE_ITEM && uint32(obj.ObjectID) == item->GetEntry() && item->GetTemplate()->GetMaxCount() > 0)
14806 {
14807 destroyItem = false;
14808 break;
14809 }
14810 }
14811
14812 if (quest->GetSrcItemId() == item->GetEntry())
14813 destroyItem = false;
14814
14815 if (destroyItem)
14816 DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
14817
14818 break;
14819 }
14820 case TYPEID_GAMEOBJECT:
14821 PlayerTalkClass->ClearMenus();
14822 questGiver->ToGameObject()->AI()->OnQuestAccept(this, quest);
14823 break;
14824 default:
14825 break;
14826 }
14827}
14828
14829bool Player::CanRewardQuest(Quest const* quest, LootItemType rewardType, uint32 rewardId, bool msg) const
14830{
14831 ItemPosCountVec dest;
14832 if (quest->GetRewChoiceItemsCount() > 0)
14833 {
14834 switch (rewardType)
14835 {
14836 case LootItemType::Item:
14837 {
14838 for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
14839 {
14840 if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemType[i] == LootItemType::Item && quest->RewardChoiceItemId[i] == rewardId)
14841 {
14843 if (res != EQUIP_ERR_OK)
14844 {
14845 if (msg)
14846 SendQuestFailed(quest->GetQuestId(), res);
14847
14848 return false;
14849 }
14850 }
14851 }
14852 break;
14853 }
14855 break;
14856 default:
14857 break;
14858 }
14859 }
14860
14861 if (quest->GetRewItemsCount() > 0)
14862 {
14863 for (uint32 i = 0; i < quest->GetRewItemsCount(); ++i)
14864 {
14865 if (quest->RewardItemId[i])
14866 {
14868 if (res != EQUIP_ERR_OK)
14869 {
14870 if (msg)
14871 SendQuestFailed(quest->GetQuestId(), res);
14872
14873 return false;
14874 }
14875 }
14876 }
14877 }
14878
14879 // QuestPackageItem.db2
14880 if (quest->GetQuestPackageID())
14881 {
14882 bool hasFilteredQuestPackageReward = false;
14883 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
14884 {
14885 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
14886 {
14887 if (questPackageItem->ItemID != int32(rewardId))
14888 continue;
14889
14890 if (CanSelectQuestPackageItem(questPackageItem))
14891 {
14892 hasFilteredQuestPackageReward = true;
14893 InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemQuantity);
14894 if (res != EQUIP_ERR_OK)
14895 {
14896 SendEquipError(res, nullptr, nullptr, questPackageItem->ItemID);
14897 return false;
14898 }
14899 }
14900 }
14901 }
14902
14903 if (!hasFilteredQuestPackageReward)
14904 {
14905 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(quest->GetQuestPackageID()))
14906 {
14907 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
14908 {
14909 if (questPackageItem->ItemID != int32(rewardId))
14910 continue;
14911
14912 InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemQuantity);
14913 if (res != EQUIP_ERR_OK)
14914 {
14915 SendEquipError(res, nullptr, nullptr, questPackageItem->ItemID);
14916 return false;
14917 }
14918 }
14919 }
14920 }
14921 }
14922
14923 return true;
14924}
14925
14926void Player::AddQuest(Quest const* quest, Object* questGiver)
14927{
14928 uint16 log_slot = FindQuestSlot(0);
14929
14930 if (log_slot >= MAX_QUEST_LOG_SIZE) // Player does not have any free slot in the quest log
14931 return;
14932
14933 uint32 quest_id = quest->GetQuestId();
14934
14935 // if not exist then created with set uState == NEW and rewarded=false
14936 auto questStatusItr = m_QuestStatus.emplace(quest_id, QuestStatusData{}).first;
14937 QuestStatusData& questStatusData = questStatusItr->second;
14938 QuestStatus oldStatus = questStatusData.Status;
14939
14940 // check for repeatable quests status reset
14941 SetQuestSlot(log_slot, quest_id);
14942 questStatusData.Slot = log_slot;
14943 questStatusData.Status = QUEST_STATUS_INCOMPLETE;
14944 questStatusData.Explored = false;
14945
14946 for (QuestObjective const& obj : quest->GetObjectives())
14947 {
14948 m_questObjectiveStatus.emplace(std::make_pair(QuestObjectiveType(obj.Type), obj.ObjectID), QuestObjectiveStatusData { questStatusItr, obj.ID });
14949 switch (obj.Type)
14950 {
14953 if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(obj.ObjectID))
14954 GetReputationMgr().SetVisible(factionEntry);
14955 break;
14957 m_questObjectiveCriteriaMgr->ResetCriteriaTree(obj.ObjectID);
14958 break;
14959 default:
14960 break;
14961 }
14962 }
14963
14964 GiveQuestSourceItem(quest);
14966
14967 time_t endTime = 0;
14968 if (uint32 limittime = quest->GetLimitTime())
14969 {
14970 // shared timed quest
14971 if (questGiver && questGiver->GetTypeId() == TYPEID_PLAYER)
14972 limittime = questGiver->ToPlayer()->getQuestStatusMap()[quest_id].Timer / IN_MILLISECONDS;
14973
14974 AddTimedQuest(quest_id);
14975 questStatusData.Timer = limittime * IN_MILLISECONDS;
14976 endTime = GameTime::GetGameTime() + limittime;
14977 }
14978 else
14979 questStatusData.Timer = 0;
14980
14981 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
14982 {
14983 pvpInfo.IsHostile = true;
14985 }
14986
14987 if (quest->GetSrcSpell() > 0)
14988 {
14989 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(quest->GetSrcSpell(), GetMap()->GetDifficultyID());
14990 Unit* caster = this;
14991 if (questGiver && questGiver->IsUnit() && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_ACCEPT) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER) && !spellInfo->HasTargetType(TARGET_DEST_CASTER_SUMMON))
14992 caster = questGiver->ToUnit();
14993
14994 caster->CastSpell(this, spellInfo->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK).SetCastDifficulty(spellInfo->Difficulty));
14995 }
14996
14997 SetQuestSlotEndTime(log_slot, endTime);
14998 questStatusData.AcceptTime = GameTime::GetGameTime();
14999
15001
15003
15004 SendQuestUpdate(quest_id);
15005
15006 if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled
15007 {
15008 // prepare Quest Tracker datas
15010 stmt->setUInt32(0, quest_id);
15011 stmt->setUInt64(1, GetGUID().GetCounter());
15012 stmt->setString(2, GitRevision::GetHash());
15013 stmt->setString(3, GitRevision::GetDate());
15014
15015 // add to Quest Tracker
15016 CharacterDatabase.Execute(stmt);
15017 }
15018
15019 sScriptMgr->OnQuestStatusChange(this, quest_id);
15020 sScriptMgr->OnQuestStatusChange(this, quest, oldStatus, questStatusData.Status);
15021}
15022
15024{
15025 if (quest_id)
15026 {
15028
15029 if (QuestStatusData const* questStatus = Trinity::Containers::MapGetValuePtr(m_QuestStatus, quest_id))
15030 SetQuestSlotState(questStatus->Slot, QUEST_STATE_COMPLETE);
15031
15032 if (Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id))
15033 if (qInfo->HasFlag(QUEST_FLAGS_TRACKING_EVENT))
15034 RewardQuest(qInfo, LootItemType::Item, 0, this, false);
15035 }
15036
15037 if (sWorld->getBoolConfig(CONFIG_QUEST_ENABLE_QUEST_TRACKER)) // check if Quest Tracker is enabled
15038 {
15039 // prepare Quest Tracker data
15041 stmt->setUInt32(0, quest_id);
15042 stmt->setUInt64(1, GetGUID().GetCounter());
15043
15044 // add to Quest Tracker
15045 CharacterDatabase.Execute(stmt);
15046 }
15047}
15048
15050{
15051 if (quest_id)
15052 {
15054
15055 uint16 log_slot = FindQuestSlot(quest_id);
15056 if (log_slot < MAX_QUEST_LOG_SIZE)
15058 }
15059}
15060
15062{
15063 return quest->MoneyValue(this) * sWorld->getRate(RATE_MONEY_QUEST);
15064}
15065
15067{
15068 bool rewarded = IsQuestRewarded(quest->GetQuestId()) && !quest->IsDFQuest();
15069
15070 // Not give XP in case already completed once repeatable quest
15071 if (rewarded)
15072 return 0;
15073
15074 uint32 XP = quest->XPValue(this) * sWorld->getRate(RATE_XP_QUEST);
15075
15076 // handle SPELL_AURA_MOD_XP_QUEST_PCT auras
15078 for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i)
15079 AddPct(XP, (*i)->GetAmount());
15080
15081 return XP;
15082}
15083
15085{
15086 ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID);
15087 if (!rewardProto)
15088 return false;
15089
15090 if ((rewardProto->HasFlag(ITEM_FLAG2_FACTION_ALLIANCE) && GetTeam() != ALLIANCE) ||
15091 (rewardProto->HasFlag(ITEM_FLAG2_FACTION_HORDE) && GetTeam() != HORDE))
15092 return false;
15093
15094 switch (questPackageItem->DisplayType)
15095 {
15097 return rewardProto->IsUsableByLootSpecialization(this, true);
15099 return !rewardProto->ItemSpecClassMask || (rewardProto->ItemSpecClassMask & GetClassMask()) != 0;
15101 return true;
15102 default:
15103 break;
15104 }
15105
15106 return false;
15107}
15108
15109void Player::RewardQuestPackage(uint32 questPackageId, ItemContext context, uint32 onlyItemId /*= 0*/)
15110{
15111 bool hasFilteredQuestPackageReward = false;
15112 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(questPackageId))
15113 {
15114 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
15115 {
15116 if (onlyItemId && questPackageItem->ItemID != int32(onlyItemId))
15117 continue;
15118
15119 if (CanSelectQuestPackageItem(questPackageItem))
15120 {
15121 hasFilteredQuestPackageReward = true;
15122 ItemPosCountVec dest;
15123 if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemQuantity) == EQUIP_ERR_OK)
15124 {
15125 Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, GenerateItemRandomBonusListId(questPackageItem->ItemID), {}, context);
15126 SendNewItem(item, questPackageItem->ItemQuantity, true, false);
15127 }
15128 }
15129 }
15130 }
15131
15132 if (!hasFilteredQuestPackageReward)
15133 {
15134 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(questPackageId))
15135 {
15136 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
15137 {
15138 if (onlyItemId && questPackageItem->ItemID != int32(onlyItemId))
15139 continue;
15140
15141 ItemPosCountVec dest;
15142 if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemQuantity) == EQUIP_ERR_OK)
15143 {
15144 Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, GenerateItemRandomBonusListId(questPackageItem->ItemID), {}, context);
15145 SendNewItem(item, questPackageItem->ItemQuantity, true, false);
15146 }
15147 }
15148 }
15149 }
15150}
15151
15152void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rewardId, Object* questGiver, bool announce)
15153{
15154 //this THING should be here to protect code from quest, which cast on player far teleport as a reward
15155 //should work fine, cause far teleport will be executed in Player::Update()
15156 SetCanDelayTeleport(true);
15157
15158 uint32 quest_id = quest->GetQuestId();
15159 QuestStatus oldStatus = GetQuestStatus(quest_id);
15160
15161 for (QuestObjective const& obj : quest->GetObjectives())
15162 {
15163 switch (obj.Type)
15164 {
15166 {
15167 int32 amountToDestroy = obj.Amount;
15169 amountToDestroy = std::numeric_limits<uint32>::max();
15170 DestroyItemCount(obj.ObjectID, amountToDestroy, true);
15171 break;
15172 }
15174 RemoveCurrency(obj.ObjectID, obj.Amount, CurrencyDestroyReason::QuestTurnin);
15175 break;
15176 }
15177 }
15178
15180 {
15181 for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
15182 {
15183 if (quest->ItemDrop[i])
15184 {
15185 uint32 count = quest->ItemDropQuantity[i];
15186 if (!count)
15187 count = std::numeric_limits<uint32>::max();
15188 DestroyItemCount(quest->ItemDrop[i], count, true);
15189 }
15190 }
15191 }
15192
15193 RemoveTimedQuest(quest_id);
15194
15195 if (quest->GetRewItemsCount() > 0)
15196 {
15197 for (uint32 i = 0; i < quest->GetRewItemsCount(); ++i)
15198 {
15199 if (uint32 itemId = quest->RewardItemId[i])
15200 {
15201 ItemPosCountVec dest;
15202 if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, quest->RewardItemCount[i]) == EQUIP_ERR_OK)
15203 {
15204 Item* item = StoreNewItem(dest, itemId, true, GenerateItemRandomBonusListId(itemId), {}, ItemContext::Quest_Reward);
15205 SendNewItem(item, quest->RewardItemCount[i], true, false);
15206 }
15207 else if (quest->IsDFQuest())
15209 }
15210 }
15211 }
15212
15213 CurrencyGainSource currencyGainSource = [&]() -> CurrencyGainSource
15214 {
15216 {
15217 if (quest->IsWorldQuest())
15219
15221 }
15222
15224
15225 if (quest->IsDaily())
15227 else if (quest->IsWeekly())
15229 else if (quest->IsWorldQuest())
15231
15232 return gainSource;
15233 }();
15234
15235 switch (rewardType)
15236 {
15237 case LootItemType::Item:
15238 {
15239 ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(rewardId);
15240 if (rewardProto && quest->GetRewChoiceItemsCount())
15241 {
15242 for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
15243 {
15244 if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemType[i] == LootItemType::Item && quest->RewardChoiceItemId[i] == rewardId)
15245 {
15246 ItemPosCountVec dest;
15247 if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, rewardId, quest->RewardChoiceItemCount[i]) == EQUIP_ERR_OK)
15248 {
15249 Item* item = StoreNewItem(dest, rewardId, true, GenerateItemRandomBonusListId(rewardId), {}, ItemContext::Quest_Reward);
15250 SendNewItem(item, quest->RewardChoiceItemCount[i], true, false);
15251 }
15252 }
15253 }
15254 }
15255
15256 // QuestPackageItem.db2
15257 if (rewardProto && quest->GetQuestPackageID())
15259 break;
15260 }
15262 {
15263 if (sCurrencyTypesStore.HasRecord(rewardId) && quest->GetRewChoiceItemsCount())
15264 for (uint32 i = 0; i < QUEST_REWARD_CHOICES_COUNT; ++i)
15265 if (quest->RewardChoiceItemId[i] && quest->RewardChoiceItemType[i] == LootItemType::Currency && quest->RewardChoiceItemId[i] == rewardId)
15266 AddCurrency(quest->RewardChoiceItemId[i], quest->RewardChoiceItemCount[i], currencyGainSource);
15267
15268 break;
15269 }
15270 default:
15271 break;
15272 }
15273
15274 for (uint8 i = 0; i < QUEST_REWARD_CURRENCY_COUNT; ++i)
15275 if (quest->RewardCurrencyId[i])
15276 AddCurrency(quest->RewardCurrencyId[i], quest->RewardCurrencyCount[i], currencyGainSource);
15277
15278 if (uint32 skill = quest->GetRewardSkillId())
15279 UpdateSkillPro(skill, 1000, quest->GetRewardSkillPoints());
15280
15281 uint16 log_slot = FindQuestSlot(quest_id);
15282 if (log_slot < MAX_QUEST_LOG_SIZE)
15283 SetQuestSlot(log_slot, 0);
15284
15285 uint32 XP = GetQuestXPReward(quest);
15286
15287 int32 moneyRew = 0;
15288 if (!IsMaxLevel())
15289 GiveXP(XP, nullptr);
15290 else
15291 moneyRew = int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY));
15292
15293 moneyRew += GetQuestMoneyReward(quest);
15294
15295 if (moneyRew)
15296 {
15297 ModifyMoney(moneyRew);
15298
15299 if (moneyRew > 0)
15301
15303 }
15304
15305 // honor reward
15306 if (uint32 honor = quest->CalculateHonorGain(GetLevel()))
15307 RewardHonor(nullptr, 0, honor);
15308
15309 // title reward
15310 if (quest->GetRewTitle())
15311 {
15312 if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetRewTitle()))
15313 SetTitle(titleEntry);
15314 }
15315
15316 // Send reward mail
15317 if (uint32 mail_template_id = quest->GetRewMailTemplateId())
15318 {
15320 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
15321 if (uint32 questMailSender = quest->GetRewMailSenderEntry())
15322 MailDraft(mail_template_id).SendMailTo(trans, this, questMailSender, MAIL_CHECK_MASK_HAS_BODY, quest->GetRewMailDelaySecs());
15323 else
15324 MailDraft(mail_template_id).SendMailTo(trans, this, questGiver, MAIL_CHECK_MASK_HAS_BODY, quest->GetRewMailDelaySecs());
15325 CharacterDatabase.CommitTransaction(trans);
15326 }
15327
15328 if (quest->IsDaily() || quest->IsDFQuest())
15329 {
15330 SetDailyQuestStatus(quest_id);
15331 if (quest->IsDaily())
15332 {
15336 }
15337 }
15338 else if (quest->IsWeekly())
15339 SetWeeklyQuestStatus(quest_id);
15340 else if (quest->IsMonthly())
15341 SetMonthlyQuestStatus(quest_id);
15342 else if (quest->IsSeasonal())
15343 SetSeasonalQuestStatus(quest_id);
15344
15345 RemoveActiveQuest(quest_id, false);
15347 SetRewardedQuest(quest_id);
15348
15349 SendQuestReward(quest, questGiver ? questGiver->ToCreature() : nullptr, XP, !announce);
15350
15351 RewardReputation(quest);
15352
15353 // cast spells after mark quest complete (some spells have quest completed state requirements in spell_area data)
15354 if (quest->GetRewSpell() > 0)
15355 {
15356 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(quest->GetRewSpell(), GetMap()->GetDifficultyID());
15357 Unit* caster = this;
15358 if (questGiver && questGiver->IsUnit() && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER))
15359 caster = questGiver->ToUnit();
15360
15361 caster->CastSpell(this, spellInfo->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK).SetCastDifficulty(spellInfo->Difficulty));
15362 }
15363 else
15364 {
15365 for (QuestRewardDisplaySpell displaySpell : quest->RewardDisplaySpell)
15366 {
15367 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(displaySpell.PlayerConditionId))
15368 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
15369 continue;
15370
15371 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(displaySpell.SpellId, GetMap()->GetDifficultyID());
15372 Unit* caster = this;
15373 if (questGiver && questGiver->IsUnit() && !quest->HasFlag(QUEST_FLAGS_PLAYER_CAST_COMPLETE) && !spellInfo->HasTargetType(TARGET_UNIT_CASTER))
15374 caster = questGiver->ToUnit();
15375
15376 caster->CastSpell(this, spellInfo->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK).SetCastDifficulty(spellInfo->Difficulty));
15377 }
15378 }
15379
15380 if (quest->GetZoneOrSort() > 0)
15385
15386 // make full db save
15387 SaveToDB(false);
15388
15389 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
15390 SetQuestCompletedBit(questBit, true);
15391
15392 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
15393 {
15396 }
15397
15398 SendQuestUpdate(quest_id, true, true);
15399
15400 bool updateVisibility = false;
15402 updateVisibility = PhasingHandler::OnConditionChange(this, false);
15403
15404 //lets remove flag for delayed teleports
15405 SetCanDelayTeleport(false);
15406
15407 if (questGiver && questGiver->IsWorldObject())
15408 {
15409 //For AutoSubmition was added plr case there as it almost same exclute AI script cases.
15410 // Send next quest
15411 if (Quest const* nextQuest = GetNextQuest(questGiver, quest))
15412 {
15413 // Only send the quest to the player if the conditions are met
15414 if (CanTakeQuest(nextQuest, false))
15415 {
15416 if (nextQuest->IsAutoAccept() && CanAddQuest(nextQuest, true))
15417 AddQuestAndCheckCompletion(nextQuest, questGiver);
15418
15419 PlayerTalkClass->SendQuestGiverQuestDetails(nextQuest, questGiver->GetGUID(), true, false);
15420 }
15421 }
15422
15423 PlayerTalkClass->ClearMenus();
15424 if (Creature* creatureQGiver = questGiver->ToCreature())
15425 creatureQGiver->AI()->OnQuestReward(this, quest, rewardType, rewardId);
15426 else if (GameObject* goQGiver = questGiver->ToGameObject())
15427 goQGiver->AI()->OnQuestReward(this, quest, rewardType, rewardId);
15428 }
15429
15430 sScriptMgr->OnQuestStatusChange(this, quest_id);
15431 sScriptMgr->OnQuestStatusChange(this, quest, oldStatus, QUEST_STATUS_REWARDED);
15432
15433 if (updateVisibility)
15435}
15436
15438{
15439 m_RewardedQuests.insert(quest_id);
15441
15442 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
15443 SetQuestCompletedBit(questBit, true);
15444}
15445
15447{
15448 if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
15449 {
15450 QuestStatus qStatus = GetQuestStatus(questId);
15451
15452 // we can only fail incomplete quest or...
15453 if (qStatus != QUEST_STATUS_INCOMPLETE)
15454 {
15455 // completed timed quest with no requirements
15456 if (qStatus != QUEST_STATUS_COMPLETE || !quest->GetLimitTime() || !quest->GetObjectives().empty())
15457 return;
15458 }
15459
15461
15462 uint16 log_slot = FindQuestSlot(questId);
15463
15464 if (log_slot < MAX_QUEST_LOG_SIZE)
15466
15467 if (quest->GetLimitTime())
15468 {
15469 QuestStatusData& q_status = m_QuestStatus[questId];
15470
15471 RemoveTimedQuest(questId);
15472 q_status.Timer = 0;
15473
15474 SendQuestTimerFailed(questId);
15475 }
15476 else
15477 SendQuestFailed(questId);
15478
15479 // Destroy quest items on quest failure.
15480 for (QuestObjective const& obj : quest->GetObjectives())
15481 if (obj.Type == QUEST_OBJECTIVE_ITEM)
15482 if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(obj.ObjectID))
15483 if (itemTemplate->GetBonding() == BIND_QUEST)
15484 DestroyItemCount(obj.ObjectID, obj.Amount, true, true);
15485
15486 // Destroy items received during the quest.
15487 for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
15488 if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
15489 if (quest->ItemDropQuantity[i] && itemTemplate->GetBonding() == BIND_QUEST)
15490 DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
15491 }
15492}
15493
15495{
15496 for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
15497 {
15498 uint32 questId = GetQuestSlotQuestId(slot);
15499 if (!questId)
15500 continue;
15501
15502 if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
15503 if (quest->HasFlag(flag))
15504 FailQuest(questId);
15505 }
15506}
15507
15509{
15510 if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
15511 {
15512 // Destroy quest items on quest abandon.
15513 for (QuestObjective const& obj : quest->GetObjectives())
15514 if (obj.Type == QUEST_OBJECTIVE_ITEM)
15515 if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(obj.ObjectID))
15516 if (itemTemplate->GetBonding() == BIND_QUEST)
15517 DestroyItemCount(obj.ObjectID, obj.Amount, true, true);
15518
15519 // Destroy items received during the quest.
15520 for (uint8 i = 0; i < QUEST_ITEM_DROP_COUNT; ++i)
15521 if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(quest->ItemDrop[i]))
15522 if (quest->ItemDropQuantity[i] && itemTemplate->GetBonding() == BIND_QUEST)
15523 DestroyItemCount(quest->ItemDrop[i], quest->ItemDropQuantity[i], true, true);
15524 }
15525}
15526
15527bool Player::SatisfyQuestSkill(Quest const* qInfo, bool msg) const
15528{
15529 uint32 skill = qInfo->GetRequiredSkill();
15530
15531 // skip 0 case RequiredSkill
15532 if (skill == 0)
15533 return true;
15534
15535 // check skill value
15536 if (GetSkillValue(skill) < qInfo->GetRequiredSkillValue())
15537 {
15538 if (msg)
15539 {
15541 TC_LOG_DEBUG("misc", "Player::SatisfyQuestSkill: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't have the required skill value.",
15542 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15543 }
15544
15545 return false;
15546 }
15547
15548 return true;
15549}
15550
15551bool Player::SatisfyQuestLevel(Quest const* qInfo, bool msg) const
15552{
15553 return SatisfyQuestMinLevel(qInfo, msg) && SatisfyQuestMaxLevel(qInfo, msg);
15554}
15555
15556bool Player::SatisfyQuestMinLevel(Quest const* qInfo, bool msg) const
15557{
15558 if (GetLevel() < GetQuestMinLevel(qInfo))
15559 {
15560 if (msg)
15561 {
15563 TC_LOG_DEBUG("misc", "Player::SatisfyQuestMinLevel: Sent QUEST_ERR_FAILED_LOW_LEVEL (QuestID: {}) because player '{}' ({}) doesn't have the required (min) level.",
15564 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15565 }
15566 return false;
15567 }
15568 return true;
15569}
15570
15571bool Player::SatisfyQuestMaxLevel(Quest const* qInfo, bool msg) const
15572{
15573 if (qInfo->GetMaxLevel() > 0 && GetLevel() > qInfo->GetMaxLevel())
15574 {
15575 if (msg)
15576 {
15577 SendCanTakeQuestResponse(QUEST_ERR_NONE); // There doesn't seem to be a specific response for too high player level
15578 TC_LOG_DEBUG("misc", "Player::SatisfyQuestMaxLevel: Sent QUEST_ERR_FAILED_LOW_LEVEL (QuestID: {}) because player '{}' ({}) doesn't have the required (max) level.",
15579 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15580 }
15581 return false;
15582 }
15583 return true;
15584}
15585
15586bool Player::SatisfyQuestLog(bool msg) const
15587{
15588 // exist free slot
15590 return true;
15591
15592 if (msg)
15593 {
15595 SendDirectMessage(data.Write());
15596 }
15597 return false;
15598}
15599
15600bool Player::SatisfyQuestDependentQuests(Quest const* qInfo, bool msg) const
15601{
15602 return SatisfyQuestPreviousQuest(qInfo, msg) && SatisfyQuestDependentPreviousQuests(qInfo, msg) &&
15604}
15605
15606bool Player::SatisfyQuestPreviousQuest(Quest const* qInfo, bool msg) const
15607{
15608 // No previous quest (might be first quest in a series)
15609 if (!qInfo->GetPrevQuestId())
15610 return true;
15611
15612 uint32 prevId = std::abs(qInfo->GetPrevQuestId());
15613 // If positive previous quest rewarded, return true
15614 if (qInfo->GetPrevQuestId() > 0 && m_RewardedQuests.count(prevId) > 0)
15615 return true;
15616
15617 // If negative previous quest active, return true
15618 if (qInfo->GetPrevQuestId() < 0 && GetQuestStatus(prevId) == QUEST_STATUS_INCOMPLETE)
15619 return true;
15620
15621 // Has positive prev. quest in non-rewarded state
15622 // and negative prev. quest in non-active state
15623 if (msg)
15624 {
15626 TC_LOG_DEBUG("misc", "Player::SatisfyQuestPreviousQuest: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't have required quest {}.",
15627 qInfo->GetQuestId(), GetName(), GetGUID().ToString(), prevId);
15628 }
15629
15630 return false;
15631}
15632
15633bool Player::SatisfyQuestDependentPreviousQuests(Quest const* qInfo, bool msg) const
15634{
15635 // No previous quest (might be first quest in a series)
15636 if (qInfo->DependentPreviousQuests.empty())
15637 return true;
15638
15639 for (uint32 prevId : qInfo->DependentPreviousQuests)
15640 {
15641 // checked in startup
15642 Quest const* questInfo = sObjectMgr->GetQuestTemplate(prevId);
15643 ASSERT(questInfo);
15644
15645 // If any of the previous quests completed, return true
15646 if (IsQuestRewarded(prevId))
15647 {
15648 // skip one-from-all exclusive group
15649 if (questInfo->GetExclusiveGroup() >= 0)
15650 return true;
15651
15652 // each-from-all exclusive group (< 0)
15653 // can be start if only all quests in prev quest exclusive group completed and rewarded
15654 auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(questInfo->GetExclusiveGroup());
15655 for (auto itr = bounds.first; itr != bounds.second; ++itr)
15656 {
15657 // skip checked quest id, only state of other quests in group is interesting
15658 uint32 exclusiveQuestId = itr->second;
15659 if (exclusiveQuestId == prevId)
15660 continue;
15661
15662 // alternative quest from group also must be completed and rewarded (reported)
15663 if (!IsQuestRewarded(exclusiveQuestId))
15664 {
15665 if (msg)
15666 {
15668 TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentPreviousQuests: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't have the required quest (1).",
15669 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15670 }
15671
15672 return false;
15673 }
15674 }
15675
15676 return true;
15677 }
15678 }
15679
15680 // Has only prev. quests in non-rewarded state
15681 if (msg)
15682 {
15684 TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentPreviousQuests: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't have required quest (2).",
15685 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15686 }
15687
15688 return false;
15689}
15690
15691bool Player::SatisfyQuestBreadcrumbQuest(Quest const* qInfo, bool msg) const
15692{
15693 uint32 breadcrumbTargetQuestId = std::abs(qInfo->GetBreadcrumbForQuestId());
15694
15695 //If this is not a breadcrumb quest.
15696 if (!breadcrumbTargetQuestId)
15697 return true;
15698
15699 // If the target quest is not available
15700 if (!CanTakeQuest(sObjectMgr->GetQuestTemplate(breadcrumbTargetQuestId), false))
15701 {
15702 if (msg)
15703 {
15705 TC_LOG_DEBUG("misc", "Player::SatisfyQuestBreadcrumbQuest: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: {}) because target quest (QuestID: {}) is not available to player '{}' ({}).",
15706 qInfo->GetQuestId(), breadcrumbTargetQuestId, GetName(), GetGUID().ToString());
15707 }
15708
15709 return false;
15710 }
15711
15712 return true;
15713}
15714
15716{
15717 for (uint32 breadcrumbQuestId : qInfo->DependentBreadcrumbQuests)
15718 {
15719 QuestStatus status = GetQuestStatus(breadcrumbQuestId);
15720 // If any of the breadcrumb quests are in the quest log, return false.
15721 if (status == QUEST_STATUS_INCOMPLETE || status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_FAILED)
15722 {
15723 if (msg)
15724 {
15726 TC_LOG_DEBUG("misc", "Player::SatisfyQuestDependentBreadcrumbQuests: Sent INVALIDREASON_DONT_HAVE_REQ (QuestID: {}) because player '{}' ({}) has a breadcrumb quest towards this quest in the quest log.",
15727 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15728 }
15729
15730 return false;
15731 }
15732 }
15733 return true;
15734}
15735
15736bool Player::SatisfyQuestClass(Quest const* qInfo, bool msg) const
15737{
15738 uint32 reqClass = qInfo->GetAllowableClasses();
15739
15740 if (reqClass == 0)
15741 return true;
15742
15743 if ((reqClass & GetClassMask()) == 0)
15744 {
15745 if (msg)
15746 {
15748 TC_LOG_DEBUG("misc", "Player::SatisfyQuestClass: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't have required class.",
15749 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15750 }
15751
15752 return false;
15753 }
15754
15755 return true;
15756}
15757
15758bool Player::SatisfyQuestRace(Quest const* qInfo, bool msg) const
15759{
15760 if (!qInfo->GetAllowableRaces().HasRace(GetRace()))
15761 {
15762 if (msg)
15763 {
15765 TC_LOG_DEBUG("misc", "Player::SatisfyQuestRace: Sent QUEST_ERR_FAILED_WRONG_RACE (QuestID: {}) because player '{}' ({}) doesn't have required race.",
15766 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15767
15768 }
15769 return false;
15770 }
15771 return true;
15772}
15773
15774bool Player::SatisfyQuestReputation(Quest const* qInfo, bool msg) const
15775{
15776 uint32 fIdMin = qInfo->GetRequiredMinRepFaction(); //Min required rep
15777 if (fIdMin && GetReputationMgr().GetReputation(fIdMin) < qInfo->GetRequiredMinRepValue())
15778 {
15779 if (msg)
15780 {
15782 TC_LOG_DEBUG("misc", "Player::SatisfyQuestReputation: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't required reputation (min).",
15783 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15784 }
15785 return false;
15786 }
15787
15788 uint32 fIdMax = qInfo->GetRequiredMaxRepFaction(); //Max required rep
15789 if (fIdMax && GetReputationMgr().GetReputation(fIdMax) >= qInfo->GetRequiredMaxRepValue())
15790 {
15791 if (msg)
15792 {
15794 TC_LOG_DEBUG("misc", "SatisfyQuestReputation: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't required reputation (max).",
15795 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15796 }
15797 return false;
15798 }
15799
15800 return true;
15801}
15802
15803bool Player::SatisfyQuestStatus(Quest const* qInfo, bool msg) const
15804{
15806 {
15807 if (msg)
15808 {
15810 TC_LOG_DEBUG("misc", "Player::SatisfyQuestStatus: Sent QUEST_STATUS_REWARDED (QuestID: {}) because player '{}' ({}) quest status is already REWARDED.",
15811 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15812 }
15813 return false;
15814 }
15815
15817 {
15818 if (msg)
15819 {
15821 TC_LOG_DEBUG("misc", "Player::SatisfyQuestStatus: Sent QUEST_ERR_ALREADY_ON1 (QuestID: {}) because player '{}' ({}) quest status is not NONE.",
15822 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15823 }
15824 return false;
15825 }
15826 return true;
15827}
15828
15829bool Player::SatisfyQuestConditions(Quest const* qInfo, bool msg) const
15830{
15831 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, qInfo->GetQuestId(), this))
15832 {
15833 if (msg)
15834 {
15836 TC_LOG_DEBUG("misc", "Player::SatisfyQuestConditions: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) doesn't meet conditions.",
15837 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15838 }
15839 TC_LOG_DEBUG("condition", "Player::SatisfyQuestConditions: conditions not met for quest {}", qInfo->GetQuestId());
15840 return false;
15841 }
15842 return true;
15843}
15844
15845bool Player::SatisfyQuestTimed(Quest const* qInfo, bool msg) const
15846{
15847 if (!m_timedquests.empty() && qInfo->GetLimitTime())
15848 {
15849 if (msg)
15850 {
15852 TC_LOG_DEBUG("misc", "Player::SatisfyQuestTimed: Sent QUEST_ERR_ONLY_ONE_TIMED (QuestID: {}) because player '{}' ({}) is already on a timed quest.",
15853 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15854 }
15855 return false;
15856 }
15857 return true;
15858}
15859
15860bool Player::SatisfyQuestExclusiveGroup(Quest const* qInfo, bool msg) const
15861{
15862 // non positive exclusive group, if > 0 then can be start if any other quest in exclusive group already started/completed
15863 if (qInfo->GetExclusiveGroup() <= 0)
15864 return true;
15865
15866 auto bounds = sObjectMgr->GetExclusiveQuestGroupBounds(qInfo->GetExclusiveGroup());
15867 for (auto itr = bounds.first; itr != bounds.second; ++itr)
15868 {
15869 uint32 exclude_Id = itr->second;
15870
15871 // skip checked quest id, only state of other quests in group is interesting
15872 if (exclude_Id == qInfo->GetQuestId())
15873 continue;
15874
15875 // not allow have daily quest if daily quest from exclusive group already recently completed
15876 Quest const* Nquest = sObjectMgr->GetQuestTemplate(exclude_Id);
15877 ASSERT(Nquest);
15878 if (!SatisfyQuestDay(Nquest, false) || !SatisfyQuestWeek(Nquest, false) || !SatisfyQuestSeasonal(Nquest, false))
15879 {
15880 if (msg)
15881 {
15883 TC_LOG_DEBUG("misc", "Player::SatisfyQuestExclusiveGroup: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) already did daily quests in exclusive group.",
15884 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15885 }
15886
15887 return false;
15888 }
15889
15890 // alternative quest already started or completed - but don't check rewarded states if both are repeatable
15891 if (GetQuestStatus(exclude_Id) != QUEST_STATUS_NONE || (!(qInfo->IsRepeatable() && Nquest->IsRepeatable()) && GetQuestRewardStatus(exclude_Id)))
15892 {
15893 if (msg)
15894 {
15896 TC_LOG_DEBUG("misc", "Player::SatisfyQuestExclusiveGroup: Sent QUEST_ERR_NONE (QuestID: {}) because player '{}' ({}) already did quest in exclusive group.",
15897 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15898 }
15899 return false;
15900 }
15901 }
15902 return true;
15903}
15904
15905bool Player::SatisfyQuestDay(Quest const* qInfo, bool /*msg*/) const
15906{
15907 if (!qInfo->IsDaily() && !qInfo->IsDFQuest())
15908 return true;
15909
15910 if (qInfo->IsDFQuest())
15911 {
15912 if (m_DFQuests.find(qInfo->GetQuestId()) != m_DFQuests.end())
15913 return false;
15914
15915 return true;
15916 }
15917
15918 return m_activePlayerData->DailyQuestsCompleted.FindIndex(qInfo->GetQuestId()) == -1;
15919}
15920
15921bool Player::SatisfyQuestWeek(Quest const* qInfo, bool /*msg*/) const
15922{
15923 if (!qInfo->IsWeekly() || m_weeklyquests.empty())
15924 return true;
15925
15926 // if not found in cooldown list
15927 return m_weeklyquests.find(qInfo->GetQuestId()) == m_weeklyquests.end();
15928}
15929
15930bool Player::SatisfyQuestSeasonal(Quest const* qInfo, bool /*msg*/) const
15931{
15932 if (!qInfo->IsSeasonal() || m_seasonalquests.empty())
15933 return true;
15934
15935 auto itr = m_seasonalquests.find(qInfo->GetEventIdForQuest());
15936 if (itr == m_seasonalquests.end() || itr->second.empty())
15937 return true;
15938
15939 // if not found in cooldown list
15940 return itr->second.find(qInfo->GetQuestId()) == itr->second.end();
15941}
15942
15943bool Player::SatisfyQuestExpansion(Quest const* qInfo, bool msg) const
15944{
15945 if (GetSession()->GetExpansion() < qInfo->GetExpansion())
15946 {
15947 if (msg)
15949
15950 TC_LOG_DEBUG("misc", "Player::SatisfyQuestExpansion: Sent QUEST_ERR_FAILED_EXPANSION (QuestID: {}) because player '{}' ({}) does not have required expansion.",
15951 qInfo->GetQuestId(), GetName(), GetGUID().ToString());
15952 return false;
15953 }
15954 return true;
15955}
15956
15957bool Player::SatisfyQuestMonth(Quest const* qInfo, bool /*msg*/) const
15958{
15959 if (!qInfo->IsMonthly() || m_monthlyquests.empty())
15960 return true;
15961
15962 // if not found in cooldown list
15963 return m_monthlyquests.find(qInfo->GetQuestId()) == m_monthlyquests.end();
15964}
15965
15967{
15968 uint32 srcitem = quest->GetSrcItemId();
15969 if (srcitem > 0)
15970 {
15971 // Don't give source item if it is the same item used to start the quest
15972 ItemTemplate const* itemTemplate = ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(srcitem));
15973 if (quest->GetQuestId() == itemTemplate->GetStartQuest())
15974 return true;
15975
15976 uint32 count = quest->GetSrcItemCount();
15977 if (count <= 0)
15978 count = 1;
15979
15980 ItemPosCountVec dest;
15981 InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, srcitem, count);
15982 if (msg == EQUIP_ERR_OK)
15983 {
15984 Item* item = StoreNewItem(dest, srcitem, true);
15985 SendNewItem(item, count, true, false);
15986 return true;
15987 }
15988 // player already have max amount required item, just report success
15989 if (msg == EQUIP_ERR_ITEM_MAX_COUNT)
15990 return true;
15991
15992 SendEquipError(msg, nullptr, nullptr, srcitem);
15993 return false;
15994 }
15995
15996 return true;
15997}
15998
16000{
16001 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
16002 if (quest)
16003 {
16004 uint32 srcItemId = quest->GetSrcItemId();
16005 ItemTemplate const* item = sObjectMgr->GetItemTemplate(srcItemId);
16006
16007 if (srcItemId > 0)
16008 {
16009 uint32 count = quest->GetSrcItemCount();
16010 if (count <= 0)
16011 count = 1;
16012
16013 // There are two cases where the source item is not destroyed:
16014 // - Item cannot be unequipped (example: non-empty bags)
16015 // - The source item is the item that started the quest, so the player is supposed to keep it (otherwise it was already destroyed in AddQuestAndCheckCompletion())
16016 InventoryResult res = CanUnequipItems(srcItemId, count);
16017 if (res != EQUIP_ERR_OK)
16018 {
16019 if (msg)
16020 SendEquipError(res, nullptr, nullptr, srcItemId);
16021 return false;
16022 }
16023
16024 ASSERT(item);
16025 if (item->GetStartQuest() != questId)
16026 DestroyItemCount(srcItemId, count, true, true);
16027 }
16028 }
16029
16030 return true;
16031}
16032
16034{
16035 Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id);
16036 if (qInfo)
16037 {
16038 if (qInfo->IsSeasonal() && !qInfo->IsRepeatable())
16039 return !SatisfyQuestSeasonal(qInfo, false);
16040
16041 // for repeatable quests: rewarded field is set after first reward only to prevent getting XP more than once
16042 if (!qInfo->IsRepeatable())
16043 return IsQuestRewarded(quest_id);
16044
16045 return false;
16046 }
16047 return false;
16048}
16049
16051{
16052 if (quest_id)
16053 {
16054 QuestStatusMap::const_iterator itr = m_QuestStatus.find(quest_id);
16055 if (itr != m_QuestStatus.end())
16056 return itr->second.Status;
16057
16058 if (GetQuestRewardStatus(quest_id))
16059 return QUEST_STATUS_REWARDED;
16060 }
16061 return QUEST_STATUS_NONE;
16062}
16063
16064bool Player::CanShareQuest(uint32 quest_id) const
16065{
16066 Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id);
16067 if (qInfo && qInfo->HasFlag(QUEST_FLAGS_SHARABLE))
16068 {
16069 QuestStatusMap::const_iterator itr = m_QuestStatus.find(quest_id);
16070 return (itr != m_QuestStatus.end());
16071 }
16072 return false;
16073}
16074
16075void Player::SetQuestStatus(uint32 questId, QuestStatus status, bool update /*= true*/)
16076{
16077 if (Quest const* quest = sObjectMgr->GetQuestTemplate(questId))
16078 {
16079 QuestStatus oldStatus = m_QuestStatus[questId].Status;
16080 m_QuestStatus[questId].Status = status;
16081
16082 if (!quest->IsTurnIn())
16084
16085 sScriptMgr->OnQuestStatusChange(this, questId);
16086 sScriptMgr->OnQuestStatusChange(this, quest, oldStatus, status);
16087 }
16088
16089 if (update)
16090 SendQuestUpdate(questId);
16091}
16092
16093void Player::RemoveActiveQuest(uint32 questId, bool update /*= true*/)
16094{
16095 QuestStatusMap::iterator itr = m_QuestStatus.find(questId);
16096 if (itr != m_QuestStatus.end())
16097 {
16098 for (auto objectiveItr = m_questObjectiveStatus.begin(); objectiveItr != m_questObjectiveStatus.end(); )
16099 {
16100 if (objectiveItr->second.QuestStatusItr == itr)
16101 objectiveItr = m_questObjectiveStatus.erase(objectiveItr);
16102 else
16103 ++objectiveItr;
16104 }
16105 m_QuestStatus.erase(itr);
16107 }
16108
16109 if (update)
16110 SendQuestUpdate(questId);
16111}
16112
16113void Player::RemoveRewardedQuest(uint32 questId, bool update /*= true*/)
16114{
16115 RewardedQuestSet::iterator rewItr = m_RewardedQuests.find(questId);
16116 if (rewItr != m_RewardedQuests.end())
16117 {
16118 m_RewardedQuests.erase(rewItr);
16120 }
16121
16122 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId))
16123 SetQuestCompletedBit(questBit, false);
16124
16125 // Remove seasonal quest also
16126 Quest const* qInfo = sObjectMgr->GetQuestTemplate(questId);
16127 ASSERT(qInfo);
16128 if (qInfo->IsSeasonal())
16129 {
16130 uint16 eventId = qInfo->GetEventIdForQuest();
16131 if (m_seasonalquests.find(eventId) != m_seasonalquests.end())
16132 {
16133 m_seasonalquests[eventId].erase(questId);
16135 }
16136 }
16137
16138 if (update)
16139 SendQuestUpdate(questId);
16140}
16141
16142void Player::SendQuestUpdate(uint32 questId, bool updateInteractions /*= true*/, bool updateGameObjectQuestGiverStatus /*= false*/)
16143{
16144 SpellAreaForQuestMapBounds saBounds = sSpellMgr->GetSpellAreaForQuestMapBounds(questId);
16145
16146 if (saBounds.first != saBounds.second)
16147 {
16148 std::set<uint32> aurasToRemove, aurasToCast;
16149 uint32 zone = 0, area = 0;
16150 GetZoneAndAreaId(zone, area);
16151
16152 for (SpellAreaForQuestMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
16153 {
16154 if (itr->second->flags & SPELL_AREA_FLAG_AUTOREMOVE && !itr->second->IsFitToRequirements(this, zone, area))
16155 aurasToRemove.insert(itr->second->spellId);
16156 else if (itr->second->flags & SPELL_AREA_FLAG_AUTOCAST && !(itr->second->flags & SPELL_AREA_FLAG_IGNORE_AUTOCAST_ON_QUEST_STATUS_CHANGE))
16157 aurasToCast.insert(itr->second->spellId);
16158 }
16159
16160 // Auras matching the requirements will be inside the aurasToCast container.
16161 // Auras not matching the requirements may prevent using auras matching the requirements.
16162 // aurasToCast will erase conflicting auras in aurasToRemove container to handle spells used by multiple quests.
16163
16164 for (auto itr = aurasToRemove.begin(); itr != aurasToRemove.end();)
16165 {
16166 bool auraRemoved = false;
16167
16168 for (const auto i : aurasToCast)
16169 {
16170 if (*itr == i)
16171 {
16172 itr = aurasToRemove.erase(itr);
16173 auraRemoved = true;
16174 break;
16175 }
16176 }
16177
16178 if (!auraRemoved)
16179 ++itr;
16180 }
16181
16182 for (auto spellId : aurasToCast)
16183 if (!HasAura(spellId))
16184 CastSpell(this, spellId, true);
16185
16186 for (auto spellId : aurasToRemove)
16187 RemoveAurasDueToSpell(spellId);
16188 }
16189
16190 if (updateInteractions)
16191 UpdateVisibleObjectInteractions(true, false, updateGameObjectQuestGiverStatus, true);
16192}
16193
16195{
16196 QuestRelationResult qr, qir;
16197
16198 switch (questgiver->GetTypeId())
16199 {
16200 case TYPEID_GAMEOBJECT:
16201 {
16202 if (GameObjectAI* ai = questgiver->ToGameObject()->AI())
16203 if (Optional<QuestGiverStatus> questStatus = ai->GetDialogStatus(this))
16204 return *questStatus;
16205 qr = sObjectMgr->GetGOQuestRelations(questgiver->GetEntry());
16206 qir = sObjectMgr->GetGOQuestInvolvedRelations(questgiver->GetEntry());
16207 break;
16208 }
16209 case TYPEID_UNIT:
16210 {
16211 Creature const* questGiverCreature = questgiver->ToCreature();
16212 if (!questGiverCreature->IsInteractionAllowedWhileHostile() && questGiverCreature->IsHostileTo(this))
16214
16215 if (!questGiverCreature->IsInteractionAllowedInCombat() && questGiverCreature->IsInCombat())
16217
16218 if (CreatureAI* ai = questgiver->ToCreature()->AI())
16219 if (Optional<QuestGiverStatus> questStatus = ai->GetDialogStatus(this))
16220 return *questStatus;
16221 qr = sObjectMgr->GetCreatureQuestRelations(questgiver->GetEntry());
16222 qir = sObjectMgr->GetCreatureQuestInvolvedRelations(questgiver->GetEntry());
16223 break;
16224 }
16225 default:
16226 // it's impossible, but check
16227 TC_LOG_ERROR("entities.player.quest", "Player::GetQuestDialogStatus: Called with unexpected type (Entry: {}, Type: {}) by player '{}' ({})",
16228 questgiver->GetEntry(), questgiver->GetTypeId(), GetName(), GetGUID().ToString());
16230 }
16231
16233
16234 for (uint32 questId : qir)
16235 {
16236 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
16237 if (!quest)
16238 continue;
16239
16240 switch (GetQuestStatus(questId))
16241 {
16243 if (quest->IsImportant())
16245 else if (quest->GetQuestTag() == QuestTagType::CovenantCalling)
16247 else if (quest->HasFlagEx(QUEST_FLAGS_EX_LEGENDARY))
16249 else
16251 break;
16253 if (quest->IsImportant())
16255 else if (quest->GetQuestTag() == QuestTagType::CovenantCalling)
16257 else if (quest->HasFlagEx(QUEST_FLAGS_EX_LEGENDARY))
16259 else
16260 result |= QuestGiverStatus::Reward;
16261 break;
16262 default:
16263 break;
16264 }
16265
16266 if (quest->IsTurnIn() && CanTakeQuest(quest, false) && quest->IsRepeatable() && !quest->IsDailyOrWeekly() && !quest->IsMonthly())
16267 {
16268 if (GetLevel() > (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF)))
16270 else
16272 }
16273 }
16274
16275 for (uint32 questId : qr)
16276 {
16277 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
16278 if (!quest)
16279 continue;
16280
16281 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_QUEST_AVAILABLE, quest->GetQuestId(), this))
16282 continue;
16283
16284 if (GetQuestStatus(questId) == QUEST_STATUS_NONE)
16285 {
16286 if (CanSeeStartQuest(quest))
16287 {
16288 if (SatisfyQuestLevel(quest, false))
16289 {
16290 bool isTrivial = GetLevel() > (GetQuestLevel(quest) + sWorld->getIntConfig(CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF));
16291 if (quest->IsImportant())
16293 else if (quest->GetQuestTag() == QuestTagType::CovenantCalling)
16295 else if (quest->HasFlagEx(QUEST_FLAGS_EX_LEGENDARY))
16297 else if (quest->IsDaily())
16299 else
16300 result |= isTrivial ? QuestGiverStatus::Trivial : QuestGiverStatus::Quest;
16301 }
16302 else if (quest->IsImportant())
16304 else if (quest->HasFlagEx(QUEST_FLAGS_EX_LEGENDARY))
16306 else
16307 result |= QuestGiverStatus::Future;
16308 }
16309 }
16310 }
16311
16312 return result;
16313}
16314
16315void Player::SkipQuests(std::vector<uint32> const& questIds)
16316{
16317 bool updateVisibility = false;
16318 for (uint32 const& questId : questIds)
16319 {
16320 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
16321 if (!quest)
16322 return;
16323
16324 uint16 questSlot = FindQuestSlot(questId);
16325 QuestStatus oldStatus = GetQuestStatus(questSlot);
16326
16327 if (questSlot != MAX_QUEST_LOG_SIZE)
16328 {
16329 if (quest->GetLimitTime())
16330 RemoveTimedQuest(questId);
16331
16332 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
16333 {
16336 }
16337
16338 SetQuestSlot(questSlot, 0);
16339 TakeQuestSourceItem(questId, true); // remove quest src item from player
16340 AbandonQuest(questId); // remove all quest items player received before abandoning quest. Note, this does not remove normal drop items that happen to be quest requirements.
16341 RemoveActiveQuest(questId);
16342 }
16343
16344 SetRewardedQuest(questId);
16345 SendQuestUpdate(questId, false);
16346
16347 if (!updateVisibility && quest->HasFlag(QUEST_FLAGS_UPDATE_PHASESHIFT))
16348 updateVisibility = PhasingHandler::OnConditionChange(this, false);
16349
16350 sScriptMgr->OnQuestStatusChange(this, questId);
16351 sScriptMgr->OnQuestStatusChange(this, quest, oldStatus, QUEST_STATUS_REWARDED);
16352 }
16353
16354 UpdateVisibleObjectInteractions(true, false, true, true);
16355
16356 // make full db save
16357 SaveToDB(false);
16358
16359 if (updateVisibility)
16361}
16362
16364{
16365 std::list<Creature*> creatureList;
16366 GetCreatureListWithOptionsInGrid(creatureList, 100.0f, { .IgnorePhases = true, .PrivateObjectOwnerGuid = GetGUID() }); // we might want to replace this with SummonList in Player at some point
16367
16368 for (Creature* creature : creatureList)
16369 {
16370 CreatureSummonedData const* summonedData = sObjectMgr->GetCreatureSummonedData(creature->GetEntry());
16371 if (!summonedData)
16372 continue;
16373
16374 if (summonedData->DespawnOnQuestsRemoved)
16375 {
16376 if (std::find(summonedData->DespawnOnQuestsRemoved->begin(), summonedData->DespawnOnQuestsRemoved->end(), questId) != summonedData->DespawnOnQuestsRemoved->end())
16377 creature->DespawnOrUnsummon();
16378 }
16379 }
16380}
16381
16382// not used in Trinity, but used in scripting code
16384{
16385 Quest const* qInfo = sObjectMgr->GetQuestTemplate(quest_id);
16386 if (!qInfo)
16387 return 0;
16388
16389 uint16 slot = FindQuestSlot(quest_id);
16390 if (slot >= MAX_QUEST_LOG_SIZE)
16391 return 0;
16392
16393 for (QuestObjective const& obj : qInfo->GetObjectives())
16394 if (obj.ObjectID == entry)
16395 return GetQuestSlotObjectiveData(slot, obj);
16396
16397 return 0;
16398}
16399
16401{
16402 // adjust progress of quest objectives that rely on external counters, like items
16403 for (QuestObjective const& obj : quest->GetObjectives())
16404 {
16405 switch (obj.Type)
16406 {
16408 if (!(obj.Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM))
16409 {
16410 uint32 reqItemCount = obj.Amount;
16411 uint32 curItemCount = GetItemCount(obj.ObjectID, true);
16412 SetQuestObjectiveData(obj, std::min(curItemCount, reqItemCount));
16413 }
16414 break;
16416 {
16417 uint32 reqCurrencyCount = obj.Amount;
16418 uint32 curCurrencyCount = GetCurrencyQuantity(obj.ObjectID);
16419 SetQuestObjectiveData(obj, std::min(reqCurrencyCount, curCurrencyCount));
16420 break;
16421 }
16423 if (m_questObjectiveCriteriaMgr->HasCompletedObjective(&obj))
16424 SetQuestObjectiveData(obj, 1);
16425 break;
16426 default:
16427 break;
16428 }
16429 }
16430}
16431
16433{
16434 for (uint16 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
16435 if (GetQuestSlotQuestId(i) == quest_id)
16436 return i;
16437
16438 return MAX_QUEST_LOG_SIZE;
16439}
16440
16442{
16443 return m_playerData->QuestLog[slot].QuestID;
16444}
16445
16447{
16448 return m_playerData->QuestLog[slot].StateFlags;
16449}
16450
16452{
16453 if (counter < MAX_QUEST_COUNTS)
16454 return m_playerData->QuestLog[slot].ObjectiveProgress[counter];
16455 return 0;
16456}
16457
16459{
16460 return m_playerData->QuestLog[slot].EndTime;
16461}
16462
16463bool Player::GetQuestSlotObjectiveFlag(uint16 slot, int8 objectiveIndex) const
16464{
16465 if (objectiveIndex < MAX_QUEST_COUNTS)
16466 return (*m_playerData->QuestLog[slot].ObjectiveFlags) & (1 << objectiveIndex);
16467 return false;
16468}
16469
16471{
16472 if (objective.StorageIndex < 0)
16473 {
16474 TC_LOG_ERROR("entities.player.quest", "Player::GetQuestObjectiveData: Called for quest {} with invalid StorageIndex {} (objective data is not tracked)",
16475 objective.QuestID, int32(objective.StorageIndex));
16476 return 0;
16477 }
16478
16479 if (objective.StorageIndex >= MAX_QUEST_COUNTS)
16480 {
16481 TC_LOG_ERROR("entities.player.quest", "Player::GetQuestObjectiveData: Player '{}' ({}) quest {} out of range StorageIndex {}",
16482 GetName(), GetGUID().ToString(), objective.QuestID, uint32(objective.StorageIndex));
16483 return 0;
16484 }
16485
16486 if (!objective.IsStoringFlag())
16487 return GetQuestSlotCounter(slot, objective.StorageIndex);
16488
16489 return GetQuestSlotObjectiveFlag(slot, objective.StorageIndex) ? 1 : 0;
16490}
16491
16493{
16494 uint16 slot = FindQuestSlot(questId);
16495 if (slot >= MAX_QUEST_LOG_SIZE)
16496 return 0;
16497
16498 QuestObjective const* obj = sObjectMgr->GetQuestObjective(objectiveId);
16499 if (!obj)
16500 return 0;
16501
16502 return GetQuestSlotObjectiveData(slot, *obj);
16503}
16504
16506{
16507 auto questLogField = m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::QuestLog, slot);
16508 SetUpdateFieldValue(questLogField.ModifyValue(&UF::QuestLog::QuestID), quest_id);
16509 SetUpdateFieldValue(questLogField.ModifyValue(&UF::QuestLog::StateFlags), 0);
16510 SetUpdateFieldValue(questLogField.ModifyValue(&UF::QuestLog::EndTime), 0);
16511 SetUpdateFieldValue(questLogField.ModifyValue(&UF::QuestLog::ObjectiveFlags), 0);
16512 for (uint32 i = 0; i < MAX_QUEST_COUNTS; ++i)
16513 SetUpdateFieldValue(questLogField.ModifyValue(&UF::QuestLog::ObjectiveProgress, i), 0);
16514}
16515
16517{
16518 if (counter >= MAX_QUEST_COUNTS)
16519 return;
16520
16522 .ModifyValue(&UF::PlayerData::QuestLog, slot)
16523 .ModifyValue(&UF::QuestLog::ObjectiveProgress, counter), count);
16524}
16525
16527{
16529 .ModifyValue(&UF::PlayerData::QuestLog, slot)
16530 .ModifyValue(&UF::QuestLog::StateFlags), state);
16531}
16532
16534{
16536 .ModifyValue(&UF::PlayerData::QuestLog, slot)
16537 .ModifyValue(&UF::QuestLog::StateFlags), state);
16538}
16539
16540void Player::SetQuestSlotEndTime(uint16 slot, time_t endTime)
16541{
16543 .ModifyValue(&UF::PlayerData::QuestLog, slot)
16544 .ModifyValue(&UF::QuestLog::EndTime), uint32(endTime));
16545}
16546
16548{
16550 .ModifyValue(&UF::PlayerData::QuestLog, slot)
16551 .ModifyValue(&UF::QuestLog::ObjectiveFlags), 1 << objectiveIndex);
16552}
16553
16555{
16557 .ModifyValue(&UF::PlayerData::QuestLog, slot)
16558 .ModifyValue(&UF::QuestLog::ObjectiveFlags), 1 << objectiveIndex);
16559}
16560
16561void Player::SetQuestCompletedBit(uint32 questBit, bool completed)
16562{
16563 if (!questBit)
16564 return;
16565
16566 uint32 fieldOffset = (questBit - 1) / QUESTS_COMPLETED_BITS_PER_BLOCK;
16567 if (fieldOffset >= QUESTS_COMPLETED_BITS_SIZE)
16568 return;
16569
16570 uint64 flag = UI64LIT(1) << ((questBit - 1) % QUESTS_COMPLETED_BITS_PER_BLOCK);
16571 if (completed)
16573 else
16575}
16576
16578{
16579 if (questId)
16580 {
16582 {
16583 // Dont complete failed quest
16584 if (!status->Explored && status->Status != QUEST_STATUS_FAILED)
16585 {
16586 status->Explored = true;
16588
16589 SendQuestComplete(questId);
16590 }
16591 }
16592 if (CanCompleteQuest(questId))
16593 CompleteQuest(questId);
16594 }
16595}
16596
16597//not used in Trinityd, function for external script library
16598void Player::GroupEventHappens(uint32 questId, WorldObject const* pEventObject)
16599{
16600 if (Group* group = GetGroup())
16601 {
16602 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
16603 {
16604 Player* player = itr->GetSource();
16605
16606 // for any leave or dead (with not released body) group member at appropriate distance
16607 if (player && player->IsAtGroupRewardDistance(pEventObject) && !player->GetCorpse())
16608 player->AreaExploredOrEventHappens(questId);
16609 }
16610 }
16611 else
16613}
16614
16615namespace
16616{
16617struct
16618{
16619 std::function<bool(QuestObjective const*)> QuestBoundItem = [](QuestObjective const* objective) { return (objective->Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM) != 0; };
16620 std::function<bool(QuestObjective const*)> NotQuestBoundItem = [](QuestObjective const* objective) { return (objective->Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM) == 0; };
16621} const ItemQuestObjectiveFilters;
16622}
16623
16624void Player::ItemAddedQuestCheck(uint32 entry, uint32 count, Optional<bool> boundItemFlagRequirement /*= {}*/, bool* hadBoundItemObjective /*= nullptr*/)
16625{
16626 std::vector<QuestObjective const*> updatedObjectives;
16627 std::function<bool(QuestObjective const*)> const* objectiveFilter = nullptr;
16628 if (boundItemFlagRequirement)
16629 objectiveFilter = *boundItemFlagRequirement ? &ItemQuestObjectiveFilters.QuestBoundItem : &ItemQuestObjectiveFilters.NotQuestBoundItem;
16630
16631 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(entry);
16632 UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_ITEM, itemTemplate->GetId(), count, ObjectGuid::Empty, &updatedObjectives, objectiveFilter);
16633 if (itemTemplate->QuestLogItemId && (updatedObjectives.size() != 1 || !(updatedObjectives[0]->Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM)))
16634 UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_ITEM, itemTemplate->QuestLogItemId, count, ObjectGuid::Empty, &updatedObjectives, objectiveFilter);
16635
16636 if (updatedObjectives.size() == 1 && updatedObjectives[0]->Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM)
16637 {
16638 if (hadBoundItemObjective)
16639 *hadBoundItemObjective = updatedObjectives.size() == 1 && updatedObjectives[0]->Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM;
16640
16641 SendQuestUpdateAddItem(itemTemplate, *updatedObjectives[0], count);
16642 }
16643}
16644
16646{
16647 for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { QUEST_OBJECTIVE_ITEM, entry }))
16648 {
16649 uint32 questId = objectiveItr.second.QuestStatusItr->first;
16650 uint16 logSlot = objectiveItr.second.QuestStatusItr->second.Slot;
16651 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
16652 QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
16653
16654 if (!quest || !objective || !IsQuestObjectiveCompletable(logSlot, quest, *objective))
16655 continue;
16656
16657 int32 newItemCount = GetItemCount(entry, false); // we may have more than what the status shows, so we have to iterate inventory
16658
16659 if (newItemCount < objective->Amount)
16660 {
16661 SetQuestObjectiveData(*objective, newItemCount);
16662 IncompleteQuest(questId);
16663 }
16664 }
16665 UpdateVisibleObjectInteractions(true, false, false, true);
16666}
16667
16669{
16670 ASSERT(cInfo);
16671
16672 if (cInfo->Entry)
16673 KilledMonsterCredit(cInfo->Entry, guid);
16674
16675 for (uint8 i = 0; i < MAX_KILL_CREDIT; ++i)
16676 if (cInfo->KillCredit[i])
16678}
16679
16680void Player::KilledMonsterCredit(uint32 entry, ObjectGuid guid /*= ObjectGuid::Empty*/)
16681{
16682 uint16 addKillCount = 1;
16683 uint32 real_entry = entry;
16684 Creature* killed = nullptr;
16685 if (!guid.IsEmpty())
16686 {
16687 killed = GetMap()->GetCreature(guid);
16688 if (killed && killed->GetEntry())
16689 real_entry = killed->GetEntry();
16690 }
16691
16692 StartCriteria(CriteriaStartEvent::KillNPC, real_entry); // MUST BE CALLED FIRST
16693 UpdateCriteria(CriteriaType::KillCreature, real_entry, addKillCount, 0, killed);
16694
16696}
16697
16699{
16702}
16703
16705{
16707}
16708
16710{
16712}
16713
16715{
16717}
16718
16720{
16722}
16723
16724void Player::ReputationChanged(FactionEntry const* factionEntry, int32 change)
16725{
16729}
16730
16731void Player::CurrencyChanged(uint32 currencyId, int32 change)
16732{
16736}
16737
16738void Player::UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int32 objectId, int64 addCount, ObjectGuid victimGuid /*= ObjectGuid::Empty*/,
16739 std::vector<QuestObjective const*>* updatedObjectives /*= nullptr*/, std::function<bool(QuestObjective const*)> const* objectiveFilter /*= nullptr*/)
16740{
16741 bool anyObjectiveChangedCompletionState = false;
16742 bool updatePhaseShift = false;
16743 bool updateZoneAuras = false;
16744
16745 for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { objectiveType, objectId }))
16746 {
16747 uint32 questId = objectiveItr.second.QuestStatusItr->first;
16748 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
16749 if (!quest)
16750 continue;
16751
16753 if (GetGroup() && GetGroup()->isRaidGroup() && !quest->IsAllowedInRaid(GetMap()->GetDifficultyID()))
16754 continue;
16755
16756 uint16 logSlot = objectiveItr.second.QuestStatusItr->second.Slot;
16757 QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
16758 if (!objective || !IsQuestObjectiveCompletable(logSlot, quest, *objective))
16759 continue;
16760
16762 if (objective->Type == QUEST_OBJECTIVE_MONSTER && victimGuid.IsEmpty())
16763 continue;
16764
16765 bool objectiveWasComplete = IsQuestObjectiveComplete(logSlot, quest, *objective);
16766 if (objectiveWasComplete && addCount >= 0)
16767 continue;
16768
16769 if (objectiveFilter && !(*objectiveFilter)(objective))
16770 continue;
16771
16772 bool objectiveIsNowComplete = false;
16773 if (objective->IsStoringValue())
16774 {
16776 if (Player const* victim = ObjectAccessor::GetPlayer(GetMap(), victimGuid))
16777 if (victim->GetEffectiveTeam() != GetEffectiveTeam())
16778 continue;
16779
16780 int32 currentProgress = GetQuestSlotObjectiveData(logSlot, *objective);
16781 if (addCount > 0 ? (currentProgress < objective->Amount) : (currentProgress > 0))
16782 {
16783 int32 newProgress = std::clamp<int32>(currentProgress + addCount, 0, objective->Amount);
16784 SetQuestObjectiveData(*objective, newProgress);
16785 if (addCount > 0 && !(objective->Flags & QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG))
16786 {
16787 switch (objectiveType)
16788 {
16790 break; // case handled by SMSG_ITEM_PUSH_RESULT
16792 SendQuestUpdateAddPlayer(quest, newProgress);
16793 break;
16794 default:
16795 SendQuestUpdateAddCredit(quest, victimGuid, *objective, newProgress);
16796 break;
16797 }
16798 }
16799
16800 objectiveIsNowComplete = IsQuestObjectiveComplete(logSlot, quest, *objective);
16801 }
16802 }
16803 else if (objective->IsStoringFlag())
16804 {
16805 SetQuestObjectiveData(*objective, addCount > 0);
16806
16807 if (addCount > 0 && !(objective->Flags & QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG))
16809
16810 objectiveIsNowComplete = IsQuestObjectiveComplete(logSlot, quest, *objective);
16811 }
16812 else
16813 {
16814 switch (objectiveType)
16815 {
16817 objectiveIsNowComplete = GetCurrencyQuantity(objectId) + addCount >= objective->Amount;
16818 break;
16820 objectiveIsNowComplete = addCount != 0;
16821 break;
16823 objectiveIsNowComplete = GetReputationMgr().GetReputation(objectId) + addCount >= objective->Amount;
16824 break;
16826 objectiveIsNowComplete = GetReputationMgr().GetReputation(objectId) + addCount <= objective->Amount;
16827 break;
16829 objectiveIsNowComplete = int64(GetMoney()) + addCount >= objective->Amount;
16830 break;
16832 objectiveIsNowComplete = IsQuestObjectiveProgressBarComplete(logSlot, quest);
16833 break;
16834 default:
16835 ABORT_MSG("Unhandled quest objective type %u", uint32(objectiveType));
16836 break;
16837 }
16838 }
16839
16841 {
16842 if (IsQuestObjectiveProgressBarComplete(logSlot, quest))
16843 {
16844 auto progressBarObjectiveItr = std::find_if(quest->GetObjectives().begin(), quest->GetObjectives().end(), [](QuestObjective const& otherObjective)
16845 {
16846 return otherObjective.Type == QUEST_OBJECTIVE_PROGRESS_BAR && !(otherObjective.Flags & QUEST_OBJECTIVE_FLAG_PART_OF_PROGRESS_BAR);
16847 });
16848 if (progressBarObjectiveItr != quest->GetObjectives().end())
16849 SendQuestUpdateAddCreditSimple(*progressBarObjectiveItr);
16850
16851 objectiveIsNowComplete = true;
16852 }
16853 }
16854
16855 if (objectiveWasComplete != objectiveIsNowComplete)
16856 anyObjectiveChangedCompletionState = true;
16857
16858 if (objectiveIsNowComplete && objective->CompletionEffect)
16859 {
16860 if (objective->CompletionEffect->GameEventId)
16861 GameEvents::Trigger(*objective->CompletionEffect->GameEventId, this, nullptr);
16862 if (objective->CompletionEffect->SpellId)
16863 CastSpell(this, *objective->CompletionEffect->SpellId, true);
16864 if (objective->CompletionEffect->ConversationId)
16866 if (objective->CompletionEffect->UpdatePhaseShift)
16867 updatePhaseShift = true;
16868 if (objective->CompletionEffect->UpdateZoneAuras)
16869 updateZoneAuras = true;
16870 }
16871
16872 if (objectiveIsNowComplete)
16873 {
16874 if (CanCompleteQuest(questId, objective->ID))
16875 CompleteQuest(questId);
16876 }
16877 else if (!(objective->Flags & QUEST_OBJECTIVE_FLAG_OPTIONAL) && objectiveItr.second.QuestStatusItr->second.Status == QUEST_STATUS_COMPLETE)
16878 IncompleteQuest(questId);
16879
16880 if (updatedObjectives)
16881 updatedObjectives->push_back(objective);
16882
16883 if (objective->Type == QUEST_OBJECTIVE_ITEM && addCount >= 0 && objective->Flags2 & QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM)
16884 break;
16885 }
16886
16887 if (anyObjectiveChangedCompletionState)
16888 UpdateVisibleObjectInteractions(true, false, false, true);
16889
16890 if (updatePhaseShift)
16892
16893 if (updateZoneAuras)
16894 {
16897 }
16898}
16899
16901{
16902 // Search incomplete objective first
16903 if (GetQuestObjectiveForItem(itemid, true))
16904 return true;
16905
16906 // This part - for ItemDrop
16907 for (std::pair<uint32 const, QuestStatusData> const& questStatus : m_QuestStatus)
16908 {
16909 if (questStatus.second.Status != QUEST_STATUS_INCOMPLETE)
16910 continue;
16911
16912 Quest const* qInfo = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(questStatus.first));
16913 // hide quest if player is in raid-group and quest is no raid quest
16914 if (GetGroup() && GetGroup()->isRaidGroup() && !qInfo->IsAllowedInRaid(GetMap()->GetDifficultyID()))
16915 if (!InBattleground())
16916 continue;
16917
16918 for (uint8 j = 0; j < QUEST_ITEM_DROP_COUNT; ++j)
16919 {
16920 // examined item is a source item
16921 if (qInfo->ItemDrop[j] != itemid)
16922 continue;
16923
16924 ItemTemplate const* pProto = ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(itemid));
16925
16926 // allows custom amount drop when not 0
16927 uint32 maxAllowedCount = qInfo->ItemDropQuantity[j] ? qInfo->ItemDropQuantity[j] : pProto->GetMaxStackSize();
16928
16929 // 'unique' item
16930 if (pProto->GetMaxCount() && pProto->GetMaxCount() < maxAllowedCount)
16931 maxAllowedCount = pProto->GetMaxCount();
16932
16933 if (GetItemCount(itemid, true) < maxAllowedCount)
16934 return true;
16935 }
16936 }
16937
16938 return false;
16939}
16940
16941QuestObjective const* Player::GetQuestObjectiveForItem(uint32 itemId, bool onlyIncomplete) const
16942{
16943 auto findObjectiveForItem = [this, onlyIncomplete](uint32 itemId) -> QuestObjective const*
16944 {
16945 for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { QUEST_OBJECTIVE_ITEM, itemId }))
16946 {
16947 Quest const* qInfo = sObjectMgr->GetQuestTemplate(objectiveItr.second.QuestStatusItr->first);
16948 QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
16949 if (!qInfo || !objective || !IsQuestObjectiveCompletable(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
16950 continue;
16951
16952 // hide quest if player is in raid-group and quest is no raid quest
16953 if (GetGroup() && GetGroup()->isRaidGroup() && !qInfo->IsAllowedInRaid(GetMap()->GetDifficultyID()))
16954 if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
16955 continue;
16956
16957 if (!onlyIncomplete || !IsQuestObjectiveComplete(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
16958 return objective;
16959 }
16960 return nullptr;
16961 };
16962
16963 if (QuestObjective const* objective = findObjectiveForItem(itemId))
16964 return objective;
16965
16966 if (ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId))
16967 if (itemTemplate->QuestLogItemId)
16968 if (QuestObjective const* objective = findObjectiveForItem(itemTemplate->QuestLogItemId))
16969 return objective;
16970
16971 return nullptr;
16972}
16973
16975{
16976 uint16 slot = FindQuestSlot(objective.QuestID);
16977 if (slot >= MAX_QUEST_LOG_SIZE)
16978 return 0;
16979
16980 return GetQuestSlotObjectiveData(slot, objective);
16981}
16982
16984{
16985 if (objective.StorageIndex < 0)
16986 {
16987 TC_LOG_ERROR("entities.player.quest", "Player::SetQuestObjectiveData: called for quest {} with invalid StorageIndex {} (objective data is not tracked)",
16988 objective.QuestID, objective.StorageIndex);
16989 return;
16990 }
16991
16992 auto itr = m_QuestStatus.find(objective.QuestID);
16993 if (itr == m_QuestStatus.end())
16994 {
16995 TC_LOG_ERROR("entities.player.quest", "Player::SetQuestObjectiveData: player '{}' ({}) doesn't have quest status data (QuestID: {})",
16996 GetName(), GetGUID().ToString(), objective.QuestID);
16997 return;
16998 }
16999
17000 QuestStatusData& status = itr->second;
17001
17002 if (uint8(objective.StorageIndex) >= MAX_QUEST_COUNTS)
17003 {
17004 TC_LOG_ERROR("entities.player.quest", "Player::SetQuestObjectiveData: player '{}' ({}) quest {} out of range StorageIndex {}",
17005 GetName(), GetGUID().ToString(), objective.QuestID, objective.StorageIndex);
17006 return;
17007 }
17008
17009 if (status.Slot >= MAX_QUEST_LOG_SIZE)
17010 return;
17011
17012 // No change
17013 int32 oldData = GetQuestSlotObjectiveData(status.Slot, objective);
17014 if (oldData == data)
17015 return;
17016
17017 if (Quest const* quest = sObjectMgr->GetQuestTemplate(objective.QuestID))
17018 sScriptMgr->OnQuestObjectiveChange(this, quest, objective, oldData, data);
17019
17020 // Add to save
17022
17023 // Update quest fields
17024 if (!objective.IsStoringFlag())
17025 SetQuestSlotCounter(status.Slot, objective.StorageIndex, data);
17026 else if (data)
17027 SetQuestSlotObjectiveFlag(status.Slot, objective.StorageIndex);
17028 else
17030}
17031
17032bool Player::IsQuestObjectiveCompletable(uint16 slot, Quest const* quest, QuestObjective const& objective) const
17033{
17034 ASSERT(objective.QuestID == quest->GetQuestId());
17035
17037 {
17038 // delegate check to actual progress bar objective
17039 auto progressBarObjectiveItr = std::find_if(quest->GetObjectives().begin(), quest->GetObjectives().end(), [](QuestObjective const& otherObjective)
17040 {
17041 return otherObjective.Type == QUEST_OBJECTIVE_PROGRESS_BAR && !(otherObjective.Flags & QUEST_OBJECTIVE_FLAG_PART_OF_PROGRESS_BAR);
17042 });
17043 if (progressBarObjectiveItr == quest->GetObjectives().end())
17044 return false;
17045
17046 return IsQuestObjectiveCompletable(slot, quest, *progressBarObjectiveItr) && !IsQuestObjectiveComplete(slot, quest, *progressBarObjectiveItr);
17047 }
17048
17049 int32 objectiveIndex = int32(std::distance(&quest->GetObjectives()[0], &objective));
17050 if (!objectiveIndex)
17051 return true;
17052
17053 // check sequenced objectives
17054 int32 previousIndex = objectiveIndex - 1;
17055 bool objectiveSequenceSatisfied = true;
17056 bool previousSequencedObjectiveComplete = false;
17057 int32 previousSequencedObjectiveIndex = -1;
17058 do
17059 {
17060 QuestObjective const& previousObjective = quest->GetObjectives()[previousIndex];
17061 if (previousObjective.Flags & QUEST_OBJECTIVE_FLAG_SEQUENCED)
17062 {
17063 previousSequencedObjectiveIndex = previousIndex;
17064 previousSequencedObjectiveComplete = IsQuestObjectiveComplete(slot, quest, previousObjective);
17065 break;
17066 }
17067
17068 if (objectiveSequenceSatisfied)
17069 objectiveSequenceSatisfied = IsQuestObjectiveComplete(slot, quest, previousObjective) || (previousObjective.Flags & (QUEST_OBJECTIVE_FLAG_OPTIONAL | QUEST_OBJECTIVE_FLAG_PART_OF_PROGRESS_BAR));
17070
17071 --previousIndex;
17072 } while (previousIndex >= 0);
17073
17074 if (objective.Flags & QUEST_OBJECTIVE_FLAG_SEQUENCED)
17075 {
17076 if (previousSequencedObjectiveIndex == -1)
17077 return objectiveSequenceSatisfied;
17078 if (!previousSequencedObjectiveComplete || !objectiveSequenceSatisfied)
17079 return false;
17080 }
17081 else if (!previousSequencedObjectiveComplete && previousSequencedObjectiveIndex != -1)
17082 {
17083 if (!IsQuestObjectiveCompletable(slot, quest, quest->GetObjectives()[previousSequencedObjectiveIndex]))
17084 return false;
17085 }
17086
17087 return true;
17088}
17089
17090bool Player::IsQuestObjectiveComplete(uint16 slot, Quest const* quest, QuestObjective const& objective) const
17091{
17092 switch (objective.Type)
17093 {
17103 if (GetQuestSlotObjectiveData(slot, objective) < objective.Amount)
17104 return false;
17105 break;
17107 if (GetReputationMgr().GetReputation(objective.ObjectID) < objective.Amount)
17108 return false;
17109 break;
17111 if (GetReputationMgr().GetReputation(objective.ObjectID) > objective.Amount)
17112 return false;
17113 break;
17115 if (!HasEnoughMoney(uint64(objective.Amount)))
17116 return false;
17117 break;
17124 if (!GetQuestSlotObjectiveData(slot, objective))
17125 return false;
17126 break;
17128 if (!HasSpell(objective.ObjectID))
17129 return false;
17130 break;
17132 if (!HasCurrency(objective.ObjectID, objective.Amount))
17133 return false;
17134 break;
17136 if (!IsQuestObjectiveProgressBarComplete(slot, quest))
17137 return false;
17138 break;
17139 default:
17140 TC_LOG_ERROR("entities.player.quest", "Player::CanCompleteQuest: Player '{}' ({}) tried to complete a quest (ID: {}) with an unknown objective type {}",
17141 GetName(), GetGUID().ToString(), objective.QuestID, objective.Type);
17142 return false;
17143 }
17144
17145 return true;
17146}
17147
17148bool Player::IsQuestObjectiveComplete(uint32 questId, uint32 objectiveId) const
17149{
17150 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
17151 if (!quest)
17152 return false;
17153
17154 uint16 slot = FindQuestSlot(questId);
17155 if (slot >= MAX_QUEST_LOG_SIZE)
17156 return false;
17157
17158 QuestObjective const* obj = sObjectMgr->GetQuestObjective(objectiveId);
17159 if (!obj)
17160 return false;
17161
17162 return IsQuestObjectiveComplete(slot, quest, *obj);
17163}
17164
17166{
17167 float progress = 0.0f;
17168 for (QuestObjective const& obj : quest->GetObjectives())
17169 {
17171 {
17172 progress += GetQuestSlotObjectiveData(slot, obj) * obj.ProgressBarWeight;
17173 if (progress >= 100.0f)
17174 return true;
17175 }
17176 }
17177 return false;
17178}
17179
17181{
17182 if (questId)
17183 {
17185 data.QuestID = questId;
17186 SendDirectMessage(data.Write());
17187 }
17188}
17189
17190void Player::SendQuestReward(Quest const* quest, Creature const* questGiver, uint32 xp, bool hideChatMessage) const
17191{
17192 uint32 questId = quest->GetQuestId();
17193 sGameEventMgr->HandleQuestComplete(questId);
17194
17195 uint32 moneyReward;
17196
17197 if (!IsMaxLevel())
17198 {
17199 moneyReward = GetQuestMoneyReward(quest);
17200 }
17201 else // At max level, increase gold reward
17202 {
17203 xp = 0;
17204 moneyReward = uint32(GetQuestMoneyReward(quest) + int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)));
17205 }
17206
17208
17209 packet.QuestID = questId;
17210 packet.MoneyReward = moneyReward;
17211 packet.XPReward = xp;
17212 packet.SkillLineIDReward = quest->GetRewardSkillId();
17213 packet.NumSkillUpsReward = quest->GetRewardSkillPoints();
17214
17215 if (questGiver)
17216 {
17217 if (questGiver->IsGossip())
17219
17220 if (questGiver->IsQuestGiver())
17222
17224 if (Quest const* rewardQuest = GetNextQuest(questGiver, quest))
17225 packet.UseQuestReward = CanTakeQuest(rewardQuest, false);
17226 }
17227
17228 packet.HideChatMessage = hideChatMessage;
17229
17230 SendDirectMessage(packet.Write());
17231}
17232
17234{
17235 if (questId)
17236 {
17237 WorldPackets::Quest::QuestGiverQuestFailed questGiverQuestFailed;
17238 questGiverQuestFailed.QuestID = questId;
17239 questGiverQuestFailed.Reason = reason; // failed reason (valid reasons: 4, 16, 50, 17, other values show default message)
17240 SendDirectMessage(questGiverQuestFailed.Write());
17241 }
17242}
17243
17245{
17246 if (questId)
17247 {
17248 WorldPackets::Quest::QuestUpdateFailedTimer questUpdateFailedTimer;
17249 questUpdateFailedTimer.QuestID = questId;
17250 SendDirectMessage(questUpdateFailedTimer.Write());
17251 }
17252}
17253
17254void Player::SendCanTakeQuestResponse(QuestFailedReason reason, bool sendErrorMessage /*= true*/, std::string reasonText /*= ""*/) const
17255{
17256 WorldPackets::Quest::QuestGiverInvalidQuest questGiverInvalidQuest;
17257
17258 questGiverInvalidQuest.Reason = reason;
17259 questGiverInvalidQuest.SendErrorMessage = sendErrorMessage;
17260 questGiverInvalidQuest.ReasonText = reasonText;
17261
17262 SendDirectMessage(questGiverInvalidQuest.Write());
17263}
17264
17265void Player::SendQuestConfirmAccept(Quest const* quest, Player* receiver) const
17266{
17267 if (!receiver)
17268 return;
17269
17271
17272 packet.QuestTitle = quest->GetLogTitle();
17273 uint32 questID = quest->GetQuestId();
17274
17275 LocaleConstant localeConstant = receiver->GetSession()->GetSessionDbLocaleIndex();
17276 if (localeConstant != LOCALE_enUS)
17277 if (QuestTemplateLocale const* questTemplateLocale = sObjectMgr->GetQuestLocale(questID))
17278 ObjectMgr::GetLocaleString(questTemplateLocale->LogTitle, localeConstant, packet.QuestTitle);
17279
17280 packet.QuestID = questID;
17281 packet.InitiatedBy = GetGUID();
17282
17283 receiver->SendDirectMessage(packet.Write());
17284}
17285
17286void Player::SendPushToPartyResponse(Player const* player, QuestPushReason reason, Quest const* quest /*= nullptr*/) const
17287{
17288 if (player)
17289 {
17291 response.SenderGUID = player->GetGUID();
17292 response.Result = AsUnderlyingType(reason);
17293 if (quest)
17294 {
17295 response.QuestTitle = quest->GetLogTitle();
17297 if (localeConstant != LOCALE_enUS)
17298 if (QuestTemplateLocale const* questTemplateLocale = sObjectMgr->GetQuestLocale(quest->GetQuestId()))
17299 ObjectMgr::GetLocaleString(questTemplateLocale->LogTitle, localeConstant, response.QuestTitle);
17300 }
17301
17302 SendDirectMessage(response.Write());
17303 }
17304}
17305
17306void Player::SendQuestUpdateAddCredit(Quest const* quest, ObjectGuid guid, QuestObjective const& obj, uint16 count) const
17307{
17309 packet.VictimGUID = guid;
17310 packet.QuestID = quest->GetQuestId();
17311 packet.ObjectID = obj.ObjectID;
17312 packet.Count = count;
17313 packet.Required = obj.Amount;
17314 packet.ObjectiveType = obj.Type;
17315 SendDirectMessage(packet.Write());
17316}
17317
17319{
17321 packet.QuestID = obj.QuestID;
17322 packet.ObjectID = obj.ObjectID;
17323 packet.ObjectiveType = obj.Type;
17324 SendDirectMessage(packet.Write());
17325}
17326
17327void Player::SendQuestUpdateAddItem(ItemTemplate const* itemTemplate, QuestObjective const& obj, uint16 count) const
17328{
17330
17331 packet.PlayerGUID = GetGUID();
17332
17333 packet.Slot = INVENTORY_SLOT_BAG_0;
17334 packet.SlotInBag = 0;
17335 packet.Item.ItemID = itemTemplate->GetId();
17336 packet.QuestLogItemID = itemTemplate->QuestLogItemId;
17337 packet.Quantity = count;
17340 packet.Unused_1017 = true;
17341
17343 GetGroup()->BroadcastPacket(packet.Write(), true);
17344 else
17345 SendDirectMessage(packet.Write());
17346}
17347
17348void Player::SendQuestUpdateAddPlayer(Quest const* quest, uint16 newCount) const
17349{
17350 WorldPackets::Quest::QuestUpdateAddPvPCredit questUpdateAddPvpCredit;
17351 questUpdateAddPvpCredit.QuestID = quest->GetQuestId();
17352 questUpdateAddPvpCredit.Count = newCount;
17353 SendDirectMessage(questUpdateAddPvpCredit.Write());
17354}
17355
17357{
17359}
17360
17362{
17364
17365 for (auto itr = guids.begin(); itr != guids.end(); ++itr)
17366 {
17367 if (itr->IsAnyTypeCreature())
17368 {
17369 // need also pet quests case support
17370 Creature* questgiver = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, *itr);
17371 if (!questgiver)
17372 continue;
17373 if (!questgiver->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER))
17374 continue;
17375
17376 response.QuestGiver.emplace_back(questgiver->GetGUID(), GetQuestDialogStatus(questgiver));
17377 }
17378 else if (itr->IsGameObject())
17379 {
17380 GameObject* questgiver = GetMap()->GetGameObject(*itr);
17381 if (!questgiver || questgiver->GetGoType() != GAMEOBJECT_TYPE_QUESTGIVER)
17382 continue;
17383
17384 response.QuestGiver.emplace_back(questgiver->GetGUID(), GetQuestDialogStatus(questgiver));
17385 }
17386 }
17387
17388 SendDirectMessage(response.Write());
17389}
17390
17392{
17393 for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
17394 {
17395 uint32 questId = GetQuestSlotQuestId(i);
17396 if (questId == 0)
17397 continue;
17398
17399 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
17400 if (!quest)
17401 continue;
17402
17403 if (quest->HasFlag(QUEST_FLAGS_FLAGS_PVP))
17404 return true;
17405 }
17406
17407 return false;
17408}
17409
17410/*********************************************************/
17411/*** LOAD SYSTEM ***/
17412/*********************************************************/
17413
17415{
17416 if (!result)
17417 return;
17418
17419 auto declinedNames = m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::DeclinedNames, 0);
17420 for (uint8 i = 0; i < MAX_DECLINED_NAME_CASES; ++i)
17421 SetUpdateFieldValue(declinedNames.ModifyValue(&UF::DeclinedNames::Name, i), (*result)[i].GetString());
17422}
17423
17425{
17426 // arenateamid, played_week, played_season, personal_rating
17427 uint16 personalRatingCache[] = {0, 0, 0};
17428
17429 if (result)
17430 {
17431 do
17432 {
17433 Field* fields = result->Fetch();
17434
17435 uint32 arenaTeamId = fields[0].GetUInt32();
17436
17437 ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId);
17438 if (!arenaTeam)
17439 {
17440 TC_LOG_ERROR("entities.player.loading", "Player::_LoadArenaTeamInfo: couldn't load arenateam {}", arenaTeamId);
17441 continue;
17442 }
17443
17444 uint8 arenaSlot = arenaTeam->GetSlot();
17445 ASSERT(arenaSlot < 3);
17446
17447 personalRatingCache[arenaSlot] = fields[4].GetUInt16();
17448
17449 SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_ID, arenaTeamId);
17450 SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_TYPE, arenaTeam->GetType());
17451 SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_MEMBER, (arenaTeam->GetCaptain() == GetGUID()) ? 0 : 1);
17452 SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_GAMES_WEEK, uint32(fields[1].GetUInt16()));
17453 SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_GAMES_SEASON, uint32(fields[2].GetUInt16()));
17454 SetArenaTeamInfoField(arenaSlot, ARENA_TEAM_WINS_SEASON, uint32(fields[3].GetUInt16()));
17455 }
17456 while (result->NextRow());
17457 }
17458
17459 for (uint8 slot = 0; slot <= 2; ++slot)
17460 {
17461 SetArenaTeamInfoField(slot, ARENA_TEAM_PERSONAL_RATING, uint32(personalRatingCache[slot]));
17462 }
17463}
17464
17466{
17467 // SetPQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, "SELECT setguid, setindex, name, iconname, ignore_mask, AssignedSpecIndex, item0, item1, item2, item3, item4, item5, item6, item7, item8, item9, item10, item11, item12, item13, item14, item15, item16, item17, item18 FROM character_equipmentsets WHERE guid = '{}' ORDER BY setindex", GUID_LOPART(m_guid));
17468 if (!result)
17469 return;
17470
17471 do
17472 {
17473 Field* fields = result->Fetch();
17474 EquipmentSetInfo eqSet;
17475
17476 eqSet.Data.Guid = fields[0].GetUInt64();
17478 eqSet.Data.SetID = fields[1].GetUInt8();
17479 eqSet.Data.SetName = fields[2].GetString();
17480 eqSet.Data.SetIcon = fields[3].GetString();
17481 eqSet.Data.IgnoreMask = fields[4].GetUInt32();
17482 eqSet.Data.AssignedSpecIndex = fields[5].GetInt32();
17484
17486 if (ObjectGuid::LowType guid = fields[6 + i].GetUInt64())
17487 eqSet.Data.Pieces[i] = ObjectGuid::Create<HighGuid::Item>(guid);
17488
17489 eqSet.Data.Appearances.fill(0);
17490 eqSet.Data.Enchants.fill(0);
17491
17492 if (eqSet.Data.SetID >= MAX_EQUIPMENT_SET_INDEX) // client limit
17493 continue;
17494
17495 _equipmentSets[eqSet.Data.Guid] = eqSet;
17496 } while (result->NextRow());
17497}
17498
17500{
17501 // 0 1 2 3 4 5 6 7 8 9
17502 //SELECT setguid, setindex, name, iconname, ignore_mask, appearance0, appearance1, appearance2, appearance3, appearance4,
17503 // 10 11 12 13 14 15 16 17 18 19 20 21
17504 // appearance5, appearance6, appearance7, appearance8, appearance9, appearance10, appearance11, appearance12, appearance13, appearance14, appearance15, appearance16,
17505 // 22 23 24 25
17506 // appearance17, appearance18, mainHandEnchant, offHandEnchant FROM character_transmog_outfits WHERE guid = ? ORDER BY setindex
17507 if (!result)
17508 return;
17509
17510 do
17511 {
17512 Field* fields = result->Fetch();
17513 EquipmentSetInfo eqSet;
17514
17515 eqSet.Data.Guid = fields[0].GetUInt64();
17517 eqSet.Data.SetID = fields[1].GetUInt8();
17518 eqSet.Data.SetName = fields[2].GetString();
17519 eqSet.Data.SetIcon = fields[3].GetString();
17520 eqSet.Data.IgnoreMask = fields[4].GetUInt32();
17522 eqSet.Data.Pieces.fill(ObjectGuid::Empty);
17523
17525 eqSet.Data.Appearances[i] = fields[5 + i].GetInt32();
17526
17527 for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i)
17528 eqSet.Data.Enchants[i] = fields[24 + i].GetInt32();
17529
17530 if (eqSet.Data.SetID >= MAX_EQUIPMENT_SET_INDEX) // client limit
17531 continue;
17532
17533 _equipmentSets[eqSet.Data.Guid] = eqSet;
17534 } while (result->NextRow());
17535}
17536
17538{
17539 if (!result)
17540 return;
17541
17542 Field* fields = result->Fetch();
17543 // Expecting only one row
17544 // 0 1 2 3 4 5 6 7 8 9 10
17545 // SELECT instanceId, team, joinX, joinY, joinZ, joinO, joinMapId, taxiStart, taxiEnd, mountSpell, queueTypeId FROM character_battleground_data WHERE guid = ?
17546
17547 m_bgData.bgInstanceID = fields[0].GetUInt32();
17548 m_bgData.bgTeam = Team(fields[1].GetUInt16());
17549 m_bgData.joinPos = WorldLocation(fields[6].GetUInt16(), // Map
17550 fields[2].GetFloat(), // X
17551 fields[3].GetFloat(), // Y
17552 fields[4].GetFloat(), // Z
17553 fields[5].GetFloat()); // Orientation
17554 m_bgData.taxiPath[0] = fields[7].GetUInt32();
17555 m_bgData.taxiPath[1] = fields[8].GetUInt32();
17556 m_bgData.mountSpell = fields[9].GetUInt32();
17557 m_bgData.queueId = BattlegroundQueueTypeId::FromPacked(fields[10].GetUInt64());
17558}
17559
17560bool Player::LoadPositionFromDB(uint32& mapid, float& x, float& y, float& z, float& o, bool& in_flight, ObjectGuid guid)
17561{
17563 stmt->setUInt64(0, guid.GetCounter());
17564 PreparedQueryResult result = CharacterDatabase.Query(stmt);
17565
17566 if (!result)
17567 return false;
17568
17569 Field* fields = result->Fetch();
17570
17571 x = fields[0].GetFloat();
17572 y = fields[1].GetFloat();
17573 z = fields[2].GetFloat();
17574 o = fields[3].GetFloat();
17575 mapid = fields[4].GetUInt16();
17576 in_flight = !fields[5].GetString().empty();
17577
17578 return true;
17579}
17580
17582{
17584 m_homebindAreaId = areaId;
17585
17586 // update sql homebind
17588 stmt->setUInt16(0, m_homebind.GetMapId());
17589 stmt->setUInt16(1, m_homebindAreaId);
17590 stmt->setFloat (2, m_homebind.GetPositionX());
17591 stmt->setFloat (3, m_homebind.GetPositionY());
17592 stmt->setFloat (4, m_homebind.GetPositionZ());
17593 stmt->setFloat (5, m_homebind.GetOrientation());
17594 stmt->setUInt64(6, GetGUID().GetCounter());
17595 CharacterDatabase.Execute(stmt);
17596}
17597
17599{
17602 packet.BindMapID = m_homebind.GetMapId();
17604 SendDirectMessage(packet.Write());
17605}
17606
17607void Player::SendPlayerBound(ObjectGuid const& binderGuid, uint32 areaId) const
17608{
17609 WorldPackets::Misc::PlayerBound packet(binderGuid, areaId);
17610 SendDirectMessage(packet.Write());
17611}
17612
17614{
17615 return GetSession()->PlayerLoading();
17616}
17617
17619{
17621 if (!result)
17622 {
17623 std::string name = "<unknown>";
17624 sCharacterCache->GetCharacterNameByGuid(guid, name);
17625 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player '{}' ({}) not found in table `characters`, can't load. ", name, guid.ToString());
17626 return false;
17627 }
17628
17629 struct PlayerLoadData
17630 {
17631 // "SELECT c.guid, account, name, race, class, gender, level, xp, money, inventorySlots, bankSlots, restState, playerFlags, playerFlagsEx, "
17632 // "position_x, position_y, position_z, map, orientation, taximask, createTime, createMode, cinematic, totaltime, leveltime, rest_bonus, logout_time, is_logout_resting, resettalents_cost, "
17633 // "resettalents_time, primarySpecialization, trans_x, trans_y, trans_z, trans_o, transguid, extra_flags, summonedPetNumber, at_login, zone, online, death_expire_time, taxi_path, dungeonDifficulty, "
17634 // "totalKills, todayKills, yesterdayKills, chosenTitle, watchedFaction, drunk, "
17635 // "health, power1, power2, power3, power4, power5, power6, power7, power8, power9, power10, instance_id, activeTalentGroup, lootSpecId, exploredZones, knownTitles, actionBars, "
17636 // "raidDifficulty, legacyRaidDifficulty, fishingSteps, honor, honorLevel, honorRestState, honorRestBonus, numRespecs, "
17637 // "personalTabardEmblemStyle, personalTabardEmblemColor, personalTabardBorderStyle, personalTabardBorderColor, personalTabardBackgroundColor "
17638 // "FROM characters c LEFT JOIN character_fishingsteps cfs ON c.guid = cfs.guid WHERE c.guid = ?", CONNECTION_ASYNC);
17639
17641 uint32 account;
17642 std::string name;
17643 uint8 race;
17644 uint8 class_;
17645 Gender gender;
17646 uint8 level;
17647 uint32 xp;
17648 uint64 money;
17649 uint8 inventorySlots;
17650 uint8 bankSlots;
17651 PlayerRestState restState;
17652 PlayerFlags playerFlags;
17653 PlayerFlagsEx playerFlagsEx;
17654 float position_x;
17655 float position_y;
17656 float position_z;
17657 uint16 map;
17658 float orientation;
17659 std::string taximask;
17660 time_t createTime;
17661 PlayerCreateMode createMode;
17662 uint8 cinematic;
17663 uint32 totaltime;
17664 uint32 leveltime;
17665 float rest_bonus;
17666 time_t logout_time;
17667 uint8 is_logout_resting;
17668 uint32 resettalents_cost;
17669 time_t resettalents_time;
17670 uint32 primarySpecialization;
17671 float trans_x;
17672 float trans_y;
17673 float trans_z;
17674 float trans_o;
17675 ObjectGuid::LowType transguid;
17676 uint16 extra_flags;
17677 uint32 summonedPetNumber;
17678 uint16 at_login;
17679 uint16 zone;
17680 uint8 online;
17681 time_t death_expire_time;
17682 std::string taxi_path;
17683 Difficulty dungeonDifficulty;
17684 uint32 totalKills;
17685 uint16 todayKills;
17686 uint16 yesterdayKills;
17687 uint32 chosenTitle;
17688 uint32 watchedFaction;
17689 uint8 drunk;
17690 uint32 health;
17691 std::array<uint32, MAX_POWERS_PER_CLASS> powers;
17692 uint32 instance_id;
17693 uint8 activeTalentGroup;
17694 uint32 lootSpecId;
17695 std::string exploredZones;
17696 std::string knownTitles;
17697 uint8 actionBars;
17698 Difficulty raidDifficulty;
17699 Difficulty legacyRaidDifficulty;
17700 uint8 fishingSteps;
17701 uint32 honor;
17702 uint32 honorLevel;
17703 PlayerRestState honorRestState;
17704 float honorRestBonus;
17705 uint8 numRespecs;
17706 int32 personalTabardEmblemStyle;
17707 int32 personalTabardEmblemColor;
17708 int32 personalTabardBorderStyle;
17709 int32 personalTabardBorderColor;
17710 int32 personalTabardBackgroundColor;
17711
17712 explicit PlayerLoadData(Field const* fields)
17713 {
17714 std::size_t i = 0;
17715 guid = fields[i++].GetUInt64();
17716 account = fields[i++].GetUInt32();
17717 name = fields[i++].GetString();
17718 race = fields[i++].GetUInt8();
17719 class_ = fields[i++].GetUInt8();
17720 gender = Gender(fields[i++].GetUInt8());
17721 level = fields[i++].GetUInt8();
17722 xp = fields[i++].GetUInt32();
17723 money = fields[i++].GetUInt64();
17724 inventorySlots = fields[i++].GetUInt8();
17725 bankSlots = fields[i++].GetUInt8();
17726 restState = PlayerRestState(fields[i++].GetUInt8());
17727 playerFlags = PlayerFlags(fields[i++].GetUInt32());
17728 playerFlagsEx = PlayerFlagsEx(fields[i++].GetUInt32());
17729 position_x = fields[i++].GetFloat();
17730 position_y = fields[i++].GetFloat();
17731 position_z = fields[i++].GetFloat();
17732 map = fields[i++].GetUInt16();
17733 orientation = fields[i++].GetFloat();
17734 taximask = fields[i++].GetString();
17735 createTime = fields[i++].GetInt64();
17736 createMode = PlayerCreateMode(fields[i++].GetInt8());
17737 cinematic = fields[i++].GetUInt8();
17738 totaltime = fields[i++].GetUInt32();
17739 leveltime = fields[i++].GetUInt32();
17740 rest_bonus = fields[i++].GetFloat();
17741 logout_time = fields[i++].GetInt64();
17742 is_logout_resting = fields[i++].GetUInt8();
17743 resettalents_cost = fields[i++].GetUInt32();
17744 resettalents_time = fields[i++].GetInt64();
17745 primarySpecialization = fields[i++].GetUInt32();
17746 trans_x = fields[i++].GetFloat();
17747 trans_y = fields[i++].GetFloat();
17748 trans_z = fields[i++].GetFloat();
17749 trans_o = fields[i++].GetFloat();
17750 transguid = fields[i++].GetUInt64();
17751 extra_flags = fields[i++].GetUInt16();
17752 summonedPetNumber = fields[i++].GetUInt32();
17753 at_login = fields[i++].GetUInt16();
17754 zone = fields[i++].GetUInt16();
17755 online = fields[i++].GetUInt8();
17756 death_expire_time = fields[i++].GetInt64();
17757 taxi_path = fields[i++].GetString();
17758 dungeonDifficulty = Difficulty(fields[i++].GetUInt8());
17759 totalKills = fields[i++].GetUInt32();
17760 todayKills = fields[i++].GetUInt16();
17761 yesterdayKills = fields[i++].GetUInt16();
17762 chosenTitle = fields[i++].GetUInt32();
17763 watchedFaction = fields[i++].GetUInt32();
17764 drunk = fields[i++].GetUInt8();
17765 health = fields[i++].GetUInt32();
17766 for (uint32& power : powers)
17767 power = fields[i++].GetUInt32();
17768 instance_id = fields[i++].GetUInt32();
17769 activeTalentGroup = fields[i++].GetUInt8();
17770 lootSpecId = fields[i++].GetUInt32();
17771 exploredZones = fields[i++].GetString();
17772 knownTitles = fields[i++].GetString();
17773 actionBars = fields[i++].GetUInt8();
17774 raidDifficulty = Difficulty(fields[i++].GetUInt8());
17775 legacyRaidDifficulty = Difficulty(fields[i++].GetUInt8());
17776 fishingSteps = fields[i++].GetUInt8();
17777 honor = fields[i++].GetUInt32();
17778 honorLevel = fields[i++].GetUInt32();
17779 honorRestState = PlayerRestState(fields[i++].GetUInt8());
17780 honorRestBonus = fields[i++].GetFloat();
17781 numRespecs = fields[i++].GetUInt8();
17782 personalTabardEmblemStyle = fields[i++].GetInt32();
17783 personalTabardEmblemColor = fields[i++].GetInt32();
17784 personalTabardBorderStyle = fields[i++].GetInt32();
17785 personalTabardBorderColor = fields[i++].GetInt32();
17786 personalTabardBackgroundColor = fields[i++].GetInt32();
17787 }
17788
17789 } fields(result->Fetch());
17790
17791 // check if the character's account in the db and the logged in account match.
17792 // player should be able to load/delete character only with correct account!
17793 if (fields.account != GetSession()->GetAccountId())
17794 {
17795 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) loading from wrong account (is: {}, should be: {})", guid.ToString(), GetSession()->GetAccountId(), fields.account);
17796 return false;
17797 }
17798
17800 {
17801 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) is banned, can't load.", guid.ToString());
17802 return false;
17803 }
17804
17805 Object::_Create(guid);
17806
17807 m_name = std::move(fields.name);
17808
17809 // check name limitations
17810 if (ObjectMgr::CheckPlayerName(m_name, GetSession()->GetSessionDbcLocale()) != CHAR_NAME_SUCCESS ||
17812 {
17814 stmt->setUInt16(0, uint16(AT_LOGIN_RENAME));
17815 stmt->setUInt64(1, guid.GetCounter());
17816 CharacterDatabase.Execute(stmt);
17817 return false;
17818 }
17819
17821
17825
17826 if (!IsValidGender(fields.gender))
17827 {
17828 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has wrong gender ({}), can't load.", guid.ToString(), uint32(fields.gender));
17829 return false;
17830 }
17831
17832 SetRace(fields.race);
17833 SetClass(fields.class_);
17834 SetGender(fields.gender);
17835
17836 // check if race/class combination is valid
17837 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(GetRace(), GetClass());
17838 if (!info)
17839 {
17840 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has wrong race/class ({}/{}), can't load.", guid.ToString(), GetRace(), GetClass());
17841 return false;
17842 }
17843
17844 SetLevel(fields.level, false);
17845 SetXP(fields.xp);
17846
17847 std::vector<std::string_view> exploredZones = Trinity::Tokenize(fields.exploredZones, ' ', false);
17848 for (std::size_t i = 0; i < exploredZones.size(); ++i)
17849 AddExploredZones(i / 2, Trinity::StringTo<uint64>(exploredZones[i]).value_or(UI64LIT(0)) << (32 * (i % 2)));
17850
17851 std::vector<std::string_view> knownTitles = Trinity::Tokenize(fields.knownTitles, ' ', false);
17852 for (std::size_t i = 0; i < knownTitles.size(); ++i)
17854 Trinity::StringTo<uint64>(knownTitles[i]).value_or(UI64LIT(0)) << (32 * (i % 2)));
17855
17856 SetObjectScale(1.0f);
17857
17858 // load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateCriteria)
17861
17862 SetMoney(std::min(fields.money, MAX_MONEY_AMOUNT));
17863
17864 std::vector<UF::ChrCustomizationChoice> customizations;
17866 {
17867 do
17868 {
17869 Field* fields = customizationsResult->Fetch();
17870 customizations.emplace_back();
17871 UF::ChrCustomizationChoice& choice = customizations.back();
17872 choice.ChrCustomizationOptionID = fields[0].GetUInt32();
17873 choice.ChrCustomizationChoiceID = fields[1].GetUInt32();
17874
17875 } while (customizationsResult->NextRow());
17876 }
17877
17878 SetCustomizations(Trinity::Containers::MakeIteratorPair(customizations.begin(), customizations.end()), false);
17879 SetInventorySlotCount(fields.inventorySlots);
17880 SetBankBagSlotCount(fields.bankSlots);
17881 SetNativeGender(fields.gender);
17883 ReplaceAllPlayerFlags(fields.playerFlags);
17884 ReplaceAllPlayerFlagsEx(fields.playerFlagsEx);
17885 SetWatchedFactionIndex(fields.watchedFaction);
17886
17887 m_atLoginFlags = fields.at_login;
17888
17889 if (!GetSession()->ValidateAppearance(Races(GetRace()), Classes(GetClass()), fields.gender, MakeChrCustomizationChoiceRange(customizations)))
17890 {
17891 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has wrong Appearance values (Hair/Skin/Color), can't load.", guid.ToString());
17892 return false;
17893 }
17894
17895 // set which actionbars the client has active - DO NOT REMOVE EVER AGAIN (can be changed though, if it does change fieldwise)
17896 SetMultiActionBars(fields.actionBars);
17897
17898 m_fishingSteps = fields.fishingSteps;
17899
17901
17902 TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: Load Basic value of player '{}' is: ", m_name);
17904
17905 //Need to call it to initialize m_team (m_team can be calculated from race)
17906 //Other way is to saves m_team into characters table.
17908
17909 // load home bind and check in same time class/race pair, it used later for restore broken positions
17911 return false;
17912
17914 InitPrimaryProfessions(); // to max set before any spell loaded
17915
17916 // init saved position, and fix it later if problematic
17917 Relocate(fields.position_x, fields.position_y, fields.position_z, fields.orientation);
17918
17919 uint32 mapId = fields.map;
17920 uint32 instanceId = fields.instance_id;
17921
17922 SetDungeonDifficultyID(CheckLoadedDungeonDifficultyID(fields.dungeonDifficulty));
17923 SetRaidDifficultyID(CheckLoadedRaidDifficultyID(fields.raidDifficulty));
17925
17926 auto RelocateToHomebind = [this, &mapId, &instanceId]() { mapId = m_homebind.GetMapId(); instanceId = 0; WorldRelocate(m_homebind); };
17927
17929
17934
17937
17938 GetSession()->SetPlayer(this);
17939 MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
17940 Map* map = nullptr;
17941 bool player_at_bg = false;
17942 if (!mapEntry || !IsPositionValid())
17943 {
17944 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has invalid coordinates (MapId: {} X: {} Y: {} Z: {} O: {}). Teleport to default race/class locations.",
17946 RelocateToHomebind();
17947 }
17948 // Player was saved in Arena or Bg
17949 else if (mapEntry->IsBattlegroundOrArena())
17950 {
17951 Battleground* currentBg = nullptr;
17952 if (m_bgData.bgInstanceID) //saved in Battleground
17953 currentBg = sBattlegroundMgr->GetBattleground(m_bgData.bgInstanceID, BATTLEGROUND_TYPE_NONE);
17954
17955 player_at_bg = currentBg && currentBg->IsPlayerInBattleground(GetGUID());
17956
17957 if (player_at_bg && currentBg->GetStatus() != STATUS_WAIT_LEAVE)
17958 {
17959 map = currentBg->GetBgMap();
17960
17961 if (BattlegroundPlayer const* bgPlayer = currentBg->GetBattlegroundPlayerData(GetGUID()))
17962 {
17963 AddBattlegroundQueueId(bgPlayer->queueTypeId);
17964 m_bgData.bgTypeID = BattlegroundTypeId(bgPlayer->queueTypeId.BattlemasterListId);
17965
17966 //join player to battleground group
17967 currentBg->EventPlayerLoggedIn(this);
17968
17969 SetInviteForBattlegroundQueueType(bgPlayer->queueTypeId, currentBg->GetInstanceID());
17971 }
17972 }
17973 // Bg was not found - go to Entry Point
17974 else
17975 {
17976 // leave bg
17977 if (player_at_bg)
17978 {
17979 player_at_bg = false;
17980 currentBg->RemovePlayerAtLeave(GetGUID(), false, true);
17981 }
17982
17983 // Do not look for instance if bg not found
17985 mapId = _loc.GetMapId();
17986 instanceId = 0;
17987
17988 // Db field type is type int16, so it can never be MAPID_INVALID
17989 //if (mapId == MAPID_INVALID) -- code kept for reference
17990 if (int16(mapId) == int16(-1)) // Battleground Entry Point not found (???)
17991 {
17992 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) was in BG in database, but BG was not found and entry point was invalid! Teleport to default race/class locations.",
17993 guid.ToString());
17994 RelocateToHomebind();
17995 }
17996 else
17997 Relocate(&_loc);
17998
17999 // We are not in BG anymore
18001 }
18002 }
18003 // currently we do not support transport in bg
18004 else if (fields.transguid)
18005 {
18006 ObjectGuid transGUID = ObjectGuid::Create<HighGuid::Transport>(fields.transguid);
18007
18008 Transport* transport = nullptr;
18009 if (Map* transportMap = sMapMgr->CreateMap(mapId, this))
18010 {
18011 if (Transport* transportOnMap = transportMap->GetTransport(transGUID))
18012 {
18013 if (transportOnMap->GetExpectedMapId() != mapId)
18014 {
18015 mapId = transportOnMap->GetExpectedMapId();
18016 instanceId = 0;
18017 transportMap = sMapMgr->CreateMap(mapId, this);
18018 if (transportMap)
18019 transport = transportMap->GetTransport(transGUID);
18020 }
18021 else
18022 transport = transportOnMap;
18023 }
18024 }
18025
18026 if (transport)
18027 {
18028 float x = fields.trans_x, y = fields.trans_y, z = fields.trans_z, o = fields.trans_o;
18030 transport->CalculatePassengerPosition(x, y, z, &o);
18031
18032 if (!Trinity::IsValidMapCoord(x, y, z, o) ||
18033 // transport size limited
18034 std::fabs(m_movementInfo.transport.pos.GetPositionX()) > 250.0f ||
18035 std::fabs(m_movementInfo.transport.pos.GetPositionY()) > 250.0f ||
18036 std::fabs(m_movementInfo.transport.pos.GetPositionZ()) > 250.0f)
18037 {
18038 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has invalid transport coordinates (X: {} Y: {} Z: {} O: {}). Teleport to bind location.",
18039 guid.ToString(), x, y, z, o);
18040
18042
18043 RelocateToHomebind();
18044 }
18045 else
18046 {
18047 Relocate(x, y, z, o);
18048 mapId = transport->GetMapId();
18049
18050 transport->AddPassenger(this);
18051 }
18052 }
18053 else
18054 {
18055 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has problems with transport guid ({}). Teleport to bind location.",
18056 guid.ToString(), fields.transguid);
18057
18058 RelocateToHomebind();
18059 }
18060 }
18061 // currently we do not support taxi in instance
18062 else if (!fields.taxi_path.empty())
18063 {
18064 instanceId = 0;
18065
18066 // Not finish taxi flight path
18067 if (m_bgData.HasTaxiPath())
18068 {
18069 for (int i = 0; i < 2; ++i)
18071 }
18072 else if (!m_taxi.LoadTaxiDestinationsFromString(fields.taxi_path, GetTeam()))
18073 {
18074 // problems with taxi path loading
18075 TaxiNodesEntry const* nodeEntry = nullptr;
18076 if (uint32 node_id = m_taxi.GetTaxiSource())
18077 nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
18078
18079 if (!nodeEntry) // don't know taxi start node, teleport to homebind
18080 {
18081 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has wrong data in taxi destination list ({}), teleport to homebind.", GetGUID().ToString(), fields.taxi_path);
18082 RelocateToHomebind();
18083 }
18084 else // has start node, teleport to it
18085 {
18086 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player ({}) has too short taxi destination list ({}), teleport to original node.", GetGUID().ToString(), fields.taxi_path);
18087 mapId = nodeEntry->ContinentID;
18088 Relocate(nodeEntry->Pos.X, nodeEntry->Pos.Y, nodeEntry->Pos.Z, 0.0f);
18089 }
18091 }
18092
18093 if (uint32 node_id = m_taxi.GetTaxiSource())
18094 {
18095 // save source node as recall coord to prevent recall and fall from sky
18096 TaxiNodesEntry const* nodeEntry = sTaxiNodesStore.LookupEntry(node_id);
18097 if (nodeEntry && nodeEntry->ContinentID == GetMapId())
18098 {
18099 ASSERT(nodeEntry); // checked in m_taxi.LoadTaxiDestinationsFromString
18100 mapId = nodeEntry->ContinentID;
18101 Relocate(nodeEntry->Pos.X, nodeEntry->Pos.Y, nodeEntry->Pos.Z, 0.0f);
18102 }
18103
18104 // flight will started later
18105 }
18106 }
18107 else if (mapEntry->IsDungeon() && instanceId)
18108 {
18109 // try finding instance by id first
18110 map = sMapMgr->FindMap(mapId, instanceId);
18111 }
18112
18113 // Map could be changed before
18114 mapEntry = sMapStore.LookupEntry(mapId);
18115 // client without expansion support
18116 if (mapEntry)
18117 {
18118 if (GetSession()->GetExpansion() < mapEntry->Expansion())
18119 {
18120 TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: Player '{}' ({}) using client without required expansion tried login at non accessible map {}",
18121 GetName(), GetGUID().ToString(), mapId);
18122 RelocateToHomebind();
18123 }
18124 }
18125
18126 // NOW player must have valid map
18127 // load the player's map here if it's not already loaded
18128 if (!map)
18129 map = sMapMgr->CreateMap(mapId, this);
18130 AreaTriggerStruct const* areaTrigger = nullptr;
18131 bool check = false;
18132
18133 if (!map)
18134 {
18135 areaTrigger = sObjectMgr->GetGoBackTrigger(mapId);
18136 check = true;
18137 }
18138 else if (map->IsDungeon()) // if map is dungeon...
18139 {
18140 if (TransferAbortParams denyReason = map->CannotEnter(this)) // ... and can't enter map, then look for entry point.
18141 {
18142 SendTransferAborted(map->GetId(), denyReason.Reason, denyReason.Arg, denyReason.MapDifficultyXConditionId);
18143 areaTrigger = sObjectMgr->GetGoBackTrigger(mapId);
18144 check = true;
18145 }
18146 else if (instanceId && !sInstanceLockMgr.FindActiveInstanceLock(guid, { mapId, map->GetDifficultyID() })) // ... and instance is reseted then look for entrance.
18147 {
18148 areaTrigger = sObjectMgr->GetMapEntranceTrigger(mapId);
18149 check = true;
18150 }
18151 }
18152
18153 if (check) // in case of special event when creating map...
18154 {
18155 if (areaTrigger) // ... if we have an areatrigger, then relocate to new map/coordinates.
18156 {
18157 Relocate(areaTrigger->target_X, areaTrigger->target_Y, areaTrigger->target_Z, GetOrientation());
18158 if (mapId != areaTrigger->target_mapId)
18159 {
18160 mapId = areaTrigger->target_mapId;
18161 map = sMapMgr->CreateMap(mapId, this);
18162 }
18163 }
18164 }
18165
18166 if (!map)
18167 {
18168 RelocateToHomebind();
18169 map = sMapMgr->CreateMap(mapId, this);
18170 if (!map)
18171 {
18172 TC_LOG_ERROR("entities.player.loading", "Player::LoadFromDB: Player '{}' ({}) Map: {}, X: {}, Y: {}, Z: {}, O: {}. Invalid default map coordinates or instance couldn't be created.",
18174 return false;
18175 }
18176 }
18177
18178 SetMap(map);
18180
18181 // now that map position is determined, check instance validity
18183 m_InstanceValid = false;
18184
18185 if (player_at_bg)
18187
18188 // randomize first save time in range [CONFIG_INTERVAL_SAVE] around [CONFIG_INTERVAL_SAVE]
18189 // this must help in case next save after mass player load after server startup
18190 m_nextSave = urand(m_nextSave / 2, m_nextSave * 3 / 2);
18191
18193
18194 time_t now = GameTime::GetGameTime();
18195 time_t logoutTime = time_t(fields.logout_time);
18196
18198
18199 // since last logout (in seconds)
18200 uint32 time_diff = uint32(now - logoutTime); //uint64 is excessive for a time_diff in seconds.. uint32 allows for 136~ year difference.
18201
18202 // set value, including drunk invisibility detection
18203 // calculate sobering. after 15 minutes logged out, the player will be sober again
18204 if (time_diff < uint32(GetDrunkValue()) * 9)
18205 SetDrunkValue(GetDrunkValue() - time_diff / 9);
18206 else
18207 SetDrunkValue(0);
18208
18209 m_createTime = fields.createTime;
18210 m_createMode = fields.createMode;
18211 m_cinematic = fields.cinematic;
18212 m_Played_time[PLAYED_TIME_TOTAL] = fields.totaltime;
18213 m_Played_time[PLAYED_TIME_LEVEL] = fields.leveltime;
18214
18215 SetTalentResetCost(fields.resettalents_cost);
18216 SetTalentResetTime(fields.resettalents_time);
18217
18218 if (!m_taxi.LoadTaxiMask(fields.taximask)) // must be before InitTaxiNodesForLevel
18219 TC_LOG_WARN("entities.player.loading", "Player::LoadFromDB: Player ({}) has invalid taximask ({}) in DB. Forced partial load.", GetGUID().ToString(), fields.taximask);
18220
18221 uint32 extraflags = fields.extra_flags;
18222
18223 _LoadPetStable(fields.summonedPetNumber, holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS));
18224
18226 {
18227 TC_LOG_ERROR("entities.player.cheat", "Player::LoadFromDB: Player ({}) tried to login while forced to rename, can't load.'", GetGUID().ToString());
18228 return false;
18229 }
18230
18231 // Honor system
18232 // Update Honor kills data
18233 m_lastHonorUpdateTime = logoutTime;
18235
18236 m_deathExpireTime = fields.death_expire_time;
18237
18240
18242
18243 // make sure the unit is considered out of combat for proper loading
18244 ClearInCombat();
18245
18246 // reset stats before loading any modifiers
18249 InitRunes();
18250
18251 // rest bonus can only be calculated after InitStatsForLevel()
18252 _restMgr->LoadRestBonus(REST_TYPE_XP, fields.restState, fields.rest_bonus);
18253
18254 // load skills after InitStatsForLevel because it triggering aura apply also
18256 UpdateSkillsForLevel(); //update skills after load, to make sure they are correctly update at player load
18257
18258 SetNumRespecs(fields.numRespecs);
18259 SetPrimarySpecialization(fields.primarySpecialization);
18260 SetActiveTalentGroup(fields.activeTalentGroup);
18262 if (!primarySpec || primarySpec->ClassID != GetClass() || GetActiveTalentGroup() >= MAX_SPECIALIZATIONS)
18264
18265 uint32 lootSpecId = fields.lootSpecId;
18266 if (ChrSpecializationEntry const* chrSpec = sChrSpecializationStore.LookupEntry(lootSpecId))
18267 if (chrSpec->ClassID == GetClass())
18268 SetLootSpecId(lootSpecId);
18269
18279
18281
18285 // add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura)
18288
18289 // Load spell locations - must be after loading auras
18291
18292 // after spell load, learn rewarded spell if need also
18301
18302 // after spell and quest load
18306
18308 holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TRAIT_ENTRIES)); // must be after loading spells
18309
18310 // must be before inventory (some items required reputation check)
18312
18319 time_diff);
18320
18323
18324 // update items with duration and realtime
18325 UpdateItemDuration(time_diff, true);
18326
18328
18329 // unread mails and next delivery time, actual mails not loaded
18337
18339
18340 // check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES
18341 // note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded
18342 uint32 curTitle = fields.chosenTitle;
18343 if (curTitle && !HasTitle(curTitle))
18344 curTitle = 0;
18345
18346 SetChosenTitle(curTitle);
18347
18348 // has to be called after last Relocate() in Player::LoadFromDB
18350
18352
18353 uint32 savedHealth = fields.health;
18354 if (!savedHealth)
18356
18357 // Spell code allow apply any auras to dead character in load time in aura/spell/item loading
18358 // Do now before stats re-calculation cleanup for ghost state unexpected auras
18359 if (!IsAlive())
18361 else
18363
18364 //apply all stat bonuses from items and auras
18365 SetCanModifyStats(true);
18367
18368 // restore remembered power/health values (but not more max values)
18369 SetHealth(savedHealth > GetMaxHealth() ? GetMaxHealth() : savedHealth);
18370 uint32 loadedPowers = 0;
18371 for (uint32 i = 0; i < MAX_POWERS; ++i)
18372 {
18373 if (GetPowerIndex(Powers(i)) != MAX_POWERS)
18374 {
18375 uint32 savedPower = fields.powers[loadedPowers];
18376 uint32 maxPower = m_unitData->MaxPower[loadedPowers];
18377 SetPower(Powers(i), (savedPower > maxPower) ? maxPower : savedPower);
18378 if (++loadedPowers >= MAX_POWERS_PER_CLASS)
18379 break;
18380 }
18381 }
18382
18383 for (; loadedPowers < MAX_POWERS_PER_CLASS; ++loadedPowers)
18385
18387 // Init rune recharge
18389 {
18390 int32 runes = GetPower(POWER_RUNES);
18391 int32 maxRunes = GetMaxPower(POWER_RUNES);
18392 uint32 runeCooldown = GetRuneBaseCooldown();
18393 while (runes < maxRunes)
18394 {
18395 SetRuneCooldown(runes, runeCooldown);
18396 ++runes;
18397 }
18398 }
18399
18400 SetPersonalTabard(fields.personalTabardEmblemStyle, fields.personalTabardEmblemColor, fields.personalTabardBorderStyle,
18401 fields.personalTabardBorderColor, fields.personalTabardBackgroundColor);
18402
18403 TC_LOG_DEBUG("entities.player.loading", "Player::LoadFromDB: The value of player '{}' after load item and aura is: ", m_name);
18405
18406 // GM state
18408 {
18409 switch (sWorld->getIntConfig(CONFIG_GM_LOGIN_STATE))
18410 {
18411 default:
18412 case 0: break; // disable
18413 case 1: SetGameMaster(true); break; // enable
18414 case 2: // save state
18415 if (extraflags & PLAYER_EXTRA_GM_ON)
18416 SetGameMaster(true);
18417 break;
18418 }
18419
18420 switch (sWorld->getIntConfig(CONFIG_GM_VISIBLE_STATE))
18421 {
18422 default:
18423 case 0: SetGMVisible(false); break; // invisible
18424 case 1: break; // visible
18425 case 2: // save state
18426 if (extraflags & PLAYER_EXTRA_GM_INVISIBLE)
18427 SetGMVisible(false);
18428 break;
18429 }
18430
18431 switch (sWorld->getIntConfig(CONFIG_GM_CHAT))
18432 {
18433 default:
18434 case 0: break; // disable
18435 case 1: SetGMChat(true); break; // enable
18436 case 2: // save state
18437 if (extraflags & PLAYER_EXTRA_GM_CHAT)
18438 SetGMChat(true);
18439 break;
18440 }
18441
18442 switch (sWorld->getIntConfig(CONFIG_GM_WHISPERING_TO))
18443 {
18444 default:
18445 case 0: break; // disable
18446 case 1: SetAcceptWhispers(true); break; // enable
18447 case 2: // save state
18448 if (extraflags & PLAYER_EXTRA_ACCEPT_WHISPERS)
18449 SetAcceptWhispers(true);
18450 break;
18451 }
18452 }
18453
18454 InitPvP();
18455
18456 // RaF stuff.
18457 if (GetSession()->IsARecruiter() || (GetSession()->GetRecruiterId() != 0))
18459
18461
18464
18466
18467 std::unique_ptr<Garrison> garrison = std::make_unique<Garrison>(this);
18468 if (garrison->LoadFromDB(holder.GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GARRISON),
18473 _garrison = std::move(garrison);
18474
18475 _InitHonorLevelOnLoadFromDB(fields.honor, fields.honorLevel);
18476
18477 _restMgr->LoadRestBonus(REST_TYPE_HONOR, fields.honorRestState, fields.honorRestBonus);
18478 if (time_diff > 0)
18479 {
18480 //speed collect rest bonus in offline, in logout, far from tavern, city (section/in hour)
18481 float bubble0 = 0.031f;
18482 //speed collect rest bonus in offline, in logout, in tavern, city (section/in hour)
18483 float bubble1 = 0.125f;
18484 float bubble = fields.is_logout_resting > 0
18485 ? bubble1 * sWorld->getRate(RATE_REST_OFFLINE_IN_TAVERN_OR_CITY)
18486 : bubble0 * sWorld->getRate(RATE_REST_OFFLINE_IN_WILDERNESS);
18487
18488 _restMgr->AddRestBonus(REST_TYPE_XP, time_diff * _restMgr->CalcExtraPerSec(REST_TYPE_XP, bubble));
18489 }
18490
18491 // Unlock battle pet system if it's enabled in bnet account
18492 if (GetSession()->GetBattlePetMgr()->IsBattlePetSystemEnabled())
18494
18495 m_achievementMgr->CheckAllAchievementCriteria(this);
18496 m_questObjectiveCriteriaMgr->CheckAllQuestObjectiveCriteria(this);
18497
18498 PushQuests();
18499
18500 for (TransmogIllusionEntry const* transmogIllusion : sTransmogIllusionStore)
18501 {
18502 if (!transmogIllusion->GetFlags().HasFlag(TransmogIllusionFlags::PlayerConditionGrantsOnLogin))
18503 continue;
18504
18505 if (GetSession()->GetCollectionMgr()->HasTransmogIllusion(transmogIllusion->ID))
18506 continue;
18507
18508 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(transmogIllusion->UnlockConditionID))
18509 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
18510 continue;
18511
18512 GetSession()->GetCollectionMgr()->AddTransmogIllusion(transmogIllusion->ID);
18513 }
18514
18515 return true;
18516}
18517
18519{
18520 for (Quest const* quest : sObjectMgr->GetQuestTemplatesAutoPush())
18521 {
18522 if (quest->GetQuestTag() && quest->GetQuestTag() != QuestTagType::Tag)
18523 continue;
18524
18525 if (!quest->IsUnavailable() && CanTakeQuest(quest, false))
18526 AddQuestAndCheckCompletion(quest, nullptr);
18527 }
18528}
18529
18531{
18532 if (!result)
18533 return;
18534
18535 do
18536 {
18537 // SELECT id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154 FROM character_cuf_profiles WHERE guid = ?
18538 Field* fields = result->Fetch();
18539
18540 uint8 id = fields[0].GetUInt8();
18541 std::string name = fields[1].GetString();
18542 uint16 frameHeight = fields[2].GetUInt16();
18543 uint16 frameWidth = fields[3].GetUInt16();
18544 uint8 sortBy = fields[4].GetUInt8();
18545 uint8 healthText = fields[5].GetUInt8();
18546 uint32 boolOptions = fields[6].GetUInt32();
18547 uint8 topPoint = fields[7].GetUInt8();
18548 uint8 bottomPoint = fields[8].GetUInt8();
18549 uint8 leftPoint = fields[9].GetUInt8();
18550 uint16 topOffset = fields[10].GetUInt16();
18551 uint16 bottomOffset = fields[11].GetUInt16();
18552 uint16 leftOffset = fields[12].GetUInt16();
18553
18554 if (id > MAX_CUF_PROFILES)
18555 {
18556 TC_LOG_ERROR("entities.player", "Player::_LoadCUFProfiles: Player '{}' ({}) has an CUF profile with invalid id (ID: {}), max is {}.", GetName(), GetGUID().ToString(), id, MAX_CUF_PROFILES);
18557 continue;
18558 }
18559
18560 _CUFProfiles[id] = std::make_unique<CUFProfile>(name, frameHeight, frameWidth, sortBy, healthText, boolOptions, topPoint, bottomPoint, leftPoint, topOffset, bottomOffset, leftOffset);
18561 }
18562 while (result->NextRow());
18563}
18564
18565bool Player::isAllowedToLoot(const Creature* creature) const
18566{
18567 if (!creature->isDead())
18568 return false;
18569
18570 if (HasPendingBind())
18571 return false;
18572
18573 Loot const* loot = creature->GetLootForPlayer(this);
18574 if (!loot || loot->isLooted()) // nothing to loot or everything looted.
18575 return false;
18576 if (!loot->HasAllowedLooter(GetGUID()) || (!loot->hasItemForAll() && !loot->hasItemFor(this))) // no loot in creature for this player
18577 return false;
18578
18579 switch (loot->GetLootMethod())
18580 {
18581 case PERSONAL_LOOT:
18582 case FREE_FOR_ALL:
18583 return true;
18584 case ROUND_ROBIN:
18585 // may only loot if the player is the loot roundrobin player
18586 // or if there are free/quest/conditional item for the player
18587 if (loot->roundRobinPlayer.IsEmpty() || loot->roundRobinPlayer == GetGUID())
18588 return true;
18589
18590 return loot->hasItemFor(this);
18591 case MASTER_LOOT:
18592 case GROUP_LOOT:
18593 case NEED_BEFORE_GREED:
18594 // may only loot if the player is the loot roundrobin player
18595 // or item over threshold (so roll(s) can be launched or to preview master looted items)
18596 // or if there are free/quest/conditional item for the player
18597 if (loot->roundRobinPlayer.IsEmpty() || loot->roundRobinPlayer == GetGUID())
18598 return true;
18599
18600 if (loot->hasOverThresholdItem())
18601 return true;
18602
18603 return loot->hasItemFor(this);
18604 }
18605
18606 return false;
18607}
18608
18610{
18611 m_actionButtons.clear();
18612
18613 if (result)
18614 {
18615 do
18616 {
18617 Field* fields = result->Fetch();
18618 uint8 button = fields[0].GetUInt8();
18619 uint64 action = fields[1].GetUInt64();
18620 uint8 type = fields[2].GetUInt8();
18621
18622 if (ActionButton* ab = AddActionButton(button, action, type))
18623 ab->uState = ACTIONBUTTON_UNCHANGED;
18624 else
18625 {
18626 TC_LOG_DEBUG("entities.player", "Player::_LoadActions: Player '{}' ({}) has an invalid action button (Button: {}, Action: {}, Type: {}). It will be deleted at next save. This can be due to a player changing their talents.",
18627 GetName(), GetGUID().ToString(), button, action, type);
18628
18629 // Will be deleted in DB at next save (it can create data until save but marked as deleted).
18630 m_actionButtons[button].uState = ACTIONBUTTON_DELETED;
18631 }
18632 } while (result->NextRow());
18633 }
18634}
18635
18637{
18638 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadAuras: Loading auras for {}", GetGUID().ToString());
18639
18640 /*
18641 0 1 2 3 4 5 6
18642 SELECT casterGuid, itemGuid, spell, effectMask, effectIndex, amount, baseAmount FROM character_aura_effect WHERE guid = ?
18643 */
18644
18645 ObjectGuid casterGuid, itemGuid;
18646 std::map<AuraKey, AuraLoadEffectInfo> effectInfo;
18647 if (effectResult)
18648 {
18649 do
18650 {
18651 Field* fields = effectResult->Fetch();
18652 uint32 effectIndex = fields[4].GetUInt8();
18653 if (effectIndex < MAX_SPELL_EFFECTS)
18654 {
18655 casterGuid.SetRawValue(fields[0].GetBinary());
18656 itemGuid.SetRawValue(fields[1].GetBinary());
18657 AuraKey key{ casterGuid, itemGuid, fields[2].GetUInt32(), fields[3].GetUInt32() };
18658 AuraLoadEffectInfo& info = effectInfo[key];
18659 info.Amounts[effectIndex] = fields[5].GetInt32();
18660 info.BaseAmounts[effectIndex] = fields[6].GetInt32();
18661 }
18662 }
18663 while (effectResult->NextRow());
18664 }
18665
18666 /*
18667 0 1 2 3 4 5 6 7 8 9 10 11
18668 SELECT casterGuid, itemGuid, spell, effectMask, recalculateMask, difficulty, stackCount, maxDuration, remainTime, remainCharges, castItemId, castItemLevel FROM character_aura WHERE guid = ?
18669 */
18670 if (auraResult)
18671 {
18672 do
18673 {
18674 Field* fields = auraResult->Fetch();
18675 casterGuid.SetRawValue(fields[0].GetBinary());
18676 itemGuid.SetRawValue(fields[1].GetBinary());
18677 AuraKey key{ casterGuid, itemGuid, fields[2].GetUInt32(), fields[3].GetUInt32() };
18678 uint32 recalculateMask = fields[4].GetUInt32();
18679 Difficulty difficulty = Difficulty(fields[5].GetUInt8());
18680 uint8 stackCount = fields[6].GetUInt8();
18681 int32 maxDuration = fields[7].GetInt32();
18682 int32 remainTime = fields[8].GetInt32();
18683 uint8 remainCharges = fields[9].GetUInt8();
18684 uint32 castItemId = fields[10].GetUInt32();
18685 int32 castItemLevel = fields[11].GetInt32();
18686
18687 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(key.SpellId, difficulty);
18688 if (!spellInfo)
18689 {
18690 TC_LOG_ERROR("entities.player", "Player::_LoadAuras: Player '{}' ({}) has an invalid aura (SpellID: {}), ignoring.",
18691 GetName(), GetGUID().ToString(), key.SpellId);
18692 continue;
18693 }
18694
18695 if (difficulty != DIFFICULTY_NONE && !sDifficultyStore.LookupEntry(difficulty))
18696 {
18697 TC_LOG_ERROR("entities.player", "Player::_LoadAuras: Player '{}' ({}) has an invalid aura difficulty {} (SpellID: {}), ignoring.",
18698 GetName(), GetGUID().ToString(), uint32(difficulty), key.SpellId);
18699 continue;
18700 }
18701
18702 // negative effects should continue counting down after logout
18703 if (remainTime != -1 && (!spellInfo->IsPositive() || spellInfo->HasAttribute(SPELL_ATTR4_AURA_EXPIRES_OFFLINE)))
18704 {
18705 if (remainTime/IN_MILLISECONDS <= int32(timediff))
18706 continue;
18707
18708 remainTime -= timediff*IN_MILLISECONDS;
18709 }
18710
18711 // prevent wrong values of remainCharges
18712 if (spellInfo->ProcCharges)
18713 {
18714 // we have no control over the order of applying auras and modifiers allow auras
18715 // to have more charges than value in SpellInfo
18716 if (remainCharges <= 0/* || remainCharges > spellproto->procCharges*/)
18717 remainCharges = spellInfo->ProcCharges;
18718 }
18719 else
18720 remainCharges = 0;
18721
18722 AuraLoadEffectInfo& info = effectInfo[key];
18723 ObjectGuid castId = ObjectGuid::Create<HighGuid::Cast>(SPELL_CAST_SOURCE_NORMAL, GetMapId(), spellInfo->Id, GetMap()->GenerateLowGuid<HighGuid::Cast>());
18724 AuraCreateInfo createInfo(castId, spellInfo, difficulty, key.EffectMask, this);
18725 createInfo
18726 .SetCasterGUID(casterGuid)
18727 .SetBaseAmount(info.BaseAmounts.data())
18728 .SetCastItem(itemGuid, castItemId, castItemLevel);
18729
18730 if (Aura* aura = Aura::TryCreate(createInfo))
18731 {
18732 if (!aura->CanBeSaved())
18733 {
18734 aura->Remove();
18735 continue;
18736 }
18737
18738 aura->SetLoadedState(maxDuration, remainTime, remainCharges, stackCount, recalculateMask, info.Amounts.data());
18739 aura->ApplyForTargets();
18740 TC_LOG_DEBUG("entities.player", "Player::_LoadAuras: Added aura (SpellID: {}, EffectMask: {}) to player '{} ({})",
18741 spellInfo->Id, key.EffectMask, GetName(), GetGUID().ToString());
18742 }
18743 }
18744 while (auraResult->NextRow());
18745 }
18746}
18747
18749{
18750 for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup()))
18751 CastSpell(this, sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID, true);
18752}
18753
18755{
18757 SpawnCorpseBones(false);
18758
18759 if (!IsAlive())
18760 {
18762 ResurrectPlayer(0.5f);
18763 else if (result)
18764 {
18765 Field* fields = result->Fetch();
18766 _corpseLocation.WorldRelocate(fields[0].GetUInt16(), fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat());
18767 if (!sMapStore.AssertEntry(_corpseLocation.GetMapId())->Instanceable())
18769 else
18771 }
18772 }
18773
18775}
18776
18778 PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult,
18779 PreparedQueryResult azeriteEmpoweredItemResult, uint32 timeDiff)
18780{
18781 // 0 1 2 3 4 5 6 7 8 9 10 11 12
18782 // SELECT guid, itemEntry, creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text,
18783 // 13 14 15 16 17 18
18784 // battlePetSpeciesId, battlePetBreedData, battlePetLevel, battlePetDisplayId, context, bonusListIDs,
18785 // 19 20 21 22 23
18786 // itemModifiedAppearanceAllSpecs, itemModifiedAppearanceSpec1, itemModifiedAppearanceSpec2, itemModifiedAppearanceSpec3, itemModifiedAppearanceSpec4,
18787 // 24 25 26 27 28
18788 // spellItemEnchantmentAllSpecs, spellItemEnchantmentSpec1, spellItemEnchantmentSpec2, spellItemEnchantmentSpec3, spellItemEnchantmentSpec4,
18789 // 29 30 31 32 33 34 35 36 37 38 39 40
18790 // gemItemId1, gemBonuses1, gemContext1, gemScalingLevel1, gemItemId2, gemBonuses2, gemContext2, gemScalingLevel2, gemItemId3, gemBonuses3, gemContext3, gemScalingLevel3
18791 // 41 42
18792 // fixedScalingLevel, artifactKnowledgeLevel FROM item_instance
18793 // 43 44
18794 // bag, slot
18795 // FROM character_inventory ci
18796 // JOIN item_instance ii ON ci.item = ii.guid
18797 // LEFT JOIN item_instance_gems ig ON ii.guid = ig.itemGuid
18798 // LEFT JOIN item_instance_transmog iit ON ii.guid = iit.itemGuid
18799 // LEFT JOIN item_instance_modifiers im ON ii.guid = im.itemGuid
18800 // WHERE ci.guid = ?
18801 // ORDER BY (ii.flags & 0x80000) ASC, bag ASC, slot ASC
18802
18803 //NOTE: ORDER BY ii.flags & 0x80000 makes child items load last - they need their parents to be already loaded
18804 //NOTE: the "order by `bag`" is important because it makes sure
18805 //the bagMap is filled before items in the bags are loaded
18806 //NOTE2: the "order by `slot`" is needed because mainhand weapons are (wrongly?)
18807 //expected to be equipped before offhand items (@todo fixme)
18808
18809 std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo> additionalData;
18810 ItemAdditionalLoadInfo::Init(&additionalData, artifactsResult, azeriteResult, azeriteItemMilestonePowersResult,
18811 azeriteItemUnlockedEssencesResult, azeriteEmpoweredItemResult);
18812
18813 if (result)
18814 {
18815 uint32 zoneId = GetZoneId();
18816
18817 std::map<ObjectGuid, Bag*> bagMap; // fast guid lookup for bags
18818 std::map<ObjectGuid, Item*> invalidBagMap; // fast guid lookup for bags
18819 std::list<Item*> problematicItems;
18820 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
18821
18822 // Prevent items from being added to the queue while loading
18824 do
18825 {
18826 Field* fields = result->Fetch();
18827 if (Item* item = _LoadItem(trans, zoneId, timeDiff, fields))
18828 {
18829 if (ItemAdditionalLoadInfo* addionalDataPtr = Trinity::Containers::MapGetValuePtr(additionalData, fields[0].GetUInt64()))
18830 {
18831 if (item->GetTemplate()->GetArtifactID() && addionalDataPtr->Artifact)
18832 item->LoadArtifactData(this, addionalDataPtr->Artifact->Xp, addionalDataPtr->Artifact->ArtifactAppearanceId,
18833 addionalDataPtr->Artifact->ArtifactTierId, addionalDataPtr->Artifact->ArtifactPowers);
18834
18835 if (addionalDataPtr->AzeriteItem)
18836 if (AzeriteItem* azeriteItem = item->ToAzeriteItem())
18837 azeriteItem->LoadAzeriteItemData(this, *addionalDataPtr->AzeriteItem);
18838
18839 if (addionalDataPtr->AzeriteEmpoweredItem)
18840 if (AzeriteEmpoweredItem* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem())
18841 azeriteEmpoweredItem->LoadAzeriteEmpoweredItemData(this, *addionalDataPtr->AzeriteEmpoweredItem);
18842 }
18843
18844 ObjectGuid bagGuid = fields[51].GetUInt64() ? ObjectGuid::Create<HighGuid::Item>(fields[51].GetUInt64()) : ObjectGuid::Empty;
18845 uint8 slot = fields[52].GetUInt8();
18846
18849
18851 if (item->HasItemFlag(ITEM_FIELD_FLAG_CHILD))
18852 {
18853 if (Item* parent = GetItemByGuid(item->GetCreator()))
18854 {
18855 parent->SetChildItem(item->GetGUID());
18856 item->CopyArtifactDataFromParent(parent);
18857 }
18858 else
18859 {
18860 TC_LOG_ERROR("entities.player", "Player::_LoadInventory: Player '{}' ({}) has child item ({}, entry: {}) which can't be loaded into inventory because parent item was not found (Bag {}, slot: {}). Item will be sent by mail.",
18861 GetName(), GetGUID().ToString(), item->GetGUID().ToString(), item->GetEntry(), bagGuid.ToString(), slot);
18862 item->DeleteFromInventoryDB(trans);
18863 problematicItems.push_back(item);
18864 continue;
18865 }
18866 }
18867
18868 // Item is not in bag
18869 if (!bagGuid)
18870 {
18871 item->SetContainer(nullptr);
18872 item->SetSlot(slot);
18873
18875 {
18876 ItemPosCountVec dest;
18877 err = CanStoreItem(INVENTORY_SLOT_BAG_0, slot, dest, item, false);
18878 if (err == EQUIP_ERR_OK)
18879 item = StoreItem(dest, item, true);
18880 }
18881 else if (IsEquipmentPos(INVENTORY_SLOT_BAG_0, slot))
18882 {
18883 uint16 dest;
18884 err = CanEquipItem(slot, dest, item, false, false);
18885 if (err == EQUIP_ERR_OK)
18886 QuickEquipItem(dest, item);
18887 }
18888 else if (IsBankPos(INVENTORY_SLOT_BAG_0, slot))
18889 {
18890 ItemPosCountVec dest;
18891 err = CanBankItem(INVENTORY_SLOT_BAG_0, slot, dest, item, false, false);
18892 if (err == EQUIP_ERR_OK)
18893 item = BankItem(dest, item, true);
18894 }
18895
18896 // Remember bags that may contain items in them
18897 if (err == EQUIP_ERR_OK)
18898 {
18899 if (IsBagPos(item->GetPos()))
18900 if (Bag* pBag = item->ToBag())
18901 bagMap[item->GetGUID()] = pBag;
18902 }
18903 else
18904 if (IsBagPos(item->GetPos()))
18905 if (item->IsBag())
18906 invalidBagMap[item->GetGUID()] = item;
18907 }
18908 else
18909 {
18910 item->SetSlot(NULL_SLOT);
18911 // Item is in the bag, find the bag
18912 std::map<ObjectGuid, Bag*>::iterator itr = bagMap.find(bagGuid);
18913 if (itr != bagMap.end())
18914 {
18915 ItemPosCountVec dest;
18916 err = CanStoreItem(itr->second->GetSlot(), slot, dest, item);
18917 if (err == EQUIP_ERR_OK)
18918 item = StoreItem(dest, item, true);
18919 }
18920 else if (invalidBagMap.find(bagGuid) != invalidBagMap.end())
18921 {
18922 std::map<ObjectGuid, Item*>::iterator invalidBagItr = invalidBagMap.find(bagGuid);
18923 if (std::find(problematicItems.begin(), problematicItems.end(), invalidBagItr->second) != problematicItems.end())
18925 }
18926 else
18927 {
18928 TC_LOG_ERROR("entities.player", "Player::_LoadInventory: Player '{}' ({}) has item ({}, entry: {}) which doesnt have a valid bag (Bag {}, slot: {}). Possible cheat?",
18929 GetName(), GetGUID().ToString(), item->GetGUID().ToString(), item->GetEntry(), bagGuid.ToString(), slot);
18930 item->DeleteFromInventoryDB(trans);
18931 delete item;
18932 continue;
18933 }
18934 }
18935
18936 // Item's state may have changed after storing
18937 if (err == EQUIP_ERR_OK)
18938 item->SetState(ITEM_UNCHANGED, this);
18939 else
18940 {
18941 TC_LOG_ERROR("entities.player", "Player::_LoadInventory: Player '{}' ({}) has item ({}, entry: {}) which can't be loaded into inventory (Bag {}, slot: {}) by reason {}. Item will be sent by mail.",
18942 GetName(), GetGUID().ToString(), item->GetGUID().ToString(), item->GetEntry(), bagGuid.ToString(), slot, uint32(err));
18943 item->DeleteFromInventoryDB(trans);
18944 problematicItems.push_back(item);
18945 }
18946 }
18947 } while (result->NextRow());
18948
18950
18951 // Send problematic items by mail
18952 while (!problematicItems.empty())
18953 {
18954 std::string subject = GetSession()->GetTrinityString(LANG_NOT_EQUIPPED_ITEM);
18955
18956 MailDraft draft(subject, "There were problems with equipping item(s).");
18957 for (uint8 i = 0; !problematicItems.empty() && i < MAX_MAIL_ITEMS; ++i)
18958 {
18959 draft.AddItem(problematicItems.front());
18960 problematicItems.pop_front();
18961 }
18963 }
18964
18965 CharacterDatabase.CommitTransaction(trans);
18966 }
18967 //if (IsAlive())
18969 // Apply all azerite item mods, azerite empowered item mods will get applied through its spell script
18971}
18972
18974{
18975 if (!result)
18976 return;
18977
18978 do
18979 {
18980 // SELECT itemId, itemEntry, slot, creatorGuid, randomBonusListId, fixedScalingLevel, artifactKnowledgeLevel, context, bonusListIDs FROM character_void_storage WHERE playerGuid = ?
18981 Field* fields = result->Fetch();
18982
18983 uint64 itemId = fields[0].GetUInt64();
18984 uint32 itemEntry = fields[1].GetUInt32();
18985 uint8 slot = fields[2].GetUInt8();
18986 ObjectGuid creatorGuid = fields[3].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[3].GetUInt64()) : ObjectGuid::Empty;
18987 ItemRandomBonusListId randomBonusListId = fields[4].GetUInt32();
18988 uint32 fixedScalingLevel = fields[5].GetUInt32();
18989 uint32 artifactKnowledgeLevel = fields[6].GetUInt32();
18990 ItemContext context = ItemContext(fields[7].GetUInt8());
18991 std::vector<int32> bonusListIDs;
18992 for (std::string_view bonusListIDtoken : Trinity::Tokenize(fields[8].GetStringView(), ' ', false))
18993 if (Optional<int32> bonusListID = Trinity::StringTo<int32>(bonusListIDtoken))
18994 bonusListIDs.push_back(*bonusListID);
18995
18996 if (!itemId)
18997 {
18998 TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '{}' ({}) has an item with an invalid id (item id: {}, entry: {}).",
18999 GetName(), GetGUID().ToString(), itemId, itemEntry);
19000 continue;
19001 }
19002
19003 if (!sObjectMgr->GetItemTemplate(itemEntry))
19004 {
19005 TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '{}' ({}) has an item with an invalid entry (item id: {}, entry: {}).",
19006 GetName(), GetGUID().ToString(), itemId, itemEntry);
19007 continue;
19008 }
19009
19010 if (slot >= VOID_STORAGE_MAX_SLOT)
19011 {
19012 TC_LOG_ERROR("entities.player", "Player::_LoadVoidStorage: Player '{}' ({}) has an item with an invalid slot (item id: {}, entry: {}, slot: {}).",
19013 GetName(), GetGUID().ToString(), itemId, itemEntry, slot);
19014 continue;
19015 }
19016
19017 _voidStorageItems[slot] = new VoidStorageItem(itemId, itemEntry, creatorGuid, randomBonusListId, fixedScalingLevel, artifactKnowledgeLevel,
19018 context, bonusListIDs);
19019
19021 voidInstance.Initialize(_voidStorageItems[slot]);
19022 BonusData bonus;
19023 bonus.Initialize(voidInstance);
19024
19026 }
19027 while (result->NextRow());
19028}
19029
19031{
19032 Item* item = nullptr;
19033 ObjectGuid::LowType itemGuid = fields[0].GetUInt64();
19034 uint32 itemEntry = fields[1].GetUInt32();
19035 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry))
19036 {
19037 bool remove = false;
19038 item = NewItemOrBag(proto);
19039 if (item->LoadFromDB(itemGuid, GetGUID(), fields, itemEntry))
19040 {
19042
19043 // Do not allow to have item limited to another map/zone in alive state
19044 if (IsAlive() && item->IsLimitedToAnotherMapOrZone(GetMapId(), zoneId))
19045 {
19046 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player ({}, name: '{}', map: {}) has item ({}) limited to another map ({}). Deleting item.",
19047 GetGUID().ToString(), GetName(), GetMapId(), item->GetGUID().ToString(), zoneId);
19048 remove = true;
19049 }
19050 // "Conjured items disappear if you are logged out for more than 15 minutes"
19051 else if (timeDiff > 15 * MINUTE && proto->HasFlag(ITEM_FLAG_CONJURED))
19052 {
19053 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player ({}, name: '{}', diff: {}) has conjured item ({}) with expired lifetime (15 minutes). Deleting item.",
19054 GetGUID().ToString(), GetName(), timeDiff, item->GetGUID().ToString());
19055 remove = true;
19056 }
19057 else if (item->IsRefundable())
19058 {
19059 if (item->GetPlayedTime() > (2 * HOUR))
19060 {
19061 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadInventory: player ({}, name: '{}') has item ({}) with expired refund time ({}). Deleting refund data and removing refundable flag.",
19062 GetGUID().ToString(), GetName(), item->GetGUID().ToString(), item->GetPlayedTime());
19063
19064 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_REFUND_INSTANCE);
19065 stmt->setUInt64(0, item->GetGUID().GetCounter());
19066 trans->Append(stmt);
19067
19069 }
19070 else
19071 {
19072 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_REFUNDS);
19073 stmt->setUInt64(0, item->GetGUID().GetCounter());
19074 stmt->setUInt64(1, GetGUID().GetCounter());
19075 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
19076 {
19077 item->SetRefundRecipient(GetGUID());
19078 item->SetPaidMoney((*result)[0].GetUInt64());
19079 item->SetPaidExtendedCost((*result)[1].GetUInt16());
19080 AddRefundReference(item->GetGUID());
19081 }
19082 else
19083 {
19084 TC_LOG_WARN("entities.player.loading", "Player::_LoadInventory: player ({}, name: '{}') has item ({}) with refundable flags, but without data in item_refund_instance. Removing flag.",
19085 GetGUID().ToString(), GetName(), item->GetGUID().ToString());
19087 }
19088 }
19089 }
19090 else if (item->IsBOPTradeable())
19091 {
19092 stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_BOP_TRADE);
19093 stmt->setUInt64(0, item->GetGUID().GetCounter());
19094 if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
19095 {
19096 GuidSet looters;
19097 for (std::string_view guidStr : Trinity::Tokenize((*result)[0].GetStringView(), ' ', false))
19098 looters.insert(ObjectGuid::Create<HighGuid::Player>(Trinity::StringTo<uint64>(guidStr).value_or(UI64LIT(0))));
19099
19100 if (looters.size() > 1 && item->GetTemplate()->GetMaxStackSize() == 1 && item->IsSoulBound())
19101 {
19102 item->SetSoulboundTradeable(looters);
19103 AddTradeableItem(item);
19104 }
19105 else
19106 item->ClearSoulboundTradeable(this);
19107 }
19108 else
19109 {
19110 TC_LOG_WARN("entities.player.loading", "Player::_LoadInventory: player ({}, name: '{}') has item ({}) with ITEM_FLAG_BOP_TRADEABLE flag, but without data in item_soulbound_trade_data. Removing flag.",
19111 GetGUID().ToString(), GetName(), item->GetGUID().ToString());
19113 }
19114 }
19115 else if (proto->GetHolidayID())
19116 {
19117 remove = true;
19118 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
19119 GameEventMgr::ActiveEvents const& activeEventsList = sGameEventMgr->GetActiveEventList();
19120 for (GameEventMgr::ActiveEvents::const_iterator itr = activeEventsList.begin(); itr != activeEventsList.end(); ++itr)
19121 {
19122 if (events[*itr].holiday_id == proto->GetHolidayID())
19123 {
19124 remove = false;
19125 break;
19126 }
19127 }
19128 }
19129 }
19130 else
19131 {
19132 TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player ({}, name: '{}') has a broken item (GUID: {}, entry: {}) in inventory. Deleting item.",
19133 GetGUID().ToString(), GetName(), itemGuid, itemEntry);
19134 remove = true;
19135 }
19136 // Remove item from inventory if necessary
19137 if (remove)
19138 {
19139 Item::DeleteFromInventoryDB(trans, itemGuid);
19140 item->FSetState(ITEM_REMOVED);
19141 item->SaveToDB(trans); // it also deletes item object!
19142 item = nullptr;
19143 }
19144 }
19145 else
19146 {
19147 TC_LOG_ERROR("entities.player", "Player::_LoadInventory: player ({}, name: '{}') has an unknown item (entry: {}) in inventory. Deleting item.",
19148 GetGUID().ToString(), GetName(), itemEntry);
19149 Item::DeleteFromInventoryDB(trans, itemGuid);
19150 Item::DeleteFromDB(trans, itemGuid);
19151 AzeriteItem::DeleteFromDB(trans, itemGuid);
19152 AzeriteEmpoweredItem::DeleteFromDB(trans, itemGuid);
19153 }
19154 return item;
19155}
19156
19157// load mailed item which should receive current player
19158Item* Player::_LoadMailedItem(ObjectGuid const& playerGuid, Player* player, uint64 mailId, Mail* mail, Field* fields, ItemAdditionalLoadInfo* addionalData)
19159{
19160 ObjectGuid::LowType itemGuid = fields[0].GetUInt64();
19161 uint32 itemEntry = fields[1].GetUInt32();
19162
19163 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemEntry);
19164 if (!proto)
19165 {
19166 TC_LOG_ERROR("entities.player", "Player '{}' ({}) has unknown item in mailed items (GUID: {}, Entry: {}) in mail ({}), deleted.",
19167 player ? player->GetName() : "<unknown>", playerGuid.ToString(), itemGuid, itemEntry, mailId);
19168
19169 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
19170
19172 stmt->setUInt64(0, itemGuid);
19173 trans->Append(stmt);
19174
19175 Item::DeleteFromDB(trans, itemGuid);
19176 AzeriteItem::DeleteFromDB(trans, itemGuid);
19177 AzeriteEmpoweredItem::DeleteFromDB(trans, itemGuid);
19178
19179 CharacterDatabase.CommitTransaction(trans);
19180 return nullptr;
19181 }
19182
19183 Item* item = NewItemOrBag(proto);
19184
19185 ObjectGuid ownerGuid = fields[51].GetUInt64() ? ObjectGuid::Create<HighGuid::Player>(fields[51].GetUInt64()) : ObjectGuid::Empty;
19186 if (!item->LoadFromDB(itemGuid, ownerGuid, fields, itemEntry))
19187 {
19188 TC_LOG_ERROR("entities.player", "Player::_LoadMailedItems: Item (GUID: {}) in mail ({}) doesn't exist, deleted from mail.", itemGuid, mailId);
19189
19191 stmt->setUInt64(0, itemGuid);
19192 CharacterDatabase.Execute(stmt);
19193
19194 item->FSetState(ITEM_REMOVED);
19195
19197 item->SaveToDB(temp); // it also deletes item object !
19198 return nullptr;
19199 }
19200
19201 if (addionalData)
19202 {
19203 if (item->GetTemplate()->GetArtifactID() && addionalData->Artifact)
19204 item->LoadArtifactData(player, addionalData->Artifact->Xp, addionalData->Artifact->ArtifactAppearanceId,
19205 addionalData->Artifact->ArtifactTierId, addionalData->Artifact->ArtifactPowers);
19206
19207 if (addionalData->AzeriteItem)
19208 if (AzeriteItem* azeriteItem = item->ToAzeriteItem())
19209 azeriteItem->LoadAzeriteItemData(player, *addionalData->AzeriteItem);
19210
19211 if (addionalData->AzeriteEmpoweredItem)
19212 if (AzeriteEmpoweredItem* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem())
19213 azeriteEmpoweredItem->LoadAzeriteEmpoweredItemData(player, *addionalData->AzeriteEmpoweredItem);
19214 }
19215
19216 if (mail)
19217 mail->AddItem(itemGuid, itemEntry);
19218
19219 if (player)
19220 player->AddMItem(item);
19221
19222 return item;
19223}
19224
19225void Player::_LoadMail(PreparedQueryResult mailsResult, PreparedQueryResult mailItemsResult, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult,
19226 PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult)
19227{
19228 std::unordered_map<uint64, Mail*> mailById;
19229
19230 if (mailsResult)
19231 {
19232 do
19233 {
19234 Field* fields = mailsResult->Fetch();
19235 Mail* m = new Mail();
19236
19237 m->messageID = fields[0].GetUInt64();
19238 m->messageType = fields[1].GetUInt8();
19239 m->sender = fields[2].GetUInt64();
19240 m->receiver = fields[3].GetUInt64();
19241 m->subject = fields[4].GetString();
19242 m->body = fields[5].GetString();
19243 m->expire_time = fields[6].GetInt64();
19244 m->deliver_time = fields[7].GetInt64();
19245 m->money = fields[8].GetUInt64();
19246 m->COD = fields[9].GetUInt64();
19247 m->checked = fields[10].GetUInt8();
19248 m->stationery = fields[11].GetUInt8();
19249 m->mailTemplateId = fields[12].GetInt16();
19250
19251 if (m->mailTemplateId && !sMailTemplateStore.LookupEntry(m->mailTemplateId))
19252 {
19253 TC_LOG_ERROR("entities.player", "Player::_LoadMail: Mail ({}) has nonexistent MailTemplateId ({}), remove at load", m->messageID, m->mailTemplateId);
19254 m->mailTemplateId = 0;
19255 }
19256
19258
19259 m_mail.push_back(m);
19260 mailById[m->messageID] = m;
19261 }
19262 while (mailsResult->NextRow());
19263 }
19264
19265 if (mailItemsResult)
19266 {
19267 std::unordered_map<ObjectGuid::LowType, ItemAdditionalLoadInfo> additionalData;
19268 ItemAdditionalLoadInfo::Init(&additionalData, artifactResult, azeriteItemResult, azeriteItemMilestonePowersResult,
19269 azeriteItemUnlockedEssencesResult, azeriteEmpoweredItemResult);
19270
19271 do
19272 {
19273 Field* fields = mailItemsResult->Fetch();
19274 uint64 mailId = fields[52].GetUInt64();
19275 _LoadMailedItem(GetGUID(), this, mailId, mailById[mailId], fields, Trinity::Containers::MapGetValuePtr(additionalData, fields[0].GetUInt64()));
19276 } while (mailItemsResult->NextRow());
19277 }
19278
19280}
19281
19283{
19284 uint16 slot = 0;
19285
19287 //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, status, explored, acceptTime, endTime WHERE guid = '{}' AND status <> 0", GetGUIDLow());
19288
19289 time_t lastDailyReset = sWorld->GetNextDailyQuestsResetTime() - DAY;
19290 time_t lastWeeklyReset = sWorld->GetNextWeeklyQuestsResetTime() - WEEK;
19291
19292 if (result)
19293 {
19294 do
19295 {
19296 Field* fields = result->Fetch();
19297
19298 uint32 quest_id = fields[0].GetUInt32();
19299 // used to be new, no delete?
19300 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
19301 if (!quest)
19302 continue;
19303
19304 // find or create
19305 QuestStatusData questStatusData;
19306
19307 uint8 qstatus = fields[1].GetUInt8();
19308 if (qstatus < MAX_QUEST_STATUS)
19309 questStatusData.Status = QuestStatus(qstatus);
19310 else
19311 {
19312 questStatusData.Status = QUEST_STATUS_INCOMPLETE;
19313 TC_LOG_ERROR("entities.player", "Player::_LoadQuestStatus: Player '{}' ({}) has invalid quest {} status ({}), replaced by QUEST_STATUS_INCOMPLETE(3).",
19314 GetName(), GetGUID().ToString(), quest_id, qstatus);
19315 }
19316
19317 questStatusData.Explored = (fields[2].GetUInt8() > 0);
19318
19319 questStatusData.AcceptTime = time_t(fields[3].GetInt64());
19321 {
19322 if ((quest->IsDaily() && questStatusData.AcceptTime < lastDailyReset)
19323 || (quest->IsWeekly() && questStatusData.AcceptTime < lastWeeklyReset))
19324 {
19325 questStatusData.Status = QUEST_STATUS_NONE;
19328 }
19329 }
19330
19331 time_t endTime = time_t(fields[4].GetInt64());
19332
19333 if (quest->GetLimitTime() && !GetQuestRewardStatus(quest_id))
19334 {
19335 AddTimedQuest(quest_id);
19336
19337 if (endTime <= GameTime::GetGameTime())
19338 questStatusData.Timer = 1;
19339 else
19340 questStatusData.Timer = uint32((endTime - GameTime::GetGameTime()) * IN_MILLISECONDS);
19341 }
19342 else
19343 endTime = 0;
19344
19345 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadQuestStatus: Quest status is {{{}}} for quest {{{}}} for player ({})", questStatusData.Status, quest_id, GetGUID().ToString());
19346
19347 // add to quest log
19348 if (slot < MAX_QUEST_LOG_SIZE && questStatusData.Status != QUEST_STATUS_NONE)
19349 {
19350 questStatusData.Slot = slot;
19351
19352 auto questStatusItr = m_QuestStatus.emplace(quest_id, std::move(questStatusData)).first;
19353 for (QuestObjective const& obj : quest->GetObjectives())
19354 m_questObjectiveStatus.emplace(std::make_pair(QuestObjectiveType(obj.Type), obj.ObjectID), QuestObjectiveStatusData{ questStatusItr, obj.ID });
19355
19356 SetQuestSlot(slot, quest_id);
19357 SetQuestSlotEndTime(slot, endTime);
19358
19359 if (questStatusItr->second.Status == QUEST_STATUS_COMPLETE)
19361 else if (questStatusItr->second.Status == QUEST_STATUS_FAILED)
19363
19365 CastSpell(this, quest->GetSrcSpell(), TRIGGERED_FULL_MASK);
19366
19367 ++slot;
19368 }
19369 }
19370 while (result->NextRow());
19371 }
19372
19373 // clear quest log tail
19374 for (uint16 i = slot; i < MAX_QUEST_LOG_SIZE; ++i)
19375 SetQuestSlot(i, 0);
19376}
19377
19379{
19380
19382 //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, objective, data WHERE guid = '{}'", GetGUIDLow());
19383
19384 if (result)
19385 {
19386 do
19387 {
19388 Field* fields = result->Fetch();
19389
19390 uint32 questID = fields[0].GetUInt32();
19391 Quest const* quest = sObjectMgr->GetQuestTemplate(questID);
19392 auto itr = m_QuestStatus.find(questID);
19393 if (itr != m_QuestStatus.end() && itr->second.Slot < MAX_QUEST_LOG_SIZE && quest)
19394 {
19395 QuestStatusData& questStatusData = itr->second;
19396 uint8 storageIndex = fields[1].GetUInt8();
19397 auto objectiveItr = std::find_if(quest->Objectives.begin(), quest->Objectives.end(), [=](QuestObjective const& objective) { return uint8(objective.StorageIndex) == storageIndex; });
19398 if (objectiveItr != quest->Objectives.end())
19399 {
19400 int32 data = fields[2].GetInt32();
19401 if (!objectiveItr->IsStoringFlag())
19402 SetQuestSlotCounter(questStatusData.Slot, storageIndex, data);
19403 else if (data)
19404 SetQuestSlotObjectiveFlag(questStatusData.Slot, storageIndex);
19405 }
19406 else
19407 TC_LOG_ERROR("entities.player", "Player::_LoadQuestStatusObjectives: Player '{}' ({}) has quest {} out of range objective index {}.", GetName(), GetGUID().ToString(), questID, storageIndex);
19408 }
19409 else
19410 TC_LOG_ERROR("entities.player", "Player::_LoadQuestStatusObjectives: Player {} ({}) does not have quest {} but has objective data for it.", GetName(), GetGUID().ToString(), questID);
19411 }
19412 while (result->NextRow());
19413 }
19414}
19415
19417{
19418 // SELECT quest FROM character_queststatus_rewarded WHERE guid = ?
19419
19420 if (result)
19421 {
19422 do
19423 {
19424 Field* fields = result->Fetch();
19425
19426 uint32 quest_id = fields[0].GetUInt32();
19427 // used to be new, no delete?
19428 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
19429 if (quest)
19430 {
19431 // learn rewarded spell if unknown
19433
19434 // set rewarded title if any
19435 if (quest->GetRewTitle())
19436 if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(quest->GetRewTitle()))
19437 SetTitle(titleEntry);
19438
19439 // Skip loading special quests - they are also added to rewarded quests but only once and remain there forever
19440 // instead add them separately from load daily/weekly/monthly/seasonal
19441 if (!quest->IsDailyOrWeekly() && !quest->IsMonthly() && !quest->IsSeasonal())
19442 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
19443 SetQuestCompletedBit(questBit, true);
19444
19445 for (uint32 i = 0; i < quest->GetRewChoiceItemsCount(); ++i)
19447
19448 for (uint32 i = 0; i < quest->GetRewItemsCount(); ++i)
19450
19451 if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID()))
19452 for (QuestPackageItemEntry const* questPackageItem : *questPackageItems)
19453 if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID))
19454 if (rewardProto->ItemSpecClassMask & GetClassMask())
19455 GetSession()->GetCollectionMgr()->AddItemAppearance(questPackageItem->ItemID);
19456
19458 m_RewardedQuests.insert(quest_id);
19459 }
19460 }
19461 while (result->NextRow());
19462 }
19463}
19464
19466{
19467 m_DFQuests.clear();
19468
19469 //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, time FROM character_queststatus_daily WHERE guid = '{}'", GetGUIDLow());
19470
19471 if (result)
19472 {
19473 do
19474 {
19475 Field* fields = result->Fetch();
19476 uint32 quest_id = fields[0].GetUInt32();
19477 if (Quest const* qQuest = sObjectMgr->GetQuestTemplate(quest_id))
19478 {
19479 if (qQuest->IsDFQuest())
19480 {
19481 m_DFQuests.insert(qQuest->GetQuestId());
19482 m_lastDailyQuestTime = fields[1].GetInt64();
19483 continue;
19484 }
19485 }
19486
19487 // save _any_ from daily quest times (it must be after last reset anyway)
19488 m_lastDailyQuestTime = fields[1].GetInt64();
19489
19490 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
19491 if (!quest)
19492 continue;
19493
19495 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
19496 SetQuestCompletedBit(questBit, true);
19497
19498 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadDailyQuestStatus: Loaded daily quest cooldown (QuestID: {}) for player '{}' ({})",
19499 quest_id, GetName(), GetGUID().ToString());
19500 }
19501 while (result->NextRow());
19502 }
19503
19504 m_DailyQuestChanged = false;
19505}
19506
19508{
19509 m_weeklyquests.clear();
19510
19511 if (result)
19512 {
19513 do
19514 {
19515 Field* fields = result->Fetch();
19516 uint32 quest_id = fields[0].GetUInt32();
19517 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
19518 if (!quest)
19519 continue;
19520
19521 m_weeklyquests.insert(quest_id);
19522 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
19523 SetQuestCompletedBit(questBit, true);
19524
19525 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadWeeklyQuestStatus: Loaded weekly quest cooldown (QuestID: {}) for player '{}' ({})",
19526 quest_id, GetName(), GetGUID().ToString());
19527 }
19528 while (result->NextRow());
19529 }
19530
19531 m_WeeklyQuestChanged = false;
19532}
19533
19535{
19536 m_seasonalquests.clear();
19537
19538 if (result)
19539 {
19540 do
19541 {
19542 Field* fields = result->Fetch();
19543 uint32 quest_id = fields[0].GetUInt32();
19544 uint32 event_id = fields[1].GetUInt32();
19545 uint32 completedTime = fields[2].GetInt64();
19546 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
19547 if (!quest)
19548 continue;
19549
19550 m_seasonalquests[event_id][quest_id] = completedTime;
19551 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
19552 SetQuestCompletedBit(questBit, true);
19553
19554 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadSeasonalQuestStatus: Loaded seasonal quest cooldown (QuestID: {}) for player '{}' ({})",
19555 quest_id, GetName(), GetGUID().ToString());
19556 }
19557 while (result->NextRow());
19558 }
19559
19560 m_SeasonalQuestChanged = false;
19561}
19562
19564{
19565 m_monthlyquests.clear();
19566
19567 if (result)
19568 {
19569 do
19570 {
19571 Field* fields = result->Fetch();
19572 uint32 quest_id = fields[0].GetUInt32();
19573 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
19574 if (!quest)
19575 continue;
19576
19577 m_monthlyquests.insert(quest_id);
19578 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(quest_id))
19579 SetQuestCompletedBit(questBit, true);
19580
19581 TC_LOG_DEBUG("entities.player.loading", "Player::_LoadMonthlyQuestStatus: Loaded monthly quest cooldown (QuestID: {}) for player '{}' ({})",
19582 quest_id, GetName(), GetGUID().ToString());
19583 }
19584 while (result->NextRow());
19585 }
19586
19587 m_MonthlyQuestChanged = false;
19588}
19589
19591{
19592 //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, active, disabled, favorite FROM character_spell WHERE guid = '{}'", GetGUIDLow());
19593 if (result)
19594 {
19595 do
19596 AddSpell((*result)[0].GetUInt32(), (*result)[1].GetBool(), false, false, (*result)[2].GetBool(), true);
19597 while (result->NextRow());
19598 }
19599
19600 if (favoritesResult)
19601 {
19602 do
19603 {
19604 auto itr = m_spells.find((*favoritesResult)[0].GetUInt32());
19605 if (itr != m_spells.end())
19606 itr->second.favorite = true;
19607 } while (favoritesResult->NextRow());
19608 }
19609}
19610
19612{
19613 // 0 1 2 3 4 5
19614 //QueryResult* result = CharacterDatabase.PQuery("SELECT Spell, MapId, PositionX, PositionY, PositionZ, Orientation FROM character_spell_location WHERE Guid = ?", GetGUIDLow());
19615
19617 if (result)
19618 {
19619 do
19620 {
19621 Field* fields = result->Fetch();
19622 uint32 spellId = fields[0].GetUInt32();
19623
19624 if (!sSpellMgr->GetSpellInfo(spellId, DIFFICULTY_NONE))
19625 {
19626 TC_LOG_ERROR("spells", "Player::_LoadStoredAuraTeleportLocations: Player {} ({}) spell (ID: {}) does not exist",
19627 GetName(), GetGUID().ToString(), spellId);
19628 continue;
19629 }
19630
19631 WorldLocation location(fields[1].GetUInt32(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat());
19632 if (!MapManager::IsValidMapCoord(location))
19633 {
19634 TC_LOG_ERROR("spells", "Player::_LoadStoredAuraTeleportLocations: Player {} ({}) spell (ID: {}) has invalid position on map {}, {{{}}}.",
19635 GetName(), GetGUID().ToString(), spellId, location.GetMapId(), location.ToString());
19636 continue;
19637 }
19638
19640 storedLocation.Loc = location;
19642 }
19643 while (result->NextRow());
19644 }
19645}
19646
19648{
19649 //QueryResult* result = CharacterDatabase.PQuery("SELECT guid FROM group_member WHERE memberGuid={}", GetGUIDLow());
19650 if (result)
19651 {
19652 if (Group* group = sGroupMgr->GetGroupByDbStoreId((*result)[0].GetUInt32()))
19653 {
19654 if (group->IsLeader(GetGUID()))
19656
19657 uint8 subgroup = group->GetMemberGroup(GetGUID());
19658 SetGroup(group, subgroup);
19659 SetPartyType(group->GetGroupCategory(), GROUP_TYPE_NORMAL);
19661 // the group leader may change the instance difficulty while the player is offline
19662 SetDungeonDifficultyID(group->GetDungeonDifficultyID());
19663 SetRaidDifficultyID(group->GetRaidDifficultyID());
19664 SetLegacyRaidDifficultyID(group->GetLegacyRaidDifficultyID());
19665 }
19666 }
19667
19668 if (!GetGroup() || !GetGroup()->IsLeader(GetGUID()))
19670}
19671
19673{
19674 InstanceMap* map = GetMap()->ToInstanceMap();
19675 if (!map || map->GetInstanceId() != _pendingBindId)
19676 return;
19677
19678 if (!IsGameMaster())
19679 map->CreateInstanceLockForPlayer(this);
19680}
19681
19682void Player::SetPendingBind(uint32 instanceId, uint32 bindTimer)
19683{
19684 _pendingBindId = instanceId;
19685 _pendingBindTimer = bindTimer;
19686}
19687
19689{
19691
19692 std::vector<InstanceLock const*> instanceLocks = sInstanceLockMgr.GetInstanceLocksForPlayer(GetGUID());
19693
19695 instanceInfo.LockList.reserve(instanceLocks.size());
19696
19697 for (InstanceLock const* instanceLock : instanceLocks)
19698 {
19699 instanceInfo.LockList.emplace_back();
19700
19701 WorldPackets::Instance::InstanceLock& lockInfos = instanceInfo.LockList.back();
19702 lockInfos.InstanceID = instanceLock->GetInstanceId();
19703 lockInfos.MapID = instanceLock->GetMapId();
19704 lockInfos.DifficultyID = instanceLock->GetDifficultyId();
19705 lockInfos.TimeRemaining = int32(std::max(std::chrono::duration_cast<Seconds>(instanceLock->GetEffectiveExpiryTime() - now).count(), SI64LIT(0)));
19706 lockInfos.CompletedMask = instanceLock->GetData()->CompletedEncountersMask;
19707
19708 lockInfos.Locked = !instanceLock->IsExpired();
19709 lockInfos.Extended = instanceLock->IsExtended();
19710 }
19711
19712 SendDirectMessage(instanceInfo.Write());
19713}
19714
19715bool Player::Satisfy(AccessRequirement const* ar, uint32 target_map, TransferAbortParams* params, bool report)
19716{
19717 if (!IsGameMaster())
19718 {
19719 uint8 LevelMin = 0;
19720 uint8 LevelMax = 0;
19721 int32 failedMapDifficultyXCondition = 0;
19722 uint32 missingItem = 0;
19723 uint32 missingQuest = 0;
19724 uint32 missingAchievement = 0;
19725
19726 MapEntry const* mapEntry = sMapStore.LookupEntry(target_map);
19727 if (!mapEntry)
19728 return false;
19729
19730 Difficulty target_difficulty = GetDifficultyID(mapEntry);
19731 MapDifficultyEntry const* mapDiff = sDB2Manager.GetDownscaledMapDifficultyData(target_map, target_difficulty);
19732 if (!sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
19733 {
19734 if (DB2Manager::MapDifficultyConditionsContainer const* mapDifficultyConditions = sDB2Manager.GetMapDifficultyConditions(mapDiff->ID))
19735 {
19736 for (auto&& itr : *mapDifficultyConditions)
19737 {
19738 if (!ConditionMgr::IsPlayerMeetingCondition(this, itr.second))
19739 {
19740 failedMapDifficultyXCondition = itr.first;
19741 break;
19742 }
19743 }
19744 }
19745 }
19746
19747 if (ar)
19748 {
19749 if (!sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_LEVEL))
19750 {
19751 if (ar->levelMin && GetLevel() < ar->levelMin)
19752 LevelMin = ar->levelMin;
19753 if (ar->levelMax && GetLevel() > ar->levelMax)
19754 LevelMax = ar->levelMax;
19755 }
19756
19757 if (ar->item)
19758 {
19759 if (!HasItemCount(ar->item) &&
19760 (!ar->item2 || !HasItemCount(ar->item2)))
19761 missingItem = ar->item;
19762 }
19763 else if (ar->item2 && !HasItemCount(ar->item2))
19764 missingItem = ar->item2;
19765
19766 if (GetTeam() == ALLIANCE && ar->quest_A && !GetQuestRewardStatus(ar->quest_A))
19767 missingQuest = ar->quest_A;
19768 else if (GetTeam() == HORDE && ar->quest_H && !GetQuestRewardStatus(ar->quest_H))
19769 missingQuest = ar->quest_H;
19770
19771 Player* leader = this;
19772 ObjectGuid leaderGuid = GetGroup() ? GetGroup()->GetLeaderGUID() : GetGUID();
19773 if (leaderGuid != GetGUID())
19774 leader = ObjectAccessor::FindPlayer(leaderGuid);
19775
19776 if (ar->achievement)
19777 if (!leader || !leader->HasAchieved(ar->achievement))
19778 missingAchievement = ar->achievement;
19779 }
19780
19781 if (LevelMin || LevelMax || failedMapDifficultyXCondition || missingItem || missingQuest || missingAchievement)
19782 {
19783 if (params)
19784 params->Reason = TRANSFER_ABORT_ERROR;
19785
19786 if (report)
19787 {
19788 if (missingQuest && !ar->questFailedText.empty())
19790 else if (mapDiff->Message[sWorld->GetDefaultDbcLocale()][0] != '\0' || failedMapDifficultyXCondition) // if (missingAchievement) covered by this case
19791 {
19792 if (params)
19793 {
19795 params->Arg = target_difficulty;
19796 params->MapDifficultyXConditionId = failedMapDifficultyXCondition;
19797 }
19798 }
19799 else if (missingItem)
19800 GetSession()->SendNotification(GetSession()->GetTrinityString(LANG_LEVEL_MINREQUIRED_AND_ITEM), LevelMin, ASSERT_NOTNULL(sObjectMgr->GetItemTemplate(missingItem))->GetName(GetSession()->GetSessionDbcLocale()));
19801 else if (LevelMin)
19803 }
19804 return false;
19805 }
19806 }
19807 return true;
19808}
19809
19811{
19812 if (CanBeGameMaster())
19813 {
19815 return true;
19816 }
19817 else
19818 return false;
19819}
19820
19821bool Player::CheckInstanceValidity(bool /*isLogin*/)
19822{
19823 // game masters' instances are always valid
19824 if (IsGameMaster())
19825 return true;
19826
19827 // non-instances are always valid
19828 Map* map = FindMap();
19829 InstanceMap* instance = map ? map->ToInstanceMap() : nullptr;
19830 if (!instance)
19831 return true;
19832
19833 Group* group = GetGroup();
19834 // raid instances require the player to be in a raid group to be valid
19835 if (map->IsRaid() && !sWorld->getBoolConfig(CONFIG_INSTANCE_IGNORE_RAID) && (map->GetEntry()->Expansion() >= sWorld->getIntConfig(CONFIG_EXPANSION)))
19836 if (!group || !group->isRaidGroup())
19837 return false;
19838
19839 if (group)
19840 {
19841 if (group != instance->GetOwningGroup())
19842 return false;
19843 }
19844 else
19845 {
19846 // instance is invalid if we are not grouped and there are other players
19847 if (map->GetPlayersCountExceptGMs() > 1)
19848 return false;
19849 }
19850
19851 return true;
19852}
19853
19855{
19856 if (_instanceResetTimes.size() < sWorld->getIntConfig(CONFIG_MAX_INSTANCES_PER_HOUR))
19857 return true;
19858 return _instanceResetTimes.find(instanceId) != _instanceResetTimes.end();
19859}
19860
19861void Player::AddInstanceEnterTime(uint32 instanceId, time_t enterTime)
19862{
19863 if (_instanceResetTimes.find(instanceId) == _instanceResetTimes.end())
19864 _instanceResetTimes.insert(InstanceTimeMap::value_type(instanceId, enterTime + HOUR));
19865}
19866
19868{
19869 WorldSafeLocsEntry const* entranceLocation = nullptr;
19870 MapEntry const* mapEntry = sMapStore.AssertEntry(targetMapId);
19871
19872 if (mapEntry->Instanceable())
19873 {
19874 // Check if we can contact the instancescript of the instance for an updated entrance location
19875 if (uint32 targetInstanceId = sMapMgr->FindInstanceIdForPlayer(targetMapId, this))
19876 if (Map* map = sMapMgr->FindMap(targetMapId, targetInstanceId))
19877 if (InstanceMap* instanceMap = map->ToInstanceMap())
19878 if (InstanceScript* instanceScript = instanceMap->GetInstanceScript())
19879 entranceLocation = sObjectMgr->GetWorldSafeLoc(instanceScript->GetEntranceLocation());
19880
19881 // Finally check with the instancesave for an entrance location if we did not get a valid one from the instancescript
19882 if (!entranceLocation)
19883 {
19884 Group* group = GetGroup();
19885 Difficulty difficulty = group ? group->GetDifficultyID(mapEntry) : GetDifficultyID(mapEntry);
19886 ObjectGuid instanceOwnerGuid = group ? group->GetRecentInstanceOwner(targetMapId) : GetGUID();
19887 if (InstanceLock const* instanceLock = sInstanceLockMgr.FindActiveInstanceLock(instanceOwnerGuid, { mapEntry, sDB2Manager.GetDownscaledMapDifficultyData(targetMapId, difficulty) }))
19888 entranceLocation = sObjectMgr->GetWorldSafeLoc(instanceLock->GetData()->EntranceWorldSafeLocId);
19889 }
19890 }
19891 return entranceLocation;
19892}
19893
19895{
19896 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(GetRace(), GetClass());
19897 if (!info)
19898 {
19899 TC_LOG_ERROR("entities.player", "Player::_LoadHomeBind: Player '{}' ({}) has incorrect race/class ({}/{}) pair. Can't load.",
19901 return false;
19902 }
19903
19904 bool ok = false;
19905 // 0 1 2 3 4 5
19906 // SELECT mapId, zoneId, posX, posY, posZ, orientation FROM character_homebind WHERE guid = ?
19907 if (result)
19908 {
19909 Field* fields = result->Fetch();
19910
19911 m_homebind.WorldRelocate(fields[0].GetUInt16(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat(), fields[5].GetFloat());
19912 m_homebindAreaId = fields[1].GetUInt16();
19913
19914 MapEntry const* bindMapEntry = sMapStore.LookupEntry(m_homebind.GetMapId());
19915
19916 // accept saved data only for valid position (and non instanceable), and accessable
19918 !bindMapEntry->Instanceable() && GetSession()->GetExpansion() >= bindMapEntry->Expansion())
19919 ok = true;
19920 else
19921 {
19923 stmt->setUInt64(0, GetGUID().GetCounter());
19924 CharacterDatabase.Execute(stmt);
19925 }
19926 }
19927
19928 auto saveHomebindToDb = [&]()
19929 {
19931 stmt->setUInt64(0, GetGUID().GetCounter());
19932 stmt->setUInt16(1, m_homebind.GetMapId());
19933 stmt->setUInt16(2, m_homebindAreaId);
19934 stmt->setFloat(3, m_homebind.GetPositionX());
19935 stmt->setFloat(4, m_homebind.GetPositionY());
19936 stmt->setFloat(5, m_homebind.GetPositionZ());
19938 CharacterDatabase.Execute(stmt);
19939 };
19940
19941 if (!ok && HasAtLoginFlag(AT_LOGIN_FIRST))
19942 {
19944 if (!createPosition.TransportGuid)
19945 {
19946 m_homebind.WorldRelocate(createPosition.Loc);
19948
19949 saveHomebindToDb();
19950 ok = true;
19951 }
19952 }
19953
19954 if (!ok)
19955 {
19956 WorldSafeLocsEntry const* loc = sObjectMgr->GetDefaultGraveyard(GetTeam());
19957 if (!loc && GetRace() == RACE_PANDAREN_NEUTRAL)
19958 loc = sObjectMgr->GetWorldSafeLoc(3295); // The Wandering Isle, Starting Area GY
19959
19960 ASSERT(loc, "Missing fallback graveyard location for faction %u", uint32(GetTeamId()));
19961
19964
19965 saveHomebindToDb();
19966 }
19967
19968 TC_LOG_DEBUG("entities.player", "Player::_LoadHomeBind: Setting home position (MapID: {}, AreaID: {}, X: {}, Y: {}, Z: {} O: {}) of player '{}' ({})",
19970
19971 return true;
19972}
19973
19974/*********************************************************/
19975/*** SAVE SYSTEM ***/
19976/*********************************************************/
19977
19978void Player::SaveToDB(bool create /*=false*/)
19979{
19980 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
19981 LoginDatabaseTransaction loginTransaction = LoginDatabase.BeginTransaction();
19982
19983 SaveToDB(loginTransaction, trans, create);
19984
19985 CharacterDatabase.CommitTransaction(trans);
19986 LoginDatabase.CommitTransaction(loginTransaction);
19987}
19988
19989void Player::SaveToDB(LoginDatabaseTransaction loginTransaction, CharacterDatabaseTransaction trans, bool create /* = false */)
19990{
19991 // delay auto save at any saves (manual, in code, or autosave)
19992 m_nextSave = sWorld->getIntConfig(CONFIG_INTERVAL_SAVE);
19993
19994 //lets allow only players in world to be saved
19996 {
19998 return;
19999 }
20000
20001 // first save/honor gain after midnight will also update the player's honor fields
20003
20004 TC_LOG_DEBUG("entities.unit", "Player::SaveToDB: The value of player {} at save: ", m_name);
20006
20007 if (!create)
20008 sScriptMgr->OnPlayerSave(this);
20009
20010 CharacterDatabasePreparedStatement* stmt = nullptr;
20011 uint8 index = 0;
20012
20013 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_FISHINGSTEPS);
20014 stmt->setUInt64(0, GetGUID().GetCounter());
20015 trans->Append(stmt);
20016
20017 auto finiteAlways = [](float f) { return std::isfinite(f) ? f : 0.0f; };
20018
20019 if (create)
20020 {
20023 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER);
20024 stmt->setUInt64(index++, GetGUID().GetCounter());
20025 stmt->setUInt32(index++, GetSession()->GetAccountId());
20026 stmt->setString(index++, GetName());
20027 stmt->setUInt8(index++, GetRace());
20028 stmt->setUInt8(index++, GetClass());
20029 stmt->setUInt8(index++, GetNativeGender()); // save gender from PLAYER_BYTES_3, UNIT_BYTES_0 changes with every transform effect
20030 stmt->setUInt8(index++, GetLevel());
20031 stmt->setUInt32(index++, GetXP());
20032 stmt->setUInt64(index++, GetMoney());
20033 stmt->setUInt8(index++, GetInventorySlotCount());
20034 stmt->setUInt8(index++, GetBankBagSlotCount());
20035 stmt->setUInt8(index++, m_activePlayerData->RestInfo[REST_TYPE_XP].StateID);
20036 stmt->setUInt32(index++, m_playerData->PlayerFlags);
20037 stmt->setUInt32(index++, m_playerData->PlayerFlagsEx);
20038 stmt->setUInt16(index++, (uint16)GetMapId());
20039 stmt->setUInt32(index++, (uint32)GetInstanceId());
20040 stmt->setUInt8(index++, uint8(GetDungeonDifficultyID()));
20041 stmt->setUInt8(index++, uint8(GetRaidDifficultyID()));
20042 stmt->setUInt8(index++, uint8(GetLegacyRaidDifficultyID()));
20043 stmt->setFloat(index++, finiteAlways(GetPositionX()));
20044 stmt->setFloat(index++, finiteAlways(GetPositionY()));
20045 stmt->setFloat(index++, finiteAlways(GetPositionZ()));
20046 stmt->setFloat(index++, finiteAlways(GetOrientation()));
20047 stmt->setFloat(index++, finiteAlways(GetTransOffsetX()));
20048 stmt->setFloat(index++, finiteAlways(GetTransOffsetY()));
20049 stmt->setFloat(index++, finiteAlways(GetTransOffsetZ()));
20050 stmt->setFloat(index++, finiteAlways(GetTransOffsetO()));
20051 ObjectGuid::LowType transLowGUID = UI64LIT(0);
20052 if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
20053 transLowGUID = transport->GetGUID().GetCounter();
20054 stmt->setUInt64(index++, transLowGUID);
20055
20056 std::ostringstream ss;
20057 ss << m_taxi;
20058 stmt->setString(index++, ss.str());
20059 stmt->setInt64(index++, m_createTime);
20060 stmt->setInt8(index++, AsUnderlyingType(m_createMode));
20061 stmt->setUInt8(index++, m_cinematic);
20062 stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_TOTAL]);
20063 stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_LEVEL]);
20064 stmt->setFloat(index++, finiteAlways(_restMgr->GetRestBonus(REST_TYPE_XP)));
20065 stmt->setUInt64(index++, GameTime::GetGameTime());
20066 stmt->setUInt8(index++, (HasPlayerFlag(PLAYER_FLAGS_RESTING) ? 1 : 0));
20067 //save, far from tavern/city
20068 //save, but in tavern/city
20069 stmt->setUInt32(index++, GetTalentResetCost());
20070 stmt->setInt64(index++, GetTalentResetTime());
20072 stmt->setUInt16(index++, (uint16)m_ExtraFlags);
20073 stmt->setUInt32(index++, 0); // summonedPetNumber
20074 stmt->setUInt16(index++, (uint16)m_atLoginFlags);
20075 stmt->setInt64(index++, m_deathExpireTime);
20076
20077 ss.str("");
20079
20080 stmt->setString(index++, ss.str());
20081 stmt->setUInt32(index++, m_activePlayerData->LifetimeHonorableKills);
20082 stmt->setUInt16(index++, m_activePlayerData->TodayHonorableKills);
20083 stmt->setUInt16(index++, m_activePlayerData->YesterdayHonorableKills);
20084 stmt->setUInt32(index++, m_playerData->PlayerTitle);
20085 stmt->setUInt32(index++, m_activePlayerData->WatchedFactionIndex);
20086 stmt->setUInt8(index++, GetDrunkValue());
20087 stmt->setUInt32(index++, GetHealth());
20088
20089 for (uint32 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
20090 stmt->setUInt32(index++, m_unitData->Power[i]);
20091
20092 stmt->setUInt32(index++, GetSession()->GetLatency());
20093
20094 stmt->setUInt8(index++, GetActiveTalentGroup());
20095
20096 stmt->setUInt32(index++, GetLootSpecId());
20097
20098 ss.str("");
20099 for (size_t i = 0; i < m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size(); ++i)
20100 {
20101 ss << uint32(m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] & 0xFFFFFFFF) << ' ';
20102 ss << uint32((m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] >> 32) & 0xFFFFFFFF) << ' ';
20103 }
20104 stmt->setString(index++, ss.str());
20105
20106 ss.str("");
20107 // cache equipment...
20108 for (uint32 i = 0; i < REAGENT_BAG_SLOT_END; ++i)
20109 {
20110 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
20111 {
20112 ss << uint32(item->GetTemplate()->GetInventoryType()) << ' ' << item->GetDisplayId(this) << ' ';
20113 if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetVisibleEnchantmentId(this)))
20114 ss << enchant->ItemVisual;
20115 else
20116 ss << '0';
20117
20118 ss << ' '
20119 << uint32(sItemStore.AssertEntry(item->GetVisibleEntry(this))->SubclassID) << ' '
20120 << uint32(item->GetVisibleSecondaryModifiedAppearanceId(this)) << ' ';
20121 }
20122 else
20123 ss << "0 0 0 0 0 ";
20124 }
20125
20126 stmt->setString(index++, ss.str());
20127
20128 ss.str("");
20129 for (uint32 i = 0; i < m_activePlayerData->KnownTitles.size(); ++i)
20130 {
20131 ss << uint32(m_activePlayerData->KnownTitles[i] & 0xFFFFFFFF) << ' ';
20132 ss << uint32((m_activePlayerData->KnownTitles[i] >> 32) & 0xFFFFFFFF) << ' ';
20133 }
20134 stmt->setString(index++, ss.str());
20135
20136 stmt->setUInt8(index++, m_activePlayerData->MultiActionBars);
20137 stmt->setUInt32(index++, sRealmList->GetMinorMajorBugfixVersionForBuild(realm.Build));
20138 }
20139 else
20140 {
20141 // Update query
20142 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHARACTER);
20143 stmt->setString(index++, GetName());
20144 stmt->setUInt8(index++, GetRace());
20145 stmt->setUInt8(index++, GetClass());
20146 stmt->setUInt8(index++, GetNativeGender()); // save gender from PLAYER_BYTES_3, UNIT_BYTES_0 changes with every transform effect
20147 stmt->setUInt8(index++, GetLevel());
20148 stmt->setUInt32(index++, GetXP());
20149 stmt->setUInt64(index++, GetMoney());
20150 stmt->setUInt8(index++, GetInventorySlotCount());
20151 stmt->setUInt8(index++, GetBankBagSlotCount());
20152 stmt->setUInt8(index++, m_activePlayerData->RestInfo[REST_TYPE_XP].StateID);
20153 stmt->setUInt32(index++, m_playerData->PlayerFlags);
20154 stmt->setUInt32(index++, m_playerData->PlayerFlagsEx);
20155
20156 if (!IsBeingTeleported())
20157 {
20158 stmt->setUInt16(index++, (uint16)GetMapId());
20159 stmt->setUInt32(index++, (uint32)GetInstanceId());
20160 stmt->setUInt8(index++, uint8(GetDungeonDifficultyID()));
20161 stmt->setUInt8(index++, uint8(GetRaidDifficultyID()));
20162 stmt->setUInt8(index++, uint8(GetLegacyRaidDifficultyID()));
20163 stmt->setFloat(index++, finiteAlways(GetPositionX()));
20164 stmt->setFloat(index++, finiteAlways(GetPositionY()));
20165 stmt->setFloat(index++, finiteAlways(GetPositionZ()));
20166 stmt->setFloat(index++, finiteAlways(GetOrientation()));
20167 }
20168 else
20169 {
20170 stmt->setUInt16(index++, (uint16)GetTeleportDest().GetMapId());
20171 stmt->setUInt32(index++, (uint32)0);
20172 stmt->setUInt8(index++, uint8(GetDungeonDifficultyID()));
20173 stmt->setUInt8(index++, uint8(GetRaidDifficultyID()));
20174 stmt->setUInt8(index++, uint8(GetLegacyRaidDifficultyID()));
20175 stmt->setFloat(index++, finiteAlways(GetTeleportDest().GetPositionX()));
20176 stmt->setFloat(index++, finiteAlways(GetTeleportDest().GetPositionY()));
20177 stmt->setFloat(index++, finiteAlways(GetTeleportDest().GetPositionZ()));
20178 stmt->setFloat(index++, finiteAlways(GetTeleportDest().GetOrientation()));
20179 }
20180
20181 stmt->setFloat(index++, finiteAlways(GetTransOffsetX()));
20182 stmt->setFloat(index++, finiteAlways(GetTransOffsetY()));
20183 stmt->setFloat(index++, finiteAlways(GetTransOffsetZ()));
20184 stmt->setFloat(index++, finiteAlways(GetTransOffsetO()));
20185 ObjectGuid::LowType transLowGUID = UI64LIT(0);
20186 if (Transport* transport = dynamic_cast<Transport*>(GetTransport()))
20187 transLowGUID = transport->GetGUID().GetCounter();
20188 stmt->setUInt64(index++, transLowGUID);
20189
20190 std::ostringstream ss;
20191 ss << m_taxi;
20192 stmt->setString(index++, ss.str());
20193 stmt->setUInt8(index++, m_cinematic);
20194 stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_TOTAL]);
20195 stmt->setUInt32(index++, m_Played_time[PLAYED_TIME_LEVEL]);
20196 stmt->setFloat(index++, finiteAlways(_restMgr->GetRestBonus(REST_TYPE_XP)));
20197 stmt->setUInt64(index++, GameTime::GetGameTime());
20198 stmt->setUInt8(index++, (HasPlayerFlag(PLAYER_FLAGS_RESTING) ? 1 : 0));
20199 //save, far from tavern/city
20200 //save, but in tavern/city
20201 stmt->setUInt32(index++, GetTalentResetCost());
20202 stmt->setInt64(index++, GetTalentResetTime());
20203 stmt->setUInt8(index++, GetNumRespecs());
20205 stmt->setUInt16(index++, (uint16)m_ExtraFlags);
20206 if (PetStable const* petStable = GetPetStable())
20207 stmt->setUInt32(index++, petStable->GetCurrentPet() && petStable->GetCurrentPet()->Health > 0 ? petStable->GetCurrentPet()->PetNumber : 0); // summonedPetNumber
20208 else
20209 stmt->setUInt32(index++, 0); // summonedPetNumber
20210 stmt->setUInt16(index++, (uint16)m_atLoginFlags);
20211 stmt->setUInt16(index++, GetZoneId());
20212 stmt->setInt64(index++, m_deathExpireTime);
20213
20214 ss.str("");
20216
20217 stmt->setString(index++, ss.str());
20218 stmt->setUInt32(index++, m_activePlayerData->LifetimeHonorableKills);
20219 stmt->setUInt16(index++, m_activePlayerData->TodayHonorableKills);
20220 stmt->setUInt16(index++, m_activePlayerData->YesterdayHonorableKills);
20221 stmt->setUInt32(index++, m_playerData->PlayerTitle);
20222 stmt->setUInt32(index++, m_activePlayerData->WatchedFactionIndex);
20223 stmt->setUInt8(index++, GetDrunkValue());
20224 stmt->setUInt32(index++, GetHealth());
20225
20226 for (uint32 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
20227 stmt->setUInt32(index++, m_unitData->Power[i]);
20228
20229 stmt->setUInt32(index++, GetSession()->GetLatency());
20230
20231 stmt->setUInt8(index++, GetActiveTalentGroup());
20232
20233 stmt->setUInt32(index++, GetLootSpecId());
20234
20235 ss.str("");
20236 for (size_t i = 0; i < m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX].size(); ++i)
20237 {
20238 ss << uint32(m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] & 0xFFFFFFFF) << ' ';
20239 ss << uint32((m_activePlayerData->DataFlags[PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX][i] >> 32) & 0xFFFFFFFF) << ' ';
20240 }
20241 stmt->setString(index++, ss.str());
20242
20243 ss.str("");
20244 // cache equipment...
20245 for (uint32 i = 0; i < REAGENT_BAG_SLOT_END; ++i)
20246 {
20247 if (Item* item = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
20248 {
20249 ss << uint32(item->GetTemplate()->GetInventoryType()) << ' ' << item->GetDisplayId(this) << ' ';
20250 if (SpellItemEnchantmentEntry const* enchant = sSpellItemEnchantmentStore.LookupEntry(item->GetVisibleEnchantmentId(this)))
20251 ss << enchant->ItemVisual;
20252 else
20253 ss << '0';
20254
20255 ss << ' '
20256 << uint32(sItemStore.AssertEntry(item->GetVisibleEntry(this))->SubclassID) << ' '
20257 << uint32(item->GetVisibleSecondaryModifiedAppearanceId(this)) << ' ';
20258 }
20259 else
20260 ss << "0 0 0 0 0 ";
20261 }
20262
20263 stmt->setString(index++, ss.str());
20264
20265 ss.str("");
20266 for (uint32 i = 0; i < m_activePlayerData->KnownTitles.size(); ++i)
20267 {
20268 ss << uint32(m_activePlayerData->KnownTitles[i] & 0xFFFFFFFF) << ' ';
20269 ss << uint32((m_activePlayerData->KnownTitles[i] >> 32) & 0xFFFFFFFF) << ' ';
20270 }
20271
20272 stmt->setString(index++, ss.str());
20273 stmt->setUInt8(index++, m_activePlayerData->MultiActionBars);
20274
20275 stmt->setUInt8(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0);
20276 stmt->setUInt32(index++, m_activePlayerData->Honor);
20277 stmt->setUInt32(index++, GetHonorLevel());
20278 stmt->setUInt8(index++, m_activePlayerData->RestInfo[REST_TYPE_HONOR].StateID);
20279 stmt->setFloat(index++, finiteAlways(_restMgr->GetRestBonus(REST_TYPE_HONOR)));
20280 stmt->setUInt32(index++, sRealmList->GetMinorMajorBugfixVersionForBuild(realm.Build));
20281
20282 // Index
20283 stmt->setUInt64(index, GetGUID().GetCounter());
20284 }
20285
20286 trans->Append(stmt);
20287
20288 if (m_fishingSteps != 0)
20289 {
20290 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_FISHINGSTEPS);
20291 index = 0;
20292 stmt->setUInt64(index++, GetGUID().GetCounter());
20293 stmt->setUInt32(index++, m_fishingSteps);
20294 trans->Append(stmt);
20295 }
20296
20297 if (m_mailsUpdated) //save mails only when needed
20298 _SaveMail(trans);
20299
20300 _SaveCustomizations(trans);
20301 _SaveBGData(trans);
20302 _SaveInventory(trans);
20303 _SaveVoidStorage(trans);
20304 _SaveQuestStatus(trans);
20305 _SaveDailyQuestStatus(trans);
20309 _SaveGlyphs(trans);
20310 _SaveTalents(trans);
20311 _SaveTraits(trans);
20312 _SaveSpells(trans);
20313 GetSpellHistory()->SaveToDB<Player>(trans);
20314 _SaveActions(trans);
20315 _SaveAuras(trans);
20316 _SaveSkills(trans);
20318 m_achievementMgr->SaveToDB(trans);
20319 m_reputationMgr->SaveToDB(trans);
20320 m_questObjectiveCriteriaMgr->SaveToDB(trans);
20321 _SaveEquipmentSets(trans);
20322 GetSession()->SaveTutorialsData(trans); // changed only while character in game
20324 _SaveCurrency(trans);
20325 _SaveCUFProfiles(trans);
20326 if (_garrison)
20327 _garrison->SaveToDB(trans);
20328
20329 // check if stats should only be saved on logout
20330 // save stats can be out of transaction
20332 _SaveStats(trans);
20333
20334 // TODO: Move this out
20335 GetSession()->GetCollectionMgr()->SaveAccountToys(loginTransaction);
20336 GetSession()->GetBattlePetMgr()->SaveToDB(loginTransaction);
20337 GetSession()->GetCollectionMgr()->SaveAccountHeirlooms(loginTransaction);
20338 GetSession()->GetCollectionMgr()->SaveAccountMounts(loginTransaction);
20341
20343 loginStmt->setUInt32(0, GetSession()->GetAccountId());
20344 loginStmt->setUInt8(1, realm.Id.Region);
20345 loginStmt->setUInt8(2, realm.Id.Site);
20346 loginTransaction->Append(loginStmt);
20347
20348 loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_LAST_PLAYER_CHARACTERS);
20349 loginStmt->setUInt32(0, GetSession()->GetAccountId());
20350 loginStmt->setUInt8(1, realm.Id.Region);
20351 loginStmt->setUInt8(2, realm.Id.Site);
20352 loginStmt->setUInt32(3, realm.Id.Realm);
20353 loginStmt->setString(4, GetName());
20354 loginStmt->setUInt64(5, GetGUID().GetCounter());
20355 loginStmt->setUInt32(6, GameTime::GetGameTime());
20356 loginTransaction->Append(loginStmt);
20357
20358 // save pet (hunter pet level and experience and all type pets health/mana).
20359 if (Pet* pet = GetPet())
20360 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
20361}
20362
20363// fast save function for item/money cheating preventing - save only inventory and money state
20365{
20366 _SaveInventory(trans);
20367 _SaveCurrency(trans);
20368
20370 stmt->setUInt64(0, GetMoney());
20371 stmt->setUInt64(1, GetGUID().GetCounter());
20372 trans->Append(stmt);
20373}
20374
20375template<typename iterator>
20377{
20379 stmt->setUInt64(0, guid);
20380 trans->Append(stmt);
20381
20382 for (auto&& customization : customizations)
20383 {
20384 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_CUSTOMIZATION);
20385 stmt->setUInt64(0, guid);
20386 stmt->setUInt32(1, customization.ChrCustomizationOptionID);
20387 stmt->setUInt32(2, customization.ChrCustomizationChoiceID);
20388 trans->Append(stmt);
20389 }
20390}
20391
20394{
20395 SavePlayerCustomizations(trans, guid, customizations);
20396}
20397
20399{
20401 return;
20402
20404
20405 SavePlayerCustomizations(trans, GetGUID().GetCounter(), Trinity::Containers::MakeIteratorPair(m_playerData->Customizations.begin(), m_playerData->Customizations.end()));
20406}
20407
20409{
20410 int32 traitConfigId = [&]() -> int32
20411 {
20412 UF::TraitConfig const* traitConfig = GetTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID);
20413 if (!traitConfig)
20414 return 0;
20415
20416 int32 usedSavedTraitConfigIndex = m_activePlayerData->TraitConfigs.FindIndexIf([localIdent = *traitConfig->LocalIdentifier](UF::TraitConfig const& savedConfig)
20417 {
20418 return static_cast<TraitConfigType>(*savedConfig.Type) == TraitConfigType::Combat
20419 && (static_cast<TraitCombatConfigFlags>(*savedConfig.CombatConfigFlags) & TraitCombatConfigFlags::ActiveForSpec) == TraitCombatConfigFlags::None
20420 && (static_cast<TraitCombatConfigFlags>(*savedConfig.CombatConfigFlags) & TraitCombatConfigFlags::SharedActionBars) == TraitCombatConfigFlags::None
20421 && savedConfig.LocalIdentifier == localIdent;
20422 });
20423
20424 if (usedSavedTraitConfigIndex >= 0)
20425 return m_activePlayerData->TraitConfigs[usedSavedTraitConfigIndex].ID;
20426
20427 return 0;
20428 }();
20429
20431
20432 for (ActionButtonList::iterator itr = m_actionButtons.begin(); itr != m_actionButtons.end();)
20433 {
20434 switch (itr->second.uState)
20435 {
20436 case ACTIONBUTTON_NEW:
20437 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACTION);
20438 stmt->setUInt64(0, GetGUID().GetCounter());
20439 stmt->setUInt8(1, GetActiveTalentGroup());
20440 stmt->setInt32(2, traitConfigId);
20441 stmt->setUInt8(3, itr->first);
20442 stmt->setUInt64(4, itr->second.GetAction());
20443 stmt->setUInt8(5, uint8(itr->second.GetType()));
20444 trans->Append(stmt);
20445
20446 itr->second.uState = ACTIONBUTTON_UNCHANGED;
20447 ++itr;
20448 break;
20450 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACTION);
20451 stmt->setUInt64(0, itr->second.GetAction());
20452 stmt->setUInt8(1, uint8(itr->second.GetType()));
20453 stmt->setUInt64(2, GetGUID().GetCounter());
20454 stmt->setUInt8(3, itr->first);
20455 stmt->setUInt8(4, GetActiveTalentGroup());
20456 stmt->setInt32(5, traitConfigId);
20457 trans->Append(stmt);
20458
20459 itr->second.uState = ACTIONBUTTON_UNCHANGED;
20460 ++itr;
20461 break;
20463 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC);
20464 stmt->setUInt64(0, GetGUID().GetCounter());
20465 stmt->setUInt8(1, itr->first);
20466 stmt->setUInt8(2, GetActiveTalentGroup());
20467 stmt->setInt32(3, traitConfigId);
20468 trans->Append(stmt);
20469
20470 m_actionButtons.erase(itr++);
20471 break;
20472 default:
20473 ++itr;
20474 break;
20475 }
20476 }
20477}
20478
20480{
20482 stmt->setUInt64(0, GetGUID().GetCounter());
20483 trans->Append(stmt);
20484
20485 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
20486 stmt->setUInt64(0, GetGUID().GetCounter());
20487 trans->Append(stmt);
20488
20489 uint8 index;
20490 for (AuraMap::const_iterator itr = m_ownedAuras.begin(); itr != m_ownedAuras.end(); ++itr)
20491 {
20492 if (!itr->second->CanBeSaved())
20493 continue;
20494
20495 Aura* aura = itr->second;
20496 uint32 recalculateMask = 0;
20497 AuraKey key = aura->GenerateKey(recalculateMask);
20498
20499 index = 0;
20500 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
20501 stmt->setUInt64(index++, GetGUID().GetCounter());
20502 stmt->setBinary(index++, key.Caster.GetRawValue());
20503 stmt->setBinary(index++, key.Item.GetRawValue());
20504 stmt->setUInt32(index++, key.SpellId);
20505 stmt->setUInt32(index++, key.EffectMask);
20506 stmt->setUInt32(index++, recalculateMask);
20507 stmt->setUInt8(index++, aura->GetCastDifficulty());
20508 stmt->setUInt8(index++, aura->GetStackAmount());
20509 stmt->setInt32(index++, aura->GetMaxDuration());
20510 stmt->setInt32(index++, aura->GetDuration());
20511 stmt->setUInt8(index++, aura->GetCharges());
20512 stmt->setUInt32(index++, aura->GetCastItemId());
20513 stmt->setInt32(index++, aura->GetCastItemLevel());
20514 trans->Append(stmt);
20515
20516 for (AuraEffect const* effect : aura->GetAuraEffects())
20517 {
20518 if (effect)
20519 {
20520 index = 0;
20521 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA_EFFECT);
20522 stmt->setUInt64(index++, GetGUID().GetCounter());
20523 stmt->setBinary(index++, key.Caster.GetRawValue());
20524 stmt->setBinary(index++, key.Item.GetRawValue());
20525 stmt->setUInt32(index++, key.SpellId);
20526 stmt->setUInt32(index++, key.EffectMask);
20527 stmt->setUInt8(index++, effect->GetEffIndex());
20528 stmt->setInt32(index++, effect->GetAmount());
20529 stmt->setInt32(index++, effect->GetBaseAmount());
20530 trans->Append(stmt);
20531 }
20532 }
20533 }
20534}
20535
20537{
20539 // force items in buyback slots to new state
20540 // and remove those that aren't already
20541 for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; ++i)
20542 {
20543 Item* item = m_items[i];
20544 if (!item)
20545 continue;
20546
20547 if (item->GetState() == ITEM_NEW)
20548 {
20549 if (ItemTemplate const* itemTemplate = item->GetTemplate())
20550 if (itemTemplate->HasFlag(ITEM_FLAG_HAS_LOOT))
20551 sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
20552
20553 continue;
20554 }
20555
20556 item->DeleteFromInventoryDB(trans);
20557 item->DeleteFromDB(trans);
20559
20560 if (ItemTemplate const* itemTemplate = item->GetTemplate())
20561 if (itemTemplate->HasFlag(ITEM_FLAG_HAS_LOOT))
20562 sLootItemStorage->RemoveStoredLootForContainer(item->GetGUID().GetCounter());
20563 }
20564
20565 // Updated played time for refundable items. We don't do this in Player::Update because there's simply no need for it,
20566 // the client auto counts down in real time after having received the initial played time on the first
20567 // SMSG_ITEM_REFUND_INFO_RESPONSE packet.
20568 // Item::UpdatePlayedTime is only called when needed, which is in DB saves, and item refund info requests.
20569 GuidSet::iterator i_next;
20570 for (GuidSet::iterator itr = m_refundableItems.begin(); itr!= m_refundableItems.end(); itr = i_next)
20571 {
20572 // use copy iterator because itr may be invalid after operations in this loop
20573 i_next = itr;
20574 ++i_next;
20575
20576 Item* iPtr = GetItemByGuid(*itr);
20577 if (iPtr)
20578 {
20579 iPtr->UpdatePlayedTime(this);
20580 continue;
20581 }
20582 else
20583 {
20584 TC_LOG_ERROR("entities.player", "Player::_SaveInventory: Can't find item ({}) in refundable storage for player '{}' ({}), removing.",
20585 itr->ToString(), GetName(), GetGUID().ToString());
20586 m_refundableItems.erase(itr);
20587 }
20588 }
20589
20590 // update enchantment durations
20591 for (EnchantDurationList::iterator itr = m_enchantDuration.begin(); itr != m_enchantDuration.end(); ++itr)
20592 itr->item->SetEnchantmentDuration(itr->slot, itr->leftduration, this);
20593
20594 // if no changes
20595 if (m_itemUpdateQueue.empty())
20596 return;
20597
20598 for (size_t i = 0; i < m_itemUpdateQueue.size(); ++i)
20599 {
20600 Item* item = m_itemUpdateQueue[i];
20601 if (!item)
20602 continue;
20603
20604 Bag* container = item->GetContainer();
20605 if (item->GetState() != ITEM_REMOVED)
20606 {
20607 Item* test = GetItemByPos(item->GetBagSlot(), item->GetSlot());
20608 if (test == nullptr)
20609 {
20610 ObjectGuid::LowType bagTestGUID = UI64LIT(0);
20611 if (Item* test2 = GetItemByPos(INVENTORY_SLOT_BAG_0, item->GetBagSlot()))
20612 bagTestGUID = test2->GetGUID().GetCounter();
20613
20614 TC_LOG_ERROR("entities.player", "Player::_SaveInventory: Player '{}' ({}) has incorrect values (Bag: {}, Slot: {}) for the item ({}, State: {}). The player doesn't have an item at that position.",
20615 GetName(), GetGUID().ToString(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString(), (int32)item->GetState());
20616 // according to the test that was just performed nothing should be in this slot, delete
20617 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT);
20618 stmt->setUInt64(0, bagTestGUID);
20619 stmt->setUInt8(1, item->GetSlot());
20620 stmt->setUInt64(2, GetGUID().GetCounter());
20621 trans->Append(stmt);
20622
20623 RemoveTradeableItem(item);
20625 RemoveItemDurations(item);
20626
20627 // also THIS item should be somewhere else, cheat attempt
20628 item->FSetState(ITEM_REMOVED); // we are IN updateQueue right now, can't use SetState which modifies the queue
20630 // don't skip, let the switch delete it
20631 //continue;
20632 }
20633 else if (test != item)
20634 {
20635 TC_LOG_ERROR("entities.player", "Player::_SaveInventory: Player '{}' ({}) has incorrect values (Bag: {}, Slot: {}) for the item ({}). {} is there instead!",
20636 GetName(), GetGUID().ToString(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString(), test->GetGUID().ToString());
20637 // save all changes to the item...
20638 if (item->GetState() != ITEM_NEW) // only for existing items, no duplicates
20639 item->SaveToDB(trans);
20640 // ...but do not save position in inventory
20641 continue;
20642 }
20643 }
20644
20645 switch (item->GetState())
20646 {
20647 case ITEM_NEW:
20648 case ITEM_CHANGED:
20649 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_INVENTORY_ITEM);
20650 stmt->setUInt64(0, GetGUID().GetCounter());
20651 stmt->setUInt64(1, container ? container->GetGUID().GetCounter() : UI64LIT(0));
20652 stmt->setUInt8 (2, item->GetSlot());
20653 stmt->setUInt64(3, item->GetGUID().GetCounter());
20654 trans->Append(stmt);
20655 break;
20656 case ITEM_REMOVED:
20657 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_ITEM);
20658 stmt->setUInt64(0, item->GetGUID().GetCounter());
20659 trans->Append(stmt);
20660 break;
20661 case ITEM_UNCHANGED:
20662 break;
20663 }
20664
20665 item->SaveToDB(trans); // item have unchanged inventory record and can be save standalone
20666 }
20667 m_itemUpdateQueue.clear();
20668}
20669
20671{
20672 CharacterDatabasePreparedStatement* stmt = nullptr;
20673
20674 for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
20675 {
20676 if (!_voidStorageItems[i]) // unused item
20677 {
20678 // DELETE FROM void_storage WHERE slot = ? AND playerGuid = ?
20680 stmt->setUInt8(0, i);
20681 stmt->setUInt64(1, GetGUID().GetCounter());
20682 }
20683 else
20684 {
20685 // REPLACE INTO character_void_storage (itemId, playerGuid, itemEntry, slot, creatorGuid, randomBonusListId, upgradeId, fixedScalingLevel, artifactKnowledgeLevel, bonusListIDs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
20686 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_VOID_STORAGE_ITEM);
20687 stmt->setUInt64(0, _voidStorageItems[i]->ItemId);
20688 stmt->setUInt64(1, GetGUID().GetCounter());
20690 stmt->setUInt8(3, i);
20691 stmt->setUInt64(4, _voidStorageItems[i]->CreatorGuid.GetCounter());
20692 stmt->setUInt32(5, _voidStorageItems[i]->RandomBonusListId);
20693 stmt->setUInt32(6, _voidStorageItems[i]->FixedScalingLevel);
20694 stmt->setUInt32(7, _voidStorageItems[i]->ArtifactKnowledgeLevel);
20695 stmt->setUInt8(8, AsUnderlyingType(_voidStorageItems[i]->Context));
20696 std::ostringstream bonusListIDs;
20697 for (int32 bonusListID : _voidStorageItems[i]->BonusListIDs)
20698 bonusListIDs << bonusListID << ' ';
20699 stmt->setString(9, bonusListIDs.str());
20700 }
20701
20702 trans->Append(stmt);
20703 }
20704}
20705
20707{
20709 for (uint8 i = 0; i < MAX_CUF_PROFILES; ++i)
20710 {
20711 if (!_CUFProfiles[i]) // unused profile
20712 {
20713 // DELETE FROM character_cuf_profiles WHERE guid = ? and id = ?
20714 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_CUF_PROFILES_BY_ID);
20715 stmt->setUInt64(0, GetGUID().GetCounter());
20716 stmt->setUInt8(1, i);
20717 }
20718 else
20719 {
20720 // REPLACE INTO character_cuf_profiles (guid, id, name, frameHeight, frameWidth, sortBy, healthText, boolOptions, unk146, unk147, unk148, unk150, unk152, unk154) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
20721 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_CUF_PROFILES);
20722 stmt->setUInt64(0, GetGUID().GetCounter());
20723 stmt->setUInt8(1, i);
20724 stmt->setString(2, _CUFProfiles[i]->ProfileName);
20725 stmt->setUInt16(3, _CUFProfiles[i]->FrameHeight);
20726 stmt->setUInt16(4, _CUFProfiles[i]->FrameWidth);
20727 stmt->setUInt8(5, _CUFProfiles[i]->SortBy);
20728 stmt->setUInt8(6, _CUFProfiles[i]->HealthText);
20729 stmt->setUInt32(7, _CUFProfiles[i]->BoolOptions.to_ulong()); // 25 of 32 fields used, fits in an int
20730 stmt->setUInt8(8, _CUFProfiles[i]->TopPoint);
20731 stmt->setUInt8(9, _CUFProfiles[i]->BottomPoint);
20732 stmt->setUInt8(10, _CUFProfiles[i]->LeftPoint);
20733 stmt->setUInt16(11, _CUFProfiles[i]->TopOffset);
20734 stmt->setUInt16(12, _CUFProfiles[i]->BottomOffset);
20735 stmt->setUInt16(13, _CUFProfiles[i]->LeftOffset);
20736 }
20737
20738 trans->Append(stmt);
20739 }
20740}
20741
20743{
20745
20746 for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ++itr)
20747 {
20748 Mail* m = (*itr);
20749 if (m->state == MAIL_STATE_CHANGED)
20750 {
20751 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_MAIL);
20752 stmt->setUInt8(0, uint8(m->HasItems() ? 1 : 0));
20753 stmt->setInt64(1, m->expire_time);
20754 stmt->setInt64(2, m->deliver_time);
20755 stmt->setUInt64(3, m->money);
20756 stmt->setUInt64(4, m->COD);
20757 stmt->setUInt8(5, uint8(m->checked));
20758 stmt->setUInt64(6, m->messageID);
20759
20760 trans->Append(stmt);
20761
20762 if (!m->removedItems.empty())
20763 {
20764 for (std::vector<ObjectGuid::LowType>::iterator itr2 = m->removedItems.begin(); itr2 != m->removedItems.end(); ++itr2)
20765 {
20766 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM);
20767 stmt->setUInt64(0, *itr2);
20768 trans->Append(stmt);
20769 }
20770 m->removedItems.clear();
20771 }
20773 }
20774 else if (m->state == MAIL_STATE_DELETED)
20775 {
20776 if (m->HasItems())
20777 {
20778 for (MailItemInfoVec::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2)
20779 {
20780 Item::DeleteFromDB(trans, itr2->item_guid);
20781 AzeriteItem::DeleteFromDB(trans, itr2->item_guid);
20782 AzeriteEmpoweredItem::DeleteFromDB(trans, itr2->item_guid);
20783 }
20784 }
20785 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_BY_ID);
20786 stmt->setUInt64(0, m->messageID);
20787 trans->Append(stmt);
20788
20789 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_MAIL_ITEM_BY_ID);
20790 stmt->setUInt64(0, m->messageID);
20791 trans->Append(stmt);
20792 }
20793 }
20794
20795 //deallocate deleted mails...
20796 for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end();)
20797 {
20798 if ((*itr)->state == MAIL_STATE_DELETED)
20799 {
20800 Mail* m = *itr;
20801 m_mail.erase(itr);
20802 delete m;
20803 itr = m_mail.begin();
20804 }
20805 else
20806 ++itr;
20807 }
20808
20809 m_mailsUpdated = false;
20810}
20811
20813{
20814 bool isTransaction = bool(trans);
20815 if (!isTransaction)
20816 trans = CharacterDatabase.BeginTransaction();
20817
20819
20820 bool keepAbandoned = !(sWorld->GetCleaningFlags() & CharacterDatabaseCleaner::CLEANING_FLAG_QUESTSTATUS);
20821
20822 for (auto saveItr = m_QuestStatusSave.begin(); saveItr != m_QuestStatusSave.end(); ++saveItr)
20823 {
20824 if (saveItr->second == QUEST_DEFAULT_SAVE_TYPE)
20825 {
20826 auto statusItr = m_QuestStatus.find(saveItr->first);
20827 if (statusItr != m_QuestStatus.end() && (keepAbandoned || statusItr->second.Status != QUEST_STATUS_NONE))
20828 {
20829 QuestStatusData const& qData = statusItr->second;
20830
20831 // Save main quest status and timer
20832 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS);
20833 stmt->setUInt64(0, GetGUID().GetCounter());
20834 stmt->setUInt32(1, statusItr->first);
20835 stmt->setUInt8(2, uint8(qData.Status));
20836 stmt->setBool(3, qData.Explored);
20837 stmt->setInt64(4, qData.AcceptTime);
20838 stmt->setInt64(5, GetQuestSlotEndTime(qData.Slot));
20839 trans->Append(stmt);
20840
20841 // Save objectives
20843 stmt->setUInt64(0, GetGUID().GetCounter());
20844 stmt->setUInt32(1, saveItr->first);
20845 trans->Append(stmt);
20846
20847 Quest const* quest = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(saveItr->first));
20848
20849 for (QuestObjective const& obj : quest->GetObjectives())
20850 {
20851 int32 count = GetQuestSlotObjectiveData(qData.Slot, obj);
20852 if (!count)
20853 continue;
20854
20855 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES);
20856 stmt->setUInt64(0, GetGUID().GetCounter());
20857 stmt->setUInt32(1, statusItr->first);
20858 stmt->setUInt8(2, obj.StorageIndex);
20859 stmt->setInt32(3, count);
20860 trans->Append(stmt);
20861 }
20862 }
20863 }
20864 else
20865 {
20866 // Delete
20867 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST);
20868 stmt->setUInt64(0, GetGUID().GetCounter());
20869 stmt->setUInt32(1, saveItr->first);
20870 trans->Append(stmt);
20871
20873 stmt->setUInt64(0, GetGUID().GetCounter());
20874 stmt->setUInt32(1, saveItr->first);
20875 trans->Append(stmt);
20876 }
20877 }
20878
20879 m_QuestStatusSave.clear();
20880
20881 for (auto saveItr = m_RewardedQuestsSave.begin(); saveItr != m_RewardedQuestsSave.end(); ++saveItr)
20882 {
20883 if (saveItr->second == QUEST_DEFAULT_SAVE_TYPE)
20884 {
20885 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_QUESTSTATUS_REWARDED);
20886 stmt->setUInt64(0, GetGUID().GetCounter());
20887 stmt->setUInt32(1, saveItr->first);
20888 trans->Append(stmt);
20889
20890 }
20891 else if (saveItr->second == QUEST_FORCE_DELETE_SAVE_TYPE || !keepAbandoned)
20892 {
20894 stmt->setUInt64(0, GetGUID().GetCounter());
20895 stmt->setUInt32(1, saveItr->first);
20896 trans->Append(stmt);
20897 }
20898 }
20899
20900 m_RewardedQuestsSave.clear();
20901
20902 if (!isTransaction)
20903 CharacterDatabase.CommitTransaction(trans);
20904}
20905
20907{
20909 return;
20910
20911 m_DailyQuestChanged = false;
20912
20913 // save last daily quest time for all quests: we need only mostly reset time for reset check anyway
20914
20915 // we don't need transactions here.
20917 stmt->setUInt64(0, GetGUID().GetCounter());
20918 trans->Append(stmt);
20919
20920 for (int32 questId : m_activePlayerData->DailyQuestsCompleted)
20921 {
20922 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY);
20923 stmt->setUInt64(0, GetGUID().GetCounter());
20924 stmt->setUInt32(1, questId);
20926 trans->Append(stmt);
20927 }
20928
20929 if (!m_DFQuests.empty())
20930 {
20931 for (DFQuestsDoneList::iterator itr = m_DFQuests.begin(); itr != m_DFQuests.end(); ++itr)
20932 {
20933 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY);
20934 stmt->setUInt64(0, GetGUID().GetCounter());
20935 stmt->setUInt32(1, (*itr));
20937 trans->Append(stmt);
20938 }
20939 }
20940}
20941
20943{
20944 if (!m_WeeklyQuestChanged || m_weeklyquests.empty())
20945 return;
20946
20947 // we don't need transactions here.
20949 stmt->setUInt64(0, GetGUID().GetCounter());
20950 trans->Append(stmt);
20951
20952 for (QuestSet::const_iterator iter = m_weeklyquests.begin(); iter != m_weeklyquests.end(); ++iter)
20953 {
20954 uint32 questId = *iter;
20955
20956 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY);
20957 stmt->setUInt64(0, GetGUID().GetCounter());
20958 stmt->setUInt32(1, questId);
20959 trans->Append(stmt);
20960 }
20961
20962 m_WeeklyQuestChanged = false;
20963}
20964
20966{
20968 return;
20969
20970 // we don't need transactions here.
20972 stmt->setUInt64(0, GetGUID().GetCounter());
20973 trans->Append(stmt);
20974
20975 m_SeasonalQuestChanged = false;
20976
20977 if (m_seasonalquests.empty())
20978 return;
20979
20980 for (SeasonalQuestMapByEvent::const_iterator iter = m_seasonalquests.begin(); iter != m_seasonalquests.end(); ++iter)
20981 {
20982 uint16 eventId = iter->first;
20983
20984 for (SeasonalQuestMapByQuest::const_iterator itr = iter->second.begin(); itr != iter->second.end(); ++itr)
20985 {
20986 uint32 questId = itr->first;
20987 time_t completedTime = itr->second;
20988
20990 stmt->setUInt64(0, GetGUID().GetCounter());
20991 stmt->setUInt32(1, questId);
20992 stmt->setUInt32(2, eventId);
20993 stmt->setInt64(3, completedTime);
20994 trans->Append(stmt);
20995 }
20996 }
20997}
20998
21000{
21001 if (!m_MonthlyQuestChanged || m_monthlyquests.empty())
21002 return;
21003
21004 // we don't need transactions here.
21006 stmt->setUInt64(0, GetGUID().GetCounter());
21007 trans->Append(stmt);
21008
21009 for (QuestSet::const_iterator iter = m_monthlyquests.begin(); iter != m_monthlyquests.end(); ++iter)
21010 {
21011 uint32 questId = *iter;
21012
21013 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY);
21014 stmt->setUInt64(0, GetGUID().GetCounter());
21015 stmt->setUInt32(1, questId);
21016 trans->Append(stmt);
21017 }
21018
21019 m_MonthlyQuestChanged = false;
21020}
21021
21023{
21025 // we don't need transactions here.
21026 for (SkillStatusMap::iterator itr = mSkillStatus.begin(); itr != mSkillStatus.end();)
21027 {
21028 if (itr->second.uState == SKILL_UNCHANGED)
21029 {
21030 ++itr;
21031 continue;
21032 }
21033
21034 uint16 value = m_activePlayerData->Skill->SkillRank[itr->second.pos];
21035 uint16 max = m_activePlayerData->Skill->SkillMaxRank[itr->second.pos];
21036 int8 professionSlot = int8(GetProfessionSlotFor(itr->first));
21037
21038 switch (itr->second.uState)
21039 {
21040 case SKILL_NEW:
21041 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILLS);
21042 stmt->setUInt64(0, GetGUID().GetCounter());
21043 stmt->setUInt16(1, uint16(itr->first));
21044 stmt->setUInt16(2, value);
21045 stmt->setUInt16(3, max);
21046 stmt->setInt8(4, professionSlot);
21047 trans->Append(stmt);
21048 break;
21049 case SKILL_CHANGED:
21050 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_SKILLS);
21051 stmt->setUInt16(0, value);
21052 stmt->setUInt16(1, max);
21053 stmt->setInt8(2, professionSlot);
21054 stmt->setUInt64(3, GetGUID().GetCounter());
21055 stmt->setUInt16(4, uint16(itr->first));
21056 trans->Append(stmt);
21057 break;
21058 case SKILL_DELETED:
21059 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL);
21060 stmt->setUInt64(0, GetGUID().GetCounter());
21061 stmt->setUInt16(1, uint16(itr->first));
21062 trans->Append(stmt);
21063 break;
21064 default:
21065 break;
21066 }
21067
21068 itr->second.uState = SKILL_UNCHANGED;
21069 ++itr;
21070 }
21071}
21072
21074{
21076
21077 for (PlayerSpellMap::iterator itr = m_spells.begin(); itr != m_spells.end();)
21078 {
21079 if (itr->second.state == PLAYERSPELL_REMOVED || itr->second.state == PLAYERSPELL_CHANGED)
21080 {
21081 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL);
21082 stmt->setUInt32(0, itr->first);
21083 stmt->setUInt64(1, GetGUID().GetCounter());
21084 trans->Append(stmt);
21085 }
21086
21087 if ((itr->second.state == PLAYERSPELL_NEW || itr->second.state == PLAYERSPELL_CHANGED))
21088 {
21089 // add only changed/new not dependent spells
21090 if (!itr->second.dependent)
21091 {
21092 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SPELL);
21093 stmt->setUInt64(0, GetGUID().GetCounter());
21094 stmt->setUInt32(1, itr->first);
21095 stmt->setBool(2, itr->second.active);
21096 stmt->setBool(3, itr->second.disabled);
21097 trans->Append(stmt);
21098 }
21099
21100 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_FAVORITE);
21101 stmt->setUInt32(0, itr->first);
21102 stmt->setUInt64(1, GetGUID().GetCounter());
21103 trans->Append(stmt);
21104
21105 if (itr->second.favorite)
21106 {
21107 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SPELL_FAVORITE);
21108 stmt->setUInt64(0, GetGUID().GetCounter());
21109 stmt->setUInt32(1, itr->first);
21110 trans->Append(stmt);
21111 }
21112 }
21113
21114 if (itr->second.state == PLAYERSPELL_REMOVED)
21115 {
21116 itr = m_spells.erase(itr);
21117 continue;
21118 }
21119
21120 if (itr->second.state != PLAYERSPELL_TEMPORARY)
21121 itr->second.state = PLAYERSPELL_UNCHANGED;
21122
21123 ++itr;
21124 }
21125}
21126
21128{
21129 for (auto itr = m_storedAuraTeleportLocations.begin(); itr != m_storedAuraTeleportLocations.end(); )
21130 {
21131 StoredAuraTeleportLocation& storedLocation = itr->second;
21132 if (storedLocation.State == StoredAuraTeleportLocation::DELETED)
21133 {
21135 stmt->setUInt64(0, GetGUID().GetCounter());
21136 trans->Append(stmt);
21137 itr = m_storedAuraTeleportLocations.erase(itr);
21138 continue;
21139 }
21140
21141 if (storedLocation.State == StoredAuraTeleportLocation::CHANGED)
21142 {
21144 stmt->setUInt64(0, GetGUID().GetCounter());
21145 trans->Append(stmt);
21146
21148 stmt->setUInt64(0, GetGUID().GetCounter());
21149 stmt->setUInt32(1, itr->first);
21150 stmt->setUInt32(2, storedLocation.Loc.GetMapId());
21151 stmt->setFloat(3, storedLocation.Loc.GetPositionX());
21152 stmt->setFloat(4, storedLocation.Loc.GetPositionY());
21153 stmt->setFloat(5, storedLocation.Loc.GetPositionZ());
21154 stmt->setFloat(6, storedLocation.Loc.GetOrientation());
21155 trans->Append(stmt);
21156 }
21157
21158 ++itr;
21159 }
21160}
21161
21162// save player stats -- only for external usage
21163// real stats will be recalculated on player login
21165{
21166 // check if stat saving is enabled and if char level is high enough
21167 if (!sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE) || GetLevel() < sWorld->getIntConfig(CONFIG_MIN_LEVEL_STAT_SAVE))
21168 return;
21169
21171
21172 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS);
21173 stmt->setUInt64(0, GetGUID().GetCounter());
21174 trans->Append(stmt);
21175
21176 uint8 index = 0;
21177
21178 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_STATS);
21179 stmt->setUInt64(index++, GetGUID().GetCounter());
21180 stmt->setUInt32(index++, GetMaxHealth());
21181
21182 for (uint8 i = 0; i < MAX_POWERS_PER_CLASS; ++i)
21183 stmt->setUInt32(index++, m_unitData->MaxPower[i]);
21184
21185 for (uint8 i = 0; i < MAX_STATS; ++i)
21186 stmt->setUInt32(index++, GetStat(Stats(i)));
21187
21188 for (int i = 0; i < MAX_SPELL_SCHOOL; ++i)
21189 stmt->setUInt32(index++, GetResistance(SpellSchools(i)));
21190
21191 stmt->setFloat(index++, m_activePlayerData->BlockPercentage);
21192 stmt->setFloat(index++, m_activePlayerData->DodgePercentage);
21193 stmt->setFloat(index++, m_activePlayerData->ParryPercentage);
21194 stmt->setFloat(index++, m_activePlayerData->CritPercentage);
21195 stmt->setFloat(index++, m_activePlayerData->RangedCritPercentage);
21196 stmt->setFloat(index++, m_activePlayerData->SpellCritPercentage);
21197 stmt->setUInt32(index++, m_unitData->AttackPower);
21198 stmt->setUInt32(index++, m_unitData->RangedAttackPower);
21199 stmt->setUInt32(index++, GetBaseSpellPowerBonus());
21200 stmt->setUInt32(index, m_activePlayerData->CombatRatings[CR_RESILIENCE_PLAYER_DAMAGE]);
21201 stmt->setFloat(index++, m_activePlayerData->Mastery);
21202 stmt->setInt32(index++, m_activePlayerData->Versatility);
21203
21204 trans->Append(stmt);
21205}
21206
21208{
21209 if (!sLog->ShouldLog("entities.unit", LOG_LEVEL_DEBUG))
21210 return;
21211
21212 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "HP is: \t\t\t{}\t\tMP is: \t\t\t{}", GetMaxHealth(), GetMaxPower(POWER_MANA));
21213 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "AGILITY is: \t\t{}\t\tSTRENGTH is: \t\t{}", GetStat(STAT_AGILITY), GetStat(STAT_STRENGTH));
21214 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "INTELLECT is: \t\t{}", GetStat(STAT_INTELLECT));
21215 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "STAMINA is: \t\t{}", GetStat(STAT_STAMINA));
21216 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "Armor is: \t\t{}\t\tBlock is: \t\t{}", GetArmor(), *m_activePlayerData->BlockPercentage);
21217 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "HolyRes is: \t\t{}\t\tFireRes is: \t\t{}", GetResistance(SPELL_SCHOOL_MASK_HOLY), GetResistance(SPELL_SCHOOL_MASK_FIRE));
21218 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "NatureRes is: \t\t{}\t\tFrostRes is: \t\t{}", GetResistance(SPELL_SCHOOL_MASK_NATURE), GetResistance(SPELL_SCHOOL_MASK_FROST));
21219 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "ShadowRes is: \t\t{}\t\tArcaneRes is: \t\t{}", GetResistance(SPELL_SCHOOL_MASK_SHADOW), GetResistance(SPELL_SCHOOL_MASK_ARCANE));
21220 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "MIN_DAMAGE is: \t\t{}\tMAX_DAMAGE is: \t\t{}", *m_unitData->MinDamage, *m_unitData->MaxDamage);
21221 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "MIN_OFFHAND_DAMAGE is: \t{}\tMAX_OFFHAND_DAMAGE is: \t{}", *m_unitData->MinOffHandDamage, *m_unitData->MaxOffHandDamage);
21222 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "MIN_RANGED_DAMAGE is: \t{}\tMAX_RANGED_DAMAGE is: \t{}", *m_unitData->MinRangedDamage, *m_unitData->MaxRangedDamage);
21223 sLog->OutMessage("entities.unit", LOG_LEVEL_DEBUG, "ATTACK_TIME is: \t{}\t\tRANGE_ATTACK_TIME is: \t{}", GetBaseAttackTime(BASE_ATTACK), GetBaseAttackTime(RANGED_ATTACK));
21224}
21225
21226/*********************************************************/
21227/*** FLOOD FILTER SYSTEM ***/
21228/*********************************************************/
21229
21231{
21232 // ignore chat spam protection for GMs in any mode
21234 return;
21235
21236 uint32 limit;
21237 uint32 delay;
21238 switch (index)
21239 {
21241 limit = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_COUNT);
21242 delay = sWorld->getIntConfig(CONFIG_CHATFLOOD_MESSAGE_DELAY);
21243 break;
21245 limit = sWorld->getIntConfig(CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT);
21246 delay = sWorld->getIntConfig(CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY);
21247 break;
21248 default:
21249 return;
21250 }
21251
21252 time_t current = GameTime::GetGameTime();
21253 if (m_chatFloodData[index].Time > current)
21254 {
21255 if (!limit)
21256 return;
21257
21258 ++m_chatFloodData[index].Count;
21259 if (m_chatFloodData[index].Count >= limit)
21260 {
21261 // prevent overwrite mute time, if message send just before mutes set, for example.
21262 time_t new_mute = current + sWorld->getIntConfig(CONFIG_CHATFLOOD_MUTE_TIME);
21263 if (GetSession()->m_muteTime < new_mute)
21264 GetSession()->m_muteTime = new_mute;
21265
21266 m_chatFloodData[index].Count = 0;
21267 }
21268 }
21269 else
21270 m_chatFloodData[index].Count = 1;
21271
21272 m_chatFloodData[index].Time = current + delay;
21273}
21274
21275/*********************************************************/
21276/*** LOW LEVEL FUNCTIONS:Notifiers ***/
21277/*********************************************************/
21278
21280{
21282
21283 stmt->setFloat(0, loc.GetPositionX());
21284 stmt->setFloat(1, loc.GetPositionY());
21285 stmt->setFloat(2, loc.GetPositionZ());
21286 stmt->setFloat(3, loc.GetOrientation());
21287 stmt->setUInt16(4, uint16(loc.GetMapId()));
21288 stmt->setUInt16(5, zoneId);
21289 stmt->setUInt64(6, guid.GetCounter());
21290
21291 CharacterDatabase.ExecuteOrAppend(trans, stmt);
21292}
21293
21295{
21297}
21298
21300{
21301 if (err && err != m_swingErrorMsg)
21303
21304 m_swingErrorMsg = err;
21305}
21306
21308{
21310 cancelAutoRepeat.Guid = target->GetGUID(); // may be it's target guid
21311 SendMessageToSet(cancelAutoRepeat.Write(), true);
21312}
21313
21315{
21317}
21318
21319void Player::SendDungeonDifficulty(int32 forcedDifficulty /*= -1*/) const
21320{
21321 WorldPackets::Misc::DungeonDifficultySet dungeonDifficultySet;
21322 dungeonDifficultySet.DifficultyID = forcedDifficulty == -1 ? GetDungeonDifficultyID() : forcedDifficulty;
21323 SendDirectMessage(dungeonDifficultySet.Write());
21324}
21325
21326void Player::SendRaidDifficulty(bool legacy, int32 forcedDifficulty /*= -1*/) const
21327{
21328 WorldPackets::Misc::RaidDifficultySet raidDifficultySet;
21329 raidDifficultySet.DifficultyID = forcedDifficulty == -1 ? (legacy ? GetLegacyRaidDifficultyID() : GetRaidDifficultyID()) : forcedDifficulty;
21330 raidDifficultySet.Legacy = legacy;
21331 SendDirectMessage(raidDifficultySet.Write());
21332}
21333
21335{
21337 SendDirectMessage(data.Write());
21338}
21339
21342{
21343 for (auto itr = m_recentInstances.begin(); itr != m_recentInstances.end(); )
21344 {
21345 Map* map = sMapMgr->FindMap(itr->first, itr->second);
21346 bool forgetInstance = false;
21347 if (map)
21348 {
21349 if (InstanceMap* instance = map->ToInstanceMap())
21350 {
21351 switch (instance->Reset(method))
21352 {
21355 forgetInstance = true;
21356 break;
21358 if (method == InstanceResetMethod::Manual)
21360 else if (method == InstanceResetMethod::OnChangeDifficulty)
21361 forgetInstance = true;
21362 break;
21364 break;
21365 default:
21366 break;
21367 }
21368 }
21369 }
21370
21371 if (forgetInstance)
21372 itr = m_recentInstances.erase(itr);
21373 else
21374 ++itr;
21375 }
21376}
21377
21379{
21381 data.MapID = MapId;
21382 SendDirectMessage(data.Write());
21383}
21384
21386{
21387 /*reasons for instance reset failure:
21388 // 0: There are players inside the instance.
21389 // 1: There are players offline in your party.
21390 // 2>: There are players in your party attempting to zone into an instance.
21391 */
21392
21394 data.MapID = mapID;
21395 data.ResetFailedReason = reason;
21396 SendDirectMessage(data.Write());
21397}
21398
21399bool Player::IsLockedToDungeonEncounter(uint32 dungeonEncounterId) const
21400{
21401 DungeonEncounterEntry const* dungeonEncounter = sDungeonEncounterStore.LookupEntry(dungeonEncounterId);
21402 if (!dungeonEncounter)
21403 return false;
21404
21405 InstanceLock const* instanceLock = sInstanceLockMgr.FindActiveInstanceLock(GetGUID(), { GetMap()->GetEntry(), GetMap()->GetMapDifficulty() });
21406 if (!instanceLock)
21407 return false;
21408
21409 return (instanceLock->GetData()->CompletedEncountersMask & (1u << dungeonEncounter->Bit)) != 0;
21410}
21411
21412bool Player::IsLockedToDungeonEncounter(uint32 dungeonEncounterId, Difficulty difficulty) const
21413{
21414 DungeonEncounterEntry const* dungeonEncounter = sDungeonEncounterStore.LookupEntry(dungeonEncounterId);
21415 if (!dungeonEncounter)
21416 return false;
21417
21418 InstanceLock const* instanceLock = sInstanceLockMgr.FindActiveInstanceLock(GetGUID(), { uint32(dungeonEncounter->MapID), difficulty });
21419 if (!instanceLock)
21420 return false;
21421
21422 return (instanceLock->GetData()->CompletedEncountersMask & (1u << dungeonEncounter->Bit)) != 0;
21423}
21424
21425/*********************************************************/
21426/*** Update timers ***/
21427/*********************************************************/
21428
21430void Player::UpdateAfkReport(time_t currTime)
21431{
21432 if (m_bgData.bgAfkReportedTimer <= currTime)
21433 {
21435 m_bgData.bgAfkReportedTimer = currTime+5*MINUTE;
21436 }
21437}
21438
21439void Player::SetContestedPvP(Player* attackedPlayer)
21440{
21441 if (attackedPlayer && (attackedPlayer == this || (duel && duel->Opponent == attackedPlayer)))
21442 return;
21443
21444 SetContestedPvPTimer(30000);
21446 {
21449 // call MoveInLineOfSight for nearby contested guards
21450 Trinity::AIRelocationNotifier notifier(*this);
21452 }
21453 for (Unit* unit : m_Controlled)
21454 {
21455 if (!unit->HasUnitState(UNIT_STATE_ATTACK_PLAYER))
21456 {
21457 unit->AddUnitState(UNIT_STATE_ATTACK_PLAYER);
21458 Trinity::AIRelocationNotifier notifier(*unit);
21460 }
21461 }
21462}
21463
21465{
21467 return;
21468
21469 if (m_contestedPvPTimer <= diff)
21471 else
21472 m_contestedPvPTimer -= diff;
21473}
21474
21476{
21480}
21481
21482void Player::UpdatePvPFlag(time_t currTime)
21483{
21484 if (!IsPvP())
21485 return;
21486
21487 if (!pvpInfo.EndTimer || (currTime < pvpInfo.EndTimer +300) || pvpInfo.IsHostile)
21488 return;
21489
21490 if (pvpInfo.EndTimer <= currTime)
21491 {
21492 pvpInfo.EndTimer = 0;
21494 }
21495
21496 UpdatePvP(false);
21497}
21498
21499void Player::UpdateDuelFlag(time_t currTime)
21500{
21501 if (duel && duel->State == DUEL_STATE_COUNTDOWN && duel->StartTime <= currTime)
21502 {
21503 sScriptMgr->OnPlayerDuelStart(this, duel->Opponent);
21504
21505 SetDuelTeam(1);
21506 duel->Opponent->SetDuelTeam(2);
21507
21509 duel->Opponent->duel->State = DUEL_STATE_IN_PROGRESS;
21510 }
21511}
21512
21514{
21515 ObjectGuid pet_guid = GetPetGUID();
21516 if (!pet_guid.IsEmpty())
21517 {
21518 if (!pet_guid.IsPet())
21519 return nullptr;
21520
21521 Pet* pet = ObjectAccessor::GetPet(*this, pet_guid);
21522
21523 if (!pet)
21524 return nullptr;
21525
21526 if (IsInWorld())
21527 return pet;
21528
21529 // there may be a guardian in this slot
21530 //TC_LOG_ERROR("entities.player", "Player::GetPet: Pet {} does not exist.", GUID_LOPART(pet_guid));
21531 //const_cast<Player*>(this)->SetPetGUID(0);
21532 }
21533
21534 return nullptr;
21535}
21536
21537void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
21538{
21539 if (!pet)
21540 pet = GetPet();
21541
21542 if (pet)
21543 {
21544 TC_LOG_DEBUG("entities.pet", "Player::RemovePet: Player '{}' ({}), Pet (Entry: {}, Mode: {}, ReturnReagent: {})",
21545 GetName(), GetGUID().ToString(), pet->GetEntry(), mode, returnreagent);
21546
21547 if (pet->m_removed)
21548 return;
21549 }
21550
21551 if (returnreagent && (pet || m_temporaryUnsummonedPetNumber) && !InBattleground())
21552 {
21553 //returning of reagents only for players, so best done here
21554 uint32 spellId = pet ? *pet->m_unitData->CreatedBySpell : m_oldpetspell;
21555 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID());
21556
21557 if (spellInfo)
21558 {
21559 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; ++i)
21560 {
21561 if (spellInfo->Reagent[i] > 0)
21562 {
21563 ItemPosCountVec dest; //for succubus, voidwalker, felhunter and felguard credit soulshard when despawn reason other than death (out of range, logout)
21564 InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellInfo->Reagent[i], spellInfo->ReagentCount[i]);
21565 if (msg == EQUIP_ERR_OK)
21566 {
21567 Item* item = StoreNewItem(dest, spellInfo->Reagent[i], true);
21568 if (IsInWorld())
21569 SendNewItem(item, spellInfo->ReagentCount[i], true, false);
21570 }
21571 }
21572 }
21573 }
21575 }
21576
21577 if (!pet)
21578 {
21579 // Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
21580 if (mode == PET_SAVE_NOT_IN_SLOT && m_petStable && m_petStable->CurrentPetIndex)
21581 m_petStable->CurrentPetIndex.reset();
21582
21583 return;
21584 }
21585
21586 pet->CombatStop();
21587
21588 // only if current pet in slot
21589 pet->SavePetToDB(mode);
21590
21591 PetStable::PetInfo const* currentPet = m_petStable->GetCurrentPet();
21592 ASSERT(currentPet && currentPet->PetNumber == pet->GetCharmInfo()->GetPetNumber());
21593 if (mode == PET_SAVE_NOT_IN_SLOT)
21594 m_petStable->CurrentPetIndex.reset();
21595 else if (mode == PET_SAVE_AS_DELETED)
21596 {
21597 if (m_activePlayerData->PetStable.has_value())
21598 {
21599 int32 ufIndex = m_activePlayerData->PetStable->Pets.FindIndexIf([currentPet](UF::StablePetInfo const& p) { return p.PetNumber == currentPet->PetNumber; });
21600 if (ufIndex >= 0)
21602 .ModifyValue(&UF::ActivePlayerData::PetStable, 0)
21603 .ModifyValue(&UF::StableInfo::Pets), ufIndex);
21604 }
21605
21606 if (Optional<uint32> petIndex = m_petStable->GetCurrentActivePetIndex())
21607 m_petStable->ActivePets[*petIndex].reset();
21608
21609 m_petStable->CurrentPetIndex.reset();
21610 }
21611 // else if (stable slots) handled in opcode handlers due to required swaps
21612 // else (current pet) doesnt need to do anything
21613
21614 SetMinion(pet, false);
21615
21616 pet->AddObjectToRemoveList();
21617 pet->m_removed = true;
21618
21619 if (pet->isControlled())
21620 {
21621 WorldPackets::Pet::PetSpells petSpellsPacket;
21622 SendDirectMessage(petSpellsPacket.Write());
21623
21624 if (GetGroup())
21626 }
21627}
21628
21630{
21631 WorldPackets::Pet::PetTameFailure petTameFailure;
21632 petTameFailure.Result = AsUnderlyingType(result);
21633 SendDirectMessage(petTameFailure.Write());
21634}
21635
21636void Player::AddPetAura(PetAura const* petSpell)
21637{
21638 m_petAuras.insert(petSpell);
21639 if (Pet* pet = GetPet())
21640 pet->CastPetAura(petSpell);
21641}
21642
21643void Player::RemovePetAura(PetAura const* petSpell)
21644{
21645 m_petAuras.erase(petSpell);
21646 if (Pet* pet = GetPet())
21647 pet->RemoveAurasDueToSpell(petSpell->GetAura(pet->GetEntry()));
21648}
21649
21651{
21652 if (Creature* summonedBattlePet = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, GetCritterGUID()))
21653 if (!GetSummonedBattlePetGUID().IsEmpty() && GetSummonedBattlePetGUID() == summonedBattlePet->GetBattlePetCompanionGUID())
21654 return summonedBattlePet;
21655
21656 return nullptr;
21657}
21658
21660{
21661 if (pet)
21662 {
21667 }
21668 else
21669 {
21674 }
21675}
21676
21678{
21679 Unit* charm = GetCharmed();
21680 if (!charm)
21681 return;
21682
21683 if (charm->GetTypeId() == TYPEID_UNIT)
21684 {
21686 static_cast<Puppet*>(charm)->UnSummon();
21687 else if (charm->IsVehicle())
21688 {
21689 ExitVehicle();
21690
21691 // Temporary for issue https://github.com/TrinityCore/TrinityCore/issues/24876
21693 {
21694 TC_LOG_FATAL("entities.player", "Player::StopCastingCharm Player '{}' ({}) is not able to uncharm vehicle ({}) because of missing SPELL_AURA_CONTROL_VEHICLE",
21696
21697 // attempt to recover from missing HandleAuraControlVehicle unapply handling
21698 // THIS IS A HACK, NEED TO FIND HOW IS IT EVEN POSSBLE TO NOT HAVE THE AURA
21699 _ExitVehicle();
21700 }
21701 }
21702 }
21703 if (!GetCharmedGUID().IsEmpty())
21704 charm->RemoveCharmAuras();
21705
21706 if (!GetCharmedGUID().IsEmpty())
21707 {
21708 TC_LOG_FATAL("entities.player", "Player::StopCastingCharm: Player '{}' ({}) is not able to uncharm unit ({})", GetName(), GetGUID().ToString(), GetCharmedGUID().ToString());
21709 if (!charm->GetCharmerGUID().IsEmpty())
21710 {
21711 TC_LOG_FATAL("entities.player", "Player::StopCastingCharm: Charmed unit has charmer {}\nPlayer debug info: {}\nCharm debug info: {}",
21712 charm->GetCharmerGUID().ToString(), GetDebugInfo(), charm->GetDebugInfo());
21713 ABORT();
21714 }
21715
21716 SetCharm(charm, false);
21717 }
21718}
21719
21720void Player::Say(std::string_view text, Language language, WorldObject const* /*= nullptr*/)
21721{
21722 std::string _text(text);
21723 sScriptMgr->OnPlayerChat(this, CHAT_MSG_SAY, language, _text);
21724
21725 SendChatMessageToSetInRange(CHAT_MSG_SAY, language, std::move(_text), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY));
21726}
21727
21728void Player::SendChatMessageToSetInRange(ChatMsg chatMsg, Language language, std::string&& text, float range)
21729{
21730 Trinity::CustomChatTextBuilder builder(this, chatMsg, std::move(text), language, this);
21732
21733 // Send to self
21734 localizer(this);
21735
21736 // Send to players
21737 Trinity::MessageDistDeliverer<Trinity::LocalizedDo<Trinity::CustomChatTextBuilder>> notifier(this, localizer, range, false, nullptr, true);
21738 Cell::VisitWorldObjects(this, notifier, range);
21739}
21740
21741void Player::Say(uint32 textId, WorldObject const* target /*= nullptr*/)
21742{
21743 Talk(textId, CHAT_MSG_SAY, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), target);
21744}
21745
21746void Player::Yell(std::string_view text, Language language, WorldObject const* /*= nullptr*/)
21747{
21748 std::string _text(text);
21749 sScriptMgr->OnPlayerChat(this, CHAT_MSG_YELL, language, _text);
21750
21751 SendChatMessageToSetInRange(CHAT_MSG_YELL, language, std::move(_text), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL));
21752}
21753
21754void Player::Yell(uint32 textId, WorldObject const* target /*= nullptr*/)
21755{
21756 Talk(textId, CHAT_MSG_YELL, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_YELL), target);
21757}
21758
21759void Player::TextEmote(std::string_view text, WorldObject const* /*= nullptr*/, bool /*= false*/)
21760{
21761 std::string _text(text);
21762 sScriptMgr->OnPlayerChat(this, CHAT_MSG_EMOTE, LANG_UNIVERSAL, _text);
21763
21765 packet.Initialize(CHAT_MSG_EMOTE, LANG_UNIVERSAL, this, this, _text);
21767}
21768
21769void Player::WhisperAddon(std::string const& text, std::string const& prefix, bool isLogged, Player* receiver)
21770{
21771 std::string _text(text);
21772 sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, uint32(isLogged ? LANG_ADDON_LOGGED : LANG_ADDON), _text, receiver);
21773
21774 if (!receiver->GetSession()->IsAddonRegistered(prefix))
21775 return;
21776
21778 packet.Initialize(CHAT_MSG_WHISPER, isLogged ? LANG_ADDON_LOGGED : LANG_ADDON, this, this, text, 0, "", DEFAULT_LOCALE, prefix);
21779 receiver->SendDirectMessage(packet.Write());
21780}
21781
21782void Player::TextEmote(uint32 textId, WorldObject const* target /*= nullptr*/, bool /*isBossEmote = false*/)
21783{
21784 Talk(textId, CHAT_MSG_EMOTE, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_TEXTEMOTE), target);
21785}
21786
21787void Player::Whisper(std::string_view text, Language language, Player* target, bool /*= false*/)
21788{
21789 ASSERT(target);
21790
21791 bool isAddonMessage = language == LANG_ADDON;
21792
21793 if (!isAddonMessage) // if not addon data
21794 language = LANG_UNIVERSAL; // whispers should always be readable
21795
21796 std::string _text(text);
21797 sScriptMgr->OnPlayerChat(this, CHAT_MSG_WHISPER, language, _text, target);
21798
21800 packet.Initialize(CHAT_MSG_WHISPER, language, this, this, _text);
21801 target->SendDirectMessage(packet.Write());
21802
21803 // rest stuff shouldn't happen in case of addon message
21804 if (isAddonMessage)
21805 return;
21806
21807 packet.Initialize(CHAT_MSG_WHISPER_INFORM, language, target, target, _text);
21808 SendDirectMessage(packet.Write());
21809
21810 if (!isAcceptWhispers() && !IsGameMaster() && !target->IsGameMaster())
21811 {
21812 SetAcceptWhispers(true);
21814 }
21815
21816 // announce afk or dnd message
21817 if (target->isAFK())
21818 ChatHandler(GetSession()).PSendSysMessage(LANG_PLAYER_AFK, target->GetName().c_str(), target->autoReplyMsg.c_str());
21819 else if (target->isDND())
21820 ChatHandler(GetSession()).PSendSysMessage(LANG_PLAYER_DND, target->GetName().c_str(), target->autoReplyMsg.c_str());
21821}
21822
21823void Player::Whisper(uint32 textId, Player* target, bool /*isBossWhisper = false*/)
21824{
21825 if (!target)
21826 return;
21827
21828 BroadcastTextEntry const* bct = sBroadcastTextStore.LookupEntry(textId);
21829 if (!bct)
21830 {
21831 TC_LOG_ERROR("entities.unit", "WorldObject::Whisper: `broadcast_text` was not {} found", textId);
21832 return;
21833 }
21834
21838 target->SendDirectMessage(packet.Write());
21839}
21840
21842{
21843 if (IsGameMaster())
21844 return true;
21845
21846 for (std::pair<uint32 const, LanguageDesc> const& languageDesc : sLanguageMgr->GetLanguageDescById(language))
21847 if (languageDesc.second.SkillId && HasSkill(languageDesc.second.SkillId))
21848 return true;
21849
21851 return true;
21852
21853 return false;
21854}
21855
21857{
21858 ItemMap::const_iterator itr = mMitems.find(id);
21859 return itr != mMitems.end() ? itr->second : nullptr;
21860}
21861
21863{
21864 ASSERT(it);
21865 //ASSERT deleted, because items can be added before loading
21866 mMitems[it->GetGUID().GetCounter()] = it;
21867}
21868
21870{
21871 return mMitems.erase(id) ? true : false;
21872}
21873
21875{
21877}
21878
21880{
21881 Pet* pet = GetPet();
21882
21883 if (!pet)
21884 return;
21885
21886 CharmInfo* charmInfo = pet->GetCharmInfo();
21887
21888 WorldPackets::Pet::PetSpells petSpellsPacket;
21889 petSpellsPacket.PetGUID = pet->GetGUID();
21890 petSpellsPacket._CreatureFamily = pet->GetCreatureTemplate()->family; // creature family (required for pet talents)
21891 petSpellsPacket.Specialization = pet->GetSpecialization();
21892 petSpellsPacket.TimeLimit = pet->GetDuration();
21893 petSpellsPacket.ReactState = pet->GetReactState();
21894 petSpellsPacket.CommandState = charmInfo->GetCommandState();
21895
21896 // action bar loop
21897 for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
21898 petSpellsPacket.ActionButtons[i] = charmInfo->GetActionBarEntry(i)->packedData;
21899
21900 if (pet->IsPermanentPetFor(this))
21901 {
21902 // spells loop
21903 for (PetSpellMap::iterator itr = pet->m_spells.begin(); itr != pet->m_spells.end(); ++itr)
21904 {
21905 if (itr->second.state == PETSPELL_REMOVED)
21906 continue;
21907
21908 petSpellsPacket.Actions.push_back(MAKE_UNIT_ACTION_BUTTON(itr->first, itr->second.active));
21909 }
21910 }
21911
21912 // Cooldowns
21913 pet->GetSpellHistory()->WritePacket(&petSpellsPacket);
21914
21915 SendDirectMessage(petSpellsPacket.Write());
21916}
21917
21919{
21920 Unit* charm = GetCharmed();
21921 if (!charm)
21922 return;
21923
21924 CharmInfo* charmInfo = charm->GetCharmInfo();
21925
21926 if (!charmInfo)
21927 {
21928 TC_LOG_ERROR("entities.player", "Player::PossessSpellInitialize: charm ({}) has no charminfo!", charm->GetGUID().ToString());
21929 return;
21930 }
21931
21932 WorldPackets::Pet::PetSpells petSpellsPacket;
21933 petSpellsPacket.PetGUID = charm->GetGUID();
21934
21935 for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
21936 petSpellsPacket.ActionButtons[i] = charmInfo->GetActionBarEntry(i)->packedData;
21937
21938 // Cooldowns
21939 charm->GetSpellHistory()->WritePacket(&petSpellsPacket);
21940
21941 SendDirectMessage(petSpellsPacket.Write());
21942}
21943
21945{
21946 Creature* vehicle = GetVehicleCreatureBase();
21947 if (!vehicle)
21948 return;
21949
21951 petSpells.PetGUID = vehicle->GetGUID();
21952 petSpells._CreatureFamily = 0; // Pet Family (0 for all vehicles)
21953 petSpells.Specialization = 0;
21954 petSpells.TimeLimit = vehicle->IsSummon() ? vehicle->ToTempSummon()->GetTimer().count() : 0;
21955 petSpells.ReactState = vehicle->GetReactState();
21956 petSpells.CommandState = COMMAND_FOLLOW;
21957 petSpells.Flag = 0x8;
21958
21959 for (uint32 i = 0; i < MAX_SPELL_CONTROL_BAR; ++i)
21960 petSpells.ActionButtons[i] = MAKE_UNIT_ACTION_BUTTON(0, i + 8);
21961
21962 for (uint32 i = 0; i < MAX_CREATURE_SPELLS; ++i)
21963 {
21964 uint32 spellId = vehicle->m_spells[i];
21965 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID());
21966 if (!spellInfo)
21967 continue;
21968
21970 continue;
21971
21972 if (!sConditionMgr->IsObjectMeetingVehicleSpellConditions(vehicle->GetEntry(), spellId, this, vehicle))
21973 {
21974 TC_LOG_DEBUG("condition", "Player::VehicleSpellInitialize: Player '{}' ({}) doesn't meet conditions for vehicle (Entry: {}, Spell: {})",
21975 GetName(), GetGUID().ToString(), vehicle->ToCreature()->GetEntry(), spellId);
21976 continue;
21977 }
21978
21979 if (spellInfo->IsPassive())
21980 vehicle->CastSpell(vehicle, spellInfo->Id, true);
21981
21982 petSpells.ActionButtons[i] = MAKE_UNIT_ACTION_BUTTON(spellId, i + 8);
21983 }
21984
21985 // Cooldowns
21986 vehicle->GetSpellHistory()->WritePacket(&petSpells);
21987
21988 SendDirectMessage(petSpells.Write());
21989}
21990
21992{
21993 Unit* charm = GetFirstControlled();
21994 if (!charm)
21995 return;
21996
21997 CharmInfo* charmInfo = charm->GetCharmInfo();
21998 if (!charmInfo)
21999 {
22000 TC_LOG_ERROR("entities.player", "Player::CharmSpellInitialize(): Player '{}' ({}) has a charm ({}) but no no charminfo!",
22001 GetName(), GetGUID().ToString(), charm->GetGUID().ToString());
22002 return;
22003 }
22004
22006 petSpells.PetGUID = charm->GetGUID();
22007
22008 if (charm->GetTypeId() == TYPEID_UNIT)
22009 {
22010 petSpells.ReactState = charm->ToCreature()->GetReactState();
22011 petSpells.CommandState = charmInfo->GetCommandState();
22012 }
22013
22014 for (uint32 i = 0; i < MAX_UNIT_ACTION_BAR_INDEX; ++i)
22015 petSpells.ActionButtons[i] = charmInfo->GetActionBarEntry(i)->packedData;
22016
22017 for (uint32 i = 0; i < MAX_SPELL_CHARM; ++i)
22018 {
22019 CharmSpellInfo* cspell = charmInfo->GetCharmSpell(i);
22020 if (cspell->GetAction())
22021 petSpells.Actions.push_back(cspell->packedData);
22022 }
22023
22024 // Cooldowns
22025 if (charm->GetTypeId() != TYPEID_PLAYER)
22026 charm->GetSpellHistory()->WritePacket(&petSpells);
22027
22028 SendDirectMessage(petSpells.Write());
22029}
22030
22032{
22034 SendDirectMessage(packet.Write());
22035}
22036
22037bool Player::IsAffectedBySpellmod(SpellInfo const* spellInfo, SpellModifier const* mod, Spell* spell)
22038{
22039 if (!mod || !spellInfo)
22040 return false;
22041
22042 // First time this aura applies a mod to us and is out of charges
22043 if (spell && mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges() && !spell->m_appliedMods.count(mod->ownerAura))
22044 return false;
22045
22046 switch (mod->op)
22047 {
22048 case SpellModOp::Duration: // +duration to infinite duration spells making them limited
22049 if (spellInfo->GetDuration() == -1)
22050 return false;
22051 break;
22052 case SpellModOp::CritChance: // mod crit to spells that can't crit
22053 if (!spellInfo->HasAttribute(SPELL_ATTR0_CU_CAN_CRIT))
22054 return false;
22055 break;
22056 case SpellModOp::PointsIndex0: // check if spell has any effect at that index
22057 case SpellModOp::Points:
22058 if (spellInfo->GetEffects().size() <= EFFECT_0)
22059 return false;
22060 break;
22061 case SpellModOp::PointsIndex1: // check if spell has any effect at that index
22062 if (spellInfo->GetEffects().size() <= EFFECT_1)
22063 return false;
22064 break;
22065 case SpellModOp::PointsIndex2: // check if spell has any effect at that index
22066 if (spellInfo->GetEffects().size() <= EFFECT_2)
22067 return false;
22068 break;
22069 case SpellModOp::PointsIndex3: // check if spell has any effect at that index
22070 if (spellInfo->GetEffects().size() <= EFFECT_3)
22071 return false;
22072 break;
22073 case SpellModOp::PointsIndex4: // check if spell has any effect at that index
22074 if (spellInfo->GetEffects().size() <= EFFECT_4)
22075 return false;
22076 break;
22077 default:
22078 break;
22079 }
22080
22081 return spellInfo->IsAffectedBySpellMod(mod);
22082}
22083
22084template <class T>
22085void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, T base, int32* flat, float* pct) const
22086{
22087 ASSERT(flat && pct);
22088
22089 *flat = 0;
22090 *pct = 1.0f;
22091
22092 // Drop charges for triggering spells instead of triggered ones
22094 spell = m_spellModTakingSpell;
22095
22096 switch (op)
22097 {
22098 // special case, if a mod makes spell instant, only consume that mod
22100 {
22101 SpellModifier* modInstantSpell = nullptr;
22103 {
22104 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22105 continue;
22106
22107 if (base < T(10000) && static_cast<SpellModifierByClassMask*>(mod)->value <= -100)
22108 {
22109 modInstantSpell = mod;
22110 break;
22111 }
22112 }
22113
22114 if (!modInstantSpell)
22115 {
22117 {
22118 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22119 continue;
22120
22121 if (base < T(10000) && static_cast<SpellPctModifierByLabel*>(mod)->value.ModifierValue <= -1.0f)
22122 {
22123 modInstantSpell = mod;
22124 break;
22125 }
22126 }
22127 }
22128
22129 if (modInstantSpell)
22130 {
22131 Player::ApplyModToSpell(modInstantSpell, spell);
22132 *pct = 0.0f;
22133 return;
22134 }
22135 break;
22136 }
22137 // special case if two mods apply 100% critical chance, only consume one
22139 {
22140 SpellModifier* modCritical = nullptr;
22142 {
22143 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22144 continue;
22145
22146 if (static_cast<SpellModifierByClassMask*>(mod)->value >= 100)
22147 {
22148 modCritical = mod;
22149 break;
22150 }
22151 }
22152
22153 if (!modCritical)
22154 {
22156 {
22157 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22158 continue;
22159
22160 if (static_cast<SpellFlatModifierByLabel*>(mod)->value.ModifierValue >= 100)
22161 {
22162 modCritical = mod;
22163 break;
22164 }
22165 }
22166 }
22167
22168 if (modCritical)
22169 {
22170 Player::ApplyModToSpell(modCritical, spell);
22171 *flat = 100;
22172 return;
22173 }
22174 break;
22175 }
22176 default:
22177 break;
22178 }
22179
22181 {
22182 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22183 continue;
22184
22185 int32 value = static_cast<SpellModifierByClassMask*>(mod)->value;
22186 if (value == 0)
22187 continue;
22188
22189 *flat += value;
22190 Player::ApplyModToSpell(mod, spell);
22191 }
22192
22194 {
22195 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22196 continue;
22197
22198 int32 value = static_cast<SpellFlatModifierByLabel*>(mod)->value.ModifierValue;
22199 if (value == 0)
22200 continue;
22201
22202 *flat += value;
22203 Player::ApplyModToSpell(mod, spell);
22204 }
22205
22207 {
22208 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22209 continue;
22210
22211 // skip percent mods for null basevalue (most important for spell mods with charges)
22212 if (base + *flat == T(0))
22213 continue;
22214
22215 int32 value = static_cast<SpellModifierByClassMask*>(mod)->value;
22216 if (value == 0)
22217 continue;
22218
22219 // special case (skip > 10sec spell casts for instant cast setting)
22221 {
22222 if (base >= T(10000) && value <= -100)
22223 continue;
22224 }
22225
22226 *pct *= 1.0f + CalculatePct(1.0f, value);
22227 Player::ApplyModToSpell(mod, spell);
22228 }
22229
22231 {
22232 if (!IsAffectedBySpellmod(spellInfo, mod, spell))
22233 continue;
22234
22235 // skip percent mods for null basevalue (most important for spell mods with charges)
22236 if (base + *flat == T(0))
22237 continue;
22238
22239 float value = static_cast<SpellPctModifierByLabel*>(mod)->value.ModifierValue;
22240 if (value == 1.0f)
22241 continue;
22242
22243 // special case (skip > 10sec spell casts for instant cast setting)
22245 {
22246 if (base >= T(10000) && value <= -1.0f)
22247 continue;
22248 }
22249
22250 *pct *= value;
22251 Player::ApplyModToSpell(mod, spell);
22252 }
22253}
22254
22255template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, int32 base, int32* flat, float* pct) const;
22256template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, uint32 base, int32* flat, float* pct) const;
22257template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, float base, int32* flat, float* pct) const;
22258template TC_GAME_API void Player::GetSpellModValues(SpellInfo const* spellInfo, SpellModOp op, Spell* spell, double base, int32* flat, float* pct) const;
22259
22260template <class T>
22261void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, T& basevalue, Spell* spell /*= nullptr*/) const
22262{
22263 float totalmul = 1.0f;
22264 int32 totalflat = 0;
22265
22266 GetSpellModValues(spellInfo, op, spell, basevalue, &totalflat, &totalmul);
22267
22268 basevalue = T(double(basevalue + totalflat) * totalmul);
22269}
22270
22271template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, int32& basevalue, Spell* spell) const;
22272template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, uint32& basevalue, Spell* spell) const;
22273template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, float& basevalue, Spell* spell) const;
22274template TC_GAME_API void Player::ApplySpellMod(SpellInfo const* spellInfo, SpellModOp op, double& basevalue, Spell* spell) const;
22275
22277{
22278 TC_LOG_DEBUG("spells", "Player::AddSpellMod: Player '{}' ({}), SpellID: {}", GetName(), GetGUID().ToString(), mod->spellId);
22279
22281 if (apply)
22282 m_spellMods[AsUnderlyingType(mod->op)][mod->type].insert(mod);
22283 else
22284 m_spellMods[AsUnderlyingType(mod->op)][mod->type].erase(mod);
22285
22287 switch (mod->type)
22288 {
22289 case SPELLMOD_FLAT:
22290 case SPELLMOD_PCT:
22291 if (!IsLoading())
22292 {
22294
22296
22298 packet.Modifiers.resize(1);
22299 WorldPackets::Spells::SpellModifier& spellMod = packet.Modifiers[0];
22300
22301 spellMod.ModIndex = AsUnderlyingType(mod->op);
22302
22303 for (int eff = 0; eff < 128; ++eff)
22304 {
22305 flag128 mask;
22306 mask[eff / 32] = 1u << (eff % 32);
22307 if (static_cast<SpellModifierByClassMask const*>(mod)->mask & mask)
22308 {
22310
22311 if (mod->type == SPELLMOD_FLAT)
22312 {
22313 modData.ModifierValue = 0.0f;
22315 if (static_cast<SpellModifierByClassMask const*>(spellMod)->mask & mask)
22316 modData.ModifierValue += static_cast<SpellModifierByClassMask const*>(spellMod)->value;
22317 }
22318 else
22319 {
22320 modData.ModifierValue = 1.0f;
22321 for (SpellModifier* spellMod : m_spellMods[AsUnderlyingType(mod->op)][SPELLMOD_PCT])
22322 if (static_cast<SpellModifierByClassMask const*>(spellMod)->mask & mask)
22323 modData.ModifierValue *= 1.0f + CalculatePct(1.0f, static_cast<SpellModifierByClassMask const*>(spellMod)->value);
22324 }
22325
22326 modData.ClassIndex = eff;
22327
22328 spellMod.ModifierData.push_back(modData);
22329 }
22330 }
22331
22332 SendDirectMessage(packet.Write());
22333 }
22334 break;
22336 if (apply)
22337 {
22339 .ModifyValue(&UF::ActivePlayerData::SpellFlatModByLabel)) = static_cast<SpellFlatModifierByLabel const*>(mod)->value;
22340 }
22341 else
22342 {
22343 int32 firstIndex = m_activePlayerData->SpellFlatModByLabel.FindIndex(static_cast<SpellFlatModifierByLabel const*>(mod)->value);
22344 if (firstIndex >= 0)
22346 .ModifyValue(&UF::ActivePlayerData::SpellFlatModByLabel), firstIndex);
22347 }
22348 break;
22349 case SPELLMOD_LABEL_PCT:
22350 if (apply)
22351 {
22353 .ModifyValue(&UF::ActivePlayerData::SpellPctModByLabel)) = static_cast<SpellPctModifierByLabel const*>(mod)->value;
22354 }
22355 else
22356 {
22357 int32 firstIndex = m_activePlayerData->SpellPctModByLabel.FindIndex(static_cast<SpellPctModifierByLabel const*>(mod)->value);
22358 if (firstIndex >= 0)
22360 .ModifyValue(&UF::ActivePlayerData::SpellPctModByLabel), firstIndex);
22361 }
22362 break;
22363 default:
22364 break;
22365 }
22366}
22367
22369{
22370 if (!spell)
22371 return;
22372
22373 // don't do anything with no charges
22374 if (mod->ownerAura->IsUsingCharges() && !mod->ownerAura->GetCharges())
22375 return;
22376
22377 // register inside spell, proc system uses this to drop charges
22378 spell->m_appliedMods.insert(mod->ownerAura);
22379}
22380
22382{
22383 if (apply && m_spellModTakingSpell != nullptr)
22384 return;
22385
22386 if (!apply && (!m_spellModTakingSpell || m_spellModTakingSpell != spell))
22387 return;
22388
22389 m_spellModTakingSpell = apply ? spell : nullptr;
22390}
22391
22393{
22396 for (uint8 i = 0; i < MAX_SPELLMOD; ++i)
22397 {
22399 flatMod.ModifierData.resize(128);
22401 pctMod.ModifierData.resize(128);
22402 flatMod.ModIndex = pctMod.ModIndex = i;
22403 for (uint8 j = 0; j < 128; ++j)
22404 {
22405 flag128 mask;
22406 mask[j / 32] = 1u << (j % 32);
22407
22408 flatMod.ModifierData[j].ClassIndex = j;
22409 flatMod.ModifierData[j].ModifierValue = 0.0f;
22410 pctMod.ModifierData[j].ClassIndex = j;
22411 pctMod.ModifierData[j].ModifierValue = 1.0f;
22412
22413 for (SpellModifier* mod : m_spellMods[i][SPELLMOD_FLAT])
22414 if (static_cast<SpellModifierByClassMask const*>(mod)->mask & mask)
22415 flatMod.ModifierData[j].ModifierValue += static_cast<SpellModifierByClassMask const*>(mod)->value;
22416
22417 for (SpellModifier* mod : m_spellMods[i][SPELLMOD_PCT])
22418 if (static_cast<SpellModifierByClassMask const*>(mod)->mask & mask)
22419 pctMod.ModifierData[j].ModifierValue *= 1.0f + CalculatePct(1.0f, static_cast<SpellModifierByClassMask const*>(mod)->value);
22420 }
22421
22422 flatMod.ModifierData.erase(std::remove_if(flatMod.ModifierData.begin(), flatMod.ModifierData.end(), [](WorldPackets::Spells::SpellModifierData const& mod)
22423 {
22424 return G3D::fuzzyEq(mod.ModifierValue, 0.0f);
22425 }), flatMod.ModifierData.end());
22426
22427 pctMod.ModifierData.erase(std::remove_if(pctMod.ModifierData.begin(), pctMod.ModifierData.end(), [](WorldPackets::Spells::SpellModifierData const& mod)
22428 {
22429 return G3D::fuzzyEq(mod.ModifierValue, 1.0f);
22430 }), pctMod.ModifierData.end());
22431
22432 flatMods.Modifiers.emplace_back(std::move(flatMod));
22433 pctMods.Modifiers.emplace_back(std::move(pctMod));
22434 }
22435
22436 if (!flatMods.Modifiers.empty())
22437 SendDirectMessage(flatMods.Write());
22438
22439 if (!pctMods.Modifiers.empty())
22440 SendDirectMessage(pctMods.Write());
22441}
22442
22443// send Proficiency
22444void Player::SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const
22445{
22447 packet.ProficiencyMask = itemSubclassMask;
22448 packet.ProficiencyClass = itemClass;
22449 SendDirectMessage(packet.Write());
22450}
22451
22453{
22454 sPetitionMgr->RemoveSignaturesBySigner(guid);
22455 sPetitionMgr->RemovePetitionsByOwner(guid);
22456}
22457
22458void Player::SetPersonalTabard(uint32 style, uint32 color, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
22459{
22460 auto personalTabard = m_values.ModifyValue(&Player::m_playerData).ModifyValue(&UF::PlayerData::PersonalTabard);
22461 SetUpdateFieldValue(personalTabard.ModifyValue(&UF::CustomTabardInfo::EmblemStyle), style);
22462 SetUpdateFieldValue(personalTabard.ModifyValue(&UF::CustomTabardInfo::EmblemColor), color);
22463 SetUpdateFieldValue(personalTabard.ModifyValue(&UF::CustomTabardInfo::BorderStyle), borderStyle);
22464 SetUpdateFieldValue(personalTabard.ModifyValue(&UF::CustomTabardInfo::BorderColor), borderColor);
22465 SetUpdateFieldValue(personalTabard.ModifyValue(&UF::CustomTabardInfo::BackgroundColor), backgroundColor);
22466}
22467
22469{
22470 CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(guid);
22471 if (!characterInfo)
22472 return;
22473
22474 for (uint8 i = 0; i < MAX_ARENA_SLOT; ++i)
22475 {
22476 uint32 arenaTeamId = characterInfo->ArenaTeamId[i];
22477 if (arenaTeamId != 0)
22478 {
22479 ArenaTeam* arenaTeam = sArenaTeamMgr->GetArenaTeamById(arenaTeamId);
22480 if (arenaTeam)
22481 arenaTeam->DelMember(guid, true);
22482 }
22483 }
22484}
22485
22487{
22488 if (UF::PVPInfo const* pvpInfo = GetPvpInfoForBracket(slot))
22489 return pvpInfo->Rating;
22490
22491 return 0;
22492}
22493
22495{
22496 int32 index = m_activePlayerData->PvpInfo.FindIndexIf([bracket](UF::PVPInfo const& pvpInfo)
22497 {
22498 return pvpInfo.Bracket == bracket && !*pvpInfo.Disqualified;
22499 });
22500 if (index >= 0)
22501 return &m_activePlayerData->PvpInfo[index];
22502
22503 return nullptr;
22504}
22505
22506bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes, Creature* npc /*= nullptr*/, uint32 spellid /*= 0*/, uint32 preferredMountDisplay /*= 0*/)
22507{
22508 if (nodes.size() < 2)
22509 {
22511 return false;
22512 }
22513
22514 // not let cheating with start flight in time of logout process || while in combat || has type state: stunned || has type state: root
22516 {
22518 return false;
22519 }
22520
22522 return false;
22523
22524 // taximaster case
22525 if (npc)
22526 {
22527 // not let cheating with start flight mounted
22529
22531 RestoreDisplayId(true);
22532
22534 {
22536 return false;
22537 }
22538
22539 // not let cheating with start flight in time of logout process || if casting not finished || while in combat || if not use Spell's with EffectSendTaxi
22540 if (IsNonMeleeSpellCast(false))
22541 {
22543 return false;
22544 }
22545 }
22546 // cast case or scripted call case
22547 else
22548 {
22550
22552 RestoreDisplayId(true);
22553
22555 if (spell->m_spellInfo->Id != spellid)
22557
22559
22561 if (spell->m_spellInfo->Id != spellid)
22563 }
22564
22565 uint32 sourcenode = nodes[0];
22566
22567 // starting node too far away (cheat?)
22568 TaxiNodesEntry const* node = sTaxiNodesStore.LookupEntry(sourcenode);
22569 if (!node)
22570 {
22572 return false;
22573 }
22574
22575 // Prepare to flight start now
22576
22577 // stop combat at start taxi flight if any
22578 CombatStop();
22579
22582 ExitVehicle();
22583
22584 // stop trade (client cancel trade at taxi map open but cheating tools can be used for reopen it)
22585 TradeCancel(true);
22586
22587 // clean not finished taxi path if any
22589
22590 // 0 element current node
22591 m_taxi.AddTaxiDestination(sourcenode);
22592
22593 // fill destinations path tail
22594 uint32 sourcepath = 0;
22595 uint32 totalcost = 0;
22596 uint32 firstcost = 0;
22597
22598 uint32 prevnode = sourcenode;
22599 uint32 lastnode;
22600
22601 for (uint32 i = 1; i < nodes.size(); ++i)
22602 {
22603 uint32 path, cost;
22604
22605 lastnode = nodes[i];
22606 sObjectMgr->GetTaxiPath(prevnode, lastnode, path, cost);
22607
22608 if (!path)
22609 {
22611 return false;
22612 }
22613
22614 totalcost += cost;
22615 if (i == 1)
22616 firstcost = cost;
22617
22618 if (prevnode == sourcenode)
22619 sourcepath = path;
22620
22621 m_taxi.AddTaxiDestination(lastnode);
22622
22623 prevnode = lastnode;
22624 }
22625
22626 // get mount model (in case non taximaster (npc == NULL) allow more wide lookup)
22627 //
22628 // Hack-Fix for Alliance not being able to use Acherus taxi. There is
22629 // only one mount ID for both sides. Probably not good to use 315 in case DBC nodes
22630 // change but I couldn't find a suitable alternative. OK to use class because only DK
22631 // can use this taxi.
22632 uint32 mount_display_id;
22633 if (node->GetFlags().HasFlag(TaxiNodeFlags::UsePlayerFavoriteMount) && preferredMountDisplay)
22634 mount_display_id = preferredMountDisplay;
22635 else
22636 mount_display_id = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == nullptr || (sourcenode == 315 && GetClass() == CLASS_DEATH_KNIGHT));
22637
22638 // in spell case allow 0 model
22639 if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0)
22640 {
22643 return false;
22644 }
22645
22646 uint64 money = GetMoney();
22647
22648 if (npc)
22649 {
22650 float discount = GetReputationPriceDiscount(npc);
22651 totalcost = uint32(ceil(totalcost * discount));
22652 firstcost = uint32(ceil(firstcost * discount));
22654 }
22655 else
22657
22658 if (money < totalcost)
22659 {
22662 return false;
22663 }
22664
22665 //Checks and preparations done, DO FLIGHT
22667
22668 // prevent stealth flight
22669 //RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Interacting);
22670
22671 if (sWorld->getBoolConfig(CONFIG_INSTANT_TAXI))
22672 {
22673 TaxiNodesEntry const* lastPathNode = sTaxiNodesStore.LookupEntry(nodes[nodes.size()-1]);
22674 ASSERT(lastPathNode);
22676 ModifyMoney(-int64(totalcost));
22678 TeleportTo(lastPathNode->ContinentID, lastPathNode->Pos.X, lastPathNode->Pos.Y, lastPathNode->Pos.Z, GetOrientation());
22679 return false;
22680 }
22681 else
22682 {
22683 ModifyMoney(-int64(firstcost));
22686 GetSession()->SendDoFlight(mount_display_id, sourcepath);
22687 }
22688 return true;
22689}
22690
22691bool Player::ActivateTaxiPathTo(uint32 taxi_path_id, uint32 spellid /*= 0*/)
22692{
22693 TaxiPathEntry const* entry = sTaxiPathStore.LookupEntry(taxi_path_id);
22694 if (!entry)
22695 return false;
22696
22697 std::vector<uint32> nodes;
22698
22699 nodes.resize(2);
22700 nodes[0] = entry->FromTaxiNode;
22701 nodes[1] = entry->ToTaxiNode;
22702
22703 return ActivateTaxiPathTo(nodes, nullptr, spellid);
22704}
22705
22707{
22708 if (!IsInFlight())
22709 return;
22710
22712 m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
22713}
22714
22716{
22717 m_taxi.ClearTaxiDestinations(); // not destinations, clear source node
22718 Dismount();
22720}
22721
22723{
22724 uint32 sourceNode = m_taxi.GetTaxiSource();
22725 if (!sourceNode)
22726 return;
22727
22728 TC_LOG_DEBUG("entities.unit", "Player::ContinueTaxiFlight: Restart {} taxi flight", GetGUID().ToString());
22729
22730 uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourceNode, GetTeam(), true);
22731 if (!mountDisplayId)
22732 return;
22733
22735
22736 // search appropriate start path node
22737 uint32 startNode = 0;
22738
22739 TaxiPathNodeList const& nodeList = sTaxiPathNodesByPath[path];
22740
22741 float distPrev;
22742 float distNext = GetExactDistSq(nodeList[0]->Loc.X, nodeList[0]->Loc.Y, nodeList[0]->Loc.Z);
22743
22744 for (uint32 i = 1; i < nodeList.size(); ++i)
22745 {
22746 TaxiPathNodeEntry const* node = nodeList[i];
22747 TaxiPathNodeEntry const* prevNode = nodeList[i-1];
22748
22749 // skip nodes at another map
22750 if (node->ContinentID != GetMapId())
22751 continue;
22752
22753 distPrev = distNext;
22754
22755 distNext = GetExactDistSq(node->Loc.X, node->Loc.Y, node->Loc.Z);
22756
22757 float distNodes =
22758 (node->Loc.X - prevNode->Loc.X) * (node->Loc.X - prevNode->Loc.X) +
22759 (node->Loc.Y - prevNode->Loc.Y) * (node->Loc.Y - prevNode->Loc.Y) +
22760 (node->Loc.Z - prevNode->Loc.Z) * (node->Loc.Z - prevNode->Loc.Z);
22761
22762 if (distNext + distPrev < distNodes)
22763 {
22764 startNode = i;
22765 break;
22766 }
22767 }
22768
22769 GetSession()->SendDoFlight(mountDisplayId, path, startNode);
22770}
22771
22772void Player::InitDataForForm(bool reapplyMods)
22773{
22775
22776 SpellShapeshiftFormEntry const* ssEntry = sSpellShapeshiftFormStore.LookupEntry(form);
22777 if (ssEntry && ssEntry->CombatRoundTime)
22778 {
22782 }
22783 else
22785
22787
22788 // update auras at form change, ignore this at mods reapply (.reset stats/etc) when form not change.
22789 if (!reapplyMods)
22791
22794}
22795
22797{
22798 ChrModelEntry const* model = sDB2Manager.GetChrModel(GetRace(), GetNativeGender());
22799 if (!model)
22800 {
22801 TC_LOG_ERROR("entities.player", "Player::InitDisplayIds: Player '{}' ({}) has incorrect race/gender pair. Can't init display ids.", GetName(), GetGUID().ToString());
22802 return;
22803 }
22804
22805 SetDisplayId(model->DisplayID, true);
22807}
22808
22809inline bool Player::_StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int64 price, ItemTemplate const* pProto, Creature* pVendor, VendorItem const* crItem, bool bStore)
22810{
22811 uint32 stacks = count / pProto->GetBuyCount();
22812 ItemPosCountVec vDest;
22813 uint16 uiDest = 0;
22814 InventoryResult msg = bStore ?
22815 CanStoreNewItem(bag, slot, vDest, item, count) :
22816 CanEquipNewItem(slot, uiDest, item, false);
22817 if (msg != EQUIP_ERR_OK)
22818 {
22819 SendEquipError(msg, nullptr, nullptr, item);
22820 return false;
22821 }
22822
22823 ModifyMoney(-price);
22824
22825 if (crItem->ExtendedCost) // case for new honor system
22826 {
22827 ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
22828 ASSERT(iece);
22829 for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
22830 {
22831 if (iece->ItemID[i])
22832 DestroyItemCount(iece->ItemID[i], iece->ItemCount[i] * stacks, true);
22833 }
22834
22835 for (int i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
22836 {
22838 continue;
22839
22840 if (iece->CurrencyID[i])
22842 }
22843 }
22844
22845 Item* it = bStore ?
22846 StoreNewItem(vDest, item, true, GenerateItemRandomBonusListId(item), {}, ItemContext::Vendor, &crItem->BonusListIDs, false) :
22847 EquipNewItem(uiDest, item, ItemContext::Vendor, true);
22848 if (it)
22849 {
22850 uint32 new_count = pVendor->UpdateVendorItemCurrentCount(crItem, count);
22851
22853 packet.VendorGUID = pVendor->GetGUID();
22854 packet.Muid = vendorslot + 1;
22855 packet.NewQuantity = crItem->maxcount > 0 ? new_count : 0xFFFFFFFF;
22856 packet.QuantityBought = count;
22857 SendDirectMessage(packet.Write());
22858
22859 SendNewItem(it, count, true, false, false);
22860
22861 if (!bStore)
22863
22864 if (pProto->HasFlag(ITEM_FLAG_ITEM_PURCHASE_RECORD) && crItem->ExtendedCost && pProto->GetMaxStackSize() == 1)
22865 {
22868 it->SetPaidMoney(price);
22869 it->SetPaidExtendedCost(crItem->ExtendedCost);
22870 it->SaveRefundDataToDB();
22872 }
22873
22875 }
22876 return true;
22877}
22878
22879bool Player::BuyCurrencyFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count)
22880{
22881 // cheating attempt
22882 if (count < 1) count = 1;
22883
22884 if (!IsAlive())
22885 return false;
22886
22887 CurrencyTypesEntry const* proto = sCurrencyTypesStore.LookupEntry(currency);
22888 if (!proto)
22889 {
22890 SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, currency, 0);
22891 return false;
22892 }
22893
22895 if (!creature)
22896 {
22897 TC_LOG_DEBUG("network", "Player::BuyCurrencyFromVendorSlot: Vendor ({}) not found or player '{}' ({}) can't interact with him.",
22898 vendorGuid.ToString(), GetName(), GetGUID().ToString());
22899 SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, nullptr, currency, 0);
22900 return false;
22901 }
22902
22903 VendorItemData const* vItems = creature->GetVendorItems();
22904 if (!vItems || vItems->Empty())
22905 {
22906 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0);
22907 return false;
22908 }
22909
22910 if (vendorSlot >= vItems->GetItemCount())
22911 {
22912 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0);
22913 return false;
22914 }
22915
22916 VendorItem const* crItem = vItems->GetItem(vendorSlot);
22917 // store diff item (cheating)
22918 if (!crItem || crItem->item != currency || crItem->Type != ITEM_VENDOR_TYPE_CURRENCY)
22919 {
22920 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0);
22921 return false;
22922 }
22923
22924 if (count % crItem->maxcount)
22925 {
22927 return false;
22928 }
22929
22930 uint32 stacks = count / crItem->maxcount;
22931 ItemExtendedCostEntry const* iece;
22932 if (crItem->ExtendedCost)
22933 {
22934 iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
22935 if (!iece)
22936 {
22937 TC_LOG_ERROR("entities.player", "Player::BuyCurrencyFromVendorSlot: Currency {} has wrong ExtendedCost field value {}", currency, crItem->ExtendedCost);
22938 return false;
22939 }
22940
22941 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
22942 {
22943 if (iece->ItemID[i] && !HasItemCount(iece->ItemID[i], (iece->ItemCount[i] * stacks)))
22944 {
22946 return false;
22947 }
22948 }
22949
22950 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
22951 {
22952 if (!iece->CurrencyID[i])
22953 continue;
22954
22955 CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(iece->CurrencyID[i]);
22956 if (!entry)
22957 {
22958 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, currency, 0); // Find correct error
22959 return false;
22960 }
22961
22963 {
22964 // Not implemented
22965 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
22966 return false;
22967 }
22968 else if (!HasCurrency(iece->CurrencyID[i], (iece->CurrencyCount[i] * stacks)))
22969 {
22970 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
22971 return false;
22972 }
22973 }
22974
22975 // check for personal arena rating requirement
22977 {
22978 // probably not the proper equip err
22979 SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, nullptr, nullptr);
22980 return false;
22981 }
22982
22984 {
22985 SendBuyError(BUY_ERR_REPUTATION_REQUIRE, creature, currency, 0);
22986 return false;
22987 }
22988
22990 {
22991 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
22992 return false;
22993 }
22994
22996 {
22997 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
22998 return false;
22999 }
23000 }
23001 else // currencies have no price defined, can only be bought with ExtendedCost
23002 {
23003 SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, currency, 0);
23004 return false;
23005 }
23006
23007 AddCurrency(currency, count, CurrencyGainSource::Vendor);
23008 if (iece)
23009 {
23010 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
23011 {
23012 if (!iece->ItemID[i])
23013 continue;
23014
23015 DestroyItemCount(iece->ItemID[i], iece->ItemCount[i] * stacks, true);
23016 }
23017
23018 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
23019 {
23020 if (!iece->CurrencyID[i])
23021 continue;
23022
23024 continue;
23025
23027 }
23028 }
23029
23030 return true;
23031}
23032
23033// Return true is the bought item has a max count to force refresh of window by caller
23034bool Player::BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot)
23035{
23036 // cheating attempt
23037 if (count < 1) count = 1;
23038
23039 // cheating attempt
23040 if (slot > MAX_BAG_SIZE && slot != NULL_SLOT)
23041 return false;
23042
23043 if (!IsAlive())
23044 return false;
23045
23046 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
23047 if (!pProto)
23048 {
23049 SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0);
23050 return false;
23051 }
23052
23053 if (!(pProto->GetAllowableClass() & GetClassMask()) && pProto->GetBonding() == BIND_ON_ACQUIRE && !IsGameMaster())
23054 {
23055 SendBuyError(BUY_ERR_CANT_FIND_ITEM, nullptr, item, 0);
23056 return false;
23057 }
23058
23060 return false;
23061
23063 if (!creature)
23064 {
23065 TC_LOG_DEBUG("network", "Player::BuyItemFromVendorSlot: Vendor ({}) not found or player '{}' ({}) can't interact with him.",
23066 vendorguid.ToString(), GetName(), GetGUID().ToString());
23067 SendBuyError(BUY_ERR_DISTANCE_TOO_FAR, nullptr, item, 0);
23068 return false;
23069 }
23070
23071 if (!sConditionMgr->IsObjectMeetingVendorItemConditions(creature->GetEntry(), item, this, creature))
23072 {
23073 TC_LOG_DEBUG("condition", "Player::BuyItemFromVendorSlot: Player '{}' ({}) doesn't meed conditions for creature (Entry: {}, Item: {})",
23074 GetName(), GetGUID().ToString(), creature->GetEntry(), item);
23075 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
23076 return false;
23077 }
23078
23079 VendorItemData const* vItems = creature->GetVendorItems();
23080 if (!vItems || vItems->Empty())
23081 {
23082 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
23083 return false;
23084 }
23085
23086 if (vendorslot >= vItems->GetItemCount())
23087 {
23088 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
23089 return false;
23090 }
23091
23092 VendorItem const* crItem = vItems->GetItem(vendorslot);
23093 // store diff item (cheating)
23094 if (!crItem || crItem->item != item)
23095 {
23096 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
23097 return false;
23098 }
23099
23100 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(crItem->PlayerConditionId))
23101 {
23102 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
23103 {
23104 SendEquipError(EQUIP_ERR_ITEM_LOCKED, nullptr, nullptr);
23105 return false;
23106 }
23107 }
23108
23109 // check current item amount if it limited
23110 if (crItem->maxcount != 0)
23111 {
23112 if (creature->GetVendorItemCurrentCount(crItem) < count)
23113 {
23114 SendBuyError(BUY_ERR_ITEM_ALREADY_SOLD, creature, item, 0);
23115 return false;
23116 }
23117 }
23118
23120 {
23121 SendBuyError(BUY_ERR_REPUTATION_REQUIRE, creature, item, 0);
23122 return false;
23123 }
23124
23125 if (crItem->ExtendedCost)
23126 {
23127 // Can only buy full stacks for extended cost
23128 if (count % pProto->GetBuyCount())
23129 {
23131 return false;
23132 }
23133
23134 uint32 stacks = count / pProto->GetBuyCount();
23135 ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(crItem->ExtendedCost);
23136 if (!iece)
23137 {
23138 TC_LOG_ERROR("entities.player", "Player::BuyItemFromVendorSlot: Item {} has wrong ExtendedCost field value {}", pProto->GetId(), crItem->ExtendedCost);
23139 return false;
23140 }
23141
23142 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
23143 {
23144 if (iece->ItemID[i] && !HasItemCount(iece->ItemID[i], iece->ItemCount[i] * stacks))
23145 {
23147 return false;
23148 }
23149 }
23150
23151 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
23152 {
23153 if (!iece->CurrencyID[i])
23154 continue;
23155
23156 CurrencyTypesEntry const* entry = sCurrencyTypesStore.LookupEntry(iece->CurrencyID[i]);
23157 if (!entry)
23158 {
23159 SendBuyError(BUY_ERR_CANT_FIND_ITEM, creature, item, 0);
23160 return false;
23161 }
23162
23164 {
23165 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
23166 return false;
23167 }
23168 else if (!HasCurrency(iece->CurrencyID[i], iece->CurrencyCount[i] * stacks))
23169 {
23171 return false;
23172 }
23173 }
23174
23175 // check for personal arena rating requirement
23177 {
23178 // probably not the proper equip err
23179 SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK, nullptr, nullptr);
23180 return false;
23181 }
23182
23183 if (iece->MinFactionID && int32(GetReputationRank(iece->MinFactionID)) < iece->MinReputation)
23184 {
23185 SendBuyError(BUY_ERR_REPUTATION_REQUIRE, creature, item, 0);
23186 return false;
23187 }
23188
23190 {
23191 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
23192 return false;
23193 }
23194
23196 {
23197 SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, nullptr, nullptr); // Find correct error
23198 return false;
23199 }
23200 }
23201
23202 uint64 price = 0;
23203 if (pProto->GetBuyPrice() > 0) //Assume price cannot be negative (do not know why it is int32)
23204 {
23205 double buyPricePerItem = double(pProto->GetBuyPrice()) / pProto->GetBuyCount();
23206 uint64 maxCount = MAX_MONEY_AMOUNT / buyPricePerItem;
23207 if ((uint64)count > maxCount)
23208 {
23209 TC_LOG_ERROR("entities.player.cheat", "Player::BuyItemFromVendorSlot: Player '{}' ({}) tried to buy item (ItemID: {}, Count: {}), causing overflow",
23210 GetName(), GetGUID().ToString(), pProto->GetId(), (uint32)count);
23211 count = (uint8)maxCount;
23212 }
23213 price = uint64(buyPricePerItem * count); //it should not exceed MAX_MONEY_AMOUNT
23214
23215 // reputation discount
23216 price = uint64(floor(price * GetReputationPriceDiscount(creature)));
23217 price = pProto->GetBuyPrice() > 0 ? std::max(uint64(1), price) : price;
23218
23220 price -= CalculatePct(price, priceMod);
23221
23222 if (!HasEnoughMoney(price))
23223 {
23224 SendBuyError(BUY_ERR_NOT_ENOUGHT_MONEY, creature, item, 0);
23225 return false;
23226 }
23227 }
23228
23229 if ((bag == NULL_BAG && slot == NULL_SLOT) || IsInventoryPos(bag, slot))
23230 {
23231 if (!_StoreOrEquipNewItem(vendorslot, item, count, bag, slot, price, pProto, creature, crItem, true))
23232 return false;
23233 }
23234 else if (IsEquipmentPos(bag, slot))
23235 {
23236 if (count != 1)
23237 {
23238 SendEquipError(EQUIP_ERR_NOT_EQUIPPABLE, nullptr, nullptr);
23239 return false;
23240 }
23241 if (!_StoreOrEquipNewItem(vendorslot, item, count, bag, slot, price, pProto, creature, crItem, false))
23242 return false;
23243 }
23244 else
23245 {
23246 SendEquipError(EQUIP_ERR_WRONG_SLOT, nullptr, nullptr);
23247 return false;
23248 }
23249
23251
23252 if (crItem->maxcount != 0) // bought
23253 {
23254 if (pProto->GetQuality() > ITEM_QUALITY_EPIC || (pProto->GetQuality() == ITEM_QUALITY_EPIC && pProto->GetBaseItemLevel() >= MinNewsItemLevel))
23255 if (Guild* guild = GetGuild())
23256 guild->AddGuildNews(GUILD_NEWS_ITEM_PURCHASED, GetGUID(), 0, item);
23257
23258 return true;
23259 }
23260
23261 return false;
23262}
23263
23265{
23266 // returns the maximal personal arena rating that can be used to purchase items requiring this condition
23267 // so return max[in arenateams](personalrating[teamtype])
23268 uint32 max_personal_rating = 0;
23269 for (uint8 i = minarenaslot; i < MAX_ARENA_SLOT; ++i)
23270 {
23271 uint32 p_rating = GetArenaPersonalRating(i);
23272 if (max_personal_rating < p_rating)
23273 max_personal_rating = p_rating;
23274 }
23275 return max_personal_rating;
23276}
23277
23279{
23280 // GMs never get homebind timer online
23282 {
23283 if (m_HomebindTimer) // instance valid, but timer not reset
23285
23286 // instance is valid, reset homebind timer
23287 m_HomebindTimer = 0;
23288 }
23289 else if (m_HomebindTimer > 0)
23290 {
23291 if (time >= m_HomebindTimer)
23292 {
23293 // teleport to nearest graveyard
23295 }
23296 else
23297 m_HomebindTimer -= time;
23298 }
23299 else
23300 {
23301 // instance is invalid, start homebind timer
23302 m_HomebindTimer = 60000;
23303 // send message to player
23305 TC_LOG_DEBUG("maps", "Player::UpdateHomebindTime: Player '{}' ({}) will be teleported to homebind in 60 seconds",
23306 GetName(), GetGUID().ToString());
23307 }
23308}
23309
23311{
23312 // pvp flag should stay after relog
23314 UpdatePvP(true, true);
23315}
23316
23317void Player::UpdatePvPState(bool onlyFFA)
23318{
23320 // no, we shouldn't, those are checked for affecting player by client
23322 && (pvpInfo.IsInFFAPvPArea || sWorld->IsFFAPvPRealm() || HasAuraType(SPELL_AURA_SET_FFA_PVP)))
23323 {
23324 if (!IsFFAPvP())
23325 {
23327 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
23328 (*itr)->SetPvpFlag(UNIT_BYTE2_FLAG_FFA_PVP);
23329 }
23330 }
23331 else if (IsFFAPvP())
23332 {
23334 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
23335 (*itr)->RemovePvpFlag(UNIT_BYTE2_FLAG_FFA_PVP);
23336 }
23337
23338 if (onlyFFA)
23339 return;
23340
23341 if (pvpInfo.IsHostile) // in hostile area
23342 {
23343 if (!IsPvP() || pvpInfo.EndTimer)
23344 UpdatePvP(true, true);
23345 }
23346 else // in friendly area
23347 {
23349 pvpInfo.EndTimer = GameTime::GetGameTime(); // start toggle-off
23350 }
23351}
23352
23353void Player::SetPvP(bool state)
23354{
23355 Unit::SetPvP(state);
23356 for (ControlList::iterator itr = m_Controlled.begin(); itr != m_Controlled.end(); ++itr)
23357 (*itr)->SetPvP(state);
23358}
23359
23360void Player::UpdatePvP(bool state, bool _override)
23361{
23362 if (!state || _override)
23363 {
23364 SetPvP(state);
23365 pvpInfo.EndTimer = 0;
23366 }
23367 else
23368 {
23370 SetPvP(state);
23371 }
23372}
23373
23375{
23376 // no potion used i combat or still in combat
23377 if (!m_lastPotionId || IsInCombat())
23378 return;
23379
23380 // Call not from spell cast, send cooldown event for item spells if no in combat
23381 if (!spell)
23382 {
23383 // spell/item pair let set proper cooldown (except non-existing charged spell cooldown spellmods for potions)
23384 if (ItemTemplate const* proto = sObjectMgr->GetItemTemplate(m_lastPotionId))
23385 for (uint8 idx = 0; idx < proto->Effects.size(); ++idx)
23386 if (proto->Effects[idx]->TriggerType == ITEM_SPELLTRIGGER_ON_USE)
23387 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(proto->Effects[idx]->SpellID, DIFFICULTY_NONE))
23389 }
23390 // from spell cases (m_lastPotionId set in Spell::SendSpellCooldown)
23391 else
23392 {
23393 if (spell->IsIgnoringCooldowns())
23394 return;
23395 else
23397 }
23398
23399 m_lastPotionId = 0;
23400}
23401
23402void Player::SetResurrectRequestData(WorldObject const* caster, uint32 health, uint32 mana, uint32 appliedAura)
23403{
23406 _resurrectionData->GUID = caster->GetGUID();
23407 _resurrectionData->Location.WorldRelocate(*caster);
23408 _resurrectionData->Health = health;
23409 _resurrectionData->Mana = mana;
23410 _resurrectionData->Aura = appliedAura;
23411}
23412
23413 //slot to be excluded while counting
23414bool Player::EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) const
23415{
23416 if (!enchantmentcondition)
23417 return true;
23418
23419 SpellItemEnchantmentConditionEntry const* Condition = sSpellItemEnchantmentConditionStore.LookupEntry(enchantmentcondition);
23420
23421 if (!Condition)
23422 return true;
23423
23424 uint8 curcount[4] = {0, 0, 0, 0};
23425
23426 //counting current equipped gem colors
23428 {
23429 if (i == slot)
23430 continue;
23432 if (pItem2 && !pItem2->IsBroken())
23433 {
23434 for (UF::SocketedGem const& gemData : pItem2->m_itemData->Gems)
23435 {
23436 ItemTemplate const* gemProto = sObjectMgr->GetItemTemplate(gemData.ItemID);
23437 if (!gemProto)
23438 continue;
23439
23440 GemPropertiesEntry const* gemProperty = sGemPropertiesStore.LookupEntry(gemProto->GetGemProperties());
23441 if (!gemProperty)
23442 continue;
23443
23444 uint32 GemColor = gemProperty->Type;
23445
23446 for (uint8 b = 0, tmpcolormask = 1; b < 4; b++, tmpcolormask <<= 1)
23447 if (tmpcolormask & GemColor)
23448 ++curcount[b];
23449 }
23450 }
23451 }
23452
23453 bool activate = true;
23454
23455 for (uint8 i = 0; i < 5; i++)
23456 {
23457 if (!Condition->LtOperandType[i])
23458 continue;
23459
23460 uint32 _cur_gem = curcount[Condition->LtOperandType[i] - 1];
23461
23462 // if have <CompareColor> use them as count, else use <value> from Condition
23463 uint32 _cmp_gem = Condition->RtOperandType[i] ? curcount[Condition->RtOperandType[i] - 1]: Condition->RtOperand[i];
23464
23465 switch (Condition->Operator[i])
23466 {
23467 case 2: // requires less <color> than (<value> || <comparecolor>) gems
23468 activate &= (_cur_gem < _cmp_gem) ? true : false;
23469 break;
23470 case 3: // requires more <color> than (<value> || <comparecolor>) gems
23471 activate &= (_cur_gem > _cmp_gem) ? true : false;
23472 break;
23473 case 5: // requires at least <color> than (<value> || <comparecolor>) gems
23474 activate &= (_cur_gem >= _cmp_gem) ? true : false;
23475 break;
23476 }
23477 }
23478
23479 TC_LOG_DEBUG("entities.player.items", "Player::EnchantmentFitsRequirements: Checking Condition {}, there are {} Meta Gems, {} Red Gems, {} Yellow Gems and {} Blue Gems, Activate:{}",
23480 enchantmentcondition, curcount[0], curcount[1], curcount[2], curcount[3], activate ? "yes" : "no");
23481
23482 return activate;
23483}
23484
23486{
23487 //cycle all equipped items
23488 for (uint32 slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
23489 {
23490 //enchants for the slot being socketed are handled by Player::ApplyItemMods
23491 if (slot == exceptslot)
23492 continue;
23493
23494 Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
23495
23496 if (!pItem || !pItem->GetSocketColor(0))
23497 continue;
23498
23499 for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
23500 {
23501 uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
23502 if (!enchant_id)
23503 continue;
23504
23505 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
23506 if (!enchantEntry)
23507 continue;
23508
23509 uint32 condition = enchantEntry->ConditionID;
23510 if (condition)
23511 {
23512 //was enchant active with/without item?
23513 bool wasactive = EnchantmentFitsRequirements(condition, apply ? exceptslot : -1);
23514 //should it now be?
23515 if (wasactive ^ EnchantmentFitsRequirements(condition, apply ? -1 : exceptslot))
23516 {
23517 // ignore item gem conditions
23518 //if state changed, (dis)apply enchant
23519 ApplyEnchantment(pItem, EnchantmentSlot(enchant_slot), !wasactive, true, true);
23520 }
23521 }
23522 }
23523 }
23524}
23525
23526 //if false -> then toggled off if was on| if true -> toggled on if was off AND meets requirements
23528{
23529 //cycle all equipped items
23530 for (int slot = EQUIPMENT_SLOT_START; slot < EQUIPMENT_SLOT_END; ++slot)
23531 {
23532 //enchants for the slot being socketed are handled by WorldSession::HandleSocketOpcode(WorldPacket& recvData)
23533 if (slot == exceptslot)
23534 continue;
23535
23536 Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, slot);
23537
23538 if (!pItem || !pItem->GetSocketColor(0)) //if item has no sockets or no item is equipped go to next item
23539 continue;
23540
23541 //cycle all (gem)enchants
23542 for (uint32 enchant_slot = SOCK_ENCHANTMENT_SLOT; enchant_slot < SOCK_ENCHANTMENT_SLOT+3; ++enchant_slot)
23543 {
23544 uint32 enchant_id = pItem->GetEnchantmentId(EnchantmentSlot(enchant_slot));
23545 if (!enchant_id) //if no enchant go to next enchant(slot)
23546 continue;
23547
23548 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
23549 if (!enchantEntry)
23550 continue;
23551
23552 //only metagems to be (de)activated, so only enchants with condition
23553 uint32 condition = enchantEntry->ConditionID;
23554 if (condition)
23555 ApplyEnchantment(pItem, EnchantmentSlot(enchant_slot), apply);
23556 }
23557 }
23558}
23559
23561{
23562 // Taxi path store
23563 if (!m_taxi.empty())
23564 {
23565 m_bgData.mountSpell = 0;
23568
23569 // On taxi we don't need check for dungeon
23571 }
23572 else
23573 {
23575
23576 // Mount spell id storing
23577 if (IsMounted())
23578 {
23580 if (!auras.empty())
23581 m_bgData.mountSpell = (*auras.begin())->GetId();
23582 }
23583 else
23584 m_bgData.mountSpell = 0;
23585
23586 // If map is dungeon find linked graveyard
23587 if (GetMap()->IsDungeon())
23588 {
23589 if (WorldSafeLocsEntry const* entry = sObjectMgr->GetClosestGraveyard(*this, GetTeam(), this))
23590 m_bgData.joinPos.WorldRelocate(entry->Loc.GetMapId(), entry->Loc.GetPositionX(), entry->Loc.GetPositionY(), entry->Loc.GetPositionZ());
23591 else
23592 TC_LOG_ERROR("entities.player", "Player::SetBattlegroundEntryPoint: Dungeon (MapID: {}) has no linked graveyard, setting home location as entry point.", GetMapId());
23593 }
23594 // If new entry point is not BG or arena set it
23595 else if (!GetMap()->IsBattlegroundOrArena())
23597 }
23598
23599 if (m_bgData.joinPos.m_mapId == MAPID_INVALID) // In error cases use homebind position
23601}
23602
23604{
23605 m_bgData.bgTeam = team;
23606 SetArenaFaction(uint8(team == ALLIANCE ? 1 : 0));
23607}
23608
23610{
23611 return m_bgData.bgTeam ? m_bgData.bgTeam : GetTeam();
23612}
23613
23614void Player::LeaveBattleground(bool teleportToEntryPoint)
23615{
23616 if (Battleground* bg = GetBattleground())
23617 {
23618 bg->RemovePlayerAtLeave(GetGUID(), teleportToEntryPoint, true);
23619
23620 // call after remove to be sure that player resurrected for correct cast
23621 if (bg->isBattleground() && !IsGameMaster() && sWorld->getBoolConfig(CONFIG_BATTLEGROUND_CAST_DESERTER))
23622 {
23623 if (bg->GetStatus() == STATUS_IN_PROGRESS || bg->GetStatus() == STATUS_WAIT_JOIN)
23624 {
23625 //lets check if player was teleported from BG and schedule delayed Deserter spell cast
23627 {
23629 return;
23630 }
23631
23632 CastSpell(this, 26013, true); // Deserter
23633 }
23634 }
23635 }
23636}
23637
23639{
23641 if (bg->IsArena())
23645
23646 return GetSession()->HasPermission(perm);
23647}
23648
23650{
23651 // a player can complain about 15 people per 5 minutes
23652 if (m_bgData.bgAfkReportedCount++ >= 15)
23653 return false;
23654
23655 return true;
23656}
23657
23660{
23662 reportAfkResult.Offender = GetGUID();
23664 // Battleground also must be in progress!
23665 if (!bg || bg != reporter->GetBattleground() || GetEffectiveTeam() != reporter->GetEffectiveTeam() || bg->GetStatus() != STATUS_IN_PROGRESS)
23666 {
23667 reporter->SendDirectMessage(reportAfkResult.Write());
23668 return;
23669 }
23670
23671 // check if player has 'Idle' or 'Inactive' debuff
23672 if (m_bgData.bgAfkReporter.find(reporter->GetGUID()) == m_bgData.bgAfkReporter.end() && !HasAura(43680) && !HasAura(43681) && reporter->CanReportAfkDueToLimit())
23673 {
23674 m_bgData.bgAfkReporter.insert(reporter->GetGUID());
23675 // by default 3 players have to complain to apply debuff
23676 if (m_bgData.bgAfkReporter.size() >= sWorld->getIntConfig(CONFIG_BATTLEGROUND_REPORT_AFK))
23677 {
23678 // cast 'Idle' spell
23679 CastSpell(this, 43680, true);
23680 m_bgData.bgAfkReporter.clear();
23681 reportAfkResult.NumBlackMarksOnOffender = m_bgData.bgAfkReporter.size();
23682 reportAfkResult.NumPlayersIHaveReported = reporter->m_bgData.bgAfkReportedCount;
23684 }
23685 }
23686
23687 reporter->SendDirectMessage(reportAfkResult.Write());
23688}
23689
23690uint8 Player::GetStartLevel(uint8 race, uint8 playerClass, Optional<int32> characterTemplateId) const
23691{
23692 uint8 startLevel = sWorld->getIntConfig(CONFIG_START_PLAYER_LEVEL);
23693 if (sChrRacesStore.AssertEntry(race)->GetFlags().HasFlag(ChrRacesFlag::IsAlliedRace))
23694 startLevel = sWorld->getIntConfig(CONFIG_START_ALLIED_RACE_LEVEL);
23695
23696 if (playerClass == CLASS_DEATH_KNIGHT)
23697 {
23698 if (race == RACE_PANDAREN_ALLIANCE || race == RACE_PANDAREN_HORDE)
23699 startLevel = std::max<uint8>(sWorld->getIntConfig(CONFIG_START_ALLIED_RACE_LEVEL), startLevel);
23700 else
23701 startLevel = std::max<uint8>(sWorld->getIntConfig(CONFIG_START_DEATH_KNIGHT_PLAYER_LEVEL), startLevel);
23702 }
23703 else if (playerClass == CLASS_DEMON_HUNTER)
23704 startLevel = std::max<uint8>(sWorld->getIntConfig(CONFIG_START_DEMON_HUNTER_PLAYER_LEVEL), startLevel);
23705 else if (playerClass == CLASS_EVOKER)
23706 startLevel = std::max<uint8>(sWorld->getIntConfig(CONFIG_START_EVOKER_PLAYER_LEVEL), startLevel);
23707
23708 if (characterTemplateId)
23709 {
23711 {
23712 if (CharacterTemplate const* charTemplate = sCharacterTemplateDataStore->GetCharacterTemplate(*characterTemplateId))
23713 startLevel = std::max(charTemplate->Level, startLevel);
23714 }
23715 else
23716 TC_LOG_WARN("cheat", "Account: {} (IP: {}) tried to use a character template without given permission. Possible cheating attempt.",
23718 }
23719
23721 startLevel = std::max<uint8>(sWorld->getIntConfig(CONFIG_START_GM_LEVEL), startLevel);
23722
23723 return startLevel;
23724}
23725
23726bool Player::HaveAtClient(Object const* u) const
23727{
23728 return u == this || m_clientGUIDs.find(u->GetGUID()) != m_clientGUIDs.end();
23729}
23730
23731bool Player::IsNeverVisibleFor(WorldObject const* seer, bool allowServersideObjects) const
23732{
23733 if (Unit::IsNeverVisibleFor(seer, allowServersideObjects))
23734 return true;
23735
23736 if (GetSession()->PlayerLogout() || GetSession()->PlayerLoading())
23737 return true;
23738
23739 return false;
23740}
23741
23742bool Player::CanNeverSee(WorldObject const* obj) const
23743{
23744 // the intent is to delay sending visible objects until client is ready for them
23745 // some gameobjects dont function correctly if they are sent before TransportServerTime is correctly set (after CMSG_MOVE_INIT_ACTIVE_MOVER_COMPLETE)
23747}
23748
23749bool Player::CanAlwaysSee(WorldObject const* obj) const
23750{
23751 // Always can see self
23752 if (GetUnitBeingMoved() == obj)
23753 return true;
23754
23755 ObjectGuid guid = m_activePlayerData->FarsightObject;
23756 if (!guid.IsEmpty())
23757 if (obj->GetGUID() == guid)
23758 return true;
23759
23760 return false;
23761}
23762
23764{
23766 return true;
23767
23768 if (duel && duel->State != DUEL_STATE_CHALLENGED && duel->Opponent == seer)
23769 return false;
23770
23771 if (Player const* seerPlayer = seer->ToPlayer())
23772 if (IsGroupVisibleFor(seerPlayer))
23773 return true;
23774
23775 return false;
23776}
23777
23779{
23780 if (!u)
23781 return false;
23782
23783 // Always can see self
23784 if (u == this)
23785 return true;
23786
23787 // Visible units, always are visible for all players
23788 if (IsVisible())
23789 return true;
23790
23791 // GMs are visible for higher gms (or players are visible for gms)
23793 return GetSession()->GetSecurity() <= u->GetSession()->GetSecurity();
23794
23795 // non faction visibility non-breakable for non-GMs
23796 return false;
23797}
23798
23799template<class T>
23800inline void BeforeVisibilityDestroy(T* /*t*/, Player* /*p*/) { }
23801
23802template<>
23804{
23805 if (p->GetPetGUID() == t->GetGUID() && t->IsPet())
23806 t->ToPet()->Remove(PET_SAVE_NOT_IN_SLOT, true);
23807
23808 if (Vignettes::VignetteData const* vignette = t->GetVignette())
23809 {
23810 if (!vignette->Data->IsInfiniteAOI())
23811 {
23813 vignetteUpdate.Removed.push_back(vignette->Guid);
23814 p->SendDirectMessage(vignetteUpdate.Write());
23815 }
23816 }
23817}
23818
23819template<>
23821{
23822 if (Vignettes::VignetteData const* vignette = t->GetVignette())
23823 {
23824 if (!vignette->Data->IsInfiniteAOI())
23825 {
23827 vignetteUpdate.Removed.push_back(vignette->Guid);
23828 p->SendDirectMessage(vignetteUpdate.Write());
23829 }
23830 }
23831}
23832
23833template<>
23835{
23836 if (Vignettes::VignetteData const* vignette = t->GetVignette())
23837 {
23838 if (!vignette->Data->IsInfiniteAOI())
23839 {
23841 vignetteUpdate.Removed.push_back(vignette->Guid);
23842 p->SendDirectMessage(vignetteUpdate.Write());
23843 }
23844 }
23845}
23846
23848{
23849 if (targets.begin() == targets.end())
23850 return;
23851
23852 UpdateData udata(GetMapId());
23853 std::set<WorldObject*> newVisibleObjects;
23854
23855 for (WorldObject* target : targets)
23856 {
23857 if (target == this)
23858 continue;
23859
23860 switch (target->GetTypeId())
23861 {
23862 case TYPEID_UNIT:
23863 UpdateVisibilityOf(target->ToCreature(), udata, newVisibleObjects);
23864 break;
23865 case TYPEID_PLAYER:
23866 UpdateVisibilityOf(target->ToPlayer(), udata, newVisibleObjects);
23867 break;
23868 case TYPEID_GAMEOBJECT:
23869 UpdateVisibilityOf(target->ToGameObject(), udata, newVisibleObjects);
23870 break;
23872 UpdateVisibilityOf(target->ToDynObject(), udata, newVisibleObjects);
23873 break;
23874 case TYPEID_CORPSE:
23875 UpdateVisibilityOf(target->ToCorpse(), udata, newVisibleObjects);
23876 break;
23877 case TYPEID_AREATRIGGER:
23878 UpdateVisibilityOf(target->ToAreaTrigger(), udata, newVisibleObjects);
23879 break;
23880 case TYPEID_SCENEOBJECT:
23881 UpdateVisibilityOf(target->ToSceneObject(), udata, newVisibleObjects);
23882 break;
23884 UpdateVisibilityOf(target->ToConversation(), udata, newVisibleObjects);
23885 break;
23886 default:
23887 break;
23888 }
23889 }
23890
23891 if (!udata.HasData())
23892 return;
23893
23894 WorldPacket packet;
23895 udata.BuildPacket(&packet);
23896 SendDirectMessage(&packet);
23897
23898 for (WorldObject* visibleUnit : newVisibleObjects)
23899 SendInitialVisiblePackets(visibleUnit);
23900}
23901
23903{
23904 if (HaveAtClient(target))
23905 {
23906 if (!CanSeeOrDetect(target, false, true))
23907 {
23908 switch (target->GetTypeId())
23909 {
23910 case TYPEID_UNIT:
23912 break;
23913 case TYPEID_PLAYER:
23915 break;
23916 case TYPEID_GAMEOBJECT:
23918 break;
23919 default:
23920 break;
23921 }
23922
23923 if (!target->IsDestroyedObject())
23924 target->SendOutOfRangeForPlayer(this);
23925 else
23926 target->DestroyForPlayer(this);
23927
23928 m_clientGUIDs.erase(target->GetGUID());
23929
23930 #ifdef TRINITY_DEBUG
23931 TC_LOG_DEBUG("maps", "Object {} out of range for player {}. Distance = {}", target->GetGUID().ToString(), GetGUID().ToString(), GetDistance(target));
23932 #endif
23933 }
23934 }
23935 else
23936 {
23937 if (CanSeeOrDetect(target, false, true))
23938 {
23939 target->SendUpdateToPlayer(this);
23940 m_clientGUIDs.insert(target->GetGUID());
23941
23942 #ifdef TRINITY_DEBUG
23943 TC_LOG_DEBUG("maps", "Object {} is visible now for player {}. Distance = {}", target->GetGUID().ToString(), GetGUID().ToString(), GetDistance(target));
23944 #endif
23945
23946 // target aura duration for caster show only if target exist at caster client
23947 // send data at target visibility change (adding to client)
23949 }
23950 }
23951}
23952
23954{
23955 if (m_clientGUIDs.empty())
23956 return;
23957
23958 if (!IsInWorld())
23959 return;
23960
23961 UpdateData udata(GetMapId());
23962 WorldPacket packet;
23963 for (auto itr = m_clientGUIDs.begin(); itr != m_clientGUIDs.end(); ++itr)
23964 {
23965 if (itr->IsCreatureOrVehicle())
23966 {
23967 Creature* creature = GetMap()->GetCreature(*itr);
23968 // Update fields of triggers, transformed units or uninteractible units (values dependent on GM state)
23969 if (!creature || (!creature->IsTrigger() && !creature->HasAuraType(SPELL_AURA_TRANSFORM) && !creature->IsUninteractible()))
23970 continue;
23971
23974 creature->BuildValuesUpdateBlockForPlayer(&udata, this);
23975 }
23976 else if (itr->IsAnyTypeGameObject())
23977 {
23978 GameObject* go = GetMap()->GetGameObject(*itr);
23979 if (!go)
23980 continue;
23981
23983 go->BuildValuesUpdateBlockForPlayer(&udata, this);
23984 }
23985 }
23986
23987 if (!udata.HasData())
23988 return;
23989
23990 udata.BuildPacket(&packet);
23991 SendDirectMessage(&packet);
23992}
23993
23995{
23996 auto sendVignette = [](Vignettes::VignetteData const& vignette, Player const* where)
23997 {
23998 if (!vignette.Data->IsInfiniteAOI() && Vignettes::CanSee(where, vignette))
23999 {
24001 vignette.FillPacket(vignetteUpdate.Added);
24002 where->SendDirectMessage(vignetteUpdate.Write());
24003 }
24004 };
24005
24006 if (Unit* targetUnit = target->ToUnit())
24007 {
24008 SendAurasForTarget(targetUnit);
24009 if (targetUnit->IsAlive())
24010 {
24011 if (targetUnit->HasUnitState(UNIT_STATE_MELEE_ATTACKING) && targetUnit->GetVictim())
24012 targetUnit->SendMeleeAttackStart(targetUnit->GetVictim());
24013 }
24014
24015 if (Vignettes::VignetteData const* vignette = targetUnit->GetVignette())
24016 sendVignette(*vignette, this);
24017 }
24018 else if (GameObject* targetGo = target->ToGameObject())
24019 {
24020 if (Vignettes::VignetteData const* vignette = targetGo->GetVignette())
24021 sendVignette(*vignette, this);
24022 }
24023}
24024
24025template<class T>
24026void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObject*>& visibleNow)
24027{
24028 if (HaveAtClient(target))
24029 {
24030 if (!CanSeeOrDetect(target, false, true))
24031 {
24032 BeforeVisibilityDestroy<T>(target, this);
24033
24034 if (!target->IsDestroyedObject())
24035 target->BuildOutOfRangeUpdateBlock(&data);
24036 else
24037 target->BuildDestroyUpdateBlock(&data);
24038
24039 m_clientGUIDs.erase(target->GetGUID());
24040
24041 #ifdef TRINITY_DEBUG
24042 TC_LOG_DEBUG("maps", "Object {} is out of range for player {}. Distance = {}", target->GetGUID().ToString(), GetGUID().ToString(), GetDistance(target));
24043 #endif
24044 }
24045 }
24046 else
24047 {
24048 if (CanSeeOrDetect(target, false, true))
24049 {
24050 target->BuildCreateUpdateBlockForPlayer(&data, this);
24051 m_clientGUIDs.insert(target->GetGUID());
24052 visibleNow.insert(target);
24053
24054 #ifdef TRINITY_DEBUG
24055 TC_LOG_DEBUG("maps", "Object {} is visible now for player {}. Distance = {}", target->GetGUID().ToString(), GetGUID().ToString(), GetDistance(target));
24056 #endif
24057 }
24058 }
24059}
24060
24061template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24062template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24063template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24064template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24065template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24066template void Player::UpdateVisibilityOf(AreaTrigger* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24067template void Player::UpdateVisibilityOf(SceneObject* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24068template void Player::UpdateVisibilityOf(Conversation* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
24069
24071{
24072 // Prevent updating visibility if player is not in world (example: LoadFromDB sets drunkstate which updates invisibility while player is not in map)
24073 if (!IsInWorld())
24074 return;
24075
24076 if (!forced)
24078 else
24079 {
24082 }
24083}
24084
24086{
24087 // updates visibility of all objects around point of view for current player
24088 Trinity::VisibleNotifier notifier(*this);
24090 notifier.SendToSelf(); // send gathered data
24091}
24092
24094{
24096}
24097
24098bool Player::ModifyMoney(int64 amount, bool sendError /*= true*/)
24099{
24100 if (!amount)
24101 return true;
24102
24103 sScriptMgr->OnPlayerMoneyChanged(this, amount);
24104
24105 if (amount < 0)
24106 SetMoney(GetMoney() > uint64(-amount) ? GetMoney() + amount : 0);
24107 else
24108 {
24109 if (GetMoney() <= MAX_MONEY_AMOUNT - static_cast<uint64>(amount))
24110 SetMoney(GetMoney() + amount);
24111 else
24112 {
24113 sScriptMgr->OnPlayerMoneyLimit(this, amount);
24114
24115 if (sendError)
24116 SendEquipError(EQUIP_ERR_TOO_MUCH_GOLD, nullptr, nullptr);
24117 return false;
24118 }
24119 }
24120
24121 return true;
24122}
24123
24125{
24126 bool loading = GetSession()->PlayerLoading();
24127
24128 if (!loading)
24129 MoneyChanged(value);
24130
24132
24133 if (!loading)
24135}
24136
24138{
24139 return m_RewardedQuests.find(quest_id) != m_RewardedQuests.end();
24140}
24141
24143{
24144 ObjectGuid selectionGUID = GetTarget();
24145 if (!selectionGUID.IsEmpty())
24146 return ObjectAccessor::GetUnit(*this, selectionGUID);
24147 return nullptr;
24148}
24149
24151{
24152 ObjectGuid selectionGUID = GetTarget();
24153 if (!selectionGUID.IsEmpty())
24154 return ObjectAccessor::FindConnectedPlayer(selectionGUID);
24155 return nullptr;
24156}
24157
24158bool Player::IsInGroup(ObjectGuid groupGuid) const
24159{
24160 if (Group const* group = GetGroup())
24161 if (group->GetGUID() == groupGuid)
24162 return true;
24163
24164 if (Group const* group = GetOriginalGroup())
24165 if (group->GetGUID() == groupGuid)
24166 return true;
24167
24168 return false;
24169}
24170
24172{
24173 Group const* group = GetGroup();
24174 if (!partyIndex)
24175 return group;
24176
24177 GroupCategory category = GroupCategory(*partyIndex);
24178 if (group && group->GetGroupCategory() == category)
24179 return group;
24180
24181 Group const* originalGroup = GetOriginalGroup();
24182 if (originalGroup && originalGroup->GetGroupCategory() == category)
24183 return originalGroup;
24184
24185 return nullptr;
24186}
24187
24188void Player::SetGroup(Group* group, int8 subgroup)
24189{
24190 if (group == nullptr)
24191 m_group.unlink();
24192 else
24193 {
24194 // never use SetGroup without a subgroup unless you specify NULL for group
24195 ASSERT(subgroup >= 0);
24196 m_group.link(group, this);
24197 m_group.setSubGroup((uint8)subgroup);
24198 }
24199
24201}
24202
24204{
24206 {
24209 }
24210
24212
24215
24218
24219 // SMSG_SET_PROFICIENCY
24220 // SMSG_SET_PCT_SPELL_MODIFIER
24221 // SMSG_SET_FLAT_SPELL_MODIFIER
24222
24227
24230
24233 GetSpellHistory()->WritePacket(&sendSpellHistory);
24234 SendDirectMessage(sendSpellHistory.Write());
24235
24238 GetSpellHistory()->WritePacket(&sendSpellCharges);
24239 SendDirectMessage(sendSpellCharges.Write());
24240
24242 activeGlyphs.Glyphs.reserve(GetGlyphs(GetActiveTalentGroup()).size());
24243 for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup()))
24244 if (std::vector<uint32> const* bindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId))
24245 for (uint32 bindableSpell : *bindableSpells)
24246 if (HasSpell(bindableSpell) && m_overrideSpells.find(bindableSpell) == m_overrideSpells.end())
24247 activeGlyphs.Glyphs.emplace_back(uint32(bindableSpell), uint16(glyphId));
24248
24249 activeGlyphs.IsFullUpdate = true;
24250 SendDirectMessage(activeGlyphs.Write());
24251
24254
24256 m_reputationMgr->SendInitialReputations();
24261
24262 m_achievementMgr->SendAllData(this);
24263 m_questObjectiveCriteriaMgr->SendAllData(this);
24264
24266 static float const TimeSpeed = 0.01666667f;
24267 WorldPackets::Misc::LoginSetTimeSpeed loginSetTimeSpeed;
24268 loginSetTimeSpeed.NewSpeed = TimeSpeed;
24269 loginSetTimeSpeed.GameTime = *GameTime::GetWowTime();
24270 loginSetTimeSpeed.ServerTime = *GameTime::GetWowTime();
24271 loginSetTimeSpeed.GameTimeHolidayOffset = 0;
24272 loginSetTimeSpeed.ServerTimeHolidayOffset = 0;
24273 SendDirectMessage(loginSetTimeSpeed.Write());
24274
24277 if (MapDifficultyEntry const* mapDifficulty = GetMap()->GetMapDifficulty())
24278 worldServerInfo.InstanceGroupSize = mapDifficulty->MaxPlayers;
24279 worldServerInfo.IsTournamentRealm = 0;
24280 // worldServerInfo.RestrictedAccountMaxLevel; /// @todo
24281 // worldServerInfo.RestrictedAccountMaxMoney; /// @todo
24282 worldServerInfo.DifficultyID = GetMap()->GetDifficultyID();
24283 // worldServerInfo.XRealmPvpAlert; /// @todo
24284 SendDirectMessage(worldServerInfo.Write());
24285
24286 // Spell modifiers
24288
24289 // SMSG_ACCOUNT_MOUNT_UPDATE
24291 mountUpdate.IsFullUpdate = true;
24292 mountUpdate.Mounts = &GetSession()->GetCollectionMgr()->GetAccountMounts();
24293 SendDirectMessage(mountUpdate.Write());
24294
24295 // SMSG_ACCOUNT_TOYS_UPDATE
24297 toyUpdate.IsFullUpdate = true;
24298 toyUpdate.Toys = &GetSession()->GetCollectionMgr()->GetAccountToys();
24299 SendDirectMessage(toyUpdate.Write());
24300
24301 // SMSG_ACCOUNT_HEIRLOOM_UPDATE
24303 heirloomUpdate.IsFullUpdate = true;
24304 heirloomUpdate.Heirlooms = &GetSession()->GetCollectionMgr()->GetAccountHeirlooms();
24305 SendDirectMessage(heirloomUpdate.Write());
24306
24308
24310 initialSetup.ServerExpansionLevel = sWorld->getIntConfig(CONFIG_EXPANSION);
24311 SendDirectMessage(initialSetup.Write());
24312
24313 SetMovedUnit(this);
24314}
24315
24317{
24319
24320 // Send map wide vignettes before UpdateZone, that will send zone wide vignettes
24321 // But first send on new map will wipe all vignettes on client
24322 {
24324 vignetteUpdate.ForceUpdate = true;
24325
24326 for (Vignettes::VignetteData const* vignette : GetMap()->GetInfiniteAOIVignettes())
24327 if (!vignette->Data->GetFlags().HasFlag(VignetteFlags::ZoneInfiniteAOI) && Vignettes::CanSee(this, *vignette))
24328 vignette->FillPacket(vignetteUpdate.Added);
24329
24330 SendDirectMessage(vignetteUpdate.Write());
24331 }
24332
24333 // update zone
24334 uint32 newzone, newarea;
24335 GetZoneAndAreaId(newzone, newarea);
24336 UpdateZone(newzone, newarea); // also call SendInitWorldStates();
24337
24339
24340 CastSpell(this, 836, true); // LOGINEFFECT
24341
24342 // set some aura effects that send packet to player client after add player to map
24343 // SendMessageToSet not send it to player not it map, only for aura that not changed anything at re-apply
24344 // same auras state lost at far teleport, send it one more time in this case also
24345 static const AuraType auratypes[] =
24346 {
24350 };
24351 for (AuraType const* itr = &auratypes[0]; itr && itr[0] != SPELL_AURA_NONE; ++itr)
24352 {
24353 Unit::AuraEffectList const& auraList = GetAuraEffectsByType(*itr);
24354 if (!auraList.empty())
24355 auraList.front()->HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true);
24356 }
24357
24359 SetRooted(true);
24360
24362 // manual send package (have code in HandleEffect(this, AURA_EFFECT_HANDLE_SEND_FOR_CLIENT, true); that must not be re-applied.
24364 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_ROOT, m_movementCounter++);
24365
24367 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_SET_FEATHER_FALL, m_movementCounter++);
24368
24370 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_SET_WATER_WALK, m_movementCounter++);
24371
24373 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_SET_HOVERING, m_movementCounter++);
24374
24376 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_DISABLE_GRAVITY, m_movementCounter++);
24377
24380
24382 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_ENABLE_DOUBLE_JUMP, m_movementCounter++);
24383
24386
24388 setCompoundState.StateChanges.emplace_back(SMSG_MOVE_DISABLE_INERTIA, m_movementCounter++);
24389
24390 if (!setCompoundState.StateChanges.empty())
24391 {
24392 setCompoundState.MoverGUID = GetGUID();
24393 SendDirectMessage(setCompoundState.Write());
24394 }
24395
24396 SendAurasForTarget(this);
24397 SendEnchantmentDurations(); // must be after add to map
24398 SendItemDurations(); // must be after add to map
24399
24400 if (GetMap()->IsRaid())
24401 {
24402 Difficulty mapDifficulty = GetMap()->GetDifficultyID();
24403 DifficultyEntry const* difficulty = sDifficultyStore.AssertEntry(mapDifficulty);
24404 SendRaidDifficulty((difficulty->Flags & DIFFICULTY_FLAG_LEGACY) != 0, mapDifficulty);
24405 }
24406 else if (GetMap()->IsNonRaidDungeon())
24408
24410
24411 if (_garrison)
24412 _garrison->SendRemoteInfo();
24413
24415
24416 if (!GetPlayerSharingQuest().IsEmpty())
24417 {
24418 if (Quest const* quest = sObjectMgr->GetQuestTemplate(GetSharedQuestID()))
24419 PlayerTalkClass->SendQuestGiverQuestDetails(quest, GetGUID(), true, false);
24420 else
24422 }
24423
24425}
24426
24428{
24430 return;
24431 if (Group* group = GetGroup())
24432 group->UpdatePlayerOutOfRange(this);
24433
24435 if (Pet* pet = GetPet())
24436 pet->ResetGroupUpdateFlag();
24437}
24438
24439void Player::SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg /*= 0*/, int32 mapDifficultyXConditionID /*= 0*/) const
24440{
24442 transferAborted.MapID = mapid;
24443 transferAborted.Arg = arg;
24444 transferAborted.TransfertAbort = reason;
24445 transferAborted.MapDifficultyXConditionID = mapDifficultyXConditionID;
24446 SendDirectMessage(transferAborted.Write());
24447}
24448
24450{
24452 return;
24453
24454 TimePoint now = GameTime::Now();
24455 for (ItemEffectEntry const* effectData : pItem->GetEffects())
24456 {
24457 SpellInfo const* effectSpellInfo = sSpellMgr->GetSpellInfo(effectData->SpellID, DIFFICULTY_NONE);
24458 if (!effectSpellInfo)
24459 continue;
24460
24461 // apply proc cooldown to equip auras if we have any
24462 if (effectData->TriggerType == ITEM_SPELLTRIGGER_ON_EQUIP)
24463 {
24464 SpellProcEntry const* procEntry = sSpellMgr->GetSpellProcEntry(effectSpellInfo);
24465 if (!procEntry)
24466 continue;
24467
24468 if (Aura* itemAura = GetAura(effectData->SpellID, GetGUID(), pItem->GetGUID()))
24469 itemAura->AddProcCooldown(procEntry, now);
24470 continue;
24471 }
24472
24473 // wrong triggering type
24474 if (effectData->TriggerType != ITEM_SPELLTRIGGER_ON_USE)
24475 continue;
24476
24477 // Don't replace longer cooldowns by equip cooldown if we have any.
24478 if (GetSpellHistory()->GetRemainingCooldown(effectSpellInfo) > 30s)
24479 continue;
24480
24481 GetSpellHistory()->AddCooldown(effectData->SpellID, pItem->GetEntry(), std::chrono::seconds(30));
24482
24484 data.ItemGuid = pItem->GetGUID();
24485 data.SpellID = effectData->SpellID;
24486 data.Cooldown = 30 * IN_MILLISECONDS; // Always 30secs?
24487 SendDirectMessage(data.Write());
24488 }
24489}
24490
24491void Player::ResetSpells(bool myClassOnly)
24492{
24493 // not need after this call
24496
24497 // make full copy of map (spells removed and marked as deleted at another spell remove
24498 // and we can't use original map for safe iterative with visit each spell at loop end
24499 PlayerSpellMap smap = GetSpellMap();
24500
24501 uint32 family;
24502
24503 if (myClassOnly)
24504 {
24505 ChrClassesEntry const* clsEntry = sChrClassesStore.LookupEntry(GetClass());
24506 if (!clsEntry)
24507 return;
24508 family = clsEntry->SpellClassSet;
24509
24510 for (PlayerSpellMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter)
24511 {
24512 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(iter->first, DIFFICULTY_NONE);
24513 if (!spellInfo)
24514 continue;
24515
24516 // skip server-side/triggered spells
24517 if (spellInfo->SpellLevel == 0)
24518 continue;
24519
24520 // skip wrong class/race skills
24521 if (!IsSpellFitByClassAndRace(spellInfo->Id))
24522 continue;
24523
24524 // skip other spell families
24525 if (spellInfo->SpellFamilyName != family)
24526 continue;
24527
24528 // skip broken spells
24529 if (!SpellMgr::IsSpellValid(spellInfo, this, false))
24530 continue;
24531 }
24532 }
24533 else
24534 for (PlayerSpellMap::const_iterator iter = smap.begin(); iter != smap.end(); ++iter)
24535 RemoveSpell(iter->first, false, false); // only iter->first can be accessed, object by iter->second can be deleted already
24536
24540}
24541
24543{
24544 if (!sWorld->getBoolConfig(CONFIG_START_ALL_SPELLS))
24545 return;
24546
24547 // learn default race/class spells
24548 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(GetRace(), GetClass());
24549 ASSERT(info);
24550 for (PlayerCreateInfoSpells::const_iterator itr = info->customSpells.begin(); itr != info->customSpells.end(); ++itr)
24551 {
24552 uint32 tspell = *itr;
24553 TC_LOG_DEBUG("entities.player.loading", "Player::LearnCustomSpells: Player '{}' ({}, Class: {} Race: {}): Adding initial spell (SpellID: {})",
24554 GetName(), GetGUID().ToString(), uint32(GetClass()), uint32(GetRace()), tspell);
24555 if (!IsInWorld()) // will send in INITIAL_SPELLS in list anyway at map add
24556 AddSpell(tspell, true, true, true, false);
24557 else // but send in normal spell in game learn case
24558 LearnSpell(tspell, true);
24559 }
24560}
24561
24563{
24564 // learn default race/class skills
24565 PlayerInfo const* info = sObjectMgr->GetPlayerInfo(GetRace(), GetClass());
24566 ASSERT(info);
24567 for (PlayerCreateInfoSkills::const_iterator itr = info->skills.begin(); itr != info->skills.end(); ++itr)
24568 {
24569 SkillRaceClassInfoEntry const* rcInfo = *itr;
24570 if (HasSkill(rcInfo->SkillID))
24571 continue;
24572
24573 if (rcInfo->MinLevel > GetLevel())
24574 continue;
24575
24576 LearnDefaultSkill(rcInfo);
24577 }
24578}
24579
24581{
24582 uint16 skillId = rcInfo->SkillID;
24583 switch (GetSkillRangeType(rcInfo))
24584 {
24586 SetSkill(skillId, 0, 300, 300);
24587 break;
24588 case SKILL_RANGE_LEVEL:
24589 {
24590 uint16 skillValue = 1;
24591 uint16 maxValue = GetMaxSkillValueForLevel();
24592 if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
24593 skillValue = maxValue;
24594 else if (GetClass() == CLASS_DEATH_KNIGHT)
24595 skillValue = std::min(std::max<uint16>({ 1, uint16((GetLevel() - 1) * 5) }), maxValue);
24596
24597 SetSkill(skillId, 0, skillValue, maxValue);
24598 break;
24599 }
24600 case SKILL_RANGE_MONO:
24601 SetSkill(skillId, 0, 1, 1);
24602 break;
24603 case SKILL_RANGE_RANK:
24604 {
24605 SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcInfo->SkillTierID);
24606 uint16 maxValue = tier->GetValueForTierIndex(0);
24607 uint16 skillValue = 1;
24608 if (rcInfo->Flags & SKILL_FLAG_ALWAYS_MAX_VALUE)
24609 skillValue = maxValue;
24610 else if (GetClass() == CLASS_DEATH_KNIGHT)
24611 skillValue = std::min(std::max(uint16(1), uint16((GetLevel() - 1) * 5)), maxValue);
24612
24613 SetSkill(skillId, 1, skillValue, maxValue);
24614 break;
24615 }
24616 default:
24617 break;
24618 }
24619}
24620
24622{
24623 int32 spell_id = quest->GetRewSpell();
24624 uint32 src_spell_id = quest->GetSrcSpell();
24625
24626 // skip quests without rewarded spell
24627 if (!spell_id)
24628 return;
24629
24630 // if RewSpellCast = -1 we remove aura do to SrcSpell from player.
24631 if (spell_id == -1 && src_spell_id)
24632 {
24633 RemoveAurasDueToSpell(src_spell_id);
24634 return;
24635 }
24636
24637 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell_id, DIFFICULTY_NONE);
24638 if (!spellInfo)
24639 return;
24640
24641 // check learned spells state
24642 bool found = false;
24643 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
24644 {
24645 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && !HasSpell(spellEffectInfo.TriggerSpell))
24646 {
24647 found = true;
24648 break;
24649 }
24650 }
24651
24652 // skip quests with not teaching spell or already known spell
24653 if (!found)
24654 return;
24655
24656 if (spellInfo->GetEffects().empty())
24657 return;
24658
24659 SpellEffectInfo const& effect = spellInfo->GetEffect(EFFECT_0);
24660 uint32 learned_0 = effect.TriggerSpell;
24661 if (!HasSpell(learned_0))
24662 {
24663 found = false;
24664 SkillLineAbilityMapBounds skills = sSpellMgr->GetSkillLineAbilityMapBounds(learned_0);
24665 for (auto skillItr = skills.first; skillItr != skills.second; ++skillItr)
24666 {
24667 if (skillItr->second->AcquireMethod == SKILL_LINE_ABILITY_REWARDED_FROM_QUEST)
24668 {
24669 found = true;
24670 break;
24671 }
24672 }
24673
24674 if (!found)
24675 return;
24676 }
24677
24678 CastSpell(this, spell_id, true);
24679}
24680
24682{
24683 // learn spells received from quest completing
24684 for (RewardedQuestSet::const_iterator itr = m_RewardedQuests.begin(); itr != m_RewardedQuests.end(); ++itr)
24685 {
24686 Quest const* quest = sObjectMgr->GetQuestTemplate(*itr);
24687 if (!quest)
24688 continue;
24689
24691 }
24692}
24693
24695{
24696 uint32 classMask = GetClassMask();
24697 std::vector<SkillLineAbilityEntry const*> const* skillLineAbilities = sDB2Manager.GetSkillLineAbilitiesBySkill(skillId);
24698 if (!skillLineAbilities)
24699 return;
24700
24701 for (SkillLineAbilityEntry const* ability : *skillLineAbilities)
24702 {
24703 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(ability->Spell, DIFFICULTY_NONE);
24704 if (!spellInfo)
24705 continue;
24706
24707 switch (ability->AcquireMethod)
24708 {
24711 break;
24713 if (!ability->GetFlags().HasFlag(SkillLineAbilityFlags::CanFallbackToLearnedOnSkillLearn) ||
24714 !spellInfo->MeetsFutureSpellPlayerCondition(this))
24715 continue;
24716 break;
24717 default:
24718 continue;
24719 }
24720
24721 // Check race if set
24722 if (!ability->RaceMask.IsEmpty() && !ability->RaceMask.HasRace(race))
24723 continue;
24724
24725 // Check class if set
24726 if (ability->ClassMask && !(ability->ClassMask & classMask))
24727 continue;
24728
24729 // Check level, skip class spells if not high enough
24730 uint32 requiredLevel = std::max(spellInfo->SpellLevel, spellInfo->BaseLevel);
24731
24732 // riding special cases
24733 if (skillId == SKILL_RIDING)
24734 {
24735 if (GetClassMask() & ((1 << (CLASS_DEATH_KNIGHT - 1)) | (1 << (CLASS_DEMON_HUNTER - 1)))
24736 && (ability->Spell == SPELL_APPRENTICE_RIDING || ability->Spell == SPELL_JOURNEYMAN_RIDING))
24737 requiredLevel = 0;
24738 }
24739
24740 if (requiredLevel > GetLevel())
24741 continue;
24742
24743 // need unlearn spell
24744 if (int32(skillValue) < ability->MinSkillLineRank && ability->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE)
24745 RemoveSpell(ability->Spell);
24746 // need learn
24747 else if (!IsInWorld())
24748 AddSpell(ability->Spell, true, true, true, false, false, ability->SkillLine);
24749 else
24750 LearnSpell(ability->Spell, true, ability->SkillLine);
24751 }
24752}
24753
24755{
24756 int32 const* professionsBegin = m_activePlayerData->ProfessionSkillLine.begin();
24757 int32 const* professionsEnd = m_activePlayerData->ProfessionSkillLine.end();
24758
24759 // Find profession slot
24760 auto professionSlot = std::find(professionsBegin, professionsEnd, int32(skillId));
24761 if (professionSlot == professionsEnd)
24762 return -1;
24763
24764 return std::distance(professionsBegin, professionSlot);
24765}
24766
24768{
24769 SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(skillId);
24770 if (!skillEntry)
24771 return -1;
24772
24773 if (skillEntry->ParentSkillLineID || skillEntry->CategoryID != SKILL_CATEGORY_PROFESSION)
24774 return -1;
24775
24776 int32 const* professionsBegin = m_activePlayerData->ProfessionSkillLine.begin();
24777 int32 const* professionsEnd = m_activePlayerData->ProfessionSkillLine.end();
24778
24779 // if there is no same profession, find any free slot
24780 auto freeSlot = std::find(professionsBegin, professionsEnd, 0);
24781 return freeSlot != professionsEnd ? std::distance(professionsBegin, freeSlot) : -1;
24782}
24783
24785{
24786 if (!target || target->GetVisibleAuras().empty()) // speedup things
24787 return;
24788
24789 Unit::VisibleAuraContainer const& visibleAuras = target->GetVisibleAuras();
24790
24792 update.UpdateAll = true;
24793 update.UnitGUID = target->GetGUID();
24794 update.Auras.reserve(visibleAuras.size());
24795
24796 for (AuraApplication* auraApp : visibleAuras)
24797 {
24799 auraApp->BuildUpdatePacket(auraInfo, false);
24800 update.Auras.push_back(auraInfo);
24801 }
24802
24803 SendDirectMessage(update.Write());
24804}
24805
24807{
24808 if (Quest const* qQuest = sObjectMgr->GetQuestTemplate(quest_id))
24809 {
24810 if (!qQuest->IsDFQuest())
24811 {
24813 m_lastDailyQuestTime = GameTime::GetGameTime(); // last daily quest time
24814 m_DailyQuestChanged = true;
24815 }
24816 else
24817 {
24818 m_DFQuests.insert(quest_id);
24820 m_DailyQuestChanged = true;
24821 }
24822 }
24823}
24824
24826{
24827 return m_activePlayerData->DailyQuestsCompleted.FindIndex(quest_id) >= 0;
24828}
24829
24831{
24832 m_weeklyquests.insert(quest_id);
24833 m_WeeklyQuestChanged = true;
24834}
24835
24837{
24838 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
24839 if (!quest)
24840 return;
24841
24844}
24845
24847{
24848 m_monthlyquests.insert(quest_id);
24849 m_MonthlyQuestChanged = true;
24850}
24851
24853{
24854 for (int32 questId : m_activePlayerData->DailyQuestsCompleted)
24855 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId))
24856 SetQuestCompletedBit(questBit, false);
24857
24859 dailyQuestsReset.Count = int32(m_activePlayerData->DailyQuestsCompleted.size());
24860 SendDirectMessage(dailyQuestsReset.Write());
24861
24863
24864 m_DFQuests.clear(); // Dungeon Finder Quests.
24865
24866 for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
24867 {
24868 uint32 questId = GetQuestSlotQuestId(slot);
24869 if (!questId)
24870 continue;
24871
24872 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
24873 if (!quest || !quest->IsDaily() || !quest->HasFlagEx(QUEST_FLAGS_EX_REMOVE_ON_PERIODIC_RESET))
24874 continue;
24875
24876 SetQuestSlot(slot, 0);
24877 AbandonQuest(questId);
24878 RemoveActiveQuest(questId);
24880
24881 if (quest->GetLimitTime())
24882 RemoveTimedQuest(questId);
24883
24885 }
24886
24887 // DB data deleted in caller
24888 m_DailyQuestChanged = false;
24890
24891 if (_garrison)
24892 _garrison->ResetFollowerActivationLimit();
24893
24895}
24896
24898{
24899 if (m_weeklyquests.empty())
24900 return;
24901
24902 for (uint32 questId : m_weeklyquests)
24903 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId))
24904 SetQuestCompletedBit(questBit, false);
24905
24906 for (uint16 slot = 0; slot < MAX_QUEST_LOG_SIZE; ++slot)
24907 {
24908 uint32 questId = GetQuestSlotQuestId(slot);
24909 if (!questId)
24910 continue;
24911
24912 Quest const* quest = sObjectMgr->GetQuestTemplate(questId);
24913 if (!quest || !quest->IsWeekly() || !quest->HasFlagEx(QUEST_FLAGS_EX_REMOVE_ON_PERIODIC_RESET))
24914 continue;
24915
24916 SetQuestSlot(slot, 0);
24917 AbandonQuest(questId);
24918 RemoveActiveQuest(questId);
24920
24921 if (quest->GetLimitTime())
24922 RemoveTimedQuest(questId);
24923
24925 }
24926
24927 m_weeklyquests.clear();
24928 // DB data deleted in caller
24929 m_WeeklyQuestChanged = false;
24930}
24931
24932void Player::ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime)
24933{
24934 // DB data deleted in caller
24935 m_SeasonalQuestChanged = false;
24936
24937 auto eventItr = m_seasonalquests.find(event_id);
24938 if (eventItr == m_seasonalquests.end())
24939 return;
24940
24941 if (eventItr->second.empty())
24942 return;
24943
24944 for (auto questItr = eventItr->second.begin(); questItr != eventItr->second.end(); )
24945 {
24946 if (questItr->second < eventStartTime)
24947 {
24948 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questItr->first))
24949 SetQuestCompletedBit(questBit, false);
24950
24951 questItr = eventItr->second.erase(questItr);
24952 }
24953 else
24954 ++questItr;
24955 }
24956
24957 if (eventItr->second.empty())
24958 m_seasonalquests.erase(eventItr);
24959
24960}
24961
24963{
24964 if (m_monthlyquests.empty())
24965 return;
24966
24967 for (uint32 questId : m_monthlyquests)
24968 if (uint32 questBit = sDB2Manager.GetQuestUniqueBitFlag(questId))
24969 SetQuestCompletedBit(questBit, false);
24970
24971 m_monthlyquests.clear();
24972 // DB data deleted in caller
24973 m_MonthlyQuestChanged = false;
24974}
24975
24977{
24978 if (GetBattlegroundId() == 0)
24979 return nullptr;
24980
24981 return sBattlegroundMgr->GetBattleground(GetBattlegroundId(), m_bgData.bgTypeID);
24982}
24983
24985{
24986 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
24987 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
24989 return 0;
24990}
24991
24992bool Player::InBattlegroundQueue(bool ignoreArena) const
24993{
24994 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
24995 if (m_bgBattlegroundQueueID[i].bgQueueTypeId != BATTLEGROUND_QUEUE_NONE
24996 && (!ignoreArena || m_bgBattlegroundQueueID[i].bgQueueTypeId.BattlemasterListId != BATTLEGROUND_AA))
24997 return true;
24998 return false;
24999}
25000
25002{
25005
25007}
25008
25010{
25011 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25012 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
25013 return i;
25015}
25016
25018{
25019 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25020 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
25022 return false;
25023}
25024
25026{
25028}
25029
25031{
25032 m_bgData.bgInstanceID = val;
25033 m_bgData.bgTypeID = bgTypeId;
25034 m_bgData.queueId = queueId;
25035}
25036
25038{
25039 for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25040 {
25041 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE || m_bgBattlegroundQueueID[i].bgQueueTypeId == val)
25042 {
25047 return i;
25048 }
25049 }
25051}
25052
25054{
25055 for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25056 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == BATTLEGROUND_QUEUE_NONE)
25057 return true;
25058 return false;
25059}
25060
25062{
25063 for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25064 {
25065 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == val)
25066 {
25071 return;
25072 }
25073 }
25074}
25075
25077{
25078 for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25079 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
25081}
25082
25084{
25085 for (uint8 i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25086 if (m_bgBattlegroundQueueID[i].invitedToInstance == instanceId)
25087 return true;
25088 return false;
25089}
25090
25092{
25093 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25094 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
25095 m_bgBattlegroundQueueID[i].mercenary = mercenary;
25096}
25097
25099{
25100 for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i)
25101 if (m_bgBattlegroundQueueID[i].bgQueueTypeId == bgQueueTypeId)
25103 return false;
25104}
25105
25107{
25109 if (!bg || !bg->isArena())
25110 return false;
25111
25112 return true;
25113}
25114
25116{
25117 // get a template bg instead of running one
25118 BattlegroundTemplate const* bg = sBattlegroundMgr->GetBattlegroundTemplateByTypeId(bgTypeId);
25119 if (!bg)
25120 return false;
25121
25122 // limit check leel to dbc compatible level range
25123 uint32 level = GetLevel();
25124 if (level > DEFAULT_MAX_LEVEL)
25125 level = DEFAULT_MAX_LEVEL;
25126
25127 if (level < bg->GetMinLevel() || level > bg->GetMaxLevel())
25128 return false;
25129
25130 return true;
25131}
25132
25134{
25136}
25137
25139{
25140 if (!factionTemplate || !factionTemplate->Faction)
25141 return 1.0f;
25142
25143 ReputationRank rank = GetReputationRank(factionTemplate->Faction);
25144 if (rank <= REP_NEUTRAL)
25145 return 1.0f;
25146
25147 return 1.0f - 0.05f* (rank - REP_NEUTRAL);
25148}
25149
25151{
25152 return m_trade ? m_trade->GetTrader() : nullptr;
25153}
25154
25156{
25157 uint8 race = GetRace();
25158 uint32 classmask = GetClassMask();
25159
25160 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spell_id);
25161 if (bounds.first == bounds.second)
25162 return true;
25163
25164 for (SkillLineAbilityMap::const_iterator _spell_idx = bounds.first; _spell_idx != bounds.second; ++_spell_idx)
25165 {
25166 // skip wrong race skills
25167 if (!_spell_idx->second->RaceMask.IsEmpty() && !_spell_idx->second->RaceMask.HasRace(race))
25168 continue;
25169
25170 // skip wrong class skills
25171 if (_spell_idx->second->ClassMask && (_spell_idx->second->ClassMask & classmask) == 0)
25172 continue;
25173
25174 // skip wrong class and race skill saved in SkillRaceClassInfo.dbc
25175 if (!sDB2Manager.GetSkillRaceClassInfo(_spell_idx->second->SkillLine, GetRace(), GetClass()))
25176 continue;
25177
25178 return true;
25179 }
25180
25181 return false;
25182}
25183
25185{
25186 for (QuestObjectiveStatusMap::value_type const& objectiveItr : Trinity::Containers::MapEqualRange(m_questObjectiveStatus, { QUEST_OBJECTIVE_GAMEOBJECT, GOId }))
25187 {
25188 Quest const* qInfo = ASSERT_NOTNULL(sObjectMgr->GetQuestTemplate(objectiveItr.second.QuestStatusItr->first));
25189 QuestObjective const* objective = sObjectMgr->GetQuestObjective(objectiveItr.second.ObjectiveId);
25190 if (!qInfo || !objective || !IsQuestObjectiveCompletable(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
25191 continue;
25192
25193 // hide quest if player is in raid-group and quest is no raid quest
25194 if (GetGroup() && GetGroup()->isRaidGroup() && !qInfo->IsAllowedInRaid(GetMap()->GetDifficultyID()))
25195 if (!InBattleground()) //there are two ways.. we can make every bg-quest a raidquest, or add this code here.. i don't know if this can be exploited by other quests, but i think all other quests depend on a specific area.. but keep this in mind, if something strange happens later
25196 continue;
25197
25198 if (!IsQuestObjectiveComplete(objectiveItr.second.QuestStatusItr->second.Slot, qInfo, *objective))
25199 return true;
25200 }
25201
25202 return false;
25203}
25204
25205void Player::UpdateVisibleObjectInteractions(bool allUnits, bool onlySpellClicks, bool gameObjectQuestGiverStatus, bool questObjectiveGameObjects)
25206{
25208 UpdateData udata(GetMapId());
25209 for (ObjectGuid visibleObjectGuid : m_clientGUIDs)
25210 {
25211 if (visibleObjectGuid.IsGameObject() && (gameObjectQuestGiverStatus || questObjectiveGameObjects))
25212 {
25213 GameObject* gameObject = ObjectAccessor::GetGameObject(*this, visibleObjectGuid);
25214 if (!gameObject)
25215 continue;
25216
25217 if (gameObjectQuestGiverStatus && gameObject->GetGoType() == GAMEOBJECT_TYPE_QUESTGIVER)
25218 giverStatusMultiple.QuestGiver.emplace_back(visibleObjectGuid, GetQuestDialogStatus(gameObject));
25219
25220 if (questObjectiveGameObjects)
25221 {
25222 UF::ObjectData::Base objMask;
25224
25225 if (m_questObjectiveStatus.contains({ QUEST_OBJECTIVE_GAMEOBJECT, int32(gameObject->GetEntry()) }))
25227
25228 switch (gameObject->GetGoType())
25229 {
25235 if (sObjectMgr->IsGameObjectForQuests(gameObject->GetEntry()))
25237 break;
25238 default:
25239 break;
25240 }
25241
25242 if (objMask.GetChangesMask().IsAnySet() || goMask.GetChangesMask().IsAnySet())
25243 gameObject->BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), goMask.GetChangesMask(), this);
25244 }
25245 }
25246 else if (visibleObjectGuid.IsCreatureOrVehicle() && (allUnits || onlySpellClicks))
25247 {
25248 Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, visibleObjectGuid);
25249 if (!creature)
25250 continue;
25251
25252 if (allUnits)
25253 {
25254 UF::ObjectData::Base objMask;
25255 UF::UnitData::Base unitMask;
25256 for (uint32 i = 0; i < creature->m_unitData->NpcFlags.size(); ++i)
25257 if (creature->m_unitData->NpcFlags[i])
25258 unitMask.MarkChanged(&UF::UnitData::NpcFlags, i);
25259
25260 if (objMask.GetChangesMask().IsAnySet() || unitMask.GetChangesMask().IsAnySet())
25261 creature->BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), unitMask.GetChangesMask(), this);
25262
25263 if (creature->IsQuestGiver())
25264 giverStatusMultiple.QuestGiver.emplace_back(visibleObjectGuid, GetQuestDialogStatus(creature));
25265 }
25266 else if (onlySpellClicks)
25267 {
25268 // check if this unit requires quest specific flags
25269 if (!creature->HasNpcFlag(UNIT_NPC_FLAG_SPELLCLICK))
25270 continue;
25271
25272 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(creature->GetEntry());
25273 for (auto const& clickPair : clickBounds)
25274 {
25275 if (sConditionMgr->HasConditionsForSpellClickEvent(creature->GetEntry(), clickPair.second.spellId))
25276 {
25277 UF::ObjectData::Base objMask;
25278 UF::UnitData::Base unitMask;
25279 unitMask.MarkChanged(&UF::UnitData::NpcFlags, 0); // NpcFlags[0] has UNIT_NPC_FLAG_SPELLCLICK
25280 creature->BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), unitMask.GetChangesMask(), this);
25281 break;
25282 }
25283 }
25284 }
25285 }
25286 }
25287
25288 // If as a result of npcflag updates we stop seeing UNIT_NPC_FLAG_QUESTGIVER then
25289 // we must also send SMSG_QUEST_GIVER_STATUS_MULTIPLE because client will not request it automatically
25290 if (!giverStatusMultiple.QuestGiver.empty())
25291 SendDirectMessage(giverStatusMultiple.Write());
25292
25293 if (udata.HasData())
25294 {
25295 WorldPacket packet;
25296 udata.BuildPacket(&packet);
25297 SendDirectMessage(&packet);
25298 }
25299}
25300
25302{
25304}
25305
25307{
25308 if (!summoner)
25309 return;
25310
25311 // Player already has active summon request
25312 if (HasSummonPending())
25313 return;
25314
25315 // Evil Twin (ignore player summon, but hide this for summoner)
25316 if (HasAura(23445))
25317 return;
25318
25321 m_summon_instanceId = summoner->GetInstanceId();
25322
25324 summonRequest.SummonerGUID = summoner->GetGUID();
25326 summonRequest.AreaID = summoner->GetZoneId();
25327 SendDirectMessage(summonRequest.Write());
25328
25329 if (Group const* group = GetGroup())
25330 {
25332 summonCast.Target = GetGUID();
25333 group->BroadcastPacket(summonCast.Write(), false);
25334 }
25335}
25336
25338{
25339 auto broadcastSummonResponse = [&](bool accepted)
25340 {
25341 if (Group const* group = GetGroup())
25342 {
25344 summonResponse.Target = GetGUID();
25345 summonResponse.Accepted = accepted;
25346 group->BroadcastPacket(summonResponse.Write(), false);
25347 }
25348 };
25349
25350 if (!agree)
25351 {
25352 m_summon_expire = 0;
25353 broadcastSummonResponse(false);
25354 return;
25355 }
25356
25357 // expire and auto declined
25359 {
25360 broadcastSummonResponse(false);
25361 return;
25362 }
25363
25364 // stop taxi flight at summon
25366
25367 // drop flag at summon
25368 // this code can be reached only when GM is summoning player who carries flag, because player should be immune to summoning spells when he carries flag
25369 if (Battleground* bg = GetBattleground())
25370 bg->EventPlayerDroppedFlag(this);
25371
25372 m_summon_expire = 0;
25373
25376
25378
25379 broadcastSummonResponse(true);
25380}
25381
25383{
25384 for (ItemDurationList::iterator itr = m_itemDuration.begin(); itr != m_itemDuration.end(); ++itr)
25385 {
25386 if (*itr == item)
25387 {
25388 m_itemDuration.erase(itr);
25389 break;
25390 }
25391 }
25392}
25393
25395{
25396 if (*item->m_itemData->Expiration)
25397 {
25398 m_itemDuration.push_back(item);
25399 item->SendTimeUpdate(this);
25400 }
25401}
25402
25403void Player::AutoUnequipOffhandIfNeed(bool force /*= false*/)
25404{
25406 if (!offItem)
25407 return;
25408
25409 // unequip offhand weapon if player doesn't have dual wield anymore
25410 if (!CanDualWield()
25412 || offItem->GetTemplate()->GetInventoryType() == INVTYPE_WEAPON))
25413 force = true;
25414
25415 // need unequip offhand for 2h-weapon without TitanGrip (in any from hands)
25416 if (!force && (CanTitanGrip() || (offItem->GetTemplate()->GetInventoryType() != INVTYPE_2HWEAPON && !IsTwoHandUsed())))
25417 return;
25418
25419 ItemPosCountVec off_dest;
25420 if (CanStoreItem(NULL_BAG, NULL_SLOT, off_dest, offItem, false) == EQUIP_ERR_OK)
25421 {
25423 StoreItem(off_dest, offItem, true);
25424 }
25425 else
25426 {
25428 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
25429 offItem->DeleteFromInventoryDB(trans); // deletes item from character's inventory
25430 offItem->SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone
25431
25432 std::string subject = GetSession()->GetTrinityString(LANG_NOT_EQUIPPED_ITEM);
25433 MailDraft(subject, "There were problems with equipping one or several items").AddItem(offItem).SendMailTo(trans, this, MailSender(this, MAIL_STATIONERY_GM), MAIL_CHECK_MASK_COPIED);
25434
25435 CharacterDatabase.CommitTransaction(trans);
25436 }
25437}
25438
25440{
25441 return sOutdoorPvPMgr->GetOutdoorPvPToZoneId(GetMap(), GetZoneId());
25442}
25443
25444bool Player::HasItemFitToSpellRequirements(SpellInfo const* spellInfo, Item const* ignoreItem) const
25445{
25446 if (spellInfo->EquippedItemClass < 0)
25447 return true;
25448
25449 // scan other equipped items for same requirements (mostly 2 daggers/etc)
25450 // for optimize check 2 used cases only
25451 switch (spellInfo->EquippedItemClass)
25452 {
25453 case ITEM_CLASS_WEAPON:
25454 {
25456 if (item != ignoreItem && item->IsFitToSpellRequirements(spellInfo))
25457 return true;
25459 if (item != ignoreItem && item->IsFitToSpellRequirements(spellInfo))
25460 return true;
25461 break;
25462 }
25463 case ITEM_CLASS_ARMOR:
25464 {
25466 {
25467 // most used check: shield only
25469 {
25471 if (item != ignoreItem && item->IsFitToSpellRequirements(spellInfo))
25472 return true;
25473
25474 // special check to filter things like Shield Wall, the aura is not permanent and must stay even without required item
25475 if (!spellInfo->IsPassive())
25476 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
25477 if (spellEffectInfo.IsAura())
25478 return true;
25479 }
25480
25481 // tabard not have dependent spells
25484 if (item != ignoreItem && item->IsFitToSpellRequirements(spellInfo))
25485 return true;
25486 }
25487 else
25488 {
25489 // requires item equipped in all armor slots
25491 {
25493 if (!item || item == ignoreItem || !item->IsFitToSpellRequirements(spellInfo))
25494 return false;
25495 }
25496
25497 return true;
25498 }
25499 break;
25500 }
25501 default:
25502 TC_LOG_ERROR("entities.player", "Player::HasItemFitToSpellRequirements: Not handled spell requirement for item class {}", spellInfo->EquippedItemClass);
25503 break;
25504 }
25505
25506 return false;
25507}
25508
25509bool Player::CanNoReagentCast(SpellInfo const* spellInfo) const
25510{
25511 // don't take reagents for spells with SPELL_ATTR5_NO_REAGENT_WHILE_PREP
25514 return true;
25515
25516 // Check no reagent use mask
25517 flag128 noReagentMask;
25518 noReagentMask[0] = m_activePlayerData->NoReagentCostMask[0];
25519 noReagentMask[1] = m_activePlayerData->NoReagentCostMask[1];
25520 noReagentMask[2] = m_activePlayerData->NoReagentCostMask[2];
25521 noReagentMask[3] = m_activePlayerData->NoReagentCostMask[3];
25522 if (spellInfo->SpellFamilyFlags & noReagentMask)
25523 return true;
25524
25525 return false;
25526}
25527
25529{
25530 for (AuraMap::iterator itr = m_ownedAuras.begin(); itr != m_ownedAuras.end();)
25531 {
25532 Aura* aura = itr->second;
25533
25534 // skip not self applied auras
25535 SpellInfo const* spellInfo = aura->GetSpellInfo();
25536 if (aura->GetCasterGUID() != GetGUID())
25537 {
25538 ++itr;
25539 continue;
25540 }
25541
25542 // skip if not item dependent or have alternative item
25543 if (HasItemFitToSpellRequirements(spellInfo, pItem))
25544 {
25545 ++itr;
25546 continue;
25547 }
25548
25549 // no alt item, remove aura, restart check
25550 RemoveOwnedAura(itr);
25551 }
25552
25553 // currently cast spells can be dependent from item
25554 for (uint32 i = 0; i < CURRENT_MAX_SPELL; ++i)
25555 if (Spell* spell = GetCurrentSpell(CurrentSpellTypes(i)))
25556 if (spell->getState() != SPELL_STATE_DELAYED && !HasItemFitToSpellRequirements(spell->m_spellInfo, pItem))
25558}
25559
25561{
25563
25564 uint32 spells[3] = { };
25565
25567 for (AuraEffectList::const_iterator itr = dummyAuras.begin(); itr != dummyAuras.end(); ++itr)
25568 {
25569 // Soulstone Resurrection // prio: 3 (max, non death persistent)
25570 if ((*itr)->GetSpellInfo()->SpellFamilyName == SPELLFAMILY_WARLOCK && (*itr)->GetSpellInfo()->SpellFamilyFlags[1] & 0x1000000)
25571 spells[0] = 3026;
25572 // Twisting Nether // prio: 2 (max)
25573 else if ((*itr)->GetId() == 23701 && roll_chance_i(10))
25574 spells[1] = 23700;
25575 }
25576
25577 // Reincarnation (passive spell) // prio: 1
25578 if (HasSpell(20608) && !GetSpellHistory()->HasCooldown(21169))
25579 spells[2] = 21169;
25580
25581 for (uint32 selfResSpell : spells)
25582 if (selfResSpell)
25583 AddSelfResSpell(selfResSpell);
25584}
25585
25586// Used in triggers for check "Only to targets that grant experience or honor" req
25587bool Player::isHonorOrXPTarget(Unit const* victim) const
25588{
25589 uint8 v_level = victim->GetLevelForTarget(this);
25591
25592 // Victim level less gray level
25593 if (v_level < k_grey && !sWorld->getIntConfig(CONFIG_MIN_CREATURE_SCALED_XP_RATIO))
25594 return false;
25595
25596 if (Creature const* const creature = victim->ToCreature())
25597 {
25598 if (creature->IsCritter() || creature->IsTotem())
25599 return false;
25600 }
25601 return true;
25602}
25603
25605{
25606 bool recruitAFriend = false;
25607 if (GetLevel() <= sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL) || !forXP)
25608 {
25609 if (Group* group = GetGroup())
25610 {
25611 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
25612 {
25613 Player* player = itr->GetSource();
25614 if (!player)
25615 continue;
25616
25617 if (!player->IsAtRecruitAFriendDistance(this))
25618 continue; // member (alive or dead) or his corpse at req. distance
25619
25620 if (forXP)
25621 {
25622 // level must be allowed to get RaF bonus
25623 if (player->GetLevel() > sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL))
25624 continue;
25625
25626 // level difference must be small enough to get RaF bonus, UNLESS we are lower level
25627 if (player->GetLevel() < GetLevel())
25629 continue;
25630 }
25631
25632 bool ARecruitedB = (player->GetSession()->GetRecruiterId() == GetSession()->GetAccountId());
25633 bool BRecruitedA = (GetSession()->GetRecruiterId() == player->GetSession()->GetAccountId());
25634 if (ARecruitedB || BRecruitedA)
25635 {
25636 recruitAFriend = true;
25637 break;
25638 }
25639 }
25640 }
25641 }
25642 return recruitAFriend;
25643}
25644
25646{
25647 if (!pRewardSource)
25648 return;
25649
25650 ObjectGuid creature_guid = (pRewardSource->GetTypeId() == TYPEID_UNIT) ? pRewardSource->GetGUID() : ObjectGuid::Empty;
25651
25652 // prepare data for near group iteration
25653 if (Group* group = GetGroup())
25654 {
25655 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
25656 {
25657 Player* player = itr->GetSource();
25658 if (!player)
25659 continue;
25660
25661 if (!player->IsAtGroupRewardDistance(pRewardSource))
25662 continue; // member (alive or dead) or his corpse at req. distance
25663
25664 // quest objectives updated only for alive group member or dead but with not released body
25665 if (player->IsAlive()|| !player->GetCorpse())
25666 player->KilledMonsterCredit(creature_id, creature_guid);
25667 }
25668 }
25669 else // if (!group)
25670 KilledMonsterCredit(creature_id, creature_guid);
25671}
25672
25673bool Player::IsAtGroupRewardDistance(WorldObject const* pRewardSource) const
25674{
25675 if (!pRewardSource || !IsInMap(pRewardSource))
25676 return false;
25677
25678 WorldObject const* player = GetCorpse();
25679 if (!player || IsAlive())
25680 player = this;
25681
25682 if (player->GetMap()->IsDungeon())
25683 return true;
25684
25685 return pRewardSource->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_GROUP_XP_DISTANCE);
25686}
25687
25689{
25690 if (!pOther || !IsInMap(pOther))
25691 return false;
25692
25693 WorldObject const* player = GetCorpse();
25694 if (!player || IsAlive())
25695 player = this;
25696
25697 return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE);
25698}
25699
25701{
25702 // Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse
25703 TeleportTo(_resurrectionData->Location);
25704
25705 if (IsBeingTeleported())
25706 {
25708 return;
25709 }
25710
25712}
25713
25715{
25716 // save health and mana before resurrecting, _resurrectionData can be erased
25717 uint32 resurrectHealth = _resurrectionData->Health;
25718 uint32 resurrectMana = _resurrectionData->Mana;
25719 uint32 resurrectAura = _resurrectionData->Aura;
25720 ObjectGuid resurrectGUID = _resurrectionData->GUID;
25721
25722 ResurrectPlayer(0.0f, false);
25723
25724 SetHealth(resurrectHealth);
25725 SetPower(POWER_MANA, resurrectMana);
25726
25727 SetPower(POWER_RAGE, 0);
25731
25732 if (uint32 aura = resurrectAura)
25734 .SetOriginalCaster(resurrectGUID));
25735
25737}
25738
25739void Player::SetClientControl(Unit* target, bool allowMove)
25740{
25741 // a player can never client control nothing
25742 ASSERT(target);
25743
25744 // don't allow possession to be overridden
25745 if (target->HasUnitState(UNIT_STATE_CHARMED) && (GetGUID() != target->GetCharmerGUID()))
25746 {
25747 TC_LOG_ERROR("entities.player", "Player '{}' attempt to client control '{}', which is charmed by GUID {}",
25748 GetName(), target->GetName(), target->GetCharmerGUID().ToString());
25749 return;
25750 }
25751
25752 // still affected by some aura that shouldn't allow control, only allow on last such aura to be removed
25754 allowMove = false;
25755
25757 data.Guid = target->GetGUID();
25758 data.On = allowMove;
25759 SendDirectMessage(data.Write());
25760
25761 WorldObject* viewpoint = GetViewpoint();
25762 if (!viewpoint)
25763 viewpoint = this;
25764 if (target != viewpoint)
25765 {
25766 if (viewpoint != this)
25767 SetViewpoint(viewpoint, false);
25768 if (target != this)
25769 SetViewpoint(target, true);
25770 }
25771
25772 SetMovedUnit(target);
25773}
25774
25776{
25777 // Some spells applied at enter into zone (with subzones), aura removed in UpdateAreaDependentAuras that called always at zone->area update
25778 SpellAreaForAreaMapBounds saBounds = sSpellMgr->GetSpellAreaForAreaMapBounds(newZone);
25779 for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
25780 if (itr->second->flags & SPELL_AREA_FLAG_AUTOCAST && itr->second->IsFitToRequirements(this, newZone, 0))
25781 if (!HasAura(itr->second->spellId))
25782 CastSpell(this, itr->second->spellId, true);
25783}
25784
25786{
25787 // remove auras from spells with area limitations
25788 for (AuraMap::iterator iter = m_ownedAuras.begin(); iter != m_ownedAuras.end();)
25789 {
25790 // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date
25791 if (iter->second->GetSpellInfo()->CheckLocation(GetMapId(), m_zoneUpdateId, newArea, this) != SPELL_CAST_OK)
25792 RemoveOwnedAura(iter);
25793 else
25794 ++iter;
25795 }
25796
25797 // some auras applied at subzone enter
25798 SpellAreaForAreaMapBounds saBounds = sSpellMgr->GetSpellAreaForAreaMapBounds(newArea);
25799 for (SpellAreaForAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr)
25800 if (itr->second->flags & SPELL_AREA_FLAG_AUTOCAST && itr->second->IsFitToRequirements(this, m_zoneUpdateId, newArea))
25801 if (!HasAura(itr->second->spellId))
25802 CastSpell(this, itr->second->spellId, true);
25803}
25804
25806{
25807 if (pvp)
25808 {
25809 if (!sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP))
25810 return copseReclaimDelay[0];
25811 }
25812 else if (!sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE))
25813 return 0;
25814
25815 time_t now = GameTime::GetGameTime();
25816 // 0..2 full period
25817 // should be ceil(x)-1 but not floor(x)
25818 uint64 count = (now < m_deathExpireTime - 1) ? (m_deathExpireTime - 1 - now) / DEATH_EXPIRE_STEP : 0;
25819 return copseReclaimDelay[count];
25820}
25821
25823{
25824 bool pvp = (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) != 0;
25825
25826 if ((pvp && !sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP)) ||
25827 (!pvp && !sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE)))
25828 return;
25829
25830 time_t now = GameTime::GetGameTime();
25831
25832 if (now < m_deathExpireTime)
25833 {
25834 // full and partly periods 1..3
25835 uint64 count = (m_deathExpireTime - now) / DEATH_EXPIRE_STEP + 1;
25836
25837 if (count < MAX_DEATH_COUNT)
25838 m_deathExpireTime = now+(count + 1) * DEATH_EXPIRE_STEP;
25839 else
25841 }
25842 else
25844}
25845
25847{
25848 Corpse* corpse = GetCorpse();
25849
25850 if (load && !corpse)
25851 return -1;
25852
25853 bool pvp = corpse ? corpse->GetType() == CORPSE_RESURRECTABLE_PVP : (m_ExtraFlags & PLAYER_EXTRA_PVP_DEATH) != 0;
25854
25855 uint32 delay;
25856
25857 if (load)
25858 {
25859 if (corpse->GetGhostTime() > m_deathExpireTime)
25860 return -1;
25861
25862 uint64 count = 0;
25863
25864 if ((pvp && sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP)) ||
25865 (!pvp && sWorld->getBoolConfig(CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE)))
25866 {
25867 count = (m_deathExpireTime - corpse->GetGhostTime()) / DEATH_EXPIRE_STEP;
25868
25869 if (count >= MAX_DEATH_COUNT)
25870 count = MAX_DEATH_COUNT - 1;
25871 }
25872
25873 time_t expected_time = corpse->GetGhostTime() + copseReclaimDelay[count];
25874 time_t now = GameTime::GetGameTime();
25875
25876 if (now >= expected_time)
25877 return -1;
25878
25879 delay = expected_time - now;
25880 }
25881 else
25882 delay = GetCorpseReclaimDelay(pvp);
25883
25884 return delay * IN_MILLISECONDS;
25885}
25886
25888{
25890 packet.Remaining = delay;
25891 SendDirectMessage(packet.Write());
25892}
25893
25895{
25896 Group* group = GetGroup();
25897 if (!group)
25898 return nullptr;
25899
25900 std::vector<Player*> nearMembers;
25901 nearMembers.reserve(group->GetMembersCount());
25902
25903 for (GroupReference* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
25904 {
25905 Player* Target = itr->GetSource();
25906
25907 // IsHostileTo check duel and controlled by enemy
25908 if (Target && Target != this && IsWithinDistInMap(Target, radius) &&
25909 !Target->HasInvisibilityAura() && !IsHostileTo(Target))
25910 nearMembers.push_back(Target);
25911 }
25912
25913 if (nearMembers.empty())
25914 return nullptr;
25915
25916 uint32 randTarget = urand(0, nearMembers.size()-1);
25917 return nearMembers[randTarget];
25918}
25919
25921{
25922 Group const* grp = GetGroup(partyIndex);
25923 if (!grp)
25924 return ERR_NOT_IN_GROUP;
25925
25926 if (grp->isLFGGroup())
25927 {
25928 ObjectGuid gguid = grp->GetGUID();
25929 if (!sLFGMgr->GetKicksLeft(gguid))
25931
25932 lfg::LfgState state = sLFGMgr->GetState(gguid);
25933 if (sLFGMgr->IsVoteKickActive(gguid))
25935
25938
25941
25942 Player* player = ObjectAccessor::FindConnectedPlayer(guidMember);
25943 if (player && !player->m_lootRolls.empty())
25945
25947 for (GroupReference const* itr = grp->GetFirstMember(); itr != nullptr; itr = itr->next())
25948 if (itr->GetSource() && itr->GetSource()->IsInMap(this) && itr->GetSource()->IsInCombat())
25950
25951 /* Missing support for these types
25952 return ERR_PARTY_LFG_BOOT_COOLDOWN_S;
25953 return ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S;
25954 */
25955 }
25956 else
25957 {
25958 if (!grp->IsLeader(GetGUID()) && !grp->IsAssistant(GetGUID()))
25959 return ERR_NOT_LEADER;
25960
25961 if (InBattleground())
25962 return ERR_INVITE_RESTRICTED;
25963
25964 if (grp->IsLeader(guidMember))
25965 return ERR_NOT_LEADER;
25966 }
25967
25968 return ERR_PARTY_RESULT_OK;
25969}
25970
25972{
25973 return sLFGMgr->GetState(GetGUID()) != lfg::LFG_STATE_NONE;
25974}
25975
25977{
25978 if (sLFGMgr->selectedRandomLfgDungeon(GetGUID()))
25979 {
25980 Map const* map = GetMap();
25981 return sLFGMgr->inLfgDungeonMap(GetGUID(), map->GetId(), map->GetDifficultyID());
25982 }
25983
25984 return false;
25985}
25986
25988{
25989 //we must move references from m_group to m_originalGroup
25991
25992 m_group.unlink();
25993 m_group.link(group, this);
25994 m_group.setSubGroup((uint8)subgroup);
25995}
25996
25998{
25999 //remove existing reference
26000 m_group.unlink();
26001 if (Group* group = GetOriginalGroup())
26002 {
26003 m_group.link(group, this);
26005 }
26006 SetOriginalGroup(nullptr);
26007}
26008
26010{
26011 if (group == nullptr)
26013 else
26014 {
26015 // never use SetOriginalGroup without a subgroup unless you specify NULL for group
26016 ASSERT(subgroup >= 0);
26017 m_originalGroup.link(group, this);
26019 }
26020}
26021
26023{
26024 ASSERT(category < MAX_GROUP_CATEGORY);
26026}
26027
26029{
26030 GroupCategory category = group->GetGroupCategory();
26031 // Rejoining the last group should not reset the sequence
26032 if (m_groupUpdateSequences[category].GroupGuid != group->GetGUID())
26033 {
26034 m_groupUpdateSequences[category].GroupGuid = group->GetGUID();
26035 m_groupUpdateSequences[category].UpdateSequenceNumber = 1;
26036 }
26037}
26038
26040{
26041 return m_groupUpdateSequences[category].UpdateSequenceNumber++;
26042}
26043
26045{
26046 // process liquid auras using generic unit code
26047 Unit::ProcessTerrainStatusUpdate(oldLiquidStatus, newLiquidData);
26048
26050
26051 // player specific logic for mirror timers
26052 if (GetLiquidStatus() && newLiquidData)
26053 {
26054 // Breath bar state (under water in any liquid type)
26055 if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::AllLiquids))
26058
26059 // Fatigue bar state (if not on flight path or transport)
26060 if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::DarkWater) && !IsInFlight() && !GetTransport())
26062
26063 // Lava state (any contact)
26064 if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::Magma))
26067
26068 // Slime state (any contact)
26069 if (newLiquidData->type_flags.HasFlag(map_liquidHeaderTypeFlags::Slime))
26072 }
26073
26076}
26077
26079{
26081 if (GetCombatManager().HasPvPCombat())
26082 EnablePvpRules(true);
26083}
26084
26086{
26090}
26091
26092float Player::GetBlockPercent(uint8 attackerLevel) const
26093{
26094 float blockArmor = float(*m_activePlayerData->ShieldBlock);
26095 float armorConstant = sDB2Manager.EvaluateExpectedStat(ExpectedStatType::ArmorConstant, attackerLevel, -2, 0, CLASS_NONE, 0);
26096
26097 if (!(blockArmor + armorConstant))
26098 return 0;
26099
26100 return std::min(blockArmor / (blockArmor + armorConstant), 0.85f);
26101}
26102
26103void Player::SetCanParry(bool value)
26104{
26105 if (m_canParry == value)
26106 return;
26107
26108 m_canParry = value;
26110}
26111
26112void Player::SetCanBlock(bool value)
26113{
26114 if (m_canBlock == value)
26115 return;
26116
26117 m_canBlock = value;
26119}
26120
26121bool ItemPosCount::isContainedIn(std::vector<ItemPosCount> const& vec) const
26122{
26123 for (ItemPosCountVec::const_iterator itr = vec.begin(); itr != vec.end(); ++itr)
26124 if (itr->pos == pos)
26125 return true;
26126 return false;
26127}
26128
26130{
26131 if (Unit* target = Object::ToUnit(GetViewpoint()))
26132 {
26133 target->RemoveAurasByType(SPELL_AURA_BIND_SIGHT, GetGUID());
26134 target->RemoveAurasByType(SPELL_AURA_MOD_POSSESS, GetGUID());
26135 target->RemoveAurasByType(SPELL_AURA_MOD_POSSESS_PET, GetGUID());
26136 }
26137}
26138
26140{
26141 if (apply)
26142 {
26143 TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player '{}' ({}) creates seer (Entry: {}, TypeId: {}).",
26144 GetName(), GetGUID().ToString(), target->GetEntry(), target->GetTypeId());
26145
26146 if (ObjectGuid::Empty != m_activePlayerData->FarsightObject)
26147 {
26148 TC_LOG_FATAL("entities.player", "Player::CreateViewpoint: Player '{}' ({}) cannot add new viewpoint!", GetName(), GetGUID().ToString());
26149 return;
26150 }
26151
26153
26154 // farsight dynobj or puppet may be very far away
26155 UpdateVisibilityOf(target);
26156
26157 if (Unit* targetUnit = target->ToUnit(); targetUnit && targetUnit != GetVehicleBase())
26158 targetUnit->AddPlayerToVision(this);
26159 SetSeer(target);
26160 }
26161 else
26162 {
26163 TC_LOG_DEBUG("maps", "Player::CreateViewpoint: Player {} removed seer", GetName());
26164
26165 if (target->GetGUID() != m_activePlayerData->FarsightObject)
26166 {
26167 TC_LOG_FATAL("entities.player", "Player::CreateViewpoint: Player '{}' ({}) cannot remove current viewpoint!", GetName(), GetGUID().ToString());
26168 return;
26169 }
26170
26172
26173 if (Unit* targetUnit = target->ToUnit(); targetUnit && targetUnit != GetVehicleBase())
26174 targetUnit->RemovePlayerFromVision(this);
26175
26176 //must immediately set seer back otherwise may crash
26177 SetSeer(this);
26178
26179 //WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0);
26180 //SendDirectMessage(&data);
26181 }
26182}
26183
26185{
26186 ObjectGuid guid = m_activePlayerData->FarsightObject;
26187 if (!guid.IsEmpty())
26188 return static_cast<WorldObject*>(ObjectAccessor::GetObjectByTypeMask(*this, guid, TYPEMASK_SEER));
26189 return nullptr;
26190}
26191
26193{
26194 // It is possible to call this method with a null pointer, only skipping faction check.
26195 if (gameobject)
26196 {
26197 FactionTemplateEntry const* playerFaction = GetFactionTemplateEntry();
26198 FactionTemplateEntry const* faction = sFactionTemplateStore.LookupEntry(gameobject->GetFaction());
26199
26200 if (playerFaction && faction && !playerFaction->IsFriendlyTo(faction))
26201 return false;
26202 }
26203
26204 bool hasRecentlyDroppedFlagDebuff = HasAura([](Aura const* aura) -> bool
26205 {
26207 return true;
26209 return true;
26211 return true;
26212 return false;
26213 });
26214
26215 // BUG: sometimes when player clicks on flag in AB - client won't send gameobject_use, only gameobject_report_use packet
26216 // Note: Mount, stealth and invisibility will be removed when used
26217 return (!isTotalImmune() && // Damage immune
26218 !hasRecentlyDroppedFlagDebuff && // Still has recently held flag debuff
26219 IsAlive()); // Alive
26220}
26221
26223{
26224 return (!HasStealthAura() && // not stealthed
26225 !HasInvisibilityAura() && // not invisible
26226 IsAlive()); // live player
26227}
26228
26230{
26232 return 0;
26233
26235 if (!bsc) // shouldn't happen
26236 return 0;
26237
26238 int64 cost = 0;
26239 for (UF::ChrCustomizationChoice const& newChoice : newCustomizations)
26240 {
26241 int32 currentCustomizationIndex = m_playerData->Customizations.FindIndexIf([&](UF::ChrCustomizationChoice const& currentCustomization)
26242 {
26243 return currentCustomization.ChrCustomizationOptionID == newChoice.ChrCustomizationOptionID;
26244 });
26245
26246 if (currentCustomizationIndex == -1 || m_playerData->Customizations[currentCustomizationIndex].ChrCustomizationChoiceID != newChoice.ChrCustomizationChoiceID)
26247 if (ChrCustomizationOptionEntry const* customizationOption = sChrCustomizationOptionStore.LookupEntry(newChoice.ChrCustomizationOptionID))
26248 cost += bsc->Cost * customizationOption->BarberShopCostModifier;
26249 }
26250
26251 return cost;
26252}
26253
26255{
26257
26258 uint32 immuneMask = 0;
26259 for (AuraEffectList::const_iterator itr = immune.begin(); itr != immune.end(); ++itr)
26260 {
26261 immuneMask |= (*itr)->GetMiscValue();
26262 if (immuneMask & SPELL_SCHOOL_MASK_ALL) // total immunity
26263 return true;
26264 }
26265 return false;
26266}
26267
26268bool Player::HasTitle(uint32 bitIndex) const
26269{
26270 uint32 fieldIndexOffset = bitIndex / 64;
26271 if (fieldIndexOffset >= m_activePlayerData->KnownTitles.size())
26272 return false;
26273
26274 uint64 flag = UI64LIT(1) << (bitIndex % 64);
26275 return (m_activePlayerData->KnownTitles[fieldIndexOffset] & flag) != 0;
26276}
26277
26278bool Player::HasTitle(CharTitlesEntry const* title) const
26279{
26280 return HasTitle(title->MaskID);
26281}
26282
26283void Player::SetTitle(CharTitlesEntry const* title, bool lost)
26284{
26285 uint32 fieldIndexOffset = title->MaskID / 64;
26286 uint64 flag = UI64LIT(1) << (title->MaskID % 64);
26287
26288 if (lost)
26289 {
26290 if (!HasTitle(title))
26291 return;
26292
26294 }
26295 else
26296 {
26297 if (HasTitle(title))
26298 return;
26299
26301 }
26302
26304 packet.Index = title->MaskID;
26305 SendDirectMessage(packet.Write());
26306}
26307
26309{
26310 return uint8(m_runes->RuneState & ((1 << GetMaxPower(POWER_RUNES)) - 1));
26311}
26312
26314{
26315 float cooldown = RUNE_BASE_COOLDOWN;
26316
26318 for (AuraEffectList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i)
26319 if ((*i)->GetMiscValue() == POWER_RUNES)
26320 cooldown *= 1.0f - (*i)->GetAmount() / 100.0f;
26321
26322 // Runes cooldown are now affected by player's haste from equipment ...
26323 float hastePct = GetRatingBonusValue(CR_HASTE_MELEE);
26324
26325 // ... and some auras.
26329
26330 cooldown *= 1.0f - (hastePct / 100.0f);
26331
26332 return cooldown;
26333}
26334
26336{
26337 m_runes->Cooldown[index] = cooldown;
26338 m_runes->SetRuneState(index, (cooldown == 0) ? true : false);
26339 int32 activeRunes = std::count(std::begin(m_runes->Cooldown), &m_runes->Cooldown[std::min(GetMaxPower(POWER_RUNES), MAX_RUNES)], 0u);
26340 if (activeRunes != GetPower(POWER_RUNES))
26341 SetPower(POWER_RUNES, activeRunes);
26342}
26343
26344void Runes::SetRuneState(uint8 index, bool set /*= true*/)
26345{
26346 auto itr = std::find(CooldownOrder.begin(), CooldownOrder.end(), index);
26347 if (set)
26348 {
26349 RuneState |= (1 << index); // usable
26350 if (itr != CooldownOrder.end())
26351 CooldownOrder.erase(itr);
26352 }
26353 else
26354 {
26355 RuneState &= ~(1 << index); // on cooldown
26356 if (itr == CooldownOrder.end())
26357 CooldownOrder.push_back(index);
26358 }
26359}
26360
26362{
26363 uint32 maxRunes = uint32(GetMaxPower(POWER_RUNES));
26364
26365 WorldPackets::Spells::ResyncRunes data(maxRunes);
26366 data.Runes.Start = uint8((1 << maxRunes) - 1);
26367 data.Runes.Count = GetRunesState();
26368
26369 float baseCd = float(GetRuneBaseCooldown());
26370 for (uint32 i = 0; i < maxRunes; ++i)
26371 data.Runes.Cooldowns.push_back(uint8((baseCd - float(GetRuneCooldown(i))) / baseCd * 255));
26372
26373 SendDirectMessage(data.Write());
26374}
26375
26377{
26379 return;
26380
26381 uint32 runeIndex = GetPowerIndex(POWER_RUNES);
26382 if (runeIndex == MAX_POWERS)
26383 return;
26384
26385 m_runes = std::make_unique<Runes>();
26386 m_runes->RuneState = 0;
26387
26388 for (uint8 i = 0; i < MAX_RUNES; ++i)
26389 SetRuneCooldown(i, 0); // reset cooldowns
26390
26393}
26394
26395void Player::AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const& store, ItemContext context, bool broadcast, bool createdByPlayer)
26396{
26397 Loot loot(nullptr, ObjectGuid::Empty, LOOT_NONE, nullptr);
26398 loot.FillLoot(loot_id, store, this, true, false, LOOT_MODE_DEFAULT, context);
26399 loot.AutoStore(this, bag, slot, broadcast, createdByPlayer);
26401}
26402
26403void Player::StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot* loot, AELootResult* aeResult/* = nullptr*/)
26404{
26405 NotNormalLootItem* ffaItem = nullptr;
26406
26407 LootItem* item = loot->LootItemInSlot(lootSlot, this, &ffaItem);
26408
26409 if (!item || item->is_looted)
26410 {
26411 SendEquipError(EQUIP_ERR_LOOT_GONE, nullptr, nullptr);
26412 return;
26413 }
26414
26415 if (!item->HasAllowedLooter(GetGUID()))
26416 {
26418 return;
26419 }
26420
26421 if (item->is_blocked)
26422 {
26424 return;
26425 }
26426
26427 // dont allow protected item to be looted by someone else
26428 if (!item->rollWinnerGUID.IsEmpty() && item->rollWinnerGUID != GetGUID())
26429 {
26431 return;
26432 }
26433
26434 ItemPosCountVec dest;
26435 InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item->itemid, item->count);
26436 if (msg == EQUIP_ERR_OK)
26437 {
26438 Item* newitem = StoreNewItem(dest, item->itemid, true, item->randomBonusListId, item->GetAllowedLooters(), item->context);
26439
26440 if (ffaItem)
26441 {
26442 //freeforall case, notify only one player of the removal
26443 ffaItem->is_looted = true;
26444 SendNotifyLootItemRemoved(loot->GetGUID(), loot->GetOwnerGUID(), lootSlot);
26445 }
26446 else //not freeforall, notify everyone
26447 loot->NotifyItemRemoved(lootSlot, GetMap());
26448
26449 //if only one person is supposed to loot the item, then set it to looted
26450 if (!item->freeforall)
26451 item->is_looted = true;
26452
26453 --loot->unlootedCount;
26454
26455 if (newitem && (newitem->GetQuality() > ITEM_QUALITY_EPIC || (newitem->GetQuality() == ITEM_QUALITY_EPIC && newitem->GetItemLevel(this) >= MinNewsItemLevel)))
26456 if (Guild* guild = GetGuild())
26457 guild->AddGuildNews(GUILD_NEWS_ITEM_LOOTED, GetGUID(), 0, item->itemid);
26458
26459 // if aeLooting then we must delay sending out item so that it appears properly stacked in chat
26460 if (!aeResult || !newitem)
26461 {
26462 SendNewItem(newitem, uint32(item->count), false, false, true, loot->GetDungeonEncounterId());
26466 }
26467 else
26468 aeResult->Add(newitem, item->count, GetLootTypeForClient(loot->loot_type), loot->GetDungeonEncounterId());
26469
26470 // LootItem is being removed (looted) from the container, delete it from the DB.
26471 if (loot->loot_type == LOOT_ITEM)
26472 sLootItemStorage->RemoveStoredLootItemForContainer(lootWorldObjectGuid.GetCounter(), item->itemid, item->count, item->LootListId);
26473
26474 if (newitem)
26475 ApplyItemLootedSpell(newitem, true);
26476 else
26477 ApplyItemLootedSpell(sObjectMgr->GetItemTemplate(item->itemid));
26478 }
26479 else
26480 SendEquipError(msg, nullptr, nullptr, item->itemid);
26481}
26482
26484{
26485 // 0 1 2 3
26486 // SetPQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, "SELECT skill, value, max, professionSlot FROM character_skills WHERE guid = '{}'", GUID_LOPART(m_guid));
26487
26488 Races race = Races(GetRace());
26489 std::unordered_map<uint32, uint32> loadedSkillValues;
26490 std::vector<uint16> loadedProfessionsWithoutSlot; // fixup old characters
26491 if (result)
26492 {
26493 do
26494 {
26495 if (mSkillStatus.size() >= PLAYER_MAX_SKILLS) // client limit
26496 {
26497 TC_LOG_ERROR("entities.player", "Player::_LoadSkills: Player '{}' ({}) has more than {} skills.",
26499 break;
26500 }
26501
26502 Field* fields = result->Fetch();
26503 uint16 skill = fields[0].GetUInt16();
26504 uint16 value = fields[1].GetUInt16();
26505 uint16 max = fields[2].GetUInt16();
26506 int8 professionSlot = fields[3].GetInt8();
26507
26508 SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(skill, race, GetClass());
26509 if (!rcEntry)
26510 {
26511 TC_LOG_ERROR("entities.player", "Player::_LoadSkills: Player '{}' ({}, Race: {}, Class: {}) has forbidden skill {} for his race/class combination",
26512 GetName(), GetGUID().ToString(), uint32(race), uint32(GetClass()), skill);
26513
26514 mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(mSkillStatus.size(), SKILL_DELETED)));
26515 continue;
26516 }
26517
26518 // set fixed skill ranges
26519 switch (GetSkillRangeType(rcEntry))
26520 {
26521 case SKILL_RANGE_LANGUAGE: // 300..300
26522 value = max = 300;
26523 break;
26524 case SKILL_RANGE_MONO: // 1..1, grey monolite bar
26525 value = max = 1;
26526 break;
26527 case SKILL_RANGE_LEVEL:
26529 break;
26530 default:
26531 break;
26532 }
26533
26534 auto skillItr = mSkillStatus.find(skill);
26535 if (skillItr == mSkillStatus.end())
26536 skillItr = mSkillStatus.insert(SkillStatusMap::value_type(skill, SkillStatusData(mSkillStatus.size(), SKILL_UNCHANGED))).first;
26537
26538 uint16 step = 0;
26539
26540 if (SkillLineEntry const* skillLine = sSkillLineStore.LookupEntry(rcEntry->SkillID))
26541 {
26542 if (skillLine->CategoryID == SKILL_CATEGORY_SECONDARY)
26543 step = max / 75;
26544
26545 if (skillLine->CategoryID == SKILL_CATEGORY_PROFESSION)
26546 {
26547 step = max / 75;
26548
26549 if (!skillLine->ParentSkillLineID)
26550 {
26551 if (professionSlot != -1)
26553 else
26554 loadedProfessionsWithoutSlot.push_back(skill);
26555 }
26556 }
26557 }
26558
26559 SetSkillLineId(skillItr->second.pos, skill);
26560 SetSkillStep(skillItr->second.pos, step);
26561 SetSkillRank(skillItr->second.pos, value);
26562 SetSkillStartingRank(skillItr->second.pos, 1);
26563 SetSkillMaxRank(skillItr->second.pos, max);
26564 SetSkillTempBonus(skillItr->second.pos, 0);
26565 SetSkillPermBonus(skillItr->second.pos, 0);
26566
26567 loadedSkillValues[skill] = value;
26568 }
26569 while (result->NextRow());
26570 }
26571
26572 // Learn skill rewarded spells after all skills have been loaded to prevent learning a skill from them before its loaded with proper value from DB
26573 for (auto const& [skillId, skillValue] : loadedSkillValues)
26574 {
26575 LearnSkillRewardedSpells(skillId, skillValue, race);
26576
26577 // enable parent skill line if missing
26578 SkillLineEntry const* skillEntry = sSkillLineStore.LookupEntry(skillId);
26579 if (skillEntry->ParentSkillLineID && skillEntry->ParentTierIndex > 0 && GetSkillStep(skillEntry->ParentSkillLineID) < skillEntry->ParentTierIndex)
26580 if (SkillRaceClassInfoEntry const* rcEntry = sDB2Manager.GetSkillRaceClassInfo(skillEntry->ParentSkillLineID, GetRace(), GetClass()))
26581 if (SkillTiersEntry const* tier = sObjectMgr->GetSkillTier(rcEntry->SkillTierID))
26582 SetSkill(skillEntry->ParentSkillLineID, skillEntry->ParentTierIndex, std::max<uint16>(GetPureSkillValue(skillEntry->ParentSkillLineID), 1), tier->GetValueForTierIndex(skillEntry->ParentTierIndex - 1));
26583
26584 if (std::vector<SkillLineEntry const*> const* childSkillLines = sDB2Manager.GetSkillLinesForParentSkill(skillId))
26585 {
26586 for (auto childItr = childSkillLines->begin(); childItr != childSkillLines->end() && mSkillStatus.size() < PLAYER_MAX_SKILLS; ++childItr)
26587 {
26588 if (mSkillStatus.find((*childItr)->ID) == mSkillStatus.end())
26589 {
26590 uint32 pos = mSkillStatus.size();
26591 SetSkillLineId(pos, (*childItr)->ID);
26592 SetSkillStartingRank(pos, 1);
26593 mSkillStatus.insert(SkillStatusMap::value_type((*childItr)->ID, SkillStatusData(pos, SKILL_UNCHANGED)));
26594 }
26595 }
26596 }
26597 }
26598
26599 for (uint16 skill : loadedProfessionsWithoutSlot)
26600 {
26601 int32 emptyProfessionSlot = FindEmptyProfessionSlotFor(skill);
26602 if (emptyProfessionSlot != -1)
26603 {
26605 mSkillStatus.at(skill).uState = SKILL_CHANGED;
26606 }
26607 }
26608
26611}
26612
26614{
26615 ItemTemplate const* pProto = pItem->GetTemplate();
26616
26617 // proto based limitations
26618 if (InventoryResult res = CanEquipUniqueItem(pProto, eslot, limit_count))
26619 return res;
26620
26621 // check unique-equipped on gems
26622 for (UF::SocketedGem const& gemData : pItem->m_itemData->Gems)
26623 {
26624 ItemTemplate const* pGem = sObjectMgr->GetItemTemplate(gemData.ItemID);
26625 if (!pGem)
26626 continue;
26627
26628 // include for check equip another gems with same limit category for not equipped item (and then not counted)
26629 uint32 gem_limit_count = !pItem->IsEquipped() && pGem->GetItemLimitCategory()
26631
26632 if (InventoryResult res = CanEquipUniqueItem(pGem, eslot, gem_limit_count))
26633 return res;
26634 }
26635
26636 return EQUIP_ERR_OK;
26637}
26638
26639InventoryResult Player::CanEquipUniqueItem(ItemTemplate const* itemProto, uint8 except_slot, uint32 limit_count) const
26640{
26641 // check unique-equipped on item
26642 if (itemProto->HasFlag(ITEM_FLAG_UNIQUE_EQUIPPABLE))
26643 {
26644 // there is an equip limit on this item
26645 if (HasItemOrGemWithIdEquipped(itemProto->GetId(), 1, except_slot))
26647 }
26648
26649 // check unique-equipped limit
26650 if (itemProto->GetItemLimitCategory())
26651 {
26652 ItemLimitCategoryEntry const* limitEntry = sItemLimitCategoryStore.LookupEntry(itemProto->GetItemLimitCategory());
26653 if (!limitEntry)
26655
26656 // NOTE: limitEntry->mode not checked because if item have have-limit then it applied and to equip case
26657 uint8 limitQuantity = GetItemLimitCategoryQuantity(limitEntry);
26658
26659 if (limit_count > limitQuantity)
26661
26662 // there is an equip limit on this item
26663 if (HasItemWithLimitCategoryEquipped(itemProto->GetItemLimitCategory(), limitQuantity - limit_count + 1, except_slot))
26665 else if (HasGemWithLimitCategoryEquipped(itemProto->GetItemLimitCategory(), limitQuantity - limit_count + 1, except_slot))
26667 }
26668
26669 return EQUIP_ERR_OK;
26670}
26671
26673{
26674 m_lastFallTime = time;
26675 m_lastFallZ = z;
26676}
26677
26678void Player::HandleFall(MovementInfo const& movementInfo)
26679{
26680 // calculate total z distance of the fall
26681 float z_diff = m_lastFallZ - movementInfo.pos.GetPositionZ();
26682 //TC_LOG_DEBUG("misc", "zDiff = {}", z_diff);
26683
26684 //Players with low fall distance, Feather Fall or physical immunity (charges used) are ignored
26685 // 14.57 can be calculated by resolving damageperc formula below to 0
26686 if (z_diff >= 14.57f && !isDead() && !IsGameMaster() &&
26689 {
26690 //Safe fall, fall height reduction
26692
26693 float damageperc = 0.018f*(z_diff-safe_fall)-0.2426f;
26694
26695 if (damageperc > 0)
26696 {
26697 uint32 damage = (uint32)(damageperc * GetMaxHealth()*sWorld->getRate(RATE_DAMAGE_FALL));
26698
26700 damage = 0;
26701
26702 float height = movementInfo.pos.m_positionZ;
26703 UpdateGroundPositionZ(movementInfo.pos.m_positionX, movementInfo.pos.m_positionY, height);
26704
26706
26707 if (damage > 0)
26708 {
26709 //Prevent fall damage from being more than the player maximum health
26710 if (damage > GetMaxHealth())
26711 damage = GetMaxHealth();
26712
26713 // Gust of Wind
26714 if (HasAura(43621))
26715 damage = GetMaxHealth()/2;
26716
26717 uint32 original_health = GetHealth();
26718 uint32 final_damage = EnvironmentalDamage(DAMAGE_FALL, damage);
26719
26720 // recheck alive, might have died of EnvironmentalDamage, avoid cases when player die in fact like Spirit of Redemption case
26721 if (IsAlive() && final_damage < original_health)
26723 }
26724
26725 //Z given by moveinfo, LastZ, FallTime, WaterZ, MapZ, Damage, Safefall reduction
26726 TC_LOG_DEBUG("entities.player.falldamage", "FALLDAMAGE z={} sz={} pZ={} FallTime={} mZ={} damage={} SF={}\nPlayer debug info:\n{}", movementInfo.pos.GetPositionZ(), height, GetPositionZ(), movementInfo.jump.fallTime, height, damage, safe_fall, GetDebugInfo());
26727 }
26728 }
26729}
26730
26732{
26733 m_achievementMgr->Reset();
26734}
26735
26737{
26738 m_achievementMgr->SendAchievementInfo(player);
26739}
26740
26742{
26743 return m_achievementMgr->GetAchievementPoints();
26744}
26745
26746std::vector<uint32> Player::GetCompletedAchievementIds() const
26747{
26748 return m_achievementMgr->GetCompletedAchievementIds();
26749}
26750
26751bool Player::HasAchieved(uint32 achievementId) const
26752{
26753 return m_achievementMgr->HasAchieved(achievementId);
26754}
26755
26756void Player::StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost/* = Milliseconds::zero()*/)
26757{
26758 m_achievementMgr->StartCriteria(startEvent, entry, timeLost);
26759}
26760
26762{
26763 m_achievementMgr->FailCriteria(condition, failAsset);
26764 m_questObjectiveCriteriaMgr->FailCriteria(condition, failAsset);
26765}
26766
26767void Player::UpdateCriteria(CriteriaType type, uint64 miscValue1 /*= 0*/, uint64 miscValue2 /*= 0*/, uint64 miscValue3 /*= 0*/, WorldObject* ref /*= nullptr*/)
26768{
26769 m_achievementMgr->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, ref, this);
26770 m_questObjectiveCriteriaMgr->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, ref, this);
26771
26772 // Update only individual achievement criteria here, otherwise we may get multiple updates
26773 // from a single boss kill
26775 return;
26776
26777 if (Scenario* scenario = GetScenario())
26778 scenario->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, ref, this);
26779
26780 if (Guild* guild = sGuildMgr->GetGuildById(GetGuildId()))
26781 guild->UpdateCriteria(type, miscValue1, miscValue2, miscValue3, ref, this);
26782}
26783
26785{
26786 m_achievementMgr->CompletedAchievement(entry, this);
26787}
26788
26789bool Player::ModifierTreeSatisfied(uint32 modifierTreeId) const
26790{
26791 return m_achievementMgr->ModifierTreeSatisfied(modifierTreeId);
26792}
26793
26795{
26796 if (IsInCombat())
26798
26799 if (isDead())
26801
26804
26805 TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
26806 if (!talentInfo)
26807 return TALENT_FAILED_UNKNOWN;
26808
26809 if (talentInfo->SpecID && ChrSpecialization(talentInfo->SpecID) != GetPrimarySpecialization())
26810 return TALENT_FAILED_UNKNOWN;
26811
26812 // prevent learn talent for different class (cheating)
26813 if (talentInfo->ClassID != GetClass())
26814 return TALENT_FAILED_UNKNOWN;
26815
26816 // check if we have enough talent points
26817 if (talentInfo->TierID >= m_activePlayerData->MaxTalentTiers)
26818 return TALENT_FAILED_UNKNOWN;
26819
26820 // TODO: prevent changing talents that are on cooldown
26821
26822 // Check if there is a different talent for us to learn in selected slot
26823 // Example situation:
26824 // Warrior talent row 2 slot 0
26825 // Talent.dbc has an entry for each specialization
26826 // but only 2 out of 3 have SpecID != 0
26827 // We need to make sure that if player is in one of these defined specs he will not learn the other choice
26828 TalentEntry const* bestSlotMatch = nullptr;
26829 for (TalentEntry const* talent : sDB2Manager.GetTalentsByPosition(GetClass(), talentInfo->TierID, talentInfo->ColumnIndex))
26830 {
26831 if (!talent->SpecID)
26832 bestSlotMatch = talent;
26833 else if (ChrSpecialization(talent->SpecID) == GetPrimarySpecialization())
26834 {
26835 bestSlotMatch = talent;
26836 break;
26837 }
26838 }
26839
26840 if (talentInfo != bestSlotMatch)
26841 return TALENT_FAILED_UNKNOWN;
26842
26843 // Check if player doesn't have any talent in current tier
26844 for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
26845 {
26846 for (TalentEntry const* talent : sDB2Manager.GetTalentsByPosition(GetClass(), talentInfo->TierID, c))
26847 {
26848 if (!HasTalent(talent->ID, GetActiveTalentGroup()))
26849 continue;
26850
26853
26854 if (GetSpellHistory()->HasCooldown(talent->SpellID))
26855 {
26856 *spellOnCooldown = talent->SpellID;
26858 }
26859
26860 RemoveTalent(talent);
26861 }
26862 }
26863
26864 // spell not set in talent.dbc
26865 uint32 spellid = talentInfo->SpellID;
26866 if (!spellid)
26867 {
26868 TC_LOG_ERROR("entities.player", "Player::LearnTalent: Talent.dbc has no spellInfo for talent: {} (spell id = 0)", talentId);
26869 return TALENT_FAILED_UNKNOWN;
26870 }
26871
26872 // already known
26873 if (HasTalent(talentId, GetActiveTalentGroup()) || HasSpell(spellid))
26874 return TALENT_FAILED_UNKNOWN;
26875
26876 if (!AddTalent(talentInfo, GetActiveTalentGroup(), true))
26877 return TALENT_FAILED_UNKNOWN;
26878
26879 TC_LOG_DEBUG("misc", "Player::LearnTalent: TalentID: {} Spell: {} Group: {}\n", talentId, spellid, GetActiveTalentGroup());
26880
26881 return TALENT_LEARN_OK;
26882}
26883
26885{
26886 // Reset only talents that have different spells for each spec
26887 uint32 class_ = GetClass();
26888 for (uint32 t = 0; t < MAX_TALENT_TIERS; ++t)
26889 for (uint32 c = 0; c < MAX_TALENT_COLUMNS; ++c)
26890 if (sDB2Manager.GetTalentsByPosition(class_, t, c).size() > 1)
26891 for (TalentEntry const* talent : sDB2Manager.GetTalentsByPosition(class_, t, c))
26892 RemoveTalent(talent);
26893
26895
26897
26898 ChrSpecializationEntry const* defaultSpec = ASSERT_NOTNULL(sDB2Manager.GetDefaultChrSpecializationForClass(GetClass()));
26899 SetPrimarySpecialization(defaultSpec->ID);
26900 SetActiveTalentGroup(defaultSpec->OrderIndex);
26901
26903
26905 UpdateItemSetAuras(false);
26906}
26907
26909{
26910 if (slot >= MAX_PVP_TALENT_SLOTS)
26911 return TALENT_FAILED_UNKNOWN;
26912
26913 if (IsInCombat())
26915
26916 if (isDead())
26918
26919 PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(talentID);
26920 if (!talentInfo)
26921 return TALENT_FAILED_UNKNOWN;
26922
26923 if (talentInfo->SpecID != int32(GetPrimarySpecialization()))
26924 return TALENT_FAILED_UNKNOWN;
26925
26926 if (talentInfo->LevelRequired > GetLevel())
26927 return TALENT_FAILED_UNKNOWN;
26928
26929 if (sDB2Manager.GetRequiredLevelForPvpTalentSlot(slot, Classes(GetClass())) > GetLevel())
26930 return TALENT_FAILED_UNKNOWN;
26931
26932 if (PvpTalentCategoryEntry const* talentCategory = sPvpTalentCategoryStore.LookupEntry(talentInfo->PvpTalentCategoryID))
26933 if (!(talentCategory->TalentSlotMask & (1 << slot)))
26934 return TALENT_FAILED_UNKNOWN;
26935
26936 // Check if player doesn't have this talent in other slot
26937 if (HasPvpTalent(talentID, GetActiveTalentGroup()))
26938 return TALENT_FAILED_UNKNOWN;
26939
26940 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(talentInfo->PlayerConditionID))
26941 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
26943
26944 if (PvpTalentEntry const* talent = sPvpTalentStore.LookupEntry(GetPvpTalentMap(GetActiveTalentGroup())[slot]))
26945 {
26948
26949 if (GetSpellHistory()->HasCooldown(talent->SpellID))
26950 {
26951 *spellOnCooldown = talent->SpellID;
26953 }
26954
26956 }
26957
26958 if (!AddPvpTalent(talentInfo, GetActiveTalentGroup(), slot))
26959 return TALENT_FAILED_UNKNOWN;
26960
26961 return TALENT_LEARN_OK;
26962}
26963
26964bool Player::AddPvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup, uint8 slot)
26965{
26966 ASSERT(talent);
26967 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE);
26968 if (!spellInfo)
26969 {
26970 TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) does not exist.", talent->SpellID);
26971 return false;
26972 }
26973
26974 if (!SpellMgr::IsSpellValid(spellInfo, this, false))
26975 {
26976 TC_LOG_ERROR("spells", "Player::AddTalent: Spell (ID: {}) is invalid", talent->SpellID);
26977 return false;
26978 }
26979
26980 if (activeTalentGroup == GetActiveTalentGroup() && HasAuraType(SPELL_AURA_PVP_TALENTS))
26981 {
26982 LearnSpell(talent->SpellID, true);
26983
26984 // Move this to toggle ?
26985 if (talent->OverridesSpellID)
26986 AddOverrideSpell(talent->OverridesSpellID, talent->SpellID);
26987 }
26988
26989 GetPvpTalentMap(activeTalentGroup)[slot] = talent->ID;
26990
26991 return true;
26992}
26993
26994void Player::RemovePvpTalent(PvpTalentEntry const* talent, uint8 activeTalentGroup)
26995{
26996 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talent->SpellID, DIFFICULTY_NONE);
26997 if (!spellInfo)
26998 return;
26999
27000 RemoveSpell(talent->SpellID, true);
27001
27002 // Move this to toggle ?
27003 if (talent->OverridesSpellID)
27005
27006 // if this talent rank can be found in the PlayerTalentMap, mark the talent as removed so it gets deleted
27007 auto plrPvpTalent = std::find(GetPvpTalentMap(activeTalentGroup).begin(), GetPvpTalentMap(activeTalentGroup).end(), talent->ID);
27008 if (plrPvpTalent != GetPvpTalentMap(activeTalentGroup).end())
27009 *plrPvpTalent = 0;
27010}
27011
27013{
27015 for (uint32 pvpTalentId : pvpTalents)
27016 {
27017 if (PvpTalentEntry const* pvpTalentInfo = sPvpTalentStore.LookupEntry(pvpTalentId))
27018 {
27019 if (enable)
27020 {
27021 LearnSpell(pvpTalentInfo->SpellID, false);
27022 if (pvpTalentInfo->OverridesSpellID)
27023 AddOverrideSpell(pvpTalentInfo->OverridesSpellID, pvpTalentInfo->SpellID);
27024 }
27025 else
27026 {
27027 if (pvpTalentInfo->OverridesSpellID)
27028 RemoveOverrideSpell(pvpTalentInfo->OverridesSpellID, pvpTalentInfo->SpellID);
27029 RemoveSpell(pvpTalentInfo->SpellID, true);
27030 }
27031 }
27032 }
27033}
27034
27035bool Player::HasPvpTalent(uint32 talentID, uint8 activeTalentGroup) const
27036{
27037 return std::find(GetPvpTalentMap(activeTalentGroup).begin(), GetPvpTalentMap(activeTalentGroup).end(), talentID) != GetPvpTalentMap(activeTalentGroup).end();
27038}
27039
27040void Player::EnablePvpRules(bool dueToCombat /*= false*/)
27041{
27042 if (!HasPvpRulesEnabled())
27043 {
27044 if (!HasSpell(195710)) // Honorable Medallion
27045 CastSpell(this, 208682, true); // Learn Gladiator's Medallion
27046
27048 }
27049
27050 if (!dueToCombat)
27051 {
27053 {
27054 if (!aura->IsPermanent())
27055 {
27056 aura->SetMaxDuration(-1);
27057 aura->SetDuration(-1);
27058 }
27059 }
27060 }
27061
27063}
27064
27066{
27067 // Don't disable pvp rules when in pvp zone.
27069 return;
27070
27071 if (!GetCombatManager().HasPvPCombat())
27072 {
27075 }
27076 else if (Aura* aura = GetAura(SPELL_PVP_RULES_ENABLED))
27077 aura->SetDuration(aura->GetSpellInfo()->GetMaxDuration());
27078}
27079
27081{
27083}
27084
27086{
27088}
27089
27091{
27092 if (InBattleground())
27093 return true;
27094
27095 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaID))
27096 {
27097 do
27098 {
27099 if (area->IsSanctuary())
27100 return false;
27101
27102 if (area->GetFlags().HasFlag(AreaFlags::FreeForAllPvP))
27103 return true;
27104
27105 if (sBattlefieldMgr->IsWorldPvpArea(area->ID))
27106 return true;
27107
27108 area = sAreaTableStore.LookupEntry(area->ParentAreaID);
27109
27110 } while (area);
27111 }
27112
27113 return false;
27114}
27115
27117{
27118 if (m_lastFallTime >= minfo.jump.fallTime || m_lastFallZ <= minfo.pos.GetPositionZ() || opcode == CMSG_MOVE_FALL_LAND)
27120}
27121
27123{
27124 Pet* pet = GetPet();
27125 if (!pet)
27126 return;
27127
27129 pet->SetReactState(reactState);
27130 if (CharmInfo* charmInfo = pet->GetCharmInfo())
27131 charmInfo->SetCommandState(commandState);
27132
27134
27136 petMode.PetGUID = pet->GetGUID();
27137 petMode.ReactState = reactState;
27138 petMode.CommandState = commandState;
27139 petMode.Flag = 0;
27140 SendDirectMessage(petMode.Write());
27141}
27142
27144{
27145 if (Pet* pet = GetPet())
27146 {
27148 petMode.PetGUID = pet->GetGUID();
27150 {
27152 pet->SetReactState(*m_temporaryPetReactState);
27153 }
27154
27155 if (CharmInfo* charmInfo = pet->GetCharmInfo())
27156 petMode.CommandState = charmInfo->GetCommandState();
27157
27158 petMode.Flag = 0;
27159 SendDirectMessage(petMode.Write());
27160 }
27161
27163}
27164
27166{
27167 Pet* pet = GetPet();
27168 if (!pet)
27169 return;
27170
27172 {
27174 m_oldpetspell = pet->m_unitData->CreatedBySpell;
27175 }
27176
27178}
27179
27181{
27183 return;
27184
27185 // not resummon in not appropriate state
27187 return;
27188
27189 if (!GetPetGUID().IsEmpty())
27190 return;
27191
27192 Pet* NewPet = new Pet(this);
27193 if (!NewPet->LoadPetFromDB(this, 0, m_temporaryUnsummonedPetNumber, true))
27194 delete NewPet;
27195
27197}
27198
27199void Player::UnsummonBattlePetTemporaryIfAny(bool onFlyingMount /*= false*/)
27200{
27201 Creature* battlepet = GetSummonedBattlePet();
27202 if (!battlepet || !battlepet->IsSummon())
27203 return;
27204
27205 if (onFlyingMount && !battlepet->ToTempSummon()->IsDismissedOnFlyingMount())
27206 return;
27207
27208 if (battlepet->ToTempSummon()->IsAutoResummoned())
27210
27212}
27213
27215{
27217 return;
27218
27219 // not resummon in not appropriate state
27221 return;
27222
27224
27226}
27227
27229{
27231}
27232
27233bool Player::CanSeeGossipOn(Creature const* creature) const
27234{
27235 if (creature->HasNpcFlag(UNIT_NPC_FLAG_GOSSIP))
27236 {
27237 if (GetGossipMenuForSource(creature))
27238 return true;
27239 }
27240
27241 // for cases with questgiver/ender without gossip menus
27242 if (creature->HasNpcFlag(UNIT_NPC_FLAG_QUESTGIVER))
27243 {
27244 QuestRelationResult objectQIR = sObjectMgr->GetCreatureQuestInvolvedRelations(creature->GetEntry());
27245 for (uint32 quest_id : objectQIR)
27246 {
27247 QuestStatus status = GetQuestStatus(quest_id);
27248 if (status == QUEST_STATUS_COMPLETE || status == QUEST_STATUS_INCOMPLETE)
27249 return true;
27250 }
27251
27252 QuestRelationResult objectQR = sObjectMgr->GetCreatureQuestRelations(creature->GetEntry());
27253 for (uint32 quest_id : objectQR)
27254 {
27255 Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
27256 if (!quest)
27257 continue;
27258
27259 if (CanTakeQuest(quest, false))
27260 return true;
27261 }
27262 }
27263 return false;
27264}
27265
27267{
27269 return false;
27270
27271 auto clickBounds = sObjectMgr->GetSpellClickInfoMapBounds(c->GetEntry());
27272 if (clickBounds.begin() == clickBounds.end())
27273 return false;
27274
27275 for (auto const& clickPair : clickBounds)
27276 {
27277 if (!clickPair.second.IsFitToRequirements(this, c))
27278 return false;
27279
27280 if (sConditionMgr->IsObjectMeetingSpellClickConditions(c->GetEntry(), clickPair.second.spellId, this, c))
27281 return true;
27282 }
27283
27284 return false;
27285}
27286
27288{
27291
27292 for (uint8 i = 0; i < MAX_SPECIALIZATIONS; ++i)
27293 {
27294 ChrSpecializationEntry const* spec = sDB2Manager.GetChrSpecializationByIndex(GetClass(), i);
27295 if (!spec)
27296 continue;
27297
27298 PlayerTalentMap* talents = GetTalentMap(i);
27299 PlayerPvpTalentMap const& pvpTalents = GetPvpTalentMap(i);
27300
27302 groupInfoPkt.SpecID = spec->ID;
27303 groupInfoPkt.TalentIDs.reserve(talents->size());
27304
27305 for (PlayerTalentMap::const_iterator itr = talents->begin(); itr != talents->end(); ++itr)
27306 {
27307 if (itr->second == PLAYERSPELL_REMOVED)
27308 continue;
27309
27310 TalentEntry const* talentInfo = sTalentStore.LookupEntry(itr->first);
27311 if (!talentInfo)
27312 {
27313 TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '{}' ({}) has unknown talent id: {}",
27314 GetName(), GetGUID().ToString(), itr->first);
27315 continue;
27316 }
27317
27318 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE);
27319 if (!spellEntry)
27320 {
27321 TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '{}' ({}) has unknown talent spell: {}",
27322 GetName(), GetGUID().ToString(), talentInfo->SpellID);
27323 continue;
27324 }
27325
27326 groupInfoPkt.TalentIDs.push_back(uint16(itr->first));
27327 }
27328
27329 for (std::size_t slot = 0; slot < MAX_PVP_TALENT_SLOTS; ++slot)
27330 {
27331 if (!pvpTalents[slot])
27332 continue;
27333
27334 PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(pvpTalents[slot]);
27335 if (!talentInfo)
27336 {
27337 TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '{}' ({}) has unknown pvp talent id: {}",
27338 GetName(), GetGUID().ToString(), pvpTalents[slot]);
27339 continue;
27340 }
27341
27342 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE);
27343 if (!spellEntry)
27344 {
27345 TC_LOG_ERROR("entities.player", "Player::SendTalentsInfoData: Player '{}' ({}) has unknown pvp talent spell: {}",
27346 GetName(), GetGUID().ToString(), talentInfo->SpellID);
27347 continue;
27348 }
27349
27350 groupInfoPkt.PvPTalents.emplace_back();
27351 WorldPackets::Talent::PvPTalent& pvpTalent = groupInfoPkt.PvPTalents.back();
27352 pvpTalent.PvPTalentID = pvpTalents[slot];
27353 pvpTalent.Slot = slot;
27354 }
27355
27356 if (i == GetActiveTalentGroup())
27357 packet.Info.ActiveGroup = packet.Info.TalentGroups.size();
27358
27359 if (!groupInfoPkt.TalentIDs.empty() || !groupInfoPkt.PvPTalents.empty() || i == GetActiveTalentGroup())
27360 packet.Info.TalentGroups.push_back(groupInfoPkt);
27361 }
27362
27363 SendDirectMessage(packet.Write());
27364}
27365
27367{
27369
27370 for (EquipmentSetContainer::value_type const& eqSet : _equipmentSets)
27371 {
27372 if (eqSet.second.State == EQUIPMENT_SET_DELETED)
27373 continue;
27374
27375 data.SetData.push_back(&eqSet.second.Data);
27376 }
27377
27378 SendDirectMessage(data.Write());
27379}
27380
27382{
27383 if (newEqSet.Guid != 0)
27384 {
27385 // something wrong...
27386 EquipmentSetContainer::const_iterator itr = _equipmentSets.find(newEqSet.Guid);
27387 if (itr == _equipmentSets.end() || itr->second.Data.Guid != newEqSet.Guid)
27388 {
27389 TC_LOG_ERROR("entities.player", "Player::SetEquipmentSet: Player '{}' ({}) tried to save nonexistent equipment set {} (index: {})",
27390 GetName(), GetGUID().ToString(), newEqSet.Guid, newEqSet.SetID);
27391 return;
27392 }
27393 }
27394
27395 uint64 setGuid = (newEqSet.Guid != 0) ? newEqSet.Guid : sObjectMgr->GenerateEquipmentSetGuid();
27396
27397 EquipmentSetInfo& eqSlot = _equipmentSets[setGuid];
27398 eqSlot.Data = newEqSet;
27399
27400 if (eqSlot.Data.Guid == 0)
27401 {
27402 eqSlot.Data.Guid = setGuid;
27403
27405 data.GUID = eqSlot.Data.Guid;
27406 data.Type = eqSlot.Data.Type;
27407 data.SetID = eqSlot.Data.SetID;
27408 SendDirectMessage(data.Write());
27409 }
27410
27412}
27413
27415{
27416 for (EquipmentSetContainer::iterator itr = _equipmentSets.begin(); itr != _equipmentSets.end();)
27417 {
27418 EquipmentSetInfo& eqSet = itr->second;
27420 uint8 j = 0;
27421 switch (eqSet.State)
27422 {
27424 ++itr;
27425 break; // nothing do
27427 {
27429 {
27430 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_EQUIP_SET);
27431 stmt->setString(j++, eqSet.Data.SetName);
27432 stmt->setString(j++, eqSet.Data.SetIcon);
27433 stmt->setUInt32(j++, eqSet.Data.IgnoreMask);
27434 stmt->setInt32(j++, eqSet.Data.AssignedSpecIndex);
27436 stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter());
27437 stmt->setUInt64(j++, GetGUID().GetCounter());
27438 stmt->setUInt64(j++, eqSet.Data.Guid);
27439 stmt->setUInt32(j, eqSet.Data.SetID);
27440 }
27441 else
27442 {
27443 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_TRANSMOG_OUTFIT);
27444 stmt->setString(j++, eqSet.Data.SetName);
27445 stmt->setString(j++, eqSet.Data.SetIcon);
27446 stmt->setUInt32(j++, eqSet.Data.IgnoreMask);
27448 stmt->setInt32(j++, eqSet.Data.Appearances[i]);
27449 for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i)
27450 stmt->setInt32(j++, eqSet.Data.Enchants[i]);
27451 stmt->setUInt64(j++, GetGUID().GetCounter());
27452 stmt->setUInt64(j++, eqSet.Data.Guid);
27453 stmt->setUInt32(j, eqSet.Data.SetID);
27454 }
27455 trans->Append(stmt);
27457 ++itr;
27458 break;
27459 }
27460 case EQUIPMENT_SET_NEW:
27461 {
27463 {
27464 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_EQUIP_SET);
27465 stmt->setUInt64(j++, GetGUID().GetCounter());
27466 stmt->setUInt64(j++, eqSet.Data.Guid);
27467 stmt->setUInt32(j++, eqSet.Data.SetID);
27468 stmt->setString(j++, eqSet.Data.SetName);
27469 stmt->setString(j++, eqSet.Data.SetIcon);
27470 stmt->setUInt32(j++, eqSet.Data.IgnoreMask);
27471 stmt->setInt32(j++, eqSet.Data.AssignedSpecIndex);
27473 stmt->setUInt64(j++, eqSet.Data.Pieces[i].GetCounter());
27474 }
27475 else
27476 {
27477 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_TRANSMOG_OUTFIT);
27478 stmt->setUInt64(j++, GetGUID().GetCounter());
27479 stmt->setUInt64(j++, eqSet.Data.Guid);
27480 stmt->setUInt32(j++, eqSet.Data.SetID);
27481 stmt->setString(j++, eqSet.Data.SetName);
27482 stmt->setString(j++, eqSet.Data.SetIcon);
27483 stmt->setUInt32(j++, eqSet.Data.IgnoreMask);
27485 stmt->setInt32(j++, eqSet.Data.Appearances[i]);
27486 for (std::size_t i = 0; i < eqSet.Data.Enchants.size(); ++i)
27487 stmt->setInt32(j++, eqSet.Data.Enchants[i]);
27488 }
27489 trans->Append(stmt);
27491 ++itr;
27492 break;
27493 }
27496 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_EQUIP_SET);
27497 else
27498 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_TRANSMOG_OUTFIT);
27499 stmt->setUInt64(0, eqSet.Data.Guid);
27500 trans->Append(stmt);
27501 itr = _equipmentSets.erase(itr);
27502 break;
27503 }
27504 }
27505}
27506
27508{
27510 stmt->setUInt64(0, GetGUID().GetCounter());
27511 trans->Append(stmt);
27512 /* guid, bgInstanceID, bgTeam, x, y, z, o, map, taxi[0], taxi[1], mountSpell */
27513 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_BGDATA);
27514 stmt->setUInt64(0, GetGUID().GetCounter());
27516 stmt->setUInt16(2, m_bgData.bgTeam);
27521 stmt->setUInt16(7, m_bgData.joinPos.GetMapId());
27522 stmt->setUInt32(8, m_bgData.taxiPath[0]);
27523 stmt->setUInt32(9, m_bgData.taxiPath[1]);
27524 stmt->setUInt32(10, m_bgData.mountSpell);
27525 stmt->setUInt64(11, m_bgData.queueId.GetPacked());
27526 trans->Append(stmt);
27527}
27528
27530{
27531 for (EquipmentSetContainer::iterator itr = _equipmentSets.begin(); itr != _equipmentSets.end();)
27532 {
27533 if (itr->second.Data.Guid == id)
27534 {
27535 if (itr->second.State == EQUIPMENT_SET_NEW)
27536 itr = _equipmentSets.erase(itr);
27537 else
27538 itr->second.State = EQUIPMENT_SET_DELETED;
27539 break;
27540 }
27541 ++itr;
27542 }
27543}
27544
27545void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/)
27546{
27547 m_atLoginFlags &= ~flags;
27548
27549 if (persist)
27550 {
27552
27553 stmt->setUInt16(0, uint16(flags));
27554 stmt->setUInt64(1, GetGUID().GetCounter());
27555
27556 CharacterDatabase.Execute(stmt);
27557 }
27558}
27559
27561{
27562 // this may be called during Map::Update
27563 // after decrement+unlink, ++m_mapRefIter will continue correctly
27564 // when the first element of the list is being removed
27565 // nocheck_prev will return the padding element of the RefManager
27566 // instead of nullptr in the case of prev
27567 GetMap()->UpdateIteratorBack(this);
27569 GetMapRef().unlink();
27570}
27571
27573{
27574 Unit::SetMap(map);
27575 m_mapRef.link(map, this);
27576}
27577
27579{
27580 // SELECT talentGroup, glyphId from character_glyphs WHERE guid = ?
27581 if (!result)
27582 return;
27583
27584 do
27585 {
27586 Field* fields = result->Fetch();
27587
27588 uint8 spec = fields[0].GetUInt8();
27589 if (spec >= MAX_SPECIALIZATIONS || !sDB2Manager.GetChrSpecializationByIndex(GetClass(), spec))
27590 continue;
27591
27592 uint16 glyphId = fields[1].GetUInt16();
27593 if (!sGlyphPropertiesStore.LookupEntry(glyphId))
27594 continue;
27595
27596 GetGlyphs(spec).push_back(glyphId);
27597
27598 } while (result->NextRow());
27599}
27600
27602{
27604 stmt->setUInt64(0, GetGUID().GetCounter());
27605 trans->Append(stmt);
27606
27607 for (uint8 spec = 0; spec < MAX_SPECIALIZATIONS; ++spec)
27608 {
27609 for (uint32 glyphId : GetGlyphs(spec))
27610 {
27611 uint8 index = 0;
27612
27613 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS);
27614 stmt->setUInt64(index++, GetGUID().GetCounter());
27615 stmt->setUInt8(index++, spec);
27616 stmt->setUInt16(index++, uint16(glyphId));
27617
27618 trans->Append(stmt);
27619 }
27620 }
27621}
27622
27624{
27625 // "SELECT talentId, talentGroup FROM character_talent WHERE guid = ?"
27626 if (result)
27627 {
27628 do
27629 if (TalentEntry const* talent = sTalentStore.LookupEntry((*result)[0].GetUInt32()))
27630 AddTalent(talent, (*result)[1].GetUInt8(), false);
27631 while (result->NextRow());
27632 }
27633}
27634
27636{
27637 // "SELECT talentID0, talentID1, talentID2, talentID3, talentGroup FROM character_pvp_talent WHERE guid = ?"
27638 if (result)
27639 {
27640 do
27641 for (uint8 slot = 0; slot < MAX_PVP_TALENT_SLOTS; ++slot)
27642 if (PvpTalentEntry const* talent = sPvpTalentStore.LookupEntry((*result)[slot].GetUInt32()))
27643 AddPvpTalent(talent, (*result)[4].GetUInt8(), slot);
27644 while (result->NextRow());
27645 }
27646}
27647
27649{
27650 std::unordered_multimap<int32, WorldPackets::Traits::TraitEntry> traitEntriesByConfig;
27651 if (entriesResult)
27652 {
27653 // 0 1, 2 3 4
27654 // SELECT traitConfigId, traitNodeId, traitNodeEntryId, rank, grantedRanks FROM character_trait_entry WHERE guid = ?
27655 do
27656 {
27657 Field* fields = entriesResult->Fetch();
27659 traitEntry.TraitNodeID = fields[1].GetInt32();
27660 traitEntry.TraitNodeEntryID = fields[2].GetInt32();
27661 traitEntry.Rank = fields[3].GetInt32();
27662 traitEntry.GrantedRanks = fields[4].GetInt32();
27663
27664 if (!TraitMgr::IsValidEntry(traitEntry))
27665 continue;
27666
27667 traitEntriesByConfig.emplace(fields[0].GetInt32(), traitEntry);
27668
27669 } while (entriesResult->NextRow());
27670 }
27671
27672 if (configsResult)
27673 {
27674 // 0 1 2 3 4 5 6 7
27675 // SELECT traitConfigId, type, chrSpecializationId, combatConfigFlags, localIdentifier, skillLineId, traitSystemId, `name` FROM character_trait_config WHERE guid = ?
27676 do
27677 {
27678 Field* fields = configsResult->Fetch();
27680 traitConfig.ID = fields[0].GetInt32();
27681 traitConfig.Type = static_cast<TraitConfigType>(fields[1].GetInt32());
27682 switch (traitConfig.Type)
27683 {
27685 traitConfig.ChrSpecializationID = fields[2].GetInt32();
27686 traitConfig.CombatConfigFlags = static_cast<TraitCombatConfigFlags>(fields[3].GetInt32());
27687 traitConfig.LocalIdentifier = fields[4].GetInt32();
27688 break;
27690 traitConfig.SkillLineID = fields[5].GetInt32();
27691 break;
27693 traitConfig.TraitSystemID = fields[6].GetInt32();
27694 break;
27695 default:
27696 break;
27697 }
27698
27699 traitConfig.Name = fields[7].GetString();
27700
27701 for (auto&& [_, traitEntry] : Trinity::Containers::MapEqualRange(traitEntriesByConfig, traitConfig.ID))
27702 traitConfig.Entries.emplace_back() = traitEntry;
27703
27704 if (TraitMgr::ValidateConfig(traitConfig, this) != TraitMgr::LearnResult::Ok)
27705 {
27706 traitConfig.Entries.clear();
27707 for (UF::TraitEntry const& grantedEntry : TraitMgr::GetGrantedTraitEntriesForConfig(traitConfig, this))
27708 traitConfig.Entries.emplace_back(grantedEntry);
27709 }
27710
27711 AddTraitConfig(traitConfig);
27712
27713 } while (configsResult->NextRow());
27714 }
27715
27716 auto hasConfigForSpec = [&](int32 specId)
27717 {
27718 return m_activePlayerData->TraitConfigs.FindIndexIf([=](UF::TraitConfig const& traitConfig)
27719 {
27720 return traitConfig.Type == AsUnderlyingType(TraitConfigType::Combat)
27721 && traitConfig.ChrSpecializationID == specId
27723 }) >= 0;
27724 };
27725
27726 auto findFreeLocalIdentifier = [&](int32 specId)
27727 {
27728 int32 index = 1;
27729 while (m_activePlayerData->TraitConfigs.FindIndexIf([specId, index](UF::TraitConfig const& traitConfig)
27730 {
27731 return traitConfig.Type == AsUnderlyingType(TraitConfigType::Combat)
27732 && traitConfig.ChrSpecializationID == specId
27733 && traitConfig.LocalIdentifier == index;
27734 }) >= 0)
27735 ++index;
27736
27737 return index;
27738 };
27739
27740 for (uint32 i = 0; i < MAX_SPECIALIZATIONS - 1 /*initial spec doesnt get a config*/; ++i)
27741 {
27742 if (ChrSpecializationEntry const* spec = sDB2Manager.GetChrSpecializationByIndex(GetClass(), i))
27743 {
27744 if (hasConfigForSpec(spec->ID))
27745 continue;
27746
27748 traitConfig.Type = TraitConfigType::Combat;
27749 traitConfig.ChrSpecializationID = spec->ID;
27751 traitConfig.LocalIdentifier = findFreeLocalIdentifier(spec->ID);
27752 traitConfig.Name = spec->Name[GetSession()->GetSessionDbcLocale()];
27753
27754 CreateTraitConfig(traitConfig);
27755 }
27756 }
27757
27758 int32 activeConfig = m_activePlayerData->TraitConfigs.FindIndexIf([&](UF::TraitConfig const& traitConfig)
27759 {
27760 return traitConfig.Type == AsUnderlyingType(TraitConfigType::Combat)
27763 });
27764
27765 if (activeConfig >= 0)
27766 SetActiveCombatTraitConfigID(m_activePlayerData->TraitConfigs[activeConfig].ID);
27767
27768 for (UF::TraitConfig const& traitConfig : m_activePlayerData->TraitConfigs)
27769 {
27770 switch (static_cast<TraitConfigType>(*traitConfig.Type))
27771 {
27773 if (traitConfig.ID != int32(*m_activePlayerData->ActiveCombatTraitConfigID))
27774 continue;
27775 break;
27777 if (!HasSkill(traitConfig.SkillLineID))
27778 continue;
27779 break;
27780 default:
27781 break;
27782 }
27783
27784 ApplyTraitConfig(traitConfig.ID, true);
27785 }
27786}
27787
27789{
27791 stmt->setUInt64(0, GetGUID().GetCounter());
27792 trans->Append(stmt);
27793
27794 for (uint8 group = 0; group < MAX_SPECIALIZATIONS; ++group)
27795 {
27796 PlayerTalentMap* talents = GetTalentMap(group);
27797 for (auto itr = talents->begin(); itr != talents->end();)
27798 {
27799 if (itr->second == PLAYERSPELL_REMOVED)
27800 {
27801 itr = talents->erase(itr);
27802 continue;
27803 }
27804
27805 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
27806 stmt->setUInt64(0, GetGUID().GetCounter());
27807 stmt->setUInt32(1, itr->first);
27808 stmt->setUInt8(2, group);
27809 trans->Append(stmt);
27810 ++itr;
27811 }
27812 }
27813
27814 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_PVP_TALENT);
27815 stmt->setUInt64(0, GetGUID().GetCounter());
27816 trans->Append(stmt);
27817
27818 for (uint8 group = 0; group < MAX_SPECIALIZATIONS; ++group)
27819 {
27820 PlayerPvpTalentMap const& talents = GetPvpTalentMap(group);
27821 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_PVP_TALENT);
27822 stmt->setUInt64(0, GetGUID().GetCounter());
27823 stmt->setUInt32(1, talents[0]);
27824 stmt->setUInt32(2, talents[1]);
27825 stmt->setUInt32(3, talents[2]);
27826 stmt->setUInt32(4, talents[3]);
27827 stmt->setUInt8(5, group);
27828 trans->Append(stmt);
27829 }
27830}
27831
27833{
27834 CharacterDatabasePreparedStatement* stmt = nullptr;
27835 for (auto& [traitConfigId, state] : m_traitConfigStates)
27836 {
27837 switch (state)
27838 {
27840 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRAIT_ENTRIES);
27841 stmt->setUInt64(0, GetGUID().GetCounter());
27842 stmt->setInt32(1, traitConfigId);
27843 trans->Append(stmt);
27844
27845 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRAIT_CONFIGS);
27846 stmt->setUInt64(0, GetGUID().GetCounter());
27847 stmt->setInt32(1, traitConfigId);
27848 trans->Append(stmt);
27849
27850 if (UF::TraitConfig const* traitConfig = GetTraitConfig(traitConfigId))
27851 {
27852 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TRAIT_CONFIGS);
27853 stmt->setUInt64(0, GetGUID().GetCounter());
27854 stmt->setInt32(1, traitConfig->ID);
27855 stmt->setInt32(2, traitConfig->Type);
27856 switch (static_cast<TraitConfigType>(*traitConfig->Type))
27857 {
27859 stmt->setInt32(3, traitConfig->ChrSpecializationID);
27860 stmt->setInt32(4, traitConfig->CombatConfigFlags);
27861 stmt->setInt32(5, traitConfig->LocalIdentifier);
27862 stmt->setNull(6);
27863 stmt->setNull(7);
27864 break;
27866 stmt->setNull(3);
27867 stmt->setNull(4);
27868 stmt->setNull(5);
27869 stmt->setInt32(6, traitConfig->SkillLineID);
27870 stmt->setNull(7);
27871 break;
27873 stmt->setNull(3);
27874 stmt->setNull(4);
27875 stmt->setNull(5);
27876 stmt->setNull(6);
27877 stmt->setInt32(7, traitConfig->TraitSystemID);
27878 break;
27879 default:
27880 break;
27881 }
27882
27883 stmt->setString(8, traitConfig->Name);
27884 trans->Append(stmt);
27885
27886 for (UF::TraitEntry const& traitEntry : traitConfig->Entries)
27887 {
27888 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TRAIT_ENTRIES);
27889 stmt->setUInt64(0, GetGUID().GetCounter());
27890 stmt->setInt32(1, traitConfig->ID);
27891 stmt->setInt32(2, traitEntry.TraitNodeID);
27892 stmt->setInt32(3, traitEntry.TraitNodeEntryID);
27893 stmt->setInt32(4, traitEntry.Rank);
27894 stmt->setInt32(5, traitEntry.GrantedRanks);
27895 trans->Append(stmt);
27896 }
27897 }
27898 break;
27900 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRAIT_ENTRIES);
27901 stmt->setUInt64(0, GetGUID().GetCounter());
27902 stmt->setInt32(1, traitConfigId);
27903 trans->Append(stmt);
27904
27905 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TRAIT_CONFIGS);
27906 stmt->setUInt64(0, GetGUID().GetCounter());
27907 stmt->setInt32(1, traitConfigId);
27908 trans->Append(stmt);
27909
27910 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_TRAIT_CONFIG);
27911 stmt->setUInt64(0, GetGUID().GetCounter());
27912 stmt->setInt32(1, traitConfigId);
27913 trans->Append(stmt);
27914 break;
27915 default:
27916 break;
27917 }
27918 }
27919
27920 m_traitConfigStates.clear();
27921}
27922
27924{
27925 if (GetActiveTalentGroup() == spec->OrderIndex)
27926 return;
27927
27928 if (IsNonMeleeSpellCast(false))
27930
27931 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
27932 _SaveActions(trans);
27933 CharacterDatabase.CommitTransaction(trans);
27934
27935 // TO-DO: We need more research to know what happens with warlock's reagent
27936 if (Pet* pet = GetPet())
27938
27941 ExitVehicle();
27943
27945
27946 // remove single target auras at other targets
27947 AuraList& scAuras = GetSingleCastAuras();
27948 for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();)
27949 {
27950 Aura* aura = *iter;
27951 if (aura->GetUnitOwner() != this)
27952 {
27953 aura->Remove();
27954 iter = scAuras.begin();
27955 }
27956 else
27957 ++iter;
27958 }
27959 /*RemoveAllAurasOnDeath();
27960 if (GetPet())
27961 GetPet()->RemoveAllAurasOnDeath();*/
27962
27963 //RemoveAllAuras(GetGUID(), nullptr, false, true); // removes too many auras
27964 //ExitVehicle(); // should be impossible to switch specs from inside a vehicle..
27965
27966 // Let client clear his current Actions
27968 // m_actionButtons.clear() is called in the next _LoadActionButtons
27969 for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
27970 {
27971 TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
27972 if (!talentInfo)
27973 continue;
27974
27975 // unlearn only talents for character class
27976 // some spell learned by one class as normal spells or know at creation but another class learn it as talent,
27977 // to prevent unexpected lost normal learned spell skip another class talents
27978 if (talentInfo->ClassID != GetClass())
27979 continue;
27980
27981 if (talentInfo->SpellID == 0)
27982 continue;
27983
27984 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE);
27985 if (!spellInfo)
27986 continue;
27987
27988 RemoveSpell(talentInfo->SpellID, true);
27989
27990 // search for spells that the talent teaches and unlearn them
27991 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
27992 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
27993 RemoveSpell(spellEffectInfo.TriggerSpell, true);
27994
27995 if (talentInfo->OverridesSpellID)
27996 RemoveOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
27997 }
27998
27999 for (uint32 pvpTalentID = 0; pvpTalentID < sPvpTalentStore.GetNumRows(); ++pvpTalentID)
28000 {
28001 PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(pvpTalentID);
28002 if (!talentInfo)
28003 continue;
28004
28005 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(talentInfo->SpellID, DIFFICULTY_NONE);
28006 if (!spellInfo)
28007 continue;
28008
28009 RemoveSpell(talentInfo->SpellID, true);
28010
28011 // search for spells that the talent teaches and unlearn them
28012 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
28013 if (spellEffectInfo.IsEffect(SPELL_EFFECT_LEARN_SPELL) && spellEffectInfo.TriggerSpell > 0)
28014 RemoveSpell(spellEffectInfo.TriggerSpell, true);
28015
28016 if (talentInfo->OverridesSpellID)
28017 RemoveOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
28018 }
28019
28020 ApplyTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID, false);
28021
28022 // Remove spec specific spells
28024
28025 for (uint32 glyphId : GetGlyphs(GetActiveTalentGroup()))
28026 RemoveAurasDueToSpell(sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID);
28027
28030 int32 specTraitConfigIndex = m_activePlayerData->TraitConfigs.FindIndexIf([spec](UF::TraitConfig const& traitConfig)
28031 {
28032 return static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
28033 && traitConfig.ChrSpecializationID == int32(spec->ID)
28035 });
28036 if (specTraitConfigIndex >= 0)
28037 SetActiveCombatTraitConfigID(m_activePlayerData->TraitConfigs[specTraitConfigIndex].ID);
28038 else
28040
28041 for (uint32 talentId = 0; talentId < sTalentStore.GetNumRows(); ++talentId)
28042 {
28043 TalentEntry const* talentInfo = sTalentStore.LookupEntry(talentId);
28044 if (!talentInfo)
28045 continue;
28046
28047 // learn only talents for character class
28048 if (talentInfo->ClassID != GetClass())
28049 continue;
28050
28051 if (!talentInfo->SpellID)
28052 continue;
28053
28054 // if the talent can be found in the newly activated PlayerTalentMap
28055 if (HasTalent(talentInfo->ID, GetActiveTalentGroup()))
28056 {
28057 LearnSpell(talentInfo->SpellID, true); // add the talent to the PlayerSpellMap
28058 if (talentInfo->OverridesSpellID)
28059 AddOverrideSpell(talentInfo->OverridesSpellID, talentInfo->SpellID);
28060 }
28061 }
28062
28063 for (uint8 slot = 0; slot < MAX_PVP_TALENT_SLOTS; ++slot)
28064 {
28065 PvpTalentEntry const* talentInfo = sPvpTalentStore.LookupEntry(GetPvpTalentMap(GetActiveTalentGroup())[slot]);
28066 if (!talentInfo)
28067 continue;
28068
28069 if (!talentInfo->SpellID)
28070 continue;
28071
28072 AddPvpTalent(talentInfo, GetActiveTalentGroup(), slot);
28073 }
28074
28076
28077 if (CanUseMastery())
28078 for (uint32 i = 0; i < MAX_MASTERY_SPELLS; ++i)
28079 if (uint32 mastery = spec->MasterySpellID[i])
28080 LearnSpell(mastery, true);
28081
28082 ApplyTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID, true);
28083
28085
28087
28089 Powers pw = GetPowerType();
28090 if (pw != POWER_MANA)
28091 SetPower(POWER_MANA, 0); // Mana must be 0 even if it isn't the active power type.
28092
28093 SetPower(pw, 0);
28094 UpdateItemSetAuras(false);
28095 // update visible transmog
28097 if (Item* equippedItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
28098 SetVisibleItemSlot(i, equippedItem);
28099
28100 for (uint32 glyphId : GetGlyphs(spec->OrderIndex))
28101 CastSpell(this, sGlyphPropertiesStore.AssertEntry(glyphId)->SpellID, true);
28102
28104 activeGlyphs.Glyphs.reserve(GetGlyphs(spec->OrderIndex).size());
28105 for (uint32 glyphId : GetGlyphs(spec->OrderIndex))
28106 if (std::vector<uint32> const* bindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId))
28107 for (uint32 bindableSpell : *bindableSpells)
28108 if (HasSpell(bindableSpell) && m_overrideSpells.find(bindableSpell) == m_overrideSpells.end())
28109 activeGlyphs.Glyphs.emplace_back(uint32(bindableSpell), uint16(glyphId));
28110
28111 activeGlyphs.IsFullUpdate = true;
28112 SendDirectMessage(activeGlyphs.Write());
28113
28115 {
28116 if (AzeriteItem* azeriteItem = item->ToAzeriteItem())
28117 {
28118 if (azeriteItem->IsEquipped())
28119 {
28121 ApplyAzeritePowers(azeriteItem, false);
28122 }
28123
28124 azeriteItem->SetSelectedAzeriteEssences(spec->ID);
28125
28126 if (azeriteItem->IsEquipped())
28127 {
28128 ApplyAzeritePowers(azeriteItem, true);
28130 }
28131
28132 azeriteItem->SetState(ITEM_CHANGED, this);
28133 }
28134 }
28135
28137 for (AuraEffect* aurEff : shapeshiftAuras)
28138 {
28139 aurEff->HandleShapeshiftBoosts(this, false);
28140 aurEff->HandleShapeshiftBoosts(this, true);
28141 }
28142}
28143
28144void Player::StartLoadingActionButtons(std::function<void()>&& callback /*= nullptr*/)
28145{
28146 int32 traitConfigId = [&]() -> int32
28147 {
28148 UF::TraitConfig const* traitConfig = GetTraitConfig(m_activePlayerData->ActiveCombatTraitConfigID);
28149 if (!traitConfig)
28150 return 0;
28151
28152 int32 usedSavedTraitConfigIndex = m_activePlayerData->TraitConfigs.FindIndexIf([localIdent = *traitConfig->LocalIdentifier](UF::TraitConfig const& savedConfig)
28153 {
28154 return static_cast<TraitConfigType>(*savedConfig.Type) == TraitConfigType::Combat
28155 && (static_cast<TraitCombatConfigFlags>(*savedConfig.CombatConfigFlags) & TraitCombatConfigFlags::ActiveForSpec) == TraitCombatConfigFlags::None
28156 && (static_cast<TraitCombatConfigFlags>(*savedConfig.CombatConfigFlags) & TraitCombatConfigFlags::SharedActionBars) == TraitCombatConfigFlags::None
28157 && savedConfig.LocalIdentifier == localIdent;
28158 });
28159
28160 if (usedSavedTraitConfigIndex >= 0)
28161 return m_activePlayerData->TraitConfigs[usedSavedTraitConfigIndex].ID;
28162
28163 return 0;
28164 }();
28165
28166 // load them asynchronously
28168 stmt->setUInt64(0, GetGUID().GetCounter());
28169 stmt->setUInt8(1, GetActiveTalentGroup());
28170 stmt->setInt32(2, traitConfigId);
28171
28172 WorldSession* mySess = GetSession();
28173 mySess->GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(stmt)
28174 .WithPreparedCallback([mySess, myGuid = GetGUID(), callback = std::move(callback)](PreparedQueryResult result)
28175 {
28176 // safe callback, we can't pass this pointer directly
28177 // in case player logs out before db response (player would be deleted in that case)
28178 if (Player* thisPlayer = mySess->GetPlayer(); thisPlayer && thisPlayer->GetGUID() == myGuid)
28179 {
28180 thisPlayer->LoadActions(result);
28181
28182 if (callback)
28183 callback();
28184 }
28185 }));
28186}
28187
28189{
28190 _LoadActions(result);
28191
28193}
28194
28196{
28198 auto hasConfigId = [&](int32 id)
28199 {
28200 return m_activePlayerData->TraitConfigs.FindIndexIf([id](UF::TraitConfig const& config) { return config.ID == id; }) >= 0;
28201 };
28202
28203 while (hasConfigId(configId))
28205
28206 traitConfig.ID = configId;
28207
28208 int32 traitConfigIndex = m_activePlayerData->TraitConfigs.size();
28209 AddTraitConfig(traitConfig);
28210
28211 for (UF::TraitEntry const& grantedEntry : TraitMgr::GetGrantedTraitEntriesForConfig(traitConfig, this))
28212 {
28213 auto entryItr = std::find_if(traitConfig.Entries.begin(), traitConfig.Entries.end(),
28214 [&](WorldPackets::Traits::TraitEntry const& entry) { return entry.TraitNodeID == grantedEntry.TraitNodeID && entry.TraitNodeEntryID == grantedEntry.TraitNodeEntryID; });
28215
28216 if (entryItr == traitConfig.Entries.end())
28218 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, traitConfigIndex)
28219 .ModifyValue(&UF::TraitConfig::Entries)) = grantedEntry;
28220 }
28221
28223}
28224
28226{
28228 setter.ModifyValue(&UF::TraitConfig::ID).SetValue(traitConfig.ID);
28229 setter.ModifyValue(&UF::TraitConfig::Name).SetValue(traitConfig.Name);
28230 setter.ModifyValue(&UF::TraitConfig::Type).SetValue(AsUnderlyingType(traitConfig.Type));
28231 setter.ModifyValue(&UF::TraitConfig::SkillLineID).SetValue(traitConfig.SkillLineID);;
28232 setter.ModifyValue(&UF::TraitConfig::ChrSpecializationID).SetValue(traitConfig.ChrSpecializationID);
28233 setter.ModifyValue(&UF::TraitConfig::CombatConfigFlags).SetValue(AsUnderlyingType(traitConfig.CombatConfigFlags));
28234 setter.ModifyValue(&UF::TraitConfig::LocalIdentifier).SetValue(traitConfig.LocalIdentifier);
28235 setter.ModifyValue(&UF::TraitConfig::TraitSystemID).SetValue(traitConfig.TraitSystemID);
28236
28237 for (WorldPackets::Traits::TraitEntry const& traitEntry : traitConfig.Entries)
28238 {
28239 UF::TraitEntry& newEntry = AddDynamicUpdateFieldValue(setter.ModifyValue(&UF::TraitConfig::Entries));
28240 newEntry.TraitNodeID = traitEntry.TraitNodeID;
28241 newEntry.TraitNodeEntryID = traitEntry.TraitNodeEntryID;
28242 newEntry.Rank = traitEntry.Rank;
28243 newEntry.GrantedRanks = traitEntry.GrantedRanks;
28244 }
28245}
28246
28248{
28249 int32 index = m_activePlayerData->TraitConfigs.FindIndexIf([configId](UF::TraitConfig const& config) { return config.ID == configId; });
28250 if (index < 0)
28251 return nullptr;
28252
28253 return &m_activePlayerData->TraitConfigs[index];
28254}
28255
28256void Player::UpdateTraitConfig(WorldPackets::Traits::TraitConfig&& newConfig, int32 savedConfigId, bool withCastTime)
28257{
28258 int32 index = m_activePlayerData->TraitConfigs.FindIndexIf([&](UF::TraitConfig const& config) { return config.ID == newConfig.ID; });
28259 if (index < 0)
28260 return;
28261
28262 if (withCastTime)
28263 {
28264 CastSpell(this, TraitMgr::COMMIT_COMBAT_TRAIT_CONFIG_CHANGES_SPELL_ID, CastSpellExtraArgs(SPELLVALUE_BASE_POINT0, savedConfigId).SetCustomArg(std::move(newConfig)));
28265 return;
28266 }
28267
28268 bool isActiveConfig = true;
28269 bool loadActionButtons = false;
28270 switch (TraitConfigType(*m_activePlayerData->TraitConfigs[index].Type))
28271 {
28273 isActiveConfig = newConfig.ID == int32(*m_activePlayerData->ActiveCombatTraitConfigID);
28274 loadActionButtons = m_activePlayerData->TraitConfigs[index].LocalIdentifier != newConfig.LocalIdentifier;
28275 break;
28277 isActiveConfig = HasSkill(m_activePlayerData->TraitConfigs[index].SkillLineID);
28278 break;
28279 default:
28280 break;
28281 }
28282
28283 std::function<void()> finalizeTraitConfigUpdate = [=, this, newConfig = std::move(newConfig)]()
28284 {
28286 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, index)
28287 .ModifyValue(&UF::TraitConfig::LocalIdentifier), newConfig.LocalIdentifier);
28288
28289 ApplyTraitEntryChanges(newConfig.ID, newConfig, isActiveConfig, true);
28290
28291 if (savedConfigId)
28292 ApplyTraitEntryChanges(savedConfigId, newConfig, false, false);
28293
28294 if (EnumFlag(newConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags::StarterBuild))
28295 SetTraitConfigUseStarterBuild(newConfig.ID, true);
28296 };
28297
28298 if (loadActionButtons)
28299 {
28300 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
28301 _SaveActions(trans);
28302 CharacterDatabase.CommitTransaction(trans);
28303
28304 StartLoadingActionButtons(std::move(finalizeTraitConfigUpdate));
28305 }
28306 else
28307 finalizeTraitConfigUpdate();
28308}
28309
28310void Player::ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits::TraitConfig const& newConfig, bool applyTraits, bool consumeCurrencies)
28311{
28312 int32 editedIndex = m_activePlayerData->TraitConfigs.FindIndexIf([editedConfigId](UF::TraitConfig const& config) { return config.ID == editedConfigId; });
28313 if (editedIndex < 0)
28314 return;
28315
28316 auto makeTraitEntryFinder = [](int32 traitNodeId, int32 traitNodeEntryId)
28317 {
28318 return [=](auto const& ufEntry) { return ufEntry.TraitNodeID == traitNodeId && ufEntry.TraitNodeEntryID == traitNodeEntryId; };
28319 };
28320
28321 UF::TraitConfig const& editedConfig = m_activePlayerData->TraitConfigs[editedIndex];
28322
28323 // remove traits not found in new config
28324 std::set<int32, std::greater<>> entryIndicesToRemove;
28325 for (int32 i = 0; i < int32(editedConfig.Entries.size()); ++i)
28326 {
28327 UF::TraitEntry const& oldEntry = editedConfig.Entries[i];
28328 auto entryItr = std::find_if(newConfig.Entries.begin(), newConfig.Entries.end(), makeTraitEntryFinder(oldEntry.TraitNodeID, oldEntry.TraitNodeEntryID));
28329 if (entryItr != newConfig.Entries.end())
28330 continue;
28331
28332 if (applyTraits)
28333 ApplyTraitEntry(oldEntry.TraitNodeEntryID, 0, 0, false);
28334
28335 entryIndicesToRemove.insert(i);
28336 }
28337
28338 for (int32 indexToRemove : entryIndicesToRemove)
28339 {
28341 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, editedIndex)
28342 .ModifyValue(&UF::TraitConfig::Entries), indexToRemove);
28343 }
28344
28345 std::vector<WorldPackets::Traits::TraitEntry> costEntries;
28346
28347 // apply new traits
28348 for (std::size_t i = 0; i < newConfig.Entries.size(); ++i)
28349 {
28350 WorldPackets::Traits::TraitEntry const& newEntry = newConfig.Entries[i];
28351 int32 oldEntryIndex = editedConfig.Entries.FindIndexIf(makeTraitEntryFinder(newEntry.TraitNodeID, newEntry.TraitNodeEntryID));
28352 if (oldEntryIndex < 0)
28353 {
28354 if (consumeCurrencies)
28355 costEntries.push_back(newEntry);
28356
28358 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, editedIndex)
28359 .ModifyValue(&UF::TraitConfig::Entries));
28360 newUfEntry.TraitNodeID = newEntry.TraitNodeID;
28361 newUfEntry.TraitNodeEntryID = newEntry.TraitNodeEntryID;
28362 newUfEntry.Rank = newEntry.Rank;
28363 newUfEntry.GrantedRanks = newEntry.GrantedRanks;
28364
28365 if (applyTraits)
28366 ApplyTraitEntry(newUfEntry.TraitNodeEntryID, newUfEntry.Rank, 0, true);
28367 }
28368 else if (newEntry.Rank != editedConfig.Entries[oldEntryIndex].Rank || newEntry.GrantedRanks != editedConfig.Entries[oldEntryIndex].GrantedRanks)
28369 {
28370 if (consumeCurrencies && newEntry.Rank > editedConfig.Entries[oldEntryIndex].Rank)
28371 {
28372 WorldPackets::Traits::TraitEntry& costEntry = costEntries.emplace_back(newEntry);
28373 costEntry.Rank -= editedConfig.Entries[oldEntryIndex].Rank;
28374 }
28375
28377 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, editedIndex)
28378 .ModifyValue(&UF::TraitConfig::Entries, oldEntryIndex)
28379 .ModifyValue(&UF::TraitEntry::Rank), newEntry.Rank);
28380
28382 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, editedIndex)
28383 .ModifyValue(&UF::TraitConfig::Entries, oldEntryIndex)
28384 .ModifyValue(&UF::TraitEntry::GrantedRanks), newEntry.GrantedRanks);
28385
28386 if (applyTraits)
28387 ApplyTraitEntry(newEntry.TraitNodeEntryID, newEntry.Rank, newEntry.GrantedRanks, true);
28388 }
28389 }
28390
28391 if (consumeCurrencies)
28392 {
28393 std::map<int32, int32> currencies;
28394 for (WorldPackets::Traits::TraitEntry const& costEntry : costEntries)
28395 TraitMgr::FillSpentCurrenciesMap(costEntry, currencies);
28396
28397 for (auto [traitCurrencyId, amount] : currencies)
28398 {
28399 TraitCurrencyEntry const* traitCurrency = sTraitCurrencyStore.LookupEntry(traitCurrencyId);
28400 if (!traitCurrency)
28401 continue;
28402
28403 switch (traitCurrency->GetType())
28404 {
28406 ModifyMoney(-amount);
28407 break;
28409 RemoveCurrency(traitCurrency->CurrencyTypesID, amount /* TODO: CurrencyDestroyReason */);
28410 break;
28411 default:
28412 break;
28413 }
28414 }
28415 }
28416
28417 m_traitConfigStates[editedConfigId] = PLAYERSPELL_CHANGED;
28418}
28419
28420void Player::RenameTraitConfig(int32 editedConfigId, std::string&& newName)
28421{
28422 int32 editedIndex = m_activePlayerData->TraitConfigs.FindIndexIf([editedConfigId](UF::TraitConfig const& traitConfig)
28423 {
28424 return traitConfig.ID == editedConfigId
28425 && static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
28427 });
28428 if (editedIndex < 0)
28429 return;
28430
28432 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, editedIndex)
28433 .ModifyValue(&UF::TraitConfig::Name), std::move(newName));
28434
28435 m_traitConfigStates[editedConfigId] = PLAYERSPELL_CHANGED;
28436}
28437
28439{
28440 int32 deletedIndex = m_activePlayerData->TraitConfigs.FindIndexIf([deletedConfigId](UF::TraitConfig const& traitConfig)
28441 {
28442 return traitConfig.ID == deletedConfigId
28443 && static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
28445 });
28446 if (deletedIndex < 0)
28447 return;
28448
28450 .ModifyValue(&UF::ActivePlayerData::TraitConfigs), deletedIndex);
28451
28452 m_traitConfigStates[deletedConfigId] = PLAYERSPELL_REMOVED;
28453}
28454
28456{
28457 UF::TraitConfig const* traitConfig = GetTraitConfig(configId);
28458 if (!traitConfig)
28459 return;
28460
28461 for (UF::TraitEntry const& traitEntry : traitConfig->Entries)
28462 ApplyTraitEntry(traitEntry.TraitNodeEntryID, traitEntry.Rank, traitEntry.GrantedRanks, apply);
28463}
28464
28465void Player::ApplyTraitEntry(int32 traitNodeEntryId, int32 /*rank*/, int32 /*grantedRanks*/, bool apply)
28466{
28467 TraitNodeEntryEntry const* traitNodeEntry = sTraitNodeEntryStore.LookupEntry(traitNodeEntryId);
28468 if (!traitNodeEntry)
28469 return;
28470
28471 TraitDefinitionEntry const* traitDefinition = sTraitDefinitionStore.LookupEntry(traitNodeEntry->TraitDefinitionID);
28472 if (!traitDefinition)
28473 return;
28474
28475 if (traitDefinition->SpellID)
28476 {
28477 if (apply)
28478 LearnSpell(traitDefinition->SpellID, true, 0, false, traitNodeEntry->TraitDefinitionID);
28479 else
28480 RemoveSpell(traitDefinition->SpellID);
28481 }
28482}
28483
28484void Player::SetTraitConfigUseStarterBuild(int32 traitConfigId, bool useStarterBuild)
28485{
28486 int32 configIndex = m_activePlayerData->TraitConfigs.FindIndexIf([traitConfigId](UF::TraitConfig const& traitConfig)
28487 {
28488 return traitConfig.ID == traitConfigId
28489 && static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
28491 });
28492 if (configIndex < 0)
28493 return;
28494
28495 bool currentlyUsesStarterBuild = EnumFlag(static_cast<TraitCombatConfigFlags>(*m_activePlayerData->TraitConfigs[configIndex].CombatConfigFlags)).HasFlag(TraitCombatConfigFlags::StarterBuild);
28496 if (currentlyUsesStarterBuild == useStarterBuild)
28497 return;
28498
28499 if (useStarterBuild)
28501 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, configIndex)
28503 else
28505 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, configIndex)
28507
28509}
28510
28511void Player::SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig)
28512{
28513 int32 configIndex = m_activePlayerData->TraitConfigs.FindIndexIf([traitConfigId](UF::TraitConfig const& traitConfig)
28514 {
28515 return traitConfig.ID == traitConfigId
28516 && static_cast<TraitConfigType>(*traitConfig.Type) == TraitConfigType::Combat
28518 });
28519 if (configIndex < 0)
28520 return;
28521
28522 bool currentlyUsesSharedActionBars = EnumFlag(static_cast<TraitCombatConfigFlags>(*m_activePlayerData->TraitConfigs[configIndex].CombatConfigFlags)).HasFlag(TraitCombatConfigFlags::SharedActionBars);
28523 if (currentlyUsesSharedActionBars == usesSharedActionBars)
28524 return;
28525
28526 if (usesSharedActionBars)
28527 {
28529 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, configIndex)
28531
28532 {
28534 stmt->setUInt64(0, GetGUID().GetCounter());
28535 stmt->setInt32(1, traitConfigId);
28536 CharacterDatabase.Execute(stmt);
28537 }
28538
28539 if (isLastSelectedSavedConfig)
28540 StartLoadingActionButtons(); // load action buttons that were saved in shared mode
28541 }
28542 else
28543 {
28545 .ModifyValue(&UF::ActivePlayerData::TraitConfigs, configIndex)
28547
28548 // trigger a save with traitConfigId
28549 for (auto&& [_, button] : m_actionButtons)
28550 if (button.uState != ACTIONBUTTON_DELETED)
28551 button.uState = ACTIONBUTTON_NEW;
28552 }
28553
28555}
28556
28557void Player::SetReputation(uint32 factionentry, int32 value)
28558{
28559 GetReputationMgr().SetReputation(sFactionStore.LookupEntry(factionentry), value);
28560}
28562{
28563 return GetReputationMgr().GetReputation(sFactionStore.LookupEntry(factionentry));
28564}
28565
28566std::string Player::GetGuildName() const
28567{
28568 return GetGuildId() ? sGuildMgr->GetGuildById(GetGuildId())->GetName() : "";
28569}
28570
28572{
28573 m_refundableItems.insert(it);
28574}
28575
28577{
28578 GuidSet::iterator itr = m_refundableItems.find(it);
28579 if (itr != m_refundableItems.end())
28580 m_refundableItems.erase(itr);
28581}
28582
28584{
28585 // This function call unsets ITEM_FIELD_FLAG_REFUNDABLE if played time is over 2 hours.
28586 item->UpdatePlayedTime(this);
28587
28588 if (!item->IsRefundable())
28589 {
28590 TC_LOG_DEBUG("entities.player.items", "Item refund: item not refundable!");
28591 return;
28592 }
28593
28594 if (GetGUID() != item->GetRefundRecipient()) // Formerly refundable item got traded
28595 {
28596 TC_LOG_DEBUG("entities.player.items", "Item refund: item was traded!");
28597 item->SetNotRefundable(this);
28598 return;
28599 }
28600
28601 ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(item->GetPaidExtendedCost());
28602 if (!iece)
28603 {
28604 TC_LOG_DEBUG("entities.player.items", "Item refund: cannot find extendedcost data.");
28605 return;
28606 }
28607
28608 WorldPackets::Item::SetItemPurchaseData setItemPurchaseData;
28609 setItemPurchaseData.ItemGUID = item->GetGUID();
28610 setItemPurchaseData.PurchaseTime = GetTotalPlayedTime() - item->GetPlayedTime();
28611 setItemPurchaseData.Contents.Money = item->GetPaidMoney();
28612
28613 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) // item cost data
28614 {
28615 setItemPurchaseData.Contents.Items[i].ItemCount = iece->ItemCount[i];
28616 setItemPurchaseData.Contents.Items[i].ItemID = iece->ItemID[i];
28617 }
28618
28619 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) // currency cost data
28620 {
28622 continue;
28623
28624 setItemPurchaseData.Contents.Currencies[i].CurrencyCount = iece->CurrencyCount[i];
28625 setItemPurchaseData.Contents.Currencies[i].CurrencyID = iece->CurrencyID[i];
28626 }
28627
28628 SendDirectMessage(setItemPurchaseData.Write());
28629}
28630
28631bool Player::AddItem(uint32 itemId, uint32 count)
28632{
28633 uint32 noSpaceForCount = 0;
28634 ItemPosCountVec dest;
28635 InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, count, &noSpaceForCount);
28636 if (msg != EQUIP_ERR_OK)
28637 count -= noSpaceForCount;
28638
28639 if (count == 0 || dest.empty())
28640 {
28642 ChatHandler(GetSession()).PSendSysMessage("You don't have any space in your bags.");
28643 return false;
28644 }
28645
28646 Item* item = StoreNewItem(dest, itemId, true, GenerateItemRandomBonusListId(itemId));
28647 if (item)
28648 SendNewItem(item, count, true, false);
28649 else
28650 return false;
28651 return true;
28652}
28653
28655{
28656 if (!m_petStable)
28657 m_petStable = std::make_unique<PetStable>();
28658
28659 return *m_petStable;
28660}
28661
28663{
28665 auto ufPet = AddDynamicUpdateFieldValue(ufStable.ModifyValue(&UF::StableInfo::Pets));
28666 ufPet.ModifyValue(&UF::StablePetInfo::PetSlot).SetValue(slot);
28667 ufPet.ModifyValue(&UF::StablePetInfo::PetNumber).SetValue(pet.PetNumber);
28668 ufPet.ModifyValue(&UF::StablePetInfo::CreatureID).SetValue(pet.CreatureId);
28669 ufPet.ModifyValue(&UF::StablePetInfo::DisplayID).SetValue(pet.DisplayId);
28670 ufPet.ModifyValue(&UF::StablePetInfo::ExperienceLevel).SetValue(pet.Level);
28671 ufPet.ModifyValue(&UF::StablePetInfo::PetFlags).SetValue(flags);
28672 ufPet.ModifyValue(&UF::StablePetInfo::Name).SetValue(pet.Name);
28673}
28674
28675void Player::SetPetSlot(uint32 petNumber, PetSaveMode dstPetSlot)
28676{
28678
28679 WorldSession* sess = GetSession();
28680 PetStable* petStable = GetPetStable();
28681 if (!petStable)
28682 {
28684 return;
28685 }
28686
28687 auto [srcPet, srcPetSlot] = Pet::GetLoadPetInfo(*petStable, 0, petNumber, {});
28688 PetStable::PetInfo const* dstPet = Pet::GetLoadPetInfo(*petStable, 0, 0, dstPetSlot).first;
28689
28690 if (!srcPet || srcPet->Type != HUNTER_PET)
28691 {
28693 return;
28694 }
28695
28696 if (dstPet && dstPet->Type != HUNTER_PET)
28697 {
28699 return;
28700 }
28701
28702 Optional<PetStable::PetInfo>* src = nullptr;
28703 Optional<PetStable::PetInfo>* dst = nullptr;
28704 Optional<uint32> newActivePetIndex;
28705
28706 if (IsActivePetSlot(srcPetSlot) && IsActivePetSlot(dstPetSlot))
28707 {
28708 // active<->active: only swap ActivePets and CurrentPetIndex (do not despawn pets)
28709 src = &petStable->ActivePets[srcPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
28710 dst = &petStable->ActivePets[dstPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
28711
28712 if (petStable->GetCurrentActivePetIndex() == uint32_t(srcPetSlot))
28713 newActivePetIndex = dstPetSlot;
28714 else if (petStable->GetCurrentActivePetIndex() == uint32(dstPetSlot))
28715 newActivePetIndex = srcPetSlot;
28716 }
28717 else if (IsStabledPetSlot(srcPetSlot) && IsStabledPetSlot(dstPetSlot))
28718 {
28719 // stabled<->stabled: only swap StabledPets
28720 src = &petStable->StabledPets[srcPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
28721 dst = &petStable->StabledPets[dstPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
28722 }
28723 else if (IsActivePetSlot(srcPetSlot) && IsStabledPetSlot(dstPetSlot))
28724 {
28725 // active<->stabled: swap petStable contents and despawn active pet if it is involved in swap
28726 if (petStable->CurrentPetIndex == uint32(srcPetSlot))
28727 {
28728 Pet* oldPet = GetPet();
28729 if (oldPet && !oldPet->IsAlive())
28730 {
28732 return;
28733 }
28734
28736 }
28737
28738 if (dstPet)
28739 {
28740 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(dstPet->CreatureId);
28741 if (!creatureInfo || !creatureInfo->IsTameable(CanTameExoticPets(), creatureInfo->GetDifficulty(DIFFICULTY_NONE)))
28742 {
28744 return;
28745 }
28746 }
28747
28748 src = &petStable->ActivePets[srcPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
28749 dst = &petStable->StabledPets[dstPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
28750 }
28751 else if (IsStabledPetSlot(srcPetSlot) && IsActivePetSlot(dstPetSlot))
28752 {
28753 // stabled<->active: swap petStable contents and despawn active pet if it is involved in swap
28754 if (petStable->CurrentPetIndex == uint32(dstPetSlot))
28755 {
28756 Pet* oldPet = GetPet();
28757 if (oldPet && !oldPet->IsAlive())
28758 {
28760 return;
28761 }
28762
28764 }
28765
28766 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(srcPet->CreatureId);
28767 if (!creatureInfo || !creatureInfo->IsTameable(CanTameExoticPets(), creatureInfo->GetDifficulty(DIFFICULTY_NONE)))
28768 {
28770 return;
28771 }
28772
28773 src = &petStable->StabledPets[srcPetSlot - PET_SAVE_FIRST_STABLE_SLOT];
28774 dst = &petStable->ActivePets[dstPetSlot - PET_SAVE_FIRST_ACTIVE_SLOT];
28775 }
28776
28777 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
28778
28780 stmt->setInt16(0, dstPetSlot);
28781 stmt->setUInt64(1, GetGUID().GetCounter());
28782 stmt->setUInt32(2, srcPet->PetNumber);
28783 trans->Append(stmt);
28784
28785 if (dstPet)
28786 {
28787 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
28788 stmt->setInt16(0, srcPetSlot);
28789 stmt->setUInt64(1, GetGUID().GetCounter());
28790 stmt->setUInt32(2, dstPet->PetNumber);
28791 trans->Append(stmt);
28792 }
28793
28794 GetSession()->AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(trans)).AfterComplete(
28795 [sess = GetSession(), this, src, srcPetSlot = srcPetSlot, dst, dstPetSlot = dstPetSlot, newActivePetIndex](bool success)
28796 {
28797 if (sess->GetPlayer() == this)
28798 {
28799 if (success)
28800 {
28801 std::swap(*src, *dst);
28802 if (newActivePetIndex)
28803 sess->GetPlayer()->GetPetStable()->SetCurrentActivePetIndex(*newActivePetIndex);
28804
28805 int32 srcPetIndex = m_activePlayerData->PetStable->Pets.FindIndexIf([srcPetSlot](UF::StablePetInfo const& p) { return p.PetSlot == uint32(srcPetSlot); });
28806 int32 dstPetIndex = m_activePlayerData->PetStable->Pets.FindIndexIf([dstPetSlot](UF::StablePetInfo const& p) { return p.PetSlot == uint32(dstPetSlot); });
28807
28808 if (srcPetIndex >= 0)
28809 {
28810 SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData)
28811 .ModifyValue(&UF::ActivePlayerData::PetStable, 0)
28812 .ModifyValue(&UF::StableInfo::Pets, srcPetIndex)
28813 .ModifyValue(&UF::StablePetInfo::PetSlot), dstPetSlot);
28814 }
28815
28816 if (dstPetIndex >= 0)
28817 {
28818 SetUpdateFieldValue(m_values.ModifyValue(&Player::m_activePlayerData)
28819 .ModifyValue(&UF::ActivePlayerData::PetStable, 0)
28820 .ModifyValue(&UF::StableInfo::Pets, dstPetIndex)
28821 .ModifyValue(&UF::StablePetInfo::PetSlot), srcPetSlot);
28822 }
28823
28824 sess->SendPetStableResult(StableResult::StableSuccess);
28825 }
28826 else
28827 {
28828 sess->SendPetStableResult(StableResult::InternalError);
28829 }
28830 }
28831 });
28832}
28833
28835{
28836 if (!m_activePlayerData->PetStable.has_value())
28837 return ObjectGuid::Empty;
28838
28839 return m_activePlayerData->PetStable->StableMaster;
28840}
28841
28843{
28844 if (!m_activePlayerData->PetStable.has_value())
28845 return;
28846
28848 .ModifyValue(&UF::ActivePlayerData::PetStable, 0)
28849 .ModifyValue(&UF::StableInfo::StableMaster), stableMaster);
28850}
28851
28853{
28854 WorldPackets::Item::ItemPurchaseRefundResult itemPurchaseRefundResult;
28855 itemPurchaseRefundResult.ItemGUID = item->GetGUID();
28856 itemPurchaseRefundResult.Result = error;
28857 if (!error)
28858 {
28859 itemPurchaseRefundResult.Contents.emplace();
28860 itemPurchaseRefundResult.Contents->Money = item->GetPaidMoney();
28861 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i) // item cost data
28862 {
28863 itemPurchaseRefundResult.Contents->Items[i].ItemCount = iece->ItemCount[i];
28864 itemPurchaseRefundResult.Contents->Items[i].ItemID = iece->ItemID[i];
28865 }
28866
28867 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i) // currency cost data
28868 {
28870 continue;
28871
28872 itemPurchaseRefundResult.Contents->Currencies[i].CurrencyCount = iece->CurrencyCount[i];
28873 itemPurchaseRefundResult.Contents->Currencies[i].CurrencyID = iece->CurrencyID[i];
28874 }
28875 }
28876
28877 SendDirectMessage(itemPurchaseRefundResult.Write());
28878}
28879
28881{
28882 if (!item->IsRefundable())
28883 {
28884 TC_LOG_DEBUG("entities.player.items", "Item refund: item not refundable!");
28885 return;
28886 }
28887
28888 if (item->IsRefundExpired()) // item refund has expired
28889 {
28890 item->SetNotRefundable(this);
28891 SendItemRefundResult(item, nullptr, 10);
28892 return;
28893 }
28894
28895 if (GetGUID() != item->GetRefundRecipient()) // Formerly refundable item got traded
28896 {
28897 TC_LOG_DEBUG("entities.player.items", "Item refund: item was traded!");
28898 item->SetNotRefundable(this);
28899 return;
28900 }
28901
28902 ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(item->GetPaidExtendedCost());
28903 if (!iece)
28904 {
28905 TC_LOG_DEBUG("entities.player.items", "Item refund: cannot find extendedcost data.");
28906 return;
28907 }
28908
28909 bool store_error = false;
28910 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
28911 {
28912 uint32 count = iece->ItemCount[i];
28913 uint32 itemid = iece->ItemID[i];
28914
28915 if (count && itemid)
28916 {
28917 ItemPosCountVec dest;
28918 InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count);
28919 if (msg != EQUIP_ERR_OK)
28920 {
28921 store_error = true;
28922 break;
28923 }
28924 }
28925 }
28926
28927 if (store_error)
28928 {
28929 SendItemRefundResult(item, iece, 10);
28930 return;
28931 }
28932
28933 SendItemRefundResult(item, iece, 0);
28934
28935 uint64 moneyRefund = item->GetPaidMoney(); // item-> will be invalidated in DestroyItem
28936
28937 // Save all relevant data to DB to prevent desynchronisation exploits
28938 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
28939
28940 // Delete any references to the refund data
28941 item->SetNotRefundable(this, true, &trans, false);
28943
28944 // Destroy item
28945 DestroyItem(item->GetBagSlot(), item->GetSlot(), true);
28946
28947 // Grant back extendedcost items
28948 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_ITEMS; ++i)
28949 {
28950 uint32 count = iece->ItemCount[i];
28951 uint32 itemid = iece->ItemID[i];
28952 if (count && itemid)
28953 {
28954 ItemPosCountVec dest;
28955 InventoryResult msg = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemid, count);
28956 ASSERT(msg == EQUIP_ERR_OK);
28957 Item* it = StoreNewItem(dest, itemid, true);
28958 SendNewItem(it, count, true, false, true);
28959 }
28960 }
28961
28962 // Grant back currencies
28963 for (uint8 i = 0; i < MAX_ITEM_EXT_COST_CURRENCIES; ++i)
28964 {
28966 continue;
28967
28968 uint32 count = iece->CurrencyCount[i];
28969 uint32 currencyid = iece->CurrencyID[i];
28970 if (count && currencyid)
28971 AddCurrency(currencyid, count, CurrencyGainSource::ItemRefund);
28972 }
28973
28974 // Grant back money
28975 if (moneyRefund)
28976 ModifyMoney(moneyRefund); // Saved in SaveInventoryAndGoldToDB
28977
28979
28980 CharacterDatabase.CommitTransaction(trans);
28981}
28982
28984{
28985 MailSender sender(MAIL_CREATURE, UI64LIT(34337) /* The Postmaster */);
28986 MailDraft draft("Recovered Item", "We recovered a lost item in the twisting nether and noted that it was yours.$B$BPlease find said object enclosed."); // This is the text used in Cataclysm, it probably wasn't changed.
28987 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
28988
28989 if (Item* item = Item::CreateItem(itemEntry, count, context, nullptr))
28990 {
28991 item->SaveToDB(trans);
28992 draft.AddItem(item);
28993 }
28994
28995 draft.SendMailTo(trans, MailReceiver(this, GetGUID().GetCounter()), sender);
28996 CharacterDatabase.CommitTransaction(trans);
28997}
28998
28999void Player::SetRandomWinner(bool isWinner)
29000{
29001 m_IsBGRandomWinner = isWinner;
29003 {
29005
29006 stmt->setUInt64(0, GetGUID().GetCounter());
29007
29008 CharacterDatabase.Execute(stmt);
29009 }
29010}
29011
29013{
29014 //QueryResult result = CharacterDatabase.PQuery("SELECT guid FROM character_battleground_random WHERE guid = '{}'", GetGUIDLow());
29015
29016 if (result)
29017 m_IsBGRandomWinner = true;
29018}
29019
29021{
29022 float sum = 0;
29023 uint32 count = 0;
29024
29025 for (int i = EQUIPMENT_SLOT_START; i < EQUIPMENT_SLOT_END; ++i)
29026 {
29027 // don't check tabard, ranged, offhand or shirt
29029 continue;
29030
29031 if (m_items[i])
29032 sum += m_items[i]->GetItemLevel(this);
29033
29034 ++count;
29035 }
29036
29037 return ((float)sum) / count;
29038}
29039
29041{
29042 if (!result)
29043 return;
29044
29045 do
29046 {
29047 Field* fields = result->Fetch();
29048 _instanceResetTimes.insert(InstanceTimeMap::value_type(fields[0].GetUInt32(), fields[1].GetUInt64()));
29049 } while (result->NextRow());
29050}
29051
29053{
29054 if (!result)
29055 return;
29056
29057 m_petStable = std::make_unique<PetStable>();
29058
29059 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
29060 // SELECT id, entry, modelid, level, exp, Reactstate, slot, name, renamed, curhealth, curmana, abdata, savetime, CreatedBySpell, PetType, specialization FROM character_pet WHERE owner = ?
29061 if (result)
29062 {
29063
29064 do
29065 {
29066 Field* fields = result->Fetch();
29067 PetStable::PetInfo petInfo;
29068 petInfo.PetNumber = fields[0].GetUInt32();
29069 petInfo.CreatureId = fields[1].GetUInt32();
29070 petInfo.DisplayId = fields[2].GetUInt32();
29071 petInfo.Level = fields[3].GetUInt16();
29072 petInfo.Experience = fields[4].GetUInt32();
29073 petInfo.ReactState = ReactStates(fields[5].GetUInt8());
29074 PetSaveMode slot = PetSaveMode(fields[6].GetInt16());
29075 petInfo.Name = fields[7].GetString();
29076 petInfo.WasRenamed = fields[8].GetBool();
29077 petInfo.Health = fields[9].GetUInt32();
29078 petInfo.Mana = fields[10].GetUInt32();
29079 petInfo.ActionBar = fields[11].GetString();
29080 petInfo.LastSaveTime = fields[12].GetUInt32();
29081 petInfo.CreatedBySpellId = fields[13].GetUInt32();
29082 petInfo.Type = PetType(fields[14].GetUInt8());
29083 petInfo.SpecializationId = fields[15].GetUInt16();
29085 {
29086 m_petStable->ActivePets[slot] = std::move(petInfo);
29087
29088 if (m_petStable->ActivePets[slot]->Type == HUNTER_PET)
29089 AddPetToUpdateFields(*m_petStable->ActivePets[slot], slot, PET_STABLE_ACTIVE);
29090 }
29091 else if (slot >= PET_SAVE_FIRST_STABLE_SLOT && slot < PET_SAVE_LAST_STABLE_SLOT)
29092 {
29093 m_petStable->StabledPets[slot - PET_SAVE_FIRST_STABLE_SLOT] = std::move(petInfo);
29094
29095 if (m_petStable->StabledPets[slot - PET_SAVE_FIRST_STABLE_SLOT]->Type == HUNTER_PET)
29097 }
29098 else if (slot == PET_SAVE_NOT_IN_SLOT)
29099 m_petStable->UnslottedPets.push_back(std::move(petInfo));
29100
29101 } while (result->NextRow());
29102 }
29103
29104 if (Pet::GetLoadPetInfo(*m_petStable, 0, summonedPetNumber, {}).first)
29105 m_temporaryUnsummonedPetNumber = summonedPetNumber;
29106}
29107
29109{
29110 if (_instanceResetTimes.empty())
29111 return;
29112
29114 stmt->setUInt32(0, GetSession()->GetAccountId());
29115 trans->Append(stmt);
29116
29117 for (InstanceTimeMap::const_iterator itr = _instanceResetTimes.begin(); itr != _instanceResetTimes.end(); ++itr)
29118 {
29119 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES);
29120 stmt->setUInt32(0, GetSession()->GetAccountId());
29121 stmt->setUInt32(1, itr->first);
29122 stmt->setInt64(2, itr->second);
29123 trans->Append(stmt);
29124 }
29125}
29126
29128{
29129 for (GuidList::const_iterator itr = WhisperList.begin(); itr != WhisperList.end(); ++itr)
29130 if (*itr == guid)
29131 return true;
29132
29133 return false;
29134}
29135
29137{
29138 for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
29139 if (!_voidStorageItems[i]) // unused item
29140 return i;
29141
29142 return VOID_STORAGE_MAX_SLOT;
29143}
29144
29146{
29147 uint8 count = 0;
29148
29149 for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
29150 if (!_voidStorageItems[i])
29151 count++;
29152
29153 return count;
29154}
29155
29157{
29159
29160 if (slot >= VOID_STORAGE_MAX_SLOT)
29161 {
29163 return 255;
29164 }
29165
29166 _voidStorageItems[slot] = new VoidStorageItem(std::move(item));
29167 return slot;
29168}
29169
29171{
29172 if (slot >= VOID_STORAGE_MAX_SLOT)
29173 {
29175 return;
29176 }
29177
29178 delete _voidStorageItems[slot];
29179 _voidStorageItems[slot] = nullptr;
29180}
29181
29183{
29184 if (oldSlot >= VOID_STORAGE_MAX_SLOT || newSlot >= VOID_STORAGE_MAX_SLOT || oldSlot == newSlot)
29185 return false;
29186
29187 std::swap(_voidStorageItems[newSlot], _voidStorageItems[oldSlot]);
29188 return true;
29189}
29190
29192{
29193 if (slot >= VOID_STORAGE_MAX_SLOT)
29194 {
29196 return nullptr;
29197 }
29198
29199 return _voidStorageItems[slot];
29200}
29201
29203{
29204 for (uint8 i = 0; i < VOID_STORAGE_MAX_SLOT; ++i)
29205 {
29206 if (_voidStorageItems[i] && _voidStorageItems[i]->ItemId == id)
29207 {
29208 slot = i;
29209 return _voidStorageItems[i];
29210 }
29211 }
29212
29213 return nullptr;
29214}
29215
29217{
29218 std::unique_ptr<Garrison> garrison(new Garrison(this));
29219 if (garrison->Create(garrSiteId))
29220 _garrison = std::move(garrison);
29221}
29222
29224{
29225 if (_garrison)
29226 {
29227 _garrison->Delete();
29228 _garrison.reset();
29229 }
29230}
29231
29233{
29235 setCollisionHeight.MoverGUID = GetGUID();
29236 setCollisionHeight.SequenceIndex = m_movementCounter++;
29237 setCollisionHeight.Height = height;
29238 setCollisionHeight.Scale = GetObjectScale();
29239 setCollisionHeight.MountDisplayID = GetMountDisplayId();
29240 setCollisionHeight.ScaleDuration = m_unitData->ScaleDuration;
29241 setCollisionHeight.Reason = reason;
29242 SendDirectMessage(setCollisionHeight.Write());
29243
29245 updateCollisionHeight.Status = &m_movementInfo;
29246 updateCollisionHeight.Height = height;
29247 updateCollisionHeight.Scale = GetObjectScale();
29248 SendMessageToSet(updateCollisionHeight.Write(), false);
29249}
29250
29252{
29253 PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(choiceId);
29254 if (!playerChoice)
29255 return;
29256
29258 PlayerChoiceLocale const* playerChoiceLocale = locale != DEFAULT_LOCALE ? sObjectMgr->GetPlayerChoiceLocale(choiceId) : nullptr;
29259
29260 PlayerTalkClass->GetInteractionData().Reset();
29261 PlayerTalkClass->GetInteractionData().SourceGuid = sender;
29262 PlayerTalkClass->GetInteractionData().PlayerChoiceId = uint32(choiceId);
29263
29264 WorldPackets::Quest::DisplayPlayerChoice displayPlayerChoice;
29265 displayPlayerChoice.SenderGUID = sender;
29266 displayPlayerChoice.ChoiceID = choiceId;
29267 displayPlayerChoice.UiTextureKitID = playerChoice->UiTextureKitId;
29268 displayPlayerChoice.SoundKitID = playerChoice->SoundKitId;
29269 displayPlayerChoice.Question = playerChoice->Question;
29270 if (playerChoiceLocale)
29271 ObjectMgr::GetLocaleString(playerChoiceLocale->Question, locale, displayPlayerChoice.Question);
29272
29273 displayPlayerChoice.Responses.resize(playerChoice->Responses.size());
29274 displayPlayerChoice.CloseChoiceFrame = false;
29275 displayPlayerChoice.HideWarboardHeader = playerChoice->HideWarboardHeader;
29276 displayPlayerChoice.KeepOpenAfterChoice = playerChoice->KeepOpenAfterChoice;
29277
29278 for (std::size_t i = 0; i < playerChoice->Responses.size(); ++i)
29279 {
29280 PlayerChoiceResponse const& playerChoiceResponseTemplate = playerChoice->Responses[i];
29281 WorldPackets::Quest::PlayerChoiceResponse& playerChoiceResponse = displayPlayerChoice.Responses[i];
29282 playerChoiceResponse.ResponseID = playerChoiceResponseTemplate.ResponseId;
29283 playerChoiceResponse.ResponseIdentifier = playerChoiceResponseTemplate.ResponseIdentifier;
29284 playerChoiceResponse.ChoiceArtFileID = playerChoiceResponseTemplate.ChoiceArtFileId;
29285 playerChoiceResponse.Flags = playerChoiceResponseTemplate.Flags;
29286 playerChoiceResponse.WidgetSetID = playerChoiceResponseTemplate.WidgetSetID;
29287 playerChoiceResponse.UiTextureAtlasElementID = playerChoiceResponseTemplate.UiTextureAtlasElementID;
29288 playerChoiceResponse.SoundKitID = playerChoiceResponseTemplate.SoundKitID;
29289 playerChoiceResponse.GroupID = playerChoiceResponseTemplate.GroupID;
29290 playerChoiceResponse.UiTextureKitID = playerChoiceResponseTemplate.UiTextureKitID;
29291 playerChoiceResponse.Answer = playerChoiceResponseTemplate.Answer;
29292 playerChoiceResponse.Header = playerChoiceResponseTemplate.Header;
29293 playerChoiceResponse.SubHeader = playerChoiceResponseTemplate.SubHeader;
29294 playerChoiceResponse.ButtonTooltip = playerChoiceResponseTemplate.ButtonTooltip;
29295 playerChoiceResponse.Description = playerChoiceResponseTemplate.Description;
29296 playerChoiceResponse.Confirmation = playerChoiceResponseTemplate.Confirmation;
29297 if (playerChoiceLocale)
29298 {
29299 if (PlayerChoiceResponseLocale const* playerChoiceResponseLocale = Trinity::Containers::MapGetValuePtr(playerChoiceLocale->Responses, playerChoiceResponseTemplate.ResponseId))
29300 {
29301 ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Answer, locale, playerChoiceResponse.Answer);
29302 ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Header, locale, playerChoiceResponse.Header);
29303 ObjectMgr::GetLocaleString(playerChoiceResponseLocale->SubHeader, locale, playerChoiceResponse.SubHeader);
29304 ObjectMgr::GetLocaleString(playerChoiceResponseLocale->ButtonTooltip, locale, playerChoiceResponse.ButtonTooltip);
29305 ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Description, locale, playerChoiceResponse.Description);
29306 ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Confirmation, locale, playerChoiceResponse.Confirmation);
29307 }
29308 }
29309
29310 if (playerChoiceResponseTemplate.Reward)
29311 {
29312 playerChoiceResponse.Reward.emplace();
29313 playerChoiceResponse.Reward->TitleID = playerChoiceResponseTemplate.Reward->TitleId;
29314 playerChoiceResponse.Reward->PackageID = playerChoiceResponseTemplate.Reward->PackageId;
29315 playerChoiceResponse.Reward->SkillLineID = playerChoiceResponseTemplate.Reward->SkillLineId;
29316 playerChoiceResponse.Reward->SkillPointCount = playerChoiceResponseTemplate.Reward->SkillPointCount;
29317 playerChoiceResponse.Reward->ArenaPointCount = playerChoiceResponseTemplate.Reward->ArenaPointCount;
29318 playerChoiceResponse.Reward->HonorPointCount = playerChoiceResponseTemplate.Reward->HonorPointCount;
29319 playerChoiceResponse.Reward->Money = playerChoiceResponseTemplate.Reward->Money;
29320 playerChoiceResponse.Reward->Xp = playerChoiceResponseTemplate.Reward->Xp;
29321 for (PlayerChoiceResponseRewardItem const& item : playerChoiceResponseTemplate.Reward->Items)
29322 {
29323 playerChoiceResponse.Reward->Items.emplace_back();
29324 WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->Items.back();
29325 rewardEntry.Item.ItemID = item.Id;
29326 rewardEntry.Quantity = item.Quantity;
29327 if (!item.BonusListIDs.empty())
29328 {
29329 rewardEntry.Item.ItemBonus.emplace();
29330 rewardEntry.Item.ItemBonus->BonusListIDs = item.BonusListIDs;
29331 }
29332 }
29333 for (PlayerChoiceResponseRewardEntry const& currency : playerChoiceResponseTemplate.Reward->Currency)
29334 {
29335 playerChoiceResponse.Reward->Items.emplace_back();
29336 WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->Items.back();
29337 rewardEntry.Item.ItemID = currency.Id;
29338 rewardEntry.Quantity = currency.Quantity;
29339 }
29340 for (PlayerChoiceResponseRewardEntry const& faction : playerChoiceResponseTemplate.Reward->Faction)
29341 {
29342 playerChoiceResponse.Reward->Items.emplace_back();
29343 WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->Items.back();
29344 rewardEntry.Item.ItemID = faction.Id;
29345 rewardEntry.Quantity = faction.Quantity;
29346 }
29347 for (PlayerChoiceResponseRewardItem const& item : playerChoiceResponseTemplate.Reward->ItemChoices)
29348 {
29349 playerChoiceResponse.Reward->ItemChoices.emplace_back();
29350 WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->ItemChoices.back();
29351 rewardEntry.Item.ItemID = item.Id;
29352 rewardEntry.Quantity = item.Quantity;
29353 if (!item.BonusListIDs.empty())
29354 {
29355 rewardEntry.Item.ItemBonus.emplace();
29356 rewardEntry.Item.ItemBonus->BonusListIDs = item.BonusListIDs;
29357 }
29358 }
29359 }
29360
29361 playerChoiceResponse.RewardQuestID = playerChoiceResponseTemplate.RewardQuestID;
29362
29363 if (playerChoiceResponseTemplate.MawPower)
29364 {
29365 WorldPackets::Quest::PlayerChoiceResponseMawPower& mawPower = playerChoiceResponse.MawPower.emplace();
29366 mawPower.TypeArtFileID = playerChoiceResponseTemplate.MawPower->TypeArtFileID;
29367 mawPower.Rarity = playerChoiceResponseTemplate.MawPower->Rarity;
29368 mawPower.RarityColor = playerChoiceResponseTemplate.MawPower->RarityColor;
29369 mawPower.SpellID = playerChoiceResponseTemplate.MawPower->SpellID;
29370 mawPower.MaxStacks = playerChoiceResponseTemplate.MawPower->MaxStacks;
29371 }
29372 }
29373
29374 SendDirectMessage(displayPlayerChoice.Write());
29375}
29376
29378{
29379 if (PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(conditionId))
29380 if (!ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
29381 return false;
29382
29383 return true;
29384}
29385
29387{
29388 if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(GetAreaId()))
29389 return IsFriendlyArea(areaEntry);
29390 return false;
29391}
29392
29393bool Player::IsFriendlyArea(AreaTableEntry const* areaEntry) const
29394{
29395 ASSERT(areaEntry != nullptr);
29396
29397 FactionTemplateEntry const* factionTemplate = GetFactionTemplateEntry();
29398 if (!factionTemplate)
29399 return false;
29400
29401 if (!(factionTemplate->FriendGroup & areaEntry->FactionGroupMask))
29402 return false;
29403
29404 return true;
29405}
29406
29408{
29409 uint32 areaId = GetAreaId();
29410 std::string areaName = "Unknown";
29411 std::string zoneName = "Unknown";
29412 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
29413 {
29414 areaName = area->AreaName[GetSession()->GetSessionDbcLocale()];
29415 if (area->GetFlags().HasFlag(AreaFlags::IsSubzone))
29416 if (AreaTableEntry const* zone = sAreaTableStore.LookupEntry(area->ParentAreaID))
29417 zoneName = zone->AreaName[GetSession()->GetSessionDbcLocale()];
29418 }
29419
29420 std::ostringstream str;
29421 str << "Map: " << GetMapId() << " (" << (FindMap() ? FindMap()->GetMapName() : "Unknown") << ") Area: " << areaId << " (" << areaName.c_str() << ") Zone: " << zoneName.c_str();
29422 return str.str();
29423}
29424
29426{
29427 std::ostringstream str;
29428 str << Position::ToString() << " " << GetMapAreaAndZoneString();
29429 return str.str();
29430}
29431
29433{
29434 ObjectGuid::LowType guildId = GetGuildId();
29435 return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr;
29436}
29437
29439{
29440 ObjectGuid::LowType guildId = GetGuildId();
29441 return guildId ? sGuildMgr->GetGuildById(guildId) : nullptr;
29442}
29443
29444Pet* Player::SummonPet(uint32 entry, Optional<PetSaveMode> slot, float x, float y, float z, float ang, uint32 duration, bool* isNew /*= nullptr*/)
29445{
29446 PetStable& petStable = GetOrInitPetStable();
29447
29448 Pet* pet = new Pet(this, SUMMON_PET);
29449
29450 if (pet->LoadPetFromDB(this, entry, 0, false, slot))
29451 {
29452 if (duration > 0)
29453 pet->SetDuration(duration);
29454
29455 if (isNew)
29456 *isNew = false;
29457
29458 return pet;
29459 }
29460
29461 // petentry == 0 for hunter "call pet" (current pet summoned if any)
29462 if (!entry)
29463 {
29464 delete pet;
29465 return nullptr;
29466 }
29467
29468 // only SUMMON_PET are handled here
29469
29470 pet->Relocate(x, y, z, ang);
29471 if (!pet->IsPositionValid())
29472 {
29473 TC_LOG_ERROR("misc", "Player::SummonPet: Pet ({}, Entry: {}) not summoned. Suggested coordinates aren't valid (X: {} Y: {})", pet->GetGUID().ToString(), pet->GetEntry(), pet->GetPositionX(), pet->GetPositionY());
29474 delete pet;
29475 return nullptr;
29476 }
29477
29478 Map* map = GetMap();
29479 uint32 pet_number = sObjectMgr->GeneratePetNumber();
29480 if (!pet->Create(map->GenerateLowGuid<HighGuid::Pet>(), map, entry, pet_number))
29481 {
29482 TC_LOG_ERROR("misc", "Player::SummonPet: No such creature entry {}", entry);
29483 delete pet;
29484 return nullptr;
29485 }
29486
29487 if (petStable.GetCurrentPet())
29489
29491
29492 pet->SetCreatorGUID(GetGUID());
29493 pet->SetFaction(GetFaction());
29494
29498
29499 SetMinion(pet, true);
29500
29501 // this enables pet details window (Shift+P)
29502 pet->GetCharmInfo()->SetPetNumber(pet_number, true);
29503 pet->SetClass(CLASS_MAGE);
29504 pet->SetPetExperience(0);
29505 pet->SetPetNextLevelExperience(1000);
29506 pet->SetFullHealth();
29509
29510 map->AddToMap(pet->ToCreature());
29511
29512 ASSERT(!petStable.CurrentPetIndex);
29513 petStable.SetCurrentUnslottedPetIndex(petStable.UnslottedPets.size());
29514 pet->FillPetInfo(&petStable.UnslottedPets.emplace_back());
29515
29516 pet->InitPetCreateSpells();
29519
29520 if (duration > 0)
29521 pet->SetDuration(duration);
29522
29523 //ObjectAccessor::UpdateObjectVisibility(pet);
29524
29525 if (isNew)
29526 *isNew = true;
29527
29528 return pet;
29529}
29530
29532{
29534 return HasSpell(chrSpec->MasterySpellID[0]) || HasSpell(chrSpec->MasterySpellID[1]);
29535
29536 return false;
29537}
29538
29540{
29543 #ifdef TRINITY_DEBUG
29544 #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
29545 { \
29546 if (check) \
29547 { \
29548 TC_LOG_DEBUG("entities.unit", "Player::ValidateMovementInfo: Violation of MovementFlags found ({}). " \
29549 "MovementFlags: {}, MovementFlags2: {} for player {}. Mask {} will be removed.", \
29550 STRINGIZE(check), mi->GetMovementFlags(), mi->GetExtraMovementFlags(), GetGUID().ToString(), maskToRemove); \
29551 mi->RemoveMovementFlag((maskToRemove)); \
29552 } \
29553 }
29554 #else
29555 #define REMOVE_VIOLATING_FLAGS(check, maskToRemove) \
29556 if (check) \
29557 mi->RemoveMovementFlag((maskToRemove));
29558 #endif
29559
29562
29569
29573
29577
29581
29585
29589
29593
29599
29603
29614
29617
29619
29620 // Client first checks if spline elevation != 0, then verifies flag presence
29621 if (G3D::fuzzyNe(mi->stepUpStartElevation, 0.0f))
29623
29624 #undef REMOVE_VIOLATING_FLAGS
29625}
29626
29627void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const
29628{
29630 WorldPackets::Spells::LearnedSpellInfo& learnedSpellInfo = supercededSpells.ClientLearnedSpellData.emplace_back();
29631 learnedSpellInfo.SpellID = newSpell;
29632 learnedSpellInfo.Superceded = oldSpell;
29633 SendDirectMessage(supercededSpells.Write());
29634}
29635
29637{
29638 if (!mapEntry->IsRaid())
29639 return m_dungeonDifficulty;
29640
29641 MapDifficultyEntry const* defaultDifficulty = sDB2Manager.GetDefaultMapDifficulty(mapEntry->ID);
29642 if (!defaultDifficulty)
29644
29645 DifficultyEntry const* difficulty = sDifficultyStore.LookupEntry(defaultDifficulty->DifficultyID);
29646 if (!difficulty || difficulty->Flags & DIFFICULTY_FLAG_LEGACY)
29648
29649 return m_raidDifficulty;
29650}
29651
29653{
29654 DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty);
29655 if (!difficultyEntry)
29656 return DIFFICULTY_NORMAL;
29657
29658 if (difficultyEntry->InstanceType != MAP_INSTANCE)
29659 return DIFFICULTY_NORMAL;
29660
29661 if (!(difficultyEntry->Flags & DIFFICULTY_FLAG_CAN_SELECT))
29662 return DIFFICULTY_NORMAL;
29663
29664 return difficulty;
29665}
29666
29668{
29669 DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty);
29670 if (!difficultyEntry)
29672
29673 if (difficultyEntry->InstanceType != MAP_RAID)
29675
29676 if (!(difficultyEntry->Flags & DIFFICULTY_FLAG_CAN_SELECT) || (difficultyEntry->Flags & DIFFICULTY_FLAG_LEGACY))
29678
29679 return difficulty;
29680}
29681
29683{
29684 DifficultyEntry const* difficultyEntry = sDifficultyStore.LookupEntry(difficulty);
29685 if (!difficultyEntry)
29686 return DIFFICULTY_10_N;
29687
29688 if (difficultyEntry->InstanceType != MAP_RAID)
29689 return DIFFICULTY_10_N;
29690
29691 if (!(difficultyEntry->Flags & DIFFICULTY_FLAG_CAN_SELECT) || !(difficultyEntry->Flags & DIFFICULTY_FLAG_LEGACY))
29692 return DIFFICULTY_10_N;
29693
29694 return difficulty;
29695}
29696
29697SpellInfo const* Player::GetCastSpellInfo(SpellInfo const* spellInfo, TriggerCastFlags& triggerFlag) const
29698{
29699 auto overrides = m_overrideSpells.find(spellInfo->Id);
29700 if (overrides != m_overrideSpells.end())
29701 for (uint32 spellId : overrides->second)
29702 if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(spellId, GetMap()->GetDifficultyID()))
29703 return Unit::GetCastSpellInfo(newInfo, triggerFlag);
29704
29705 return Unit::GetCastSpellInfo(spellInfo, triggerFlag);
29706}
29707
29708void Player::AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
29709{
29710 m_overrideSpells[overridenSpellId].insert(newSpellId);
29711}
29712
29713void Player::RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
29714{
29715 auto overrides = m_overrideSpells.find(overridenSpellId);
29716 if (overrides == m_overrideSpells.end())
29717 return;
29718
29719 overrides->second.erase(newSpellId);
29720 if (overrides->second.empty())
29721 m_overrideSpells.erase(overrides);
29722}
29723
29725{
29726 if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(AsUnderlyingType(GetPrimarySpecialization())))
29727 {
29728 for (size_t j = 0; j < specSpells->size(); ++j)
29729 {
29730 SpecializationSpellsEntry const* specSpell = (*specSpells)[j];
29731 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(specSpell->SpellID, DIFFICULTY_NONE);
29732 if (!spellInfo || spellInfo->SpellLevel > GetLevel())
29733 continue;
29734
29735 LearnSpell(specSpell->SpellID, true);
29736 if (specSpell->OverridesSpellID)
29737 AddOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
29738 }
29739 }
29740}
29741
29743{
29744 for (uint32 i = 0; i < MAX_SPECIALIZATIONS; ++i)
29745 {
29746 if (ChrSpecializationEntry const* specialization = sDB2Manager.GetChrSpecializationByIndex(GetClass(), i))
29747 {
29748 if (std::vector<SpecializationSpellsEntry const*> const* specSpells = sDB2Manager.GetSpecializationSpells(specialization->ID))
29749 {
29750 for (size_t j = 0; j < specSpells->size(); ++j)
29751 {
29752 SpecializationSpellsEntry const* specSpell = (*specSpells)[j];
29753 RemoveSpell(specSpell->SpellID, true);
29754 if (specSpell->OverridesSpellID)
29755 RemoveOverrideSpell(specSpell->OverridesSpellID, specSpell->SpellID);
29756 }
29757 }
29758
29759 for (uint32 j = 0; j < MAX_MASTERY_SPELLS; ++j)
29760 if (uint32 mastery = specialization->MasterySpellID[j])
29761 RemoveAurasDueToSpell(mastery);
29762 }
29763 }
29764}
29765
29767{
29768 int32 categoryIndex = m_activePlayerData->CategoryCooldownMods.FindIndexIf([spellCategoryId](UF::CategoryCooldownMod const& mod)
29769 {
29770 return mod.SpellCategoryID == spellCategoryId;
29771 });
29772
29773 if (categoryIndex < 0)
29774 {
29776 .ModifyValue(&Player::m_activePlayerData)
29778
29779 newMod.SpellCategoryID = spellCategoryId;
29780 newMod.ModCooldown = -mod;
29781 }
29782 else
29783 {
29785 .ModifyValue(&Player::m_activePlayerData)
29786 .ModifyValue(&UF::ActivePlayerData::CategoryCooldownMods, categoryIndex)
29787 .ModifyValue(&UF::CategoryCooldownMod::ModCooldown), m_activePlayerData->CategoryCooldownMods[categoryIndex].ModCooldown - mod);
29788 }
29789}
29790
29792{
29793 int32 categoryIndex = m_activePlayerData->CategoryCooldownMods.FindIndexIf([spellCategoryId](UF::CategoryCooldownMod const& mod)
29794 {
29795 return mod.SpellCategoryID == spellCategoryId;
29796 });
29797
29798 if (categoryIndex < 0)
29799 return;
29800
29801 if (m_activePlayerData->CategoryCooldownMods[categoryIndex].ModCooldown + mod == 0)
29802 {
29804 .ModifyValue(&Player::m_activePlayerData)
29805 .ModifyValue(&UF::ActivePlayerData::CategoryCooldownMods), categoryIndex);
29806 }
29807 else
29808 {
29810 .ModifyValue(&Player::m_activePlayerData)
29811 .ModifyValue(&UF::ActivePlayerData::CategoryCooldownMods, categoryIndex)
29812 .ModifyValue(&UF::CategoryCooldownMod::ModCooldown), m_activePlayerData->CategoryCooldownMods[categoryIndex].ModCooldown + mod);
29813 }
29814}
29815
29817{
29818 sSocialMgr->RemovePlayerSocial(GetGUID());
29819 m_social = nullptr;
29820}
29821
29823{
29824 return ASSERT_NOTNULL(sDB2Manager.GetDefaultChrSpecializationForClass(GetClass()))->ID;
29825}
29826
29828{
29830}
29831
29833{
29835 raidGroupOnly.Delay = delay;
29836 raidGroupOnly.Reason = reason;
29837
29838 SendDirectMessage(raidGroupOnly.Write());
29839}
29840
29842{
29843 ASSERT(maximum <= 1000000);
29844
29845 uint32 roll = urand(minimum, maximum);
29846
29848 randomRoll.Min = minimum;
29849 randomRoll.Max = maximum;
29850 randomRoll.Result = roll;
29851 randomRoll.Roller = GetGUID();
29852 randomRoll.RollerWowAccount = GetSession()->GetAccountGUID();
29853 if (Group* group = GetGroup())
29854 group->BroadcastPacket(randomRoll.Write(), false);
29855 else
29856 SendDirectMessage(randomRoll.Write());
29857
29858 return roll;
29859}
29860
29862{
29863 // @todo Activate pvp item levels during world pvp
29864 Map* map = GetMap();
29865 bool pvpActivity = map->IsBattlegroundOrArena() || map->GetEntry()->Flags[1] & 0x40 || HasPvpRulesEnabled();
29866
29867 if (_usePvpItemLevels != pvpActivity)
29868 {
29869 float healthPct = GetHealthPct();
29871 ActivatePvpItemLevels(pvpActivity);
29873 SetHealth(CalculatePct(GetMaxHealth(), healthPct));
29874 }
29875 // @todo other types of power scaling such as timewalking
29876}
29877
29879{
29880 uint8 limit = limitEntry->Quantity;
29881
29882 if (std::vector<ItemLimitCategoryConditionEntry const*> const* limitConditions = sDB2Manager.GetItemLimitCategoryConditions(limitEntry->ID))
29883 {
29884 for (ItemLimitCategoryConditionEntry const* limitCondition : *limitConditions)
29885 {
29886 PlayerConditionEntry const* playerCondition = sPlayerConditionStore.LookupEntry(limitCondition->PlayerConditionID);
29887 if (!playerCondition || ConditionMgr::IsPlayerMeetingCondition(this, playerCondition))
29888 limit += limitCondition->AddQuantity;
29889 }
29890 }
29891
29892 return limit;
29893}
29894
29895template <typename T>
29896static bool ForEachEquipmentSlot(InventoryType inventoryType, bool canDualWield, bool canTitanGrip, T callback)
29897{
29898 switch (inventoryType)
29899 {
29900 case INVTYPE_HEAD: callback(EQUIPMENT_SLOT_HEAD); return true;
29901 case INVTYPE_NECK: callback(EQUIPMENT_SLOT_NECK); return true;
29902 case INVTYPE_SHOULDERS: callback(EQUIPMENT_SLOT_SHOULDERS); return true;
29903 case INVTYPE_BODY: callback(EQUIPMENT_SLOT_BODY); return true;
29904 case INVTYPE_ROBE:
29905 case INVTYPE_CHEST: callback(EQUIPMENT_SLOT_CHEST); return true;
29906 case INVTYPE_WAIST: callback(EQUIPMENT_SLOT_WAIST); return true;
29907 case INVTYPE_LEGS: callback(EQUIPMENT_SLOT_LEGS); return true;
29908 case INVTYPE_FEET: callback(EQUIPMENT_SLOT_FEET); return true;
29909 case INVTYPE_WRISTS: callback(EQUIPMENT_SLOT_WRISTS); return true;
29910 case INVTYPE_HANDS: callback(EQUIPMENT_SLOT_HANDS); return true;
29911 case INVTYPE_CLOAK: callback(EQUIPMENT_SLOT_BACK); return true;
29912 case INVTYPE_FINGER:
29913 callback(EQUIPMENT_SLOT_FINGER1);
29914 callback(EQUIPMENT_SLOT_FINGER2, true);
29915 return true;
29916 case INVTYPE_TRINKET:
29917 callback(EQUIPMENT_SLOT_TRINKET1);
29918 callback(EQUIPMENT_SLOT_TRINKET2, true);
29919 return true;
29920 case INVTYPE_WEAPON:
29921 callback(EQUIPMENT_SLOT_MAINHAND);
29922 if (canDualWield)
29923 callback(EQUIPMENT_SLOT_OFFHAND, true);
29924 return true;
29925 case INVTYPE_2HWEAPON:
29926 callback(EQUIPMENT_SLOT_MAINHAND);
29927 if (canDualWield && canTitanGrip)
29928 callback(EQUIPMENT_SLOT_OFFHAND, true);
29929 return true;
29930 case INVTYPE_RANGED:
29932 case INVTYPE_WEAPONMAINHAND: callback(EQUIPMENT_SLOT_MAINHAND); return true;
29933 case INVTYPE_SHIELD:
29934 case INVTYPE_HOLDABLE:
29935 case INVTYPE_WEAPONOFFHAND: callback(EQUIPMENT_SLOT_OFFHAND); return true;
29936
29937 case INVTYPE_NON_EQUIP:
29938 case INVTYPE_BAG:
29939 case INVTYPE_TABARD:
29940 case INVTYPE_AMMO:
29941 case INVTYPE_THROWN:
29942 case INVTYPE_QUIVER:
29943 case INVTYPE_RELIC:
29944 default:
29945 return false;
29946 }
29947}
29948
29950{
29951 std::array<std::tuple<InventoryType, uint32, ObjectGuid>, EQUIPMENT_SLOT_END> bestItemLevels = { };
29952 bestItemLevels.fill({ INVTYPE_NON_EQUIP, 0, ObjectGuid::Empty });
29953 float sum = 0;
29954
29955 ForEachItem(ItemSearchLocation::Everywhere, [this, &bestItemLevels, &sum](Item* item)
29956 {
29957 ItemTemplate const* itemTemplate = item->GetTemplate();
29958 if (itemTemplate && itemTemplate->GetInventoryType() < INVTYPE_PROFESSION_TOOL)
29959 {
29960 uint16 dest;
29961 if (item->IsEquipped())
29962 {
29963 uint32 itemLevel = item->GetItemLevel(this);
29964 InventoryType inventoryType = itemTemplate->GetInventoryType();
29965 std::tuple<InventoryType, uint32, ObjectGuid>& slotData = bestItemLevels[item->GetSlot()];
29966 if (itemLevel > std::get<1>(slotData))
29967 {
29968 sum += itemLevel - std::get<1>(slotData);
29969 slotData = { inventoryType, itemLevel, item->GetGUID() };
29970 }
29971 }
29972 else if (CanEquipItem(NULL_SLOT, dest, item, true, false) == EQUIP_ERR_OK)
29973 {
29974 uint32 itemLevel = item->GetItemLevel(this);
29975 InventoryType inventoryType = itemTemplate->GetInventoryType();
29976 ForEachEquipmentSlot(inventoryType, m_canDualWield, m_canTitanGrip, [&bestItemLevels, item, itemLevel, inventoryType, &sum](EquipmentSlots slot, bool checkDuplicateGuid = false)
29977 {
29978 if (checkDuplicateGuid)
29979 {
29980 for (std::tuple<InventoryType, uint32, ObjectGuid> const& slotData : bestItemLevels)
29981 if (std::get<2>(slotData) == item->GetGUID())
29982 return;
29983 }
29984
29985 std::tuple<InventoryType, uint32, ObjectGuid>& slotData = bestItemLevels[slot];
29986 if (itemLevel > std::get<1>(slotData))
29987 {
29988 sum += itemLevel - std::get<1>(slotData);
29989 slotData = { inventoryType, itemLevel, item->GetGUID() };
29990 }
29991 });
29992 }
29993 }
29995 });
29996
29997 // If main hand is a 2h weapon, count it twice
29998 std::tuple<InventoryType, uint32, ObjectGuid> const& mainHand = bestItemLevels[EQUIPMENT_SLOT_MAINHAND];
29999 if (!m_canTitanGrip && std::get<0>(mainHand) == INVTYPE_2HWEAPON)
30000 sum += std::get<1>(mainHand);
30001
30002 sum /= 16.0f;
30004}
30005
30007{
30008 float totalItemLevel = 0;
30010 {
30011 if (Item* pItem = GetItemByPos(INVENTORY_SLOT_BAG_0, i))
30012 {
30013 uint32 itemLevel = pItem->GetItemLevel(this);
30014 totalItemLevel += itemLevel;
30015 if (!m_canTitanGrip && i == EQUIPMENT_SLOT_MAINHAND && pItem->GetTemplate()->GetInventoryType() == INVTYPE_2HWEAPON) // 2h weapon counts twice
30016 totalItemLevel += itemLevel;
30017 }
30018 }
30019
30020 totalItemLevel /= 16.0;
30021 SetAverageItemLevelEquipped(totalItemLevel);
30022}
30023
30025{
30026 // Only allow to toggle on when in stormwind/orgrimmar, and to toggle off in any rested place.
30027 // Also disallow when in combat
30029 return;
30030
30031 if (enabled && !CanEnableWarModeInArea())
30032 return;
30033
30034 // Don't allow to chang when aura SPELL_PVP_RULES_ENABLED is on
30036 return;
30037
30038 if (enabled)
30039 {
30041 SetPvP(true);
30042 }
30043 else
30044 {
30046 SetPvP(false);
30047 }
30048
30050}
30051
30052void Player::SetWarModeLocal(bool enabled)
30053{
30054 if (enabled)
30056 else
30058}
30059
30061{
30062 AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetZoneId());
30063 if (!zone || !IsFriendlyArea(zone))
30064 return false;
30065
30066 AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId());
30067 if (!area)
30068 area = zone;
30069
30070 do
30071 {
30072 if (area->GetFlags2().HasFlag(AreaFlags2::AllowWarModeToggle))
30073 return true;
30074
30075 area = sAreaTableStore.LookupEntry(area->ParentAreaID);
30076 } while (area);
30077
30078 return false;
30079}
30080
30082{
30083 uint32 auraInside = 282559;
30085
30086 if (IsWarModeDesired())
30087 {
30089 {
30091 CastSpell(this, auraInside, true);
30092 RemoveAurasDueToSpell(auraOutside);
30094 }
30095 else
30096 {
30098 CastSpell(this, auraOutside, true);
30099 RemoveAurasDueToSpell(auraInside);
30100 }
30101 SetWarModeLocal(true);
30103 }
30104 else
30105 {
30106 SetWarModeLocal(false);
30107 RemoveAurasDueToSpell(auraOutside);
30108 RemoveAurasDueToSpell(auraInside);
30113 }
30114}
30115
30117{
30119
30121}
30122
30123std::string Player::GetDebugInfo() const
30124{
30125 std::stringstream sstr;
30126 sstr << Unit::GetDebugInfo();
30127 return sstr.str();
30128}
30129
30131{
30132 if (!creature)
30133 {
30136 return;
30137 }
30138
30139 if (!creature->IsAreaSpiritHealer())
30140 return;
30141
30142 _areaSpiritHealerGUID = creature->GetGUID();
30144}
30145
30147{
30148 int32 timeLeft = 0;
30149 if (Spell* spell = spiritHealer->GetCurrentSpell(CURRENT_CHANNELED_SPELL))
30150 timeLeft = spell->GetTimer();
30151
30152 SendAreaSpiritHealerTime(spiritHealer->GetGUID(), timeLeft);
30153}
30154
30155void Player::SendAreaSpiritHealerTime(ObjectGuid const& spiritHealerGUID, int32 timeLeft) const
30156{
30158 areaSpiritHealerTime.HealerGuid = spiritHealerGUID;
30159 areaSpiritHealerTime.TimeLeft = timeLeft;
30160 SendDirectMessage(areaSpiritHealerTime.Write());
30161}
30162
30163void Player::SendDisplayToast(uint32 entry, DisplayToastType type, bool isBonusRoll, uint32 quantity, DisplayToastMethod method, uint32 questId, Item* item /*= nullptr*/) const
30164{
30166 displayToast.Quantity = quantity;
30167 displayToast.DisplayToastMethod = method;
30168 displayToast.QuestID = questId;
30169 displayToast.Type = type;
30170
30171 switch (type)
30172 {
30174 {
30175 if (!item)
30176 return;
30177
30178 displayToast.BonusRoll = isBonusRoll;
30179 displayToast.Item.Initialize(item);
30180 displayToast.LootSpec = 0; // loot spec that was selected when loot was generated (not at loot time)
30181 displayToast.Gender = GetNativeGender();
30182 break;
30183 }
30185 displayToast.CurrencyID = entry;
30186 break;
30187 default:
30188 break;
30189 }
30190
30191 SendDirectMessage(displayToast.Write());
30192}
30193
30195{
30196 return _player->GetMoney();
30197}
30198
30200{
30201 return _player->GetCurrencyQuantity(currencyId);
30202}
30203
30205{
30206 return _player->GetLevel();
30207}
30208
30210{
30211 return _player->IsQuestRewarded(questId);
30212}
30213
30215{
30216 return _player->HasAchieved(achievementId);
30217}
30218
30220{
30221 return AsUnderlyingType(_player->GetPrimarySpecialization());
30222}
30223
30224void Player::RequestSpellCast(std::unique_ptr<SpellCastRequest> castRequest)
30225{
30226 // We are overriding an already existing spell cast request so inform the client that the old cast is being replaced
30229
30230 _pendingSpellCastRequest = std::move(castRequest);
30231
30232 // If we can process the cast request right now, do it.
30235}
30236
30238{
30240 return;
30241
30242 // We have to inform the client that the cast has been canceled. Otherwise the cast button will remain highlightened
30244 castFailed.CastID = _pendingSpellCastRequest->CastRequest.CastID;
30245 castFailed.SpellID = _pendingSpellCastRequest->CastRequest.SpellID;
30246 castFailed.Reason = SPELL_FAILED_DONT_REPORT;
30247 SendDirectMessage(castFailed.Write());
30248
30249 _pendingSpellCastRequest = nullptr;
30250}
30251
30252// A spell can be queued up within 400 milliseconds before global cooldown expires or the cast finishes
30253static constexpr Milliseconds SPELL_QUEUE_TIME_WINDOW = 400ms;
30254
30255bool Player::CanRequestSpellCast(SpellInfo const* spellInfo, Unit const* castingUnit) const
30256{
30258 return false;
30259
30261 if (Spell const* spell = GetCurrentSpell(spellSlot))
30262 if (Milliseconds(spell->GetRemainingCastTime()) > SPELL_QUEUE_TIME_WINDOW)
30263 return false;
30264
30265 return true;
30266}
30267
30269{
30271 return;
30272
30273 TriggerCastFlags triggerFlag = TRIGGERED_NONE;
30274
30275 Unit* castingUnit = _pendingSpellCastRequest->CastingUnitGUID == GetGUID() ? this : ObjectAccessor::GetUnit(*this, _pendingSpellCastRequest->CastingUnitGUID);
30276
30277 // client provided targets
30278 SpellCastTargets targets(castingUnit, _pendingSpellCastRequest->CastRequest);
30279
30280 // The spell cast has been requested by using an item. Handle the cast accordingly.
30281 if (_pendingSpellCastRequest->ItemData.has_value())
30282 {
30284 _pendingSpellCastRequest = nullptr;
30285 else
30287 return;
30288 }
30289
30290 // check known spell or raid marker spell (which not requires player to know it)
30291 SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(_pendingSpellCastRequest->CastRequest.SpellID, GetMap()->GetDifficultyID());
30292 Player* plrCaster = castingUnit->ToPlayer();
30293 if (plrCaster && !plrCaster->HasActiveSpell(spellInfo->Id) && !spellInfo->HasAttribute(SPELL_ATTR8_SKIP_IS_KNOWN_CHECK))
30294 {
30295 bool allow = false;
30296
30297 // allow casting of unknown spells for special lock cases
30298 if (GameObject* go = targets.GetGOTarget())
30299 if (go->GetSpellForLock(plrCaster) == spellInfo)
30300 allow = true;
30301
30302 // allow casting of spells triggered by clientside periodic trigger auras
30304 {
30305 allow = true;
30306 triggerFlag = TRIGGERED_FULL_MASK;
30307 }
30308
30309 if (!allow)
30310 {
30312 return;
30313 }
30314 }
30315
30316 // Check possible spell cast overrides
30317 spellInfo = castingUnit->GetCastSpellInfo(spellInfo, triggerFlag);
30318 if (spellInfo->IsPassive())
30319 {
30321 return;
30322 }
30323
30324 // can't use our own spells when we're in possession of another unit
30325 if (isPossessing())
30326 {
30328 return;
30329 }
30330
30331 // Client is resending autoshot cast opcode when other spell is cast during shoot rotation
30332 // Skip it to prevent "interrupt" message
30333 // Also check targets! target may have changed and we need to interrupt current spell
30334 if (spellInfo->IsAutoRepeatRangedSpell())
30335 {
30336 if (Spell* spell = castingUnit->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL))
30337 {
30338 if (spell->m_spellInfo == spellInfo && spell->m_targets.GetUnitTargetGUID() == targets.GetUnitTargetGUID())
30339 {
30341 return;
30342 }
30343 }
30344 }
30345
30346 // auto-selection buff level base at target level (in spellInfo)
30347 if (targets.GetUnitTarget())
30348 {
30349 SpellInfo const* actualSpellInfo = spellInfo->GetAuraRankForLevel(targets.GetUnitTarget()->GetLevelForTarget(this));
30350
30351 // if rank not found then function return NULL but in explicit cast case original spell can be cast and later failed with appropriate error message
30352 if (actualSpellInfo)
30353 spellInfo = actualSpellInfo;
30354 }
30355
30356 Spell* spell = new Spell(castingUnit, spellInfo, triggerFlag);
30357
30359 spellPrepare.ClientCastID = _pendingSpellCastRequest->CastRequest.CastID;
30360 spellPrepare.ServerCastID = spell->m_castId;
30361 SendDirectMessage(spellPrepare.Write());
30362
30363 spell->m_fromClient = true;
30364 spell->m_misc.Raw.Data[0] = _pendingSpellCastRequest->CastRequest.Misc[0];
30365 spell->m_misc.Raw.Data[1] = _pendingSpellCastRequest->CastRequest.Misc[1];
30366 spell->prepare(targets);
30367
30368 _pendingSpellCastRequest = nullptr;
30369}
30370
30372{
30373 Item* item = GetUseableItemByPos(castRequest.ItemData->PackSlot, castRequest.ItemData->Slot);
30374 if (!item)
30375 {
30376 SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
30377 return false;
30378 }
30379
30380 if (item->GetGUID() != castRequest.ItemData->CastItem)
30381 {
30382 SendEquipError(EQUIP_ERR_ITEM_NOT_FOUND, nullptr, nullptr);
30383 return false;
30384 }
30385
30386 ItemTemplate const* proto = item->GetTemplate();
30387 if (!proto)
30388 {
30390 return false;
30391 }
30392
30393 // some item classes can be used only in equipped state
30394 if (proto->GetInventoryType() != INVTYPE_NON_EQUIP && !item->IsEquipped())
30395 {
30397 return false;
30398 }
30399
30400 InventoryResult msg = CanUseItem(item);
30401 if (msg != EQUIP_ERR_OK)
30402 {
30403 SendEquipError(msg, item, nullptr);
30404 return false;
30405 }
30406
30407 // only allow conjured consumable, bandage, poisons (all should have the 2^21 item flag set in DB)
30409 {
30411 return false;
30412 }
30413
30414 // don't allow items banned in arena
30416 {
30418 return false;
30419 }
30420
30421 if (IsInCombat())
30422 {
30423 for (ItemEffectEntry const* effect : item->GetEffects())
30424 {
30425 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(effect->SpellID, GetMap()->GetDifficultyID()))
30426 {
30427 if (!spellInfo->CanBeUsedInCombat(this))
30428 {
30430 return false;
30431 }
30432 }
30433 }
30434 }
30435
30436 // check also BIND_ON_ACQUIRE and BIND_QUEST for .additem or .additemset case by GM (not binded at adding to inventory)
30437 if (item->GetBonding() == BIND_ON_USE || item->GetBonding() == BIND_ON_ACQUIRE || item->GetBonding() == BIND_QUEST)
30438 {
30439 if (!item->IsSoulBound())
30440 {
30441 item->SetState(ITEM_CHANGED, this);
30442 item->SetBinding(true);
30444 }
30445 }
30446
30448
30449 // Note: If script stop casting it must send appropriate data to client to prevent stuck item in gray state.
30450 if (!sScriptMgr->OnItemUse(this, item, targets, castRequest.CastRequest.CastID))
30451 {
30452 // no script or script not process request by self
30453 CastItemUseSpell(item, targets, castRequest.CastRequest.CastID, castRequest.CastRequest.Misc);
30454 }
30455
30456 return true;
30457}
30458
30460{
30462 return false;
30463
30464 Unit const* castingUnit = _pendingSpellCastRequest->CastingUnitGUID == GetGUID() ? this : ObjectAccessor::GetUnit(*this, _pendingSpellCastRequest->CastingUnitGUID);
30465 if (!castingUnit || !castingUnit->IsInWorld() || (castingUnit != this && GetUnitBeingMoved() != castingUnit))
30466 {
30467 // If the casting unit is no longer available, just cancel the entire spell cast request and be done with it
30469 return false;
30470 }
30471
30472 // Generic and melee spells have to wait, channeled spells can be processed immediately.
30473 if (!castingUnit->GetCurrentSpell(CURRENT_CHANNELED_SPELL) && castingUnit->HasUnitState(UNIT_STATE_CASTING))
30474 return false;
30475
30476 // Waiting for the global cooldown to expire before attempting to execute the cast request
30477 if (castingUnit->GetSpellHistory()->GetRemainingGlobalCooldown(sSpellMgr->AssertSpellInfo(_pendingSpellCastRequest->CastRequest.SpellID, GetMap()->GetDifficultyID())) > 0ms)
30478 return false;
30479
30480 return true;
30481}
#define sArenaTeamMgr
Definition: ArenaTeamMgr.h:53
#define MAX_ARENA_SLOT
Definition: ArenaTeam.h:109
constexpr uint32 SPELL_ID_HEART_ESSENCE_ACTION_BAR_OVERRIDE
Definition: AzeriteItem.h:27
constexpr uint32 ITEM_ID_HEART_OF_AZEROTH
Definition: AzeriteItem.h:23
uint32 GetBagSize(Bag const *bag)
Definition: Bag.cpp:303
Item * GetItemInBag(Bag const *bag, uint8 slot)
Definition: Bag.cpp:308
#define MAX_BAG_SIZE
Definition: Bag.h:22
#define sBattlefieldMgr
#define sBattlegroundMgr
@ SCORE_BONUS_HONOR
@ SPELL_AURA_PLAYER_INACTIVE
Definition: Battleground.h:114
@ SPELL_RECENTLY_DROPPED_ALLIANCE_FLAG
Definition: Battleground.h:111
@ SPELL_RECENTLY_DROPPED_HORDE_FLAG
Definition: Battleground.h:112
@ SPELL_MERCENARY_CONTRACT_ALLIANCE
Definition: Battleground.h:118
@ SPELL_MERCENARY_CONTRACT_HORDE
Definition: Battleground.h:117
@ SPELL_RECENTLY_DROPPED_NEUTRAL_FLAG
Definition: Battleground.h:113
@ SPELL_WAITING_FOR_RESURRECT
Definition: Battleground.h:104
@ STATUS_WAIT_LEAVE
Definition: Battleground.h:168
@ STATUS_WAIT_JOIN
Definition: Battleground.h:166
@ STATUS_IN_PROGRESS
Definition: Battleground.h:167
#define MAX_CUF_PROFILES
Maximum number of CompactUnitFrames profiles.
Definition: CUFProfile.h:26
#define sCharacterCache
@ CHAR_DEL_CHAR_GLYPHS
@ CHAR_DEL_ITEM_INSTANCE_AZERITE_MILESTONE_POWER_BY_OWNER
@ CHAR_DEL_CHAR_SOCIAL_BY_FRIEND
@ CHAR_DEL_CHAR_GIFT
@ CHAR_DEL_CHAR_PET_DECLINEDNAME_BY_OWNER
@ CHAR_SEL_CHAR_OLD_CHARS
@ CHAR_DEL_GUILD_BANK_EVENTLOG_BY_PLAYER
@ CHAR_UPD_MAIL
@ CHAR_DEL_ITEM_INSTANCE_AZERITE_BY_OWNER
@ CHAR_DEL_CHARACTER_QUESTSTATUS_WEEKLY
@ CHAR_REP_CHAR_VOID_STORAGE_ITEM
@ CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST
@ CHAR_INS_CHAR_SPELL
@ CHAR_UPD_QUEST_TRACK_COMPLETE_TIME
@ CHAR_UPD_REM_AT_LOGIN_FLAG
@ CHAR_DEL_CHARACTER_FAVORITE_AUCTIONS_BY_CHAR
@ CHAR_DEL_GUILD_EVENTLOG_BY_PLAYER
@ CHAR_UPD_EQUIP_SET
@ CHAR_INS_AURA_EFFECT
@ CHAR_DEL_CHAR_SKILLS
@ CHAR_DEL_CHAR_PET_BY_OWNER
@ CHAR_DEL_CHARACTER_AURA_STORED_LOCATIONS_BY_GUID
@ CHAR_DEL_CHAR_TRANSMOG_OUTFITS
@ CHAR_SEL_MAILITEMS_AZERITE
@ CHAR_INS_CHARACTER_QUESTSTATUS_SEASONAL
@ CHAR_INS_CHAR_TALENT
@ CHAR_DEL_CHAR_STATS
@ CHAR_DEL_CHARACTER_CUSTOMIZATIONS
@ CHAR_DEL_ITEM_INSTANCE_BY_OWNER
@ CHAR_DEL_CHAR_INVENTORY_BY_ITEM
@ CHAR_INS_CHAR_SKILLS
@ CHAR_DEL_CHAR_CUF_PROFILES
@ CHAR_UPD_PLAYER_CURRENCY
@ CHAR_REP_INVENTORY_ITEM
@ CHAR_DEL_CHAR_DECLINED_NAME
@ CHAR_SEL_MAILITEMS_AZERITE_MILESTONE_POWER
@ CHAR_SEL_MAILITEMS_AZERITE_UNLOCKED_ESSENCE
@ CHAR_INS_EQUIP_SET
@ CHAR_DEL_CHAR_SPELL_FAVORITE
@ CHAR_INS_BATTLEGROUND_RANDOM
@ CHAR_SEL_MAILITEMS
@ CHAR_DEL_PLAYER_BGDATA
@ CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES
@ CHAR_UPD_CHAR_SKILLS
@ CHAR_INS_CHAR_TRAIT_ENTRIES
@ CHAR_UPD_DELETE_INFO
@ CHAR_DEL_CHAR_CUF_PROFILES_BY_ID
@ CHAR_UPD_CHAR_PET_SLOT_BY_ID
@ CHAR_DEL_INVALID_MAIL_ITEM
@ CHAR_INS_PLAYER_HOMEBIND
@ CHAR_DEL_CHAR_FISHINGSTEPS
@ CHAR_DEL_INVALID_SPELL_SPELLS
@ CHAR_INS_CHARACTER_QUESTSTATUS_DAILY
@ CHAR_INS_CHARACTER_CUSTOMIZATION
@ CHAR_DEL_CHAR_SPELL_COOLDOWNS
@ CHAR_INS_CHAR_FISHINGSTEPS
@ CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC
@ CHAR_DEL_MAIL_ITEM
@ CHAR_DEL_PLAYER_HOMEBIND
@ CHAR_DEL_CHAR_EQUIPMENTSETS
@ CHAR_REP_CHAR_CUF_PROFILES
@ CHAR_SEL_CHARACTER_ACTIONS_SPEC
@ CHAR_DEL_CHARACTER_QUESTSTATUS_DAILY
@ CHAR_SEL_CHAR_POSITION
@ CHAR_UPD_CHAR_ACTION
@ CHAR_DEL_EQUIP_SET
@ CHAR_INS_AURA
@ CHAR_DEL_ITEM_INSTANCE_ARTIFACT_POWERS_BY_OWNER
@ CHAR_DEL_CHARACTER_ARENA_STATS
@ CHAR_SEL_GROUP_MEMBER
@ CHAR_INS_CHARACTER_AURA_STORED_LOCATION
@ CHAR_DEL_CHAR_SPELL_BY_SPELL
@ CHAR_UPD_CHARACTER_POSITION
@ CHAR_DEL_CHAR_TRAIT_ENTRIES
@ CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST
@ CHAR_DEL_CHARACTER_QUESTSTATUS_SEASONAL
@ CHAR_SEL_MAILITEMS_ARTIFACT
@ CHAR_DEL_CHAR_TRAIT_CONFIGS_BY_CHAR
@ CHAR_DEL_CHAR_TRAIT_CONFIGS
@ CHAR_DEL_PLAYER_ACCOUNT_DATA
@ CHAR_DEL_ITEM_INSTANCE_TRANSMOG_BY_OWNER
@ CHAR_UPD_PLAYER_HOMEBIND
@ CHAR_DEL_MAIL
@ CHAR_INS_CHAR_GLYPHS
@ CHAR_INS_CHAR_STATS
@ CHAR_SEL_CHAR_POSITION_XYZ
@ CHAR_DEL_CHAR_TALENT
@ CHAR_DEL_CHAR_SKILL_BY_SKILL
@ CHAR_SEL_CHAR_SOCIAL
@ CHAR_DEL_ITEM_INSTANCE_AZERITE_EMPOWERED_BY_OWNER
@ CHAR_INS_CHARACTER_QUESTSTATUS_WEEKLY
@ CHAR_DEL_ITEM_REFUND_INSTANCE
@ CHAR_DEL_CHAR_INVENTORY
@ CHAR_DEL_ACCOUNT_INSTANCE_LOCK_TIMES
@ CHAR_DEL_CHAR_AURA
@ CHAR_INS_CHARACTER
@ CHAR_DEL_CHAR_QUESTSTATUS
@ CHAR_DEL_CHAR_ACTION
@ CHAR_DEL_CHARACTER_INSTANCE_LOCK_BY_GUID
@ CHAR_REP_CHAR_QUESTSTATUS_OBJECTIVES
@ CHAR_SEL_CHAR_PET_IDS
@ CHAR_SEL_ITEM_BOP_TRADE
@ CHAR_DEL_ITEM_INSTANCE_MODIFIERS_BY_OWNER
@ CHAR_DEL_MAIL_BY_ID
@ CHAR_DEL_CHAR_ACHIEVEMENTS
@ CHAR_INS_PLAYER_BGDATA
@ CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_CHAR_GUID
@ CHAR_UPD_ZONE
@ CHAR_REP_PLAYER_CURRENCY
@ CHAR_SEL_CHAR_COD_ITEM_MAIL
@ CHAR_DEL_CHAR_ACTION_BY_TRAIT_CONFIG
@ CHAR_DEL_CHAR_VOID_STORAGE_ITEM_BY_SLOT
@ CHAR_INS_QUEST_TRACK
@ CHAR_UPD_ADD_AT_LOGIN_FLAG
@ CHAR_INS_CHAR_PVP_TALENT
@ CHAR_DEL_CHAR_REPUTATION
@ CHAR_DEL_CHAR_TRAIT_ENTRIES_BY_CHAR
@ CHAR_DEL_GIFT
@ CHAR_UPD_CHARACTER
@ CHAR_DEL_ITEM_INSTANCE_ARTIFACT_BY_OWNER
@ CHAR_DEL_CHARACTER_AURA_STORED_LOCATION
@ CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT
@ CHAR_INS_CHAR_ACTION
@ CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS
@ CHAR_DEL_CHARACTER
@ CHAR_SEL_ITEM_REFUNDS
@ CHAR_INS_CHARACTER_QUESTSTATUS_MONTHLY
@ CHAR_DEL_CHAR_PVP_TALENT
@ CHAR_UPD_CHAR_MONEY
@ CHAR_DEL_CHAR_SOCIAL_BY_GUID
@ CHAR_SEL_MAILITEMS_AZERITE_EMPOWERED
@ CHAR_DEL_CHAR_AURA_EFFECT
@ CHAR_INS_CHAR_TRAIT_CONFIGS
@ CHAR_SEL_CHAR_ZONE
@ CHAR_DEL_PLAYER_CURRENCY
@ CHAR_INS_TRANSMOG_OUTFIT
@ CHAR_INS_ITEM_BOP_TRADE
@ CHAR_DEL_MAIL_ITEM_BY_ID
@ CHAR_DEL_ITEM_INSTANCE_AZERITE_UNLOCKED_ESSENCE_BY_OWNER
@ CHAR_REP_CHAR_QUESTSTATUS
@ CHAR_DEL_CHAR_SPELL
@ CHAR_UPD_TRANSMOG_OUTFIT
@ CHAR_DEL_CHAR_QUESTSTATUS_REWARDED
@ CHAR_DEL_CHAR_QUESTSTATUS_OBJECTIVES_BY_QUEST
@ CHAR_DEL_CHAR_SPELL_CHARGES
@ CHAR_DEL_CHARACTER_QUESTSTATUS_MONTHLY
@ CHAR_DEL_ITEM_INSTANCE_GEMS_BY_OWNER
@ CHAR_INS_ACCOUNT_INSTANCE_LOCK_TIMES
@ CHAR_DEL_MAIL_ITEMS
@ CHAR_DEL_TRANSMOG_OUTFIT
@ CHAR_INS_CHAR_QUESTSTATUS_REWARDED
@ CHAR_INS_CHAR_SPELL_FAVORITE
@ CHAR_DEL_BATTLEGROUND_RANDOM
#define sCharacterTemplateDataStore
#define MAX_UNIT_ACTION_BAR_INDEX
Definition: CharmInfo.h:86
constexpr uint8 MAX_SPELL_CHARM
Definition: CharmInfo.h:28
#define MAKE_UNIT_ACTION_BUTTON(A, T)
Definition: CharmInfo.h:35
constexpr uint8 MAX_SPELL_CONTROL_BAR
Definition: CharmInfo.h:31
#define CINEMATIC_UPDATEDIFF
Definition: CinematicMgr.h:25
@ MOUNT_STATUS_NONE
Definition: CollectionMgr.h:74
LocaleConstant
Definition: Common.h:48
@ LOCALE_enUS
Definition: Common.h:49
#define DEFAULT_LOCALE
Definition: Common.h:66
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
@ HOUR
Definition: Common.h:30
@ DAY
Definition: Common.h:31
@ MONTH
Definition: Common.h:33
@ WEEK
Definition: Common.h:32
AccountTypes
Definition: Common.h:39
@ SEC_PLAYER
Definition: Common.h:40
#define sConditionMgr
Definition: ConditionMgr.h:365
@ CONDITION_SOURCE_TYPE_QUEST_AVAILABLE
Definition: ConditionMgr.h:173
@ CORPSE_RESURRECTABLE_PVE
Definition: Corpse.h:32
@ CORPSE_RESURRECTABLE_PVP
Definition: Corpse.h:33
@ CORPSE_FLAG_FFA_PVP
Definition: Corpse.h:49
@ CORPSE_FLAG_SKINNABLE
Definition: Corpse.h:48
@ CORPSE_FLAG_PVP
Definition: Corpse.h:45
const uint8 MAX_KILL_CREDIT
Definition: CreatureData.h:416
const uint32 MAX_CREATURE_SPELLS
Definition: CreatureData.h:419
DB2Storage< QuestFactionRewardEntry > sQuestFactionRewardStore("QuestFactionReward.db2", &QuestFactionRewardLoadInfo::Instance)
DB2Storage< ArtifactAppearanceEntry > sArtifactAppearanceStore("ArtifactAppearance.db2", &ArtifactAppearanceLoadInfo::Instance)
DB2Storage< ItemLimitCategoryEntry > sItemLimitCategoryStore("ItemLimitCategory.db2", &ItemLimitCategoryLoadInfo::Instance)
DB2Storage< DifficultyEntry > sDifficultyStore("Difficulty.db2", &DifficultyLoadInfo::Instance)
DB2Storage< ItemEntry > sItemStore("Item.db2", &ItemLoadInfo::Instance)
DB2Storage< SkillLineEntry > sSkillLineStore("SkillLine.db2", &SkillLineLoadInfo::Instance)
DB2Storage< FriendshipReputationEntry > sFriendshipReputationStore("FriendshipReputation.db2", &FriendshipReputationLoadInfo::Instance)
DB2Storage< ArtifactEntry > sArtifactStore("Artifact.db2", &ArtifactLoadInfo::Instance)
DB2Storage< PvpTalentCategoryEntry > sPvpTalentCategoryStore("PvpTalentCategory.db2", &PvpTalentCategoryLoadInfo::Instance)
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< TaxiNodesEntry > sTaxiNodesStore("TaxiNodes.db2", &TaxiNodesLoadInfo::Instance)
DB2Storage< ChrCustomizationOptionEntry > sChrCustomizationOptionStore("ChrCustomizationOption.db2", &ChrCustomizationOptionLoadInfo::Instance)
DB2Storage< ArtifactPowerEntry > sArtifactPowerStore("ArtifactPower.db2", &ArtifactPowerLoadInfo::Instance)
TaxiPathNodesByPath sTaxiPathNodesByPath
Definition: DB2Stores.cpp:383
DB2Storage< AzeriteItemMilestonePowerEntry > sAzeriteItemMilestonePowerStore("AzeriteItemMilestonePower.db2", &AzeriteItemMilestonePowerLoadInfo::Instance)
DB2Storage< TransmogIllusionEntry > sTransmogIllusionStore("TransmogIllusion.db2", &TransmogIllusionLoadInfo::Instance)
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< SpellShapeshiftFormEntry > sSpellShapeshiftFormStore("SpellShapeshiftForm.db2", &SpellShapeshiftFormLoadInfo::Instance)
DB2Storage< CharTitlesEntry > sCharTitlesStore("CharTitles.db2", &CharTitlesLoadInfo::Instance)
DB2Storage< ChrSpecializationEntry > sChrSpecializationStore("ChrSpecialization.db2", &ChrSpecializationLoadInfo::Instance)
DB2Storage< PowerTypeEntry > sPowerTypeStore("PowerType.db2", &PowerTypeLoadInfo::Instance)
DB2Storage< TraitNodeEntryEntry > sTraitNodeEntryStore("TraitNodeEntry.db2", &TraitNodeEntryLoadInfo::Instance)
DB2Storage< PvpTalentEntry > sPvpTalentStore("PvpTalent.db2", &PvpTalentLoadInfo::Instance)
DB2Storage< ChatChannelsEntry > sChatChannelsStore("ChatChannels.db2", &ChatChannelsLoadInfo::Instance)
DB2Storage< AreaTriggerEntry > sAreaTriggerStore("AreaTrigger.db2", &AreaTriggerLoadInfo::Instance)
DB2Storage< MailTemplateEntry > sMailTemplateStore("MailTemplate.db2", &MailTemplateLoadInfo::Instance)
DB2Storage< TraitDefinitionEntry > sTraitDefinitionStore("TraitDefinition.db2", &TraitDefinitionLoadInfo::Instance)
DB2Storage< BroadcastTextEntry > sBroadcastTextStore("BroadcastText.db2", &BroadcastTextLoadInfo::Instance)
DB2Storage< ItemExtendedCostEntry > sItemExtendedCostStore("ItemExtendedCost.db2", &ItemExtendedCostLoadInfo::Instance)
DB2Storage< CurrencyTypesEntry > sCurrencyTypesStore("CurrencyTypes.db2", &CurrencyTypesLoadInfo::Instance)
DB2Storage< TraitCurrencyEntry > sTraitCurrencyStore("TraitCurrency.db2", &TraitCurrencyLoadInfo::Instance)
DB2Storage< GemPropertiesEntry > sGemPropertiesStore("GemProperties.db2", &GemPropertiesLoadInfo::Instance)
DB2Storage< GlyphPropertiesEntry > sGlyphPropertiesStore("GlyphProperties.db2", &GlyphPropertiesLoadInfo::Instance)
DB2Storage< DungeonEncounterEntry > sDungeonEncounterStore("DungeonEncounter.db2", &DungeonEncounterLoadInfo::Instance)
DB2Storage< ChrRacesEntry > sChrRacesStore("ChrRaces.db2", &ChrRacesLoadInfo::Instance)
DB2Storage< PlayerConditionEntry > sPlayerConditionStore("PlayerCondition.db2", &PlayerConditionLoadInfo::Instance)
DB2Storage< ContentTuningEntry > sContentTuningStore("ContentTuning.db2", &ContentTuningLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore("SpellItemEnchantment.db2", &SpellItemEnchantmentLoadInfo::Instance)
DB2Storage< AzeritePowerEntry > sAzeritePowerStore("AzeritePower.db2", &AzeritePowerLoadInfo::Instance)
DB2Storage< TalentEntry > sTalentStore("Talent.db2", &TalentLoadInfo::Instance)
DB2Storage< FactionTemplateEntry > sFactionTemplateStore("FactionTemplate.db2", &FactionTemplateLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
DB2Storage< TaxiPathEntry > sTaxiPathStore("TaxiPath.db2", &TaxiPathLoadInfo::Instance)
DB2Storage< RewardPackEntry > sRewardPackStore("RewardPack.db2", &RewardPackLoadInfo::Instance)
DB2Storage< FactionEntry > sFactionStore("Faction.db2", &FactionLoadInfo::Instance)
DB2Storage< CinematicSequencesEntry > sCinematicSequencesStore("CinematicSequences.db2", &CinematicSequencesLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentConditionEntry > sSpellItemEnchantmentConditionStore("SpellItemEnchantmentCondition.db2", &SpellItemEnchantmentConditionLoadInfo::Instance)
std::vector< TaxiPathNodeEntry const * > TaxiPathNodeList
Definition: DB2Stores.h:332
#define sDB2Manager
Definition: DB2Stores.h:538
#define MAX_ITEM_EXT_COST_ITEMS
#define MAX_ITEM_EXT_COST_CURRENCIES
#define MAX_SPELL_REAGENTS
#define MAX_MASTERY_SPELLS
Definition: DB2Structure.h:854
#define MAX_ITEM_ENCHANTMENT_EFFECTS
@ ITEM_EXT_COST_FLAG_REQUIRE_GUILD
Definition: DBCEnums.h:1019
@ ITEM_EXT_COST_CURRENCY_REQ_IS_SEASON_EARNED_1
Definition: DBCEnums.h:1020
TraitConfigType
Definition: DBCEnums.h:2185
#define MAX_AZERITE_EMPOWERED_TIER
Definition: DBCEnums.h:200
@ DEFAULT_MAX_LEVEL
Definition: DBCEnums.h:47
@ MAX_LEVEL
Definition: DBCEnums.h:51
@ MAP_INSTANCE
Definition: DBCEnums.h:1229
@ MAP_RAID
Definition: DBCEnums.h:1230
@ SKILL_FLAG_ALWAYS_MAX_VALUE
Definition: DBCEnums.h:1910
@ ITEM_ENCHANTMENT_TYPE_BONUS_LIST_CURVE
Definition: DBCEnums.h:1013
@ ITEM_ENCHANTMENT_TYPE_DAMAGE
Definition: DBCEnums.h:1003
@ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_TYPE
Definition: DBCEnums.h:1010
@ ITEM_ENCHANTMENT_TYPE_USE_SPELL
Definition: DBCEnums.h:1008
@ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_BY_ID
Definition: DBCEnums.h:1011
@ ITEM_ENCHANTMENT_TYPE_BONUS_LIST_ID
Definition: DBCEnums.h:1012
@ ITEM_ENCHANTMENT_TYPE_COMBAT_SPELL
Definition: DBCEnums.h:1002
@ ITEM_ENCHANTMENT_TYPE_STAT
Definition: DBCEnums.h:1006
@ ITEM_ENCHANTMENT_TYPE_RESISTANCE
Definition: DBCEnums.h:1005
@ ITEM_ENCHANTMENT_TYPE_NONE
Definition: DBCEnums.h:1001
@ ITEM_ENCHANTMENT_TYPE_EQUIP_SPELL
Definition: DBCEnums.h:1004
@ ITEM_ENCHANTMENT_TYPE_TOTEM
Definition: DBCEnums.h:1007
@ ITEM_ENCHANTMENT_TYPE_ARTIFACT_POWER_BONUS_RANK_PICKER
Definition: DBCEnums.h:1014
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
Definition: DBCEnums.h:1009
Difficulty
Definition: DBCEnums.h:873
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
@ DIFFICULTY_NORMAL_RAID
Definition: DBCEnums.h:886
@ DIFFICULTY_NORMAL
Definition: DBCEnums.h:875
@ DIFFICULTY_10_N
Definition: DBCEnums.h:877
TraitCombatConfigFlags
Definition: DBCEnums.h:2157
@ ITEM_LIMIT_CATEGORY_MODE_HAVE
Definition: DBCEnums.h:1171
AzeriteItemMilestoneType
Definition: DBCEnums.h:206
@ LifestealDiminishing
@ AvoidanceDiminishing
@ VersatilityTakenDiminishing
@ VersatilityDoneDiminishing
@ SKILL_LINE_ABILITY_LEARNED_ON_SKILL_VALUE
Definition: DBCEnums.h:1895
@ SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN
Definition: DBCEnums.h:1896
@ SKILL_LINE_ABILITY_REWARDED_FROM_QUEST
Definition: DBCEnums.h:1897
@ DIFFICULTY_FLAG_CAN_SELECT
Definition: DBCEnums.h:918
@ DIFFICULTY_FLAG_LEGACY
Definition: DBCEnums.h:921
PlayerInteractionType
Definition: DBCEnums.h:1765
AreaFlags
Definition: DBCEnums.h:110
@ AllowTradeChannel
@ EnemiesPvPFlagged
@ NoGhostOnRelease
ItemContext
Definition: DBCEnums.h:1063
#define MAX_PVP_TALENT_SLOTS
Definition: DBCEnums.h:2134
#define MAX_TALENT_TIERS
Definition: DBCEnums.h:2132
ChrSpecialization
Definition: DBCEnums.h:357
CriteriaStartEvent
Definition: DBCEnums.h:470
#define MAX_TALENT_COLUMNS
Definition: DBCEnums.h:2133
@ UseSubzoneForChatChannel
@ AllowWarModeToggle
CriteriaFailEvent
Definition: DBCEnums.h:449
#define MAX_SPELL_EFFECTS
Definition: DBCEnums.h:1953
@ CURRENCY_TYPE_ANCIENT_MANA
Definition: DBCEnums.h:801
@ CURRENCY_TYPE_AZERITE
Definition: DBCEnums.h:802
@ CURRENCY_MAX_CAP_ANCIENT_MANA
Definition: DBCEnums.h:804
@ ARTIFACT_POWER_FLAG_SCALES_WITH_NUM_POWERS
Definition: DBCEnums.h:191
#define MAX_AZERITE_ESSENCE_SLOT
Definition: DBCEnums.h:202
#define MAX_ITEM_PROTO_STATS
Definition: DBCEnums.h:990
CriteriaType
Definition: DBCEnums.h:503
@ MoneyEarnedFromQuesting
@ CompleteAnyDailyQuestPerDay
@ LearnTradeskillSkillLine
@ MaxDistFallenWithoutDying
@ DeliverKillingBlowToClass
@ CompleteAnyReplayQuest
@ DeliverKillingBlowToRace
@ DieFromEnviromentalDamage
@ LearnSpellFromSkillLine
@ QUEST_PACKAGE_FILTER_EVERYONE
Definition: DBCEnums.h:1862
@ QUEST_PACKAGE_FILTER_CLASS
Definition: DBCEnums.h:1860
@ QUEST_PACKAGE_FILTER_LOOT_SPECIALIZATION
Definition: DBCEnums.h:1859
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
SQLTransaction< LoginDatabaseConnection > LoginDatabaseTransaction
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< LoginDatabaseConnection > LoginDatabase
Accessor to the realm/login database.
Definition: DatabaseEnv.cpp:22
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
#define UI64FMTD
Definition: Define.h:126
#define TC_GAME_API
Definition: Define.h:123
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
#define SI64LIT(N)
Definition: Define.h:130
int16_t int16
Definition: Define.h:139
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
#define UI64LIT(N)
Definition: Define.h:127
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
std::unordered_set< uint32 > params[2]
Definition: DisableMgr.cpp:50
uint16 flags
Definition: DisableMgr.cpp:49
@ DISABLE_TYPE_QUEST
Definition: DisableMgr.h:28
@ DISABLE_TYPE_MAP
Definition: DisableMgr.h:29
std::chrono::steady_clock::time_point TimePoint
time_point shorthand typedefs
Definition: Duration.h:41
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
@ EQUIPMENT_SET_CHANGED
Definition: EquipmentSet.h:29
@ EQUIPMENT_SET_UNCHANGED
Definition: EquipmentSet.h:28
@ EQUIPMENT_SET_DELETED
Definition: EquipmentSet.h:31
@ EQUIPMENT_SET_NEW
Definition: EquipmentSet.h:30
#define MAX_EQUIPMENT_SET_INDEX
Definition: EquipmentSet.h:67
#define ABORT_MSG
Definition: Errors.h:75
#define ABORT
Definition: Errors.h:74
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
bool IsHolidayActive(HolidayIds id)
#define sGameEventMgr
Definition: GameEventMgr.h:177
GameTable< GtSpellScalingEntry > sSpellScalingGameTable
Definition: GameTables.cpp:38
GameTable< GtStaminaMultByILvl > sStaminaMultByILvlGameTable
Definition: GameTables.cpp:39
float GetIlvlStatMultiplier(T const *row, InventoryType invType)
Definition: GameTables.cpp:149
GameTable< GtCombatRatingsEntry > sCombatRatingsGameTable
Definition: GameTables.cpp:33
GameTable< GtBarberShopCostBaseEntry > sBarberShopCostBaseGameTable
Definition: GameTables.cpp:30
GameTable< GtCombatRatingsMultByILvl > sCombatRatingsMultByILvlGameTable
Definition: GameTables.cpp:34
float GetSpellScalingColumnForClass(GtSpellScalingEntry const *row, int32 class_)
Definition: GameTables.h:246
#define DEFAULT_GOSSIP_MESSAGE
Definition: GossipDef.h:32
GossipOptionNpc
Definition: GossipDef.h:35
#define sGroupMgr
Definition: GroupMgr.h:61
@ GROUP_TYPE_NORMAL
Definition: Group.h:90
@ GROUP_UPDATE_FLAG_PET
Definition: Group.h:138
@ GROUP_UPDATE_FULL
Definition: Group.h:141
@ GROUP_UPDATE_FLAG_NONE
Definition: Group.h:121
@ GROUP_UPDATE_FLAG_POSITION
Definition: Group.h:135
@ GROUP_UPDATE_PET_FULL
Definition: Group.h:159
GroupCategory
Definition: Group.h:112
@ MAX_GROUP_CATEGORY
Definition: Group.h:116
#define sGuildMgr
Definition: GuildMgr.h:70
@ GUILD_COMMAND_VIEW_TAB
Definition: Guild.h:144
uint32 const MinNewsItemLevel
Definition: Guild.h:260
@ GUILD_NEWS_ITEM_LOOTED
Definition: Guild.h:243
@ GUILD_NEWS_ITEM_PURCHASED
Definition: Guild.h:245
@ GUILD_MEMBER_DATA_LEVEL
Definition: Guild.h:74
@ GUILD_MEMBER_DATA_ZONEID
Definition: Guild.h:72
std::chrono::system_clock::time_point InstanceResetTimePoint
#define sInstanceLockMgr
EnchantmentSlot
Definition: ItemDefines.h:178
@ PERM_ENCHANTMENT_SLOT
Definition: ItemDefines.h:179
@ SOCK_ENCHANTMENT_SLOT_3
Definition: ItemDefines.h:183
@ MAX_ENCHANTMENT_SLOT
Definition: ItemDefines.h:195
@ TEMP_ENCHANTMENT_SLOT
Definition: ItemDefines.h:180
@ SOCK_ENCHANTMENT_SLOT_2
Definition: ItemDefines.h:182
@ PRISMATIC_ENCHANTMENT_SLOT
Definition: ItemDefines.h:185
@ SOCK_ENCHANTMENT_SLOT
Definition: ItemDefines.h:181
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_BAG_FULL
Definition: ItemDefines.h:30
@ EQUIP_ERR_CANT_EQUIP_RANK
Definition: ItemDefines.h:90
@ EQUIP_ERR_TOO_MUCH_GOLD
Definition: ItemDefines.h:104
@ EQUIP_ERR_CANT_EQUIP_EVER
Definition: ItemDefines.h:36
@ EQUIP_ERR_REAGENT_BANK_FULL
Definition: ItemDefines.h:122
@ EQUIP_ERR_NO_SLOT_AVAILABLE
Definition: ItemDefines.h:35
@ EQUIP_ERR_CANT_BUY_QUANTITY
Definition: ItemDefines.h:120
@ EQUIP_ERR_ONLY_ONE_QUIVER
Definition: ItemDefines.h:60
@ EQUIP_ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED
Definition: ItemDefines.h:102
@ EQUIP_ERR_DESTROY_NONEMPTY_BAG
Definition: ItemDefines.h:58
@ EQUIP_ERR_SPLIT_FAILED
Definition: ItemDefines.h:53
@ EQUIP_ERR_REAGENT_BANK_LOCKED
Definition: ItemDefines.h:123
@ EQUIP_ERR_ITEM_UNIQUE_EQUIPPABLE
Definition: ItemDefines.h:94
@ EQUIP_ERR_NOT_DURING_ARENA_MATCH
Definition: ItemDefines.h:105
@ EQUIP_ERR_PLAYER_DEAD
Definition: ItemDefines.h:65
@ EQUIP_ERR_BAG_IN_BAG
Definition: ItemDefines.h:31
@ EQUIP_ERR_CLIENT_LOCKED_OUT
Definition: ItemDefines.h:66
@ EQUIP_ERR_BANK_FULL
Definition: ItemDefines.h:78
@ EQUIP_ERR_NOT_IN_COMBAT
Definition: ItemDefines.h:87
@ EQUIP_ERR_ITEM_LOCKED
Definition: ItemDefines.h:63
@ EQUIP_ERR_ITEM_COOLDOWN
Definition: ItemDefines.h:137
@ EQUIP_ERR_CANT_EQUIP_LEVEL_I
Definition: ItemDefines.h:27
@ EQUIP_ERR_GENERIC_STUNNED
Definition: ItemDefines.h:64
@ EQUIP_ERR_WRONG_SLOT
Definition: ItemDefines.h:29
@ EQUIP_ERR_WRONG_BAG_TYPE
Definition: ItemDefines.h:41
@ EQUIP_ERR_PROFICIENCY_NEEDED
Definition: ItemDefines.h:34
@ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS
Definition: ItemDefines.h:111
@ EQUIP_ERR_EVENT_AUTOEQUIP_BIND_CONFIRM
Definition: ItemDefines.h:108
@ EQUIP_ERR_NO_BANK_SLOT
Definition: ItemDefines.h:61
@ EQUIP_ERR_PURCHASE_LEVEL_TOO_LOW
Definition: ItemDefines.h:114
@ EQUIP_ERR_ITEM_NOT_FOUND
Definition: ItemDefines.h:49
@ EQUIP_ERR_CANT_EQUIP_REPUTATION
Definition: ItemDefines.h:91
@ EQUIP_ERR_WRONG_BAG_TYPE_3
Definition: ItemDefines.h:124
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
@ EQUIP_ERR_LOOT_GONE
Definition: ItemDefines.h:76
@ EQUIP_ERR_CANT_SWAP
Definition: ItemDefines.h:47
@ EQUIP_ERR_NOT_OWNER
Definition: ItemDefines.h:59
@ EQUIP_ERR_CANT_EQUIP_SKILL
Definition: ItemDefines.h:28
@ EQUIP_ERR_2HANDED_EQUIPPED
Definition: ItemDefines.h:39
@ EQUIP_ERR_INV_FULL
Definition: ItemDefines.h:77
@ EQUIP_ERR_CANT_USE_ITEM
Definition: ItemDefines.h:125
@ EQUIP_ERR_INTERNAL_BAG_ERROR
Definition: ItemDefines.h:67
@ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS
Definition: ItemDefines.h:116
@ EQUIP_ERR_NOT_EQUIPPABLE
Definition: ItemDefines.h:46
@ EQUIP_ERR_VENDOR_MISSING_TURNINS
Definition: ItemDefines.h:95
@ EQUIP_ERR_2HSKILLNOTFOUND
Definition: ItemDefines.h:40
@ EQUIP_ERR_ONLY_ONE_AMMO
Definition: ItemDefines.h:69
@ EQUIP_ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS
Definition: ItemDefines.h:112
@ EQUIP_ERR_ITEM_MAX_COUNT
Definition: ItemDefines.h:43
@ EQUIP_ERR_TOO_FEW_TO_SPLIT
Definition: ItemDefines.h:52
BuyResult
Definition: ItemDefines.h:149
@ BUY_ERR_CANT_FIND_ITEM
Definition: ItemDefines.h:150
@ BUY_ERR_DISTANCE_TOO_FAR
Definition: ItemDefines.h:154
@ BUY_ERR_NOT_ENOUGHT_MONEY
Definition: ItemDefines.h:152
@ BUY_ERR_REPUTATION_REQUIRE
Definition: ItemDefines.h:158
@ BUY_ERR_ITEM_ALREADY_SOLD
Definition: ItemDefines.h:151
@ ITEM_MODIFIER_ARTIFACT_APPEARANCE_ID
Definition: ItemDefines.h:219
@ ITEM_MODIFIER_BATTLE_PET_BREED_DATA
Definition: ItemDefines.h:215
@ ITEM_MODIFIER_BATTLE_PET_SPECIES_ID
Definition: ItemDefines.h:214
@ ITEM_MODIFIER_BATTLE_PET_LEVEL
Definition: ItemDefines.h:216
SellResult
Definition: ItemDefines.h:163
@ ITEM_VENDOR_TYPE_CURRENCY
Definition: ItemDefines.h:204
ItemRandomBonusListId GenerateItemRandomBonusListId(uint32 item_id)
uint32 ItemRandomBonusListId
ItemClass
Definition: ItemTemplate.h:419
@ ITEM_CLASS_QUIVER
Definition: ItemTemplate.h:431
@ ITEM_CLASS_PROFESSION
Definition: ItemTemplate.h:439
@ ITEM_CLASS_CONTAINER
Definition: ItemTemplate.h:421
@ ITEM_CLASS_ARMOR
Definition: ItemTemplate.h:424
@ ITEM_CLASS_WEAPON
Definition: ItemTemplate.h:422
@ ITEM_CLASS_CONSUMABLE
Definition: ItemTemplate.h:420
@ ITEM_FLAG2_INTERNAL_ITEM
Definition: ItemTemplate.h:223
@ ITEM_FLAG2_FACTION_HORDE
Definition: ItemTemplate.h:212
@ ITEM_FLAG2_FACTION_ALLIANCE
Definition: ItemTemplate.h:213
@ ITEM_SUBCLASS_WEAPON_WAND
Definition: ItemTemplate.h:499
@ ITEM_SUBCLASS_WEAPON_POLEARM
Definition: ItemTemplate.h:486
@ ITEM_FIELD_FLAG_NEW_ITEM
Definition: ItemTemplate.h:152
@ ITEM_FIELD_FLAG_REFUNDABLE
Definition: ItemTemplate.h:143
@ ITEM_FIELD_FLAG_CHILD
Definition: ItemTemplate.h:150
@ ITEM_FIELD_FLAG_BOP_TRADEABLE
Definition: ItemTemplate.h:139
@ ITEM_SPELLTRIGGER_ON_USE
Definition: ItemTemplate.h:104
@ ITEM_SPELLTRIGGER_ON_LOOTED
Definition: ItemTemplate.h:111
@ ITEM_SPELLTRIGGER_ON_PROC
Definition: ItemTemplate.h:106
@ ITEM_SPELLTRIGGER_ON_PICKUP
Definition: ItemTemplate.h:109
@ ITEM_SPELLTRIGGER_ON_EQUIP
Definition: ItemTemplate.h:105
@ ITEM_SUBCLASS_CONTAINER
Definition: ItemTemplate.h:462
@ ITEM_SUBCLASS_AMMO_POUCH
Definition: ItemTemplate.h:642
@ ITEM_FLAG_REAL_DURATION
Definition: ItemTemplate.h:192
@ ITEM_FLAG_LEGACY
Definition: ItemTemplate.h:184
@ ITEM_FLAG_IGNORE_DEFAULT_ARENA_RESTRICTIONS
Definition: ItemTemplate.h:197
@ ITEM_FLAG_HAS_LOOT
Definition: ItemTemplate.h:178
@ ITEM_FLAG_NO_EQUIP_COOLDOWN
Definition: ItemTemplate.h:183
@ ITEM_FLAG_UNIQUE_EQUIPPABLE
Definition: ItemTemplate.h:195
@ ITEM_FLAG_ITEM_PURCHASE_RECORD
Definition: ItemTemplate.h:188
@ ITEM_FLAG_NOT_USEABLE_IN_ARENA
Definition: ItemTemplate.h:202
@ ITEM_FLAG_CONJURED
Definition: ItemTemplate.h:177
@ ITEM_FLAG3_DONT_REPORT_LOOT_LOG_TO_PARTY
Definition: ItemTemplate.h:266
@ ITEM_FLAG3_ALWAYS_ALLOW_DUAL_WIELD
Definition: ItemTemplate.h:267
@ ITEM_SUBCLASS_PROFESSION_ENCHANTING
Definition: ItemTemplate.h:726
@ ITEM_SUBCLASS_PROFESSION_ALCHEMY
Definition: ItemTemplate.h:720
@ ITEM_SUBCLASS_PROFESSION_INSCRIPTION
Definition: ItemTemplate.h:730
@ ITEM_SUBCLASS_PROFESSION_ENGINEERING
Definition: ItemTemplate.h:725
@ ITEM_SUBCLASS_PROFESSION_BLACKSMITHING
Definition: ItemTemplate.h:718
@ ITEM_SUBCLASS_PROFESSION_LEATHERWORKING
Definition: ItemTemplate.h:719
@ ITEM_SUBCLASS_PROFESSION_JEWELCRAFTING
Definition: ItemTemplate.h:729
@ ITEM_SUBCLASS_PROFESSION_SKINNING
Definition: ItemTemplate.h:728
@ ITEM_SUBCLASS_PROFESSION_TAILORING
Definition: ItemTemplate.h:724
@ ITEM_SUBCLASS_PROFESSION_FISHING
Definition: ItemTemplate.h:727
@ ITEM_SUBCLASS_PROFESSION_HERBALISM
Definition: ItemTemplate.h:721
@ ITEM_SUBCLASS_PROFESSION_MINING
Definition: ItemTemplate.h:723
@ ITEM_SUBCLASS_PROFESSION_COOKING
Definition: ItemTemplate.h:722
@ ITEM_MOD_HOLY_RESISTANCE
Definition: ItemTemplate.h:78
@ ITEM_MOD_CRIT_TAKEN_RANGED_RATING
Definition: ItemTemplate.h:51
@ ITEM_MOD_AGI_STR_INT
Definition: ItemTemplate.h:96
@ ITEM_MOD_CORRUPTION_RESISTANCE
Definition: ItemTemplate.h:48
@ ITEM_MOD_CR_AVOIDANCE
Definition: ItemTemplate.h:88
@ ITEM_MOD_AGI_INT
Definition: ItemTemplate.h:98
@ ITEM_MOD_NATURE_RESISTANCE
Definition: ItemTemplate.h:80
@ ITEM_MOD_HIT_MELEE_RATING
Definition: ItemTemplate.h:41
@ ITEM_MOD_MASTERY_RATING
Definition: ItemTemplate.h:74
@ ITEM_MOD_STAMINA
Definition: ItemTemplate.h:36
@ ITEM_MOD_HIT_SPELL_RATING
Definition: ItemTemplate.h:43
@ ITEM_MOD_CR_STURDINESS
Definition: ItemTemplate.h:89
@ ITEM_MOD_SPELL_PENETRATION
Definition: ItemTemplate.h:72
@ ITEM_MOD_STR_INT
Definition: ItemTemplate.h:99
@ ITEM_MOD_PARRY_RATING
Definition: ItemTemplate.h:39
@ ITEM_MOD_DEFENSE_SKILL_RATING
Definition: ItemTemplate.h:37
@ ITEM_MOD_HASTE_RANGED_RATING
Definition: ItemTemplate.h:54
@ ITEM_MOD_EXPERTISE_RATING
Definition: ItemTemplate.h:62
@ ITEM_MOD_MANA
Definition: ItemTemplate.h:30
@ ITEM_MOD_RANGED_ATTACK_POWER
Definition: ItemTemplate.h:64
@ ITEM_MOD_HEALTH
Definition: ItemTemplate.h:31
@ ITEM_MOD_CR_LIFESTEAL
Definition: ItemTemplate.h:87
@ ITEM_MOD_VERSATILITY
Definition: ItemTemplate.h:65
@ ITEM_MOD_FROST_RESISTANCE
Definition: ItemTemplate.h:77
@ ITEM_MOD_SPELL_POWER
Definition: ItemTemplate.h:70
@ ITEM_MOD_SHADOW_RESISTANCE
Definition: ItemTemplate.h:79
@ ITEM_MOD_EXTRA_ARMOR
Definition: ItemTemplate.h:75
@ ITEM_MOD_HASTE_SPELL_RATING
Definition: ItemTemplate.h:55
@ ITEM_MOD_ATTACK_POWER
Definition: ItemTemplate.h:63
@ ITEM_MOD_FIRE_RESISTANCE
Definition: ItemTemplate.h:76
@ ITEM_MOD_HASTE_RATING
Definition: ItemTemplate.h:61
@ ITEM_MOD_HIT_RANGED_RATING
Definition: ItemTemplate.h:42
@ ITEM_MOD_CRIT_SPELL_RATING
Definition: ItemTemplate.h:46
@ ITEM_MOD_BLOCK_VALUE
Definition: ItemTemplate.h:73
@ ITEM_MOD_CRIT_RANGED_RATING
Definition: ItemTemplate.h:45
@ ITEM_MOD_CRIT_MELEE_RATING
Definition: ItemTemplate.h:44
@ ITEM_MOD_STRENGTH
Definition: ItemTemplate.h:33
@ ITEM_MOD_HEALTH_REGEN
Definition: ItemTemplate.h:71
@ ITEM_MOD_BLOCK_RATING
Definition: ItemTemplate.h:40
@ ITEM_MOD_PVP_POWER
Definition: ItemTemplate.h:82
@ ITEM_MOD_ARMOR_PENETRATION_RATING
Definition: ItemTemplate.h:69
@ ITEM_MOD_ARCANE_RESISTANCE
Definition: ItemTemplate.h:81
@ ITEM_MOD_HASTE_MELEE_RATING
Definition: ItemTemplate.h:53
@ ITEM_MOD_CORRUPTION
Definition: ItemTemplate.h:47
@ ITEM_MOD_MANA_REGENERATION
Definition: ItemTemplate.h:68
@ ITEM_MOD_HIT_RATING
Definition: ItemTemplate.h:56
@ ITEM_MOD_INTELLECT
Definition: ItemTemplate.h:34
@ ITEM_MOD_RESILIENCE_RATING
Definition: ItemTemplate.h:60
@ ITEM_MOD_AGILITY
Definition: ItemTemplate.h:32
@ ITEM_MOD_DODGE_RATING
Definition: ItemTemplate.h:38
@ ITEM_MOD_CRIT_RATING
Definition: ItemTemplate.h:57
@ ITEM_MOD_AGI_STR
Definition: ItemTemplate.h:97
@ ITEM_MOD_CR_SPEED
Definition: ItemTemplate.h:86
@ ITEM_SUBCLASS_ARMOR_SHIELD
Definition: ItemTemplate.h:535
@ BIND_QUEST
Definition: ItemTemplate.h:120
@ BIND_ON_USE
Definition: ItemTemplate.h:119
@ BIND_ON_EQUIP
Definition: ItemTemplate.h:118
@ BIND_NONE
Definition: ItemTemplate.h:116
@ BIND_ON_ACQUIRE
Definition: ItemTemplate.h:117
@ ITEM_FIELD_FLAG2_EQUIPPED
Definition: ItemTemplate.h:169
InventoryType
Definition: ItemTemplate.h:378
@ INVTYPE_BODY
Definition: ItemTemplate.h:383
@ INVTYPE_FINGER
Definition: ItemTemplate.h:390
@ INVTYPE_HEAD
Definition: ItemTemplate.h:380
@ INVTYPE_CLOAK
Definition: ItemTemplate.h:395
@ INVTYPE_ROBE
Definition: ItemTemplate.h:399
@ INVTYPE_HOLDABLE
Definition: ItemTemplate.h:402
@ INVTYPE_TRINKET
Definition: ItemTemplate.h:391
@ INVTYPE_RELIC
Definition: ItemTemplate.h:407
@ INVTYPE_PROFESSION_TOOL
Definition: ItemTemplate.h:408
@ INVTYPE_RANGED
Definition: ItemTemplate.h:394
@ INVTYPE_THROWN
Definition: ItemTemplate.h:404
@ INVTYPE_WAIST
Definition: ItemTemplate.h:385
@ INVTYPE_RANGEDRIGHT
Definition: ItemTemplate.h:405
@ INVTYPE_WRISTS
Definition: ItemTemplate.h:388
@ INVTYPE_WEAPON
Definition: ItemTemplate.h:392
@ INVTYPE_WEAPONMAINHAND
Definition: ItemTemplate.h:400
@ INVTYPE_WEAPONOFFHAND
Definition: ItemTemplate.h:401
@ INVTYPE_2HWEAPON
Definition: ItemTemplate.h:396
@ INVTYPE_BAG
Definition: ItemTemplate.h:397
@ INVTYPE_NECK
Definition: ItemTemplate.h:381
@ INVTYPE_SHOULDERS
Definition: ItemTemplate.h:382
@ INVTYPE_FEET
Definition: ItemTemplate.h:387
@ INVTYPE_NON_EQUIP
Definition: ItemTemplate.h:379
@ INVTYPE_AMMO
Definition: ItemTemplate.h:403
@ INVTYPE_QUIVER
Definition: ItemTemplate.h:406
@ INVTYPE_SHIELD
Definition: ItemTemplate.h:393
@ INVTYPE_TABARD
Definition: ItemTemplate.h:398
@ INVTYPE_LEGS
Definition: ItemTemplate.h:386
@ INVTYPE_CHEST
Definition: ItemTemplate.h:384
@ INVTYPE_HANDS
Definition: ItemTemplate.h:389
@ INVTYPE_PROFESSION_GEAR
Definition: ItemTemplate.h:409
void RemoveItemsSetItem(Player *player, Item const *item)
Definition: Item.cpp:155
bool ItemCanGoIntoBag(ItemTemplate const *pProto, ItemTemplate const *pBagProto)
Definition: Item.cpp:208
Item * NewItemOrBag(ItemTemplate const *proto)
Definition: Item.cpp:52
void AddItemsSetItem(Player *player, Item const *item)
Definition: Item.cpp:66
@ ITEM_CHANGED
Definition: Item.h:55
@ ITEM_REMOVED
Definition: Item.h:57
@ ITEM_NEW
Definition: Item.h:56
@ ITEM_UNCHANGED
Definition: Item.h:54
#define sLFGMgr
Definition: LFGMgr.h:507
#define sLanguageMgr
Definition: LanguageMgr.h:97
@ LANG_NOT_EQUIPPED_ITEM
Definition: Language.h:695
@ LANG_PLAYER_DND
Definition: Language.h:696
@ LANG_LEVEL_MINREQUIRED_AND_ITEM
Definition: Language.h:82
@ LANG_PLAYER_AFK
Definition: Language.h:697
@ LANG_COMMAND_WHISPERON
Definition: Language.h:337
@ LANG_INSTANCE_LOGIN_GAMEMASTER_EXCEPTION
Definition: Language.h:1231
@ LANG_LEVEL_MINREQUIRED
Definition: Language.h:81
@ LOG_LEVEL_DEBUG
Definition: LogCommon.h:28
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sLog
Definition: Log.h:130
#define TC_LOG_INFO(filterType__,...)
Definition: Log.h:159
#define TC_LOG_FATAL(filterType__,...)
Definition: Log.h:168
@ LOGIN_DEL_BATTLE_PETS_BY_OWNER
@ LOGIN_UPD_MUTE_TIME
Definition: LoginDatabase.h:67
@ LOGIN_INS_BNET_LAST_PLAYER_CHARACTERS
@ LOGIN_DEL_BATTLE_PET_DECLINED_NAME_BY_OWNER
@ LOGIN_DEL_BNET_LAST_PLAYER_CHARACTERS
#define sLootItemStorage
LootItemType
Definition: LootItemType.h:24
LootStore LootTemplates_Creature("creature_loot_template", "creature entry", true)
@ LOOT_CORPSE
Definition: Loot.h:101
@ LOOT_INSIGNIA
Definition: Loot.h:112
@ LOOT_NONE
Definition: Loot.h:99
@ LOOT_ITEM
Definition: Loot.h:105
@ PERSONAL_LOOT
Definition: Loot.h:94
@ NEED_BEFORE_GREED
Definition: Loot.h:93
@ GROUP_LOOT
Definition: Loot.h:92
@ MASTER_LOOT
Definition: Loot.h:91
@ ROUND_ROBIN
Definition: Loot.h:90
@ FREE_FOR_ALL
Definition: Loot.h:89
constexpr LootType GetLootTypeForClient(LootType lootType)
Definition: Loot.h:118
LootError
Definition: Loot.h:137
@ MAIL_CHECK_MASK_HAS_BODY
Definition: Mail.h:57
@ MAIL_CHECK_MASK_READ
Definition: Mail.h:53
@ MAIL_CHECK_MASK_COPIED
This mail was returned. Do not allow returning mail back again.
Definition: Mail.h:55
@ MAIL_STATE_DELETED
Definition: Mail.h:76
@ MAIL_STATE_CHANGED
Definition: Mail.h:75
@ MAIL_STATE_UNCHANGED
Definition: Mail.h:74
#define MAX_MAIL_ITEMS
Definition: Mail.h:35
@ MAIL_STATIONERY_GM
Definition: Mail.h:65
@ MAIL_CREATURE
Definition: Mail.h:41
@ MAIL_NORMAL
Definition: Mail.h:39
#define MAP_LIQUID_STATUS_IN_CONTACT
Definition: MapDefines.h:135
ZLiquidStatus
Definition: MapDefines.h:125
@ LIQUID_MAP_UNDER_WATER
Definition: MapDefines.h:130
#define sMapMgr
Definition: MapManager.h:184
InstanceResetMethod
Definition: Map.h:845
TransferAbortReason
Definition: Map.h:86
@ TRANSFER_ABORT_DIFFICULTY
Definition: Map.h:94
@ TRANSFER_ABORT_UNIQUE_MESSAGE
Definition: Map.h:95
@ TRANSFER_ABORT_MAP_NOT_ALLOWED
Definition: Map.h:102
@ TRANSFER_ABORT_INSUF_EXPAN_LVL
Definition: Map.h:93
@ TRANSFER_ABORT_ERROR
Definition: Map.h:88
@ FLIGHT_MOTION_TYPE
@ EFFECT_MOTION_TYPE
#define DEFAULT_PLAYER_COMBAT_REACH
Definition: ObjectDefines.h:40
#define DEFAULT_PLAYER_BOUNDING_RADIUS
Definition: ObjectDefines.h:39
@ NOTIFY_VISIBILITY_CHANGED
Definition: ObjectDefines.h:77
std::unordered_set< ObjectGuid > GuidUnorderedSet
Definition: ObjectGuid.h:396
@ TYPEID_AZERITE_ITEM
Definition: ObjectGuid.h:39
@ TYPEID_OBJECT
Definition: ObjectGuid.h:35
@ TYPEID_AREATRIGGER
Definition: ObjectGuid.h:46
@ TYPEID_ACTIVE_PLAYER
Definition: ObjectGuid.h:42
@ TYPEID_DYNAMICOBJECT
Definition: ObjectGuid.h:44
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_CORPSE
Definition: ObjectGuid.h:45
@ TYPEID_ITEM
Definition: ObjectGuid.h:36
@ TYPEID_SCENEOBJECT
Definition: ObjectGuid.h:47
@ TYPEID_CONVERSATION
Definition: ObjectGuid.h:48
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
@ TYPEID_AZERITE_EMPOWERED_ITEM
Definition: ObjectGuid.h:38
@ TYPEID_CONTAINER
Definition: ObjectGuid.h:37
std::set< ObjectGuid > GuidSet
Definition: ObjectGuid.h:393
@ TYPEMASK_SEER
Definition: ObjectGuid.h:70
@ TYPEMASK_PLAYER
Definition: ObjectGuid.h:61
SkillRangeType GetSkillRangeType(SkillRaceClassInfoEntry const *rcEntry)
Definition: ObjectMgr.cpp:8986
#define sObjectMgr
Definition: ObjectMgr.h:1946
std::pair< GossipMenusContainer::const_iterator, GossipMenusContainer::const_iterator > GossipMenusMapBounds
Definition: ObjectMgr.h:776
PlayerCreateMode
Definition: ObjectMgr.h:613
@ SKILL_RANGE_MONO
Definition: ObjectMgr.h:963
@ SKILL_RANGE_LANGUAGE
Definition: ObjectMgr.h:961
@ SKILL_RANGE_RANK
Definition: ObjectMgr.h:964
@ SKILL_RANGE_LEVEL
Definition: ObjectMgr.h:962
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
#define sOutdoorPvPMgr
@ PETSPELL_REMOVED
Definition: PetDefines.h:72
constexpr bool IsStabledPetSlot(PetSaveMode slot)
Definition: PetDefines.h:56
#define PET_FOLLOW_DIST
Definition: PetDefines.h:97
PetTameResult
Definition: PetDefines.h:101
constexpr bool IsActivePetSlot(PetSaveMode slot)
Definition: PetDefines.h:51
PetType
Definition: PetDefines.h:30
@ SUMMON_PET
Definition: PetDefines.h:31
@ HUNTER_PET
Definition: PetDefines.h:32
PetStableFlags
Definition: PetDefines.h:62
@ PET_STABLE_INACTIVE
Definition: PetDefines.h:64
@ PET_STABLE_ACTIVE
Definition: PetDefines.h:63
PetSaveMode
Definition: PetDefines.h:41
@ PET_SAVE_FIRST_STABLE_SLOT
Definition: PetDefines.h:46
@ PET_SAVE_LAST_STABLE_SLOT
Definition: PetDefines.h:47
@ PET_SAVE_LAST_ACTIVE_SLOT
Definition: PetDefines.h:45
@ PET_SAVE_FIRST_ACTIVE_SLOT
Definition: PetDefines.h:44
@ PET_SAVE_AS_DELETED
Definition: PetDefines.h:42
@ PET_SAVE_NOT_IN_SLOT
Definition: PetDefines.h:48
@ PET_SAVE_AS_CURRENT
Definition: PetDefines.h:43
#define sPetitionMgr
Definition: PetitionMgr.h:87
float GetGameTableColumnForCombatRating(GtCombatRatingsEntry const *row, uint32 rating)
Definition: Player.cpp:5198
static bool ForEachEquipmentSlot(InventoryType inventoryType, bool canDualWield, bool canTitanGrip, T callback)
Definition: Player.cpp:29896
PlayerSpells
Definition: Player.cpp:150
@ SPELL_EXPERIENCE_ELIMINATED
Definition: Player.cpp:151
@ SPELL_JOURNEYMAN_RIDING
Definition: Player.cpp:153
@ SPELL_APPRENTICE_RIDING
Definition: Player.cpp:152
#define DEATH_EXPIRE_STEP
Definition: Player.cpp:146
void BeforeVisibilityDestroy< Creature >(Creature *t, Player *p)
Definition: Player.cpp:23803
int SkillGainChance(uint32 SkillValue, uint32 GrayLevel, uint32 GreenLevel, uint32 YellowLevel)
Definition: Player.cpp:5530
void SavePlayerCustomizations(CharacterDatabaseTransaction trans, ObjectGuid::LowType guid, Trinity::IteratorPair< iterator > customizations)
Definition: Player.cpp:20376
void BeforeVisibilityDestroy< GameObject >(GameObject *t, Player *p)
Definition: Player.cpp:23834
void BeforeVisibilityDestroy(T *, Player *)
Definition: Player.cpp:23800
static constexpr Milliseconds SPELL_QUEUE_TIME_WINDOW
Definition: Player.cpp:30253
#define REMOVE_VIOLATING_FLAGS(check, maskToRemove)
#define MAX_DEATH_COUNT
Definition: Player.cpp:147
void BeforeVisibilityDestroy< Player >(Player *t, Player *p)
Definition: Player.cpp:23820
uint64 const MAX_MONEY_AMOUNT
Definition: Player.cpp:158
static uint32 copseReclaimDelay[MAX_DEATH_COUNT]
Definition: Player.cpp:156
uint8 GetFishingStepsNeededToLevelUp(uint32 SkillValue)
Definition: Player.cpp:5622
#define ZONE_UPDATE_INTERVAL
Definition: Player.cpp:143
void DeleteSpellFromAllPlayers(uint32 spellId)
Definition: Player.cpp:2681
EquipmentSlots
Definition: Player.h:629
@ EQUIPMENT_SLOT_SHOULDERS
Definition: Player.h:633
@ EQUIPMENT_SLOT_BODY
Definition: Player.h:634
@ EQUIPMENT_SLOT_HANDS
Definition: Player.h:640
@ EQUIPMENT_SLOT_FINGER1
Definition: Player.h:641
@ EQUIPMENT_SLOT_NECK
Definition: Player.h:632
@ EQUIPMENT_SLOT_FINGER2
Definition: Player.h:642
@ EQUIPMENT_SLOT_MAINHAND
Definition: Player.h:646
@ EQUIPMENT_SLOT_TABARD
Definition: Player.h:649
@ EQUIPMENT_SLOT_TRINKET1
Definition: Player.h:643
@ EQUIPMENT_SLOT_END
Definition: Player.h:650
@ EQUIPMENT_SLOT_HEAD
Definition: Player.h:631
@ EQUIPMENT_SLOT_LEGS
Definition: Player.h:637
@ EQUIPMENT_SLOT_BACK
Definition: Player.h:645
@ EQUIPMENT_SLOT_OFFHAND
Definition: Player.h:647
@ EQUIPMENT_SLOT_WAIST
Definition: Player.h:636
@ EQUIPMENT_SLOT_FEET
Definition: Player.h:638
@ EQUIPMENT_SLOT_CHEST
Definition: Player.h:635
@ EQUIPMENT_SLOT_WRISTS
Definition: Player.h:639
@ EQUIPMENT_SLOT_TRINKET2
Definition: Player.h:644
@ EQUIPMENT_SLOT_START
Definition: Player.h:630
@ EQUIPMENT_SLOT_RANGED
Definition: Player.h:648
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
ArenaTeamInfoType
Definition: Player.h:788
@ ARENA_TEAM_GAMES_WEEK
Definition: Player.h:792
@ ARENA_TEAM_TYPE
Definition: Player.h:790
@ ARENA_TEAM_ID
Definition: Player.h:789
@ ARENA_TEAM_PERSONAL_RATING
Definition: Player.h:795
@ ARENA_TEAM_MEMBER
Definition: Player.h:791
@ ARENA_TEAM_WINS_SEASON
Definition: Player.h:794
@ ARENA_TEAM_GAMES_SEASON
Definition: Player.h:793
EnviromentalDamage
Type of environmental damages.
Definition: Player.h:816
@ DAMAGE_SLIME
Definition: Player.h:821
@ DAMAGE_FALL
Definition: Player.h:819
@ DAMAGE_LAVA
Definition: Player.h:820
@ DAMAGE_FALL_TO_VOID
Definition: Player.h:823
@ DAMAGE_DROWNING
Definition: Player.h:818
@ DAMAGE_EXHAUSTED
Definition: Player.h:817
@ REAGENT_SLOT_START
Definition: Player.h:712
@ REAGENT_SLOT_END
Definition: Player.h:713
uint32 constexpr PLAYER_MAX_HONOR_LEVEL
Definition: Player.h:1094
@ INVENTORY_SLOT_BAG_START
Definition: Player.h:675
@ INVENTORY_SLOT_BAG_END
Definition: Player.h:676
TeleportToOptions
Definition: Player.h:800
@ TELE_TO_SEAMLESS
Definition: Player.h:809
@ TELE_TO_SPELL
Definition: Player.h:806
@ TELE_TO_NOT_LEAVE_COMBAT
Definition: Player.h:804
@ TELE_TO_NOT_UNSUMMON_PET
Definition: Player.h:805
@ TELE_REVIVE_AT_TELEPORT
Definition: Player.h:808
@ TELE_TO_NONE
Definition: Player.h:801
@ TELE_TO_NOT_LEAVE_TRANSPORT
Definition: Player.h:803
std::array< uint32, MAX_PVP_TALENT_SLOTS > PlayerPvpTalentMap
Definition: Player.h:275
@ PLAYERCURRENCY_CHANGED
Definition: Player.h:258
@ PLAYERCURRENCY_UNCHANGED
Definition: Player.h:257
@ PLAYERCURRENCY_NEW
Definition: Player.h:259
@ DUEL_STATE_CHALLENGED
Definition: Player.h:357
@ DUEL_STATE_COUNTDOWN
Definition: Player.h:358
@ DUEL_STATE_COMPLETED
Definition: Player.h:360
@ DUEL_STATE_IN_PROGRESS
Definition: Player.h:359
#define MAX_RUNES
Definition: Player.h:384
@ QUEST_STATE_COMPLETE
Definition: Player.h:586
@ QUEST_STATE_FAIL
Definition: Player.h:587
@ PLAYER_EXTRA_GM_ON
Definition: Player.h:519
@ PLAYER_EXTRA_ACCEPT_WHISPERS
Definition: Player.h:520
@ PLAYER_EXTRA_GM_INVISIBLE
Definition: Player.h:522
@ PLAYER_EXTRA_PVP_DEATH
Definition: Player.h:526
@ PLAYER_EXTRA_GM_CHAT
Definition: Player.h:523
std::unordered_map< uint32, PlayerSpell > PlayerSpellMap
Definition: Player.h:276
PlayerFlags
Definition: Player.h:427
@ PLAYER_FLAGS_WAR_MODE_ACTIVE
Definition: Player.h:438
@ PLAYER_FLAGS_DND
Definition: Player.h:430
@ PLAYER_FLAGS_IN_PVP
Definition: Player.h:437
@ PLAYER_FLAGS_CONTESTED_PVP
Definition: Player.h:436
@ PLAYER_FLAGS_NO_XP_GAIN
Definition: Player.h:453
@ PLAYER_FLAGS_GUILD_LEVEL_ENABLED
Definition: Player.h:456
@ PLAYER_FLAGS_GROUP_LEADER
Definition: Player.h:428
@ PLAYER_FLAGS_RESTING
Definition: Player.h:433
@ PLAYER_FLAGS_IS_OUT_OF_BOUNDS
Definition: Player.h:442
@ PLAYER_FLAGS_WAR_MODE_DESIRED
Definition: Player.h:439
@ PLAYER_FLAGS_GHOST
Definition: Player.h:432
@ PLAYER_FLAGS_AFK
Definition: Player.h:429
@ PLAYER_FLAGS_GM
Definition: Player.h:431
@ PLAYER_FLAGS_PVP_TIMER
Definition: Player.h:446
uint8 constexpr PLAYER_LEVEL_MIN_HONOR
Definition: Player.h:1095
@ ACTIONBUTTON_NEW
Definition: Player.h:286
@ ACTIONBUTTON_UNCHANGED
Definition: Player.h:284
@ ACTIONBUTTON_DELETED
Definition: Player.h:287
@ ACTIONBUTTON_CHANGED
Definition: Player.h:285
@ SPELLMOD_LABEL_PCT
Definition: Player.h:160
@ SPELLMOD_FLAT
Definition: Player.h:157
@ SPELLMOD_PCT
Definition: Player.h:158
@ SPELLMOD_LABEL_FLAT
Definition: Player.h:159
@ RUNE_BASE_COOLDOWN
Definition: Player.h:389
DisplayToastType
Definition: Player.h:963
@ INVENTORY_SLOT_ITEM_START
Definition: Player.h:687
@ INVENTORY_SLOT_ITEM_END
Definition: Player.h:688
@ CHEAT_POWER
Definition: Player.h:952
@ CHEAT_GOD
Definition: Player.h:949
@ CHEAT_NONE
Definition: Player.h:948
@ DELAYED_BG_GROUP_RESTORE
Flag to restore group state after teleport from BG.
Definition: Player.h:910
@ DELAYED_SAVE_PLAYER
Definition: Player.h:905
@ DELAYED_BG_MOUNT_RESTORE
Flag to restore mount state after teleport from BG.
Definition: Player.h:908
@ DELAYED_BG_TAXI_RESTORE
Flag to restore taxi state after teleport from BG.
Definition: Player.h:909
@ DELAYED_SPELL_CAST_DESERTER
Definition: Player.h:907
@ DELAYED_RESURRECT_PLAYER
Definition: Player.h:906
ItemSearchLocation
Definition: Player.h:753
ActionButtonType
Definition: Player.h:291
@ ACTION_BUTTON_MOUNT
Definition: Player.h:299
@ ACTION_BUTTON_COMPANION
Definition: Player.h:298
@ ACTION_BUTTON_DROPDOWN
Definition: Player.h:295
@ ACTION_BUTTON_EQSET
Definition: Player.h:294
@ ACTION_BUTTON_C
Definition: Player.h:293
@ ACTION_BUTTON_MACRO
Definition: Player.h:296
@ ACTION_BUTTON_ITEM
Definition: Player.h:300
@ ACTION_BUTTON_CMACRO
Definition: Player.h:297
@ ACTION_BUTTON_SPELL
Definition: Player.h:292
@ PLAYER_MAX_SKILLS
Definition: Player.h:143
std::unordered_map< uint32, PlayerSpellState > PlayerTalentMap
Definition: Player.h:274
@ BUYBACK_SLOT_END
Definition: Player.h:707
@ BUYBACK_SLOT_START
Definition: Player.h:706
#define INVENTORY_DEFAULT_SIZE
Definition: Player.h:626
@ MAX_QUEST_COUNTS
Definition: Player.h:580
PlayerSpellState
Definition: Player.h:185
@ PLAYERSPELL_REMOVED
Definition: Player.h:189
@ PLAYERSPELL_UNCHANGED
Definition: Player.h:186
@ PLAYERSPELL_CHANGED
Definition: Player.h:187
@ PLAYERSPELL_NEW
Definition: Player.h:188
@ PLAYERSPELL_TEMPORARY
Definition: Player.h:190
#define MAX_TIMERS
Definition: Player.h:512
SpecResetType
Definition: Player.h:216
@ SPEC_RESET_GLYPHS
Definition: Player.h:219
@ SPEC_RESET_TALENTS
Definition: Player.h:217
@ SPEC_RESET_SPECIALIZATION
Definition: Player.h:218
@ SPEC_RESET_PET_TALENTS
Definition: Player.h:220
@ BANK_SLOT_BAG_END
Definition: Player.h:700
@ BANK_SLOT_BAG_START
Definition: Player.h:699
@ PLAYER_LOCAL_FLAG_WAR_MODE
Definition: Player.h:489
@ PLAYER_LOCAL_FLAG_RELEASE_TIMER
Definition: Player.h:481
@ PLAYER_LOCAL_FLAG_OVERRIDE_TRANSPORT_SERVER_TIME
Definition: Player.h:491
#define DISABLED_MIRROR_TIMER
Definition: Player.h:513
@ BANK_SLOT_ITEM_START
Definition: Player.h:693
@ BANK_SLOT_ITEM_END
Definition: Player.h:694
@ PLAYED_TIME_TOTAL
Definition: Player.h:828
@ PLAYED_TIME_LEVEL
Definition: Player.h:829
@ UNDERWATER_INDARKWATER
Definition: Player.h:171
@ UNDERWATER_NONE
Definition: Player.h:167
@ UNDERWATER_INSLIME
Definition: Player.h:170
@ UNDERWATER_EXIST_TIMERS
Definition: Player.h:173
@ UNDERWATER_INWATER
Definition: Player.h:168
@ UNDERWATER_INLAVA
Definition: Player.h:169
#define MAX_ACTION_BUTTONS
Definition: Player.h:340
@ PLAYER_EXPLORED_ZONES_BITS
Definition: Player.h:148
@ PLAYER_DATA_FLAG_EXPLORED_ZONES_INDEX
Definition: Player.h:150
AtLoginFlags
Definition: Player.h:536
@ AT_LOGIN_RESET_TALENTS
Definition: Player.h:540
@ AT_LOGIN_RESET_SPELLS
Definition: Player.h:539
@ AT_LOGIN_NONE
Definition: Player.h:537
@ AT_LOGIN_FIRST
Definition: Player.h:543
@ AT_LOGIN_RESURRECT
Definition: Player.h:546
@ AT_LOGIN_RENAME
Definition: Player.h:538
@ CHAR_DELETE_REMOVE
Definition: Player.h:921
@ CHAR_DELETE_UNLINK
Definition: Player.h:922
DisplayToastMethod
Definition: Player.h:971
@ PROFESSION_SLOT_MAX_COUNT
Definition: Player.h:670
@ PROFESSION_SLOT_FISHING_TOOL
Definition: Player.h:663
@ PROFESSION_SLOT_PROFESSION2_GEAR1
Definition: Player.h:659
@ PROFESSION_SLOT_PROFESSION1_GEAR1
Definition: Player.h:656
@ PROFESSION_SLOT_PROFESSION1_TOOL
Definition: Player.h:655
@ PROFESSION_SLOT_PROFESSION2_GEAR2
Definition: Player.h:660
@ PROFESSION_SLOT_START
Definition: Player.h:668
@ PROFESSION_SLOT_COOKING_GEAR1
Definition: Player.h:662
@ PROFESSION_SLOT_COOKING_TOOL
Definition: Player.h:661
@ PROFESSION_SLOT_END
Definition: Player.h:667
@ PROFESSION_SLOT_PROFESSION1_GEAR2
Definition: Player.h:657
@ CHILD_EQUIPMENT_SLOT_END
Definition: Player.h:719
@ CHILD_EQUIPMENT_SLOT_START
Definition: Player.h:718
PlayerFlagsEx
Definition: Player.h:465
MirrorTimerType
Definition: Player.h:507
@ FIRE_TIMER
Definition: Player.h:510
@ FATIGUE_TIMER
Definition: Player.h:508
@ BREATH_TIMER
Definition: Player.h:509
uint32 constexpr SPELL_PVP_RULES_ENABLED
Definition: Player.h:1096
#define MAX_PLAYER_SUMMON_DELAY
Definition: Player.h:915
#define INVENTORY_SLOT_BAG_0
Definition: Player.h:625
@ SKILL_DELETED
Definition: Player.h:595
@ SKILL_CHANGED
Definition: Player.h:593
@ SKILL_UNCHANGED
Definition: Player.h:592
@ SKILL_NEW
Definition: Player.h:594
@ QUEST_DELETE_SAVE_TYPE
Definition: Player.h:564
@ QUEST_FORCE_DELETE_SAVE_TYPE
Definition: Player.h:565
@ QUEST_DEFAULT_SAVE_TYPE
Definition: Player.h:563
DrunkenState
Definition: Player.h:417
@ DRUNKEN_TIPSY
Definition: Player.h:419
@ DRUNKEN_DRUNK
Definition: Player.h:420
@ DRUNKEN_SOBER
Definition: Player.h:418
@ DRUNKEN_SMASHED
Definition: Player.h:421
ZonePVPTypeOverride
Definition: Player.h:1100
ReputationSource
Definition: Player.h:304
@ REPUTATION_SOURCE_KILL
Definition: Player.h:305
@ REPUTATION_SOURCE_SPELL
Definition: Player.h:311
@ REPUTATION_SOURCE_QUEST
Definition: Player.h:306
@ REPUTATION_SOURCE_MONTHLY_QUEST
Definition: Player.h:309
@ REPUTATION_SOURCE_REPEATABLE_QUEST
Definition: Player.h:310
@ REPUTATION_SOURCE_WEEKLY_QUEST
Definition: Player.h:308
@ REPUTATION_SOURCE_DAILY_QUEST
Definition: Player.h:307
Trinity::IteratorPair< UF::ChrCustomizationChoice const * > MakeChrCustomizationChoiceRange(Container const &container)
Definition: Player.h:3247
@ QUESTS_COMPLETED_BITS_SIZE
Definition: Player.h:574
@ QUESTS_COMPLETED_BITS_PER_BLOCK
Definition: Player.h:575
#define MAX_ACTION_BUTTON_ACTION_VALUE
Definition: Player.h:316
@ REAGENT_BAG_SLOT_END
Definition: Player.h:682
@ REAGENT_BAG_SLOT_START
Definition: Player.h:681
@ PLAYER_SLOTS_COUNT
Definition: Player.h:620
@ PLAYER_SLOT_START
Definition: Player.h:617
@ PLAYER_SLOT_END
Definition: Player.h:619
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS
Definition: Player.h:866
@ PLAYER_LOGIN_QUERY_LOAD_CUSTOMIZATIONS
Definition: Player.h:838
@ PLAYER_LOGIN_QUERY_LOAD_CURRENCY
Definition: Player.h:889
@ PLAYER_LOGIN_QUERY_LOAD_GLYPHS
Definition: Player.h:876
@ PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES
Definition: Player.h:868
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW
Definition: Player.h:884
@ PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS
Definition: Player.h:849
@ PLAYER_LOGIN_QUERY_LOAD_AURA_EFFECTS
Definition: Player.h:841
@ PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES
Definition: Player.h:885
@ PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS
Definition: Player.h:886
@ PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST
Definition: Player.h:864
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWERS
Definition: Player.h:896
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA
Definition: Player.h:847
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_CONFIGS
Definition: Player.h:899
@ PLAYER_LOGIN_QUERY_LOAD_SKILLS
Definition: Player.h:880
@ PLAYER_LOGIN_QUERY_LOAD_BG_DATA
Definition: Player.h:875
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES_CRITERIA_PROGRESS
Definition: Player.h:848
@ PLAYER_LOGIN_QUERY_LOAD_TRANSMOG_OUTFITS
Definition: Player.h:874
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_FOLLOWER_ABILITIES
Definition: Player.h:897
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS
Definition: Player.h:858
@ PLAYER_LOGIN_QUERY_LOAD_VOID_STORAGE
Definition: Player.h:888
@ PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS
Definition: Player.h:892
@ PLAYER_LOGIN_QUERY_LOAD_ARTIFACTS
Definition: Player.h:852
@ PLAYER_LOGIN_QUERY_LOAD_INVENTORY
Definition: Player.h:851
@ PLAYER_LOGIN_QUERY_LOAD_REPUTATION
Definition: Player.h:850
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_MILESTONE_POWERS
Definition: Player.h:854
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BLUEPRINTS
Definition: Player.h:894
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE
Definition: Player.h:860
@ PLAYER_LOGIN_QUERY_LOAD_FROM
Definition: Player.h:837
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS
Definition: Player.h:845
@ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_OBJECTIVES
Definition: Player.h:846
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_UNLOCKED_ESSENCE
Definition: Player.h:862
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON_BUILDINGS
Definition: Player.h:895
@ PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS
Definition: Player.h:881
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_CHARGES
Definition: Player.h:867
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_MILESTONE_POWER
Definition: Player.h:861
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE
Definition: Player.h:853
@ PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS
Definition: Player.h:887
@ PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS
Definition: Player.h:873
@ PLAYER_LOGIN_QUERY_LOAD_MAILS
Definition: Player.h:857
@ PLAYER_LOGIN_QUERY_LOAD_AURAS
Definition: Player.h:840
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_AZERITE_EMPOWERED
Definition: Player.h:863
@ PLAYER_LOGIN_QUERY_LOAD_TALENTS
Definition: Player.h:877
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_UNLOCKED_ESSENCES
Definition: Player.h:855
@ PLAYER_LOGIN_QUERY_LOAD_GARRISON
Definition: Player.h:893
@ PLAYER_LOGIN_QUERY_LOAD_BANNED
Definition: Player.h:883
@ PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS_ARTIFACT
Definition: Player.h:859
@ PLAYER_LOGIN_QUERY_LOAD_GROUP
Definition: Player.h:839
@ PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS
Definition: Player.h:872
@ PLAYER_LOGIN_QUERY_LOAD_HOME_BIND
Definition: Player.h:865
@ PLAYER_LOGIN_QUERY_LOAD_SPELLS
Definition: Player.h:843
@ PLAYER_LOGIN_QUERY_LOAD_SPELL_FAVORITES
Definition: Player.h:844
@ PLAYER_LOGIN_QUERY_LOAD_TRAIT_ENTRIES
Definition: Player.h:898
@ PLAYER_LOGIN_QUERY_LOAD_AZERITE_EMPOWERED
Definition: Player.h:856
@ PLAYER_LOGIN_QUERY_LOAD_PVP_TALENTS
Definition: Player.h:878
@ PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES
Definition: Player.h:890
@ PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG
Definition: Player.h:882
@ PLAYER_LOGIN_QUERY_LOAD_AURA_STORED_LOCATIONS
Definition: Player.h:842
@ PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS
Definition: Player.h:871
@ LOG_XP_REASON_NO_KILL
Definition: Player.h:959
@ LOG_XP_REASON_KILL
Definition: Player.h:958
TalentLearnResult
Definition: Player.h:1060
@ TALENT_FAILED_UNKNOWN
Definition: Player.h:1062
@ TALENT_FAILED_AFFECTING_COMBAT
Definition: Player.h:1066
@ TALENT_FAILED_NO_PRIMARY_TREE_SELECTED
Definition: Player.h:1064
@ TALENT_FAILED_REST_AREA
Definition: Player.h:1069
@ TALENT_LEARN_OK
Definition: Player.h:1061
@ TALENT_FAILED_CANT_REMOVE_TALENT
Definition: Player.h:1067
@ TALENT_FAILED_CANT_DO_THAT_RIGHT_NOW
Definition: Player.h:1065
#define MAPID_INVALID
Definition: Position.h:176
QuestFailedReason
Definition: QuestDef.h:57
@ QUEST_ERR_ALREADY_DONE
Definition: QuestDef.h:61
@ QUEST_ERR_FAILED_EXPANSION
Definition: QuestDef.h:64
@ QUEST_ERR_FAILED_WRONG_RACE
Definition: QuestDef.h:60
@ QUEST_ERR_ONLY_ONE_TIMED
Definition: QuestDef.h:62
@ QUEST_ERR_FAILED_LOW_LEVEL
Definition: QuestDef.h:59
@ QUEST_ERR_NONE
Definition: QuestDef.h:58
@ QUEST_ERR_ALREADY_ON1
Definition: QuestDef.h:63
QuestPushReason
Definition: QuestDef.h:76
#define QUEST_ITEM_DROP_COUNT
Definition: QuestDef.h:46
#define QUEST_REWARD_REPUTATIONS_COUNT
Definition: QuestDef.h:50
QuestObjectiveType
Definition: QuestDef.h:331
@ QUEST_OBJECTIVE_DEFEATBATTLEPET
Definition: QuestDef.h:344
@ QUEST_OBJECTIVE_WINPVPPETBATTLES
Definition: QuestDef.h:345
@ QUEST_OBJECTIVE_INCREASE_REPUTATION
Definition: QuestDef.h:350
@ QUEST_OBJECTIVE_HAVE_CURRENCY
Definition: QuestDef.h:348
@ QUEST_OBJECTIVE_WINPETBATTLEAGAINSTNPC
Definition: QuestDef.h:343
@ QUEST_OBJECTIVE_MONSTER
Definition: QuestDef.h:332
@ QUEST_OBJECTIVE_TALKTO
Definition: QuestDef.h:335
@ QUEST_OBJECTIVE_CRITERIA_TREE
Definition: QuestDef.h:346
@ QUEST_OBJECTIVE_OBTAIN_CURRENCY
Definition: QuestDef.h:349
@ QUEST_OBJECTIVE_PROGRESS_BAR
Definition: QuestDef.h:347
@ QUEST_OBJECTIVE_PLAYERKILLS
Definition: QuestDef.h:341
@ QUEST_OBJECTIVE_ITEM
Definition: QuestDef.h:333
@ QUEST_OBJECTIVE_MONEY
Definition: QuestDef.h:340
@ QUEST_OBJECTIVE_MAX_REPUTATION
Definition: QuestDef.h:339
@ QUEST_OBJECTIVE_AREA_TRIGGER_EXIT
Definition: QuestDef.h:352
@ QUEST_OBJECTIVE_AREATRIGGER
Definition: QuestDef.h:342
@ QUEST_OBJECTIVE_CURRENCY
Definition: QuestDef.h:336
@ QUEST_OBJECTIVE_LEARNSPELL
Definition: QuestDef.h:337
@ QUEST_OBJECTIVE_AREA_TRIGGER_ENTER
Definition: QuestDef.h:351
@ QUEST_OBJECTIVE_GAMEOBJECT
Definition: QuestDef.h:334
@ QUEST_OBJECTIVE_MIN_REPUTATION
Definition: QuestDef.h:338
QuestGiverStatus
Definition: QuestDef.h:153
@ ImportantQuestRewardCompletePOI
@ CovenantCallingRewardCompletePOI
@ ImportantQuestRewardCompleteNoPOI
@ CovenantCallingRewardCompleteNoPOI
#define QUEST_REWARD_CURRENCY_COUNT
Definition: QuestDef.h:52
@ QUEST_OBJECTIVE_FLAG_2_QUEST_BOUND_ITEM
Definition: QuestDef.h:374
#define MAX_QUEST_LOG_SIZE
Definition: QuestDef.h:44
@ QUEST_OBJECTIVE_FLAG_SEQUENCED
Definition: QuestDef.h:361
@ QUEST_OBJECTIVE_FLAG_KILL_PLAYERS_SAME_FACTION
Definition: QuestDef.h:367
@ QUEST_OBJECTIVE_FLAG_PART_OF_PROGRESS_BAR
Definition: QuestDef.h:366
@ QUEST_OBJECTIVE_FLAG_OPTIONAL
Definition: QuestDef.h:362
@ QUEST_OBJECTIVE_FLAG_HIDE_CREDIT_MSG
Definition: QuestDef.h:364
@ QUEST_FLAGS_EX_NO_ITEM_REMOVAL
Definition: QuestDef.h:232
@ QUEST_FLAGS_EX_LEGENDARY
Definition: QuestDef.h:240
@ QUEST_FLAGS_EX_REWARDS_IGNORE_CAPS
Definition: QuestDef.h:255
@ QUEST_FLAGS_EX_REMOVE_ON_PERIODIC_RESET
Definition: QuestDef.h:238
@ QUEST_FLAGS_EX_NO_CREDIT_FOR_PROXY
Definition: QuestDef.h:246
@ QUEST_FLAGS_EX_RECAST_ACCEPT_SPELL_ON_LOGIN
Definition: QuestDef.h:244
QuestStatus
Definition: QuestDef.h:141
@ QUEST_STATUS_REWARDED
Definition: QuestDef.h:148
@ QUEST_STATUS_FAILED
Definition: QuestDef.h:147
@ QUEST_STATUS_INCOMPLETE
Definition: QuestDef.h:145
@ QUEST_STATUS_NONE
Definition: QuestDef.h:142
@ MAX_QUEST_STATUS
Definition: QuestDef.h:149
@ QUEST_STATUS_COMPLETE
Definition: QuestDef.h:143
#define QUEST_REWARD_CHOICES_COUNT
Definition: QuestDef.h:47
QuestFlags
Definition: QuestDef.h:192
@ QUEST_FLAGS_FLAGS_PVP
Definition: QuestDef.h:207
@ QUEST_FLAGS_HIDE_REWARD_POI
Definition: QuestDef.h:199
@ QUEST_FLAGS_AUTO_COMPLETE
Definition: QuestDef.h:210
@ QUEST_FLAGS_REMOVE_SURPLUS_ITEMS
Definition: QuestDef.h:219
@ QUEST_FLAGS_COMPLETION_AREA_TRIGGER
Definition: QuestDef.h:196
@ QUEST_FLAGS_UPDATE_PHASESHIFT
Definition: QuestDef.h:216
@ QUEST_FLAGS_COMPLETION_NO_DEATH
Definition: QuestDef.h:194
@ QUEST_FLAGS_SHARABLE
Definition: QuestDef.h:197
@ QUEST_FLAGS_PLAYER_CAST_COMPLETE
Definition: QuestDef.h:215
@ QUEST_FLAGS_COMPLETION_EVENT
Definition: QuestDef.h:195
@ QUEST_FLAGS_LAUNCH_GOSSIP_COMPLETE
Definition: QuestDef.h:218
@ QUEST_FLAGS_PLAYER_CAST_ACCEPT
Definition: QuestDef.h:214
@ QUEST_FLAGS_TRACKING_EVENT
Definition: QuestDef.h:204
Races
Definition: RaceMask.h:26
@ RACE_PANDAREN_NEUTRAL
Definition: RaceMask.h:51
@ RACE_PANDAREN_ALLIANCE
Definition: RaceMask.h:52
@ RACE_PANDAREN_HORDE
Definition: RaceMask.h:53
int32 irand(int32 min, int32 max)
Definition: Random.cpp:35
uint32 urand(uint32 min, uint32 max)
Definition: Random.cpp:42
bool roll_chance_f(float chance)
Definition: Random.h:53
bool roll_chance_i(int chance)
Definition: Random.h:59
#define sRealmList
Definition: RealmList.h:96
@ REALM_TYPE_RPPVP
Definition: Realm.h:69
@ REALM_TYPE_PVP
Definition: Realm.h:66
PlayerRestState
Definition: RestMgr.h:45
@ REST_STATE_NORMAL
Definition: RestMgr.h:47
@ REST_STATE_RAF_LINKED
Definition: RestMgr.h:48
@ REST_FLAG_IN_TAVERN
Definition: RestMgr.h:53
@ REST_FLAG_IN_FACTION_AREA
Definition: RestMgr.h:55
@ REST_FLAG_IN_CITY
Definition: RestMgr.h:54
@ REST_TYPE_XP
Definition: RestMgr.h:28
@ REST_TYPE_HONOR
Definition: RestMgr.h:29
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define sScriptMgr
Definition: ScriptMgr.h:1418
@ SERVERSIDE_VISIBILITY_GM
@ BASE_PARENT_TIER_INDEX
SpellEffIndex
Definition: SharedDefines.h:29
@ EFFECT_3
Definition: SharedDefines.h:33
@ EFFECT_1
Definition: SharedDefines.h:31
@ EFFECT_0
Definition: SharedDefines.h:30
@ EFFECT_4
Definition: SharedDefines.h:34
@ EFFECT_2
Definition: SharedDefines.h:32
#define MAX_STATS
RaidGroupReason
@ RAID_GROUP_ERR_REQUIREMENTS_UNMATCH
@ RAID_GROUP_ERR_NONE
#define MIN_SPECIALIZATION_LEVEL
#define MAX_POWERS_PER_CLASS
#define CURRENT_EXPANSION
Classes
@ CLASS_HUNTER
@ CLASS_SHAMAN
@ CLASS_WARRIOR
@ CLASS_MAGE
@ CLASS_DEATH_KNIGHT
@ CLASS_DEMON_HUNTER
@ CLASS_PALADIN
@ CLASS_NONE
@ CLASS_ROGUE
@ CLASS_EVOKER
#define PLAYER_CORPSE_LOOT_ENTRY
Language
@ LANG_ADDON_LOGGED
@ LANG_UNIVERSAL
@ LANG_ADDON
ResetFailedReason
@ INSTANCE_RESET_FAILED
@ SKILL_CATEGORY_SECONDARY
@ SKILL_CATEGORY_PROFESSION
GameobjectTypes
@ GAMEOBJECT_TYPE_GENERIC
@ GAMEOBJECT_TYPE_CHEST
@ GAMEOBJECT_TYPE_QUESTGIVER
@ GAMEOBJECT_TYPE_GOOBER
@ GAMEOBJECT_TYPE_GATHERING_NODE
MailResponseType
@ MAIL_ITEM_TAKEN
constexpr uint32 GetMaxLevelForExpansion(uint32 expansion)
Gender
@ SPELL_ATTR5_NO_REAGENT_COST_WITH_AURA
@ SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED
@ TARGET_DEST_CASTER_SUMMON
@ TARGET_UNIT_CASTER
@ CHAR_NAME_SUCCESS
SpellSchoolMask
@ SPELL_SCHOOL_MASK_NORMAL
@ SPELL_SCHOOL_MASK_SHADOW
@ SPELL_SCHOOL_MASK_ALL
@ SPELL_SCHOOL_MASK_ARCANE
@ SPELL_SCHOOL_MASK_NATURE
@ SPELL_SCHOOL_MASK_HOLY
@ SPELL_SCHOOL_MASK_FIRE
@ SPELL_SCHOOL_MASK_FROST
@ CORPSE_DYNFLAG_LOOTABLE
@ SPELL_ATTR2_ALLOW_WHILE_NOT_SHAPESHIFTED_CASTER_FORM
@ INVISIBILITY_DRUNK
CurrencyDbFlags
@ VOID_STORAGE_MAX_SLOT
@ SPELL_ATTR1_CAST_WHEN_LEARNED
@ SPELL_ATTR1_NO_SKILL_INCREASE
constexpr BattlegroundQueueTypeId BATTLEGROUND_QUEUE_NONE
#define MAX_SPECIALIZATIONS
@ UNIT_DYNFLAG_NONE
@ UNIT_DYNFLAG_REFER_A_FRIEND
@ ITEM_QUALITY_HEIRLOOM
@ ITEM_QUALITY_EPIC
@ CHAT_FLAG_GM
@ CHAT_FLAG_DEV
@ CHAT_FLAG_AFK
@ CHAT_FLAG_NONE
@ CHAT_FLAG_DND
TeamId
@ TEAM_NEUTRAL
@ VOID_TRANSFER_ERROR_FULL
@ VOID_TRANSFER_ERROR_INTERNAL_ERROR_1
static constexpr uint8 PLAYER_MAX_BATTLEGROUND_QUEUES
@ SPELL_EFFECT_TITAN_GRIP
@ SPELL_EFFECT_ATTACK_ME
@ SPELL_EFFECT_DUAL_WIELD
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_SKILL_STEP
@ ERR_NOT_IN_GROUP
@ ERR_TAXINOSUCHPATH
@ ERR_PARTY_LFG_BOOT_LIMIT
@ ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS
@ ERR_PARTY_LFG_BOOT_LOOT_ROLLS
@ ERR_PARTY_LFG_BOOT_IN_COMBAT
@ ERR_TAXIPLAYERBUSY
@ ERR_TAXIUNSPECIFIEDSERVERERROR
@ ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE
@ ERR_TAXINOTENOUGHMONEY
@ ERR_TAXIPLAYERSHAPESHIFTED
@ ERR_PARTY_LFG_BOOT_IN_PROGRESS
@ ERR_GUILD_PLAYER_NOT_IN_GUILD
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
@ MECHANIC_DISCOVERY
MailResponseResult
@ MAIL_ERR_EQUIP_ERROR
Team
@ TEAM_OTHER
@ ALLIANCE
@ HORDE
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_RUNIC_POWER
@ POWER_ENERGY
@ POWER_LUNAR_POWER
@ POWER_RUNES
@ POWER_COMBO_POINTS
@ POWER_MANA
@ POWER_FOCUS
@ SPELL_ATTR0_ONLY_INDOORS
@ SPELL_ATTR0_ONLY_OUTDOORS
ReputationRank
@ REP_UNFRIENDLY
@ REP_NEUTRAL
CurrencyDestroyReason
@ GOLD
@ SPELL_VISUAL_KIT_DRINK
@ SPELL_VISUAL_KIT_FOOD
@ LOOT_MODE_DEFAULT
Definition: SharedDefines.h:77
DuelCompleteType
@ DUEL_FLED
@ DUEL_WON
@ DUEL_INTERRUPTED
TotemCategory
BattlegroundTypeId
@ BATTLEGROUND_AA
@ BATTLEGROUND_AV
@ BATTLEGROUND_TYPE_NONE
@ SPELL_FAILED_DONT_REPORT
@ SPELL_CAST_OK
Stats
@ STAT_INTELLECT
@ STAT_AGILITY
@ STAT_STRENGTH
@ STAT_STAMINA
@ FACTION_FRIENDLY
AuraStateType
@ SPELLFAMILY_WARLOCK
@ AREA_WINTERGRASP
SpellSchools
@ SPELL_SCHOOL_NORMAL
@ SPELL_SCHOOL_HOLY
@ MAX_SPELL_SCHOOL
@ ERR_TAXIOK
CurrencyGainSource
@ EXPANSION_WRATH_OF_THE_LICH_KING
Definition: SharedDefines.h:92
ChatMsg
@ CHAT_MSG_SAY
@ CHAT_MSG_WHISPER_INFORM
@ CHAT_MSG_YELL
@ CHAT_MSG_WHISPER
@ CHAT_MSG_EMOTE
@ SPELL_ATTR4_AURA_EXPIRES_OFFLINE
@ CREATURE_TYPE_FLAG_VISIBLE_TO_GHOSTS
@ CREATURE_TYPE_FLAG_INTERACT_WHILE_DEAD
@ SPELL_ATTR8_REQUIRES_EQUIPPED_INV_TYPES
@ SPELL_ATTR8_SKIP_IS_KNOWN_CHECK
RemoveMethod
@ SKILL_PLATE_MAIL
@ SKILL_MINING
@ SKILL_FISHING
@ SKILL_UNARMED
@ SKILL_RIDING
@ SKILL_SKINNING
@ SKILL_RUNEFORGING
@ SKILL_MAIL
@ SKILL_FIST_WEAPONS
@ SKILL_HERBALISM
PartyResult
@ ERR_INVITE_RESTRICTED
@ ERR_PARTY_RESULT_OK
@ SPELL_ATTR6_DO_NOT_RESET_COOLDOWN_IN_ARENA
@ SPELL_ATTR6_ALLOW_EQUIP_WHILE_CASTING
uint32 GetSkillDiscoverySpell(uint32 skillId, uint32 spellId, Player *player)
@ FRIEND_REMOVED
Definition: SocialMgr.h:74
#define sSocialMgr
Definition: SocialMgr.h:161
@ SOCIAL_FLAG_ALL
Definition: SocialMgr.h:45
@ AURA_EFFECT_HANDLE_SKILL
@ AURA_EFFECT_HANDLE_SEND_FOR_CLIENT
AuraType
@ SPELL_AURA_PREVENT_RESURRECTION
@ SPELL_AURA_SET_FFA_PVP
@ SPELL_AURA_MOD_CURRENCY_GAIN
@ SPELL_AURA_MOD_SKILL
@ SPELL_AURA_IGNORE_MOVEMENT_FORCES
@ SPELL_AURA_MOD_COMBAT_RATING_FROM_COMBAT_RATING
@ SPELL_AURA_MOD_CURRENCY_CATEGORY_GAIN_PCT
@ SPELL_AURA_PREVENT_DURABILITY_LOSS
@ SPELL_AURA_MOD_RATING_PCT
@ SPELL_AURA_MOD_SHAPESHIFT
@ SPELL_AURA_MOD_WATER_BREATHING
@ SPELL_AURA_FEATHER_FALL
@ SPELL_AURA_MOD_REGEN_DURING_COMBAT
@ SPELL_AURA_COMPREHEND_LANGUAGE
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_MOD_POWER_REGEN
@ SPELL_AURA_MOD_VENDOR_ITEMS_PRICES
@ SPELL_AURA_MOD_XP_QUEST_PCT
@ SPELL_AURA_MOD_MELEE_HASTE_2
@ SPELL_AURA_CONTROL_VEHICLE
@ SPELL_AURA_MOD_MELEE_HASTE
@ SPELL_AURA_MOD_ROOT_2
@ SPELL_AURA_CAN_TURN_WHILE_FALLING
@ SPELL_AURA_MOD_HEALTH_REGEN_PERCENT
@ SPELL_AURA_MOD_HEALTH_REGEN_IN_COMBAT
@ SPELL_AURA_DUMMY
@ SPELL_AURA_MOD_STUN_DISABLE_GRAVITY
@ SPELL_AURA_MOD_REPUTATION_GAIN
@ SPELL_AURA_FLY
@ SPELL_AURA_MOD_FAKE_INEBRIATE
@ SPELL_AURA_GHOST
@ SPELL_AURA_WATER_WALK
@ SPELL_AURA_DISABLE_INERTIA
@ SPELL_AURA_SAFE_FALL
@ SPELL_AURA_MOD_ROOT
@ SPELL_AURA_HOVER
@ SPELL_AURA_SCHOOL_IMMUNITY
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_TAUNT
@ SPELL_AURA_MOD_CRIT_PCT
@ SPELL_AURA_MOD_HONOR_GAIN_PCT
@ SPELL_AURA_REMOVE_BARBER_SHOP_COST
@ SPELL_AURA_MOD_ROOT_DISABLE_GRAVITY
@ SPELL_AURA_PREVENT_DURABILITY_LOSS_FROM_COMBAT
@ SPELL_AURA_TRANSFORM
@ SPELL_AURA_MOD_WEAPON_CRIT_PERCENT
@ SPELL_AURA_WATER_BREATHING
@ SPELL_AURA_MOD_DURABILITY_LOSS
@ SPELL_AURA_PROVIDE_TOTEM_CATEGORY
@ SPELL_AURA_FORCE_BREATH_BAR
@ SPELL_AURA_MOD_ENVIRONMENTAL_DAMAGE_TAKEN
@ SPELL_AURA_MOD_SKILL_2
@ SPELL_AURA_MOD_POWER_REGEN_PERCENT
@ SPELL_AURA_NO_PVP_CREDIT
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_PVP_TALENTS
@ SPELL_AURA_PREVENT_REGENERATE_POWER
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL_FROM_CLIENT
@ SPELL_AURA_MOD_MELEE_HASTE_3
@ SPELL_AURA_NONE
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_MODIFY_FALL_DAMAGE_PCT
@ SPELL_AURA_MOD_REGEN
@ SPELL_AURA_MOD_FACTION_REPUTATION_GAIN
@ SPELL_AURA_MOD_SKILL_TALENT
@ SPELL_AURA_PHASE_ALWAYS_VISIBLE
@ SPELL_AURA_MOD_STUN
@ SPELL_AURA_BIND_SIGHT
ShapeshiftForm
@ FORM_NONE
SpellModOp
Definition: SpellDefines.h:149
TriggerCastFlags
Definition: SpellDefines.h:245
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
@ TRIGGERED_NONE
Not triggered.
Definition: SpellDefines.h:246
SpellValueMod
Definition: SpellDefines.h:195
@ SPELLVALUE_BASE_POINT0
Definition: SpellDefines.h:196
#define MAX_SPELLMOD
Definition: SpellDefines.h:192
@ SPELL_COOLDOWN_FLAG_INCLUDE_GCD
Starts GCD in addition to normal cooldown specified in the packet.
Definition: SpellHistory.h:40
@ SPELL_ATTR0_CU_CAN_CRIT
Definition: SpellInfo.h:155
@ SPELL_ATTR0_CU_IS_TALENT
Definition: SpellInfo.h:171
std::pair< SpellsRequiringSpellMap::const_iterator, SpellsRequiringSpellMap::const_iterator > SpellsRequiringSpellMapBounds
Definition: SpellMgr.h:577
std::pair< SpellAreaForAreaMap::const_iterator, SpellAreaForAreaMap::const_iterator > SpellAreaForAreaMapBounds
Definition: SpellMgr.h:557
@ PROC_SPELL_PHASE_NONE
Definition: SpellMgr.h:262
#define sSpellMgr
Definition: SpellMgr.h:849
@ PROC_SPELL_TYPE_MASK_ALL
Definition: SpellMgr.h:255
@ SPELL_AREA_FLAG_AUTOREMOVE
Definition: SpellMgr.h:529
@ SPELL_AREA_FLAG_IGNORE_AUTOCAST_ON_QUEST_STATUS_CHANGE
Definition: SpellMgr.h:530
@ SPELL_AREA_FLAG_AUTOCAST
Definition: SpellMgr.h:528
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition: SpellMgr.h:621
@ PROC_FLAG_LOOTED
Definition: SpellMgr.h:186
@ PROC_FLAG_NONE
Definition: SpellMgr.h:135
@ ENCHANT_PROC_ATTR_LIMIT_60
Definition: SpellMgr.h:336
@ ENCHANT_PROC_ATTR_WHITE_HIT
Definition: SpellMgr.h:335
@ PROC_HIT_NONE
Definition: SpellMgr.h:273
@ PROC_HIT_ABSORB
Definition: SpellMgr.h:284
@ PROC_HIT_CRITICAL
Definition: SpellMgr.h:275
@ PROC_HIT_NORMAL
Definition: SpellMgr.h:274
std::pair< SpellAreaForQuestMap::const_iterator, SpellAreaForQuestMap::const_iterator > SpellAreaForQuestMapBounds
Definition: SpellMgr.h:555
std::pair< SpellLearnSpellMap::const_iterator, SpellLearnSpellMap::const_iterator > SpellLearnSpellMapBounds
Definition: SpellMgr.h:618
@ SPELL_CAST_SOURCE_NORMAL
Definition: Spell.h:146
@ SPELL_STATE_DELAYED
Definition: Spell.h:239
#define sTerrainMgr
Definition: TerrainMgr.h:165
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition: Timer.h:57
@ TRADE_SLOT_INVALID
Definition: TradeData.h:28
@ UNIT_FLAG2_FORCE_MOVEMENT
Definition: UnitDefines.h:200
@ UNIT_FLAG2_ALLOW_CHEAT_SPELLS
Definition: UnitDefines.h:212
@ UNIT_FLAG2_REGENERATE_POWER
Definition: UnitDefines.h:205
@ UNIT_FLAG2_ALLOW_CHANGING_TALENTS
Definition: UnitDefines.h:203
ReactStates
Definition: UnitDefines.h:505
#define BASE_ATTACK_TIME
Definition: UnitDefines.h:35
@ MOVEMENTFLAG_DESCENDING
Definition: UnitDefines.h:380
@ MOVEMENTFLAG_PITCH_DOWN
Definition: UnitDefines.h:365
@ MOVEMENTFLAG_PITCH_UP
Definition: UnitDefines.h:364
@ MOVEMENTFLAG_RIGHT
Definition: UnitDefines.h:363
@ MOVEMENTFLAG_FORWARD
Definition: UnitDefines.h:358
@ MOVEMENTFLAG_STRAFE_LEFT
Definition: UnitDefines.h:360
@ MOVEMENTFLAG_BACKWARD
Definition: UnitDefines.h:359
@ MOVEMENTFLAG_WATERWALKING
Definition: UnitDefines.h:384
@ MOVEMENTFLAG_MASK_MOVING
Definition: UnitDefines.h:389
@ MOVEMENTFLAG_DISABLE_GRAVITY
Definition: UnitDefines.h:367
@ MOVEMENTFLAG_FLYING
Definition: UnitDefines.h:382
@ MOVEMENTFLAG_FALLING_SLOW
Definition: UnitDefines.h:385
@ MOVEMENTFLAG_CAN_FLY
Definition: UnitDefines.h:381
@ MOVEMENTFLAG_ROOT
Definition: UnitDefines.h:368
@ MOVEMENTFLAG_FALLING
Definition: UnitDefines.h:369
@ MOVEMENTFLAG_LEFT
Definition: UnitDefines.h:362
@ MOVEMENTFLAG_STRAFE_RIGHT
Definition: UnitDefines.h:361
@ MOVEMENTFLAG_MASK_HAS_PLAYER_STATUS_OPCODE
Movement flags that have change status opcodes associated for players.
Definition: UnitDefines.h:410
@ MOVEMENTFLAG_ASCENDING
Definition: UnitDefines.h:379
@ MOVEMENTFLAG_HOVER
Definition: UnitDefines.h:386
@ MOVEMENTFLAG_SPLINE_ELEVATION
Definition: UnitDefines.h:383
#define MAX_DECLINED_NAME_CASES
Definition: UnitDefines.h:484
NPCFlags
Non Player Character flags.
Definition: UnitDefines.h:295
@ UNIT_NPC_FLAG_VENDOR
Definition: UnitDefines.h:304
@ UNIT_NPC_FLAG_GOSSIP
Definition: UnitDefines.h:297
@ UNIT_NPC_FLAG_NONE
Definition: UnitDefines.h:296
@ UNIT_NPC_FLAG_QUESTGIVER
Definition: UnitDefines.h:298
@ UNIT_NPC_FLAG_SPELLCLICK
Definition: UnitDefines.h:321
@ SELF_DAMAGE
Definition: UnitDefines.h:137
@ DIRECT_DAMAGE
Definition: UnitDefines.h:132
#define BASE_MAXDAMAGE
Definition: UnitDefines.h:34
@ MOVEMENTFLAG3_ADV_FLYING
Definition: UnitDefines.h:443
NPCFlags2
Definition: UnitDefines.h:335
@ UNIT_NPC_FLAG_2_NONE
Definition: UnitDefines.h:336
@ UNIT_BYTE2_FLAG_PVP
Definition: UnitDefines.h:93
@ UNIT_BYTE2_FLAG_FFA_PVP
Definition: UnitDefines.h:95
@ UNIT_BYTE2_FLAG_SANCTUARY
Definition: UnitDefines.h:96
@ UNIT_VIS_FLAGS_ALL
Definition: UnitDefines.h:64
CommandStates
Definition: UnitDefines.h:525
@ COMMAND_FOLLOW
Definition: UnitDefines.h:527
#define BASE_MINDAMAGE
Definition: UnitDefines.h:33
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:162
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
@ UNIT_FLAG_IN_COMBAT
Definition: UnitDefines.h:163
@ UNIT_FLAG_PREPARATION
Definition: UnitDefines.h:149
@ UNIT_FLAG_IMMUNE_TO_NPC
Definition: UnitDefines.h:153
@ UNIT_FLAG_ON_TAXI
Definition: UnitDefines.h:164
@ UNIT_FLAG_DISARMED
Definition: UnitDefines.h:165
@ UNIT_FLAG_PACIFIED
Definition: UnitDefines.h:161
@ UNIT_FLAG_REMOVE_CLIENT_CONTROL
Definition: UnitDefines.h:146
@ UNIT_FLAG_CONFUSED
Definition: UnitDefines.h:166
@ UNIT_FLAG_FLEEING
Definition: UnitDefines.h:167
@ UNIT_FLAG_LOOTING
Definition: UnitDefines.h:154
@ UNIT_FLAG_UNINTERACTIBLE
Definition: UnitDefines.h:169
@ UNIT_FLAG_IMMUNE_TO_PC
Definition: UnitDefines.h:152
@ UNIT_FLAG_NOT_ATTACKABLE_1
Definition: UnitDefines.h:151
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:147
@ UNIT_FLAG_SKINNABLE
Definition: UnitDefines.h:170
@ UNIT_FLAG_MOUNT
Definition: UnitDefines.h:171
@ UNIT_FLAG_PET_IN_COMBAT
Definition: UnitDefines.h:155
@ BASE_VALUE
Definition: Unit.h:152
@ TOTAL_VALUE
Definition: Unit.h:154
@ UNIT_MASK_PUPPET
Definition: Unit.h:356
BaseModType
Definition: Unit.h:238
@ FLAT_MOD
Definition: Unit.h:239
@ MOD_END
Definition: Unit.h:241
#define WARMODE_ENLISTED_SPELL_OUTSIDE
Definition: Unit.h:41
@ MINDAMAGE
Definition: Unit.h:167
@ MAXDAMAGE
Definition: Unit.h:168
UnitMods
Definition: Unit.h:172
@ UNIT_MOD_DAMAGE_OFFHAND
Definition: Unit.h:214
@ UNIT_MOD_STAT_INTELLECT
Definition: Unit.h:176
@ UNIT_MOD_ARMOR
Definition: Unit.h:204
@ UNIT_MOD_RESISTANCE_SHADOW
Definition: Unit.h:209
@ UNIT_MOD_RESISTANCE_FROST
Definition: Unit.h:208
@ UNIT_MOD_ATTACK_POWER
Definition: Unit.h:211
@ UNIT_MOD_RESISTANCE_HOLY
Definition: Unit.h:205
@ UNIT_MOD_RESISTANCE_START
Definition: Unit.h:220
@ UNIT_MOD_RESISTANCE_ARCANE
Definition: Unit.h:210
@ UNIT_MOD_HEALTH
Definition: Unit.h:177
@ UNIT_MOD_DAMAGE_RANGED
Definition: Unit.h:215
@ UNIT_MOD_RESISTANCE_FIRE
Definition: Unit.h:206
@ UNIT_MOD_STAT_STRENGTH
Definition: Unit.h:173
@ UNIT_MOD_RESISTANCE_NATURE
Definition: Unit.h:207
@ UNIT_MOD_STAT_AGILITY
Definition: Unit.h:174
@ UNIT_MOD_DAMAGE_MAINHAND
Definition: Unit.h:213
@ UNIT_MOD_MANA
Definition: Unit.h:178
@ UNIT_MOD_STAT_STAMINA
Definition: Unit.h:175
@ UNIT_MOD_ATTACK_POWER_RANGED
Definition: Unit.h:212
DeathState
Definition: Unit.h:245
@ CORPSE
Definition: Unit.h:248
@ DEAD
Definition: Unit.h:249
@ ALIVE
Definition: Unit.h:246
@ JUST_DIED
Definition: Unit.h:247
CurrentSpellTypes
Definition: Unit.h:588
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:591
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:590
@ CURRENT_MELEE_SPELL
Definition: Unit.h:589
@ CURRENT_AUTOREPEAT_SPELL
Definition: Unit.h:592
@ UNIT_STATE_ATTACK_PLAYER
Definition: Unit.h:269
@ UNIT_STATE_CONFUSED
Definition: Unit.h:266
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_FLEEING
Definition: Unit.h:262
@ UNIT_STATE_MELEE_ATTACKING
Definition: Unit.h:256
@ UNIT_STATE_CASTING
Definition: Unit.h:270
@ UNIT_STATE_STUNNED
Definition: Unit.h:258
@ UNIT_STATE_CHARMED
Definition: Unit.h:257
#define MAX_COMBAT_RATING
Definition: Unit.h:345
BaseModGroup
Definition: Unit.h:229
@ OFFHAND_CRIT_PERCENTAGE
Definition: Unit.h:232
@ BASEMOD_END
Definition: Unit.h:234
@ SHIELD_BLOCK_VALUE
Definition: Unit.h:233
@ CRIT_PERCENTAGE
Definition: Unit.h:230
@ RANGED_CRIT_PERCENTAGE
Definition: Unit.h:231
#define CURRENT_MAX_SPELL
Definition: Unit.h:596
CombatRating
Definition: Unit.h:310
@ CR_EXPERTISE
Definition: Unit.h:334
@ CR_UNUSED_12
Definition: Unit.h:342
@ CR_CORRUPTION
Definition: Unit.h:322
@ CR_VERSATILITY_DAMAGE_TAKEN
Definition: Unit.h:341
@ CR_HASTE_RANGED
Definition: Unit.h:329
@ CR_HIT_MELEE
Definition: Unit.h:316
@ CR_CLEAVE
Definition: Unit.h:338
@ CR_LIFESTEAL
Definition: Unit.h:327
@ CR_AVOIDANCE
Definition: Unit.h:331
@ CR_RESILIENCE_PLAYER_DAMAGE
Definition: Unit.h:326
@ CR_ARMOR_PENETRATION
Definition: Unit.h:335
@ CR_CRIT_MELEE
Definition: Unit.h:319
@ CR_SPEED
Definition: Unit.h:324
@ CR_CRIT_RANGED
Definition: Unit.h:320
@ CR_VERSATILITY_HEALING_DONE
Definition: Unit.h:340
@ CR_STURDINESS
Definition: Unit.h:332
@ CR_PARRY
Definition: Unit.h:314
@ CR_DODGE
Definition: Unit.h:313
@ CR_DEFENSE_SKILL
Definition: Unit.h:312
@ CR_PVP_POWER
Definition: Unit.h:337
@ CR_UNUSED_7
Definition: Unit.h:333
@ CR_AMPLIFY
Definition: Unit.h:311
@ CR_HASTE_MELEE
Definition: Unit.h:328
@ CR_CORRUPTION_RESISTANCE
Definition: Unit.h:323
@ CR_BLOCK
Definition: Unit.h:315
@ CR_HASTE_SPELL
Definition: Unit.h:330
@ CR_VERSATILITY_DAMAGE_DONE
Definition: Unit.h:339
@ CR_RESILIENCE_CRIT_TAKEN
Definition: Unit.h:325
@ CR_HIT_SPELL
Definition: Unit.h:318
@ CR_MASTERY
Definition: Unit.h:336
@ CR_CRIT_SPELL
Definition: Unit.h:321
@ CR_HIT_RANGED
Definition: Unit.h:317
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
#define SPELL_DH_DOUBLE_JUMP
Definition: Unit.h:38
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition: Unit.h:37
T AddPct(T &base, U pct)
Definition: Util.h:85
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition: Util.h:491
T ApplyPct(T &base, U pct)
Definition: Util.h:91
T CalculatePct(T base, U pct)
Definition: Util.h:72
@ VEHICLE_FLAG_FIXED_POSITION
#define sWorldStateMgr
Definition: WorldStateMgr.h:50
void Add(Item *item, uint8 count, LootType lootType, uint32 dungeonEncounterId)
Definition: Loot.cpp:1060
static bool IsPlayerAccount(uint32 gmlevel)
Definition: AccountMgr.cpp:431
void SaveToDB(bool forceMemberSave=false)
Definition: ArenaTeam.cpp:734
ObjectGuid GetCaptain() const
Definition: ArenaTeam.h:128
void DelMember(ObjectGuid guid, bool cleanDb)
Definition: ArenaTeam.cpp:313
bool FinishWeek()
Definition: ArenaTeam.cpp:777
uint8 GetSlot() const
Definition: ArenaTeam.h:125
uint32 GetType() const
Definition: ArenaTeam.h:124
void NotifyStatsChanged()
Definition: ArenaTeam.cpp:411
Aura * GetBase() const
Definition: SpellAuras.h:78
bool HasEffect(uint8 effect) const
Definition: SpellAuras.h:83
SpellInfo const * GetSpellInfo() const
int32 GetMaxDuration() const
Definition: SpellAuras.h:168
static Aura * TryCreate(AuraCreateInfo &createInfo)
Definition: SpellAuras.cpp:377
int32 GetCastItemLevel() const
Definition: SpellAuras.h:142
Unit * GetUnitOwner() const
Definition: SpellAuras.h:147
ObjectGuid GetCasterGUID() const
Definition: SpellAuras.h:139
AuraEffectVector const & GetAuraEffects() const
Definition: SpellAuras.h:308
int32 GetDuration() const
Definition: SpellAuras.h:173
bool IsUsingCharges() const
Definition: SpellAuras.h:249
uint32 GetCastItemId() const
Definition: SpellAuras.h:141
uint8 GetStackAmount() const
Definition: SpellAuras.h:189
uint8 GetCharges() const
Definition: SpellAuras.h:180
SpellInfo const * GetSpellInfo() const
Definition: SpellAuras.h:134
Difficulty GetCastDifficulty() const
Definition: SpellAuras.h:136
time_t GetApplyTime() const
Definition: SpellAuras.h:167
AuraKey GenerateKey(uint32 &recalculateMask) const
Fills a helper structure containing aura primary key for character_aura, character_aura_effect,...
virtual void Remove(AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)=0
static void DeleteFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
static void DeleteFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition: Bag.h:27
uint32 GetBagSize() const
Definition: Bag.h:45
void StoreItem(uint8 slot, Item *pItem, bool update)
Definition: Bag.cpp:161
bool IsEmpty() const
Definition: Bag.cpp:269
Item * GetItemByPos(uint8 slot) const
Definition: Bag.cpp:288
void RemoveItem(uint8 slot, bool update)
Definition: Bag.cpp:150
void SummonPet(ObjectGuid guid)
void SaveToDB(LoginDatabaseTransaction trans)
Battleground * GetBG() const
Definition: Map.h:914
static bool IsRandomBattleground(uint32 battlemasterListId)
BattlegroundMap * GetBgMap() const
uint32 GetInstanceID() const
Definition: Battleground.h:283
BattlegroundPlayer const * GetBattlegroundPlayerData(ObjectGuid const &playerGuid) const
Definition: Battleground.h:489
bool IsPlayerMercenaryInBattleground(ObjectGuid guid) const
bool IsPlayerInBattleground(ObjectGuid guid) const
bool isArena() const
virtual void AddPlayer(Player *player, BattlegroundQueueTypeId queueId)
BattlegroundStatus GetStatus() const
Definition: Battleground.h:284
void EventPlayerLoggedIn(Player *player)
virtual void RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool SendPacket)
size_t wpos() const
Definition: ByteBuffer.h:412
void put(std::size_t pos, T value)
Definition: ByteBuffer.h:220
void LeftChannel(uint32 channelId, AreaTableEntry const *zoneEntry)
Definition: ChannelMgr.cpp:247
static ChannelMgr * ForTeam(uint32 team)
Definition: ChannelMgr.cpp:114
Channel * GetSystemChannel(uint32 channelId, AreaTableEntry const *zoneEntry=nullptr)
Definition: ChannelMgr.cpp:169
bool IsConstant() const
Definition: Channel.h:167
void JoinChannel(Player *player, std::string const &pass="")
Definition: Channel.cpp:157
uint32 GetChannelId() const
Definition: Channel.h:166
void LeaveChannel(Player *player, bool send=true, bool suspend=false)
Definition: Channel.cpp:256
AreaTableEntry const * GetZoneEntry() const
Definition: Channel.h:188
void PSendSysMessage(const char *fmt, Args &&... args)
Definition: Chat.h:57
virtual void SendSysMessage(std::string_view str, bool escapeCharacters=false)
Definition: Chat.cpp:113
void RemoveTemporaryAppearance(Item *item)
void AddItemAppearance(Item *item)
HeirloomContainer const & GetAccountHeirlooms() const
void SaveAccountToys(LoginDatabaseTransaction trans)
void OnItemAdded(Item *item)
void SaveAccountTransmogIllusions(LoginDatabaseTransaction trans)
void SaveAccountMounts(LoginDatabaseTransaction trans)
void SaveAccountHeirlooms(LoginDatabaseTransaction trans)
bool AddMount(uint32 spellId, MountStatusFlags flags, bool factionMount=false, bool learned=false)
void LoadTransmogIllusions()
ToyBoxContainer const & GetAccountToys() const
MountContainer const & GetAccountMounts() const
void CheckHeirloomUpgrades(Item *item)
void SendFavoriteAppearances() const
void SaveAccountItemAppearances(LoginDatabaseTransaction trans)
void AddTransmogIllusion(uint32 transmogIllusionId)
void LoadItemAppearances()
void EndCombatBeyondRange(float range, bool includingPvP=false)
static bool IsPlayerMeetingCondition(Player const *player, PlayerConditionEntry const *condition)
static Conversation * CreateConversation(uint32 conversationEntry, Unit *creator, Position const &pos, ObjectGuid privateObjectOwner, SpellInfo const *spellInfo=nullptr, bool autoStart=true)
Definition: Corpse.h:53
void ReplaceAllFlags(uint32 flags)
Definition: Corpse.h:106
void SaveToDB()
Definition: Corpse.cpp:104
void SetRace(uint8 race)
Definition: Corpse.h:103
void SetClass(uint8 playerClass)
Definition: Corpse.h:104
void ResetGhostTime()
Definition: Corpse.cpp:176
void SetSex(uint8 sex)
Definition: Corpse.h:105
void SetDisplayId(uint32 displayId)
Definition: Corpse.h:102
Player * lootRecipient
Definition: Corpse.h:134
void SetCustomizations(Trinity::IteratorPair< Iter > customizations)
Definition: Corpse.h:113
void SetFactionTemplate(int32 factionTemplate)
Definition: Corpse.h:107
void SetCorpseDynamicFlag(CorpseDynFlags dynamicFlags)
Definition: Corpse.h:93
std::unique_ptr< Loot > m_loot
Definition: Corpse.h:131
time_t const & GetGhostTime() const
Definition: Corpse.h:124
bool Create(ObjectGuid::LowType guidlow, Map *map)
Definition: Corpse.cpp:65
CorpseType GetType() const
Definition: Corpse.h:126
void DeleteFromDB(CharacterDatabaseTransaction trans)
Definition: Corpse.cpp:156
void SetItem(uint32 slot, uint32 item)
Definition: Corpse.h:110
virtual void OnQuestAccept(Player *, Quest const *)
Definition: CreatureAI.h:207
bool IsTrigger() const
Definition: Creature.h:113
VendorItemData const * GetVendorItems() const
Definition: Creature.cpp:3184
CreatureDifficulty const * GetCreatureDifficulty() const
Definition: Creature.h:252
bool IsReputationGainDisabled() const
Definition: Creature.h:398
uint32 m_spells[MAX_CREATURE_SPELLS]
Definition: Creature.h:302
void SetReactState(ReactStates st)
Definition: Creature.h:160
bool hasLootRecipient() const
Definition: Creature.h:284
Loot * GetLootForPlayer(Player const *player) const override
Definition: Creature.cpp:1386
CreatureTemplate const * GetCreatureTemplate() const
Definition: Creature.h:250
uint32 UpdateVendorItemCurrentCount(VendorItem const *vItem, uint32 used_count)
Definition: Creature.cpp:3223
uint32 GetVendorItemCurrentCount(VendorItem const *vItem)
Definition: Creature.cpp:3189
ReactStates GetReactState() const
Definition: Creature.h:161
bool IsRacialLeader() const
Definition: Creature.h:111
CreatureAI * AI() const
Definition: Creature.h:214
uint32 GetGossipMenuId() const
Definition: Creature.cpp:3685
static bool IsGroupCriteriaType(CriteriaType type)
static char const * GetBroadcastTextValue(BroadcastTextEntry const *broadcastText, LocaleConstant locale=DEFAULT_LOCALE, uint8 gender=GENDER_MALE, bool forceGender=false)
Definition: DB2Stores.cpp:2008
static bool IsTotemCategoryCompatibleWith(uint32 itemTotemCategoryId, uint32 requiredTotemCategoryId, bool requireAllTotems=true)
Definition: DB2Stores.cpp:2990
std::vector< std::pair< uint32, PlayerConditionEntry const * > > MapDifficultyConditionsContainer
Definition: DB2Stores.h:407
static LFGDungeonsEntry const * GetLfgDungeon(uint32 mapId, Difficulty difficulty)
Definition: DB2Stores.cpp:2591
static int32 GetNumTalentsAtLevel(uint32 level, Classes playerClass)
Definition: DB2Stores.cpp:2741
Unit * GetVictim() const
Definition: Unit.h:441
SpellInfo const * GetSpellInfo() const
Definition: Unit.h:442
WeaponAttackType GetAttackType() const
Definition: Unit.h:445
uint32 GetResist() const
Definition: Unit.h:449
ProcFlagsHit GetHitMask() const
Definition: Unit.cpp:244
uint32 GetDamage() const
Definition: Unit.h:446
uint32 GetAbsorb() const
Definition: Unit.h:448
constexpr bool HasFlag(T flag) const
Definition: EnumFlag.h:106
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
std::string GetString() const
Definition: Field.cpp:118
int64 GetInt64() const
Definition: Field.cpp:86
int8 GetInt8() const
Definition: Field.cpp:38
uint64 GetUInt64() const
Definition: Field.cpp:78
int16 GetInt16() const
Definition: Field.cpp:54
uint16 GetUInt16() const
Definition: Field.cpp:46
float GetFloat() const
Definition: Field.cpp:94
bool GetBool() const
Definition: Field.h:98
uint32 GetUInt32() const
Definition: Field.cpp:62
int32 GetInt32() const
Definition: Field.cpp:70
void AddFlag(FLAG_TYPE flag)
Definition: Object.h:442
void DelFlag(FLAG_TYPE flag)
Definition: Object.h:443
void SetValue(FLAG_TYPE flag, T_VALUES value)
Definition: Object.h:446
std::vector< GameEventData > GameEventDataMap
Definition: GameEventMgr.h:103
std::set< uint16 > ActiveEvents
Definition: GameEventMgr.h:102
virtual void OnQuestAccept(Player *, Quest const *)
Definition: GameObjectAI.h:85
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::GameObjectData::Mask const &requestedGameObjectMask, Player const *target) const
bool IsWithinDistInMap(Player const *player) const
GameObjectTemplate const * GetGOInfo() const
Definition: GameObject.h:202
uint32 GetFaction() const override
Definition: GameObject.h:388
GameObjectAI * AI() const
Definition: GameObject.h:378
GameobjectTypes GetGoType() const
Definition: GameObject.h:279
Vignettes::VignetteData const * GetVignette() const
Definition: GameObject.h:427
static void DeleteFromDB(ObjectGuid::LowType ownerGuid, CharacterDatabaseTransaction trans)
Definition: Garrison.cpp:207
GossipMenuItem const * GetItem(int32 gossipOptionId) const
Definition: GossipDef.cpp:168
uint32 GetMenuId() const
Definition: GossipDef.h:167
void setSubGroup(uint8 pSubGroup)
GroupReference * next()
Definition: Group.h:197
bool isLFGGroup() const
Definition: Group.cpp:1633
GroupCategory GetGroupCategory() const
Definition: Group.h:295
bool IsCreated() const
Definition: Group.cpp:1653
void RemoveAllInvites()
Definition: Group.cpp:397
bool IsAssistant(ObjectGuid guid) const
Definition: Group.h:311
void Disband(bool hideDestroy=false)
Definition: Group.cpp:733
bool IsLeader(ObjectGuid guid) const
Definition: Group.cpp:1700
ObjectGuid GetGUID() const
Definition: Group.cpp:1663
void RemoveInvite(Player *player)
Definition: Group.cpp:388
uint32 GetMembersCount() const
Definition: Group.h:327
bool RemoveMember(ObjectGuid guid, RemoveMethod method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, const char *reason=nullptr)
Definition: Group.cpp:570
uint32 GetInviteeCount() const
Definition: Group.h:328
GroupReference * GetFirstMember()
Definition: Group.h:325
void BroadcastPacket(WorldPacket const *packet, bool ignorePlayersInBGRaid, int group=-1, ObjectGuid ignoredPlayer=ObjectGuid::Empty) const
Definition: Group.cpp:980
ObjectGuid GetRecentInstanceOwner(uint32 mapId) const
Definition: Group.h:384
bool SameSubGroup(ObjectGuid guid1, ObjectGuid guid2) const
Definition: Group.cpp:1721
Difficulty GetDifficultyID(MapEntry const *mapEntry) const
Definition: Group.cpp:1358
ObjectGuid GetLeaderGUID() const
Definition: Group.cpp:1658
bool isRaidGroup() const
Definition: Group.cpp:1638
bool InitStatsForLevel(uint8 level)
Definition: Pet.cpp:840
Definition: Guild.h:329
static void SendCommandResult(WorldSession *session, GuildCommandType type, GuildCommandError errCode, std::string_view param="")
Definition: Guild.cpp:62
bool HandleMemberWithdrawMoney(WorldSession *session, uint64 amount, bool repair=false)
Definition: Guild.cpp:2076
uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const
Definition: Guild.cpp:3037
InstanceLockData * GetData()
void CreateInstanceLockForPlayer(Player *player)
Definition: Map.cpp:3199
Group * GetOwningGroup() const
Definition: Map.h:887
Definition: Item.h:170
uint32 GetPlayedTime()
Definition: Item.cpp:1895
static void DeleteFromInventoryDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition: Item.cpp:1129
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition: Item.cpp:1166
uint32 GetPaidExtendedCost() const
Definition: Item.h:364
uint8 GetSlot() const
Definition: Item.h:280
void SetItemFlag(ItemFieldFlags flags)
Definition: Item.h:209
bool IsCurrencyToken() const
Definition: Item.h:255
bool IsWrapped() const
Definition: Item.h:250
Bag * GetContainer()
Definition: Item.h:281
void UpdateDuration(Player *owner, uint32 diff)
Definition: Item.cpp:542
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition: Item.cpp:561
void SetFixedLevel(uint8 level)
Definition: Item.cpp:2793
bool IsLimitedToAnotherMapOrZone(uint32 cur_mapId, uint32 cur_zoneId) const
Definition: Item.cpp:1596
void RemoveItemFlag(ItemFieldFlags flags)
Definition: Item.h:210
void SetBinding(bool val)
Definition: Item.h:201
ItemBondingType GetBonding() const
Definition: Item.h:200
Trinity::IteratorPair< ItemEffectEntry const *const * > GetEffects() const
Definition: Item.h:354
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition: Item.h:298
void SetChildItem(ObjectGuid childItem)
Definition: Item.h:424
void SetPaidMoney(uint64 money)
Definition: Item.h:359
Item * CloneItem(uint32 count, Player const *player=nullptr) const
Definition: Item.cpp:1655
uint8 GetGemCountWithID(uint32 GemID) const
Definition: Item.cpp:1576
Bag * ToBag()
Definition: Item.h:241
AzeriteItem * ToAzeriteItem()
Definition: Item.h:243
int32 GetItemStatType(uint32 index) const
Definition: Item.h:342
uint32 GetEnchantmentDuration(EnchantmentSlot slot) const
Definition: Item.h:299
uint32 GetQuality() const
Definition: Item.h:337
UF::SocketedGem const * GetGem(uint16 slot) const
Definition: Item.cpp:1481
void SetCount(uint32 value)
Definition: Item.cpp:1275
void SetDurability(uint32 durability)
Definition: Item.h:258
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1141
bool IsBOPTradeable() const
Definition: Item.h:249
bool IsSoulBound() const
Definition: Item.h:218
void SaveRefundDataToDB()
Definition: Item.cpp:1814
void SetNotRefundable(Player *owner, bool changestate=true, CharacterDatabaseTransaction *trans=nullptr, bool addToCollection=true)
Definition: Item.cpp:1843
ItemUpdateState GetState() const
Definition: Item.h:322
bool IsBroken() const
Definition: Item.h:257
bool HasItemFlag(ItemFieldFlags flag) const
Definition: Item.h:208
bool IsBindedNotWith(Player const *player) const
Definition: Item.cpp:1672
bool IsEquipped() const
Definition: Item.cpp:1244
void SendTimeUpdate(Player *owner)
Definition: Item.cpp:1613
void SetItemRandomBonusList(ItemRandomBonusListId bonusListId)
Definition: Item.cpp:1158
bool IsRefundExpired()
Definition: Item.cpp:1902
void UpdatePlayedTime(Player *owner)
Definition: Item.cpp:1867
SocketColor GetSocketColor(uint32 index) const
Definition: Item.h:344
ObjectGuid GetOwnerGUID() const
Definition: Item.h:188
uint32 GetDisplayId(Player const *owner) const
Definition: Item.cpp:2405
uint64 GetPaidMoney() const
Definition: Item.h:363
int32 GetVisibleSecondaryModifiedAppearanceId(Player const *owner) const
Definition: Item.cpp:2505
uint32 GetSkill()
Definition: Item.cpp:1152
bool IsRefundable() const
Definition: Item.h:248
void SetItemFlag2(ItemFieldFlags2 flags)
Definition: Item.h:214
uint16 GetPos() const
Definition: Item.h:284
float GetItemStatValue(uint32 index, Player const *owner) const
Definition: Item.cpp:2335
uint64 CalculateDurabilityRepairCost(float discount) const
Definition: Item.cpp:1291
bool IsInTrade() const
Definition: Item.h:262
void SetSoulboundTradeable(GuidSet const &allowedLooters)
Definition: Item.cpp:1907
void SetContainedIn(ObjectGuid guid)
Definition: Item.h:191
uint32 GetVisibleEntry(Player const *owner) const
Definition: Item.cpp:2468
void RemoveItemFlag2(ItemFieldFlags2 flags)
Definition: Item.h:215
void FSetState(ItemUpdateState state)
Definition: Item.h:326
bool IsArtifactDisabled() const
Definition: Item.cpp:2571
bool IsBag() const
Definition: Item.h:252
void ClearEnchantment(EnchantmentSlot slot)
Definition: Item.cpp:1468
uint32 GetItemLevel(Player const *owner) const
Definition: Item.cpp:2279
ObjectGuid const & GetRefundRecipient() const
Definition: Item.h:362
void SetCreatePlayedTime(uint32 createPlayedTime)
Definition: Item.h:311
void SetEnchantmentDuration(EnchantmentSlot slot, uint32 duration, Player *owner)
Definition: Item.cpp:1449
InventoryResult CanBeMergedPartlyWith(ItemTemplate const *proto) const
Definition: Item.cpp:1370
void SetPaidExtendedCost(uint32 iece)
Definition: Item.h:360
void SetBonuses(std::vector< int32 > bonusListIDs)
Definition: Item.cpp:2549
void SetRefundRecipient(ObjectGuid const &guid)
Definition: Item.h:358
uint8 GetGemCountWithLimitCategory(uint32 limitCategory) const
Definition: Item.cpp:1584
void ClearSoulboundTradeable(Player *currentOwner)
Definition: Item.cpp:1913
void SetSlot(uint8 slot)
Definition: Item.h:283
bool IsNotEmptyBag() const
Definition: Item.cpp:535
virtual bool LoadFromDB(ObjectGuid::LowType guid, ObjectGuid ownerGuid, Field *fields, uint32 entry)
Definition: Item.cpp:828
bool m_lootGenerated
Definition: Item.h:318
uint32 GetCount() const
Definition: Item.h:273
bool CheckSoulboundTradeExpire()
Definition: Item.cpp:1927
void SetOwnerGUID(ObjectGuid guid)
Definition: Item.h:189
void SetContainer(Bag *container)
Definition: Item.h:285
AzeriteEmpoweredItem * ToAzeriteEmpoweredItem()
Definition: Item.h:245
uint16 GetVisibleItemVisual(Player const *owner) const
Definition: Item.cpp:2526
uint16 GetVisibleAppearanceModId(Player const *owner) const
Definition: Item.cpp:2480
uint8 GetBagSlot() const
Definition: Item.cpp:1239
ObjectGuid GetChildItem() const
Definition: Item.h:423
uint32 GetModifier(ItemModifier modifier) const
Definition: Item.cpp:2423
static void DeleteFromDB(CharacterDatabaseTransaction trans, ObjectGuid::LowType itemGuid)
Definition: Item.cpp:1088
UF::UpdateField< UF::ItemData, 0, TYPEID_ITEM > m_itemData
Definition: Item.h:449
int32 GetRequiredLevel() const
Definition: Item.cpp:2807
static Item * CreateItem(uint32 itemEntry, uint32 count, ItemContext context, Player const *player=nullptr, bool addDefaultBonuses=true)
Definition: Item.cpp:1625
void LoadArtifactData(Player const *owner, uint64 xp, uint32 artifactAppearanceId, uint32 artifactTier, std::vector< ArtifactPowerData > &powers)
Definition: Item.cpp:1003
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition: Item.cpp:1387
uint32 GetScalingContentTuningId() const
Definition: Item.h:350
Definition: Loot.h:244
void SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const &receiver, MailSender const &sender, MailCheckMask checked=MAIL_CHECK_MASK_NONE, uint32 deliver_delay=0)
Definition: Mail.cpp:192
void SendReturnToSender(uint32 sender_acc, ObjectGuid::LowType sender_guid, ObjectGuid::LowType receiver_guid, CharacterDatabaseTransaction trans)
Definition: Mail.cpp:149
MailDraft & AddItem(Item *item)
Definition: Mail.cpp:99
MailDraft & AddMoney(uint64 money)
Definition: Mail.h:145
static bool IsValidMapCoord(uint32 mapid, float x, float y)
Definition: MapManager.h:82
Definition: Map.h:189
bool IsDungeon() const
Definition: Map.cpp:3238
bool IsBattlegroundOrArena() const
Definition: Map.cpp:3340
virtual void RemovePlayerFromMap(Player *, bool)
Definition: Map.cpp:945
void SendZoneDynamicInfo(uint32 zoneId, Player *player) const
Definition: Map.cpp:3865
MapDifficultyEntry const * GetMapDifficulty() const
Definition: Map.cpp:3223
bool AddToMap(T *)
Definition: Map.cpp:550
virtual TransferAbortParams CannotEnter(Player *)
Definition: Map.h:320
void UpdatePersonalPhasesForPlayer(Player const *player)
Definition: Map.cpp:454
Weather * GetOrGenerateZoneDefaultWeather(uint32 zoneId)
Definition: Map.cpp:3930
bool IsNonRaidDungeon() const
Definition: Map.cpp:3243
void AddCorpse(Corpse *corpse)
Definition: Map.cpp:3751
void UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone)
Definition: Map.cpp:671
bool IsRaid() const
Definition: Map.cpp:3248
Corpse * ConvertCorpseToBones(ObjectGuid const &ownerGuid, bool insignia=false)
Definition: Map.cpp:3782
ObjectGuid::LowType GenerateLowGuid()
Definition: Map.h:519
BattlegroundMap * ToBattlegroundMap()
Definition: Map.h:457
static TransferAbortParams PlayerCannotEnter(uint32 mapid, Player *player)
Definition: Map.cpp:1807
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3489
Difficulty GetDifficultyID() const
Definition: Map.h:324
void UpdateIteratorBack(Player *player)
Definition: Map.cpp:3545
MapEntry const * GetEntry() const
Definition: Map.h:195
uint32 GetPlayersCountExceptGMs() const
Definition: Map.cpp:2681
uint32 GetId() const
Definition: Map.cpp:3228
char const * GetMapName() const
Definition: Map.cpp:1854
InstanceMap * ToInstanceMap()
Definition: Map.h:454
Corpse * GetCorpseByPlayer(ObjectGuid const &ownerGuid) const
Definition: Map.h:445
uint32 GetInstanceId() const
Definition: Map.h:314
Creature * GetCreature(ObjectGuid const &guid)
Definition: Map.cpp:3479
float GetFollowAngle() const override
void MoveFollow(Unit *target, float dist, ChaseAngle angle, Optional< Milliseconds > duration={}, MovementSlot slot=MOTION_SLOT_ACTIVE)
void MoveFall(uint32 id=0)
void Remove(MovementGenerator *movement, MovementSlot slot=MOTION_SLOT_ACTIVE)
LowType GetCounter() const
Definition: ObjectGuid.h:293
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsEmpty() const
Definition: ObjectGuid.h:319
uint64 GetRawValue(std::size_t i) const
Definition: ObjectGuid.h:282
bool IsItem() const
Definition: ObjectGuid.h:328
std::string ToString() const
Definition: ObjectGuid.cpp:554
void SetRawValue(std::vector< uint8 > const &guid)
Definition: ObjectGuid.cpp:584
uint64 LowType
Definition: ObjectGuid.h:278
bool IsPet() const
Definition: ObjectGuid.h:321
void Clear()
Definition: ObjectGuid.h:286
static std::string_view GetLocaleString(std::vector< std::string > const &data, LocaleConstant locale)
Definition: ObjectMgr.h:1682
static ResponseCodes CheckPlayerName(std::string_view name, LocaleConstant locale, bool create=false)
Definition: ObjectMgr.cpp:8687
Definition: Object.h:150
void SetDynamicFlag(uint32 flag)
Definition: Object.h:169
void BuildValuesUpdateBlockForPlayer(UpdateData *data, Player const *target) const
Definition: Object.cpp:197
uint16 m_objectType
Definition: Object.h:401
static Creature * ToCreature(Object *o)
Definition: Object.h:219
float GetObjectScale() const
Definition: Object.h:164
void ClearDynamicUpdateFieldValues(UF::DynamicUpdateFieldSetter< T > setter)
Definition: Object.h:329
static Unit * ToUnit(Object *o)
Definition: Object.h:225
bool IsDestroyedObject() const
Definition: Object.h:195
static GameObject * ToGameObject(Object *o)
Definition: Object.h:231
ObjectGuid const & GetGUID() const
Definition: Object.h:160
bool IsInWorld() const
Definition: Object.h:154
UF::UpdateField< UF::ObjectData, 0, TYPEID_OBJECT > m_objectData
Definition: Object.h:267
void RemoveUpdateFieldFlagValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type flag)
Definition: Object.h:301
void SendOutOfRangeForPlayer(Player *target) const
Definition: Object.cpp:244
virtual bool hasQuest(uint32) const
Definition: Object.h:192
bool IsUnit() const
Definition: Object.h:224
TypeID GetTypeId() const
Definition: Object.h:173
virtual void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const
Definition: Object.cpp:137
UF::DynamicUpdateFieldSetter< T >::insert_result AddDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter)
Definition: Object.h:308
virtual void DestroyForPlayer(Player *target) const
Definition: Object.cpp:233
void SetUpdateFieldFlagValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type flag)
Definition: Object.h:294
void SetUpdateFieldValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type value)
Definition: Object.h:287
GameObject * ToGameObject()
Definition: Object.h:233
void ReplaceAllDynamicFlags(uint32 flag)
Definition: Object.h:171
uint32 GetEntry() const
Definition: Object.h:161
UF::UpdateFieldHolder m_values
Definition: Object.h:266
void _Create(ObjectGuid const &guid)
Definition: Object.cpp:101
ByteBuffer & PrepareValuesUpdateBuffer(UpdateData *data) const
Definition: Object.cpp:225
bool IsWorldObject() const
Definition: Object.h:200
void RemoveDynamicUpdateFieldValue(UF::DynamicUpdateFieldSetter< T > setter, uint32 index)
Definition: Object.h:322
void DoWithSuppressingObjectUpdates(Action &&action)
Definition: Object.h:381
virtual void AddToWorld()
Definition: Object.cpp:107
virtual void RemoveFromWorld()
Definition: Object.cpp:124
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
virtual void SetObjectScale(float scale)
Definition: Object.h:165
virtual bool hasInvolvedQuest(uint32) const
Definition: Object.h:193
void SendUpdateToPlayer(Player *player)
Definition: Object.cpp:183
void ForceUpdateFieldChange(UF::UpdateFieldSetter< T > const &)
Definition: Object.h:270
TypeID m_objectTypeId
Definition: Object.h:403
void ApplyModUpdateFieldValue(UF::UpdateFieldSetter< T > setter, typename UF::UpdateFieldSetter< T >::value_type mod, bool apply)
Definition: Object.h:351
static Player * ToPlayer(Object *o)
Definition: Object.h:213
Unit * ToUnit()
Definition: Object.h:227
uint32 GetAura(uint32 petEntry) const
Definition: SpellMgr.h:493
Optional< uint32 > GetCurrentActivePetIndex() const
Definition: PetDefines.h:177
std::array< Optional< PetInfo >, MAX_ACTIVE_PETS > ActivePets
Definition: PetDefines.h:158
void SetCurrentUnslottedPetIndex(uint32 index)
Definition: PetDefines.h:180
std::array< Optional< PetInfo >, MAX_PET_STABLES > StabledPets
Definition: PetDefines.h:159
std::vector< PetInfo > UnslottedPets
Definition: PetDefines.h:160
PetInfo * GetCurrentPet()
Definition: PetDefines.h:162
Optional< uint32 > CurrentPetIndex
Definition: PetDefines.h:157
Definition: Pet.h:40
uint16 GetSpecialization() const
Definition: Pet.h:132
void SetDuration(int32 dur)
Definition: Pet.h:88
bool Create(ObjectGuid::LowType guidlow, Map *map, uint32 Entry, uint32 pet_number)
Definition: Pet.cpp:1673
static void DeleteFromDB(uint32 petNumber)
Definition: Pet.cpp:564
void FillPetInfo(PetStable::PetInfo *petInfo, Optional< ReactStates > forcedReactState={}) const
Definition: Pet.cpp:545
static std::pair< PetStable::PetInfo const *, PetSaveMode > GetLoadPetInfo(PetStable const &stable, uint32 petEntry, uint32 petnumber, Optional< PetSaveMode > slot)
Definition: Pet.cpp:105
void SavePetToDB(PetSaveMode mode)
Definition: Pet.cpp:452
bool LoadPetFromDB(Player *owner, uint32 petEntry, uint32 petnumber, bool current, Optional< PetSaveMode > forcedSlot={})
Definition: Pet.cpp:205
bool IsPermanentPetFor(Player *owner) const
Definition: Pet.cpp:1650
void SetPetExperience(uint32 xp)
Definition: Pet.h:84
bool isTemporarySummoned() const
Definition: Pet.h:54
int32 GetDuration() const
Definition: Pet.h:89
bool isControlled() const
Definition: Pet.h:53
void SetPetNextLevelExperience(uint32 xp)
Definition: Pet.h:85
bool m_removed
Definition: Pet.h:143
void Remove(PetSaveMode mode, bool returnreagent=false)
Definition: Pet.cpp:712
void InitPetCreateSpells()
Definition: Pet.cpp:1596
PetSpellMap m_spells
Definition: Pet.h:127
static void OnAreaChange(WorldObject *object)
static bool InDbPhaseShift(WorldObject const *object, uint8 phaseUseFlags, uint16 phaseId, uint32 phaseGroupId)
static void InheritPhaseShift(WorldObject *target, WorldObject const *source)
static void OnMapChange(WorldObject *object)
static bool OnConditionChange(WorldObject *object, bool updateVisibility=true)
static PhaseShift const & GetEmptyPhaseShift()
static void SetAlwaysVisible(WorldObject *object, bool apply, bool updateVisibility)
void SendSocialList(Player *player, uint32 flags)
Definition: SocialMgr.cpp:141
std::string SaveTaxiDestinationsToString()
Definition: PlayerTaxi.cpp:183
void AddTaxiDestination(uint32 dest)
Definition: PlayerTaxi.h:71
void SetFlightMasterFactionTemplateId(uint32 factionTemplateId)
Definition: PlayerTaxi.h:84
uint32 GetTaxiSource() const
Definition: PlayerTaxi.h:72
bool LoadTaxiDestinationsFromString(std::string const &values, uint32 team)
Definition: PlayerTaxi.cpp:136
bool empty() const
Definition: PlayerTaxi.h:82
bool LoadTaxiMask(std::string const &data)
Definition: PlayerTaxi.cpp:100
uint32 GetTaxiDestination() const
Definition: PlayerTaxi.h:73
void ClearTaxiDestinations()
Definition: PlayerTaxi.h:70
uint32 GetCurrentTaxiPath() const
Definition: PlayerTaxi.cpp:199
std::unique_ptr< QuestObjectiveCriteriaMgr > m_questObjectiveCriteriaMgr
Definition: Player.h:3196
uint32 manaBeforeDuel
Definition: Player.h:3212
bool m_bCanDelayTeleport
Definition: Player.h:3183
void LearnSpell(uint32 spell_id, bool dependent, int32 fromSkill=0, bool suppressMessaging=false, Optional< int32 > traitDefinitionId={})
Definition: Player.cpp:3216
void ContinueTaxiFlight() const
Definition: Player.cpp:22722
void SetSemaphoreTeleportNear(bool semphsetting)
Definition: Player.h:2223
void AutoStoreLoot(uint8 bag, uint8 slot, uint32 loot_id, LootStore const &store, ItemContext context=ItemContext::NONE, bool broadcast=false, bool createdByPlayer=false)
Definition: Player.cpp:26395
void StopCastingBindSight() const
Definition: Player.cpp:26129
bool IsValidPos(uint16 pos, bool explicit_pos) const
Definition: Player.h:1374
void AddNewMailDeliverTime(time_t deliver_time)
Definition: Player.cpp:2667
void SendMovieStart(uint32 movieId)
Definition: Player.cpp:6338
void SendLootError(ObjectGuid const &lootObj, ObjectGuid const &owner, LootError error) const
Definition: Player.cpp:9148
bool IsAtRecruitAFriendDistance(WorldObject const *pOther) const
Definition: Player.cpp:25688
uint8 GetStartLevel(uint8 race, uint8 playerClass, Optional< int32 > characterTemplateId) const
Definition: Player.cpp:23690
void UpdateParryPercentage()
Definition: StatSystem.cpp:655
ChrSpecialization GetPrimarySpecialization() const
Definition: Player.h:1841
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition: Player.cpp:13254
void _SaveStoredAuraTeleportLocations(CharacterDatabaseTransaction trans)
Definition: Player.cpp:21127
void SendMirrorTimer(MirrorTimerType Type, uint32 MaxValue, uint32 CurrentValue, int32 Regen)
Definition: Player.cpp:610
InstanceTimeMap _instanceResetTimes
Definition: Player.h:3200
bool m_canParry
Definition: Player.h:3098
void SendQuestConfirmAccept(Quest const *quest, Player *receiver) const
Definition: Player.cpp:17265
void SendMessageToSetInRange(WorldPacket const *data, float dist, bool self) const override
Definition: Player.cpp:6292
void CleanupChannels()
Definition: Player.cpp:4910
void SetWatchedFactionIndex(int32 index)
Definition: Player.h:2840
void UpdateMastery()
Definition: StatSystem.cpp:537
ItemMap mMitems
Definition: Player.h:1780
time_t m_summon_expire
Definition: Player.h:3119
void KilledMonsterCredit(uint32 entry, ObjectGuid guid=ObjectGuid::Empty)
Definition: Player.cpp:16680
void SetTraitConfigUseStarterBuild(int32 traitConfigId, bool useStarterBuild)
Definition: Player.cpp:28484
MapReference m_mapRef
Definition: Player.h:3166
WorldLocation m_summon_location
Definition: Player.h:3120
uint32 GetHonorLevel() const
Definition: Player.h:2276
void UpdateArmorPenetration(int32 amount)
Definition: StatSystem.cpp:755
void CheckAreaExploreAndOutdoor(void)
Definition: Player.cpp:6346
void SendInitialPacketsAfterAddToMap()
Definition: Player.cpp:24316
void SendPlayerBound(ObjectGuid const &binderGuid, uint32 areaId) const
Definition: Player.cpp:17607
void SendKnownSpells()
Definition: Player.cpp:2580
uint32 GetXP() const
Definition: Player.h:1196
static Team TeamForRace(uint8 race)
Definition: Player.cpp:6454
int64 GetQuestSlotEndTime(uint16 slot) const
Definition: Player.cpp:16458
static TeamId TeamIdForRace(uint8 race)
Definition: Player.cpp:6471
void _LoadDeclinedNames(PreparedQueryResult result)
Definition: Player.cpp:17414
std::array< int32, MAX_TIMERS > m_MirrorTimer
Definition: Player.h:3171
void RemoveActionButton(uint8 button)
Definition: Player.cpp:6249
bool AddPvpTalent(PvpTalentEntry const *talent, uint8 activeTalentGroup, uint8 slot)
Definition: Player.cpp:26964
void SetInventorySlotCount(uint8 slots)
Definition: Player.cpp:9846
void ActivatePvpItemLevels(bool activate)
Definition: Player.h:2561
void SendQuestFailed(uint32 questId, InventoryResult reason=EQUIP_ERR_OK) const
Definition: Player.cpp:17233
bool HaveAtClient(Object const *u) const
Definition: Player.cpp:23726
void ItemRemovedQuestCheck(uint32 entry, uint32 count)
Definition: Player.cpp:16645
void _LoadMail(PreparedQueryResult mailsResult, PreparedQueryResult mailItemsResult, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult, PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult)
Definition: Player.cpp:19225
GroupReference m_originalGroup
Definition: Player.h:3109
bool CanInteractWithQuestGiver(Object *questGiver) const
Definition: Player.cpp:1929
static bool IsEquipmentPos(uint16 pos)
Definition: Player.h:1365
PlayerSpellMap m_spells
Definition: Player.h:3040
void SetClientControl(Unit *target, bool allowMove)
Definition: Player.cpp:25739
void SetSpellModTakingSpell(Spell *spell, bool apply)
Definition: Player.cpp:22381
void _ApplyAllLevelScaleItemMods(bool apply)
Definition: Player.cpp:8986
InventoryResult CanUnequipItem(uint16 src, bool swap) const
Definition: Player.cpp:11127
void ApplyAzeriteEssence(AzeriteItem *item, uint32 azeriteEssenceId, uint32 rank, bool major, bool apply)
Definition: Player.cpp:8557
uint8 GetNumRespecs() const
Definition: Player.h:2837
bool Satisfy(AccessRequirement const *ar, uint32 target_map, TransferAbortParams *params=nullptr, bool report=false)
Definition: Player.cpp:19715
void RemoveAtLoginFlag(AtLoginFlags flags, bool persist=false)
Definition: Player.cpp:27545
void SetTalentResetTime(time_t time_)
Definition: Player.h:1840
bool StoreNewItemInBestSlots(uint32 itemId, uint32 amount, ItemContext context)
Definition: Player.cpp:573
uint32 m_temporaryUnsummonedPetNumber
Definition: Player.h:3189
bool _StoreOrEquipNewItem(uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot, int64 price, ItemTemplate const *pProto, Creature *pVendor, VendorItem const *crItem, bool bStore)
Definition: Player.cpp:22809
QuestStatusMap m_QuestStatus
Definition: Player.h:3027
void ResetSpells(bool myClassOnly=false)
Definition: Player.cpp:24491
void ValidateMovementInfo(MovementInfo *mi)
Definition: Player.cpp:29539
uint32 m_ChampioningFaction
Definition: Player.h:3198
void SendNotifyLootItemRemoved(ObjectGuid lootObj, ObjectGuid owner, uint8 lootListId) const
Definition: Player.cpp:9165
bool InBattlegroundQueueForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25025
UF::PVPInfo const * GetPvpInfoForBracket(int8 bracket) const
Definition: Player.cpp:22494
void _LoadCUFProfiles(PreparedQueryResult result)
Definition: Player.cpp:18530
void ExecutePendingSpellCastRequest()
Definition: Player.cpp:30268
SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType=BASE_ATTACK) const override
Definition: Player.cpp:8202
bool m_bHasDelayedTeleport
Definition: Player.h:3184
void ScheduleDelayedOperation(uint32 operation)
Definition: Player.h:3162
bool m_InstanceValid
Definition: Player.h:2571
void RemoveSpellCategoryCooldownMod(int32 spellCategoryId, int32 mod)
Definition: Player.cpp:29791
void UpdateWarModeAuras()
Definition: Player.cpp:30081
std::unique_ptr< RestMgr > _restMgr
Definition: Player.h:3222
WorldLocation & GetTeleportDest()
Definition: Player.h:2216
bool IsInstanceLoginGameMasterException() const
Definition: Player.cpp:19810
void HandleFall(MovementInfo const &movementInfo)
Definition: Player.cpp:26678
void ApplyItemObtainSpells(Item *item, bool apply)
Definition: Player.cpp:8229
void UpdateBaseModGroup(BaseModGroup modGroup)
Definition: Player.cpp:5107
time_t m_deathExpireTime
Definition: Player.h:3094
int32 GetQuestLevel(Quest const *quest) const
Definition: Player.cpp:14450
void SendItemRetrievalMail(uint32 itemEntry, uint32 count, ItemContext context)
Definition: Player.cpp:28983
void RemoveItemDependentAurasAndCasts(Item *pItem)
Definition: Player.cpp:25528
void OnGossipSelect(WorldObject *source, int32 gossipOptionId, uint32 menuId)
Definition: Player.cpp:14162
Item * StoreNewItem(ItemPosCountVec const &pos, uint32 itemId, bool update, ItemRandomBonusListId randomBonusListId=0, GuidSet const &allowedLooters=GuidSet(), ItemContext context=ItemContext::NONE, std::vector< int32 > const *bonusListIDs=nullptr, bool addToCollection=true)
Definition: Player.cpp:11537
void SetOriginalGroup(Group *group, int8 subgroup=-1)
Definition: Player.cpp:26009
bool HasPvPForcingQuest() const
Definition: Player.cpp:17391
void UpdateNextMailTimeAndUnreads()
Definition: Player.cpp:2648
bool AddItem(uint32 itemId, uint32 count)
Definition: Player.cpp:28631
void UpdateWeaponDependentCritAuras(WeaponAttackType attackType)
Definition: Player.cpp:8255
uint32 GetArenaPersonalRating(uint8 slot) const
Definition: Player.cpp:22486
uint32 GetNextResetTalentsCost() const
Definition: Player.cpp:3496
void SetSkillMaxRank(uint32 pos, uint16 max)
Definition: Player.h:2212
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2160
void UpdateEnchantTime(uint32 time)
Definition: Player.cpp:13437
std::vector< Item * > m_itemUpdateQueue
Definition: Player.h:3022
WorldLocation m_teleport_dest
Definition: Player.h:3176
void ToggleMetaGemsActive(uint8 exceptslot, bool apply)
Definition: Player.cpp:23527
bool ModifyMoney(int64 amount, bool sendError=true)
Definition: Player.cpp:24098
bool IsInFriendlyArea() const
Definition: Player.cpp:29386
void ApplyItemLootedSpell(Item *item, bool apply)
Definition: Player.cpp:8869
bool GetQuestSlotObjectiveFlag(uint16 slot, int8 objectiveIndex) const
Definition: Player.cpp:16463
void AutoUnequipChildItem(Item *parentItem)
Definition: Player.cpp:11948
uint64 healthBeforeDuel
Definition: Player.h:3211
InventoryResult CanEquipItem(uint8 slot, uint16 &dest, Item *pItem, bool swap, bool not_loading=true) const
Definition: Player.cpp:10896
void SetPlayerFlag(PlayerFlags flags)
Definition: Player.h:2738
void SendUnlearnSpells()
Definition: Player.cpp:2602
void SetPartyType(GroupCategory category, uint8 type)
Definition: Player.cpp:26022
void SendLootRelease(ObjectGuid guid) const
Definition: Player.cpp:9106
void InitPrimaryProfessions()
Definition: Player.cpp:24093
uint32 GetCurrencyTrackedQuantity(uint32 id) const
Definition: Player.cpp:7364
void SendDisplayToast(uint32 entry, DisplayToastType type, bool isBonusRoll, uint32 quantity, DisplayToastMethod method, uint32 questId=0, Item *item=nullptr) const
Definition: Player.cpp:30163
void UpdateAverageItemLevelEquipped()
Definition: Player.cpp:30006
void SetBGTeam(Team team)
Definition: Player.cpp:23603
void InitTalentForLevel()
Definition: Player.cpp:2370
void UpdateDodgePercentage()
Definition: StatSystem.cpp:696
void _SaveCustomizations(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20398
bool HasItemFitToSpellRequirements(SpellInfo const *spellInfo, Item const *ignoreItem=nullptr) const
Definition: Player.cpp:25444
uint32 GetFreeInventorySpace() const
Definition: Player.cpp:9621
int32 GetReputation(uint32 factionentry) const
Definition: Player.cpp:28561
void SetArenaFaction(uint8 arenaFaction)
Definition: Player.h:2778
int32 FindEmptyProfessionSlotFor(uint32 skillId) const
Definition: Player.cpp:24767
static void DeleteOldCharacters()
Definition: Player.cpp:4310
void _LoadGlyphs(PreparedQueryResult result)
Definition: Player.cpp:27578
static Item * _LoadMailedItem(ObjectGuid const &playerGuid, Player *player, uint64 mailId, Mail *mail, Field *fields, ItemAdditionalLoadInfo *addionalData)
Definition: Player.cpp:19158
uint32 GetItemCountWithLimitCategory(uint32 limitCategory, Item *skipItem=nullptr) const
Definition: Player.cpp:9537
void _LoadBGData(PreparedQueryResult result)
Definition: Player.cpp:17537
uint16 GetQuestSlotCounter(uint16 slot, uint8 counter) const
Definition: Player.cpp:16451
InventoryResult CanRollNeedForItem(ItemTemplate const *item, Map const *map, bool restrictOnlyLfg) const
Definition: Player.cpp:11493
InventoryResult CanEquipNewItem(uint8 slot, uint16 &dest, uint32 item, bool swap) const
Definition: Player.cpp:10882
bool CanEnableWarModeInArea() const
Definition: Player.cpp:30060
bool IsBeingTeleportedFar() const
Definition: Player.h:2221
void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1) override
Definition: Player.cpp:5052
std::vector< uint32 > GetCompletedAchievementIds() const
Definition: Player.cpp:26746
std::unordered_map< ObjectGuid, Loot * > m_AELootView
Definition: Player.h:3218
PlayerSocial * GetSocial() const
Definition: Player.h:1163
static uint32 GetZoneIdFromDB(ObjectGuid guid)
Definition: Player.cpp:7445
UF::UpdateField< UF::PlayerData, 0, TYPEID_PLAYER > m_playerData
Definition: Player.h:2863
void SendAttackSwingCancelAttack() const
Definition: Player.cpp:21294
void _LoadInventory(PreparedQueryResult result, PreparedQueryResult artifactsResult, PreparedQueryResult azeriteResult, PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult, uint32 timeDiff)
Definition: Player.cpp:18777
std::array< int16, MAX_COMBAT_RATING > m_baseRatingValue
Definition: Player.h:3053
void SetPlayerLocalFlag(PlayerLocalFlags flags)
Definition: Player.h:2833
void UpdateLocalChannels(uint32 newZone)
Definition: Player.cpp:4926
bool CanCompleteQuest(uint32 quest_id, uint32 ignoredQuestObjectiveId=0)
Definition: Player.cpp:14656
void _ApplyItemBonuses(Item *item, uint8 slot, bool apply)
Definition: Player.cpp:7900
void RemovePlayerFlag(PlayerFlags flags)
Definition: Player.h:2739
uint32 m_lastFallTime
Definition: Player.h:3168
ItemDurationList m_itemDuration
Definition: Player.h:3062
void UpdateContestedPvP(uint32 currTime)
Definition: Player.cpp:21464
std::unique_ptr< Garrison > _garrison
Definition: Player.h:3206
void AddPetToUpdateFields(PetStable::PetInfo const &pet, PetSaveMode slot, PetStableFlags flags)
Definition: Player.cpp:28662
uint32 m_lastPotionId
Definition: Player.h:3042
void ApplyAllAzeriteEmpoweredItemMods(bool apply)
Definition: Player.cpp:9023
void SendRaidGroupOnlyMessage(RaidGroupReason reason, int32 delay) const
Definition: Player.cpp:29832
void GiveLevel(uint8 level)
Definition: Player.cpp:2268
ObjectGuid GetSummonedBattlePetGUID() const
Definition: Player.h:2820
QuestStatusMap & getQuestStatusMap()
Definition: Player.h:1745
void SendUpdateToOutOfRangeGroupMembers()
Definition: Player.cpp:24427
int32 NextGroupUpdateSequenceNumber(GroupCategory category)
Definition: Player.cpp:26039
bool IsInWhisperWhiteList(ObjectGuid guid)
Definition: Player.cpp:29127
void IncompleteQuest(uint32 quest_id)
Definition: Player.cpp:15049
void SetSkillLineId(uint32 pos, uint16 skillLineId)
Definition: Player.h:2208
void Regenerate(Powers power)
Definition: Player.cpp:1694
Creature * GetNPCIfCanInteractWith(ObjectGuid const &guid, NPCFlags npcFlags, NPCFlags2 npcFlags2) const
Definition: Player.cpp:1947
void SetGroupUpdateFlag(uint32 flag)
Definition: Player.h:2614
void SendQuestReward(Quest const *quest, Creature const *questGiver, uint32 xp, bool hideChatMessage) const
Definition: Player.cpp:17190
void SendBindPointUpdate() const
Definition: Player.cpp:17598
uint32 m_titanGripPenaltySpellId
Definition: Player.h:3101
Bag * GetBagByPos(uint8 slot) const
Definition: Player.cpp:9611
void SetSeer(WorldObject *target)
Definition: Player.h:2482
bool CanUseMastery() const
Definition: Player.cpp:29531
Item * GetMItem(ObjectGuid::LowType id)
Definition: Player.cpp:21856
void UpdateWeaponDependentAuras(WeaponAttackType attackType)
Definition: Player.cpp:8292
uint32 EnvironmentalDamage(EnviromentalDamage type, uint32 damage)
Definition: Player.cpp:634
void _LoadVoidStorage(PreparedQueryResult result)
Definition: Player.cpp:18973
void SetGameMaster(bool on)
Definition: Player.cpp:2071
void KillPlayer()
Definition: Player.cpp:4495
bool ForEachItem(ItemSearchLocation location, T callback) const
Iterate over each item in the player storage.
Definition: Player.h:1270
void QuickEquipItem(uint16 pos, Item *pItem)
Definition: Player.cpp:11969
void SetQuestSlotEndTime(uint16 slot, time_t endTime)
Definition: Player.cpp:16540
void CheckTitanGripPenalty()
Definition: Player.cpp:13333
std::string autoReplyMsg
Definition: Player.h:1159
void HandleBaseModFlatValue(BaseModGroup modGroup, float amount, bool apply)
Definition: Player.cpp:5008
uint32 GetTotalPlayedTime() const
Definition: Player.h:1214
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition: Player.cpp:1611
void ApplyRatingMod(CombatRating cr, int32 value, bool apply)
Definition: Player.cpp:5362
void ResetContestedPvP()
Definition: Player.cpp:21475
void SetBattlegroundId(uint32 val, BattlegroundTypeId bgTypeId, BattlegroundQueueTypeId queueId)
Definition: Player.cpp:25030
void LearnQuestRewardedSpells()
Definition: Player.cpp:24681
void _LoadQuestStatusRewarded(PreparedQueryResult result)
Definition: Player.cpp:19416
bool m_MonthlyQuestChanged
Definition: Player.h:3081
bool _advancedCombatLoggingEnabled
Definition: Player.h:3208
void LearnCustomSpells()
Definition: Player.cpp:24542
void SendResetFailedNotify(uint32 mapid) const
Definition: Player.cpp:21334
void DuelComplete(DuelCompleteType type)
Definition: Player.cpp:7741
void UpdateCritPercentage(WeaponAttackType attType)
Definition: StatSystem.cpp:497
uint8 GetDrunkValue() const
Definition: Player.h:2288
LootRoll * GetLootRoll(ObjectGuid const &lootObjectGuid, uint8 lootListId)
Definition: Player.cpp:9046
void SetNativeGender(Gender gender) override
Definition: Player.h:1218
Gender GetNativeGender() const override
Definition: Player.h:1217
void SetTraitConfigUseSharedActionBars(int32 traitConfigId, bool usesSharedActionBars, bool isLastSelectedSavedConfig)
Definition: Player.cpp:28511
void SetRuneCooldown(uint8 index, uint32 cooldown)
Definition: Player.cpp:26335
PlayerSocial * m_social
Definition: Player.h:3105
bool Create(ObjectGuid::LowType guidlow, WorldPackets::Character::CharacterCreateInfo const *createInfo)
Definition: Player.cpp:394
SkillStatusMap mSkillStatus
Definition: Player.h:3034
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
void ApplyArtifactPowers(Item *item, bool apply)
Definition: Player.cpp:8432
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6052
Item * BankItem(ItemPosCountVec const &dest, Item *pItem, bool update)
Definition: Player.cpp:12043
WorldLocation _corpseLocation
Definition: Player.h:3214
void SendResetInstanceFailed(ResetFailedReason reason, uint32 mapID) const
Definition: Player.cpp:21385
ActionButton * AddActionButton(uint8 button, uint64 action, uint8 type)
Definition: Player.cpp:6233
void RemoveTalent(TalentEntry const *talent)
Definition: Player.cpp:2722
void SetAcceptWhispers(bool on)
Definition: Player.h:1177
void DespawnPersonalSummonsForQuest(uint32 questId)
Definition: Player.cpp:16363
std::array< ChatFloodThrottle, ChatFloodThrottle::MAX > m_chatFloodData
Definition: Player.h:3008
void SetEquipmentSet(EquipmentSetInfo::EquipmentSetData const &newEqSet)
Definition: Player.cpp:27381
TimeTracker m_groupUpdateTimer
Definition: Player.h:3139
void SendMailResult(uint64 mailId, MailResponseType mailAction, MailResponseResult mailError, uint32 equipError=0, ObjectGuid::LowType itemGuid=UI64LIT(0), uint32 itemCount=0) const
Definition: Player.cpp:2621
bool GetQuestRewardStatus(uint32 quest_id) const
Definition: Player.cpp:16033
void SendAutoRepeatCancel(Unit *target)
Definition: Player.cpp:21307
void SplitItem(uint16 src, uint16 dst, uint32 count)
Definition: Player.cpp:12647
void AddTemporarySpell(uint32 spellId)
Definition: Player.cpp:3164
bool MeetPlayerCondition(uint32 conditionId) const
Definition: Player.cpp:29377
void DailyReset()
Definition: Player.cpp:24852
void SendCurrencies() const
Send full data about all currencies to client.
Definition: Player.cpp:7037
ObjectGuid::LowType m_GuildIdInvited
Definition: Player.h:3036
void ResurrectUsingRequestData()
Definition: Player.cpp:25700
int32 getMaxTimer(MirrorTimerType timer) const
Definition: Player.cpp:691
time_t m_lastHonorUpdateTime
Definition: Player.h:3001
bool IsWarModeDesired() const
Definition: Player.h:2854
void _SaveMonthlyQuestStatus(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20999
InventoryResult CanEquipUniqueItem(Item *pItem, uint8 except_slot=NULL_SLOT, uint32 limit_count=1) const
Definition: Player.cpp:26613
uint32 DoRandomRoll(uint32 minimum, uint32 maximum)
Definition: Player.cpp:29841
uint32 GetPowerIndex(Powers power) const override
Definition: StatSystem.cpp:322
void ApplySpellMod(SpellInfo const *spellInfo, SpellModOp op, T &basevalue, Spell *spell=nullptr) const
Definition: Player.cpp:22261
uint16 FindQuestSlot(uint32 quest_id) const
Definition: Player.cpp:16432
void _SaveTalents(CharacterDatabaseTransaction trans)
Definition: Player.cpp:27788
void UpdateDuelFlag(time_t currTime)
Definition: Player.cpp:21499
void MoneyChanged(uint64 value)
Definition: Player.cpp:16719
void _SaveGlyphs(CharacterDatabaseTransaction trans) const
Definition: Player.cpp:27601
InventoryResult CanEquipChildItem(Item *parentItem) const
Definition: Player.cpp:11087
Item * GetUseableItemByPos(uint8 bag, uint8 slot) const
Definition: Player.cpp:9599
void SetSkillPermBonus(uint32 pos, uint16 bonus)
Definition: Player.h:2214
bool AddSpell(uint32 spellId, bool active, bool learning, bool dependent, bool disabled, bool loading=false, int32 fromSkill=0, bool favorite=false, Optional< int32 > traitDefinitionId={})
Definition: Player.cpp:2765
void SetCanParry(bool value)
Definition: Player.cpp:26103
PetStable & GetOrInitPetStable()
Definition: Player.cpp:28654
void SetInvSlot(uint32 slot, ObjectGuid guid)
Definition: Player.h:1454
float GetRatingBonusValue(CombatRating cr) const
Definition: Player.cpp:5286
void UpdatePotionCooldown(Spell *spell=nullptr)
Definition: Player.cpp:23374
UF::TraitConfig const * GetTraitConfig(int32 configId) const
Definition: Player.cpp:28247
Item * GetChildItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9695
void UpdateQuestObjectiveProgress(QuestObjectiveType objectiveType, int32 objectId, int64 addCount, ObjectGuid victimGuid=ObjectGuid::Empty, std::vector< QuestObjective const * > *updatedObjectives=nullptr, std::function< bool(QuestObjective const *)> const *objectiveFilter=nullptr)
Definition: Player.cpp:16738
bool CanTameExoticPets() const
Definition: Player.h:2305
uint32 _activeCheats
Definition: Player.h:3204
uint32 GetRuneBaseCooldown() const
Definition: Player.cpp:26313
Difficulty m_legacyRaidDifficulty
Definition: Player.h:3011
InventoryResult CanStoreItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap=false) const
Definition: Player.cpp:10037
void EnablePetControlsOnDismount()
Definition: Player.cpp:27143
bool IsFriendlyArea(AreaTableEntry const *inArea) const
Definition: Player.cpp:29393
void CharmSpellInitialize()
Definition: Player.cpp:21991
void SaveInventoryAndGoldToDB(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20364
void ReputationChanged(FactionEntry const *factionEntry, int32 change)
Definition: Player.cpp:16724
void _SaveCurrency(CharacterDatabaseTransaction trans)
Definition: Player.cpp:6994
bool isAllowedToLoot(Creature const *creature) const
Definition: Player.cpp:18565
void FailQuestsWithFlag(QuestFlags flag)
Definition: Player.cpp:15494
void CreateGarrison(uint32 garrSiteId)
Definition: Player.cpp:29216
void _LoadSeasonalQuestStatus(PreparedQueryResult result)
Definition: Player.cpp:19534
void SetNoRegentCostMask(flag128 mask)
Definition: Player.h:1383
GuidSet m_refundableItems
Definition: Player.h:3151
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition: Player.cpp:9888
void SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value)
Definition: Player.cpp:7435
bool CanJoinConstantChannelInZone(ChatChannelsEntry const *channel, AreaTableEntry const *zone) const
Definition: Player.cpp:4880
uint8 m_MirrorTimerFlags
Definition: Player.h:3172
void AddMItem(Item *it)
Definition: Player.cpp:21862
void UpdateVersatilityDamageDone()
Definition: StatSystem.cpp:572
uint32 m_atLoginFlags
Definition: Player.h:3013
Pet * SummonPet(uint32 entry, Optional< PetSaveMode > slot, float x, float y, float z, float ang, uint32 despwtime, bool *isNew=nullptr)
Definition: Player.cpp:29444
void Update(uint32 time) override
Definition: Player.cpp:922
void SetGroup(Group *group, int8 subgroup=-1)
Definition: Player.cpp:24188
PartyResult CanUninviteFromGroup(ObjectGuid guidMember, Optional< uint8 > partyIndex) const
Definition: Player.cpp:25920
bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, TeleportToOptions options=TELE_TO_NONE, Optional< uint32 > instanceId={})
Definition: Player.cpp:1250
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition: Player.cpp:386
bool HasCurrency(uint32 id, uint32 amount) const
Definition: Player.cpp:7413
void UpdateCorruption()
Definition: StatSystem.cpp:728
uint32 m_ExtraFlags
Definition: Player.h:3025
void SetCanTitanGrip(bool value, uint32 penaltySpellId=0)
Definition: Player.cpp:13324
void SendProficiency(ItemClass itemClass, uint32 itemSubclassMask) const
Definition: Player.cpp:22444
float GetTotalBaseModValue(BaseModGroup modGroup) const
Definition: Player.cpp:5133
void EnablePvpRules(bool dueToCombat=false)
Definition: Player.cpp:27040
bool SatisfyQuestExclusiveGroup(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15860
void SendTalentsInfoData()
Definition: Player.cpp:27287
void ApplyTraitConfig(int32 configId, bool apply)
Definition: Player.cpp:28455
GameObject * GetGameObjectIfCanInteractWith(ObjectGuid const &guid) const
Definition: Player.cpp:2004
DFQuestsDoneList m_DFQuests
Definition: Player.h:2540
void UpdatePvPState(bool onlyFFA=false)
Definition: Player.cpp:23317
void SetHonorLevel(uint8 honorLevel)
Definition: Player.cpp:6945
void DurabilityLossAll(double percent, bool inventory)
Definition: Player.cpp:4611
void AddHonorXP(uint32 xp)
Definition: Player.cpp:6921
void UpdateBlockPercentage()
Definition: StatSystem.cpp:478
uint8 m_movementForceModMagnitudeChanges
Definition: Player.h:2530
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition: Player.cpp:26192
bool IsInvitedForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25017
void DisablePetControlsOnMount(ReactStates reactState, CommandStates commandState)
Definition: Player.cpp:27122
uint32 m_ingametime
Definition: Player.h:2918
bool HasQuestForItem(uint32 itemId) const
Definition: Player.cpp:16900
void _LoadTraits(PreparedQueryResult configsResult, PreparedQueryResult entriesResult)
Definition: Player.cpp:27648
void DurabilityRepair(uint16 pos, bool takeCost, float discountMod)
Definition: Player.cpp:4802
uint32 GetCurrencyWeeklyQuantity(uint32 id) const
Definition: Player.cpp:7355
static void OfflineResurrect(ObjectGuid const &guid, CharacterDatabaseTransaction trans)
Definition: Player.cpp:4529
void _SaveDailyQuestStatus(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20906
bool m_WeeklyQuestChanged
Definition: Player.h:3080
bool HasPvpRulesEnabled() const
Definition: Player.cpp:27080
QuestObjective const * GetQuestObjectiveForItem(uint32 itemId, bool onlyIncomplete) const
Definition: Player.cpp:16941
void SetQuestCompletedBit(uint32 questBit, bool completed)
Definition: Player.cpp:16561
std::unordered_map< uint32, uint32 > m_recentInstances
Definition: Player.h:2584
void _ApplyWeaponDamage(uint8 slot, Item *item, bool apply)
Definition: Player.cpp:8154
void LeaveLFGChannel()
Definition: Player.cpp:4996
bool SatisfyQuestMinLevel(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15556
uint8 GetBankBagSlotCount() const
Definition: Player.h:1378
void SetBattlegroundEntryPoint()
Definition: Player.cpp:23560
bool InBattleground() const
Definition: Player.h:2394
void SendPlayerChoice(ObjectGuid sender, int32 choiceId)
Definition: Player.cpp:29251
void ApplySpellPenetrationBonus(int32 amount, bool apply)
Definition: StatSystem.cpp:229
InventoryResult CanStoreItems(Item **items, int count, uint32 *offendingItemId) const
Definition: Player.cpp:10668
uint32 m_sharedQuestId
Definition: Player.h:2917
void _ApplyItemMods(Item *item, uint8 slot, bool apply, bool updateItemAuras=true)
Definition: Player.cpp:7865
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition: Player.cpp:4709
uint8 GetItemLimitCategoryQuantity(ItemLimitCategoryEntry const *limitEntry) const
Definition: Player.cpp:29878
void _SaveSpells(CharacterDatabaseTransaction trans)
Definition: Player.cpp:21073
void GiveXP(uint32 xp, Unit *victim, float group_rate=1.0f)
Definition: Player.cpp:2210
uint8 unReadMails
Definition: Player.h:1775
void SetResurrectRequestData(WorldObject const *caster, uint32 health, uint32 mana, uint32 appliedAura)
Definition: Player.cpp:23402
void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type)
Definition: Player.cpp:7439
void CompletedAchievement(AchievementEntry const *entry)
Definition: Player.cpp:26784
void GetSpellModValues(SpellInfo const *spellInfo, SpellModOp op, Spell *spell, T base, int32 *flat, float *pct) const
Definition: Player.cpp:22085
void SendQuestComplete(uint32 questId) const
Definition: Player.cpp:17180
void RemoveSocial()
Definition: Player.cpp:29816
uint32 m_movie
Definition: Player.h:3075
void SendDungeonDifficulty(int32 forcedDifficulty=-1) const
Definition: Player.cpp:21319
void _LoadAuras(PreparedQueryResult auraResult, PreparedQueryResult effectResult, uint32 timediff)
Definition: Player.cpp:18636
void SetRegularAttackTime()
Definition: Player.cpp:5514
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::UnitData::Mask const &requestedUnitMask, UF::PlayerData::Mask const &requestedPlayerMask, UF::ActivePlayerData::Mask const &requestedActivePlayerMask, Player const *target) const
Definition: Player.cpp:3705
void SetGroupInvite(Group *group)
Definition: Player.h:2605
uint32 m_DelayedOperations
Definition: Player.h:3182
void PushQuests()
Definition: Player.cpp:18518
void _LoadTalents(PreparedQueryResult result)
Definition: Player.cpp:27623
Item * GetItemByEntry(uint32 entry, ItemSearchLocation where=ItemSearchLocation::Default) const
Definition: Player.cpp:12589
bool HasPvpTalent(uint32 talentID, uint8 activeTalentGroup) const
Definition: Player.cpp:27035
void RemoveItemFromBuyBackSlot(uint32 slot, bool del)
Definition: Player.cpp:13221
QuestSet m_timedquests
Definition: Player.h:2911
void SpawnCorpseBones(bool triggerSave=true)
Definition: Player.cpp:4598
void UpdateZone(uint32 newZone, uint32 newArea)
Definition: Player.cpp:7549
void TalkedToCreature(uint32 entry, ObjectGuid guid)
Definition: Player.cpp:16709
void SetDrunkValue(uint8 newDrunkValue, uint32 itemId=0)
Definition: Player.cpp:887
TalentLearnResult LearnTalent(uint32 talentId, int32 *spellOnCooldown)
Definition: Player.cpp:26794
void SetMonthlyQuestStatus(uint32 quest_id)
Definition: Player.cpp:24846
void SendPreparedGossip(WorldObject *source)
Definition: Player.cpp:14137
bool CanSeeStartQuest(Quest const *quest) const
Definition: Player.cpp:14606
bool SatisfyQuestDependentPreviousQuests(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15633
void OnPhaseChange() override
Definition: Player.cpp:30116
bool HasItemOrGemWithIdEquipped(uint32 item, uint32 count, uint8 except_slot=NULL_SLOT) const
Definition: Player.cpp:9907
std::vector< uint32 > const & GetGlyphs(uint8 spec) const
Definition: Player.h:1877
void AddRefundReference(ObjectGuid it)
Definition: Player.cpp:28571
bool IsSpellFitByClassAndRace(uint32 spell_id) const
Definition: Player.cpp:25155
float GetReputationPriceDiscount(Creature const *creature) const
Definition: Player.cpp:25133
void BuildValuesUpdateWithFlag(ByteBuffer *data, UF::UpdateFieldFlag flags, Player const *target) const override
Definition: Player.cpp:3684
Item * EquipNewItem(uint16 pos, uint32 item, ItemContext context, bool update)
Definition: Player.cpp:11741
void RemoveFromBattlegroundOrBattlefieldRaid()
Definition: Player.cpp:25997
void SetSelection(ObjectGuid const &guid)
Used for serverside target changes, does not apply to players.
Definition: Player.h:1754
bool IsPetNeedBeTemporaryUnsummoned() const
Definition: Player.cpp:27228
PetStable * GetPetStable()
Definition: Player.h:1222
void SetRaidDifficultyID(Difficulty raid_difficulty)
Definition: Player.h:2016
void LoadActions(PreparedQueryResult result)
Definition: Player.cpp:28188
Group * GetOriginalGroup() const
Definition: Player.h:2625
void PetSpellInitialize()
Definition: Player.cpp:21879
QuestSet m_weeklyquests
Definition: Player.h:2912
ObjectGuid const & GetLootGUID() const
Definition: Player.h:2091
void SetLootGUID(ObjectGuid const &guid)
Definition: Player.h:2092
void AddInstanceEnterTime(uint32 instanceId, time_t enterTime)
Definition: Player.cpp:19861
SceneMgr & GetSceneMgr()
Definition: Player.h:2715
void DeleteTraitConfig(int32 deletedConfigId)
Definition: Player.cpp:28438
bool IsMaxLevel() const
Definition: Player.cpp:2365
void SetSeasonalQuestStatus(uint32 quest_id)
Definition: Player.cpp:24836
bool SatisfyQuestDay(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15905
void UpdateEquipSpellsAtFormChange()
Definition: Player.cpp:8394
uint32 GetBaseSpellPowerBonus() const
Returns base spellpower bonus from spellpower stat on items, without spellpower from intellect stat.
Definition: Player.h:2065
void LeaveBattleground(bool teleportToEntryPoint=true)
Definition: Player.cpp:23614
GuidUnorderedSet m_clientGUIDs
Definition: Player.h:2509
uint32 GetQuestXPReward(Quest const *quest)
Definition: Player.cpp:15066
void SetFallInformation(uint32 time, float z)
Definition: Player.cpp:26672
void DurabilityRepairAll(bool takeCost, float discountMod, bool guildBank)
Definition: Player.cpp:4718
void SendInitialPacketsBeforeAddToMap()
Definition: Player.cpp:24203
SeasonalQuestMapByEvent m_seasonalquests
Definition: Player.h:2914
void RemovePlayerLocalFlag(PlayerLocalFlags flags)
Definition: Player.h:2834
void GroupEventHappens(uint32 questId, WorldObject const *pEventObject)
Definition: Player.cpp:16598
QuestGiverStatus GetQuestDialogStatus(Object const *questGiver) const
Definition: Player.cpp:16194
static void SavePositionInDB(WorldLocation const &loc, uint16 zoneId, ObjectGuid guid, CharacterDatabaseTransaction trans)
Definition: Player.cpp:21279
void DisablePvpRules()
Definition: Player.cpp:27065
TradeData * m_trade
Definition: Player.h:3077
void ApplyEnchantment(Item *item, EnchantmentSlot slot, bool apply, bool apply_dur=true, bool ignore_condition=false)
Definition: Player.cpp:13577
ObjectGuid GetStableMaster() const
Definition: Player.cpp:28834
void UpdateVisibilityOf(WorldObject *target)
Definition: Player.cpp:23902
void SetStableMaster(ObjectGuid stableMaster)
Definition: Player.cpp:28842
QuestObjectiveStatusMap m_questObjectiveStatus
Definition: Player.h:3028
bool IsLoading() const override
Definition: Player.cpp:17613
QuestSet m_monthlyquests
Definition: Player.h:2913
void ActivateTalentGroup(ChrSpecializationEntry const *spec)
Definition: Player.cpp:27923
std::unordered_map< uint32, std::unordered_set< uint32 > > m_overrideSpells
Definition: Player.h:3041
void IncreaseCurrencyCap(uint32 id, uint32 amount)
Increase currency cap.
Definition: Player.cpp:7258
bool HasPendingBind() const
Definition: Player.h:2587
bool UpdateCraftSkill(SpellInfo const *spellInfo)
Definition: Player.cpp:5541
uint32 m_nextSave
Definition: Player.h:3006
void ResetMap() override
Definition: Player.cpp:27560
bool CanAddQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14632
bool CanRewardQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14717
uint32 m_zoneUpdateTimer
Definition: Player.h:3090
bool HasActiveSpell(uint32 spell) const
Definition: Player.cpp:3805
void AddQuest(Quest const *quest, Object *questGiver)
Definition: Player.cpp:14926
uint32 GetBattlegroundQueueJoinTime(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:24984
InventoryResult CanBankItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, Item *pItem, bool swap, bool not_loading=true, bool reagentBankOnly=false) const
Definition: Player.cpp:11172
void _SaveCUFProfiles(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20706
uint8 GetInventorySlotCount() const
Definition: Player.h:1376
void AddItemToBuyBackSlot(Item *pItem)
Definition: Player.cpp:13156
void SendSellError(SellResult msg, Creature *creature, ObjectGuid guid) const
Definition: Player.cpp:13309
void ResetMonthlyQuestStatus()
Definition: Player.cpp:24962
uint32 GetItemCount(uint32 item, bool inBankAlso=false, Item *skipItem=nullptr) const
Definition: Player.cpp:9511
bool m_mailsUpdated
Definition: Player.h:1727
void SetQuestSlotObjectiveFlag(uint16 slot, int8 objectiveIndex)
Definition: Player.cpp:16547
void _LoadSpells(PreparedQueryResult result, PreparedQueryResult favoritesResult)
Definition: Player.cpp:19590
void RewardPlayerWithRewardPack(uint32 rewardPackID)
Definition: Player.cpp:6897
void SendCorpseReclaimDelay(uint32 delay) const
Definition: Player.cpp:25887
void SetTalentResetCost(uint32 cost)
Definition: Player.h:1838
void SetSkill(uint32 id, uint16 step, uint16 newVal, uint16 maxVal)
Definition: Player.cpp:5786
void RecalculateRating(CombatRating cr)
Definition: Player.h:2058
void SendExplorationExperience(uint32 Area, uint32 Experience) const
Definition: Player.cpp:21314
uint8 AddVoidStorageItem(VoidStorageItem &&item)
Definition: Player.cpp:29156
uint32 m_foodEmoteTimerCount
Definition: Player.h:2877
bool IsMercenaryForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25098
void SetPrimarySpecialization(uint32 spec)
Definition: Player.h:1842
bool CheckInstanceCount(uint32 instanceId) const
Definition: Player.cpp:19854
int64 GetBarberShopCost(Trinity::IteratorPair< UF::ChrCustomizationChoice const * > newCustomizations) const
Definition: Player.cpp:26229
void UpdateVisibleObjectInteractions(bool allUnits, bool onlySpellClicks, bool gameObjectQuestGiverStatus, bool questObjectiveGameObjects)
Definition: Player.cpp:25205
static void SaveCustomizations(CharacterDatabaseTransaction trans, ObjectGuid::LowType guid, Trinity::IteratorPair< UF::ChrCustomizationChoice const * > customizations)
Definition: Player.cpp:20392
void SetObjectScale(float scale) override
Definition: Player.cpp:1602
void UpdateTriggerVisibility()
Definition: Player.cpp:23953
Pet * GetPet() const
Definition: Player.cpp:21513
void ApplyAzeritePower(AzeriteEmpoweredItem *item, AzeritePowerEntry const *azeritePower, bool apply)
Definition: Player.cpp:8611
void _LoadArenaTeamInfo(PreparedQueryResult result)
Definition: Player.cpp:17424
WorldLocation m_homebind
Definition: Player.h:2503
void AddEnchantmentDurations(Item *item)
Definition: Player.cpp:13461
std::array< uint32, MAX_PLAYED_TIME_INDEX > m_Played_time
Definition: Player.h:1213
void RemoveTemporarySpell(uint32 spellId)
Definition: Player.cpp:3177
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition: Player.cpp:25673
void KilledMonster(CreatureTemplate const *cInfo, ObjectGuid guid)
Definition: Player.cpp:16668
bool CanTitanGrip() const
Definition: Player.h:2302
time_t GetTalentResetTime() const
Definition: Player.h:1839
void SwapItem(uint16 src, uint16 dst)
Definition: Player.cpp:12763
void _RemoveAllItemMods()
Definition: Player.cpp:8902
bool BuyItemFromVendorSlot(ObjectGuid vendorguid, uint32 vendorslot, uint32 item, uint8 count, uint8 bag, uint8 slot)
Definition: Player.cpp:23034
Guild * GetGuild()
Definition: Player.cpp:29432
void InitDisplayIds()
Definition: Player.cpp:22796
bool HasItemTotemCategory(uint32 TotemCategory) const
Definition: Player.cpp:10045
WorldObject * m_seer
Definition: Player.h:2476
bool HasTitle(uint32 bitIndex) const
Definition: Player.cpp:26268
void LearnSpecializationSpells()
Definition: Player.cpp:29724
std::unordered_map< uint32, StoredAuraTeleportLocation > m_storedAuraTeleportLocations
Definition: Player.h:3043
PlayerCurrenciesMap _currencyStorage
Definition: Player.h:3018
void SetNumRespecs(uint8 numRespecs)
Definition: Player.h:2838
Optional< AttackSwingErr > m_swingErrorMsg
Definition: Player.h:3102
void UpdateSoulboundTradeItems()
Definition: Player.cpp:13396
void ApplyItemDependentAuras(Item *item, bool apply)
Definition: Player.cpp:8299
bool m_SeasonalQuestChanged
Definition: Player.h:3082
void SetCurrentBattlePetBreedQuality(uint8 battlePetBreedQuality)
Definition: Player.h:2781
std::array< float, BASEMOD_END > m_auraBaseFlatMod
Definition: Player.h:3051
void RegenerateHealth()
Definition: Player.cpp:1856
uint16 GetPureSkillValue(uint32 skill) const
Definition: Player.cpp:6108
void ClearUpdateMask(bool remove) override
Definition: Player.cpp:3785
GuidList WhisperList
Definition: Player.h:2874
uint8 GetRunesState() const
Definition: Player.cpp:26308
uint16 GetChatFlags() const
Definition: Player.cpp:1234
friend void RemoveItemFromUpdateQueueOf(Item *item, Player *player)
Definition: Item.cpp:1218
bool IsTwoHandUsed() const
Definition: Player.cpp:13348
void _ApplyAllItemMods()
Definition: Player.cpp:8942
uint32 m_areaUpdateId
Definition: Player.h:3091
void RemoveTradeableItem(Item *item)
Definition: Player.cpp:13414
bool HasAchieved(uint32 achievementId) const
Definition: Player.cpp:26751
void CompleteQuest(uint32 quest_id)
Definition: Player.cpp:15023
bool IsImmuneToEnvironmentalDamage() const
Definition: Player.cpp:628
bool HasTalent(uint32 spell_id, uint8 spec) const
Definition: Player.cpp:3799
Item * _StoreItem(uint16 pos, Item *pItem, uint32 count, bool clone, bool update)
Definition: Player.cpp:11640
void SetCanBlock(bool value)
Definition: Player.cpp:26112
WorldSafeLocsEntry const * GetInstanceEntrance(uint32 targetMapId)
Definition: Player.cpp:19867
void SendRemoveControlBar() const
Definition: Player.cpp:22031
bool InBattlegroundQueue(bool ignoreArena=false) const
Definition: Player.cpp:24992
void RewardQuestPackage(uint32 questPackageId, ItemContext context, uint32 onlyItemId=0)
Definition: Player.cpp:15109
bool GetCommandStatus(uint32 command) const
Definition: Player.h:1206
int16 GetSkillTempBonusValue(uint32 skill) const
Definition: Player.cpp:6132
void SendChatMessageToSetInRange(ChatMsg chatMsg, Language lanugageId, std::string &&text, float range)
Definition: Player.cpp:21728
int16 GetSkillPermBonusValue(uint32 skill) const
Definition: Player.cpp:6120
bool HasSummonPending() const
Definition: Player.cpp:25301
void SendRaidInfo()
Definition: Player.cpp:19688
Item * StoreItem(ItemPosCountVec const &pos, Item *pItem, bool update)
Definition: Player.cpp:11612
WorldSession * GetSession() const
Definition: Player.h:2101
void EquipChildItem(uint8 parentBag, uint8 parentSlot, Item *parentItem)
Definition: Player.cpp:11870
OutdoorPvP * GetOutdoorPvP() const
Definition: Player.cpp:25439
int32 GetQuestObjectiveData(uint32 questId, uint32 objectiveId) const
Definition: Player.cpp:16492
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition: Player.cpp:8622
void UpdateSpellHitChances()
Definition: StatSystem.cpp:771
GroupReference m_group
Definition: Player.h:3108
SpellInfo const * GetCastSpellInfo(SpellInfo const *spellInfo, TriggerCastFlags &triggerFlag) const override
Definition: Player.cpp:29697
void ResurrectUsingRequestDataImpl()
Definition: Player.cpp:25714
ZonePVPTypeOverride GetOverrideZonePVPType() const
Definition: Player.h:1833
std::unique_ptr< ReputationMgr > m_reputationMgr
Definition: Player.h:3195
void DestroyConjuredItems(bool update)
Definition: Player.cpp:12560
bool IsQuestObjectiveCompletable(uint16 slot, Quest const *quest, QuestObjective const &objective) const
Definition: Player.cpp:17032
void UpdateAreaDependentAuras(uint32 area_id)
Definition: Player.cpp:25785
Item * GetItemByPos(uint16 pos) const
Definition: Player.cpp:9582
void outDebugValues() const
Definition: Player.cpp:21207
void _LoadPetStable(uint32 summonedPetNumber, PreparedQueryResult result)
Definition: Player.cpp:29052
bool HasSkill(uint32 skill) const
Definition: Player.cpp:6031
bool IsInvitedForBattlegroundInstance(uint32 instanceId) const
Definition: Player.cpp:25083
void UpdateExpertise(WeaponAttackType attType)
Definition: StatSystem.cpp:777
std::unique_ptr< SpellCastRequest > _pendingSpellCastRequest
Definition: Player.h:3235
uint16 GetReqKillOrCastCurrentCount(uint32 quest_id, int32 entry) const
Definition: Player.cpp:16383
void _ApplyAllStatBonuses()
Definition: StatSystem.cpp:856
uint32 GetSharedQuestID() const
Definition: Player.h:1672
void SetViewpoint(WorldObject *target, bool apply)
Definition: Player.cpp:26139
void StopMirrorTimers()
Definition: Player.cpp:724
void RemoveQuestSlotState(uint16 slot, uint32 state)
Definition: Player.cpp:16533
JoinedChannelsList m_channels
Definition: Player.h:3069
void AdjustQuestObjectiveProgress(Quest const *quest)
Definition: Player.cpp:16400
void UnsummonPetTemporaryIfAny()
Definition: Player.cpp:27165
void _LoadRandomBGStatus(PreparedQueryResult result)
Definition: Player.cpp:29012
void StartCriteria(CriteriaStartEvent startEvent, uint32 entry, Milliseconds timeLost=Milliseconds::zero())
Definition: Player.cpp:26756
void ResetGroupUpdateSequenceIfNeeded(Group const *group)
Definition: Player.cpp:26028
static bool IsAffectedBySpellmod(SpellInfo const *spellInfo, SpellModifier const *mod, Spell *spell=nullptr)
Definition: Player.cpp:22037
uint32 m_oldpetspell
Definition: Player.h:3191
void CheckDuelDistance(time_t currTime)
Definition: Player.cpp:7704
uint32 m_currentBuybackSlot
Definition: Player.h:3016
std::unordered_map< int32, PlayerSpellState > m_traitConfigStates
Definition: Player.h:3047
bool isTotalImmune() const
Definition: Player.cpp:26254
void RemoveBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition: Player.cpp:25061
bool GetsRecruitAFriendBonus(bool forXP)
Definition: Player.cpp:25604
void TogglePvpTalents(bool enable)
Definition: Player.cpp:27012
void SaveRecallPosition()
Definition: Player.h:2491
void UpdatePvPFlag(time_t currTime)
Definition: Player.cpp:21482
void _LoadQuestStatus(PreparedQueryResult result)
Definition: Player.cpp:19282
int32 GetProfessionSlotFor(uint32 skillId) const
Definition: Player.cpp:24754
void ResetHonorStats()
Definition: Player.cpp:6882
void ResetCurrencyWeekCap()
Reset weekly quantity.
Definition: Player.cpp:7323
void BuildValuesUpdate(ByteBuffer *data, Player const *target) const override
Definition: Player.cpp:3662
~Player()
Definition: Player.cpp:361
bool inRandomLfgDungeon() const
Definition: Player.cpp:25976
void KilledPlayerCredit(ObjectGuid victimGuid)
Definition: Player.cpp:16698
uint32 m_deathTimer
Definition: Player.h:3093
uint32 m_regenTimerCount
Definition: Player.h:2876
void RepopAtGraveyard()
Definition: Player.cpp:4832
bool SatisfyQuestLog(bool msg) const
Definition: Player.cpp:15586
float GetBaseModValue(BaseModGroup modGroup, BaseModType modType) const
Definition: Player.cpp:5121
bool ModifierTreeSatisfied(uint32 modifierTreeId) const
Definition: Player.cpp:26789
void _LoadMonthlyQuestStatus(PreparedQueryResult result)
Definition: Player.cpp:19563
void BuildCreateUpdateBlockForPlayer(UpdateData *data, Player *target) const override
Definition: Player.cpp:3614
uint16 GetMaxSkillValue(uint32 skill) const
Definition: Player.cpp:6067
void SendAreaSpiritHealerTime(Unit *spiritHealer) const
Definition: Player.cpp:30146
uint32 GetQuestSlotQuestId(uint16 slot) const
Definition: Player.cpp:16441
bool CanAlwaysSee(WorldObject const *obj) const override
Definition: Player.cpp:23749
void DestroyItem(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12180
std::array< float, MAX_POWERS_PER_CLASS > m_powerFraction
Definition: Player.h:2878
void CurrencyChanged(uint32 currencyId, int32 change)
Definition: Player.cpp:16731
bool IsResurrectRequested() const
Definition: Player.h:1933
uint8 FindEquipSlot(Item const *item, uint32 slot, bool swap) const
Definition: Player.cpp:9223
void SendPvpRewards() const
Send conquest currency points and their cap week/arena.
Definition: Player.cpp:7088
uint16 GetBaseSkillValue(uint32 skill) const
Definition: Player.cpp:6094
bool SatisfyQuestMonth(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15957
Difficulty GetDungeonDifficultyID() const
Definition: Player.h:2012
time_t m_nextMailDelivereTime
Definition: Player.h:1776
TeamId GetTeamId() const
Definition: Player.h:2236
void MoveItemFromInventory(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12134
bool _usePvpItemLevels
Definition: Player.h:3224
PlayerSpellMap const & GetSpellMap() const
Definition: Player.h:1901
void ResetTalentSpecialization()
Definition: Player.cpp:26884
void ApplyAllAzeriteItemMods(bool apply)
Definition: Player.cpp:9009
void SetMercenaryForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, bool mercenary)
Definition: Player.cpp:25091
void _SaveSkills(CharacterDatabaseTransaction trans)
Definition: Player.cpp:21022
void UpdateFallInformationIfNeed(MovementInfo const &minfo, uint16 opcode)
Definition: Player.cpp:27116
void SendRespondInspectAchievements(Player *player) const
Definition: Player.cpp:26736
void SetDelayedTeleportFlag(bool setting)
Definition: Player.h:3161
static bool IsReagentBankPos(uint16 pos)
Definition: Player.h:1370
static bool IsInventoryPos(uint16 pos)
Definition: Player.h:1363
void SetSpellFavorite(uint32 spellId, bool favorite)
Definition: Player.cpp:3468
bool ActivateTaxiPathTo(std::vector< uint32 > const &nodes, Creature *npc=nullptr, uint32 spellid=0, uint32 preferredMountDisplay=0)
Definition: Player.cpp:22506
void SetGMChat(bool on)
Definition: Player.h:1183
void SendLoot(Loot &loot, bool aeLooting=false)
Definition: Player.cpp:9119
bool m_bPassOnGroupLoot
Definition: Player.h:3112
ObjectGuid m_temporaryUnsummonedBattlePet
Definition: Player.h:3192
void WhisperAddon(std::string const &text, std::string const &prefix, bool isLogged, Player *receiver)
Definition: Player.cpp:21769
void UpdateTraitConfig(WorldPackets::Traits::TraitConfig &&newConfig, int32 savedConfigId, bool withCastTime)
Definition: Player.cpp:28256
void SetQuestSlotCounter(uint16 slot, uint8 counter, uint16 count)
Definition: Player.cpp:16516
void SetLegacyRaidDifficultyID(Difficulty raid_difficulty)
Definition: Player.h:2017
bool CanNoReagentCast(SpellInfo const *spellInfo) const
Definition: Player.cpp:25509
void _LoadPvpTalents(PreparedQueryResult result)
Definition: Player.cpp:27635
Item * _LoadItem(CharacterDatabaseTransaction trans, uint32 zoneId, uint32 timeDiff, Field *fields)
Definition: Player.cpp:19030
uint16 GetPureMaxSkillValue(uint32 skill) const
Definition: Player.cpp:6082
void InitDataForForm(bool reapplyMods=false)
Definition: Player.cpp:22772
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
bool HasQuestForGO(int32 goId) const
Definition: Player.cpp:25184
void SetPvP(bool state) override
Definition: Player.cpp:23353
bool CanShareQuest(uint32 questId) const
Definition: Player.cpp:16064
bool m_DailyQuestChanged
Definition: Player.h:3079
void UpdateVisibilityForPlayer()
Definition: Player.cpp:24085
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition: Player.cpp:12281
void ClearResurrectRequestData()
Definition: Player.h:1920
void StopCastingCharm()
Definition: Player.cpp:21677
void AddExploredZones(uint32 pos, uint64 mask)
Definition: Player.cpp:6421
std::string GetCoordsMapAreaAndZoneString() const
Definition: Player.cpp:29425
void SetInGuild(ObjectGuid::LowType guildId)
Definition: Player.cpp:7419
void _SaveEquipmentSets(CharacterDatabaseTransaction trans)
Definition: Player.cpp:27414
bool _LoadHomeBind(PreparedQueryResult result)
Definition: Player.cpp:19894
void AddSpellCategoryCooldownMod(int32 spellCategoryId, int32 mod)
Definition: Player.cpp:29766
void SetSemaphoreTeleportFar(bool semphsetting)
Definition: Player.h:2224
bool CanRequestSpellCast(SpellInfo const *spell, Unit const *castingUnit) const
Definition: Player.cpp:30255
Difficulty m_dungeonDifficulty
Definition: Player.h:3009
uint32 m_weaponChangeTimer
Definition: Player.h:3087
void ResummonBattlePetTemporaryUnSummonedIfAny()
Definition: Player.cpp:27214
std::unordered_map< ObjectGuid, Loot * > const & GetAELootView() const
Definition: Player.h:2094
bool SatisfyQuestConditions(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15829
WorldObject * GetViewpoint() const
Definition: Player.cpp:26184
uint32 m_WeaponProficiency
Definition: Player.h:3096
bool mSemaphoreTeleport_Far
Definition: Player.h:3180
void UpdateCorpseReclaimDelay()
Definition: Player.cpp:25822
void RemovePet(Pet *pet, PetSaveMode mode, bool returnreagent=false)
Definition: Player.cpp:21537
void UpdateHealingDonePercentMod()
Definition: StatSystem.cpp:583
int32 CalculateReputationGain(ReputationSource source, uint32 creatureOrQuestLevel, int32 rep, int32 faction, bool noQuestBonus=false)
Definition: Player.cpp:6504
uint32 GetRuneCooldown(uint8 index) const
Definition: Player.h:2643
void DeleteVoidStorageItem(uint8 slot)
Definition: Player.cpp:29170
VoidStorageItem * _voidStorageItems[VOID_STORAGE_MAX_SLOT]
Definition: Player.h:3020
void UpdateItemDuration(uint32 time, bool realtimeonly=false)
Definition: Player.cpp:13419
void SetActiveCombatTraitConfigID(int32 traitConfigId)
Definition: Player.h:1893
time_t m_createTime
Definition: Player.h:3071
uint32 m_hostileReferenceCheckTimer
Definition: Player.h:3085
float GetRatingMultiplier(CombatRating cr) const
Definition: Player.cpp:5273
WorldLocation GetCorpseLocation() const
Definition: Player.h:2164
void SendTameFailure(PetTameResult result)
Definition: Player.cpp:21629
bool TeleportToBGEntryPoint()
Definition: Player.cpp:1496
void ReplaceAllPlayerFlagsEx(PlayerFlagsEx flags)
Definition: Player.h:2745
void ApplyAzeriteItemMilestonePower(AzeriteItem *item, AzeriteItemMilestonePowerEntry const *azeriteItemMilestonePower, bool apply)
Definition: Player.cpp:8542
uint32 GetDefaultSpecId() const
Definition: Player.cpp:29822
void MoveItemToInventory(ItemPosCountVec const &dest, Item *pItem, bool update, bool in_characterInventoryDB=false)
Definition: Player.cpp:12152
bool SatisfyQuestSeasonal(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15930
void ApplyManaRegenBonus(int32 amount, bool apply)
Definition: StatSystem.cpp:806
uint8 GetNumOfVoidStorageFreeSlots() const
Definition: Player.cpp:29145
Quest const * GetNextQuest(Object const *questGiver, Quest const *quest) const
Definition: Player.cpp:14580
void InitTaxiNodesForLevel()
Definition: Player.h:1167
ActionButton const * GetActionButton(uint8 button)
Definition: Player.cpp:6264
bool IsQuestObjectiveProgressBarComplete(uint16 slot, Quest const *quest) const
Definition: Player.cpp:17165
bool IsUsingTwoHandedWeaponInOneHand() const
Definition: Player.cpp:13360
void _SaveMail(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20742
bool IsHasDelayedTeleport() const
Definition: Player.h:3160
void _LoadSkills(PreparedQueryResult result)
Definition: Player.cpp:26483
void StoreLootItem(ObjectGuid lootWorldObjectGuid, uint8 lootSlot, Loot *loot, AELootResult *aeResult=nullptr)
Definition: Player.cpp:26403
bool HasExploredZone(uint32 areaId) const
Definition: Player.cpp:6437
std::array< float, BASEMOD_END > m_auraBasePctMod
Definition: Player.h:3052
static bool IsChildEquipmentPos(uint16 pos)
Definition: Player.h:1372
bool CanJoinToBattleground(BattlegroundTemplate const *bg) const
Definition: Player.cpp:23638
std::string GetGuildName() const
Definition: Player.cpp:28566
bool SatisfyQuestRace(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15758
void SetDailyQuestStatus(uint32 quest_id)
Definition: Player.cpp:24806
void GetDodgeFromAgility(float &diminishing, float &nondiminishing) const
Definition: Player.cpp:5145
Corpse * GetCorpse() const
Definition: Player.cpp:4606
void SetBaseModPctValue(BaseModGroup modGroup, float val)
Definition: Player.cpp:5043
bool m_IsBGRandomWinner
Definition: Player.h:2899
bool SatisfyQuestClass(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15736
void ConfirmPendingBind()
Definition: Player.cpp:19672
void ApplyTraitEntry(int32 traitNodeEntryId, int32 rank, int32 grantedRanks, bool apply)
Definition: Player.cpp:28465
void DurabilityLoss(Item *item, double percent)
Definition: Player.cpp:4635
uint8 GetNextVoidStorageFreeSlot() const
Definition: Player.cpp:29136
bool SatisfyQuestReputation(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15774
std::vector< Item * > GetCraftingReagentItemsToDeposit()
Definition: Player.cpp:9552
void SendBuyError(BuyResult msg, Creature *creature, uint32 item, uint32 param) const
Definition: Player.cpp:13300
ObjectGuid _areaSpiritHealerGUID
Definition: Player.h:3225
Item * GetShield(bool useable=false) const
Definition: Player.cpp:9675
void SendRespecWipeConfirm(ObjectGuid const &guid, uint32 cost, SpecResetType respecType) const
Definition: Player.cpp:9210
uint32 m_drunkTimer
Definition: Player.h:3086
uint32 GetCurrencyIncreasedCapQuantity(uint32 id) const
Definition: Player.cpp:7373
bool HasFreeBattlegroundQueueId() const
Definition: Player.cpp:25053
bool HasPlayerLocalFlag(PlayerLocalFlags flags) const
Definition: Player.h:2832
void SetBattlePetData(BattlePets::BattlePet const *pet=nullptr)
Definition: Player.cpp:21659
std::unique_ptr< ResurrectionData > _resurrectionData
Definition: Player.h:3065
void SetPersonalTabard(uint32 style, uint32 color, uint32 borderStyle, uint32 borderColor, uint32 backgroundColor)
Definition: Player.cpp:22458
uint8 m_fishingSteps
Definition: Player.h:3135
RewardedQuestSet m_RewardedQuests
Definition: Player.h:3031
void SendInitWorldStates(uint32 zoneId, uint32 areaId)
Definition: Player.cpp:9185
void InitStatsForLevel(bool reapplyMods=false)
Definition: Player.cpp:2404
void HandleSobering()
The player sobers by 1% every 9 seconds.
Definition: Player.cpp:867
void FinishTaxiFlight()
Definition: Player.cpp:22706
Battleground * GetBattleground() const
Definition: Player.cpp:24976
bool AddTalent(TalentEntry const *talent, uint8 spec, bool learning)
Definition: Player.cpp:2688
TeleportToOptions m_teleport_options
Definition: Player.h:3178
uint32 m_contestedPvPTimer
Definition: Player.h:2879
void SetXP(uint32 xp)
Definition: Player.cpp:2197
void SetActiveTalentGroup(uint8 group)
Definition: Player.h:1844
uint32 GetTalentResetCost() const
Definition: Player.h:1837
void ClearSelfResSpell()
Definition: Player.h:2818
bool ProcessItemCast(SpellCastRequest &castRequest, SpellCastTargets const &targets)
Definition: Player.cpp:30371
void _SaveQuestStatus(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20812
Player * GetTrader() const
Definition: Player.cpp:25150
bool IsMirrorTimerActive(MirrorTimerType type) const
Definition: Player.cpp:731
void InitializeSelfResurrectionSpells()
Definition: Player.cpp:25560
void ProcessDelayedOperations()
Definition: Player.cpp:1507
void SetRewardedQuest(uint32 quest_id)
Definition: Player.cpp:15437
uint16 GetSkillStep(uint32 skill) const
Definition: Player.cpp:6040
EnchantDurationList m_enchantDuration
Definition: Player.h:3061
float GetExpertiseDodgeOrParryReduction(WeaponAttackType attType) const
Definition: Player.cpp:5347
TalentLearnResult LearnPvpTalent(uint32 talentID, uint8 slot, int32 *spellOnCooldown)
Definition: Player.cpp:26908
bool SatisfyQuestTimed(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15845
TradeData * GetTradeData() const
Definition: Player.h:1498
void UpdateAllWeaponDependentCritAuras()
Definition: Player.cpp:8286
bool SatisfyQuestMaxLevel(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15571
void _InitHonorLevelOnLoadFromDB(uint32 honor, uint32 honorLevel)
Definition: Player.cpp:6889
void RemoveQuestSlotObjectiveFlag(uint16 slot, int8 objectiveIndex)
Definition: Player.cpp:16554
ObjectGuid::LowType GetGuildId() const
Definition: Player.h:1993
bool UpdatePosition(float x, float y, float z, float orientation, bool teleport=false) override
Definition: Player.cpp:6273
bool IsActiveQuest(uint32 quest_id) const
Definition: Player.cpp:14575
void setDeathState(DeathState s) override
Definition: Player.cpp:1171
bool IsReagentBankUnlocked() const
Definition: Player.h:2705
Group * GetGroup()
Definition: Player.h:2608
void SetQuestSlotState(uint16 slot, uint32 state)
Definition: Player.cpp:16526
void ResetWeeklyQuestStatus()
Definition: Player.cpp:24897
bool IsInAreaTriggerRadius(AreaTriggerEntry const *trigger) const
Definition: Player.cpp:2042
bool RemoveMItem(ObjectGuid::LowType id)
Definition: Player.cpp:21869
std::string GetMapAreaAndZoneString() const
Definition: Player.cpp:29407
void SendRefundInfo(Item *item)
Definition: Player.cpp:28583
void AutoUnequipOffhandIfNeed(bool force=false)
Definition: Player.cpp:25403
void RemovePvpTalent(PvpTalentEntry const *talent, uint8 activeTalentGroup)
Definition: Player.cpp:26994
bool isGMChat() const
Definition: Player.h:1182
bool IsGroupVisibleFor(Player const *p) const
Definition: Player.cpp:2142
void UpdateItemLevelAreaBasedScaling()
Definition: Player.cpp:29861
uint32 GetFreeInventorySlotCount(EnumFlag< ItemSearchLocation > location=ItemSearchLocation::Inventory) const
Definition: Player.cpp:9426
void SetBaseModFlatValue(BaseModGroup modGroup, float val)
Definition: Player.cpp:5034
void SetMovie(uint32 movie)
Definition: Player.h:1943
void AtEnterCombat() override
Definition: Player.cpp:26078
bool CanBeGameMaster() const
Definition: Player.cpp:2116
void RequestSpellCast(std::unique_ptr< SpellCastRequest > castRequest)
Definition: Player.cpp:30224
bool IsDailyQuestDone(uint32 quest_id) const
Definition: Player.cpp:24825
void RemoveEnchantmentDurations(Item *item)
Definition: Player.cpp:13474
uint32 m_baseSpellPower
Definition: Player.h:3054
void ItemAddedQuestCheck(uint32 entry, uint32 count, Optional< bool > boundItemFlagRequirement={}, bool *hadBoundItemObjective=nullptr)
Definition: Player.cpp:16624
void UpdateMaxHealth() override
Definition: StatSystem.cpp:310
bool IsGameMaster() const
Definition: Player.h:1178
void InitPvP()
Definition: Player.cpp:23310
void SetPendingBind(uint32 instanceId, uint32 bindTimer)
Definition: Player.cpp:19682
void AddSelfResSpell(int32 spellId)
Definition: Player.h:2811
void CastItemUseSpell(Item *item, SpellCastTargets const &targets, ObjectGuid castCount, int32 *misc)
Definition: Player.cpp:8799
void _LoadStoredAuraTeleportLocations(PreparedQueryResult result)
Definition: Player.cpp:19611
void UpdateMeleeHitChances()
Definition: StatSystem.cpp:761
void LoadCorpse(PreparedQueryResult result)
Definition: Player.cpp:18754
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const override
Definition: Player.cpp:3638
uint32 AddBattlegroundQueueId(BattlegroundQueueTypeId val)
Definition: Player.cpp:25037
Item * EquipItem(uint16 pos, Item *pItem, bool update)
Definition: Player.cpp:11754
void SetDuelArbiter(ObjectGuid guid)
Definition: Player.h:1976
void RemoveOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
Definition: Player.cpp:29713
void _SaveSeasonalQuestStatus(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20965
PvPInfo pvpInfo
Definition: Player.h:1953
static void DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRealmChars=true, bool deleteFinally=false)
Definition: Player.cpp:3824
void SetPvPDeath(bool on)
Definition: Player.h:1188
void SendCinematicStart(uint32 CinematicSequenceId) const
Definition: Player.cpp:6329
void AddStoredAuraTeleportLocation(uint32 spellId)
Definition: Player.cpp:2744
TimePoint m_regenInterruptTimestamp
Definition: Player.h:2875
void PrepareQuestMenu(ObjectGuid guid)
Definition: Player.cpp:14474
void _SaveBGData(CharacterDatabaseTransaction trans)
Definition: Player.cpp:27507
bool SatisfyQuestExpansion(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15943
void SetQuestSlot(uint16 slot, uint32 quest_id)
Definition: Player.cpp:16505
void UpdateMirrorTimers()
Definition: Player.cpp:717
void RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Definition: Player.cpp:7253
void ModifySkillBonus(uint32 skillid, int32 val, bool talent)
Definition: Player.cpp:5721
void SummonIfPossible(bool agree)
Definition: Player.cpp:25337
void AddQuestAndCheckCompletion(Quest const *quest, Object *questGiver)
Definition: Player.cpp:14774
Item * m_items[PLAYER_SLOTS_COUNT]
Definition: Player.h:3015
void _SaveTraits(CharacterDatabaseTransaction trans)
Definition: Player.cpp:27832
void RemoveSpecializationSpells()
Definition: Player.cpp:29742
uint16 m_homebindAreaId
Definition: Player.h:2504
void SetCanDelayTeleport(bool setting)
Definition: Player.h:3159
void _SaveVoidStorage(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20670
bool SatisfyQuestLevel(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15551
uint32 GetXPForNextLevel() const
Definition: Player.h:1197
void DurabilityPointsLossAll(int32 points, bool inventory)
Definition: Player.cpp:4655
std::unique_ptr< Runes > m_runes
Definition: Player.h:3127
uint32 m_zoneUpdateId
Definition: Player.h:3089
bool IsVisibleGloballyFor(Player const *player) const
Definition: Player.cpp:23778
void SendQuestUpdateAddPlayer(Quest const *quest, uint16 newCount) const
Definition: Player.cpp:17348
static bool LoadPositionFromDB(uint32 &mapid, float &x, float &y, float &z, float &o, bool &in_flight, ObjectGuid guid)
Definition: Player.cpp:17560
void UpdateAllRunesRegen()
Definition: StatSystem.cpp:840
void SetCreateCurrency(uint32 id, uint32 amount)
Initialize currency amount for custom initialization at create character.
Definition: Player.cpp:7094
void AddItemDurations(Item *item)
Definition: Player.cpp:25394
InventoryResult CanTakeMoreSimilarItems(Item *pItem, uint32 *offendingItemId=nullptr) const
Definition: Player.cpp:10027
PlayerTaxi m_taxi
Definition: Player.h:1166
uint8 m_MirrorTimerFlagsLast
Definition: Player.h:3173
std::array< uint8, MAX_MOVE_TYPE > m_forced_speed_changes
Definition: Player.h:2529
std::vector< ItemSetEffect * > ItemSetEff
Definition: Player.h:2381
Corpse * CreateCorpse()
Definition: Player.cpp:4538
uint32 GetLootSpecId() const
Definition: Player.h:1831
bool CanNeverSee(WorldObject const *obj) const override
Definition: Player.cpp:23742
void SendCanTakeQuestResponse(QuestFailedReason reason, bool sendErrorMessage=true, std::string reasonText="") const
Definition: Player.cpp:17254
bool IsMaxHonorLevel() const
Definition: Player.h:2279
uint32 GetCorpseReclaimDelay(bool pvp) const
Definition: Player.cpp:25805
void SetTitle(CharTitlesEntry const *title, bool lost=false)
Definition: Player.cpp:26283
uint32 GetAchievementPoints() const
Definition: Player.cpp:26741
void SetTransportServerTime(int32 transportServerTime)
Definition: Player.h:2845
time_t m_lastDailyQuestTime
Definition: Player.h:3083
static Difficulty CheckLoadedLegacyRaidDifficultyID(Difficulty difficulty)
Definition: Player.cpp:29682
void CastAllObtainSpells()
Definition: Player.cpp:8210
void SendSpellModifiers() const
Definition: Player.cpp:22392
static WeaponAttackType GetAttackBySlot(uint8 slot, InventoryType inventoryType)
Definition: Player.cpp:9710
void SetWeeklyQuestStatus(uint32 quest_id)
Definition: Player.cpp:24830
void _LoadGroup(PreparedQueryResult result)
Definition: Player.cpp:19647
void DeleteEquipmentSet(uint64 id)
Definition: Player.cpp:27529
void SendOnCancelExpectedVehicleRideAura() const
Definition: Player.cpp:21874
uint32 m_baseHealthRegen
Definition: Player.h:3056
void ClearQuestSharingInfo()
Definition: Player.h:1675
static uint8 GetFactionGroupForRace(uint8 race)
Definition: Player.cpp:6480
static bool IsBagPos(uint16 pos)
Definition: Player.cpp:9766
bool EnchantmentFitsRequirements(uint32 enchantmentcondition, int8 slot) const
Definition: Player.cpp:23414
void ApplyBaseModPctValue(BaseModGroup modGroup, float pct)
Definition: Player.cpp:5021
BgBattlegroundQueueID_Rec m_bgBattlegroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES]
Definition: Player.h:2896
void UpdateSkillEnchantments(uint16 skill_id, uint16 curr_value, uint16 new_value)
Definition: Player.cpp:13933
void SendSupercededSpell(uint32 oldSpell, uint32 newSpell) const
Definition: Player.cpp:29627
void ResyncRunes() const
Definition: Player.cpp:26361
bool mSemaphoreTeleport_Near
Definition: Player.h:3179
void ToggleAFK()
Definition: Player.cpp:1214
bool CanExecutePendingSpellCastRequest()
Definition: Player.cpp:30459
std::unordered_set< PetAura const * > m_petAuras
Definition: Player.h:1236
bool CanTakeQuest(Quest const *quest, bool msg) const
Definition: Player.cpp:14620
void ApplyEquipCooldown(Item *pItem)
Definition: Player.cpp:24449
void AddCurrency(uint32 id, uint32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat)
Definition: Player.cpp:7248
uint32 GetProfessionSkillForExp(uint32 skill, int32 expansion) const
Definition: Player.cpp:6005
Difficulty m_raidDifficulty
Definition: Player.h:3010
bool SatisfyQuestDependentBreadcrumbQuests(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15715
uint8 GetActiveTalentGroup() const
Definition: Player.h:1843
void UpdateRangedHitChances()
Definition: StatSystem.cpp:766
InventoryResult CanStoreItem_InInventorySlots(uint8 slot_begin, uint8 slot_end, ItemPosCountVec &dest, ItemTemplate const *pProto, uint32 &count, bool merge, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot) const
Definition: Player.cpp:10239
void UpdateHostileAreaState(AreaTableEntry const *area)
Definition: Player.cpp:7649
void RemoveSpell(uint32 spell_id, bool disabled=false, bool learn_low_rank=true, bool suppressMessaging=false)
Definition: Player.cpp:3260
void PossessSpellInitialize()
Definition: Player.cpp:21918
PlayerPvpTalentMap const & GetPvpTalentMap(uint8 spec) const
Definition: Player.h:1875
void SendUpdateWorldState(uint32 variable, uint32 value, bool hidden=false) const
Definition: Player.cpp:9174
float GetAverageItemLevel() const
Definition: Player.cpp:29020
void UpdateItemSetAuras(bool formChange=false)
Definition: Player.cpp:8408
bool isDND() const
Definition: Player.h:1157
void _LoadWeeklyQuestStatus(PreparedQueryResult result)
Definition: Player.cpp:19507
bool LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const &holder)
Definition: Player.cpp:17618
void SendSummonRequestFrom(Unit *summoner)
Definition: Player.cpp:25306
bool SatisfyQuestPreviousQuest(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15606
bool IsActionButtonDataValid(uint8 button, uint64 action, uint8 type) const
Definition: Player.cpp:6157
void UpdateZoneDependentAuras(uint32 zone_id)
Definition: Player.cpp:25775
void AreaExploredOrEventHappens(uint32 questId)
Definition: Player.cpp:16577
void SetDungeonDifficultyID(Difficulty dungeon_difficulty)
Definition: Player.h:2015
float m_lastFallZ
Definition: Player.h:3169
void SetGMVisible(bool on)
Definition: Player.cpp:2121
EquipmentSetContainer _equipmentSets
Definition: Player.h:3128
void InitRunes()
Definition: Player.cpp:26376
void _SaveActions(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20408
void AddTradeableItem(Item *item)
Definition: Player.cpp:13409
uint32 m_baseManaRegen
Definition: Player.h:3055
void SendNewMail() const
Definition: Player.cpp:2639
time_t m_logintime
Definition: Player.h:1211
Loot * GetLootByWorldObjectGUID(ObjectGuid const &lootWorldObjectGuid) const
Definition: Player.cpp:9037
void UpdateHonorNextLevel()
Definition: Player.cpp:6957
bool TakeQuestSourceItem(uint32 questId, bool msg)
Definition: Player.cpp:15999
void ApplyTraitEntryChanges(int32 editedConfigId, WorldPackets::Traits::TraitConfig const &newConfig, bool applyTraits, bool consumeCurrencies)
Definition: Player.cpp:28310
void DeleteGarrison()
Definition: Player.cpp:29223
void LearnDefaultSkill(SkillRaceClassInfoEntry const *rcInfo)
Definition: Player.cpp:24580
bool IsQuestObjectiveComplete(uint16 slot, Quest const *quest, QuestObjective const &objective) const
Definition: Player.cpp:17090
void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional< LiquidData > const &newLiquidData) override
Definition: Player.cpp:26044
void RemoveExploredZones(uint32 pos, uint64 mask)
Definition: Player.cpp:6429
void UpdateAllRatings()
Definition: Player.cpp:5508
uint32 GetBattlegroundQueueIndex(BattlegroundQueueTypeId bgQueueTypeId) const
Definition: Player.cpp:25009
void RemoveActiveQuest(uint32 questId, bool update=true)
Definition: Player.cpp:16093
bool CheckInstanceValidity(bool)
Definition: Player.cpp:19821
void ApplySpellPowerBonus(int32 amount, bool apply)
Definition: StatSystem.cpp:150
float ApplyRatingDiminishing(CombatRating cr, float bonusValue) const
Definition: Player.cpp:5294
bool CheckAttackFitToAuraRequirement(WeaponAttackType attackType, AuraEffect const *aurEff) const override
Definition: Player.cpp:8321
Item * GetItemFromBuyBackSlot(uint32 slot)
Definition: Player.cpp:13212
void RemoveItemDurations(Item *item)
Definition: Player.cpp:25382
void SetReputation(uint32 factionentry, int32 value)
Definition: Player.cpp:28557
void InterruptPowerRegen(Powers power)
Definition: Player.cpp:1845
bool IsInGroup(ObjectGuid groupGuid) const
Definition: Player.cpp:24158
Difficulty GetRaidDifficultyID() const
Definition: Player.h:2013
bool HandlePassiveSpellLearn(SpellInfo const *spellInfo)
Definition: Player.cpp:3189
QuestStatus GetQuestStatus(uint32 quest_id) const
Definition: Player.cpp:16050
void SendNotifyLootMoneyRemoved(ObjectGuid lootObj) const
Definition: Player.cpp:9158
std::unique_ptr< PlayerAchievementMgr > m_achievementMgr
Definition: Player.h:3194
bool m_customizationsChanged
Definition: Player.h:3007
void AddTraitConfig(WorldPackets::Traits::TraitConfig const &traitConfig)
Definition: Player.cpp:28225
void DestroyForPlayer(Player *target) const override
Definition: Player.cpp:3761
MapReference & GetMapRef()
Definition: Player.h:2633
void SaveToDB(bool create=false)
Definition: Player.cpp:19978
void _SaveInstanceTimeRestrictions(CharacterDatabaseTransaction trans)
Definition: Player.cpp:29108
UF::UpdateField< UF::ActivePlayerData, 0, TYPEID_ACTIVE_PLAYER > m_activePlayerData
Definition: Player.h:2864
bool CanCompleteRepeatableQuest(Quest const *quest)
Definition: Player.cpp:14703
void SendEnchantmentDurations()
Definition: Player.cpp:13978
uint32 GetQuestMoneyReward(Quest const *quest) const
Definition: Player.cpp:15061
static void RemoveFromGroup(Group *group, ObjectGuid guid, RemoveMethod method=GROUP_REMOVEMETHOD_DEFAULT, ObjectGuid kicker=ObjectGuid::Empty, char const *reason=nullptr)
Definition: Player.cpp:2189
void SetBindPoint(ObjectGuid guid) const
Definition: Player.cpp:9201
bool SatisfyQuestSkill(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15527
void _LoadActions(PreparedQueryResult result)
Definition: Player.cpp:18609
InventoryResult CanStoreItem_InBag(uint8 bag, ItemPosCountVec &dest, ItemTemplate const *pProto, uint32 &count, bool merge, bool non_specialized, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot) const
Definition: Player.cpp:10164
void BuildValuesCreate(ByteBuffer *data, Player const *target) const override
Definition: Player.cpp:3647
bool SatisfyQuestDependentQuests(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15600
void SetAreaSpiritHealer(Creature *creature)
Definition: Player.cpp:30130
void _LoadGlyphAuras()
Definition: Player.cpp:18748
void ApplyEquipSpell(SpellInfo const *spellInfo, Item *item, bool apply, bool formChange=false)
Definition: Player.cpp:8357
void SetBuybackTimestamp(uint32 slot, time_t timestamp)
Definition: Player.h:1476
PlayerTalentMap const * GetTalentMap(uint8 spec) const
Definition: Player.h:1873
uint32 m_ArenaTeamIdInvited
Definition: Player.h:3037
void UpdateSpeakTime(ChatFloodThrottle::Index index)
Definition: Player.cpp:21230
std::unique_ptr< PetStable > m_petStable
Definition: Player.h:3186
void _LoadCurrency(PreparedQueryResult result)
Definition: Player.cpp:6965
void UnsummonBattlePetTemporaryIfAny(bool onFlyingMount=false)
Definition: Player.cpp:27199
uint32 GetBattlegroundId() const
Definition: Player.h:2396
void CreateTraitConfig(WorldPackets::Traits::TraitConfig &traitConfig)
Definition: Player.cpp:28195
uint64 GetMoney() const
Definition: Player.h:1738
static bool IsValidGender(uint8 Gender)
Definition: Player.h:1707
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition: Player.cpp:23763
void KillCreditGO(uint32 entry, ObjectGuid guid=ObjectGuid::Empty)
Definition: Player.cpp:16704
bool UpdateAllStats() override
Definition: StatSystem.cpp:197
bool CanSeeGossipOn(Creature const *creature) const
Definition: Player.cpp:27233
void SetWarModeLocal(bool enabled)
Definition: Player.cpp:30052
void ResetAllPowers()
Definition: Player.cpp:1903
bool BuyCurrencyFromVendorSlot(ObjectGuid vendorGuid, uint32 vendorSlot, uint32 currency, uint32 count)
Definition: Player.cpp:22879
void UpdateRating(CombatRating cr)
Definition: Player.cpp:5368
void ApplyAzeritePowers(Item *item, bool apply)
Definition: Player.cpp:8518
void InitializeSkillFields()
Definition: Player.cpp:5768
ReputationRank GetReputationRank(uint32 faction_id) const
Definition: Player.cpp:6497
void TradeCancel(bool sendback)
Definition: Player.cpp:13376
void UpdateArea(uint32 newArea)
Definition: Player.cpp:7491
bool IsDeveloper() const
Definition: Player.h:1174
void SetHomebind(WorldLocation const &loc, uint32 areaId)
Definition: Player.cpp:17581
uint32 m_recall_instanceId
Definition: Player.h:3125
void FailQuest(uint32 quest_id)
Definition: Player.cpp:15446
Player * GetSelectedPlayer() const
Definition: Player.cpp:24150
void SendTransferAborted(uint32 mapid, TransferAbortReason reason, uint8 arg=0, int32 mapDifficultyXConditionID=0) const
Definition: Player.cpp:24439
static void ApplyModToSpell(SpellModifier *mod, Spell *spell)
Definition: Player.cpp:22368
InventoryResult CanUnequipItems(uint32 item, uint32 count) const
Definition: Player.cpp:9484
void SetAverageItemLevelTotal(float newItemLevel)
Definition: Player.h:2747
void SetWarModeDesired(bool enabled)
Definition: Player.cpp:30024
void AddEnchantmentDuration(Item *item, EnchantmentSlot slot, uint32 duration)
Definition: Player.cpp:13547
Unit * GetSelectedUnit() const
Definition: Player.cpp:24142
void ReplaceAllPlayerFlags(PlayerFlags flags)
Definition: Player.h:2740
bool CanSelectQuestPackageItem(QuestPackageItemEntry const *questPackageItem) const
Definition: Player.cpp:15084
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition: Player.cpp:9643
Player * GetNextRandomRaidMember(float radius)
Definition: Player.cpp:25894
void AddToWorld() override
Definition: Player.cpp:1552
void SetChosenTitle(int32 title)
Definition: Player.h:2663
bool SatisfyQuestWeek(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15921
void _SaveWeeklyQuestStatus(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20942
void UpdateAverageItemLevelTotal()
Definition: Player.cpp:29949
bool GiveQuestSourceItem(Quest const *quest)
Definition: Player.cpp:15966
bool HasAtLoginFlag(AtLoginFlags f) const
Definition: Player.h:2532
void SendAurasForTarget(Unit *target) const
Definition: Player.cpp:24784
void SendPushToPartyResponse(Player const *player, QuestPushReason reason, Quest const *quest=nullptr) const
Definition: Player.cpp:17286
void RewardReputation(Unit *victim, float rate)
Definition: Player.cpp:6593
VoidStorageItem * GetVoidStorageItem(uint8 slot) const
Definition: Player.cpp:29191
bool IsVoidStorageUnlocked() const
Definition: Player.h:2693
void CancelPendingCastRequest()
Definition: Player.cpp:30237
static void LeaveAllArenaTeams(ObjectGuid guid)
Definition: Player.cpp:22468
bool IsUseEquipedWeapon(bool mainhand) const
Definition: Player.cpp:13318
void RemoveEnchantmentDurationsReferences(Item *item)
Definition: Player.cpp:13489
void HandleDrowning(uint32 time_diff)
Definition: Player.cpp:736
uint32 m_HomebindTimer
Definition: Player.h:2570
void SendResetInstanceSuccess(uint32 MapId) const
Definition: Player.cpp:21378
void ApplyItemEquipSpell(Item *item, bool apply, bool formChange=false)
Definition: Player.cpp:8334
void SetAverageItemLevelEquipped(float newItemLevel)
Definition: Player.h:2748
static Difficulty CheckLoadedRaidDifficultyID(Difficulty difficulty)
Definition: Player.cpp:29667
void SendRaidDifficulty(bool legacy, int32 forcedDifficulty=-1) const
Definition: Player.cpp:21326
static bool IsBankPos(uint16 pos)
Definition: Player.h:1368
bool UpdateSkillPro(uint16 skillId, int32 chance, uint32 step)
Definition: Player.cpp:5661
void _LoadTransmogOutfits(PreparedQueryResult result)
Definition: Player.cpp:17499
void RemovePetAura(PetAura const *petSpell)
Definition: Player.cpp:21643
void _LoadEquipmentSets(PreparedQueryResult result)
Definition: Player.cpp:17465
bool RewardHonor(Unit *victim, uint32 groupsize, int32 honor=-1, bool pvptoken=false)
Definition: Player.cpp:6726
bool SatisfyQuestStatus(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15803
void RemoveItem(uint8 bag, uint8 slot, bool update)
Definition: Player.cpp:12048
int32 CalculateCorpseReclaimDelay(bool load=false) const
Definition: Player.cpp:25846
void DeleteRefundReference(ObjectGuid it)
Definition: Player.cpp:28576
Mail * GetMail(uint64 id)
Definition: Player.cpp:3605
bool m_canTitanGrip
Definition: Player.h:3100
bool InArena() const
Definition: Player.cpp:25106
void SendLootReleaseAll() const
Definition: Player.cpp:9114
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3792
void UpdateSkillsForLevel()
Definition: Player.cpp:5738
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
ActionButtonList m_actionButtons
Definition: Player.h:3049
void BuildPlayerRepop()
Definition: Player.cpp:4350
void UninviteFromGroup()
Definition: Player.cpp:2166
bool HasPlayerFlag(PlayerFlags flags) const
Definition: Player.h:2737
void ResetInstances(InstanceResetMethod method)
Reset all solo instances and optionally send a message on success for each.
Definition: Player.cpp:21341
std::unique_ptr< DuelInfo > duel
Definition: Player.h:1972
void _SaveAuras(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20479
bool m_canBlock
Definition: Player.h:3099
uint8 GetSubGroup() const
Definition: Player.h:2612
void SetQuestStatus(uint32 questId, QuestStatus status, bool update=true)
Definition: Player.cpp:16075
bool HasGemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot=NULL_SLOT) const
Definition: Player.cpp:9950
bool isHonorOrXPTarget(Unit const *victim) const
Definition: Player.cpp:25587
bool isAFK() const
Definition: Player.h:1156
void _RemoveAllStatBonuses()
Definition: StatSystem.cpp:869
uint8 m_cinematic
Definition: Player.h:3073
Team m_team
Definition: Player.h:3005
void VehicleSpellInitialize()
Definition: Player.cpp:21944
void SetRestState(RestTypes type, PlayerRestState state)
Definition: Player.h:2718
SpellModContainer m_spellMods[MAX_SPELLMOD][SPELLMOD_END]
Definition: Player.h:3059
bool IsOutdoorPvPActive() const
Definition: Player.cpp:7736
Player(WorldSession *session)
Definition: Player.cpp:160
void AddTimedQuest(uint32 questId)
Definition: Player.h:1680
void UpdateObjectVisibility(bool forced=true) override
Definition: Player.cpp:24070
float GetBlockPercent(uint8 attackerLevel) const override
Definition: Player.cpp:26092
int32 m_spellPenetrationItemMod
Definition: Player.h:3057
void SetFreePrimaryProfessions(uint16 profs)
Definition: Player.h:1898
bool SatisfyQuestBreadcrumbQuest(Quest const *qInfo, bool msg) const
Definition: Player.cpp:15691
void SendInitialActionButtons() const
Definition: Player.h:1948
void PrepareGossipMenu(WorldObject *source, uint32 menuId, bool showQuests=false)
Definition: Player.cpp:14036
void SetMap(Map *map) override
Definition: Player.cpp:27572
void SendInitialVisiblePackets(WorldObject *target) const
Definition: Player.cpp:23994
bool isAcceptWhispers() const
Definition: Player.h:1176
void AbandonQuest(uint32 quest_id)
Definition: Player.cpp:15508
void RemoveRewardedQuest(uint32 questId, bool update=true)
Definition: Player.cpp:16113
void Yell(std::string_view text, Language language, WorldObject const *=nullptr) override
Handles yelled message in regular chat based on declared language and in config pre-defined Range.
Definition: Player.cpp:21746
void KillCreditCriteriaTreeObjective(QuestObjective const &questObjective)
Definition: Player.cpp:16714
bool CanReportAfkDueToLimit()
Definition: Player.cpp:23649
void DurabilityPointsLoss(Item *item, int32 points)
Definition: Player.cpp:4679
ObjectGuid GetPlayerSharingQuest() const
Definition: Player.h:1673
void Say(std::string_view text, Language language, WorldObject const *=nullptr) override
Handles said message in regular chat based on declared language and in config pre-defined Range.
Definition: Player.cpp:21720
std::string GetDebugInfo() const override
Definition: Player.cpp:30123
void RemoveTimedQuest(uint32 questId)
Definition: Player.h:1681
std::array< std::unique_ptr< CUFProfile >, MAX_CUF_PROFILES > _CUFProfiles
Definition: Player.h:3137
uint32 GetMaxPersonalArenaRatingRequirement(uint32 minarenaslot) const
Definition: Player.cpp:23264
void TextEmote(std::string_view text, WorldObject const *=nullptr, bool=false) override
Outputs an universal text which is supposed to be an action.
Definition: Player.cpp:21759
uint32 GetChampioningFaction() const
Definition: Player.h:2670
void LeftChannel(Channel *c)
Definition: Player.cpp:4905
WorldSession * m_session
Definition: Player.h:3067
void VisualizeItem(uint8 slot, Item *pItem)
Definition: Player.cpp:12014
void ReportedAfkBy(Player *reporter)
This player has been blamed to be inactive in a battleground.
Definition: Player.cpp:23659
InventoryResult CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec &dest, ItemTemplate const *pProto, uint32 &count, bool swap, Item *pSrcItem) const
Definition: Player.cpp:10085
Team GetEffectiveTeam() const
Definition: Player.h:2239
void FailCriteria(CriteriaFailEvent condition, int32 failAsset)
Definition: Player.cpp:26761
void SetQuestObjectiveData(QuestObjective const &objective, int32 data)
Definition: Player.cpp:16983
void ResetPvpTalents()
Definition: Player.cpp:3597
Creature * GetSummonedBattlePet() const
Definition: Player.cpp:21650
void RefundItem(Item *item)
Definition: Player.cpp:28880
void SetVisibleItemSlot(uint8 slot, Item *pItem)
Definition: Player.cpp:11995
void Whisper(std::string_view text, Language language, Player *receiver, bool=false) override
Handles whispers from Addons and players based on sender, receiver's guid and language.
Definition: Player.cpp:21787
int32 GetQuestMinLevel(Quest const *quest) const
Definition: Player.cpp:14429
void AddSpellMod(SpellModifier *mod, bool apply)
Definition: Player.cpp:22276
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition: Player.h:2151
bool UpdateFishingSkill(int32 expansion)
Definition: Player.cpp:5634
void _SaveInventory(CharacterDatabaseTransaction trans)
Definition: Player.cpp:20536
void SetFactionForRace(uint8 race)
Definition: Player.cpp:6489
void SendPreparedQuest(WorldObject *source)
Definition: Player.cpp:14534
void SendActionButtons(uint32 state) const
Definition: Player.cpp:6144
void SetSkillRank(uint32 pos, uint16 rank)
Definition: Player.h:2210
void SetContestedPvP(Player *attackedPlayer=nullptr)
Definition: Player.cpp:21439
void SetAttackSwingError(Optional< AttackSwingErr > err)
Definition: Player.cpp:21299
void SetLootSpecId(uint32 id)
Definition: Player.h:1830
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
uint32 m_ArmorProficiency
Definition: Player.h:3097
void ToggleDND()
Definition: Player.cpp:1226
void _LoadInstanceTimeRestrictions(PreparedQueryResult result)
Definition: Player.cpp:29040
void ResummonPetTemporaryUnSummonedIfAny()
Definition: Player.cpp:27180
std::array< GroupUpdateCounter, 2 > m_groupUpdateSequences
Definition: Player.h:3113
void ApplyHealthRegenBonus(int32 amount, bool apply)
Definition: StatSystem.cpp:812
bool IsCanDelayTeleport() const
Definition: Player.h:3158
bool IsAreaThatActivatesPvpTalents(uint32 areaID) const
Definition: Player.cpp:27090
std::unique_ptr< CinematicMgr > _cinematicMgr
Definition: Player.h:3149
void SendItemDurations()
Definition: Player.cpp:13984
uint32 GetGossipTextId(uint32 menuId, WorldObject *source)
Definition: Player.cpp:14367
bool CanUnderstandLanguage(Language language) const
Definition: Player.cpp:21841
void UpdateHomebindTime(uint32 time)
Definition: Player.cpp:23278
void RemovedInsignia(Player *looterPlr)
Definition: Player.cpp:9062
bool isDebugAreaTriggers
Definition: Player.h:2675
void RemoveFromWorld() override
Definition: Player.cpp:1564
void JoinedChannel(Channel *c)
Definition: Player.cpp:4900
bool CanSeeSpellClickOn(Creature const *creature) const
Definition: Player.cpp:27266
int32 GetQuestSlotObjectiveData(uint16 slot, QuestObjective const &objective) const
Definition: Player.cpp:16470
bool UpdateGatherSkill(uint32 skillId, uint32 skillValue, uint32 redLevel, uint32 multiplicator=1, WorldObject const *object=nullptr)
Definition: Player.cpp:5576
uint32 m_summon_instanceId
Definition: Player.h:3121
void SetBuybackPrice(uint32 slot, uint32 price)
Definition: Player.h:1475
void SetMultiActionBars(uint8 mask)
Definition: Player.h:1951
void _LoadQuestStatusObjectives(PreparedQueryResult result)
Definition: Player.cpp:19378
uint32 GetFreePrimaryProfessionPoints() const
Definition: Player.h:1897
void StartLoadingActionButtons(std::function< void()> &&callback=nullptr)
Definition: Player.cpp:28144
void UpdateSpellCritChance()
Definition: StatSystem.cpp:714
void UpdatePvP(bool state, bool override=false)
Definition: Player.cpp:23360
GuidUnorderedSet m_itemSoulboundTradeable
Definition: Player.h:3063
Optional< uint32 > m_teleport_instanceId
Definition: Player.h:3177
void SetSkillStep(uint32 pos, uint16 step)
Definition: Player.h:2209
Group * GetGroupInvite() const
Definition: Player.h:2604
uint32 GetCurrencyWeeklyCap(uint32 id) const
Definition: Player.cpp:7398
std::vector< Item * > GetItemListByEntry(uint32 entry, bool inBankAlso=false) const
Definition: Player.cpp:12605
void SendQuestUpdateAddCreditSimple(QuestObjective const &obj) const
Definition: Player.cpp:17318
void CleanupAfterTaxiFlight()
Definition: Player.cpp:22715
void RemoveMail(uint64 id)
Definition: Player.cpp:2608
bool IsInAreaThatActivatesPvpTalents() const
Definition: Player.cpp:27085
void SetContestedPvPTimer(uint32 newTime)
Definition: Player.h:1968
void SendEquipmentSetList()
Definition: Player.cpp:27366
void SendQuestGiverStatusMultiple()
Definition: Player.cpp:17356
PlayerMails m_mail
Definition: Player.h:3039
ChrSpecializationEntry const * GetPrimarySpecializationEntry() const
Definition: Player.cpp:29827
void SetSkillStartingRank(uint32 pos, uint16 starting)
Definition: Player.h:2211
void SetSkillTempBonus(uint32 pos, uint16 bonus)
Definition: Player.h:2213
bool ResetTalents(bool noCost=false)
Definition: Player.cpp:3529
static Difficulty CheckLoadedDungeonDifficultyID(Difficulty difficulty)
Definition: Player.cpp:29652
void _SaveStats(CharacterDatabaseTransaction trans) const
Definition: Player.cpp:21164
void SendQuestTimerFailed(uint32 questId) const
Definition: Player.cpp:17244
void SetMoney(uint64 value)
Definition: Player.cpp:24124
void AtExitCombat() override
Definition: Player.cpp:26085
void RegenerateAll()
Definition: Player.cpp:1623
static void RemovePetitionsAndSigns(ObjectGuid guid)
Definition: Player.cpp:22452
void StopMirrorTimer(MirrorTimerType Type)
Definition: Player.cpp:622
void SendMovementSetCollisionHeight(float height, WorldPackets::Movement::UpdateCollisionHeightReason reason)
Definition: Player.cpp:29232
uint32 m_groupUpdateMask
Definition: Player.h:3111
void UpdateHonorFields()
Definition: Player.cpp:6695
void ResetSeasonalQuestStatus(uint16 event_id, time_t eventStartTime)
Definition: Player.cpp:24932
BGData m_bgData
Definition: Player.h:2897
void RemoveLootRoll(LootRoll *roll)
Definition: Player.cpp:9055
WorldLocation const * GetStoredAuraTeleportLocation(uint32 spellId) const
Definition: Player.cpp:2757
uint32 GetArenaTeamId(uint8) const
Definition: Player.h:2004
Difficulty GetLegacyRaidDifficultyID() const
Definition: Player.h:2014
void SetDuelTeam(uint32 duelTeam)
Definition: Player.h:1977
Spell * m_spellModTakingSpell
Definition: Player.h:2672
void CorrectMetaGemEnchants(uint8 slot, bool apply)
Definition: Player.cpp:23485
BattlegroundQueueTypeId GetBattlegroundQueueTypeId(uint32 index) const
Definition: Player.cpp:25001
void ModifyCurrency(uint32 id, int32 amount, CurrencyGainSource gainSource=CurrencyGainSource::Cheat, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Modify currency amount.
Definition: Player.cpp:7110
Team GetBGTeam() const
Definition: Player.cpp:23609
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition: Player.cpp:10032
void SetBankBagSlotCount(uint8 count)
Definition: Player.h:1379
void RenameTraitConfig(int32 editedConfigId, std::string &&newName)
Definition: Player.cpp:28420
QuestStatusSaveMap m_QuestStatusSave
Definition: Player.h:3029
void ApplyAzeriteEssencePower(AzeriteItem *item, AzeriteEssencePowerEntry const *azeriteEssencePower, bool major, bool apply)
Definition: Player.cpp:8579
uint32 m_lastpetnumber
Definition: Player.h:3116
void UpdateAttackPowerAndDamage(bool ranged=false) override
Definition: StatSystem.cpp:343
QuestStatusSaveMap m_RewardedQuestsSave
Definition: Player.h:3032
bool HasItemWithLimitCategoryEquipped(uint32 limitCategory, uint32 count, uint8 except_slot=NULL_SLOT) const
Definition: Player.cpp:9931
std::unique_ptr< PlayerMenu > PlayerTalkClass
Definition: Player.h:2380
bool IsInSameGroupWith(Player const *p) const
Definition: Player.cpp:2153
uint32 _pendingBindTimer
Definition: Player.h:3202
uint32 GetQuestSlotState(uint16 slot) const
Definition: Player.cpp:16446
bool IsWarModeLocalActive() const
Definition: Player.h:2856
void SetBattlegroundOrBattlefieldRaid(Group *group, int8 subgroup=-1)
Definition: Player.cpp:25987
void SkipQuests(std::vector< uint32 > const &questIds)
Definition: Player.cpp:16315
WorldLocation const & GetBattlegroundEntryPoint() const
Definition: Player.h:2417
time_t m_Last_tick
Definition: Player.h:1212
ReputationMgr & GetReputationMgr()
Definition: Player.h:2251
static DrunkenState GetDrunkenstateByValue(uint8 value)
Definition: Player.cpp:876
bool IsBeingTeleported() const
Definition: Player.h:2219
uint8 GetOriginalSubGroup() const
Definition: Player.h:2627
bool IsLockedToDungeonEncounter(uint32 dungeonEncounterId) const
Definition: Player.cpp:21399
std::vector< LootRoll * > m_lootRolls
Definition: Player.h:3219
uint32 GetCurrencyQuantity(uint32 id) const
Definition: Player.cpp:7346
bool IsQuestRewarded(uint32 quest_id) const
Definition: Player.cpp:24137
bool SwapVoidStorageItem(uint8 oldSlot, uint8 newSlot)
Definition: Player.cpp:29182
void SetCustomizations(Trinity::IteratorPair< Iter > customizations, bool markChanged=true)
Definition: Player.h:2764
void SendQuestUpdate(uint32 questId, bool updateInteractions=true, bool updateGameObjectQuestGiverStatus=false)
Definition: Player.cpp:16142
void SetPetSlot(uint32 petNumber, PetSaveMode dstPetSlot)
Definition: Player.cpp:28675
void RewardQuest(Quest const *quest, LootItemType rewardType, uint32 rewardId, Object *questGiver, bool announce=true)
Definition: Player.cpp:15152
void DestroyZoneLimitedItem(bool update, uint32 new_zone)
Definition: Player.cpp:12533
void RemoveArenaEnchantments(EnchantmentSlot slot)
Definition: Player.cpp:13500
void SendItemRefundResult(Item *item, ItemExtendedCostEntry const *iece, uint8 error) const
Definition: Player.cpp:28852
bool CanCaptureTowerPoint() const
Definition: Player.cpp:26222
void RemoveStoredAuraTeleportLocation(uint32 spellId)
Definition: Player.cpp:2751
uint32 GetCurrencyMaxQuantity(CurrencyTypesEntry const *currency, bool onLoad=false, bool onUpdateVersion=false) const
Definition: Player.cpp:7382
Team GetTeam() const
Definition: Player.h:2235
void AddOverrideSpell(uint32 overridenSpellId, uint32 newSpellId)
Definition: Player.cpp:29708
void _LoadDailyQuestStatus(PreparedQueryResult result)
Definition: Player.cpp:19465
void SetInviteForBattlegroundQueueType(BattlegroundQueueTypeId bgQueueTypeId, uint32 instanceId)
Definition: Player.cpp:25076
bool GetBGAccessByLevel(BattlegroundTypeId bgTypeId) const
Definition: Player.cpp:25115
Optional< ReactStates > m_temporaryPetReactState
Definition: Player.h:3190
void AddPetAura(PetAura const *petSpell)
Definition: Player.cpp:21636
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
void SetRandomWinner(bool isWinner)
Definition: Player.cpp:28999
Difficulty GetDifficultyID(MapEntry const *mapEntry) const
Definition: Player.cpp:29636
void SendQuestUpdateAddCredit(Quest const *quest, ObjectGuid guid, QuestObjective const &obj, uint16 count) const
Definition: Player.cpp:17306
void ApplyArtifactPowerRank(Item *artifact, ArtifactPowerRankEntry const *artifactPowerRank, bool apply)
Definition: Player.cpp:8458
void RewardPlayerAndGroupAtEvent(uint32 creature_id, WorldObject *pRewardSource)
Definition: Player.cpp:25645
void SendNewItem(Item *item, uint32 quantity, bool received, bool created, bool broadcast=false, uint32 dungeonEncounterId=0)
Definition: Player.cpp:13990
void LearnSkillRewardedSpells(uint32 skillId, uint32 skillValue, Races race)
Definition: Player.cpp:24694
bool m_itemUpdateQueueBlocked
Definition: Player.h:3023
void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns=false)
Definition: Player.cpp:3479
void SendQuestUpdateAddItem(ItemTemplate const *itemTemplate, QuestObjective const &obj, uint16 count) const
Definition: Player.cpp:17327
void ResetAchievements()
Definition: Player.cpp:26731
bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const override
Definition: Player.cpp:23731
PlayerCreateMode m_createMode
Definition: Player.h:3072
InventoryResult CanUseItem(Item *pItem, bool not_loading=true) const
Definition: Player.cpp:11381
void LearnDefaultSkills()
Definition: Player.cpp:24562
uint32 _pendingBindId
Definition: Player.h:3201
uint32 GetGossipMenuForSource(WorldObject const *source) const
Definition: Player.cpp:14389
void ResurrectPlayer(float restore_percent, bool applySickness=false)
Definition: Player.cpp:4408
bool isUsingLfg() const
Definition: Player.cpp:25971
void SetSummonedBattlePetGUID(ObjectGuid guid)
Definition: Player.h:2821
void UpdateAfkReport(time_t currTime)
checks the 15 afk reports per 5 minutes limit
Definition: Player.cpp:21430
void setInt16(const uint8 index, const int16 value)
void setInt32(const uint8 index, const int32 value)
void setFloat(const uint8 index, const float value)
void setUInt8(const uint8 index, const uint8 value)
void setInt64(const uint8 index, const int64 value)
void setBool(const uint8 index, const bool value)
void setBinary(const uint8 index, const std::vector< uint8 > &value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt16(const uint8 index, const uint16 value)
void setNull(const uint8 index)
void setString(const uint8 index, const std::string &value)
void setInt8(const uint8 index, const int8 value)
void setUInt64(const uint8 index, const uint64 value)
QuestMenuItem const & GetItem(uint16 index) const
Definition: GossipDef.h:216
bool Empty() const
Definition: GossipDef.h:214
uint8 GetMenuItemCount() const
Definition: GossipDef.h:213
void ClearMenu()
Definition: GossipDef.cpp:375
void AddMenuItem(uint32 QuestId, uint8 Icon)
Definition: GossipDef.cpp:351
uint32 XPValue(Player const *player) const
Definition: QuestDef.cpp:386
bool IsTurnIn() const
Definition: QuestDef.cpp:544
uint32 GetRewSpell() const
Definition: QuestDef.h:639
std::array< int32, QUEST_REWARD_REPUTATIONS_COUNT > RewardFactionValue
Definition: QuestDef.h:697
uint16 GetEventIdForQuest() const
Definition: QuestDef.h:713
uint32 GetRewMoneyMaxLevel() const
Definition: QuestDef.cpp:529
uint32 GetRewMailSenderEntry() const
Definition: QuestDef.h:642
Optional< QuestTagType > GetQuestTag() const
Definition: QuestDef.cpp:459
uint32 GetRewTitle() const
Definition: QuestDef.h:643
std::array< LootItemType, QUEST_REWARD_CHOICES_COUNT > RewardChoiceItemType
Definition: QuestDef.h:692
std::vector< uint32 > DependentBreadcrumbQuests
Definition: QuestDef.h:726
uint32 GetRewardSkillId() const
Definition: QuestDef.h:663
std::array< uint32, QUEST_REWARD_CURRENCY_COUNT > RewardCurrencyId
Definition: QuestDef.h:700
bool IsImportant() const
Definition: QuestDef.cpp:467
uint32 GetRewMailTemplateId() const
Definition: QuestDef.h:640
std::array< uint32, QUEST_REWARD_CHOICES_COUNT > RewardChoiceItemCount
Definition: QuestDef.h:694
bool HasQuestObjectiveType(QuestObjectiveType type) const
Definition: QuestDef.h:575
uint32 GetMaxLevel() const
Definition: QuestDef.h:592
int32 GetRequiredMaxRepValue() const
Definition: QuestDef.h:601
uint32 MoneyValue(Player const *player) const
Definition: QuestDef.cpp:436
std::array< uint32, QUEST_REWARD_CHOICES_COUNT > RewardChoiceItemId
Definition: QuestDef.h:693
int32 GetRequiredMinRepValue() const
Definition: QuestDef.h:599
int32 GetExpansion() const
Definition: QuestDef.h:667
std::array< uint32, QUEST_REWARD_ITEM_COUNT > RewardItemId
Definition: QuestDef.h:688
uint32 GetContentTuningId() const
Definition: QuestDef.h:590
uint32 GetQuestPackageID() const
Definition: QuestDef.h:589
uint32 GetRewardReputationMask() const
Definition: QuestDef.h:665
std::array< uint32, QUEST_REWARD_ITEM_COUNT > RewardItemCount
Definition: QuestDef.h:689
std::array< int32, QUEST_REWARD_REPUTATIONS_COUNT > RewardFactionCapIn
Definition: QuestDef.h:699
uint32 GetSrcItemCount() const
Definition: QuestDef.h:614
bool IsDFQuest() const
Definition: QuestDef.h:681
QuestObjectives Objectives
Definition: QuestDef.h:702
uint32 GetSrcSpell() const
Definition: QuestDef.h:615
bool IsRepeatable() const
Definition: QuestDef.h:654
int32 GetZoneOrSort() const
Definition: QuestDef.h:591
int64 GetLimitTime() const
Definition: QuestDef.h:603
uint32 GetRequiredMinRepFaction() const
Definition: QuestDef.h:598
int32 GetPrevQuestId() const
Definition: QuestDef.h:604
uint32 CalculateHonorGain(uint8 level) const
Definition: QuestDef.cpp:577
std::string const & GetLogTitle() const
Definition: QuestDef.h:616
std::vector< uint32 > DependentPreviousQuests
Definition: QuestDef.h:725
uint32 GetQuestId() const
Definition: QuestDef.h:587
uint32 GetRequiredSkillValue() const
Definition: QuestDef.h:597
std::array< uint32, QUEST_ITEM_DROP_COUNT > ItemDropQuantity
Definition: QuestDef.h:691
uint32 GetRewMailDelaySecs() const
Definition: QuestDef.h:641
bool IsDaily() const
Definition: QuestDef.h:674
int32 GetExclusiveGroup() const
Definition: QuestDef.h:606
int32 GetBreadcrumbForQuestId() const
Definition: QuestDef.h:607
bool IsWorldQuest() const
Definition: QuestDef.h:578
std::array< int32, QUEST_REWARD_REPUTATIONS_COUNT > RewardFactionOverride
Definition: QuestDef.h:698
std::array< uint32, QUEST_REWARD_REPUTATIONS_COUNT > RewardFactionId
Definition: QuestDef.h:696
uint32 GetRewItemsCount() const
Definition: QuestDef.h:709
uint32 GetRequiredSkill() const
Definition: QuestDef.h:596
Trinity::RaceMask< uint64 > GetAllowableRaces() const
Definition: QuestDef.h:595
bool IsAllowedInRaid(Difficulty difficulty) const
Definition: QuestDef.cpp:569
uint32 GetRewChoiceItemsCount() const
Definition: QuestDef.h:708
uint32 GetSrcItemId() const
Definition: QuestDef.h:613
bool IsWeekly() const
Definition: QuestDef.h:675
bool IsSeasonal() const
Definition: QuestDef.h:677
bool IsDailyOrWeekly() const
Definition: QuestDef.h:678
QuestObjectives const & GetObjectives() const
Definition: QuestDef.h:631
bool HasFlagEx(QuestFlagsEx flag) const
Definition: QuestDef.h:570
std::array< uint32, QUEST_REWARD_CURRENCY_COUNT > RewardCurrencyCount
Definition: QuestDef.h:701
std::array< uint32, QUEST_ITEM_DROP_COUNT > ItemDrop
Definition: QuestDef.h:690
bool IsMonthly() const
Definition: QuestDef.h:676
uint32 GetAllowableClasses() const
Definition: QuestDef.h:594
bool HasFlag(QuestFlags flag) const
Definition: QuestDef.h:569
uint32 GetRewardSkillPoints() const
Definition: QuestDef.h:664
std::vector< QuestRewardDisplaySpell > RewardDisplaySpell
Definition: QuestDef.h:687
uint32 GetRequiredMaxRepFaction() const
Definition: QuestDef.h:600
uint32 GetNextQuestInChain() const
Definition: QuestDef.h:608
bool CanIncreaseRewardedQuestCounters() const
Definition: QuestDef.cpp:595
void unlink()
Definition: Reference.h:61
void link(TO *toObj, FROM *fromObj)
Definition: Reference.h:46
void SetVisible(FactionTemplateEntry const *factionTemplateEntry)
bool ModifyReputation(FactionEntry const *factionEntry, int32 standing, bool spillOverOnly=false, bool noSpillover=false)
int32 GetReputation(uint32 faction_id) const
bool SetReputation(FactionEntry const *factionEntry, int32 standing)
ReputationRank GetRank(FactionEntry const *factionEntry) const
PreparedQueryResult GetPreparedResult(size_t index) const
Definition: QueryHolder.cpp:37
void TriggerDelayedScenes()
Definition: SceneMgr.cpp:241
ObjectGuid GetUnitTargetGUID() const
Definition: Spell.cpp:210
GameObject * GetGOTarget() const
Definition: Spell.cpp:244
Unit * GetUnitTarget() const
Definition: Spell.cpp:218
uint32 TriggerSpell
Definition: SpellInfo.h:237
bool IsAura() const
Definition: SpellInfo.cpp:461
int32 CalcBaseValue(WorldObject const *caster, Unit const *target, uint32 itemId, int32 itemLevel) const
Definition: SpellInfo.cpp:554
bool IsEffect() const
Definition: SpellInfo.cpp:451
void AddCooldown(uint32 spellId, uint32 itemId, Duration cooldownDuration)
Definition: SpellHistory.h:108
Duration GetRemainingGlobalCooldown(SpellInfo const *spellInfo) const
void LoadFromDB(PreparedQueryResult cooldownsResult, PreparedQueryResult chargesResult)
void SendCooldownEvent(SpellInfo const *spellInfo, uint32 itemId=0, Spell *spell=nullptr, bool startCooldown=true)
void AddGlobalCooldown(SpellInfo const *spellInfo, Duration duration)
void SaveToDB(CharacterDatabaseTransaction trans)
void WritePacket(PacketType *packet) const
void ResetCooldowns(Predicate predicate, bool update=false)
Definition: SpellHistory.h:131
uint32 BaseLevel
Definition: SpellInfo.h:383
uint32 SpellLevel
Definition: SpellInfo.h:384
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition: SpellInfo.h:393
bool MeetsFutureSpellPlayerCondition(Player const *player) const
Definition: SpellInfo.cpp:4928
bool HasEffect(SpellEffectName effect) const
Definition: SpellInfo.cpp:1391
SpellCastResult CheckShapeshift(uint32 form) const
Definition: SpellInfo.cpp:1946
uint32 const Id
Definition: SpellInfo.h:325
uint32 RecoveryTime
Definition: SpellInfo.h:366
std::array< int16, MAX_SPELL_REAGENTS > ReagentCount
Definition: SpellInfo.h:394
uint64 Stances
Definition: SpellInfo.h:347
bool IsPassive() const
Definition: SpellInfo.cpp:1592
::Difficulty const Difficulty
Definition: SpellInfo.h:326
uint32 Mechanic
Definition: SpellInfo.h:329
uint32 ProcCharges
Definition: SpellInfo.h:378
bool IsRanked() const
Definition: SpellInfo.cpp:4260
bool IsHighRankOf(SpellInfo const *spellInfo) const
Definition: SpellInfo.cpp:4353
SpellInfo const * GetAuraRankForLevel(uint8 level) const
Definition: SpellInfo.cpp:4300
bool HasTargetType(::Targets target) const
Definition: SpellInfo.cpp:1444
int32 EquippedItemClass
Definition: SpellInfo.h:396
uint32 CasterAuraState
Definition: SpellInfo.h:353
bool IsAffectedBySpellMod(SpellModifier const *mod) const
Definition: SpellInfo.cpp:1814
uint32 CategoryRecoveryTime
Definition: SpellInfo.h:367
flag128 SpellFamilyFlags
Definition: SpellInfo.h:409
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
int32 GetDuration() const
Definition: SpellInfo.cpp:3791
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition: SpellInfo.h:577
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:576
int32 EquippedItemSubClassMask
Definition: SpellInfo.h:397
uint32 StartRecoveryTime
Definition: SpellInfo.h:369
bool IsDifferentRankOf(SpellInfo const *spellInfo) const
Definition: SpellInfo.cpp:4346
bool IsPrimaryProfessionFirstRank() const
Definition: SpellInfo.cpp:1516
bool IsPositive() const
Definition: SpellInfo.cpp:1709
bool IsAutoRepeatRangedSpell() const
Definition: SpellInfo.cpp:1741
uint32 ProcChance
Definition: SpellInfo.h:377
uint32 SpellFamilyName
Definition: SpellInfo.h:408
static bool IsSpellValid(SpellInfo const *spellInfo, Player *player=nullptr, bool msg=true)
Some checks for spells, to prevent adding deprecated/broken spells for trainers, spell book,...
Definition: SpellMgr.cpp:142
Definition: Spell.h:255
bool m_fromClient
Definition: Spell.h:570
bool IsIgnoringCooldowns() const
Definition: Spell.cpp:8158
struct Spell::@333::@335 Raw
uint32 Data[2]
Definition: Spell.h:602
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3426
union Spell::@333 m_misc
Item * m_CastItem
Definition: Spell.h:564
UsedSpellMods m_appliedMods
Definition: Spell.h:610
ObjectGuid m_castId
Definition: Spell.h:568
SpellInfo const *const m_spellInfo
Definition: Spell.h:563
bool IsDismissedOnFlyingMount() const
bool IsAutoResummoned() const
Milliseconds GetTimer() const
Player * GetTrader() const
Definition: TradeData.h:41
void AfterComplete(std::function< void(bool)> callback) &
Definition: Transaction.h:108
void AddPassenger(WorldObject *passenger) override
Definition: Transport.cpp:283
uint32 GetExpectedMapId() const
Returns id of the map that transport is expected to be on, according to current path progress.
Definition: Transport.cpp:737
void CalculatePassengerPosition(float &x, float &y, float &z, float *o=nullptr) const override
This method transforms supplied transport offsets into global coordinates.
Definition: Transport.h:76
Utility class to enable range for loop syntax for multimap.equal_range uses.
Definition: IteratorPair.h:32
constexpr end_iterator end() const
Definition: IteratorPair.h:39
constexpr iterator begin() const
Definition: IteratorPair.h:38
std::size_t size() const
Definition: UpdateField.h:850
int32 FindIndexIf(Pred pred) const
Definition: UpdateField.h:870
void ClearChanged(UpdateField< T, BlockBit, Bit >(Derived::*))
Definition: UpdateField.h:572
Mask const & GetChangesMask() const
Definition: UpdateField.h:605
void MarkChanged(UpdateField< T, BlockBit, Bit >(Derived::*))
Definition: UpdateField.h:527
MutableFieldReference< T, false > ModifyValue(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:683
void ClearChangesMask(UpdateField< T, BlockBit, Bit >(Derived::*field))
Definition: UpdateField.h:690
bool HasChanged(uint32 index) const
Definition: UpdateField.h:701
uint32 GetChangedObjectTypeMask() const
Definition: UpdateField.h:696
Definition: Unit.h:627
static uint32 DealDamage(Unit *attacker, Unit *victim, uint32 damage, CleanDamage const *cleanDamage=nullptr, DamageEffectType damagetype=DIRECT_DAMAGE, SpellSchoolMask damageSchoolMask=SPELL_SCHOOL_MASK_NORMAL, SpellInfo const *spellProto=nullptr, bool durabilityLoss=true)
Definition: Unit.cpp:769
Unit * GetCharmed() const
Definition: Unit.h:1191
void ClearUnitState(uint32 f)
Definition: Unit.h:733
bool IsVehicle() const
Definition: Unit.h:743
void SetMinion(Minion *minion, bool apply)
Definition: Unit.cpp:6062
bool IsCharmed() const
Definition: Unit.h:1215
void RemoveOwnedAura(AuraMap::iterator &i, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3608
Vehicle * GetVehicle() const
Definition: Unit.h:1713
void RemoveAurasByType(AuraType auraType, std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3812
bool isTargetableForAttack(bool checkFakeDeath=true) const
Definition: Unit.cpp:8168
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1321
float GetHealthPct() const
Definition: Unit.h:784
void CombatStop(bool includingCast=false, bool mutualPvP=true, bool(*unitFilter)(Unit const *otherUnit)=nullptr)
Definition: Unit.cpp:5827
void SetCreateStat(Stats stat, float val)
Definition: Unit.h:1392
void SetOffHandWeaponAttackPower(int32 attackPower)
Definition: Unit.h:1525
void AIUpdateTick(uint32 diff)
Definition: Unit.cpp:9525
void SetStat(Stats stat, int32 val)
Definition: Unit.h:761
void SetHealth(uint64 val)
Definition: Unit.cpp:9346
Unit * m_unitMovedByMe
Definition: Unit.h:1898
uint32 GetUnitMovementFlags() const
Definition: Unit.h:1664
LiquidTypeEntry const * _lastLiquid
Definition: Unit.h:1914
bool IsInteractionAllowedInCombat() const
Definition: Unit.h:1052
void RemoveAllControlled()
Definition: Unit.cpp:6428
Pet * ToPet()
Definition: Unit.h:1750
void SetGender(Gender gender)
Definition: Unit.h:756
void UpdateDamagePctDoneMods(WeaponAttackType attackType)
Definition: Unit.cpp:9150
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3685
void UpdateObjectVisibility(bool forced=true) override
Definition: Unit.cpp:11836
int64 ModifyHealth(int64 val)
Definition: Unit.cpp:8182
void SetFullHealth()
Definition: Unit.h:790
void RestoreDisplayId(bool ignorePositiveAurasPreventingMounting=false)
Definition: Unit.cpp:10172
void BuildValuesUpdateForPlayerWithMask(UpdateData *data, UF::ObjectData::Mask const &requestedObjectMask, UF::UnitData::Mask const &requestedUnitMask, Player const *target) const
Definition: Unit.cpp:13416
void ReplaceAllNpcFlags2(NPCFlags2 flags)
Definition: Unit.h:990
virtual void OnPhaseChange()
Definition: Unit.cpp:11832
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
virtual int32 GetCreatePowerValue(Powers power) const
Definition: StatSystem.cpp:89
void AddToWorld() override
Definition: Unit.cpp:9603
void SetModRangedHaste(float rangedHaste)
Definition: Unit.h:828
void RestoreFaction()
Definition: Unit.cpp:11417
float GetPPMProcChance(uint32 WeaponSpeed, float PPM, SpellInfo const *spellProto) const
Definition: Unit.cpp:7873
virtual void AtExitCombat()
Definition: Unit.cpp:8670
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4687
virtual void SetCanDualWield(bool value)
Definition: Unit.h:693
UF::UpdateField< UF::UnitData, 0, TYPEID_UNIT > m_unitData
Definition: Unit.h:1814
uint8 GetClass() const
Definition: Unit.h:752
void SetArmor(int32 val, int32 bonusVal)
Definition: Unit.h:763
uint32 m_regenTimer
Definition: Unit.h:1908
bool CanUseAttackType(uint8 attacktype) const
Definition: Unit.cpp:2492
void SetCreateHealth(uint32 val)
Definition: Unit.h:1393
uint32 GetClassMask() const
Definition: Unit.h:754
bool HasAuraTypeWithCaster(AuraType auraType, ObjectGuid caster) const
Definition: Unit.cpp:4679
Spell * FindCurrentSpellBySpellId(uint32 spell_id) const
Definition: Unit.cpp:3104
uint32 GetMountDisplayId() const
Definition: Unit.h:899
Vehicle * m_vehicle
Definition: Unit.h:1910
Creature * GetVehicleCreatureBase() const
Definition: Unit.cpp:11501
void UpdateDisplayPower()
Definition: Unit.cpp:5625
void SetRace(uint8 race)
Definition: Unit.h:750
float GetCollisionHeight() const override
Definition: Unit.cpp:13733
std::multimap< uint32, AuraApplication * > AuraApplicationMap
Definition: Unit.h:637
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition: Unit.cpp:748
bool IsPolymorphed() const
Definition: Unit.cpp:10127
bool IsAreaSpiritHealer() const
Definition: Unit.h:1002
ShapeshiftForm GetShapeshiftForm() const
Definition: Unit.h:1463
void SetFaction(uint32 faction) override
Definition: Unit.h:859
virtual void SetPvP(bool state)
Definition: Unit.cpp:11610
void SetBaseWeaponDamage(WeaponAttackType attType, WeaponDamageRange damageRange, float value)
Definition: Unit.h:1530
std::forward_list< AuraEffect * > AuraEffectList
Definition: Unit.h:644
void SetPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:9419
virtual void UpdateDamageDoneMods(WeaponAttackType attackType, int32 skipEnchantSlot=-1)
Definition: Unit.cpp:9114
uint32 GetTransformSpell() const
Definition: Unit.h:1574
static void CalcAbsorbResist(DamageInfo &damageInfo, Spell *spell=nullptr)
Definition: Unit.cpp:1797
void InterruptNonMeleeSpells(bool withDelayed, uint32 spellid=0, bool withInstant=true)
Definition: Unit.cpp:3089
bool IsPvP() const
Definition: Unit.h:873
Unit * GetVehicleBase() const
Definition: Unit.cpp:11480
MotionMaster * GetMotionMaster()
Definition: Unit.h:1652
bool IsPet() const
Definition: Unit.h:740
Powers GetPowerType() const
Definition: Unit.h:799
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:832
void Dismount()
Definition: Unit.cpp:7920
void SetCharm(Unit *target, bool apply)
Definition: Unit.cpp:6258
void SetMovedUnit(Unit *target)
Definition: Unit.cpp:9765
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1190
bool CanDualWield() const
Definition: Unit.h:692
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3059
void SetUnitMovementFlags(uint32 f)
Definition: Unit.h:1665
void CleanupsBeforeDelete(bool finalCleanup=true) override
Definition: Unit.cpp:9697
Aura * AddAura(uint32 spellId, Unit *target)
Definition: Unit.cpp:11618
virtual void AtEnterCombat()
Definition: Unit.cpp:8647
void SetModHaste(float haste)
Definition: Unit.h:827
uint32 GetBaseAttackTime(WeaponAttackType att) const
Definition: Unit.cpp:10303
void SetUnitFlag2(UnitFlags2 flags)
Definition: Unit.h:838
bool HasUnitFlag2(UnitFlags2 flags) const
Definition: Unit.h:837
std::string GetDebugInfo() const override
Definition: Unit.cpp:13774
void SetPetNameTimestamp(uint32 timestamp)
Definition: Unit.h:1225
void SetRangedWeaponAttackPower(int32 attackPower)
Definition: Unit.h:1526
void RemoveAllAurasRequiringDeadTarget()
Definition: Unit.cpp:4356
Vignettes::VignetteData const * GetVignette() const
Definition: Unit.h:1809
bool IsAlive() const
Definition: Unit.h:1164
float m_modRangedHitChance
Definition: Unit.h:1472
float GetCombatReach() const override
Definition: Unit.h:694
DeathState m_deathState
Definition: Unit.h:1857
void ApplyAttackTimePercentMod(WeaponAttackType att, float val, bool apply)
Definition: Unit.cpp:10335
void SetBonusResistanceMod(SpellSchools school, int32 val)
Definition: Unit.h:773
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9410
std::pair< AuraApplicationMap::const_iterator, AuraApplicationMap::const_iterator > AuraApplicationMapBounds
Definition: Unit.h:638
void RemoveAllAreaTriggers()
Definition: Unit.cpp:5372
int32 GetMaxPositiveAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4939
GameObject * GetGameObject(uint32 spellId) const
Definition: Unit.cpp:5201
void _ExitVehicle(Position const *exitPosition=nullptr)
Definition: Unit.cpp:12223
void RemoveAllAurasOnDeath()
Definition: Unit.cpp:4333
uint32 m_movementCounter
Incrementing counter used in movement packets.
Definition: Unit.h:1955
bool IsStandState() const
Definition: Unit.cpp:10094
TempSummon * ToTempSummon()
Definition: Unit.h:1756
bool IsQuestGiver() const
Definition: Unit.h:994
CharmInfo * GetCharmInfo()
Definition: Unit.h:1221
bool HasStealthAura() const
Definition: Unit.h:1073
void SetBattlePetCompanionExperience(uint32 experience)
Definition: Unit.h:1248
void RemoveVisFlag(UnitVisFlags flags)
Definition: Unit.h:892
ControlList m_Controlled
Definition: Unit.h:1211
void DisableSpline()
Definition: Unit.cpp:624
void DestroyForPlayer(Player *target) const override
Definition: Unit.cpp:13456
void RemoveAurasWithAttribute(uint32 flags)
Definition: Unit.cpp:4010
void SetModHasteRegen(float hasteRegen)
Definition: Unit.h:829
void UpdateMountCapability()
Definition: Unit.cpp:8051
bool HasNpcFlag2(NPCFlags2 flags) const
Definition: Unit.h:987
void SetBaseAttackTime(WeaponAttackType att, uint32 val)
Definition: Unit.cpp:10308
void AddUnitState(uint32 f)
Definition: Unit.h:731
float GetTotalAuraMultiplier(AuraType auraType) const
Definition: Unit.cpp:4934
void SetBoundingRadius(float boundingRadius)
Definition: Unit.h:697
void SetCreateMana(uint32 val)
Definition: Unit.h:1395
Gender GetGender() const
Definition: Unit.h:755
void SetModSpellHaste(float spellHaste)
Definition: Unit.h:826
bool m_ControlledByPlayer
Definition: Unit.h:1848
void SetMainHandWeaponAttackPower(int32 attackPower)
Definition: Unit.h:1524
void RemoveAurasDueToItemSpell(uint32 spellId, ObjectGuid castItemGuid)
Definition: Unit.cpp:3976
virtual void UpdateDamagePhysical(WeaponAttackType attType)
Definition: StatSystem.cpp:64
void SetRangedAttackPowerMultiplier(float attackPowerMult)
Definition: Unit.h:1523
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7561
void SetCombatReach(float combatReach)
Definition: Unit.h:695
virtual bool UpdatePosition(float x, float y, float z, float ang, bool teleport=false)
Definition: Unit.cpp:12392
void SetPvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:868
bool IsInFlight() const
Definition: Unit.h:1012
void SetResistance(SpellSchools school, int32 val)
Definition: Unit.h:772
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:4999
uint32 GetDisplayId() const
Definition: Unit.h:1567
Unit * GetUnitBeingMoved() const
Definition: Unit.h:1230
bool isPossessing() const
Definition: Unit.cpp:6465
uint32 GetNativeDisplayId() const
Definition: Unit.h:1570
uint64 GetMaxHealth() const
Definition: Unit.h:777
void ClearAllReactives()
Definition: Unit.cpp:10227
void SetRooted(bool apply, bool packetOnly=false)
Definition: Unit.cpp:11039
void AddUnitMovementFlag(uint32 f)
Definition: Unit.h:1661
std::forward_list< Aura * > AuraList
Definition: Unit.h:645
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4560
bool isPossessed() const
Definition: Unit.h:1216
uint16 GetMaxSkillValueForLevel(Unit const *target=nullptr) const
Definition: Unit.h:917
bool HasUnitMovementFlag(uint32 f) const
Definition: Unit.h:1663
uint64 GetHealth() const
Definition: Unit.h:776
bool IsSummon() const
Definition: Unit.h:738
uint32 GetFaction() const override
Definition: Unit.h:858
bool HasAuraState(AuraStateType flag, SpellInfo const *spellProto=nullptr, Unit const *Caster=nullptr) const
Definition: Unit.cpp:5961
void RemoveUnitFlag2(UnitFlags2 flags)
Definition: Unit.h:839
void RemovePvpFlag(UnitPVPStateFlags flags)
Definition: Unit.h:869
bool IsVisible() const
Definition: Unit.cpp:8346
bool HasAuraType(AuraType auraType) const
Definition: Unit.cpp:4674
void RemoveAllDynObjects()
Definition: Unit.cpp:5195
bool HasNpcFlag(NPCFlags flags) const
Definition: Unit.h:981
uint32 GetArmor() const
Definition: Unit.h:762
float m_modMeleeHitChance
Definition: Unit.h:1471
void RemoveArenaAuras()
Definition: Unit.cpp:4289
ObjectGuid GetCritterGUID() const
Definition: Unit.h:1178
uint8 GetLevelForTarget(WorldObject const *) const override
Definition: Unit.h:747
int32 GetTotalAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4929
void SetFullPower(Powers power)
Definition: Unit.h:812
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4101
void ClearUpdateMask(bool remove) override
Definition: Unit.cpp:13471
bool IsFFAPvP() const
Definition: Unit.h:874
bool CanModifyStats() const
Definition: Unit.h:1505
bool IsMounted() const
Definition: Unit.h:898
bool IsDisallowedMountForm(uint32 spellId, ShapeshiftForm form, uint32 displayId) const
Definition: Unit.cpp:8920
void SetAttackPower(int32 attackPower)
Definition: Unit.h:1516
void SetMaxHealth(uint64 val)
Definition: Unit.cpp:9377
void SetPowerType(Powers power, bool sendUpdate=true)
Definition: Unit.cpp:5534
int32 GetPower(Powers power) const
Definition: Unit.cpp:9401
void SetModTimeRate(float timeRate)
Definition: Unit.h:830
bool HasExtraUnitMovementFlag2(uint32 f) const
Definition: Unit.h:1675
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition: Unit.cpp:7376
float GetCreateStat(Stats stat) const
Definition: Unit.h:1400
virtual SpellInfo const * GetCastSpellInfo(SpellInfo const *spellInfo, TriggerCastFlags &triggerFlag) const
Definition: Unit.cpp:13678
Unit * GetFirstControlled() const
Definition: Unit.cpp:6414
void ApplyCastTimePercentMod(float val, bool apply)
Definition: Unit.cpp:10361
std::set< AuraApplication *, VisibleAuraSlotCompare > VisibleAuraContainer
Definition: Unit.h:652
bool IsGossip() const
Definition: Unit.h:995
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
virtual void Update(uint32 time) override
Definition: Unit.cpp:420
void UnsummonAllTotems()
Definition: Unit.cpp:6559
AuraMap m_ownedAuras
Definition: Unit.h:1875
std::array< float, MAX_STATS > m_createStats
Definition: Unit.h:1850
bool IsInFeralForm() const
Definition: Unit.cpp:8909
void SetLevel(uint8 lvl, bool sendUpdate=true)
Definition: Unit.cpp:9329
void SetCanModifyStats(bool modifyStats)
Definition: Unit.h:1506
void SendPlaySpellVisualKit(uint32 id, uint32 type, uint32 duration) const
Definition: Unit.cpp:11711
void SetClass(uint8 classId)
Definition: Unit.h:753
bool HasInvisibilityAura() const
Definition: Unit.h:1074
void RemoveFromWorld() override
Definition: Unit.cpp:9611
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
uint32 HasUnitTypeMask(uint32 mask) const
Definition: Unit.h:736
void ClearInCombat()
Definition: Unit.h:1046
void DoMeleeAttackIfReady()
Definition: Unit.cpp:2093
float GetStat(Stats stat) const
Definition: Unit.h:760
bool IsInteractionAllowedWhileHostile() const
Definition: Unit.h:1049
void SendDurabilityLoss(Player *receiver, uint32 percent)
Definition: Unit.cpp:10522
int32 GetTotalAuraModifierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:4989
SpellHistory * GetSpellHistory()
Definition: Unit.h:1457
bool m_canDualWield
Definition: Unit.h:704
ObjectGuid GetCharmerGUID() const
Definition: Unit.h:1187
bool HasAuraTypeWithValue(AuraType auraType, int32 value) const
Definition: Unit.cpp:4705
bool SetWaterWalking(bool enable)
Definition: Unit.cpp:12863
void SetMaxPower(Powers power, int32 val)
Definition: Unit.cpp:9456
void SendTeleportPacket(Position const &pos)
Definition: Unit.cpp:12343
virtual void setDeathState(DeathState s)
Definition: Unit.cpp:8592
void SetCreatorGUID(ObjectGuid creator)
Definition: Unit.h:1173
UF::UpdateFieldFlag GetUpdateFieldFlagsFor(Player const *target) const override
Definition: Unit.cpp:13360
void HandleStatFlatModifier(UnitMods unitMod, UnitModifierFlatType modifierType, float amount, bool apply)
Definition: Unit.cpp:8963
CombatManager & GetCombatManager()
Definition: Unit.h:1023
void SetUnitFlag(UnitFlags flags)
Definition: Unit.h:833
bool HasAuraTypeWithTriggerSpell(AuraType auratype, uint32 triggerSpell) const
Definition: Unit.cpp:4714
bool IsFlying() const
Definition: Unit.h:1735
AuraApplicationMap & GetAppliedAuras()
Definition: Unit.h:1274
void InitStatBuffMods()
Definition: Unit.cpp:5069
bool IsUninteractible() const
Definition: Unit.h:1037
virtual void ProcessTerrainStatusUpdate(ZLiquidStatus oldLiquidStatus, Optional< LiquidData > const &newLiquidData)
Definition: Unit.cpp:3208
uint32 GetCreateMana() const
Definition: Unit.h:1396
void SetRangedAttackPower(int32 attackPower)
Definition: Unit.h:1520
int32 GetResistance(SpellSchools school) const
Definition: Unit.h:769
AuraList & GetSingleCastAuras()
Definition: Unit.h:1323
bool IsAlwaysDetectableFor(WorldObject const *seer) const override
Definition: Unit.cpp:8335
void SetModCastingSpeed(float castingSpeed)
Definition: Unit.h:825
ObjectGuid GetBattlePetCompanionGUID() const
Definition: Unit.h:1180
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4506
float m_modSpellHitChance
Definition: Unit.h:1473
void ValidateAttackersAndOwnTarget()
Definition: Unit.cpp:5809
virtual void Talk(std::string_view text, ChatMsg msgType, Language language, float textRange, WorldObject const *target)
Definition: Unit.cpp:13554
static void ProcSkillsAndAuras(Unit *actor, Unit *actionTarget, ProcFlagsInit const &typeMaskActor, ProcFlagsInit const &typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition: Unit.cpp:5407
void ReplaceAllNpcFlags(NPCFlags flags)
Definition: Unit.h:984
VisibleAuraContainer const & GetVisibleAuras() const
Definition: Unit.h:1549
void SetAttackPowerMultiplier(float attackPowerMult)
Definition: Unit.h:1519
bool AttackStop()
Definition: Unit.cpp:5781
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
ObjectGuid GetTarget() const
Definition: Unit.h:1759
uint8 GetLevel() const
Definition: Unit.h:746
void SetMountDisplayId(uint32 mountDisplayId)
Definition: Unit.h:900
uint8 GetRace() const
Definition: Unit.h:749
virtual void SetDisplayId(uint32 displayId, bool setNative=false)
Definition: Unit.cpp:10148
void RemoveCharmAuras()
Definition: Unit.cpp:6551
bool IsInCombat() const
Definition: Unit.h:1043
void SetWildBattlePetLevel(uint32 wildBattlePetLevel)
Definition: Unit.h:1250
void InterruptSpell(CurrentSpellTypes spellType, bool withDelayed=true, bool withInstant=true)
Definition: Unit.cpp:3017
void RemoveUnitFlag(UnitFlags flags)
Definition: Unit.h:834
Player * m_playerMovingMe
Definition: Unit.h:1899
float GetWeaponProcChance() const
Definition: Unit.cpp:7862
ObjectGuid GetPetGUID() const
Definition: Unit.h:1176
bool isDead() const
Definition: Unit.h:1166
void UpdateStatBuffMod(Stats stat)
Definition: Unit.cpp:5079
virtual void ExitVehicle(Position const *exitPosition=nullptr)
Definition: Unit.cpp:12204
void CombatStopWithPets(bool includingCast=false)
Definition: Unit.cpp:5855
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1442
bool HasData() const
Definition: UpdateData.h:52
bool BuildPacket(WorldPacket *packet)
Definition: UpdateData.cpp:40
void AddUpdateBlock()
Definition: UpdateData.h:49
uint32 GetBlock(uint32 index) const
Definition: UpdateMask.h:53
void Set(uint32 index)
Definition: UpdateMask.h:84
bool IsAnySet() const
Definition: UpdateMask.h:63
VehicleEntry const * GetVehicleInfo() const
Definition: Vehicle.h:50
constexpr void WorldRelocate(WorldLocation const &loc)
Definition: Position.h:187
constexpr uint32 GetMapId() const
Definition: Position.h:201
uint32 m_mapId
Definition: Position.h:203
constexpr WorldLocation(uint32 mapId=MAPID_INVALID, float x=0.f, float y=0.f, float z=0.f, float o=0.f)
Definition: Position.h:181
bool IsWithinDist3d(float x, float y, float z, float dist) const
Definition: Object.cpp:1122
Map * GetMap() const
Definition: Object.h:624
virtual void ResetMap()
Definition: Object.cpp:1812
Scenario * GetScenario() const
Definition: Object.cpp:2016
ZLiquidStatus GetLiquidStatus() const
Definition: Object.h:550
std::string m_name
Definition: Object.h:795
Map * FindMap() const
Definition: Object.h:625
InstanceScript * GetInstanceScript() const
Definition: Object.cpp:1042
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition: Object.cpp:1783
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
bool IsHostileTo(WorldObject const *target) const
Definition: Object.cpp:2860
float GetTransOffsetX() const
Definition: Object.h:751
PhaseShift & GetPhaseShift()
Definition: Object.h:523
void SetZoneScript()
Definition: Object.cpp:2011
TransportBase * GetTransport() const
Definition: Object.h:750
uint32 GetInstanceId() const
Definition: Object.h:521
FlaggedValuesArray32< int32, uint64, InvisibilityType, TOTAL_INVISIBILITY_TYPES > m_invisibilityDetect
Definition: Object.h:617
bool IsOutdoors() const
Definition: Object.h:549
bool CanSeeOrDetect(WorldObject const *obj, bool implicitDetect=false, bool distanceCheck=false, bool checkAlert=false) const
Definition: Object.cpp:1514
float GetTransOffsetY() const
Definition: Object.h:752
float GetSightRange(WorldObject const *target=nullptr) const
Definition: Object.cpp:1457
std::string const & GetName() const
Definition: Object.h:555
virtual void SetMap(Map *map)
Definition: Object.cpp:1794
float GetTransOffsetZ() const
Definition: Object.h:753
void AddObjectToRemoveList()
Definition: Object.cpp:1824
void UpdatePositionData()
Definition: Object.cpp:992
bool m_isActive
Definition: Object.h:796
void UpdateGroundPositionZ(float x, float y, float &z) const
Definition: Object.cpp:1360
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
ReputationRank GetReactionTo(WorldObject const *target) const
Definition: Object.cpp:2707
void AddToNotify(uint16 f)
Definition: Object.h:732
bool IsInWorldPvpZone() const
Definition: Object.cpp:1027
float GetVisibilityRange() const
Definition: Object.cpp:1447
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibilityDetect
Definition: Object.h:620
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1078
uint32 GetAreaId() const
Definition: Object.h:546
float GetTransOffsetO() const
Definition: Object.h:754
virtual bool CanNeverSee(WorldObject const *obj) const
Definition: Object.cpp:1610
uint32 GetZoneId() const
Definition: Object.h:545
MovementInfo m_movementInfo
Definition: Object.h:761
FlaggedValuesArray32< int32, uint32, ServerSideVisibilityType, TOTAL_SERVERSIDE_VISIBILITY_TYPES > m_serverSideVisibility
Definition: Object.h:619
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition: Object.h:547
virtual bool IsNeverVisibleFor(WorldObject const *seer, bool allowServersideObjects=false) const
Definition: Object.h:821
void GetCreatureListWithOptionsInGrid(Container &creatureContainer, float maxSearchRange, FindCreatureOptions const &options) const
Definition: Object.cpp:3320
bool IsInMap(WorldObject const *obj) const
Definition: Object.cpp:1115
FactionTemplateEntry const * GetFactionTemplateEntry() const
Definition: Object.cpp:2679
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
void Initialize(ChatMsg chatType, Language language, WorldObject const *sender, WorldObject const *receiver, std::string_view message, uint32 achievementId=0, std::string_view channelName="", LocaleConstant locale=DEFAULT_LOCALE, std::string_view addonPrefix="")
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: DuelPackets.cpp:35
WorldPacket const * Write() override
Definition: DuelPackets.cpp:68
std::vector< EquipmentSetInfo::EquipmentSetData const * > SetData
WorldPacket const * Write() override
std::vector< InstanceLock > LockList
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: ItemPackets.cpp:47
WorldPacket const * Write() override
Definition: ItemPackets.cpp:37
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< ItemPurchaseContents > Contents
Definition: ItemPackets.h:149
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< ObjectGuid > ItemGUIDs
Definition: ItemPackets.h:323
WorldPacket const * Write() override
Definition: ItemPackets.cpp:89
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: LootPackets.cpp:97
WorldPacket const * Write() override
Definition: LootPackets.cpp:38
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::map< uint32, HeirloomData > const * Heirlooms
Definition: MiscPackets.h:833
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: MiscPackets.cpp:21
TaggedPosition< Position::XYZ > BindPosition
Definition: MiscPackets.h:51
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > Loc
Definition: MiscPackets.h:331
WorldPacket const * Write() override
WorldPacket const * Write() override
::DisplayToastMethod DisplayToastMethod
Definition: MiscPackets.h:999
WorldPacket const * Write() override
std::array< int32, MAX_POWERS_PER_CLASS > PowerDelta
Definition: MiscPackets.h:509
std::array< int32, MAX_STATS > StatDelta
Definition: MiscPackets.h:510
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: MiscPackets.cpp:37
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< CurrencyDestroyReason > QuantityLostSource
Definition: MiscPackets.h:116
Optional< int32 > QuantityChange
Definition: MiscPackets.h:114
Optional< CurrencyGainSource > QuantityGainSource
Definition: MiscPackets.h:115
Optional< int32 > MaxQuantity
Definition: MiscPackets.h:112
Optional< int32 > WeeklyQuantity
Definition: MiscPackets.h:110
Optional< int32 > TrackedQuantity
Definition: MiscPackets.h:111
Optional< int32 > TotalEarned
Definition: MiscPackets.h:113
WorldPacket const * Write() override
Definition: MiscPackets.cpp:48
WorldPacket const * Write() override
std::vector< Record > Data
Definition: MiscPackets.h:155
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< uint32 > InstanceGroupSize
Definition: MiscPackets.h:268
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< MoveStateChange > StateChanges
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
TaggedPosition< Position::XYZ > OldMapPosition
Optional< ShipTransferPending > Ship
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: NPCPackets.cpp:196
WorldPacket const * Write() override
Definition: NPCPackets.cpp:94
WorldPacket const * GetRawPacket() const
Definition: Packet.h:38
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: PetPackets.cpp:199
CommandStates CommandState
Definition: PetPackets.h:270
std::array< int, 10 > ActionButtons
Definition: PetPackets.h:115
std::vector< uint32 > Actions
Definition: PetPackets.h:117
WorldPacket const * Write() override
Definition: PetPackets.cpp:20
WorldPacket const * Write() override
Definition: PetPackets.cpp:192
WorldPacket const * Write() override
std::vector< PlayerChoiceResponse > Responses
Definition: QuestPackets.h:762
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< QuestGiverInfo > QuestGiver
Definition: QuestPackets.h:89
WorldPacket const * Write() override
WorldPacket const * Write() override
Definition: QuestPackets.h:582
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< AuraInfo > Auras
Definition: SpellPackets.h:192
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< LearnedSpellInfo > ClientLearnedSpellData
Definition: SpellPackets.h:414
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< uint32 > FavoriteSpells
Definition: SpellPackets.h:115
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< SpellModifier > Modifiers
Definition: SpellPackets.h:505
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< SpellCooldownStruct > SpellCooldowns
Definition: SpellPackets.h:584
WorldPacket const * Write() override
WorldPacket const * Write() override
std::vector< LearnedSpellInfo > ClientLearnedSpellData
Definition: SpellPackets.h:426
WorldPacket const * Write() override
std::array< uint64, NumActionButtons > ActionButtons
Definition: SpellPackets.h:127
WorldPacket const * Write() override
std::vector< GlyphBinding > Glyphs
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
ToyBoxContainer const * Toys
Definition: ToyPackets.h:56
WorldPacket const * Write() override
Definition: ToyPackets.cpp:30
WorldPacket const * Write() override
std::vector< ObjectGuid > Removed
WorldPacket const * Write() override
Player session in the World.
Definition: WorldSession.h:963
void SendAuctionHello(ObjectGuid guid, Creature *unit)
void SetPlayer(Player *player)
void SendPetitionShowList(ObjectGuid guid)
char const * GetTrinityString(uint32 entry) const
void SendNotification(char const *format,...) ATTR_PRINTF(2
bool isLogingOut() const
Is the user engaged in a log out process?
AccountTypes GetSecurity() const
Definition: WorldSession.h:999
LocaleConstant GetSessionDbLocaleIndex() const
void SendTaxiMenu(Creature *unit)
Definition: TaxiHandler.cpp:92
void SendLoadCUFProfiles()
void SendPetStableResult(StableResult result)
Definition: NPCHandler.cpp:366
ObjectGuid GetAccountGUID() const
LocaleConstant GetSessionDbcLocale() const
uint32 GetRecruiterId() const
Player * GetPlayer() const
bool PlayerLoading() const
Definition: WorldSession.h:969
void SendItemEnchantTimeUpdate(ObjectGuid Playerguid, ObjectGuid Itemguid, uint32 slot, uint32 Duration)
QueryCallbackProcessor & GetQueryProcessor()
TransactionCallback & AddTransactionCallback(TransactionCallback &&callback)
void SendActivateTaxiReply(ActivateTaxiReply reply)
std::string const & GetRemoteAddress() const
void ResetTimeSync()
bool HasPermission(uint32 permissionId)
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
uint32 GetAccountId() const
void SendVoidStorageTransferResult(VoidTransferError result)
void SendListInventory(ObjectGuid guid)
CollectionMgr * GetCollectionMgr() const
void SendTrainerList(Creature *npc, uint32 trainerId)
Definition: NPCHandler.cpp:112
void DoLootReleaseAll()
bool IsAddonRegistered(std::string_view prefix) const
void SaveTutorialsData(CharacterDatabaseTransaction trans)
time_t m_muteTime
void SendCancelTrade()
BattlePets::BattlePetMgr * GetBattlePetMgr() const
void SendDoFlight(uint32 mountDisplayId, uint32 path, uint32 pathNode=0)
OpcodeServer
Definition: Opcodes.h:901
@ CMSG_MOVE_FALL_LAND
Definition: Opcodes.h:511
@ SMSG_MOVE_ENABLE_DOUBLE_JUMP
Definition: Opcodes.h:1552
@ SMSG_MOVE_ROOT
Definition: Opcodes.h:1559
@ SMSG_MOVE_DISABLE_GRAVITY
Definition: Opcodes.h:1548
@ SMSG_TITLE_LOST
Definition: Opcodes.h:2000
@ SMSG_MOVE_SET_CAN_TURN_WHILE_FALLING
Definition: Opcodes.h:1576
@ SMSG_MOVE_SET_IGNORE_MOVEMENT_FORCES
Definition: Opcodes.h:1583
@ SMSG_MOVE_SET_WATER_WALK
Definition: Opcodes.h:1595
@ SMSG_SET_FLAT_SPELL_MODIFIER
Definition: Opcodes.h:1913
@ SMSG_SET_PCT_SPELL_MODIFIER
Definition: Opcodes.h:1920
@ SMSG_MOVE_SET_HOVERING
Definition: Opcodes.h:1582
@ SMSG_TITLE_EARNED
Definition: Opcodes.h:1999
@ SMSG_MOVE_DISABLE_INERTIA
Definition: Opcodes.h:1549
@ SMSG_MOVE_SET_FEATHER_FALL
Definition: Opcodes.h:1579
#define sWorld
Definition: World.h:931
uint32 GetVirtualRealmAddress()
Definition: World.cpp:3968
Rates
Server rates.
Definition: World.h:452
Realm realm
Definition: World.cpp:3966
@ CONFIG_MAX_INSTANCES_PER_HOUR
Definition: World.h:382
@ CONFIG_CHARDELETE_METHOD
Definition: World.h:370
@ CONFIG_MIN_CREATURE_SCALED_XP_RATIO
Definition: World.h:284
@ CONFIG_QUEST_LOW_LEVEL_HIDE_DIFF
Definition: World.h:317
@ CONFIG_SKILL_CHANCE_ORANGE
Definition: World.h:299
@ CONFIG_GM_CHAT
Definition: World.h:288
@ CONFIG_CHATFLOOD_MUTE_TIME
Definition: World.h:313
@ CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF
Definition: World.h:318
@ CONFIG_GM_WHISPERING_TO
Definition: World.h:289
@ CONFIG_SKILL_CHANCE_SKINNING_STEPS
Definition: World.h:304
@ CONFIG_SKILL_CHANCE_YELLOW
Definition: World.h:300
@ CONFIG_PVP_TOKEN_MAP_TYPE
Definition: World.h:353
@ CONFIG_CHARDELETE_MIN_LEVEL
Definition: World.h:371
@ CONFIG_START_ALLIED_RACE_LEVEL
Definition: World.h:265
@ CONFIG_GAME_TYPE
Definition: World.h:243
@ CONFIG_START_DEMON_HUNTER_PLAYER_LEVEL
Definition: World.h:263
@ CONFIG_START_GM_LEVEL
Definition: World.h:293
@ CONFIG_MIN_LEVEL_STAT_SAVE
Definition: World.h:365
@ CONFIG_START_EVOKER_PLAYER_LEVEL
Definition: World.h:264
@ CONFIG_START_DEATH_KNIGHT_PLAYER_LEVEL
Definition: World.h:262
@ CONFIG_MAX_PLAYER_LEVEL
Definition: World.h:259
@ CONFIG_DEATH_SICKNESS_LEVEL
Definition: World.h:337
@ CONFIG_PVP_TOKEN_ID
Definition: World.h:354
@ CONFIG_PVP_TOKEN_COUNT
Definition: World.h:355
@ CONFIG_SKILL_CHANCE_MINING_STEPS
Definition: World.h:303
@ CONFIG_START_PLAYER_MONEY
Definition: World.h:266
@ CONFIG_START_PLAYER_LEVEL
Definition: World.h:261
@ CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL
Definition: World.h:274
@ CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL_DIFFERENCE
Definition: World.h:275
@ CONFIG_INTERVAL_SAVE
Definition: World.h:234
@ CONFIG_CHATFLOOD_ADDON_MESSAGE_COUNT
Definition: World.h:311
@ CONFIG_GM_LOGIN_STATE
Definition: World.h:286
@ CONFIG_GM_VISIBLE_STATE
Definition: World.h:287
@ CONFIG_GROUP_VISIBILITY
Definition: World.h:295
@ CONFIG_CHARDELETE_DEMON_HUNTER_MIN_LEVEL
Definition: World.h:373
@ CONFIG_MIN_DISCOVERED_SCALED_XP_RATIO
Definition: World.h:285
@ CONFIG_CHARDELETE_KEEP_DAYS
Definition: World.h:369
@ CONFIG_SKILL_GAIN_GATHERING
Definition: World.h:306
@ CONFIG_CHATFLOOD_MESSAGE_DELAY
Definition: World.h:310
@ CONFIG_CHARDELETE_DEATH_KNIGHT_MIN_LEVEL
Definition: World.h:372
@ CONFIG_DISABLE_BREATHING
Definition: World.h:339
@ CONFIG_BATTLEGROUND_REPORT_AFK
Definition: World.h:343
@ CONFIG_HONOR_AFTER_DUEL
Definition: World.h:352
@ CONFIG_EXPANSION
Definition: World.h:308
@ CONFIG_SKILL_GAIN_CRAFTING
Definition: World.h:305
@ CONFIG_CHATFLOOD_MESSAGE_COUNT
Definition: World.h:309
@ CONFIG_CHATFLOOD_ADDON_MESSAGE_DELAY
Definition: World.h:312
@ CONFIG_SKILL_CHANCE_GREY
Definition: World.h:302
@ CONFIG_MAX_PRIMARY_TRADE_SKILL
Definition: World.h:281
@ CONFIG_SKILL_CHANCE_GREEN
Definition: World.h:301
@ CONFIG_WEATHER
Definition: World.h:124
@ CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVP
Definition: World.h:130
@ CONFIG_START_ALL_SPELLS
Definition: World.h:146
@ CONFIG_DEATH_CORPSE_RECLAIM_DELAY_PVE
Definition: World.h:131
@ CONFIG_PVP_TOKEN_ENABLE
Definition: World.h:149
@ CONFIG_INSTANCE_IGNORE_RAID
Definition: World.h:118
@ CONFIG_BATTLEGROUND_CAST_DESERTER
Definition: World.h:136
@ CONFIG_STATS_SAVE_ONLY_ON_LOGOUT
Definition: World.h:108
@ CONFIG_INSTANT_TAXI
Definition: World.h:116
@ CONFIG_NO_RESET_TALENT_COST
Definition: World.h:150
@ CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN
Definition: World.h:144
@ CONFIG_VMAP_INDOOR_CHECK
Definition: World.h:145
@ CONFIG_QUEST_ENABLE_QUEST_TRACKER
Definition: World.h:166
@ CONFIG_INSTANCE_IGNORE_LEVEL
Definition: World.h:117
@ RATE_POWER_CHI
Definition: World.h:466
@ RATE_DAMAGE_FALL
Definition: World.h:518
@ RATE_POWER_RUNIC_POWER_LOSS
Definition: World.h:461
@ RATE_POWER_RAGE_LOSS
Definition: World.h:456
@ RATE_REPUTATION_LOWLEVEL_QUEST
Definition: World.h:491
@ RATE_REPUTATION_LOWLEVEL_KILL
Definition: World.h:490
@ RATE_REST_OFFLINE_IN_WILDERNESS
Definition: World.h:517
@ RATE_POWER_ENERGY
Definition: World.h:458
@ RATE_POWER_MANA
Definition: World.h:454
@ RATE_REST_OFFLINE_IN_TAVERN_OR_CITY
Definition: World.h:516
@ MAX_RATES
Definition: World.h:535
@ RATE_REPUTATION_RECRUIT_A_FRIEND_BONUS
Definition: World.h:492
@ RATE_DROP_MONEY
Definition: World.h:482
@ RATE_MONEY_QUEST
Definition: World.h:533
@ RATE_HEALTH
Definition: World.h:453
@ RATE_DURABILITY_LOSS_ON_DEATH
Definition: World.h:526
@ RATE_XP_QUEST
Definition: World.h:485
@ RATE_POWER_MAELSTROM
Definition: World.h:465
@ RATE_XP_EXPLORE
Definition: World.h:487
@ RATE_POWER_INSANITY
Definition: World.h:467
@ RATE_POWER_FURY
Definition: World.h:469
@ RATE_POWER_FOCUS
Definition: World.h:457
@ RATE_POWER_ARCANE_CHARGES
Definition: World.h:468
@ RATE_HONOR
Definition: World.h:522
@ RATE_POWER_HOLY_POWER
Definition: World.h:464
@ RATE_POWER_LUNAR_POWER
Definition: World.h:463
@ RATE_POWER_ESSENCE
Definition: World.h:471
@ RATE_POWER_SOUL_SHARDS
Definition: World.h:462
@ RATE_POWER_PAIN
Definition: World.h:470
@ RATE_POWER_COMBO_POINTS_LOSS
Definition: World.h:459
@ CONFIG_GROUP_XP_DISTANCE
Definition: World.h:206
@ CONFIG_LISTEN_RANGE_YELL
Definition: World.h:211
@ CONFIG_LISTEN_RANGE_SAY
Definition: World.h:209
@ CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE
Definition: World.h:207
@ CONFIG_LISTEN_RANGE_TEXTEMOTE
Definition: World.h:210
@ SPELL_BATTLE_PET_TRAINING
Definition: BattlePetMgr.h:36
TC_GAME_API uint32 GetId(std::string_view username)
uint64 CreateClubMemberId(ObjectGuid guid)
Definition: ClubUtils.cpp:22
void apply(T *val)
Definition: ByteConverter.h:41
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
Definition: DisableMgr.cpp:285
TC_GAME_API void Trigger(uint32 gameEventId, WorldObject *source, WorldObject *target)
WowTime const * GetWowTime()
Definition: GameTime.cpp:97
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition: GameTime.cpp:54
TimePoint Now()
Current chrono steady_clock time point.
Definition: GameTime.cpp:59
time_t GetGameTime()
Definition: GameTime.cpp:44
uint32 GetGameTimeMS()
Definition: GameTime.cpp:49
TC_COMMON_API char const * GetDate()
Definition: GitRevision.cpp:26
TC_COMMON_API char const * GetHash()
Definition: GitRevision.cpp:21
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Transport * GetTransport(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Object * GetObjectByTypeMask(WorldObject const &, ObjectGuid const &, uint32 typemask)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
TC_GAME_API Pet * GetPet(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
std::unordered_map< std::string, Player * > MapType
constexpr uint32 COMMIT_COMBAT_TRAIT_CONFIG_CHANGES_SPELL_ID
Definition: TraitMgr.h:43
void FillSpentCurrenciesMap(WorldPackets::Traits::TraitEntry const &entry, std::map< int32, int32 > &cachedCurrencies)
Definition: TraitMgr.cpp:422
std::vector< TraitDefinitionEffectPointsEntry const * > const * GetTraitDefinitionEffectPointModifiers(int32 traitDefinitionId)
Definition: TraitMgr.cpp:688
int32 GenerateNewTraitConfigId()
Definition: TraitMgr.cpp:269
LearnResult ValidateConfig(WorldPackets::Traits::TraitConfig const &traitConfig, PlayerDataAccessor player, bool requireSpendingAllCurrencies)
Definition: TraitMgr.cpp:559
bool IsValidEntry(WorldPackets::Traits::TraitEntry const &traitEntry)
Definition: TraitMgr.cpp:543
std::vector< UF::TraitEntry > GetGrantedTraitEntriesForConfig(WorldPackets::Traits::TraitConfig const &traitConfig, PlayerDataAccessor player)
Definition: TraitMgr.cpp:492
auto MapEqualRange(M &map, typename M::key_type const &key)
Definition: IteratorPair.h:60
constexpr IteratorPair< iterator, end_iterator > MakeIteratorPair(iterator first, end_iterator second)
Definition: IteratorPair.h:48
auto MapGetValuePtr(M &map, typename M::key_type const &key)
Definition: MapUtils.h:29
float hk_honor_at_level_f(uint8 level, float multiplier=1.0f)
Definition: Formulas.h:51
TC_GAME_API char const * GetTrinityString(ChatHandler const *handler, TrinityStrings which)
uint8 GetGrayLevel(uint8 pl_level)
Definition: Formulas.h:66
TC_COMMON_API std::vector< std::string_view > Tokenize(std::string_view str, char sep, bool keepEmpty)
Definition: Util.cpp:56
bool IsValidMapCoord(float c)
Definition: GridDefines.h:231
constexpr std::size_t size()
Definition: UpdateField.h:796
UpdateFieldFlag
Definition: UpdateField.h:34
bool CanSee(Player const *player, VignetteData const &vignette)
Definition: Vignette.cpp:112
@ LFG_GROUP_KICK_VOTES_NEEDED
Definition: LFGMgr.h:62
LfgState
Definition: LFG.h:74
@ LFG_STATE_FINISHED_DUNGEON
Definition: LFG.h:81
@ LFG_STATE_NONE
Definition: LFG.h:75
@ RBAC_PERM_COMMAND_GM
Definition: RBAC.h:243
@ RBAC_PERM_JOIN_ARENAS
Definition: RBAC.h:58
@ RBAC_PERM_RESTORE_SAVED_GM_STATE
Definition: RBAC.h:92
@ RBAC_PERM_SKIP_CHECK_MORE_TALENTS_THAN_ALLOWED
Definition: RBAC.h:74
@ RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME
Definition: RBAC.h:70
@ RBAC_PERM_JOIN_NORMAL_BG
Definition: RBAC.h:56
@ RBAC_PERM_USE_CHARACTER_TEMPLATES
Definition: RBAC.h:63
@ RBAC_PERM_TWO_SIDE_INTERACTION_CHAT
Definition: RBAC.h:78
@ RBAC_PERM_CAN_FILTER_WHISPERS
Definition: RBAC.h:89
@ RBAC_PERM_USE_START_GM_LEVEL
Definition: RBAC.h:94
@ RBAC_PERM_JOIN_RANDOM_BG
Definition: RBAC.h:57
@ RBAC_PERM_SKIP_CHECK_CHAT_SPAM
Definition: RBAC.h:75
@ RBAC_PERM_SKIP_CHECK_DISABLE_MAP
Definition: RBAC.h:73
std::string questFailedText
Definition: ObjectMgr.h:476
uint32 achievement
Definition: ObjectMgr.h:475
void SetActionAndType(uint64 action, ActionButtonType type)
Definition: Player.h:328
uint16 ParentAreaID
Definition: DB2Structure.h:131
int16 PvpCombatWorldStateID
Definition: DB2Structure.h:144
EnumFlag< AreaFlags > GetFlags() const
Definition: DB2Structure.h:153
uint8 FactionGroupMask
Definition: DB2Structure.h:141
EnumFlag< AreaFlags2 > GetFlags2() const
Definition: DB2Structure.h:154
int32 ContentTuningID
Definition: DB2Structure.h:148
bool IsSanctuary() const
Definition: DB2Structure.h:157
DBCPosition3D Pos
Definition: DB2Structure.h:165
uint32 target_mapId
Definition: ObjectMgr.h:460
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCastItem(ObjectGuid const &guid, uint32 itemId, int32 itemLevel)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
uint32 SpellId
Definition: SpellAuras.h:106
ObjectGuid Caster
Definition: SpellAuras.h:104
ObjectGuid Item
Definition: SpellAuras.h:105
uint32 EffectMask
Definition: SpellAuras.h:107
std::array< int32, MAX_SPELL_EFFECTS > BaseAmounts
Definition: SpellAuras.h:115
std::array< int32, MAX_SPELL_EFFECTS > Amounts
Definition: SpellAuras.h:114
Team bgTeam
What side the player will be added to.
Definition: Player.h:1009
BattlegroundTypeId bgTypeID
Definition: Player.h:1003
time_t bgAfkReportedTimer
Definition: Player.h:1007
uint32 taxiPath[2]
Definition: Player.h:1012
void ClearTaxiPath()
Definition: Player.h:1017
uint32 bgInstanceID
Definition: Player.h:1001
GuidSet bgAfkReporter
Definition: Player.h:1005
BattlegroundQueueTypeId queueId
Definition: Player.h:1015
bool HasTaxiPath() const
Definition: Player.h:1018
WorldLocation joinPos
From where player entered BG.
Definition: Player.h:1014
uint8 bgAfkReportedCount
Definition: Player.h:1006
uint32 mountSpell
Definition: Player.h:1011
WorldPackets::BattlePet::BattlePet PacketInfo
Definition: BattlePetMgr.h:140
constexpr uint64 GetPacked() const
static constexpr BattlegroundQueueTypeId FromPacked(uint64 packedQueueId)
BattlegroundTypeId Id
uint8 GetMaxLevel() const
Definition: Item.h:69
uint32 AppearanceModID
Definition: Item.h:78
void Initialize(ItemTemplate const *proto)
Definition: Item.cpp:2829
CastSpellExtraArgs & SetTriggerFlags(TriggerCastFlags flag)
Definition: SpellDefines.h:467
CastSpellExtraArgs & AddSpellMod(SpellValueMod mod, int32 val)
Definition: SpellDefines.h:474
CastSpellExtraArgs & SetCastItem(Item *item)
Definition: SpellDefines.h:468
static void VisitAllObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:203
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:191
uint32 GetPetNumber() const
Definition: CharmInfo.h:94
CharmSpellInfo * GetCharmSpell(uint8 index)
Definition: CharmInfo.h:121
void SetPetNumber(uint32 petnumber, bool statwindow)
Definition: CharmInfo.cpp:227
CommandStates GetCommandState() const
Definition: CharmInfo.h:98
UnitActionBarEntry const * GetActionBarEntry(uint8 index) const
Definition: CharmInfo.h:117
ChatChannelRuleset GetRuleset() const
Definition: DB2Structure.h:622
EnumFlag< ChatChannelFlags > GetFlags() const
Definition: DB2Structure.h:621
uint32 ArmorTypeMask
Definition: DB2Structure.h:652
int32 ResSicknessSpellID
Definition: DB2Structure.h:816
std::array< int32, MAX_MASTERY_SPELLS > MasterySpellID
Definition: DB2Structure.h:870
Optional< std::vector< uint32 > > DespawnOnQuestsRemoved
Definition: CreatureData.h:618
CreatureDifficulty const * GetDifficulty(Difficulty difficulty) const
Definition: Creature.cpp:238
CreatureFamily family
Definition: CreatureData.h:507
std::vector< uint32 > GossipMenuIds
Definition: CreatureData.h:488
uint32 KillCredit[MAX_KILL_CREDIT]
Definition: CreatureData.h:481
bool IsTameable(bool canTameExotic, CreatureDifficulty const *creatureDifficulty) const
Definition: CreatureData.h:541
bool IsSuppressingChatLog(bool onUpdateVersion=false) const
bool HasTotalEarned() const
bool IsHorde() const
bool HasMaxEarnablePerWeek() const
int32 GetScaler() const
bool HasMaxQuantity(bool onLoad=false, bool onUpdateVersion=false) const
EnumFlag< CurrencyTypesFlags > GetFlags() const
bool IsTrackingQuantity() const
bool IsAlliance() const
Data sent in EquipmentSet related packets.
Definition: EquipmentSet.h:46
std::array< ObjectGuid, EQUIPMENT_SET_SLOTS > Pieces
Definition: EquipmentSet.h:54
uint32 IgnoreMask
Mask of EquipmentSlot.
Definition: EquipmentSet.h:50
uint64 Guid
Set Identifier.
Definition: EquipmentSet.h:48
int32 AssignedSpecIndex
Index of character specialization that this set is automatically equipped for.
Definition: EquipmentSet.h:51
std::array< int32, 2 > Enchants
SpellItemEnchantmentID.
Definition: EquipmentSet.h:56
std::array< int32, EQUIPMENT_SET_SLOTS > Appearances
ItemModifiedAppearanceID.
Definition: EquipmentSet.h:55
EquipmentSetUpdateState State
Server-side data.
Definition: EquipmentSet.h:64
struct EquipmentSetInfo::EquipmentSetData Data
bool IsFriendlyTo(FactionTemplateEntry const *entry) const
uint32 GetGossipMenuId() const
std::string IconName
int32 FriendshipFactionID
Definition: ObjectMgr.h:772
Optional< int32 > GossipNpcOptionID
Definition: GossipDef.h:123
uint32 OrderIndex
Definition: GossipDef.h:118
GossipOptionNpc OptionNpc
Definition: GossipDef.h:119
uint32 BoxMoney
Definition: GossipDef.h:125
uint32 ActionPoiID
Definition: GossipDef.h:132
uint32 ActionMenuID
Definition: GossipDef.h:131
float VersatilityDamageTaken
Definition: GameTables.h:99
float ResiliencePlayerDamage
Definition: GameTables.h:84
float VersatilityHealingDone
Definition: GameTables.h:98
float CorruptionResistance
Definition: GameTables.h:81
float VersatilityDamageDone
Definition: GameTables.h:97
uint32 CompletedEncountersMask
Optional< ArtifactData > Artifact
Definition: Item.h:155
Optional< AzeriteEmpoweredItemData > AzeriteEmpoweredItem
Definition: Item.h:157
static void Init(std::unordered_map< ObjectGuid::LowType, ItemAdditionalLoadInfo > *loadInfo, PreparedQueryResult artifactResult, PreparedQueryResult azeriteItemResult, PreparedQueryResult azeriteItemMilestonePowersResult, PreparedQueryResult azeriteItemUnlockedEssencesResult, PreparedQueryResult azeriteEmpoweredItemResult)
Definition: Item.cpp:310
Optional< AzeriteItemData > AzeriteItem
Definition: Item.h:156
std::array< uint32, MAX_ITEM_EXT_COST_CURRENCIES > CurrencyCount
std::array< int32, MAX_ITEM_EXT_COST_ITEMS > ItemID
std::array< uint16, MAX_ITEM_EXT_COST_ITEMS > ItemCount
std::array< uint16, MAX_ITEM_EXT_COST_CURRENCIES > CurrencyID
bool isContainedIn(std::vector< ItemPosCount > const &vec) const
Definition: Player.cpp:26121
std::unordered_set< ItemSetSpellEntry const * > SetBonuses
Definition: Item.h:45
uint32 GetRequiredSkillRank() const
Definition: ItemTemplate.h:792
uint32 GetBaseItemLevel() const
Definition: ItemTemplate.h:789
uint32 GetQuality() const
Definition: ItemTemplate.h:779
HolidayIds GetHolidayID() const
Definition: ItemTemplate.h:822
bool CanChangeEquipStateInCombat() const
uint32 GetBuyCount() const
Definition: ItemTemplate.h:783
int32 GetAllowableClass() const
Definition: ItemTemplate.h:787
uint32 GetContainerSlots() const
Definition: ItemTemplate.h:797
uint32 GetGemProperties() const
Definition: ItemTemplate.h:818
uint32 GetId() const
Definition: ItemTemplate.h:776
uint32 GetMaxStackSize() const
Definition: ItemTemplate.h:847
InventoryType GetInventoryType() const
Definition: ItemTemplate.h:786
bool IsRangedWeapon() const
Definition: ItemTemplate.h:863
uint32 GetBuyPrice() const
Definition: ItemTemplate.h:784
ItemBondingType GetBonding() const
Definition: ItemTemplate.h:806
uint32 GetArmor(uint32 itemLevel) const
uint32 GetItemSet() const
Definition: ItemTemplate.h:811
uint32 GetStartQuest() const
Definition: ItemTemplate.h:809
uint8 GetArtifactID() const
Definition: ItemTemplate.h:824
uint32 GetRequiredReputationFaction() const
Definition: ItemTemplate.h:794
std::vector< ItemEffectEntry const * > Effects
Definition: ItemTemplate.h:828
bool IsCraftingReagent() const
Definition: ItemTemplate.h:857
uint32 GetRequiredReputationRank() const
Definition: ItemTemplate.h:795
uint32 GetItemLimitCategory() const
Definition: ItemTemplate.h:821
int32 QuestLogItemId
Definition: ItemTemplate.h:840
int32 GetBaseRequiredLevel() const
Definition: ItemTemplate.h:790
bool HasFlag(ItemFlags flag) const
Definition: ItemTemplate.h:871
void GetDamage(uint32 itemLevel, float &minDamage, float &maxDamage) const
uint32 GetSubClass() const
Definition: ItemTemplate.h:778
bool IsUsableByLootSpecialization(Player const *player, bool alwaysAllowBoundToAccount) const
Trinity::RaceMask< int64 > GetAllowableRace() const
Definition: ItemTemplate.h:788
uint32 GetRequiredSpell() const
Definition: ItemTemplate.h:793
float SpellPPMRate
Definition: ItemTemplate.h:836
uint32 GetTotemCategory() const
Definition: ItemTemplate.h:815
uint32 ItemSpecClassMask
Definition: ItemTemplate.h:839
uint32 GetClass() const
Definition: ItemTemplate.h:777
uint32 GetRequiredSkill() const
Definition: ItemTemplate.h:791
uint32 GetMaxCount() const
Definition: ItemTemplate.h:796
float GetDPS(uint32 itemLevel) const
uint32 GetDelay() const
Definition: ItemTemplate.h:804
uint32 GetSkill() const
uint32 GetBagFamily() const
Definition: ItemTemplate.h:814
Definition: Loot.h:176
bool HasAllowedLooter(ObjectGuid const &looter) const
Definition: Loot.cpp:136
uint32 itemid
Definition: Loot.h:177
bool is_blocked
Definition: Loot.h:187
ObjectGuid rollWinnerGUID
Definition: Loot.h:184
uint32 LootListId
Definition: Loot.h:178
uint8 count
Definition: Loot.h:185
bool is_looted
Definition: Loot.h:186
ItemRandomBonusListId randomBonusListId
Definition: Loot.h:179
ItemContext context
Definition: Loot.h:181
GuidSet const & GetAllowedLooters() const
Definition: Loot.h:213
bool freeforall
Definition: Loot.h:188
Definition: Loot.h:281
bool AutoStore(Player *player, uint8 bag, uint8 slot, bool broadcast=false, bool createdByPlayer=false)
Definition: Loot.cpp:849
void OnLootOpened(Map *map, ObjectGuid looter)
Definition: Loot.cpp:696
bool isLooted() const
Definition: Loot.h:307
bool hasOverThresholdItem() const
Definition: Loot.cpp:986
void BuildLootResponse(WorldPackets::Loot::LootResponse &packet, Player const *viewer) const
Definition: Loot.cpp:997
void NotifyItemRemoved(uint8 lootListId, Map const *map)
Definition: Loot.cpp:658
uint8 unlootedCount
Definition: Loot.h:286
ObjectGuid roundRobinPlayer
Definition: Loot.h:287
ObjectGuid const & GetOwnerGUID() const
Definition: Loot.h:299
bool hasItemFor(Player const *player) const
Definition: Loot.cpp:965
bool hasItemForAll() const
Definition: Loot.cpp:952
LootItem * LootItemInSlot(uint32 lootListId, Player const *player, NotNormalLootItem **ffaItem=nullptr)
Definition: Loot.cpp:917
ObjectGuid const & GetGUID() const
Definition: Loot.h:298
bool FillLoot(uint32 lootId, LootStore const &store, Player *lootOwner, bool personal, bool noEmptyError=false, uint16 lootMode=LOOT_MODE_DEFAULT, ItemContext context=ItemContext::NONE)
Definition: Loot.cpp:759
uint32 GetDungeonEncounterId() const
Definition: Loot.h:304
LootMethod GetLootMethod() const
Definition: Loot.h:302
LootType loot_type
Definition: Loot.h:288
bool HasAllowedLooter(ObjectGuid const &looter) const
Definition: Loot.cpp:740
Definition: Mail.h:175
uint64 messageID
Definition: Mail.h:176
bool HasItems() const
Definition: Mail.h:214
ObjectGuid::LowType receiver
Definition: Mail.h:181
uint8 messageType
Definition: Mail.h:177
uint64 money
Definition: Mail.h:188
uint64 COD
Definition: Mail.h:189
time_t expire_time
Definition: Mail.h:186
uint8 stationery
Definition: Mail.h:178
ObjectGuid::LowType sender
Definition: Mail.h:180
std::string subject
Definition: Mail.h:182
std::vector< ObjectGuid::LowType > removedItems
Definition: Mail.h:185
std::string body
Definition: Mail.h:183
std::vector< MailItemInfo > items
Definition: Mail.h:184
void AddItem(ObjectGuid::LowType itemGuidLow, uint32 item_template)
Definition: Mail.h:193
time_t deliver_time
Definition: Mail.h:187
uint32 checked
Definition: Mail.h:190
MailState state
Definition: Mail.h:191
uint16 mailTemplateId
Definition: Mail.h:179
LocalizedString Message
int16 CosmeticParentMapID
std::array< int32, 3 > Flags
bool IsBattlegroundOrArena() const
uint8 Expansion() const
uint32 ID
bool IsDungeon() const
bool IsRaid() const
bool IsBattleArena() const
bool Instanceable() const
int32 SourceSpellID
void ResetJump()
Definition: MovementInfo.h:134
struct MovementInfo::JumpInfo jump
float stepUpStartElevation
Definition: MovementInfo.h:87
struct MovementInfo::TransportInfo transport
bool HasMovementFlag(uint32 flag) const
Definition: MovementInfo.h:112
void AddMovementFlag(uint32 flag)
Definition: MovementInfo.h:110
Position pos
Definition: MovementInfo.h:34
bool is_looted
Definition: Loot.h:221
uint32 CreatedBySpellId
Definition: PetDefines.h:149
ReactStates ReactState
Definition: PetDefines.h:152
std::string Name
Definition: PetDefines.h:140
uint16 SpecializationId
Definition: PetDefines.h:150
std::string ActionBar
Definition: PetDefines.h:141
std::unordered_map< int32, PlayerChoiceResponseLocale > Responses
Definition: ObjectMgr.h:554
std::vector< std::string > Question
Definition: ObjectMgr.h:553
std::vector< int32 > BonusListIDs
Definition: ObjectMgr.h:871
std::string Confirmation
Definition: ObjectMgr.h:925
uint16 ResponseIdentifier
Definition: ObjectMgr.h:912
std::string ButtonTooltip
Definition: ObjectMgr.h:923
uint32 UiTextureAtlasElementID
Definition: ObjectMgr.h:916
Optional< uint32 > RewardQuestID
Definition: ObjectMgr.h:927
Optional< PlayerChoiceResponseReward > Reward
Definition: ObjectMgr.h:926
Optional< PlayerChoiceResponseMawPower > MawPower
Definition: ObjectMgr.h:928
std::string Answer
Definition: ObjectMgr.h:920
std::string Description
Definition: ObjectMgr.h:924
std::string SubHeader
Definition: ObjectMgr.h:922
std::string Header
Definition: ObjectMgr.h:921
uint32 SoundKitId
Definition: ObjectMgr.h:935
bool HideWarboardHeader
Definition: ObjectMgr.h:941
bool KeepOpenAfterChoice
Definition: ObjectMgr.h:942
std::vector< PlayerChoiceResponse > Responses
Definition: ObjectMgr.h:940
std::string Question
Definition: ObjectMgr.h:938
int32 UiTextureKitId
Definition: ObjectMgr.h:934
uint32 TrackedQuantity
Definition: Player.h:268
uint32 EarnedQuantity
Definition: Player.h:270
uint32 IncreasedCapQuantity
Definition: Player.h:269
uint32 WeeklyQuantity
Definition: Player.h:267
CurrencyDbFlags Flags
Definition: Player.h:271
uint32 Quantity
Definition: Player.h:266
PlayerCurrencyState state
Definition: Player.h:265
Optional< ObjectGuid::LowType > TransportGuid
Definition: ObjectMgr.h:656
PlayerCreateInfoActions action
Definition: ObjectMgr.h:666
ItemContext itemContext
Definition: ObjectMgr.h:662
PlayerCreateInfoSkills skills
Definition: ObjectMgr.h:667
Optional< CreatePosition > createPositionNPE
Definition: ObjectMgr.h:660
PlayerCreateInfoSpells customSpells
Definition: ObjectMgr.h:664
CreatePosition createPosition
Definition: ObjectMgr.h:659
PlayerCreateInfoItems item
Definition: ObjectMgr.h:663
uint16 stats[MAX_STATS]
Definition: ObjectMgr.h:632
bool favorite
Definition: Player.h:199
Optional< int32 > TraitDefinitionId
Definition: Player.h:200
bool active
Definition: Player.h:196
bool disabled
Definition: Player.h:198
bool dependent
Definition: Player.h:197
PlayerSpellState state
Definition: Player.h:195
BattlegroundQueueTypeId bgQueueTypeId
Definition: Player.h:2890
void operator()(Player const *player) const
Definition: Player.cpp:3749
UF::ActivePlayerData::Base ActivePlayerMask
Definition: Player.h:2123
constexpr float GetPositionX() const
Definition: Position.h:76
float m_positionZ
Definition: Position.h:55
constexpr float GetPositionY() const
Definition: Position.h:77
std::string ToString() const
Definition: Position.cpp:128
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
constexpr Position(float x=0, float y=0, float z=0, float o=0)
Definition: Position.h:29
constexpr void GetPosition(float &x, float &y) const
Definition: Position.h:81
bool IsPositionValid() const
Definition: Position.cpp:42
bool IsWithinBox(Position const &center, float xradius, float yradius, float zradius) const
Definition: Position.cpp:65
constexpr void Relocate(float x, float y)
Definition: Position.h:63
constexpr float GetExactDistSq(float x, float y, float z) const
Definition: Position.h:110
constexpr Position GetPosition() const
Definition: Position.h:84
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
int32 RegenInterruptTimeMS
EnumFlag< PowerTypeFlags > GetFlags() const
bool IsHostile
Definition: Player.h:348
bool IsInNoPvPArea
‍Marks if player is in an area which forces PvP flag
Definition: Player.h:350
bool IsInFFAPvPArea
‍Marks if player is in a sanctuary or friendly capital city
Definition: Player.h:351
bool IsInHostileArea
Definition: Player.h:349
time_t EndTimer
‍Marks if player is in an FFAPvP area (such as Gurubashi Arena)
Definition: Player.h:352
int32 OverridesSpellID
int32 PvpTalentCategoryID
int32 PlayerConditionID
uint32 QuestId
Definition: GossipDef.h:144
uint8 QuestIcon
Definition: GossipDef.h:145
Optional< uint32 > SpellId
Definition: QuestDef.h:437
Optional< uint32 > ConversationId
Definition: QuestDef.h:438
Optional< uint32 > GameEventId
Definition: QuestDef.h:436
bool IsStoringFlag() const
Definition: QuestDef.h:479
static constexpr bool CanAlwaysBeProgressedInRaid(QuestObjectiveType type)
Definition: QuestDef.h:496
QuestObjectiveAction * CompletionEffect
Definition: QuestDef.h:456
int32 ObjectID
Definition: QuestDef.h:449
uint32 Flags2
Definition: QuestDef.h:452
bool IsStoringValue() const
Definition: QuestDef.h:458
int8 StorageIndex
Definition: QuestDef.h:448
uint32 Flags
Definition: QuestDef.h:451
uint32 QuestID
Definition: QuestDef.h:446
int32 Amount
Definition: QuestDef.h:450
uint32 Timer
Definition: QuestDef.h:843
QuestStatus Status
Definition: QuestDef.h:841
time_t AcceptTime
Definition: QuestDef.h:842
uint32 Build
Definition: Realm.h:83
Battlenet::RealmHandle Id
Definition: Realm.h:82
void SetRuneState(uint8 index, bool set=true)
Definition: Player.cpp:26344
uint32 ParentSkillLineID
uint32 GetValueForTierIndex(uint32 tierIndex) const
Definition: ObjectMgr.cpp:7938
WorldPackets::Spells::SpellCastRequest CastRequest
Optional< SpellCastRequestItemData > ItemData
std::array< uint32, MAX_ITEM_ENCHANTMENT_EFFECTS > EffectArg
std::array< int16, MAX_ITEM_ENCHANTMENT_EFFECTS > EffectPointsMin
std::array< uint8, MAX_ITEM_ENCHANTMENT_EFFECTS > Effect
std::array< float, MAX_ITEM_ENCHANTMENT_EFFECTS > EffectScalingPoints
EnumFlag< SpellItemEnchantmentFlags > GetFlags() const
SpellModOp op
Definition: Player.h:229
SpellModType type
Definition: Player.h:230
uint32 spellId
Definition: Player.h:232
Aura *const ownerAura
Definition: Player.h:233
enum StoredAuraTeleportLocation::@282 State
WorldLocation Loc
Definition: Player.h:205
uint32 OverridesSpellID
uint32 SpellID
uint8 ColumnIndex
EnumFlag< TaxiNodeFlags > GetFlags() const
DBCPosition3D Pos
uint16 FromTaxiNode
DBCPosition3D Loc
void Update(int32 diff)
Definition: Timer.h:121
bool Passed() const
Definition: Timer.h:131
void Reset(int32 expiry)
Definition: Timer.h:136
TraitCurrencyType GetType() const
int32 GetCurrencyQuantity(int32 currencyId) const
Definition: Player.cpp:30199
uint32 GetPrimarySpecialization() const
Definition: Player.cpp:30219
bool HasAchieved(int32 achievementId) const
Definition: Player.cpp:30214
bool IsQuestRewarded(int32 questId) const
Definition: Player.cpp:30209
constexpr bool HasRace(uint8 raceId) const
Definition: RaceMask.h:88
DynamicUpdateField< uint64, 0, 7 > KnownTitles
Definition: UpdateFields.h:892
UpdateField< int32, 32, 47 > XP
Definition: UpdateFields.h:923
UpdateField< float, 32, 61 > ParryPercentage
Definition: UpdateFields.h:937
UpdateField< uint8, 104, 108 > LocalRegenFlags
Definition: UpdateFields.h:982
UpdateFieldArray< uint64, 950, 483, 484 > QuestCompleted
DynamicUpdateField< UF::CategoryCooldownMod, 32, 33 > CategoryCooldownMods
Definition: UpdateFields.h:913
UpdateField< uint8, 104, 109 > AuraVision
Definition: UpdateFields.h:983
UpdateField< int32, 32, 48 > NextLevelXP
Definition: UpdateFields.h:924
UpdateFieldArray< int32, 32, 428, 429 > CombatRatings
UpdateField< float, 32, 63 > CritPercentage
Definition: UpdateFields.h:939
UpdateField< float, 32, 64 > RangedCritPercentage
Definition: UpdateFields.h:940
UpdateField< int32, 32, 67 > ShieldBlock
Definition: UpdateFields.h:943
UpdateField< float, 72, 79 > ModHealingPercent
Definition: UpdateFields.h:954
UpdateField< uint16, 72, 94 > YesterdayHonorableKills
Definition: UpdateFields.h:969
UpdateField< int32, 32, 52 > MaxTalentTiers
Definition: UpdateFields.h:928
UpdateField< int32, 72, 78 > ModHealingDonePos
Definition: UpdateFields.h:953
DynamicUpdateField< UF::SpellFlatModByLabel, 0, 22 > SpellFlatModByLabel
Definition: UpdateFields.h:905
UpdateField< float, 32, 59 > DodgePercentage
Definition: UpdateFields.h:935
UpdateFieldArray< float, 3, 396, 400 > WeaponAtkSpeedMultipliers
UpdateFieldArray< float, 3, 396, 397 > WeaponDmgMultipliers
UpdateField< ObjectGuid, 32, 44 > FarsightObject
Definition: UpdateFields.h:920
UpdateFieldArray< float, 7, 367, 382 > ModDamageDonePercent
UpdateField< int32, 104, 115 > HonorNextLevel
Definition: UpdateFields.h:989
UpdateFieldArray< int32, 7, 367, 375 > ModDamageDoneNeg
UpdateFieldArray< float, 7, 367, 389 > ModHealingDonePercent
UpdateField< int32, 72, 85 > ModTargetResistance
Definition: UpdateFields.h:960
UpdateField< uint32, 72, 95 > LifetimeHonorableKills
Definition: UpdateFields.h:970
UpdateField< int32, 72, 86 > ModTargetPhysicalResistance
Definition: UpdateFields.h:961
UpdateField< uint16, 72, 93 > TodayHonorableKills
Definition: UpdateFields.h:968
DynamicUpdateField< UF::TraitConfig, 0, 29 > TraitConfigs
Definition: UpdateFields.h:918
UpdateFieldArray< int32, 7, 367, 368 > ModDamageDonePos
UpdateField< int32, 72, 97 > MaxLevel
Definition: UpdateFields.h:972
UpdateFieldArray< int32, 2, 466, 467 > ProfessionSkillLine
UpdateField< uint8, 104, 110 > NumBackpackSlots
Definition: UpdateFields.h:984
UpdateField< float, 72, 80 > ModPeriodicHealingDonePercent
Definition: UpdateFields.h:955
UpdateField< float, 32, 66 > SpellCritPercentage
Definition: UpdateFields.h:942
OptionalUpdateField< UF::StableInfo, 104, 134 > PetStable
UpdateField< uint64, 32, 46 > Coinage
Definition: UpdateFields.h:922
UpdateField< float, 32, 58 > BlockPercentage
Definition: UpdateFields.h:934
DynamicUpdateField< UF::SpellPctModByLabel, 0, 21 > SpellPctModByLabel
Definition: UpdateFields.h:904
UpdateField< float, 72, 81 > ModSpellPowerPercent
Definition: UpdateFields.h:956
UpdateField< int32, 72, 98 > ScalingPlayerLevelDelta
Definition: UpdateFields.h:973
UpdateFieldArray< DynamicUpdateFieldBase< uint64 >, 8, 36, 37 > DataFlags
Definition: UpdateFields.h:888
DynamicUpdateField< int32, 0, 9 > DailyQuestsCompleted
Definition: UpdateFields.h:893
UpdateField< float, 32, 65 > OffhandCritPercentage
Definition: UpdateFields.h:941
UpdateField< int32, 104, 114 > Honor
Definition: UpdateFields.h:988
uint8 CurrentRankWithBonus
Definition: UpdateFields.h:99
UpdateField< int32, 0, 5 > BackgroundColor
Definition: UpdateFields.h:482
UpdateField< int32, 0, 2 > EmblemColor
Definition: UpdateFields.h:479
UpdateField< int32, 0, 3 > BorderStyle
Definition: UpdateFields.h:480
UpdateField< int32, 0, 4 > BorderColor
Definition: UpdateFields.h:481
UpdateField< int32, 0, 1 > EmblemStyle
Definition: UpdateFields.h:478
UpdateFieldArray< std::string, 5, 0, 1 > Name
Definition: UpdateFields.h:469
UpdateField< uint32, 0, 2 > DynamicFlags
Definition: UpdateFields.h:53
UpdateField< uint8, 0, 19 > Inebriation
Definition: UpdateFields.h:509
UpdateFieldArray< uint8, 2, 43, 44 > PartyType
Definition: UpdateFields.h:532
UpdateField< int32, 0, 30 > HonorLevel
Definition: UpdateFields.h:520
UpdateFieldArray< UF::VisibleItem, 19, 222, 223 > VisibleItems
Definition: UpdateFields.h:534
UpdateField< std::string, 32, 33 > Name
Definition: UpdateFields.h:522
UpdateField< UF::CustomTabardInfo, 32, 42 > PersonalTabard
Definition: UpdateFields.h:531
UpdateField< ObjectGuid, 0, 9 > WowAccount
Definition: UpdateFields.h:499
UpdateField< int64, 0, 31 > LogoutTime
Definition: UpdateFields.h:521
OptionalUpdateField< UF::DeclinedNames, 32, 41 > DeclinedNames
Definition: UpdateFields.h:530
UpdateFieldArray< UF::QuestLog, 175, 46, 47 > QuestLog
Definition: UpdateFields.h:533
UpdateField< uint64, 0, 11 > GuildClubMemberID
Definition: UpdateFields.h:501
UpdateField< ObjectGuid, 0, 10 > BnetAccount
Definition: UpdateFields.h:500
UpdateField< int32, 0, 2 > QuestID
Definition: UpdateFields.h:430
UpdateField< uint32, 0, 3 > StateFlags
Definition: UpdateFields.h:431
UpdateFieldArray< int16, 24, 5, 6 > ObjectiveProgress
Definition: UpdateFields.h:433
UpdateField< uint32, 0, 4 > ObjectiveFlags
Definition: UpdateFields.h:432
UpdateField< int64, 0, 1 > EndTime
Definition: UpdateFields.h:429
UpdateField< int32, 0, 1 > ItemID
Definition: UpdateFields.h:109
UpdateField< ObjectGuid, 0, 2 > StableMaster
Definition: UpdateFields.h:852
DynamicUpdateField< UF::StablePetInfo, 0, 1 > Pets
Definition: UpdateFields.h:851
UpdateField< uint32, 0, 5 > ExperienceLevel
Definition: UpdateFields.h:840
UpdateField< uint32, 0, 2 > PetNumber
Definition: UpdateFields.h:837
UpdateField< uint32, 0, 1 > PetSlot
Definition: UpdateFields.h:836
UpdateField< std::string, 0, 6 > Name
Definition: UpdateFields.h:841
UpdateField< uint8, 0, 7 > PetFlags
Definition: UpdateFields.h:842
UpdateField< uint32, 0, 4 > DisplayID
Definition: UpdateFields.h:839
UpdateField< uint32, 0, 3 > CreatureID
Definition: UpdateFields.h:838
UpdateField< int32, 4, 7 > ChrSpecializationID
Definition: UpdateFields.h:738
UpdateField< int32, 4, 6 > SkillLineID
Definition: UpdateFields.h:737
UpdateField< int32, 4, 5 > Type
Definition: UpdateFields.h:736
UpdateField< int32, 8, 9 > CombatConfigFlags
Definition: UpdateFields.h:739
UpdateField< std::string, 0, 3 > Name
Definition: UpdateFields.h:735
DynamicUpdateField< UF::TraitEntry, 0, 1 > Entries
Definition: UpdateFields.h:733
UpdateField< int32, 8, 10 > LocalIdentifier
Definition: UpdateFields.h:740
UpdateField< int32, 0, 2 > ID
Definition: UpdateFields.h:734
UpdateField< int32, 8, 11 > TraitSystemID
Definition: UpdateFields.h:741
int32 TraitNodeEntryID
Definition: UpdateFields.h:721
UpdateFieldArray< float, 10, 130, 161 > PowerRegenInterruptedFlatModifier
Definition: UpdateFields.h:397
UpdateField< float, 96, 102 > MinRangedDamage
Definition: UpdateFields.h:366
UpdateFieldArray< uint32, 2, 127, 128 > NpcFlags
Definition: UpdateFields.h:392
UpdateField< int32, 0, 5 > DisplayID
Definition: UpdateFields.h:266
UpdateField< uint32, 0, 7 > StateAnimID
Definition: UpdateFields.h:269
UpdateField< float, 32, 60 > MinOffHandDamage
Definition: UpdateFields.h:325
UpdateField< ObjectGuid, 96, 121 > GuildGUID
Definition: UpdateFields.h:386
UpdateField< float, 32, 59 > MaxDamage
Definition: UpdateFields.h:324
UpdateField< float, 32, 61 > MaxOffHandDamage
Definition: UpdateFields.h:326
UpdateField< uint32, 32, 44 > Flags
Definition: UpdateFields.h:306
UpdateField< float, 32, 58 > MinDamage
Definition: UpdateFields.h:323
UpdateField< uint32, 32, 47 > AuraState
Definition: UpdateFields.h:311
UpdateFieldArray< int32, 10, 130, 131 > Power
Definition: UpdateFields.h:394
UpdateField< float, 96, 103 > MaxRangedDamage
Definition: UpdateFields.h:367
UpdateFieldArray< float, 10, 130, 151 > PowerRegenFlatModifier
Definition: UpdateFields.h:396
UpdateFieldArray< int32, 7, 195, 210 > ManaCostModifier
Definition: UpdateFields.h:406
UpdateField< uint16, 0, 4 > ItemAppearanceModID
Definition: UpdateFields.h:241
UpdateField< int32, 0, 2 > SecondaryItemModifiedAppearanceID
Definition: UpdateFields.h:239
UpdateField< uint16, 0, 5 > ItemVisual
Definition: UpdateFields.h:242
UpdateField< int32, 0, 1 > ItemID
Definition: UpdateFields.h:238
uint32 GetAction() const
Definition: CharmInfo.h:45
uint32 GetItemCount() const
Definition: CreatureData.h:677
VendorItem const * GetItem(uint32 slot) const
Definition: CreatureData.h:669
bool Empty() const
Definition: CreatureData.h:676
uint32 ExtendedCost
Definition: CreatureData.h:658
uint32 PlayerConditionId
Definition: CreatureData.h:661
uint32 item
Definition: CreatureData.h:655
uint32 maxcount
Definition: CreatureData.h:656
std::vector< int32 > BonusListIDs
Definition: CreatureData.h:660
bool IsInfiniteAOI() const
VignetteEntry const * Data
Definition: Vignette.h:41
void FillPacket(WorldPackets::Vignette::VignetteDataSet &dataSet) const
Definition: Vignette.cpp:59
Array< ChrCustomizationChoice, 250 > Customizations
Optional< ItemBonuses > ItemBonus
void Initialize(::Item const *item)
ItemPurchaseRefundCurrency Currencies[5]
Definition: ItemPackets.h:114
ItemPurchaseRefundItem Items[5]
Definition: ItemPackets.h:113
Optional< PlayerChoiceResponseReward > Reward
Definition: QuestPackets.h:741
Optional< PlayerChoiceResponseMawPower > MawPower
Definition: QuestPackets.h:743
std::vector< uint8 > Cooldowns
Definition: SpellPackets.h:330
std::vector< SpellModifierData > ModifierData
Definition: SpellPackets.h:495
std::vector< PvPTalent > PvPTalents
Definition: TalentPackets.h:40
std::vector< TalentGroupInfo > TalentGroups
Definition: TalentPackets.h:47
TraitCombatConfigFlags CombatConfigFlags
std::vector< TraitEntry > Entries
WorldLocation Loc
Definition: ObjectMgr.h:835