TrinityCore
Loading...
Searching...
No Matches
Spell.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 "Spell.h"
20#include "Battlefield.h"
21#include "BattlefieldMgr.h"
22#include "Battleground.h"
23#include "BattlePetMgr.h"
24#include "CellImpl.h"
25#include "CharmInfo.h"
26#include "CollectionMgr.h"
27#include "CombatLogPackets.h"
28#include "Common.h"
29#include "ConditionMgr.h"
30#include "Containers.h"
31#include "CreatureAI.h"
32#include "DB2Stores.h"
33#include "DatabaseEnv.h"
34#include "DisableMgr.h"
35#include "DynamicObject.h"
36#include "G3DPosition.hpp"
37#include "GameObjectAI.h"
38#include "GridNotifiersImpl.h"
39#include "Guild.h"
40#include "InstanceLockMgr.h"
41#include "InstanceScript.h"
42#include "Item.h"
43#include "Log.h"
44#include "Loot.h"
45#include "LootMgr.h"
46#include "MotionMaster.h"
47#include "ObjectAccessor.h"
48#include "ObjectMgr.h"
49#include "PathGenerator.h"
50#include "Pet.h"
51#include "PhasingHandler.h"
52#include "Player.h"
53#include "ScriptMgr.h"
54#include "SharedDefines.h"
55#include "SpellAuraEffects.h"
56#include "SpellHistory.h"
57#include "SpellInfo.h"
58#include "SpellMgr.h"
59#include "SpellPackets.h"
60#include "SpellScript.h"
61#include "TemporarySummon.h"
62#include "TradeData.h"
63#include "TraitPackets.h"
64#include "TransmogMgr.h"
65#include "UniqueTrackablePtr.h"
66#include "Util.h"
67#include "VMapFactory.h"
68#include "Vehicle.h"
69#include "VMapManager.h"
70#include "World.h"
71#include "WorldSession.h"
72#include <numeric>
73#include <sstream>
74
76
77SpellDestination::SpellDestination(WorldObject const& wObj) : _position(wObj.GetMapId(), wObj),
78 _transportGUID(wObj.GetTransGUID()), _transportOffset(wObj.GetTransOffset())
79{
80}
81
89
97
98SpellCastTargets::SpellCastTargets() : m_targetMask(0), m_objectTarget(nullptr), m_itemTarget(nullptr),
99 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f)
100{
101}
102
104 m_targetMask(spellCastRequest.Target.Flags), m_objectTarget(nullptr), m_itemTarget(nullptr),
105 m_objectTargetGUID(spellCastRequest.Target.Unit), m_itemTargetGUID(spellCastRequest.Target.Item),
106 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f), m_strTarget(spellCastRequest.Target.Name)
107{
108 if (spellCastRequest.Target.SrcLocation)
109 {
110 m_src._transportGUID = spellCastRequest.Target.SrcLocation->Transport;
111 Position* pos;
113 pos = &m_src._transportOffset;
114 else
115 pos = &m_src._position;
116
117 pos->Relocate(spellCastRequest.Target.SrcLocation->Location.Pos);
118 if (spellCastRequest.Target.Orientation)
119 pos->SetOrientation(*spellCastRequest.Target.Orientation);
120 }
121
122 if (spellCastRequest.Target.DstLocation)
123 {
124 m_dst._transportGUID = spellCastRequest.Target.DstLocation->Transport;
125 Position* pos;
127 pos = &m_dst._transportOffset;
128 else
129 pos = &m_dst._position;
130
131 pos->Relocate(spellCastRequest.Target.DstLocation->Location.Pos);
132 if (spellCastRequest.Target.Orientation)
133 pos->SetOrientation(*spellCastRequest.Target.Orientation);
134 }
135
136 SetPitch(spellCastRequest.MissileTrajectory.Pitch);
137 SetSpeed(spellCastRequest.MissileTrajectory.Speed);
138
139 Update(caster);
140}
141
143
145{
146 data.Flags = m_targetMask;
147
150
152 data.Item = m_itemTarget->GetGUID();
153
155 {
156 data.SrcLocation.emplace();
157 data.SrcLocation->Transport = m_src._transportGUID; // relative position guid here - transport for example
159 data.SrcLocation->Location = m_src._transportOffset;
160 else
161 data.SrcLocation->Location = m_src._position;
162 }
163
165 {
166 data.DstLocation.emplace();
167 data.DstLocation->Transport = m_dst._transportGUID; // relative position guid here - transport for example
169 data.DstLocation->Location = m_dst._transportOffset;
170 else
171 data.DstLocation->Location = m_dst._position;
172 }
173
175 data.Name = m_strTarget;
176}
177
185
187{
188 if (m_objectTarget)
189 return m_objectTarget->ToUnit();
190
191 return nullptr;
192}
193
195{
196 if (!target)
197 return;
198
199 m_objectTarget = target;
200 m_objectTargetGUID = target->GetGUID();
202}
203
211
213{
214 if (m_objectTarget)
216
217 return nullptr;
218}
219
221{
222 if (!target)
223 return;
224
225 m_objectTarget = target;
226 m_objectTargetGUID = target->GetGUID();
228}
229
237
239{
240 if (m_objectTarget)
241 return m_objectTarget->ToCorpse();
242
243 return nullptr;
244}
245
250
255
262
264{
265 if (!item)
266 return;
267
268 m_itemTarget = item;
269 m_itemTargetGUID = item->GetGUID();
270 m_itemTargetEntry = item->GetEntry();
272}
273
282
291
293{
294 return &m_src;
295}
296
298{
299 return &m_src._position;
300}
301
302void SpellCastTargets::SetSrc(float x, float y, float z)
303{
304 m_src = SpellDestination(x, y, z);
306}
307
313
319
325
330
332{
333 return &m_dst;
334}
335
337{
338 return &m_dst._position;
339}
340
341void SpellCastTargets::SetDst(float x, float y, float z, float orientation, uint32 mapId)
342{
343 m_dst = SpellDestination(x, y, z, orientation, mapId);
345}
346
352
358
360{
361 m_dst = spellDest;
363}
364
366{
367 m_dst = spellTargets.m_dst;
369}
370
376
378{
380 m_dst = spellDest;
381}
382
387
389{
391}
392
394{
396}
397
399{
401
402 m_itemTarget = nullptr;
403 if (caster->GetTypeId() == TYPEID_PLAYER)
404 {
405 Player* player = caster->ToPlayer();
409 {
411 if (TradeData* pTrade = player->GetTradeData())
412 m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
413 }
414
415 if (m_itemTarget)
417 }
418
419 // update positions by transport move
421 {
423 {
424 m_src._position.Relocate(transport);
426 }
427 }
428
430 {
432 {
433 m_dst._position.Relocate(transport);
435 }
436 }
437}
438
439SpellValue::SpellValue(SpellInfo const* proto, WorldObject const* caster)
440{
441 for (SpellEffectInfo const& spellEffectInfo : proto->GetEffects())
442 EffectBasePoints[spellEffectInfo.EffectIndex] = spellEffectInfo.CalcBaseValue(caster, nullptr, 0, -1);
443
444 for (std::size_t i = proto->GetEffects().size(); i < std::size(EffectBasePoints); ++i)
445 EffectBasePoints[i] = 0.0;
446
449 RadiusMod = 1.0f;
450 AuraStackAmount = 1;
451 CriticalChance = 0.0f;
452 DurationMul = 1;
453}
454
456{
457public:
458 explicit SpellEvent(Spell* spell);
459 ~SpellEvent();
460
461 bool Execute(uint64 e_time, uint32 p_time) override;
462 void Abort(uint64 e_time) override;
463 bool IsDeletable() const override;
464 Spell const* GetSpell() const { return m_Spell.get(); }
466
467 std::string GetDebugInfo() const { return m_Spell->GetDebugInfo(); }
468
469protected:
471};
472
473Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID /*= ObjectGuid::Empty*/,
474 ObjectGuid originalCastId /*= ObjectGuid::Empty*/) :
475m_spellInfo(info), m_caster((info->HasAttribute(SPELL_ATTR6_ORIGINATE_FROM_CONTROLLER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster),
476m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
477{
479 m_fromClient = false;
480 m_selfContainer = nullptr;
482 m_executedCurrently = false;
483 m_delayStart = 0;
484 m_delayMoment = 0;
486
488 memset(m_damageMultipliers, 0, sizeof(m_damageMultipliers));
489
490 // Get data for type of attack
491 m_attackType = info->GetAttackType();
492
493 m_spellSchoolMask = info->GetSchoolMask(); // Can be override for some spell (wand shoot for example)
494
495 if (Player const* playerCaster = m_caster->ToPlayer())
496 {
497 // wand case
499 if ((playerCaster->GetClassMask() & CLASSMASK_WAND_USERS) != 0)
500 if (Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK))
501 m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->GetDamageType());
502 }
503
504 if (Player const* modOwner = caster->GetSpellModOwner())
505 {
506 modOwner->ApplySpellMod(info, SpellModOp::Doses, m_spellValue->AuraStackAmount, this);
507 modOwner->ApplySpellMod(info, SpellModOp::MaxTargets, m_spellValue->MaxAffectedTargets, this);
508 }
509
510 if (!originalCasterGUID.IsEmpty())
511 m_originalCasterGUID = originalCasterGUID;
512 else
514
517 else
518 {
521 m_originalCaster = nullptr;
522 }
523
525 _triggeredCastFlags = triggerFlags;
526
529
532
533 m_CastItem = nullptr;
535 m_castItemEntry = 0;
536 m_castItemLevel = -1;
537 m_castFlagsEx = 0;
538
540 {
544 }
545
548
549 unitTarget = nullptr;
550 itemTarget = nullptr;
551 gameObjTarget = nullptr;
552 m_corpseTarget = nullptr;
553 destTarget = nullptr;
554 effectValue = 0.0;
556 variance = 0.0f;
558 effectInfo = nullptr;
559 m_damage = 0;
560 m_healing = 0;
563 focusObject = nullptr;
565 m_originalCastId = originalCastId;
566 memset(m_misc.Raw.Data, 0, sizeof(m_misc.Raw.Data));
568 m_triggeredByAuraSpell = nullptr;
569 m_procChainLength = caster->IsUnit() ? caster->ToUnit()->GetProcChainLength() : 0;
570 _spellAura = nullptr;
571 _dynObjAura = nullptr;
572
573 //Auto Shot & Shoot (wand)
575
576 m_runesState = 0;
577 m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before.
578 m_timer = 0; // will set to castime in prepare
579 m_channelDuration = 0; // will be setup in Spell::handle_immediate
580 m_launchHandled = false;
581 m_immediateHandled = false;
582
584
586 m_empower = std::make_unique<EmpowerData>();
587
588 // Determine if spell can be reflected back to the caster
589 // Patch 1.2 notes: Spell Reflection no longer reflects abilities
590 m_canReflect = caster->IsUnit()
593 && !m_spellInfo->IsPassive();
594
595 std::ranges::fill(m_destTargets, SpellDestination(*m_caster));
596}
597
599{
600 // unload scripts
601 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
602 {
603 (*itr)->_Unload();
604 delete (*itr);
605 }
606
608 {
609 // Clean the reference to avoid later crash.
610 // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
611 TC_LOG_ERROR("spells", "SPELL: deleting spell for spell ID {}. However, spell still referenced.", m_spellInfo->Id);
612 *m_selfContainer = nullptr;
613 }
614
617
618 delete m_spellValue;
619}
620
622{
623 m_targets = targets;
624
625 // this function tries to correct spell explicit targets for spell
626 // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
627 // this also makes sure that we correctly send explicit targets to client (removes redundant data)
628 uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
629
630 if (WorldObject* target = m_targets.GetObjectTarget())
631 {
632 // check if object target is valid with needed target flags
633 // for unit case allow corpse target mask because player with not released corpse is a unit target
634 if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)))
635 || (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
636 || (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK)))
638 }
639 else
640 {
641 // try to select correct unit target if not provided by client or by serverside cast
642 if (neededTargets & (TARGET_FLAG_UNIT_MASK))
643 {
644 Unit* unit = nullptr;
645 // try to use player selection as a target
646 if (Player* playerCaster = m_caster->ToPlayer())
647 {
648 // selection has to be found and to be valid target for the spell
649 if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget()))
651 unit = selectedUnit;
652 }
653 // try to use attacked unit as a target
654 else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
655 unit = m_caster->ToUnit()->GetVictim();
656
657 // didn't find anything - let's use self as target
659 unit = m_caster->ToUnit();
660
662 }
663 }
664
665 // check if spell needs dst target
666 if (neededTargets & TARGET_FLAG_DEST_LOCATION)
667 {
668 // and target isn't set
669 if (!m_targets.HasDst())
670 {
671 // try to use unit target if provided
672 if (WorldObject* target = targets.GetObjectTarget())
673 m_targets.SetDst(*target);
674 // or use self if not available
675 else
677 }
678 }
679 else
681
682 if (neededTargets & TARGET_FLAG_SOURCE_LOCATION)
683 {
684 if (!targets.HasSrc())
686 }
687 else
689}
690
692{
693 // here go all explicit target changes made to explicit targets after spell prepare phase is finished
694 if (Unit* target = m_targets.GetUnitTarget())
695 {
696 // check for explicit target redirection, for Grounding Totem for example
699 {
700 Unit* redirect = nullptr;
701 switch (m_spellInfo->DmgClass)
702 {
705 break;
708 // should gameobjects cast damagetype melee/ranged spells this needs to be changed
710 break;
711 default:
712 break;
713 }
714 if (redirect && (redirect != target))
715 m_targets.SetUnitTarget(redirect);
716 }
717 }
718}
719
721{
722 // select targets for cast phase
724
725 uint32 processedEffectsMaskForSpell = 0;
726
727 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
728 {
729 // not call for empty effect.
730 // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
731 if (!spellEffectInfo.IsEffect())
732 continue;
733
734 // set expected type of implicit targets to be sent to client
735 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
736 if (implicitTargetMask & TARGET_FLAG_UNIT)
738 if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
740
741 uint32 implicitTargetEffectMaskToSelect = [&]
742 {
743 uint32 effectMask = 1u << spellEffectInfo.EffectIndex;
744 // set the same target list for all effects
745 // some spells appear to need this, however this requires more research
746 std::vector<SpellEffectInfo> const& effects = GetSpellInfo()->GetEffects();
747 // choose which targets we can select at once
748 for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j)
749 {
750 if (effects[j].IsEffect() &&
751 spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
752 spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
753 spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
754 spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) == effects[j].EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) &&
755 CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, j))
756 {
757 auto shouldCheckRadius = [](SpellImplicitTargetInfo const& targetInfo)
758 {
759 switch (targetInfo.GetSelectionCategory())
760 {
765 return true;
766 default:
767 break;
768 }
769 return false;
770 };
771
772 if (shouldCheckRadius(spellEffectInfo.TargetA) || shouldCheckRadius(spellEffectInfo.TargetB))
773 if (spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetA) != effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetA) ||
774 spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetB) != effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetB))
775 continue;
776
777 effectMask |= 1 << j;
778 }
779 }
780
781 return effectMask;
782 }();
783
784 implicitTargetEffectMaskToSelect &= ~processedEffectsMaskForSpell;
785 if (implicitTargetEffectMaskToSelect)
786 {
787 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, SpellTargetIndex::TargetA, implicitTargetEffectMaskToSelect);
788 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, SpellTargetIndex::TargetB, implicitTargetEffectMaskToSelect);
789 processedEffectsMaskForSpell |= implicitTargetEffectMaskToSelect;
790 }
791
792 // Select targets of effect based on effect type
793 // those are used when no valid target could be added for spell effect based on spell target type
794 // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
795 // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
796 // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
797 SelectEffectTypeImplicitTargets(spellEffectInfo);
798
799 if (m_targets.HasDst())
800 AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex);
801
802 if (implicitTargetEffectMaskToSelect
803 && (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
804 || spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST
805 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
806 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST))
807 {
809 {
810 bool noTargetFound = std::ranges::none_of(m_UniqueTargetInfo, [implicitTargetEffectMaskToSelect](TargetInfo const& target)
811 {
812 return target.EffectMask & implicitTargetEffectMaskToSelect;
813 });
814
815 if (noTargetFound)
816 {
819 return;
820 }
821 }
822 }
823
825 {
826 // maybe do this for all spells?
827 if (!focusObject && m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst())
828 {
831 return;
832 }
833
834 uint32 mask = (1 << spellEffectInfo.EffectIndex);
835 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
836 {
837 if (ihit->EffectMask & mask)
838 {
840 break;
841 }
842 }
843 }
844 }
845
847 {
848 bool anyNonImmuneTargetFound = std::ranges::any_of(m_UniqueTargetInfo, [](TargetInfo const& target)
849 {
851 });
852
853 if (!anyNonImmuneTargetFound)
854 {
857 return;
858 }
859 }
860
861 if (m_targets.HasDst())
862 {
864 {
867 if (!(status & (LIQUID_MAP_WATER_WALK | LIQUID_MAP_IN_WATER)))
868 {
871 return;
872 }
873 }
874 }
875
877 m_delayMoment = dstDelay;
878}
879
881{
882 if (m_targets.HasDst())
883 {
884 if (m_targets.HasTraj())
885 {
886 float speed = m_targets.GetSpeedXY();
887 if (speed > 0.0f)
888 return uint64(std::floor((std::max(m_targets.GetDist2d() / speed, m_spellInfo->MinDuration) + launchDelay) * 1000.0f));
889 }
891 return uint64(std::floor((std::max(m_spellInfo->Speed, m_spellInfo->MinDuration) + launchDelay) * 1000.0f));
892 else if (m_spellInfo->Speed > 0.0f)
893 {
894 // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP)
895 float dist = m_caster->GetExactDist(*m_targets.GetDstPos());
896 return uint64(std::floor((std::max(dist / m_spellInfo->Speed, m_spellInfo->MinDuration) + launchDelay) * 1000.0f));
897 }
898
899 return uint64(std::floor(launchDelay * 1000.0f));
900 }
901
902 return 0;
903}
904
909
917
919{
920 auto itr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [unit](Spell::TargetInfo const& targetInfo)
921 {
922 return targetInfo.TargetGUID == unit->GetGUID();
923 });
924
925 uint64 oldDelay = itr->TimeDelay;
926 itr->TimeDelay = hitDelay;
927
928 if (hitDelay && (!m_delayMoment || m_delayMoment > hitDelay))
929 m_delayMoment = hitDelay;
930 else if (m_delayMoment && oldDelay < hitDelay)
931 {
932 // if new hit delay is greater than old delay for this target we must check all other spell targets to see if m_delayMoment can be increased
933 auto minDelayTargetItr = std::min_element(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [](Spell::TargetInfo const& itr, Spell::TargetInfo const& smallest)
934 {
935 return itr.TimeDelay && itr.TimeDelay < smallest.TimeDelay;
936 });
937
938 m_delayMoment = minDelayTargetItr->TimeDelay;
939 }
940
941 if (GetDelayStart())
943}
944
945void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effectMask)
946{
947 if (!targetType.GetTarget())
948 return;
949
950 switch (targetType.GetSelectionCategory())
951 {
953 SelectImplicitChannelTargets(spellEffectInfo, targetType, effectMask);
954 break;
956 SelectImplicitNearbyTargets(spellEffectInfo, targetType, targetIndex, effectMask);
957 break;
959 SelectImplicitConeTargets(spellEffectInfo, targetType, targetIndex, effectMask);
960 break;
962 SelectImplicitAreaTargets(spellEffectInfo, targetType, targetIndex, effectMask);
963 break;
965 // just in case there is no dest, explanation in SelectImplicitDestDestTargets
966 CheckDst();
967
968 SelectImplicitTrajTargets(spellEffectInfo, targetType);
969 break;
971 SelectImplicitLineTargets(spellEffectInfo, targetType, targetIndex, effectMask);
972 break;
974 switch (targetType.GetObjectType())
975 {
977 switch (targetType.GetReferenceType())
978 {
981 break;
982 default:
983 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
984 break;
985 }
986 break;
988 switch (targetType.GetReferenceType())
989 {
991 SelectImplicitCasterDestTargets(spellEffectInfo, targetType, targetIndex);
992 break;
994 SelectImplicitTargetDestTargets(spellEffectInfo, targetType, targetIndex);
995 break;
997 SelectImplicitDestDestTargets(spellEffectInfo, targetType, targetIndex);
998 break;
999 default:
1000 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
1001 break;
1002 }
1003 break;
1004 default:
1005 switch (targetType.GetReferenceType())
1006 {
1008 SelectImplicitCasterObjectTargets(spellEffectInfo, targetType, effectMask);
1009 break;
1011 SelectImplicitTargetObjectTargets(spellEffectInfo, targetType, effectMask);
1012 break;
1013 default:
1014 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
1015 break;
1016 }
1017 break;
1018 }
1019 break;
1021 TC_LOG_DEBUG("spells", "SPELL: target type {}, found in spellID {}, effect {} is not implemented yet!", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex), targetType.GetTarget());
1022 break;
1023 default:
1024 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target category");
1025 break;
1026 }
1027}
1028
1029void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1030{
1032 {
1033 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target reference type");
1034 return;
1035 }
1036
1038 if (!channeledSpell)
1039 {
1040 TC_LOG_DEBUG("spells", "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1041 return;
1042 }
1043 switch (targetType.GetTarget())
1044 {
1046 {
1047 for (ObjectGuid const& channelTarget : m_originalCaster->m_unitData->ChannelObjects)
1048 {
1049 WorldObject* target = ObjectAccessor::GetUnit(*m_caster, channelTarget);
1050 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1051 // unit target may be no longer avalible - teleported out of map for example
1052 if (target && target->IsUnit())
1053 AddUnitTarget(target->ToUnit(), effMask);
1054 else
1055 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1056 }
1057 break;
1058 }
1060 if (channeledSpell->m_targets.HasDst())
1061 m_targets.SetDst(channeledSpell->m_targets);
1062 else
1063 {
1064 auto const& channelObjects = m_originalCaster->m_unitData->ChannelObjects;
1065 WorldObject* target = !channelObjects.empty() ? ObjectAccessor::GetWorldObject(*m_caster, *channelObjects.begin()) : nullptr;
1066 if (target)
1067 {
1068 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1069 if (target)
1070 {
1071 SpellDestination dest(*target);
1073 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1074
1075 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1076 m_targets.SetDst(dest);
1077 }
1078 }
1079 else
1080 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1081 }
1082 break;
1083 default:
1084 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
1085 break;
1086 }
1087}
1088
1089void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1090{
1092 {
1093 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
1094 return;
1095 }
1096
1097 float range = 0.0f;
1098 switch (targetType.GetCheckType())
1099 {
1100 case TARGET_CHECK_ENEMY:
1101 range = m_spellInfo->GetMaxRange(false, m_caster, this);
1102 break;
1103 case TARGET_CHECK_ALLY:
1104 case TARGET_CHECK_PARTY:
1105 case TARGET_CHECK_RAID:
1107 range = m_spellInfo->GetMaxRange(true, m_caster, this);
1108 break;
1109 case TARGET_CHECK_ENTRY:
1111 range = m_spellInfo->GetMaxRange(IsPositive(), m_caster, this);
1112 break;
1113 default:
1114 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
1115 break;
1116 }
1117
1118 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1119
1120 // handle emergency case - try to use other provided targets if no conditions provided
1121 if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
1122 {
1123 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: no conditions entry for target with TARGET_CHECK_ENTRY of spell ID {}, effect {} - selecting default targets", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1124 switch (targetType.GetObjectType())
1125 {
1128 {
1129 if (focusObject)
1130 AddGOTarget(focusObject, effMask);
1131 else
1132 {
1135 }
1136 return;
1137 }
1138 break;
1141 {
1142 if (focusObject)
1143 {
1146 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1147
1148 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1149 m_targets.SetDst(dest);
1150 }
1151 else
1152 {
1155 }
1156 return;
1157 }
1158 if (targetType.GetTarget() == TARGET_DEST_NEARBY_ENTRY_OR_DB)
1159 {
1160 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1161 {
1163 if (st->GetMapId() == m_caster->GetMapId() && m_caster->IsInDist(st, range))
1164 dest = st->GetPosition();
1165 else
1166 {
1167 float randomRadius = spellEffectInfo.CalcRadius(m_caster, targetIndex).Max;
1168 if (randomRadius > 0.0f)
1169 MovePosition(dest._position, m_caster, randomRadius, targetType.CalcDirectionAngle());
1170 }
1171
1172 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1173 m_targets.SetDst(dest);
1174 return;
1175 }
1176 }
1177 break;
1178 default:
1179 break;
1180 }
1181 }
1182
1183 WorldObject* target = SearchNearbyTarget(spellEffectInfo, range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
1184 float randomRadius = 0.0f;
1185 switch (targetType.GetTarget())
1186 {
1188 // if we are here then there was no db target
1189 if (!target)
1190 {
1191 target = m_caster;
1192 // radius is only meant to be randomized when using caster fallback
1193 randomRadius = spellEffectInfo.CalcRadius(m_caster, targetIndex).Max;
1194 }
1195 break;
1196 default:
1197 break;
1198 }
1199
1200 if (!target)
1201 {
1202 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1205 return;
1206 }
1207
1208 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1209 if (!target)
1210 {
1211 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set NULL target, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1214 return;
1215 }
1216
1217 switch (targetType.GetObjectType())
1218 {
1220 if (Unit* unit = target->ToUnit())
1221 AddUnitTarget(unit, effMask, true, false);
1222 else
1223 {
1224 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set object of wrong type, expected unit, got {}, effect {}", m_spellInfo->Id, target->GetGUID().GetTypeName(), effMask);
1227 return;
1228 }
1229 break;
1231 if (GameObject* gobjTarget = target->ToGameObject())
1232 AddGOTarget(gobjTarget, effMask);
1233 else
1234 {
1235 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set object of wrong type, expected gameobject, got {}, effect {}", m_spellInfo->Id, target->GetGUID().GetTypeName(), effMask);
1238 return;
1239 }
1240 break;
1242 if (Corpse* corpseTarget = target->ToCorpse())
1243 AddCorpseTarget(corpseTarget, effMask);
1244 else
1245 {
1246 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set object of wrong type, expected corpse, got {}, effect {}", m_spellInfo->Id, target->GetGUID().GetTypeName(), effMask);
1249 return;
1250 }
1251 break;
1253 {
1254 SpellDestination dest(*target);
1255 if (randomRadius > 0.0f)
1256 MovePosition(dest._position, target, randomRadius, targetType.CalcDirectionAngle());
1257
1259 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1260
1261 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1262 m_targets.SetDst(dest);
1263 break;
1264 }
1265 default:
1266 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target object type");
1267 break;
1268 }
1269
1270 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1271}
1272
1273void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1274{
1276 {
1277 ABORT_MSG("Spell::SelectImplicitConeTargets: received not implemented target reference type");
1278 return;
1279 }
1280
1281 float coneAngle = m_spellInfo->ConeAngle;
1282 switch (targetType.GetTarget())
1283 {
1285 if (coneAngle == 0.0f)
1286 coneAngle = 180.0f;
1287 break;
1288 default:
1289 break;
1290 }
1291
1292 std::list<WorldObject*> targets;
1293 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1294 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1295 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1296 SpellRange radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1297
1298 if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
1299 {
1300 float extraSearchRadius = radius.Max > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1301 Trinity::WorldObjectSpellConeTargetCheck check(*m_caster, DegToRad(coneAngle), m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
1303 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius.Max + extraSearchRadius);
1304
1305 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1306
1307 if (!targets.empty())
1308 {
1309 // Other special target selection goes here
1310 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1311 Trinity::Containers::RandomResize(targets, maxTargets);
1312
1313 for (WorldObject* itr : targets)
1314 {
1315 if (Unit* unit = itr->ToUnit())
1316 AddUnitTarget(unit, effMask, false);
1317 else if (GameObject* gObjTarget = itr->ToGameObject())
1318 AddGOTarget(gObjTarget, effMask);
1319 else if (Corpse* corpse = itr->ToCorpse())
1320 AddCorpseTarget(corpse, effMask);
1321 }
1322 }
1323 }
1324}
1325
1326void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1327{
1328 WorldObject* referer = nullptr;
1329 switch (targetType.GetReferenceType())
1330 {
1334 referer = m_caster;
1335 break;
1337 referer = m_targets.GetUnitTarget();
1338 break;
1340 {
1341 referer = m_caster;
1342
1343 // find last added target for this effect
1344 for (auto ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
1345 {
1346 if (ihit->EffectMask & (1 << spellEffectInfo.EffectIndex))
1347 {
1348 referer = ObjectAccessor::GetUnit(*m_caster, ihit->TargetGUID);
1349 break;
1350 }
1351 }
1352 break;
1353 }
1354 default:
1355 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1356 return;
1357 }
1358
1359 if (!referer)
1360 return;
1361
1362 Position const* center = nullptr;
1363 switch (targetType.GetReferenceType())
1364 {
1366 center = m_targets.GetSrcPos();
1367 break;
1369 center = m_targets.GetDstPos();
1370 break;
1374 center = referer;
1375 break;
1376 default:
1377 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1378 return;
1379 }
1380
1381 SpellRange radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1382 std::list<WorldObject*> targets;
1383 switch (targetType.GetTarget())
1384 {
1386 targets.push_back(m_caster);
1387 if (Unit* unit = m_caster->ToUnit())
1388 if (Vehicle const* vehicleKit = unit->GetVehicleKit())
1389 for (int8 seat = 0; seat < MAX_VEHICLE_SEATS; ++seat)
1390 if (Unit* passenger = vehicleKit->GetPassenger(seat))
1391 targets.push_back(passenger);
1392 break;
1394 if (Unit* targetedUnit = m_targets.GetUnitTarget())
1395 {
1396 if (!m_caster->IsUnit() || !m_caster->ToUnit()->IsInRaidWith(targetedUnit))
1397 targets.push_back(m_targets.GetUnitTarget());
1398 else
1399 SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1401 }
1402 break;
1404 targets.push_back(m_caster);
1405 SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1407 break;
1409 if (Unit* unit = m_caster->ToUnit())
1410 for (ThreatReference const* threatRef : unit->GetThreatManager().GetUnsortedThreatList())
1411 if (Unit* threateningUnit = threatRef->GetVictim())
1412 targets.push_back(threateningUnit);
1413 break;
1415 if (Creature* creature = m_caster->ToCreature())
1416 for (ObjectGuid const& tapperGuid : creature->GetTapList())
1417 if (Player* tapper = ObjectAccessor::GetPlayer(*m_caster, tapperGuid))
1418 targets.push_back(tapper);
1419 break;
1420 default:
1421 SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1423 break;
1424 }
1425
1427 {
1428 SpellDestination dest(*referer);
1430 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1431
1432 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1433
1434 m_targets.ModDst(dest);
1435 }
1436
1437 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1438
1440 targets.sort(Trinity::ObjectDistanceOrderPred(referer, false));
1441
1442 if (!targets.empty())
1443 {
1444 // Other special target selection goes here
1445 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1446 {
1448 Trinity::Containers::RandomResize(targets, maxTargets);
1449 else if (targets.size() > maxTargets)
1450 targets.resize(maxTargets);
1451 }
1452
1453 for (WorldObject* itr : targets)
1454 {
1455 if (Unit* unit = itr->ToUnit())
1456 AddUnitTarget(unit, effMask, false, true, center);
1457 else if (GameObject* gObjTarget = itr->ToGameObject())
1458 AddGOTarget(gObjTarget, effMask);
1459 else if (Corpse* corpse = itr->ToCorpse())
1460 AddCorpseTarget(corpse, effMask);
1461 }
1462 }
1463}
1464
1466{
1468
1469 switch (targetType.GetTarget())
1470 {
1471 case TARGET_DEST_CASTER:
1472 break;
1473 case TARGET_DEST_HOME:
1474 if (Player* playerCaster = m_caster->ToPlayer())
1475 dest = SpellDestination(playerCaster->m_homebind);
1476 break;
1477 case TARGET_DEST_DB:
1478 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1479 {
1482 dest = *st;
1483 else if (st->GetMapId() == m_caster->GetMapId())
1484 dest = st->GetPosition();
1485 }
1486 else
1487 {
1488 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1489 if (WorldObject* target = m_targets.GetObjectTarget())
1490 dest = *target;
1491 }
1492 break;
1494 {
1495 auto [minDist, maxDist] = m_spellInfo->GetMinMaxRange(true);
1496 float dist = frand(minDist, maxDist);
1497 float x, y, z;
1498 float angle = rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
1500
1501 float ground = m_caster->GetMapHeight(x, y, z);
1502 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
1503 LiquidData liquidData;
1504 if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(), x, y, z, {}, &liquidData, m_caster->GetCollisionHeight()))
1505 liquidLevel = liquidData.level;
1506
1507 if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
1508 {
1512 return;
1513 }
1514
1515 if (ground + 0.75 > liquidLevel)
1516 {
1520 return;
1521 }
1522
1523 dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation());
1524 break;
1525 }
1528 {
1529 Unit* unitCaster = m_caster->ToUnit();
1530 if (!unitCaster)
1531 break;
1532
1533 float dist = spellEffectInfo.CalcRadius(unitCaster, targetIndex).Max;
1534 float angle = targetType.CalcDirectionAngle();
1536 {
1537 angle = [&]()
1538 {
1540 {
1541 case MOVEMENTFLAG_NONE:
1547 return 0.0f;
1550 return static_cast<float>(M_PI);
1553 return static_cast<float>(M_PI / 2);
1555 return static_cast<float>(M_PI / 4);
1557 return static_cast<float>(3 * M_PI / 4);
1560 return static_cast<float>(-M_PI / 2);
1562 return static_cast<float>(-M_PI / 4);
1564 return static_cast<float>(-3 * M_PI / 4);
1565 default:
1566 return 0.0f;
1567 }
1568 }();
1569 }
1570
1571 Position pos = dest._position.GetPosition();
1572
1573 MovePosition(pos, unitCaster, dist, angle);
1574 dest.Relocate(pos);
1575 break;
1576 }
1580 break;
1582 if (Unit const* unitCaster = m_caster->ToUnit())
1583 if (TempSummon const* casterSummon = unitCaster->ToTempSummon())
1584 if (WorldObject const* summoner = casterSummon->GetSummoner())
1585 dest = SpellDestination(*summoner);
1586 break;
1588 {
1589 SpellRange radius = spellEffectInfo.CalcRadius(m_caster, targetIndex, this);
1590 std::vector<SpellTargetPosition const*> positionsInRange;
1591 for (auto const& [_, position] : sSpellMgr->GetSpellTargetPositions(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1592 if (m_caster->GetMapId() == position.GetMapId() && m_caster->IsInRange3d(&position, radius.Min, radius.Max))
1593 positionsInRange.push_back(&position);
1594
1595 if (positionsInRange.empty())
1596 {
1597 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1600 return;
1601 }
1602
1603 dest = Trinity::Containers::SelectRandomContainerElement(positionsInRange)->GetPosition();
1604 break;
1605 }
1606 default:
1607 {
1608 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex).Max;
1609 float angle = targetType.CalcDirectionAngle();
1610 float objSize = m_caster->GetCombatReach();
1611
1612 switch (targetType.GetTarget())
1613 {
1615 dist = PET_FOLLOW_DIST;
1616 break;
1618 if (dist > objSize)
1619 dist = objSize + (dist - objSize);
1620 break;
1625 {
1626 static constexpr float DefaultTotemDistance = 3.0f;
1627 if (!spellEffectInfo.HasRadius(targetIndex))
1628 dist = DefaultTotemDistance;
1629 break;
1630 }
1631 default:
1632 break;
1633 }
1634
1635 if (dist < objSize)
1636 dist = objSize;
1637
1638 Position pos = dest._position.GetPosition();
1639 MovePosition(pos, m_caster, dist, angle);
1640
1641 dest.Relocate(pos);
1642 break;
1643 }
1644 }
1645
1647 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1648
1649 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1650 m_targets.SetDst(dest);
1651}
1652
1654{
1656 "Spell::SelectImplicitTargetDestTargets - no explicit object target available!");
1657
1659 if (!target)
1660 return;
1661
1662 SpellDestination dest(*target);
1663
1664 switch (targetType.GetTarget())
1665 {
1669 break;
1670 default:
1671 {
1672 float angle = targetType.CalcDirectionAngle();
1673 float dist = spellEffectInfo.CalcRadius(nullptr, targetIndex).Max;
1674
1675 Position pos = dest._position.GetPosition();
1676 MovePosition(pos, target, dist, angle);
1677
1678 dest.Relocate(pos);
1679 break;
1680 }
1681 }
1682
1684 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1685
1686 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1687 m_targets.SetDst(dest);
1688}
1689
1690void Spell::SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex)
1691{
1692 // set destination to caster if no dest provided
1693 // can only happen if previous destination target could not be set for some reason
1694 // (not found nearby target, or channel target for example
1695 // maybe we should abort the spell in such case?
1696 CheckDst();
1697
1699
1700 switch (targetType.GetTarget())
1701 {
1705 case TARGET_DEST_DEST:
1706 break;
1709 break;
1711 {
1712 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex).Max;
1713 Position pos = dest._position.GetPosition();
1714 float angle = pos.GetAbsoluteAngle(m_caster) - m_caster->GetOrientation();
1715
1716 MovePosition(pos, m_caster, dist, angle);
1718
1719 dest.Relocate(pos);
1720 break;
1721 }
1722 default:
1723 {
1724 float angle = targetType.CalcDirectionAngle();
1725 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex).Max;
1726
1727 Position pos = dest._position.GetPosition();
1728 MovePosition(pos, m_caster, dist, angle);
1729
1730 dest.Relocate(pos);
1731 break;
1732 }
1733 }
1734
1736 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1737
1738 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1739 m_targets.ModDst(dest);
1740}
1741
1742void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1743{
1744 WorldObject* target = nullptr;
1745 bool checkIfValid = true;
1746
1747 switch (targetType.GetTarget())
1748 {
1749 case TARGET_UNIT_CASTER:
1750 target = m_caster;
1751 checkIfValid = false;
1752 break;
1753 case TARGET_UNIT_MASTER:
1754 target = m_caster->GetCharmerOrOwner();
1755 break;
1756 case TARGET_UNIT_PET:
1757 if (Unit* unitCaster = m_caster->ToUnit())
1758 target = unitCaster->GetGuardianPet();
1759 break;
1761 if (Unit* unitCaster = m_caster->ToUnit())
1762 if (unitCaster->IsSummon())
1763 target = unitCaster->ToTempSummon()->GetSummonerUnit();
1764 break;
1766 if (Unit* unitCaster = m_caster->ToUnit())
1767 target = unitCaster->GetVehicleBase();
1768 break;
1777 if (Creature* vehicleBase = m_caster->ToCreature())
1778 if (vehicleBase->IsVehicle())
1779 target = vehicleBase->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
1780 break;
1782 if (Creature* creatureCaster = m_caster->ToCreature())
1783 if (!creatureCaster->GetTapList().empty())
1784 target = ObjectAccessor::GetWorldObject(*creatureCaster, Trinity::Containers::SelectRandomContainerElement(creatureCaster->GetTapList()));
1785 break;
1787 if (Unit const* unitCaster = m_caster->ToUnit())
1788 target = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetCritterGUID());
1789 break;
1790 default:
1791 break;
1792 }
1793
1794 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1795
1796 if (target)
1797 {
1798 if (Unit* unit = target->ToUnit())
1799 AddUnitTarget(unit, effMask, checkIfValid);
1800 else if (GameObject* go = target->ToGameObject())
1801 AddGOTarget(go, effMask);
1802 else if (Corpse* corpse = target->ToCorpse())
1803 AddCorpseTarget(corpse, effMask);
1804 }
1805}
1806
1807void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1808{
1810 "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!");
1811
1813
1814 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1815
1816 if (target)
1817 {
1818 if (Unit* unit = target->ToUnit())
1819 AddUnitTarget(unit, effMask, true, false);
1820 else if (GameObject* gobj = target->ToGameObject())
1821 AddGOTarget(gobj, effMask);
1822 else if (Corpse* corpse = target->ToCorpse())
1823 AddCorpseTarget(corpse, effMask);
1824
1825 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1826 }
1827 // Script hook can remove object target and we would wrongly land here
1828 else if (Item* item = m_targets.GetItemTarget())
1829 AddItemTarget(item, effMask);
1830}
1831
1832void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask)
1833{
1834 int32 maxTargets = spellEffectInfo.ChainTargets;
1835 if (Player* modOwner = m_caster->GetSpellModOwner())
1836 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainTargets, maxTargets, this);
1837
1838 if (maxTargets > 1)
1839 {
1840 // mark damage multipliers as used
1841 for (size_t k = spellEffectInfo.EffectIndex; k < m_spellInfo->GetEffects().size(); ++k)
1842 if (effMask & (1 << k))
1843 m_damageMultipliers[k] = 1.0f;
1844 m_applyMultiplierMask |= effMask;
1845
1846 std::list<WorldObject*> targets;
1847 SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
1848 , spellEffectInfo, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
1849
1850 // Chain primary target is added earlier
1851 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1852
1854
1855 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
1856 {
1857 if (Unit* unit = (*itr)->ToUnit())
1858 AddUnitTarget(unit, effMask, false, true, losPosition);
1859
1861 losPosition = *itr;
1862 }
1863 }
1864}
1865
1866float tangent(float x)
1867{
1868 x = std::tan(x);
1869 //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
1870 //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
1871 //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
1872 if (x < 100000.0f && x > -100000.0f) return x;
1873 if (x >= 100000.0f) return 100000.0f;
1874 if (x <= 100000.0f) return -100000.0f;
1875 return 0.0f;
1876}
1877
1878void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType)
1879{
1880 if (!m_targets.HasTraj())
1881 return;
1882
1883 float dist2d = m_targets.GetDist2d();
1884 if (!dist2d)
1885 return;
1886
1887 Position srcPos = *m_targets.GetSrcPos();
1889 float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
1890
1891 std::list<WorldObject*> targets;
1894 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
1895 if (targets.empty())
1896 return;
1897
1899
1900 float b = tangent(m_targets.GetPitch());
1901 float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
1902 if (a > -0.0001f)
1903 a = 0.f;
1904
1905 // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
1906 // limit max range to 300 yards, sometimes triggered spells can have 50000yds
1907 float bestDist = m_spellInfo->GetMaxRange(false);
1908 if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, GetCastDifficulty()))
1909 bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
1910
1911 // GameObjects don't cast traj
1912 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
1913 for (auto itr = targets.begin(); itr != targets.end(); ++itr)
1914 {
1915 if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
1916 continue;
1917
1918 if (Unit* unit = (*itr)->ToUnit())
1919 {
1920 if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
1921 continue;
1922
1923 if (Creature* creatureTarget = unit->ToCreature())
1924 {
1925 if (!(creatureTarget->GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES))
1926 continue;
1927 }
1928 }
1929
1930 float const size = std::max((*itr)->GetCombatReach(), 1.0f);
1931 float const objDist2d = srcPos.GetExactDist2d(*itr);
1932 float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
1933
1934 float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
1935 float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
1936 float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
1937 float const height = distToHitPoint * (a * distToHitPoint + b);
1938
1939 if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
1940 continue;
1941
1942 if (distToHitPoint < bestDist)
1943 {
1944 bestDist = distToHitPoint;
1945 break;
1946 }
1947 }
1948
1949 if (dist2d > bestDist)
1950 {
1951 float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
1952 float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
1953 float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
1954
1955 SpellDestination dest(x, y, z, unitCaster->GetOrientation());
1957 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1958
1959 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1960 m_targets.ModDst(dest);
1961 }
1962}
1963
1964void Spell::SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1965{
1966 std::list<WorldObject*> targets;
1967 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1968 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1969 Position const* dst = nullptr;
1970 switch (targetType.GetReferenceType())
1971 {
1973 dst = m_targets.GetSrcPos();
1974 break;
1976 dst = m_targets.GetDstPos();
1977 break;
1979 dst = m_caster;
1980 break;
1982 dst = m_targets.GetUnitTarget();
1983 break;
1984 default:
1985 ABORT_MSG("Spell::SelectImplicitLineTargets: received not implemented target reference type");
1986 return;
1987 }
1988
1989 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1990 SpellRange radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1991
1992 if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
1993 {
1994 Trinity::WorldObjectSpellLineTargetCheck check(m_caster, dst, m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
1996 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellLineTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, radius.Max);
1997
1998 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1999
2000 if (!targets.empty())
2001 {
2002 // Other special target selection goes here
2003 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
2004 {
2005 if (maxTargets < targets.size())
2006 {
2008 targets.resize(maxTargets);
2009 }
2010 }
2011
2012 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
2013 {
2014 if (Unit* unit = (*itr)->ToUnit())
2015 AddUnitTarget(unit, effMask, false);
2016 else if (GameObject* gObjTarget = (*itr)->ToGameObject())
2017 AddGOTarget(gObjTarget, effMask);
2018 else if (Corpse* corpse = (*itr)->ToCorpse())
2019 AddCorpseTarget(corpse, effMask);
2020 }
2021 }
2022 }
2023}
2024
2026{
2027 // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER, queue them on map for later execution
2028 switch (spellEffectInfo.Effect)
2029 {
2033 {
2036
2037 // scripts may modify the target - recheck
2038 if (target && target->GetTypeId() == TYPEID_PLAYER)
2039 {
2040 // target is not stored in target map for those spells
2041 // since we're completely skipping AddUnitTarget logic, we need to check immunity manually
2042 // eg. aura 21546 makes target immune to summons
2043 Player* player = target->ToPlayer();
2044 if (player->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, nullptr))
2045 return;
2046
2047 target->GetMap()->AddFarSpellCallback([spell = this, &spellEffectInfo, targetGuid = target->GetGUID()](Map* map)
2048 {
2049 Player* player = ObjectAccessor::GetPlayer(map, targetGuid);
2050 if (!player)
2051 return;
2052
2053 // check immunity again in case it changed during update
2054 if (player->IsImmunedToSpellEffect(spell->GetSpellInfo(), spellEffectInfo, nullptr))
2055 return;
2056
2057 spell->HandleEffects(player, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2058 });
2059 }
2060 }
2061 return;
2062 default:
2063 break;
2064 }
2065
2066 // select spell implicit targets based on effect type
2067 if (!spellEffectInfo.GetImplicitTargetType())
2068 return;
2069
2070 uint32 targetMask = spellEffectInfo.GetMissingTargetMask();
2071
2072 if (!targetMask)
2073 return;
2074
2075 WorldObject* target = nullptr;
2076
2077 switch (spellEffectInfo.GetImplicitTargetType())
2078 {
2079 // add explicit object target or self to the target map
2081 // player which not released his spirit is Unit, but target flag for it is TARGET_FLAG_CORPSE_MASK
2083 {
2084 if (Unit* unit = m_targets.GetUnitTarget())
2085 target = unit;
2086 else if (targetMask & TARGET_FLAG_CORPSE_MASK)
2087 {
2088 if (Corpse* corpseTarget = m_targets.GetCorpseTarget())
2089 target = corpseTarget;
2090 }
2091 else //if (targetMask & TARGET_FLAG_UNIT_MASK)
2092 target = m_caster;
2093 }
2094 if (targetMask & TARGET_FLAG_ITEM_MASK)
2095 {
2096 if (Item* item = m_targets.GetItemTarget())
2097 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
2098 return;
2099 }
2100 if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK)
2101 target = m_targets.GetGOTarget();
2102 break;
2103 // add self to the target map
2105 if (targetMask & TARGET_FLAG_UNIT_MASK)
2106 target = m_caster;
2107 break;
2108 default:
2109 break;
2110 }
2111
2113
2114 if (target)
2115 {
2116 if (target->ToUnit())
2117 AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex, false);
2118 else if (target->ToGameObject())
2119 AddGOTarget(target->ToGameObject(), 1 << spellEffectInfo.EffectIndex);
2120 else if (target->ToCorpse())
2121 AddCorpseTarget(target->ToCorpse(), 1 << spellEffectInfo.EffectIndex);
2122 }
2123}
2124
2125uint32 Spell::GetSearcherTypeMask(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const* condList)
2126{
2127 // this function selects which containers need to be searched for spell target
2129
2130 // filter searchers based on searched object type
2131 switch (objType)
2132 {
2136 break;
2141 break;
2145 break;
2146 default:
2147 break;
2148 }
2149
2153 retMask &= GRID_MAP_TYPE_MASK_PLAYER;
2155 retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
2156
2157 if (condList)
2158 retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
2159 return retMask;
2160}
2161
2162template<class SEARCHER>
2163void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius)
2164{
2165 if (!containerMask)
2166 return;
2167
2168 // search world and grid for possible targets
2169 bool searchInGrid = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT)) != 0;
2170 bool searchInWorld = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE)) != 0;
2171 if (searchInGrid || searchInWorld)
2172 {
2173 float x = pos->GetPositionX();
2174 float y = pos->GetPositionY();
2175
2176 Map* map = referer->GetMap();
2177
2178 if (searchInWorld)
2179 Cell::VisitWorldObjects(x, y, map, searcher, radius);
2180
2181 if (searchInGrid)
2182 Cell::VisitGridObjects(x, y, map, searcher, radius);
2183 }
2184}
2185
2186template TC_GAME_API void Spell::SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
2187template TC_GAME_API void Spell::SearchTargets<Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
2188
2189WorldObject* Spell::SearchNearbyTarget(SpellEffectInfo const& spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
2190{
2191 WorldObject* target = nullptr;
2192 uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
2193 if (!containerTypeMask)
2194 return nullptr;
2195
2196 Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList, objectType);
2197 Trinity::WorldObjectLastSearcher searcher(PhasingHandler::GetAlwaysVisiblePhaseShift(), target, check, containerTypeMask);
2198 SearchTargets(searcher, containerTypeMask, m_caster, m_caster, range);
2199 return target;
2200}
2201
2202void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, SpellEffectInfo const& spellEffectInfo, SpellRange range, Position const* position, WorldObject* referer,
2203 SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList,
2205{
2206 uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
2207 if (!containerTypeMask)
2208 return;
2209
2210 float extraSearchRadius = range.Max > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
2211 Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList, objectType, searchReason);
2212 Trinity::WorldObjectListSearcher searcher(PhasingHandler::GetAlwaysVisiblePhaseShift(), targets, check, containerTypeMask);
2213 SearchTargets(searcher, containerTypeMask, m_caster, position, range.Max + extraSearchRadius);
2214}
2215
2216void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType,
2217 SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal)
2218{
2219 // max dist for jump target selection
2220 float jumpRadius = 0.0f;
2221 switch (m_spellInfo->DmgClass)
2222 {
2224 // 7.5y for multi shot
2225 jumpRadius = 7.5f;
2226 break;
2228 // 5y for swipe, cleave and similar
2229 jumpRadius = 5.0f;
2230 break;
2233 // 12.5y for chain heal spell since 3.2 patch
2234 if (isChainHeal)
2235 jumpRadius = 12.5f;
2236 // 10y as default for magic chain spells
2237 else
2238 jumpRadius = 10.0f;
2239 break;
2240 }
2241
2242 if (Player* modOwner = m_caster->GetSpellModOwner())
2243 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainJumpDistance, jumpRadius, this);
2244
2245 // max dist which spell can reach
2246 float searchRadius = [&]()
2247 {
2249 return GetMinMaxRange(false).Max;
2250
2252 return jumpRadius;
2253
2254 return jumpRadius * chainTargets;
2255 }();
2256
2258 std::list<WorldObject*> tempTargets;
2259 SearchAreaTargets(tempTargets, spellEffectInfo, { 0.0f, searchRadius }, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions.get(),
2261 tempTargets.remove(target);
2262
2263 // remove targets which are always invalid for chain spells
2264 // for some spells allow only chain targets in front of caster (swipe for example)
2266 {
2267 tempTargets.remove_if([&](WorldObject* object)
2268 {
2269 return !m_caster->HasInArc(static_cast<float>(M_PI), object);
2270 });
2271 }
2272
2273 while (chainTargets)
2274 {
2275 // try to get unit for next chain jump
2276 std::list<WorldObject*>::iterator foundItr = tempTargets.end();
2277 // get unit with highest hp deficit in dist
2278 if (isChainHeal)
2279 {
2280 uint32 maxHPDeficit = 0;
2281 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2282 {
2283 if (Unit* unit = (*itr)->ToUnit())
2284 {
2285 uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
2286 if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && chainSource->IsWithinDist(unit, jumpRadius) && IsWithinLOS(chainSource, unit, false, VMAP::ModelIgnoreFlags::M2))
2287 {
2288 foundItr = itr;
2289 maxHPDeficit = deficit;
2290 }
2291 }
2292 }
2293 }
2294 // get closest object
2295 else
2296 {
2297 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2298 {
2299 bool isBestDistanceMatch = foundItr != tempTargets.end() ? chainSource->GetDistanceOrder(*itr, *foundItr) : chainSource->IsWithinDist(*itr, jumpRadius);
2300 if (!isBestDistanceMatch)
2301 continue;
2302
2303 if (!IsWithinLOS(chainSource, *itr, false, VMAP::ModelIgnoreFlags::M2))
2304 continue;
2305
2307 continue;
2308
2309 foundItr = itr;
2310 }
2311 }
2312 // not found any valid target - chain ends
2313 if (foundItr == tempTargets.end())
2314 break;
2315
2317 chainSource = *foundItr;
2318
2319 targets.push_back(*foundItr);
2320 tempTargets.erase(foundItr);
2321 --chainTargets;
2322 }
2323}
2324
2333
2335{
2336 //==========================================================================================
2337 // Now fill data for trigger system, need know:
2338 // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
2339 //==========================================================================================
2340
2342 // Get data for type of attack and fill base info for trigger
2343 switch (m_spellInfo->DmgClass)
2344 {
2347 if (m_attackType == OFF_ATTACK)
2349 else
2352 break;
2354 // Auto attack
2356 {
2359 }
2360 else // Ranged spell attack
2361 {
2364 }
2365 break;
2366 default:
2369 && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT)) // Wands auto attack
2370 {
2373 }
2374 // For other spells trigger procflags are set in Spell::TargetInfo::DoDamageAndTriggers
2375 // Because spell positivity is dependant on target
2376 }
2377}
2378
2379std::pair<ProcFlagsInit /*attacker*/, ProcFlagsInit /*victim*/> Spell::FinalizeDataForTriggerSystem(bool positive) const
2380{
2382 {
2383 if (positive)
2385 else
2387 }
2389 {
2390 if (positive)
2392 else
2394 }
2395 else
2396 {
2397 if (positive)
2399 else
2401 }
2402}
2403
2405{
2406 m_UniqueTargetInfo.clear();
2407 m_UniqueGOTargetInfo.clear();
2408 m_UniqueItemInfo.clear();
2409 m_delayMoment = 0;
2410}
2411
2413{
2414 public:
2415 ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
2416
2417 bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
2418 {
2420 if (!caster)
2421 return true;
2422
2423 ProcFlags const typeMaskActor = PROC_FLAG_NONE;
2426 ProcFlagsSpellPhase const spellPhaseMask = PROC_SPELL_PHASE_NONE;
2427 ProcFlagsHit const hitMask = PROC_HIT_REFLECT;
2428
2429 Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
2430 return true;
2431 }
2432
2433 private:
2436};
2437
2438void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
2439{
2440 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2441 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(target, spellEffectInfo, losPosition))
2442 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2443
2444 // no effects left
2445 if (!effectMask)
2446 return;
2447
2448 if (checkIfValid)
2449 if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
2450 return;
2451
2452 // Check for effect immune skip if immuned
2453 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2454 if (target->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, m_caster))
2455 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2456
2457 ObjectGuid targetGUID = target->GetGUID();
2458
2459 // Lookup target in already in list
2460 auto ihit = std::ranges::find(m_UniqueTargetInfo, targetGUID, &TargetInfo::TargetGUID);
2461 if (ihit != std::end(m_UniqueTargetInfo)) // Found in list
2462 {
2463 // Immune effects removed from mask
2464 ihit->EffectMask |= effectMask;
2465 return;
2466 }
2467
2468 // This is new target calculate data for him
2469
2470 // Get spell hit result on target
2471 TargetInfo targetInfo;
2472 targetInfo.TargetGUID = targetGUID; // Store target GUID
2473 targetInfo.EffectMask = effectMask; // Store all effects not immune
2474 targetInfo.IsAlive = target->IsAlive();
2475 targetInfo.Damage = 0;
2476 targetInfo.Healing = 0;
2477 targetInfo.IsCrit = false;
2478
2479 // Calculate hit result
2481 targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo,
2482 m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)),
2483 false /*immunity will be checked after complete EffectMask is known*/);
2484
2485 // Spell have speed - need calculate incoming time
2486 // Incoming time is zero for self casts. At least I think so.
2487 if (m_caster != target)
2488 {
2489 float hitDelay = m_spellInfo->LaunchDelay;
2490 WorldObject const* missileSource = m_caster;
2492 {
2493 auto previousTargetItr = std::ranges::find_if(m_UniqueTargetInfo.rbegin(), m_UniqueTargetInfo.rend(), [effectMask](TargetInfo const& target)
2494 {
2495 return (target.EffectMask & effectMask) != 0;
2496 });
2497 if (previousTargetItr != std::rend(m_UniqueTargetInfo))
2498 {
2499 hitDelay = 0.0f; // this is not the first target in chain, LaunchDelay was already included
2500
2501 if (WorldObject* previousTarget = ObjectAccessor::GetWorldObject(*m_caster, previousTargetItr->TargetGUID))
2502 missileSource = previousTarget;
2503
2504 targetInfo.TimeDelay += previousTargetItr->TimeDelay;
2505 }
2506 }
2507
2509 hitDelay += std::max(m_spellInfo->Speed, m_spellInfo->MinDuration);
2510 else if (m_spellInfo->Speed > 0.0f)
2511 {
2512 // calculate spell incoming interval
2514 float dist = std::max(missileSource->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), 5.0f);
2515 hitDelay += std::max(dist / m_spellInfo->Speed, m_spellInfo->MinDuration);
2516 }
2517
2518 targetInfo.TimeDelay += uint64(std::floor(hitDelay * 1000.0f));
2519 }
2520 else
2521 targetInfo.TimeDelay = 0ULL;
2522
2523 // If target reflect spell back to caster
2524 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
2525 {
2526 // Shouldn't be able to reflect gameobject spells
2527 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
2528
2529 // Calculate reflected spell result on caster
2530 SpellCastResult castResult = m_spellInfo->CheckTarget(target, unitCaster, implicit);
2531 targetInfo.ReflectResult = castResult == SPELL_CAST_OK || castResult == SPELL_FAILED_TARGET_AURASTATE
2532 ? unitCaster->SpellHitResult(unitCaster, m_spellInfo,
2533 false /*can't reflect twice*/,
2534 false /*immunity will be checked after complete EffectMask is known*/)
2536
2538 targetInfo.ReflectingSpellId = target->GetAuraEffectsByType(SPELL_AURA_REFLECT_SPELLS).front()->GetId();
2539
2540 // Proc spell reflect aura when missile hits the original target
2542
2543 // Increase time interval for reflected spells by 1.5
2544 targetInfo.TimeDelay += targetInfo.TimeDelay >> 1;
2545 }
2546 else
2547 targetInfo.ReflectResult = SPELL_MISS_NONE;
2548
2549 // Calculate minimum incoming time
2550 if (targetInfo.TimeDelay && (!m_delayMoment || m_delayMoment > targetInfo.TimeDelay))
2551 m_delayMoment = targetInfo.TimeDelay;
2552
2553 // Add target to list
2554 m_UniqueTargetInfo.emplace_back(std::move(targetInfo));
2555}
2556
2558{
2559 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2560 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(go, spellEffectInfo))
2561 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2562
2563 // no effects left
2564 if (!effectMask)
2565 return;
2566
2567 ObjectGuid targetGUID = go->GetGUID();
2568
2569 // Lookup target in already in list
2570 auto ihit = std::ranges::find(m_UniqueGOTargetInfo, targetGUID, &GOTargetInfo::TargetGUID);
2571 if (ihit != std::end(m_UniqueGOTargetInfo)) // Found in list
2572 {
2573 // Add only effect mask
2574 ihit->EffectMask |= effectMask;
2575 return;
2576 }
2577
2578 // This is new target calculate data for him
2579
2580 GOTargetInfo target;
2581 target.TargetGUID = targetGUID;
2582 target.EffectMask = effectMask;
2583
2584 // Spell have speed - need calculate incoming time
2585 if (static_cast<WorldObject*>(m_caster) != go)
2586 {
2587 float hitDelay = m_spellInfo->LaunchDelay;
2589 hitDelay += std::max(m_spellInfo->Speed, m_spellInfo->MinDuration);
2590 else if (m_spellInfo->Speed > 0.0f)
2591 {
2592 // calculate spell incoming interval
2593 float dist = std::max(m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()), 5.0f);
2594 hitDelay += std::max(dist / m_spellInfo->Speed, m_spellInfo->MinDuration);
2595 }
2596
2597 target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
2598 }
2599 else
2600 target.TimeDelay = 0ULL;
2601
2602 // Calculate minimum incoming time
2603 if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
2604 m_delayMoment = target.TimeDelay;
2605
2606 // Add target to list
2607 m_UniqueGOTargetInfo.emplace_back(std::move(target));
2608}
2609
2610void Spell::AddItemTarget(Item* item, uint32 effectMask)
2611{
2612 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2613 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(item, spellEffectInfo))
2614 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2615
2616 // no effects left
2617 if (!effectMask)
2618 return;
2619
2620 // Lookup target in already in list
2621 auto ihit = std::ranges::find(m_UniqueItemInfo, item, &ItemTargetInfo::TargetItem);
2622 if (ihit != std::end(m_UniqueItemInfo)) // Found in list
2623 {
2624 // Add only effect mask
2625 ihit->EffectMask |= effectMask;
2626 return;
2627 }
2628
2629 // This is new target add data
2630
2631 ItemTargetInfo target;
2632 target.TargetItem = item;
2633 target.EffectMask = effectMask;
2634
2635 m_UniqueItemInfo.emplace_back(std::move(target));
2636}
2637
2638void Spell::AddCorpseTarget(Corpse* corpse, uint32 effectMask)
2639{
2640 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2641 if (!spellEffectInfo.IsEffect())
2642 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2643
2644 // no effects left
2645 if (!effectMask)
2646 return;
2647
2648 ObjectGuid targetGUID = corpse->GetGUID();
2649
2650 // Lookup target in already in list
2651 auto ihit = std::ranges::find(m_UniqueCorpseTargetInfo, targetGUID, &CorpseTargetInfo::TargetGUID);
2652 if (ihit != std::end(m_UniqueCorpseTargetInfo)) // Found in list
2653 {
2654 // Add only effect mask
2655 ihit->EffectMask |= effectMask;
2656 return;
2657 }
2658
2659 // This is new target calculate data for him
2660 CorpseTargetInfo target;
2661 target.TargetGUID = targetGUID;
2662 target.EffectMask = effectMask;
2663
2664 // Spell have speed - need calculate incoming time
2665 if (m_caster != corpse)
2666 {
2667 float hitDelay = m_spellInfo->LaunchDelay;
2669 hitDelay += std::max(m_spellInfo->Speed, m_spellInfo->MinDuration);
2670 else if (m_spellInfo->Speed > 0.0f)
2671 {
2672 // calculate spell incoming interval
2673 float dist = std::max(m_caster->GetDistance(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ()), 5.0f);
2674 hitDelay += std::max(dist / m_spellInfo->Speed, m_spellInfo->MinDuration);
2675 }
2676
2677 target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
2678 }
2679 else
2680 target.TimeDelay = 0LL;
2681
2682 // Calculate minimum incoming time
2683 if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
2684 m_delayMoment = target.TimeDelay;
2685
2686 // Add target to list
2687 m_UniqueCorpseTargetInfo.emplace_back(std::move(target));
2688}
2689
2691{
2692 m_destTargets[effIndex] = dest;
2693}
2694
2696{
2697 int32 index = 0;
2698 for (TargetInfo const& uniqueTargetInfo : m_UniqueTargetInfo)
2699 {
2700 if (uniqueTargetInfo.MissCondition == SPELL_MISS_NONE && uniqueTargetInfo.EffectMask & (1 << effect))
2701 {
2702 if (uniqueTargetInfo.TargetGUID == target)
2703 return index;
2704
2705 ++index;
2706 }
2707 }
2708
2709 return -1;
2710}
2711
2713{
2714 return std::ranges::count_if(m_UniqueTargetInfo, [effect](TargetInfo const& targetInfo)
2715 {
2716 return targetInfo.MissCondition == SPELL_MISS_NONE && targetInfo.EffectMask & (1 << effect);
2717 });
2718}
2719
2721{
2722 return std::ranges::count_if(m_UniqueGOTargetInfo, [effect](GOTargetInfo const& targetInfo)
2723 {
2724 return targetInfo.EffectMask & (1 << effect);
2725 });
2726}
2727
2729{
2730 return std::ranges::count_if(m_UniqueItemInfo, [effect](ItemTargetInfo const& targetInfo)
2731 {
2732 return targetInfo.EffectMask & (1 << effect);
2733 });
2734}
2735
2737{
2738 return std::ranges::count_if(m_UniqueCorpseTargetInfo, [effect](CorpseTargetInfo const& targetInfo)
2739 {
2740 return targetInfo.EffectMask & (1 << effect);
2741 });
2742}
2743
2745{
2746 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2747 if (!unit)
2748 return;
2749
2750 // Need init unitTarget by default unit (can changed in code on reflect)
2751 spell->unitTarget = unit;
2752
2753 // Reset damage/healing counter
2754 spell->m_damage = Damage;
2755 spell->m_healing = Healing;
2756
2757 _spellHitTarget = nullptr;
2759 _spellHitTarget = unit;
2761 _spellHitTarget = spell->m_caster->ToUnit();
2762
2764 unit->SetInCombatWith(spell->m_originalCaster);
2765
2766 // if target is flagged for pvp also flag caster if a player
2767 // but respect current pvp rules (buffing/healing npcs flagged for pvp only flags you if they are in combat)
2769 && unit->IsPvP() && spell->m_caster->IsPlayer() && spell->m_caster->GetGUID() != unit->GetGUID()
2770 && (unit->IsInCombat() || unit->IsCharmedOwnedByPlayerOrPlayer()); // need to check PvP state before spell effects, but act on it afterwards
2771
2772 if (_spellHitTarget)
2773 {
2774 SpellMissInfo missInfo = spell->PreprocessSpellHit(_spellHitTarget, *this);
2775 if (missInfo != SPELL_MISS_NONE)
2776 {
2777 if (missInfo != SPELL_MISS_MISS)
2778 spell->m_caster->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
2779 spell->m_damage = 0;
2780 spell->m_healing = 0;
2781 _spellHitTarget = nullptr;
2782 }
2783 }
2784
2785 spell->CallScriptOnHitHandlers();
2786
2787 // scripts can modify damage/healing for current target, save them
2788 Damage = spell->m_damage;
2789 Healing = spell->m_healing;
2790}
2791
2793{
2794 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2795 if (!unit)
2796 return;
2797
2798 // Need init unitTarget by default unit (can changed in code on reflect)
2799 // Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
2800 spell->unitTarget = unit;
2801 spell->targetMissInfo = MissCondition;
2802
2803 // Reset damage/healing counter
2804 spell->m_damage = Damage;
2805 spell->m_healing = Healing;
2806
2807 if (unit->IsAlive() != IsAlive && !spell->m_spellInfo->HasAttribute(SPELL_ATTR9_FORCE_CORPSE_TARGET))
2808 return;
2809
2811 return; // No missinfo in that case
2812
2813 if (_spellHitTarget)
2814 spell->DoSpellEffectHit(_spellHitTarget, spellEffectInfo, *this);
2815
2816 // scripts can modify damage/healing for current target, save them
2817 Damage = spell->m_damage;
2818 Healing = spell->m_healing;
2819}
2820
2822{
2823 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2824 if (!unit)
2825 return;
2826
2827 // other targets executed before this one changed pointer
2828 spell->unitTarget = unit;
2829 if (_spellHitTarget)
2830 spell->unitTarget = _spellHitTarget;
2831
2832 // Reset damage/healing counter
2833 spell->m_damage = Damage;
2834 spell->m_healing = Healing;
2835
2836 // Get original caster (if exist) and calculate damage/healing from him data
2837 // Skip if m_originalCaster not available
2838 Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit();
2839 if (caster)
2840 {
2841 // Fill base trigger info
2842 ProcFlagsInit procAttacker = spell->m_procAttacker;
2843 ProcFlagsInit procVictim = spell->m_procVictim;
2845
2846 // Spells with this flag cannot trigger if effect is cast on self
2847 bool const canEffectTrigger = spell->unitTarget->CanProc();
2848
2849 // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
2850 if (canEffectTrigger && !procAttacker && !procVictim)
2851 {
2852 bool positive = true;
2853 if (spell->m_damage > 0)
2854 positive = false;
2855 else if (!spell->m_healing)
2856 {
2857 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
2858 {
2859 // in case of immunity, check all effects to choose correct procFlags, as none has technically hit
2860 if (EffectMask && !(EffectMask & (1 << i)))
2861 continue;
2862
2863 if (!spell->m_spellInfo->IsPositiveEffect(i))
2864 {
2865 positive = false;
2866 break;
2867 }
2868 }
2869 }
2870
2871 std::tie(procAttacker, procVictim) = spell->FinalizeDataForTriggerSystem(positive);
2872 }
2873
2874 // All calculated do it!
2875 // Do healing
2876 bool hasHealing = false;
2877 std::unique_ptr<DamageInfo> spellDamageInfo;
2878 std::unique_ptr<HealInfo> healInfo;
2879 if (spell->m_healing > 0)
2880 {
2881 hasHealing = true;
2882 uint32 addhealth = spell->m_healing;
2883 if (IsCrit)
2884 {
2885 ProcHitMask |= PROC_HIT_CRITICAL;
2886 addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr);
2887 }
2888 else
2889 ProcHitMask |= PROC_HIT_NORMAL;
2890
2891 healInfo = std::make_unique<HealInfo>(caster, spell->unitTarget, addhealth, spell->m_spellInfo, spell->m_spellInfo->GetSchoolMask());
2892 caster->HealBySpell(*healInfo, IsCrit);
2893 spell->unitTarget->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo->GetEffectiveHeal()) * 0.5f, spell->m_spellInfo);
2894 spell->m_healing = healInfo->GetEffectiveHeal();
2895
2896 procSpellType |= PROC_SPELL_TYPE_HEAL;
2897 }
2898
2899 // Do damage
2900 bool hasDamage = false;
2901 if (spell->m_damage > 0)
2902 {
2903 hasDamage = true;
2904 // Fill base damage struct (unitTarget - is real spell target)
2905 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo, spell->m_SpellVisual, spell->m_spellSchoolMask, spell->m_castId);
2906 damageInfo.reflectingSpellId = ReflectingSpellId;
2907 // Check damage immunity
2908 if (spell->unitTarget->IsImmunedToDamage(caster, spell->m_spellInfo))
2909 {
2910 ProcHitMask = PROC_HIT_IMMUNE;
2911 spell->m_damage = 0;
2912
2913 // no packet found in sniffs
2914 }
2915 else
2916 {
2917 caster->SetLastDamagedTargetGuid(spell->unitTarget->GetGUID());
2918
2919 // Add bonuses and fill damageInfo struct
2920 caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit, MissCondition == SPELL_MISS_BLOCK, spell);
2921 Unit::DealDamageMods(damageInfo.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb);
2922
2923 ProcHitMask |= createProcHitMask(&damageInfo, MissCondition);
2924 procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE;
2925
2926 // sparring
2927 if (damageInfo.target != damageInfo.attacker)
2928 {
2929 if (Creature* victimCreature = damageInfo.target->ToCreature())
2930 damageInfo.damage = victimCreature->CalculateDamageForSparring(damageInfo.attacker, damageInfo.damage);
2931 }
2932 spell->m_damage = damageInfo.damage;
2933
2934 caster->DealSpellDamage(&damageInfo, true);
2935
2936 // Send log damage message to client
2937 caster->SendSpellNonMeleeDamageLog(&damageInfo);
2938 }
2939
2940 // Do triggers for unit
2941 if (canEffectTrigger)
2942 {
2943 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, SPELL_DIRECT_DAMAGE, spell->m_attackType, ProcHitMask);
2944 procSpellType |= PROC_SPELL_TYPE_DAMAGE;
2945 }
2946 }
2947
2948 // Passive spell hits/misses or active spells only misses (only triggers)
2949 if (!hasHealing && !hasDamage)
2950 {
2951 // Fill base damage struct (unitTarget - is real spell target)
2952 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo, spell->m_SpellVisual, spell->m_spellSchoolMask);
2953 ProcHitMask |= createProcHitMask(&damageInfo, MissCondition);
2954 // Do triggers for unit
2955 if (canEffectTrigger)
2956 {
2957 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, ProcHitMask);
2958 procSpellType |= PROC_SPELL_TYPE_NO_DMG_HEAL;
2959 }
2960
2961 // Failed Pickpocket, reveal rogue
2963 {
2964 Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit());
2965 unitCaster->RemoveAppliedAuras([](AuraApplication const* aurApp)
2966 {
2967 return aurApp->GetBase()->GetSpellInfo()->Dispel == DISPEL_STEALTH;
2968 });
2969 spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster);
2970 }
2971 }
2972
2973 // Do triggers for unit
2974 if (canEffectTrigger)
2975 {
2976 Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, ProcHitMask, spell, spellDamageInfo.get(), healInfo.get());
2977
2978 // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
2979 if (caster->GetTypeId() == TYPEID_PLAYER && (procSpellType & (PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL)))
2980 {
2983 caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo);
2984 }
2985 }
2986
2987 // set hitmask for finish procs
2988 spell->m_hitMask |= ProcHitMask;
2989 spell->m_procSpellType |= procSpellType;
2990
2991 // _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit
2992 if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
2993 {
2994 if (Unit* unitCaster = spell->m_caster->ToUnit())
2995 {
2996 unitCaster->AtTargetAttacked(unit, spell->m_spellInfo->HasInitialAggro());
2997
2999 if (Creature* targetCreature = unit->ToCreature())
3000 if (unitCaster->IsPlayer())
3001 targetCreature->SetTappedBy(unitCaster);
3002 }
3003
3006 }
3007
3008 // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
3010 caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, spell);
3011 }
3012
3013 if (_spellHitTarget)
3014 {
3015 //AI functions
3016 if (Creature* cHitTarget = _spellHitTarget->ToCreature())
3017 if (CreatureAI* hitTargetAI = cHitTarget->AI())
3018 hitTargetAI->SpellHit(spell->m_caster, spell->m_spellInfo);
3019
3020 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
3021 spell->m_caster->ToCreature()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
3022 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
3023 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
3024
3025 if (HitAura)
3026 {
3027 if (AuraApplication* aurApp = HitAura->GetApplicationOfTarget(_spellHitTarget->GetGUID()))
3028 {
3029 // only apply unapplied effects (for reapply case)
3030 uint32 effMask = EffectMask & aurApp->GetEffectsToApply();
3031 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
3032 if ((effMask & (1 << i)) && aurApp->HasEffect(i))
3033 effMask &= ~(1 << i);
3034
3035 if (effMask)
3036 _spellHitTarget->_ApplyAura(aurApp, effMask);
3037
3038 if (aurApp->IsNeedClientUpdate() && aurApp->GetRemoveMode() == AURA_REMOVE_NONE)
3039 {
3040 aurApp->ClientUpdate(false);
3041 _spellHitTarget->RemoveVisibleAuraUpdate(aurApp);
3042 }
3043 }
3044 }
3045
3046 // Needs to be called after dealing damage/healing to not remove breaking on damage auras
3047 spell->DoTriggersOnSpellHit(_spellHitTarget);
3048 }
3049
3050 if (_enablePVP)
3051 spell->m_caster->ToPlayer()->UpdatePvP(true);
3052
3053 spell->_spellAura = HitAura;
3055 spell->_spellAura = nullptr;
3056}
3057
3059{
3060 GameObject* go = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToGameObject() : ObjectAccessor::GetGameObject(*spell->m_caster, TargetGUID);
3061 if (!go)
3062 return;
3063
3065
3066 spell->HandleEffects(nullptr, nullptr, go, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3067
3068 // AI functions
3069 if (go->AI())
3070 go->AI()->SpellHit(spell->m_caster, spell->m_spellInfo);
3071
3072 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
3073 spell->m_caster->ToCreature()->AI()->SpellHitTarget(go, spell->m_spellInfo);
3074 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
3075 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(go, spell->m_spellInfo);
3076
3077 spell->CallScriptOnHitHandlers();
3079}
3080
3082{
3084
3085 spell->HandleEffects(nullptr, TargetItem, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3086
3087 spell->CallScriptOnHitHandlers();
3089}
3090
3092{
3093 Corpse* corpse = ObjectAccessor::GetCorpse(*spell->m_caster, TargetGUID);
3094 if (!corpse)
3095 return;
3096
3098
3099 spell->HandleEffects(nullptr, nullptr, nullptr, corpse, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3100
3101 spell->CallScriptOnHitHandlers();
3103}
3104
3106{
3107 if (!unit)
3108 return SPELL_MISS_EVADE;
3109
3110 // Target may have begun evading between launch and hit phases - re-check now
3111 if (Creature* creatureTarget = unit->ToCreature())
3112 if (creatureTarget->IsEvadingAttacks())
3113 return SPELL_MISS_EVADE;
3114
3115 // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
3116 if (hitInfo.TimeDelay && unit->IsImmunedToSpell(m_spellInfo, hitInfo.EffectMask, m_caster))
3117 return SPELL_MISS_IMMUNE;
3118
3120
3121 if (Player* player = unit->ToPlayer())
3122 {
3123 player->FailCriteria(CriteriaFailEvent::BeSpellTarget, m_spellInfo->Id);
3124 player->StartCriteria(CriteriaStartEvent::BeSpellTarget, m_spellInfo->Id);
3125 player->UpdateCriteria(CriteriaType::BeSpellTarget, m_spellInfo->Id, 0, 0, m_caster);
3126 }
3127
3128 if (Player* player = m_caster->ToPlayer())
3129 player->UpdateCriteria(CriteriaType::LandTargetedSpellOnTarget, m_spellInfo->Id, 0, 0, unit);
3130
3131 if (m_caster != unit)
3132 {
3133 // Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
3135 return SPELL_MISS_EVADE;
3136
3139 else if (m_caster->IsFriendlyTo(unit))
3140 {
3141 // for delayed spells ignore negative spells (after duel end) for friendly targets
3142 if (hitInfo.TimeDelay && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidAssistTarget(unit, m_spellInfo))
3143 return SPELL_MISS_EVADE;
3144
3145 // assisting case, healing and resurrection
3147 {
3149 {
3150 playerOwner->SetContestedPvP();
3151 playerOwner->UpdatePvP(true);
3152 }
3153 }
3154
3156 {
3157 if (m_originalCaster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // only do explicit combat forwarding for PvP enabled units
3158 m_originalCaster->GetCombatManager().InheritCombatStatesFrom(unit); // for creature v creature combat, the threat forward does it for us
3160 }
3161 }
3162 }
3163
3164 // original caster for auras
3165 WorldObject* origCaster = m_caster;
3166 if (m_originalCaster)
3167 origCaster = m_originalCaster;
3168
3169 // check immunity due to diminishing returns
3171 {
3172 for (SpellEffectInfo const& auraSpellEffect : m_spellInfo->GetEffects())
3173 hitInfo.AuraBasePoints[auraSpellEffect.EffectIndex] = (m_spellValue->CustomBasePointsMask & (1 << auraSpellEffect.EffectIndex))
3174 ? m_spellValue->EffectBasePoints[auraSpellEffect.EffectIndex]
3175 : auraSpellEffect.CalcBaseValue(m_originalCaster, unit, m_castItemEntry, m_castItemLevel);
3176
3177 // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
3179
3180 DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1;
3181 if (hitInfo.DRGroup)
3182 {
3183 diminishLevel = unit->GetDiminishing(hitInfo.DRGroup);
3185 // Increase Diminishing on unit, current informations for actually casts will use values above
3186 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && unit->IsAffectedByDiminishingReturns()))
3188 }
3189
3190 // Now Reduce spell duration using data received at spell hit
3191 // check whatever effects we're going to apply, diminishing returns only apply to negative aura effects
3192 hitInfo.Positive = true;
3193 if (origCaster == unit || !origCaster->IsFriendlyTo(unit))
3194 {
3195 for (SpellEffectInfo const& auraSpellEffect : m_spellInfo->GetEffects())
3196 {
3197 // mod duration only for effects applying aura!
3198 if (hitInfo.EffectMask & (1 << auraSpellEffect.EffectIndex) &&
3199 auraSpellEffect.IsUnitOwnedAuraEffect() &&
3200 !m_spellInfo->IsPositiveEffect(auraSpellEffect.EffectIndex))
3201 {
3202 hitInfo.Positive = false;
3203 break;
3204 }
3205 }
3206 }
3207
3210 else
3212
3213 // unit is immune to aura if it was diminished to 0 duration
3214 if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(m_spellInfo, hitInfo.AuraDuration, origCaster, diminishLevel))
3215 if (std::all_of(std::begin(m_spellInfo->GetEffects()), std::end(m_spellInfo->GetEffects()), [](SpellEffectInfo const& effInfo) { return !effInfo.IsEffect() || effInfo.Effect == SPELL_EFFECT_APPLY_AURA; }))
3216 return SPELL_MISS_IMMUNE;
3217 }
3218
3219 return SPELL_MISS_NONE;
3220}
3221
3222void Spell::DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo, TargetInfo& hitInfo)
3223{
3224 if (uint32 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << spellEffectInfo.EffectIndex, unit))
3225 {
3226 WorldObject* caster = m_caster;
3227 if (m_originalCaster)
3228 caster = m_originalCaster;
3229
3230 if (caster)
3231 {
3232 bool refresh = false;
3233
3234 if (!hitInfo.HitAura)
3235 {
3236 bool const resetPeriodicTimer = (m_spellInfo->StackAmount < 2) && !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER);
3237 uint32 const allAuraEffectMask = Aura::BuildEffectMaskForOwner(m_spellInfo, MAX_EFFECT_MASK, unit);
3238
3239 AuraCreateInfo createInfo(m_castId, m_spellInfo, GetCastDifficulty(), allAuraEffectMask, unit);
3240 createInfo
3241 .SetCasterGUID(caster->GetGUID())
3242 .SetBaseAmount(&hitInfo.AuraBasePoints[0])
3244 .SetPeriodicReset(resetPeriodicTimer)
3245 .SetOwnerEffectMask(aura_effmask)
3246 .SetIsRefresh(&refresh)
3249
3250 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo, false))
3251 {
3252 hitInfo.HitAura = aura->ToUnitAura();
3253
3254 hitInfo.HitAura->SetDiminishGroup(hitInfo.DRGroup);
3255
3256 if (!m_spellValue->Duration)
3257 {
3258 hitInfo.AuraDuration = caster->ModSpellDuration(m_spellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask());
3259
3260 if (hitInfo.AuraDuration > 0)
3261 {
3263
3264 // Haste modifies duration of channeled spells
3265 if (m_spellInfo->IsChanneled())
3266 caster->ModSpellDurationTime(m_spellInfo, hitInfo.AuraDuration, this);
3268 {
3269 int32 origDuration = hitInfo.AuraDuration;
3270 hitInfo.AuraDuration = 0;
3271 for (AuraEffect const* auraEff : hitInfo.HitAura->GetAuraEffects())
3272 if (int32 period = auraEff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED
3273 hitInfo.AuraDuration = std::max(std::max(origDuration / period, 1) * period, hitInfo.AuraDuration);
3274
3275 // if there is no periodic effect
3276 if (!hitInfo.AuraDuration)
3277 hitInfo.AuraDuration = int32(origDuration * m_originalCaster->m_unitData->ModCastingSpeed);
3278 }
3279
3281 {
3282 int32 newDuration = hitInfo.AuraDuration + hitInfo.HitAura->GetDuration();
3283 hitInfo.AuraDuration = std::min(newDuration, CalculatePct(hitInfo.AuraDuration, 130));
3284 }
3285 }
3286 }
3287 else
3289
3290 if (hitInfo.AuraDuration != hitInfo.HitAura->GetMaxDuration())
3291 {
3292 hitInfo.HitAura->SetMaxDuration(hitInfo.AuraDuration);
3293 hitInfo.HitAura->SetDuration(hitInfo.AuraDuration);
3294 }
3295
3296 if (refresh)
3297 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
3298 }
3299 }
3300 else
3301 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
3302 }
3303 }
3304
3305 _spellAura = hitInfo.HitAura;
3306 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3307 _spellAura = nullptr;
3308}
3309
3311{
3312 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras
3313 // this is executed after spell proc spells on target hit
3314 // spells are triggered for each hit spell target
3315 // info confirmed with retail sniffs of permafrost and shadow weaving
3316 if (!m_hitTriggerSpells.empty())
3317 {
3318 int32 _duration = 0;
3319 for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
3320 {
3321 if (CanExecuteTriggersOnHit(unit, i->triggeredByAura) && roll_chance(i->chance))
3322 {
3323 m_caster->CastSpell(unit, i->triggeredSpell->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
3324 .SetTriggeringSpell(this)
3325 .SetCastDifficulty(i->triggeredSpell->Difficulty));
3326 TC_LOG_DEBUG("spells", "Spell {} triggered spell {} by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id);
3327
3328 // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
3329 // set duration of current aura to the triggered spell
3330 if (i->triggeredSpell->GetDuration() == -1)
3331 {
3332 if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID()))
3333 {
3334 // get duration from aura-only once
3335 if (!_duration)
3336 {
3337 Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
3338 _duration = aur ? aur->GetDuration() : -1;
3339 }
3340 triggeredAur->SetDuration(_duration);
3341 }
3342 }
3343 }
3344 }
3345 }
3346
3347 // trigger linked auras remove/apply
3349 if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_HIT, m_spellInfo->Id))
3350 {
3351 for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
3352 {
3353 if (*i < 0)
3354 unit->RemoveAurasDueToSpell(-(*i));
3355 else
3358 .SetTriggeringSpell(this));
3359 }
3360 }
3361}
3362
3364{
3365 // Not need check return true
3367 return true;
3368
3369 uint32 channelTargetEffectMask = m_channelTargetEffectMask;
3370 uint32 channelAuraMask = 0;
3371 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3372 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3373 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
3374
3375 channelAuraMask &= channelTargetEffectMask;
3376
3377 float range = 0;
3378 if (channelAuraMask)
3379 {
3381 if (Player* modOwner = m_caster->GetSpellModOwner())
3382 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, range, this);
3383
3384 // add little tolerance level
3385 range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
3386 }
3387
3388 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
3389 {
3390 if (targetInfo.MissCondition == SPELL_MISS_NONE && (channelTargetEffectMask & targetInfo.EffectMask))
3391 {
3392 Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
3393 if (!unit)
3394 {
3395 if (Unit* unitCaster =m_caster->ToUnit())
3396 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3397 continue;
3398 }
3399
3400 if (IsValidDeadOrAliveTarget(unit))
3401 {
3402 if (channelAuraMask & targetInfo.EffectMask)
3403 {
3405 {
3406 if (m_caster != unit && !m_caster->IsWithinDistInMap(unit, range))
3407 {
3408 targetInfo.EffectMask &= ~aurApp->GetEffectMask();
3409 unit->RemoveAura(aurApp);
3410 if (Unit* unitCaster = m_caster->ToUnit())
3411 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3412 continue;
3413 }
3414 }
3415 else // aura is dispelled
3416 {
3417 if (Unit* unitCaster = m_caster->ToUnit())
3418 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3419 continue;
3420 }
3421 }
3422
3423 channelTargetEffectMask &= ~targetInfo.EffectMask; // remove from need alive mask effect that have alive target
3424 }
3425 }
3426 }
3427
3428 // is all effects from m_needAliveTargetMask have alive targets
3429 return channelTargetEffectMask == 0;
3430}
3431
3432SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura)
3433{
3434 if (m_CastItem)
3435 {
3438
3439 if (Player* owner = m_CastItem->GetOwner())
3441 else if (m_CastItem->GetOwnerGUID() == m_caster->GetGUID())
3443 else
3444 {
3448 }
3449 }
3450
3451 InitExplicitTargets(targets);
3452
3454
3455 if (triggeredByAura)
3456 {
3457 m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
3458 m_castItemLevel = triggeredByAura->GetBase()->GetCastItemLevel();
3459 }
3460
3461 // create and add update event for this spell
3462 _spellEvent = new SpellEvent(this);
3464
3465 // check disables
3467 {
3471 }
3472
3473 // Prevent casting at cast another spell (ServerSide check)
3475 {
3479 }
3480
3481 LoadScripts();
3482
3483 // Fill cost data (do not use power for item casts)
3484 if (!m_CastItem)
3486
3487 int32 param1 = 0, param2 = 0;
3488 SpellCastResult result = CheckCast(true, &param1, &param2);
3489 // target is checked in too many locations and with different results to handle each of them
3490 // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
3492 result = SPELL_CAST_OK;
3493 if (result != SPELL_CAST_OK)
3494 {
3495 // Periodic auras should be interrupted when aura triggers a spell which can't be cast
3496 // for example bladestorm aura should be removed on disarm as of patch 3.3.5
3497 // channeled periodic spells should be affected by this (arcane missiles, penance, etc)
3498 // a possible alternative sollution for those would be validating aura target on unit state change
3499 if (triggeredByAura && triggeredByAura->IsPeriodic() && !triggeredByAura->GetBase()->IsPassive())
3500 {
3501 SendChannelUpdate(0, result);
3502 triggeredByAura->GetBase()->SetDuration(0);
3503 }
3504
3505 if (param1 || param2)
3506 SendCastResult(result, &param1, &param2);
3507 else
3508 SendCastResult(result);
3509
3510 // queue autorepeat spells for future repeating
3513
3514 finish(result);
3515 return result;
3516 }
3517
3518 // Prepare data for triggers
3520
3524
3525 SpellCastResult movementResult = SPELL_CAST_OK;
3526 if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving())
3527 movementResult = CheckMovement();
3528
3529 // Creatures focus their target when possible
3531 {
3532 // Channeled spells and some triggered spells do not focus a cast target. They face their target later on via channel object guid and via spell attribute or not at all
3533 bool const focusTarget = !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING);
3534 if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
3536 else
3537 m_caster->ToCreature()->SetSpellFocus(this, nullptr);
3538 }
3539
3540 if (movementResult != SPELL_CAST_OK)
3541 {
3543 {
3544 SendCastResult(movementResult);
3545 finish(movementResult);
3546 return movementResult;
3547 }
3548 else
3549 {
3550 // Creatures (not controlled) give priority to spell casting over movement.
3551 // We assume that the casting is always valid and the current movement
3552 // is stopped immediately (because spells are updated before movement, so next Unit::Update would cancel the spell before stopping movement)
3553 // and future attempts are stopped by by Unit::IsMovementPreventedByCasting in movement generators to prevent casting interruption.
3555 }
3556 }
3557
3559
3560 // set timer base at cast time
3561 ReSetTimer();
3562
3563 TC_LOG_DEBUG("spells", "Spell::prepare: spell id {} source {} caster {} customCastFlags {} mask {}", m_spellInfo->Id, m_caster->GetEntry(), m_originalCaster ? m_originalCaster->GetEntry() : -1, _triggeredCastFlags, m_targets.GetTargetMask());
3564
3567
3570
3571 //Containers for channeled spells have to be set
3573 // Why check duration? 29350: channelled triggers channelled
3575 cast(true);
3576 else
3577 {
3578 // commented out !m_spellInfo->StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
3579 // as a result a spell that passed CheckCast and should be processed instantly may suffer from this delayed process
3580 // the easiest bug to observe is LoS check in AddUnitTarget, even if spell passed the CheckCast LoS check the situation can change in spell::update
3581 // because target could be relocated in the meantime, making the spell fly to the air (no targets can be registered, so no effects processed, nothing in combat log)
3582 bool willCastDirectly = !m_casttime && GetCurrentContainer() == CURRENT_GENERIC_SPELL;
3583
3584 if (Unit* unitCaster = m_caster->ToUnit())
3585 {
3586 // stealth must be removed at cast starting (at show channel bar)
3587 // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
3589 unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action, m_spellInfo);
3590
3591 // Do not register as current spell when requested to ignore cast in progress
3592 // We don't want to interrupt that other spell with cast time
3593 if (!willCastDirectly || !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS))
3594 unitCaster->SetCurrentCastSpell(this);
3595 }
3597
3600
3601 // Call CreatureAI hook OnSpellStart
3602 if (Creature* caster = m_caster->ToCreature())
3603 if (caster->IsAIEnabled())
3604 caster->AI()->OnSpellStart(GetSpellInfo());
3605
3606 if (willCastDirectly)
3607 cast(true);
3608 }
3609
3610 return SPELL_CAST_OK;
3611}
3612
3613void Spell::cancel(SpellCastResult result /*= SPELL_FAILED_INTERRUPTED*/, Optional<SpellCastResult> resultOther /*= {}*/, ObjectGuid const& failedBy /*= ObjectGuid::Empty*/)
3614{
3616 return;
3617
3618 SpellState oldState = m_spellState;
3620
3621 m_autoRepeat = false;
3622 switch (oldState)
3623 {
3626 SendCastResult(result, nullptr, nullptr, failedBy);
3627 SendInterrupted(result, resultOther, failedBy);
3628 break;
3630 SendInterrupted(result, resultOther, failedBy);
3631 break;
3633 {
3634 // Mark current spell as not deletable to protect against scripts attempting to despawn the caster twice (aura removal)
3635 // while current spell is being cancelled by despawn
3636 bool executed = m_executedCurrently;
3638
3639 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
3640 if (targetInfo.MissCondition == SPELL_MISS_NONE)
3641 if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
3642 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3643
3644 SetExecutedCurrently(executed);
3645 }
3646
3648 SendInterrupted(result, resultOther, failedBy);
3649 break;
3650 default:
3651 break;
3652 }
3653
3655 if (m_selfContainer && *m_selfContainer == this)
3656 *m_selfContainer = nullptr;
3657
3658 // originalcaster handles gameobjects/dynobjects for gob caster
3659 if (m_originalCaster)
3660 {
3662 if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
3663 {
3665 {
3666 m_originalCaster->RemoveGameObject(gameObject, true);
3667 if (gameObject->GetGoType() == GAMEOBJECT_TYPE_RITUAL)
3669 }
3670 }
3671 }
3672
3673 //set state back so finish will be processed
3674 m_spellState = oldState;
3675
3677}
3678
3679void Spell::cast(bool skipCheck)
3680{
3681 Player* modOwner = m_caster->GetSpellModOwner();
3682 Spell* lastSpellMod = nullptr;
3683 if (modOwner)
3684 {
3685 lastSpellMod = modOwner->m_spellModTakingSpell;
3686 if (lastSpellMod)
3687 modOwner->SetSpellModTakingSpell(lastSpellMod, false);
3688 }
3689
3690 _cast(skipCheck);
3691
3692 if (lastSpellMod)
3693 modOwner->SetSpellModTakingSpell(lastSpellMod, true);
3694}
3695
3696void Spell::_cast(bool skipCheck)
3697{
3698 // update pointers base at GUIDs to prevent access to non-existed already object
3699 if (!UpdatePointers())
3700 {
3701 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3702 cancel();
3703 return;
3704 }
3705
3706 // cancel at lost explicit target during cast
3708 {
3709 cancel();
3710 return;
3711 }
3712
3713 if (Player* playerCaster = m_caster->ToPlayer())
3714 {
3715 // now that we've done the basic check, now run the scripts
3716 // should be done before the spell is actually executed
3717 sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
3718
3719 // As of 3.0.2 pets begin attacking their owner's target immediately
3720 // Let any pets know we've attacked something. Check DmgClass for harmful spells only
3721 // This prevents spells such as Hunter's Mark from triggering pet attack
3722 if (GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE)
3723 if (Unit* target = m_targets.GetUnitTarget())
3724 for (Unit* controlled : playerCaster->m_Controlled)
3725 if (Creature* cControlled = controlled->ToCreature())
3726 if (CreatureAI* controlledAI = cControlled->AI())
3727 controlledAI->OwnerAttacked(target);
3728 }
3729
3731
3732 // Should this be done for original caster?
3733 Player* modOwner = m_caster->GetSpellModOwner();
3734 if (modOwner)
3735 {
3736 // Set spell which will drop charges for triggered cast spells
3737 // if not successfully cast, will be remove in finish(false)
3738 modOwner->SetSpellModTakingSpell(this, true);
3739 }
3740
3742
3743 // skip check if done already (for instant cast spells for example)
3744 if (!skipCheck)
3745 {
3746 auto cleanupSpell = [this, modOwner](SpellCastResult res, int32* p1 = nullptr, int32* p2 = nullptr)
3747 {
3748 SendCastResult(res, p1, p2);
3749 SendInterrupted(res);
3750
3751 if (modOwner)
3752 modOwner->SetSpellModTakingSpell(this, false);
3753
3754 finish(res);
3755 SetExecutedCurrently(false);
3756 };
3757
3758 int32 param1 = 0, param2 = 0;
3759 SpellCastResult castResult = CheckCast(false, &param1, &param2);
3760 if (castResult != SPELL_CAST_OK)
3761 {
3762 cleanupSpell(castResult, &param1, &param2);
3763 return;
3764 }
3765
3766 // additional check after cast bar completes (must not be in CheckCast)
3767 // if trade not complete then remember it in trade data
3769 {
3770 if (modOwner)
3771 {
3772 if (TradeData* my_trade = modOwner->GetTradeData())
3773 {
3774 if (!my_trade->IsInAcceptProcess())
3775 {
3776 // Spell will be cast after completing the trade. Silently ignore at this place
3777 my_trade->SetSpell(m_spellInfo->Id, m_CastItem);
3778 cleanupSpell(SPELL_FAILED_DONT_REPORT);
3779 return;
3780 }
3781 }
3782 }
3783 }
3784
3785 // check diminishing returns (again, only after finish cast bar, tested on retail)
3786 if (Unit* target = m_targets.GetUnitTarget())
3787 {
3788 uint32 aura_effmask = 0;
3789 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3790 if (spellEffectInfo.IsUnitOwnedAuraEffect())
3791 aura_effmask |= 1 << spellEffectInfo.EffectIndex;
3792
3793 if (aura_effmask)
3794 {
3796 {
3798 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
3799 {
3801 {
3802 if (target->HasStrongerAuraWithDR(m_spellInfo, caster))
3803 {
3804 cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
3805 return;
3806 }
3807 }
3808 }
3809 }
3810 }
3811 }
3812 }
3813 // The spell focusing is making sure that we have a valid cast target guid when we need it so only check for a guid value here.
3814 if (Creature* creatureCaster = m_caster->ToCreature())
3815 if (!creatureCaster->GetTarget().IsEmpty() && !creatureCaster->HasUnitFlag(UNIT_FLAG_POSSESSED))
3816 if (WorldObject const* target = ObjectAccessor::GetUnit(*creatureCaster, creatureCaster->GetTarget()))
3817 creatureCaster->SetInFront(target);
3818
3820
3821 // Spell may be finished after target map check
3823 {
3825
3826 // cleanup after mod system
3827 // triggered spell pointer can be not removed in some cases
3828 if (modOwner)
3829 modOwner->SetSpellModTakingSpell(this, false);
3830
3832 SetExecutedCurrently(false);
3833 return;
3834 }
3835
3836 if (Unit* unitCaster = m_caster->ToUnit())
3838 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetPetGUID()))
3839 pet->DespawnOrUnsummon();
3840
3842
3844
3845 // traded items have trade slot instead of guid in m_itemTargetGUID
3846 // set to real guid to be sent later to the client
3848
3849 if (Player* player = m_caster->ToPlayer())
3850 {
3852 {
3853 player->StartCriteria(CriteriaStartEvent::UseItem, m_CastItem->GetEntry());
3854 player->UpdateCriteria(CriteriaType::UseItem, m_CastItem->GetEntry());
3855 }
3856
3857 player->FailCriteria(CriteriaFailEvent::CastSpell, m_spellInfo->Id);
3858 player->StartCriteria(CriteriaStartEvent::CastSpell, m_spellInfo->Id);
3859 player->UpdateCriteria(CriteriaType::CastSpell, m_spellInfo->Id);
3860 }
3861
3862 // Spells that don't create items can have this attribute - handle here
3864 if (Player* playerCaster = m_caster->ToPlayer())
3865 playerCaster->UpdateCraftSkill(m_spellInfo);
3866
3867 // Powers have to be taken before SendSpellGo
3869 TakePower();
3870
3872 TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
3873 else if (Item* targetItem = m_targets.GetItemTarget())
3874 {
3876 if (targetItem->GetOwnerGUID() != m_caster->GetGUID())
3877 TakeReagents();
3878 }
3879
3880 // CAST SPELL
3882
3884 {
3886 m_launchHandled = true;
3887 }
3888
3891
3892 // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
3893 SendSpellGo();
3894
3897
3898 if (!m_spellInfo->IsChanneled())
3899 if (Creature* creatureCaster = m_caster->ToCreature())
3900 creatureCaster->ReleaseSpellFocus(this);
3901
3902 if (m_originalCaster)
3903 {
3904 // Handle procs on cast
3905 ProcFlagsInit procAttacker = m_procAttacker;
3906 if (!procAttacker)
3907 procAttacker = FinalizeDataForTriggerSystem(IsPositive()).first;
3908
3909 procAttacker |= PROC_FLAG_2_CAST_SUCCESSFUL;
3910
3911 ProcFlagsHit hitMask = m_hitMask;
3912 if (!(hitMask & PROC_HIT_CRITICAL))
3913 hitMask |= PROC_HIT_NORMAL;
3914
3917
3918 Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
3919
3920 // Call CreatureAI hook OnSpellCast
3921 if (Creature* caster = m_originalCaster->ToCreature())
3922 if (caster->IsAIEnabled())
3923 caster->AI()->OnSpellCast(GetSpellInfo());
3924 }
3925
3926 // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
3928 {
3929 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3930 // in case delayed spell remove item at cast delay start
3931 TakeCastItem();
3932
3933 // Okay, maps created, now prepare flags
3934 m_immediateHandled = false;
3935 SetDelayStart(0);
3936
3937 if (Unit* unitCaster = m_caster->ToUnit())
3938 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true, false, true, true))
3939 unitCaster->ClearUnitState(UNIT_STATE_CASTING);
3940 }
3941 else
3942 {
3943 // Immediate spell, no big deal
3945 }
3946
3949
3951
3952 if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(SPELL_LINK_CAST, m_spellInfo->Id))
3953 {
3954 for (int32 id : *spell_triggered)
3955 {
3956 if (id < 0)
3957 {
3958 if (Unit* unitCaster = m_caster->ToUnit())
3959 unitCaster->RemoveAurasDueToSpell(-id);
3960 }
3961 else
3963 .SetTriggeringSpell(this));
3964 }
3965 }
3966
3967 if (modOwner)
3968 {
3969 modOwner->SetSpellModTakingSpell(this, false);
3970
3971 //Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
3973 {
3976 }
3977 }
3978
3979 SetExecutedCurrently(false);
3980}
3981
3982template <class Container>
3983void Spell::DoProcessTargetContainer(Container& targetContainer)
3984{
3985 for (TargetInfoBase& target : targetContainer)
3986 target.PreprocessTarget(this);
3987
3988 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3989 for (TargetInfoBase& target : targetContainer)
3990 if (target.EffectMask & (1 << spellEffectInfo.EffectIndex))
3991 target.DoTargetSpellHit(this, spellEffectInfo);
3992
3993 for (TargetInfoBase& target : targetContainer)
3994 target.DoDamageAndTriggers(this);
3995}
3996
3998{
3999 // start channeling if applicable
4000 if (m_spellInfo->IsChanneled())
4001 {
4002 int32 duration = m_spellInfo->GetDuration();
4003 if (duration > 0 || m_spellValue->Duration > 0)
4004 {
4005 if (!m_spellValue->Duration)
4006 {
4007 int32 originalDuration = duration;
4008
4009 // First mod_duration then haste - see Missile Barrage
4010 // Apply duration mod
4011 if (Player* modOwner = m_caster->GetSpellModOwner())
4012 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Duration, duration);
4013
4014 duration *= m_spellValue->DurationMul;
4015
4016 // Apply haste mods
4017 m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
4018
4019 if (IsEmpowerSpell())
4020 {
4021 float ratio = float(duration) / float(originalDuration);
4022 m_empower->StageDurations.resize(m_spellInfo->EmpowerStageThresholds.size());
4023 Milliseconds totalExceptLastStage = 0ms;
4024 for (std::size_t i = 0; i < m_empower->StageDurations.size() - 1; ++i)
4025 {
4026 m_empower->StageDurations[i] = Milliseconds(int64(m_spellInfo->EmpowerStageThresholds[i].count() * ratio));
4027 totalExceptLastStage += m_empower->StageDurations[i];
4028 }
4029
4030 m_empower->StageDurations.back() = Milliseconds(duration) - totalExceptLastStage;
4031
4032 if (Player const* playerCaster = m_caster->ToPlayer())
4033 m_empower->MinHoldTime = Milliseconds(int64(m_empower->StageDurations[0].count() * playerCaster->GetEmpowerMinHoldStagePercent()));
4034 else
4035 m_empower->MinHoldTime = m_empower->StageDurations[0];
4036
4038 }
4039 }
4040 else
4041 duration = *m_spellValue->Duration;
4042
4043 m_channelDuration = duration;
4044 SendChannelStart(duration);
4045 }
4046 else if (duration == -1)
4047 SendChannelStart(duration);
4048
4049 if (duration != 0)
4050 {
4052 // GameObjects shouldn't cast channeled spells
4054 }
4055 }
4056
4058
4059 // process immediate effects (items, ground, etc.) also initialize some variables
4061
4062 // consider spell hit for some spells without target, so they may proc on finish phase correctly
4063 if (m_UniqueTargetInfo.empty())
4064 {
4067 }
4068 else
4070
4072
4074
4076
4077 // spell is finished, perform some last features of the spell here
4079
4080 // Remove used for cast item if need (it can be already NULL after TakeReagents call
4081 TakeCastItem();
4082
4084 finish(); // successfully finish spell cast (not last in case autorepeat or channel spell)
4085}
4086
4088{
4089 if (!UpdatePointers())
4090 {
4091 // finish the spell if UpdatePointers() returned false, something wrong happened there
4093 return 0;
4094 }
4095
4096 // when spell has a single missile we hit all targets (except caster) at the same time
4097 bool single_missile = m_targets.HasDst();
4098 bool ignoreTargetInfoTimeDelay = single_missile;
4099 uint64 next_time = 0;
4100
4101 if (!m_launchHandled)
4102 {
4103 uint64 launchMoment = uint64(std::floor(m_spellInfo->LaunchDelay * 1000.0f));
4104 if (launchMoment > t_offset)
4105 return launchMoment;
4106
4108 m_launchHandled = true;
4109 }
4110
4111 if (m_delayMoment > t_offset)
4112 {
4113 ignoreTargetInfoTimeDelay = false;
4114 next_time = m_delayMoment;
4115 }
4116
4117 Player* modOwner = m_caster->GetSpellModOwner();
4118 if (modOwner)
4119 modOwner->SetSpellModTakingSpell(this, true);
4120
4122
4123 if (!m_immediateHandled && m_delayMoment <= t_offset)
4124 {
4126 m_immediateHandled = true;
4127 }
4128
4129 // now recheck units targeting correctness (need before any effects apply to prevent adding immunity at first effect not allow apply second spell effect and similar cases)
4130 {
4131 std::vector<TargetInfo> delayedTargets;
4132 m_UniqueTargetInfo.erase(std::remove_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo& target) -> bool
4133 {
4134 if (ignoreTargetInfoTimeDelay || target.TimeDelay <= t_offset)
4135 {
4136 target.TimeDelay = t_offset;
4137 delayedTargets.emplace_back(std::move(target));
4138 return true;
4139 }
4140 else if (!single_missile && (next_time == 0 || target.TimeDelay < next_time))
4141 next_time = target.TimeDelay;
4142
4143 return false;
4144 }), m_UniqueTargetInfo.end());
4145
4146 DoProcessTargetContainer(delayedTargets);
4147 }
4148
4149 // now recheck gameobject targeting correctness
4150 {
4151 std::vector<GOTargetInfo> delayedGOTargets;
4152 m_UniqueGOTargetInfo.erase(std::remove_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [&](GOTargetInfo& goTarget) -> bool
4153 {
4154 if (ignoreTargetInfoTimeDelay || goTarget.TimeDelay <= t_offset)
4155 {
4156 goTarget.TimeDelay = t_offset;
4157 delayedGOTargets.emplace_back(std::move(goTarget));
4158 return true;
4159 }
4160 else if (!single_missile && (next_time == 0 || goTarget.TimeDelay < next_time))
4161 next_time = goTarget.TimeDelay;
4162
4163 return false;
4164 }), m_UniqueGOTargetInfo.end());
4165
4166 DoProcessTargetContainer(delayedGOTargets);
4167 }
4168
4170
4171 if (modOwner)
4172 modOwner->SetSpellModTakingSpell(this, false);
4173
4174 // All targets passed - need finish phase
4175 if (next_time == 0)
4176 {
4177 // spell is finished, perform some last features of the spell here
4179
4180 finish(); // successfully finish spell cast
4181
4182 // return zero, spell is finished now
4183 return 0;
4184 }
4185 else
4186 {
4187 // spell is unfinished, return next execution time
4188 return next_time;
4189 }
4190}
4191
4193{
4194 // handle some immediate features of the spell here
4196
4197 // handle effects with SPELL_EFFECT_HANDLE_HIT mode
4198 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
4199 {
4200 // don't do anything for empty effect
4201 if (!spellEffectInfo.IsEffect())
4202 continue;
4203
4204 // call effect handlers to handle destination hit
4205 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
4206 }
4207
4208 // process items
4210}
4211
4213{
4214 if (Unit* unitCaster = m_caster->ToUnit())
4216 unitCaster->SetLastExtraAttackSpell(m_spellInfo->Id);
4217
4218 // Handle procs on finish
4219 if (!m_originalCaster)
4220 return;
4221
4222 ProcFlagsInit procAttacker = m_procAttacker;
4223 if (!procAttacker)
4224 procAttacker = FinalizeDataForTriggerSystem(IsPositive()).first;
4225
4227}
4228
4230{
4231 if (!m_caster->IsUnit())
4232 return;
4233
4235
4236 if (IsAutoRepeat())
4238}
4239
4240void Spell::update(uint32 difftime)
4241{
4242 // update pointers based at it's GUIDs
4243 if (!UpdatePointers())
4244 {
4245 // cancel the spell if UpdatePointers() returned false, something wrong happened there
4246 cancel();
4247 return;
4248 }
4249
4251 {
4252 TC_LOG_DEBUG("spells", "Spell {} is cancelled due to removal of target.", m_spellInfo->Id);
4253 cancel();
4254 return;
4255 }
4256
4257 // check if the unit caster has moved before the spell finished
4258 if (m_timer != 0 && m_caster->IsUnit() && m_caster->ToUnit()->isMoving() && CheckMovement() != SPELL_CAST_OK)
4259 cancel();
4260
4261 switch (m_spellState)
4262 {
4264 {
4265 if (m_timer > 0)
4266 {
4267 if (difftime >= (uint32)m_timer)
4268 m_timer = 0;
4269 else
4270 m_timer -= difftime;
4271 }
4272
4274 // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
4275 cast(!m_casttime);
4276 break;
4277 }
4279 {
4280 if (m_timer)
4281 {
4282 // check if there are alive targets left
4284 {
4285 TC_LOG_DEBUG("spells", "Channeled spell {} is removed due to lack of targets", m_spellInfo->Id);
4286 m_timer = 0;
4287
4288 // Also remove applied auras
4289 for (TargetInfo const& target : m_UniqueTargetInfo)
4290 if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
4291 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
4292 }
4293
4294 if (m_timer > 0)
4295 {
4296 if (difftime >= (uint32)m_timer)
4297 m_timer = 0;
4298 else
4299 m_timer -= difftime;
4300 }
4301 }
4302
4303 if (IsEmpowerSpell())
4304 {
4305 int32 completedStages = [&]() -> int32
4306 {
4308 for (std::size_t i = 0; i < m_empower->StageDurations.size(); ++i)
4309 {
4310 passed -= m_empower->StageDurations[i];
4311 if (passed < 0ms)
4312 return i;
4313 }
4314
4315 return m_empower->StageDurations.size();
4316 }();
4317
4318 if (completedStages != m_empower->CompletedStages)
4319 {
4321 empowerSetStage.CastID = m_castId;
4322 empowerSetStage.CasterGUID = m_caster->GetGUID();
4323 empowerSetStage.Stage = m_empower->CompletedStages;
4324 m_caster->SendMessageToSet(empowerSetStage.Write(), true);
4325
4326 m_empower->CompletedStages = completedStages;
4327 if (Unit* unitCaster = m_caster->ToUnit())
4328 unitCaster->SetSpellEmpowerStage(completedStages);
4329
4331 }
4332
4334 {
4335 m_empower->IsReleased = true;
4336 m_timer = 0;
4339 }
4340 }
4341
4342 if (m_timer == 0)
4343 {
4345 finish();
4346
4347 // We call the hook here instead of in Spell::finish because we only want to call it for completed channeling. Everything else is handled by interrupts
4348 if (Creature* creatureCaster = m_caster->ToCreature())
4349 if (creatureCaster->IsAIEnabled())
4350 creatureCaster->AI()->OnChannelFinished(m_spellInfo);
4351 }
4352 break;
4353 }
4354 default:
4355 break;
4356 }
4357}
4358
4360{
4362 return;
4364
4366 m_scriptResult.SetResult(result);
4367
4368 if (!m_caster)
4369 return;
4370
4371 Unit* unitCaster = m_caster->ToUnit();
4372 if (!unitCaster)
4373 return;
4374
4375 // successful cast of the initial autorepeat spell is moved to idle state so that it is not deleted as long as autorepeat is active
4376 if (IsAutoRepeat() && unitCaster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) == this)
4378
4379 if (m_spellInfo->IsChanneled())
4380 unitCaster->UpdateInterruptMask();
4381
4382 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true, false, true, true))
4384
4385 // Unsummon summon as possessed creatures on spell cancel
4386 if (m_spellInfo->IsChanneled() && unitCaster->GetTypeId() == TYPEID_PLAYER)
4387 {
4388 if (Unit* charm = unitCaster->GetCharmed())
4389 if (charm->GetTypeId() == TYPEID_UNIT
4390 && charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
4391 && charm->m_unitData->CreatedBySpell == int32(m_spellInfo->Id))
4392 ((Puppet*)charm)->UnSummon();
4393 }
4394
4395 if (Creature* creatureCaster = unitCaster->ToCreature())
4396 creatureCaster->ReleaseSpellFocus(this);
4397
4398 {
4399 // Mark current spell as not deletable to protect against scripts attempting to despawn the caster twice
4400 // while current spell is already being finished by despawn
4401 bool executed = m_executedCurrently;
4403
4405
4406 SetExecutedCurrently(executed);
4407 }
4408
4409 if (IsEmpowerSpell())
4410 {
4411 // Empower spells trigger gcd at the end of cast instead of at start
4412 if (SpellInfo const* gcd = sSpellMgr->GetSpellInfo(SPELL_EMPOWER_HARDCODED_GCD, DIFFICULTY_NONE))
4413 unitCaster->GetSpellHistory()->AddGlobalCooldown(gcd, Milliseconds(gcd->StartRecoveryTime));
4414 }
4415
4416 if (result != SPELL_CAST_OK)
4417 {
4418 // on failure (or manual cancel) send TraitConfigCommitFailed to revert talent UI saved config selection
4420 if (WorldPackets::Traits::TraitConfig const* traitConfig = std::any_cast<WorldPackets::Traits::TraitConfig>(&m_customArg))
4422
4423 if (IsEmpowerSpell())
4424 {
4425 unitCaster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
4426 RefundPower();
4427 }
4428
4429 return;
4430 }
4431
4432 if (unitCaster->GetTypeId() == TYPEID_UNIT && unitCaster->IsSummon())
4433 {
4434 // Unsummon statue
4435 uint32 spell = unitCaster->m_unitData->CreatedBySpell;
4436 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, GetCastDifficulty());
4437 if (spellInfo && spellInfo->IconFileDataId == 134230)
4438 {
4439 TC_LOG_DEBUG("spells", "Statue {} is unsummoned in spell {} finish", unitCaster->GetGUID().ToString(), m_spellInfo->Id);
4440 // Avoid infinite loops with setDeathState(JUST_DIED) being called over and over
4441 // It might make sense to do this check in Unit::setDeathState() and all overloaded functions
4442 if (unitCaster->getDeathState() != JUST_DIED)
4443 unitCaster->setDeathState(JUST_DIED);
4444 return;
4445 }
4446 }
4447
4448 // Stop Attack for some spells
4450 unitCaster->AttackStop();
4451}
4452
4453template<class T>
4454inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError,
4455 int32* param1, int32* param2, [[maybe_unused]] ObjectGuid const& failedBy)
4456{
4457 packet.CastID = castId;
4458 packet.SpellID = spellInfo->Id;
4459 packet.Reason = result;
4460
4461 switch (result)
4462 {
4464 if (param1)
4465 packet.FailedArg1 = *param1;
4466 else
4467 packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
4468 break;
4470 if (param1)
4471 packet.FailedArg1 = *param1;
4472 else
4473 packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
4474 break;
4475 case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
4476 if (param1)
4477 packet.FailedArg1 = *param1;
4478 else
4479 {
4480 // hardcode areas limitation case
4481 switch (spellInfo->Id)
4482 {
4483 case 41617: // Cenarion Mana Salve
4484 case 41619: // Cenarion Healing Salve
4485 packet.FailedArg1 = 3905;
4486 break;
4487 case 41618: // Bottled Nethergon Energy
4488 case 41620: // Bottled Nethergon Vapor
4489 packet.FailedArg1 = 3842;
4490 break;
4491 case 45373: // Bloodberry Elixir
4492 packet.FailedArg1 = 4075;
4493 break;
4494 default: // default case (don't must be)
4495 packet.FailedArg1 = 0;
4496 break;
4497 }
4498 }
4499 break;
4501 if (param1)
4502 {
4503 packet.FailedArg1 = *param1;
4504 }
4505 else
4506 {
4507 if (spellInfo->Totem[0])
4508 packet.FailedArg1 = spellInfo->Totem[0];
4509 else if (spellInfo->Totem[1])
4510 packet.FailedArg1 = spellInfo->Totem[1];
4511 }
4512 break;
4514 if (param1)
4515 {
4516 packet.FailedArg1 = *param1;
4517 }
4518 else
4519 {
4520 if (spellInfo->TotemCategory[0])
4521 packet.FailedArg1 = spellInfo->TotemCategory[0];
4522 else if (spellInfo->TotemCategory[1])
4523 packet.FailedArg1 = spellInfo->TotemCategory[1];
4524 }
4525 break;
4529 if (param1 && param2)
4530 {
4531 packet.FailedArg1 = *param1;
4532 packet.FailedArg2 = *param2;
4533 }
4534 else
4535 {
4536 packet.FailedArg1 = spellInfo->EquippedItemClass;
4537 packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
4538 }
4539 break;
4541 if (param1)
4542 packet.FailedArg1 = *param1; // ItemLimitCategory id
4543 break;
4545 if (param1)
4546 packet.FailedArg1 = *param1;
4547 break;
4549 if (param1)
4550 packet.FailedArg1 = *param1; // weapon subclass id
4551 break;
4553 if (param1 && param2)
4554 {
4555 packet.FailedArg1 = *param1; // Item id
4556 packet.FailedArg2 = *param2; // Item count
4557 }
4558 break;
4560 if (param1 && param2)
4561 {
4562 packet.FailedArg1 = *param1; // SkillLine.dbc id
4563 packet.FailedArg2 = *param2; // required skill value
4564 }
4565 break;
4567 if (param1)
4568 packet.FailedArg1 = *param1; // required fishing skill
4569 break;
4571 packet.FailedArg1 = customError;
4572 break;
4574 if (param1)
4575 packet.FailedArg1 = *param1;
4576 else
4577 packet.FailedArg1 = 0; // Unknown
4578 break;
4580 if (param1)
4581 packet.FailedArg1 = *param1;
4582 break;
4584 {
4585 ASSERT(param1);
4586 packet.FailedArg1 = *param1;
4587 break;
4588 }
4590 if constexpr (requires { { packet.FailedBy } -> std::assignable_from<ObjectGuid>; })
4591 packet.FailedBy = failedBy;
4592 break;
4593 // TODO: SPELL_FAILED_NOT_STANDING
4594 default:
4595 break;
4596 }
4597}
4598
4599void Spell::SendCastResult(SpellCastResult result, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/, ObjectGuid const& failedBy /*= ObjectGuid::Empty*/) const
4600{
4601 if (result == SPELL_CAST_OK)
4602 return;
4603
4604 Player const* receiver = m_caster->ToPlayer();
4606 if (Player const* target = Object::ToPlayer(m_targets.GetUnitTarget()))
4607 receiver = target;
4608
4609 if (!receiver)
4610 return;
4611
4612 if (receiver->IsLoading()) // don't send cast results at loading time
4613 return;
4614
4616 result = SPELL_FAILED_DONT_REPORT;
4617
4619 castFailed.Visual = m_SpellVisual;
4620 FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, failedBy);
4621 receiver->SendDirectMessage(castFailed.Write());
4622}
4623
4624void Spell::SendPetCastResult(SpellCastResult result, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
4625{
4626 if (result == SPELL_CAST_OK)
4627 return;
4628
4629 Unit* owner = m_caster->GetCharmerOrOwner();
4630 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
4631 return;
4632
4634 result = SPELL_FAILED_DONT_REPORT;
4635
4638 owner->ToPlayer()->SendDirectMessage(petCastFailed.Write());
4639}
4640
4641void Spell::SendCastResult(Player const* caster, SpellInfo const* spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/)
4642{
4643 if (result == SPELL_CAST_OK)
4644 return;
4645
4647 packet.Visual = spellVisual;
4648 FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, ObjectGuid::Empty);
4649 caster->SendDirectMessage(packet.Write());
4650}
4651
4653{
4654 if (result == MountResult::Ok)
4655 return;
4656
4657 if (!m_caster->IsPlayer())
4658 return;
4659
4660 Player* caster = m_caster->ToPlayer();
4661 if (caster->IsLoading()) // don't send mount results at loading time
4662 return;
4663
4665 packet.Result = AsUnderlyingType(result);
4666 caster->SendDirectMessage(packet.Write());
4667}
4668
4670{
4671 if (!IsNeedSendToClient())
4672 return;
4673
4674 TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id={}", m_spellInfo->Id);
4675
4676 uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
4677 uint32 schoolImmunityMask = 0;
4678 uint32 mechanicImmunityMask = 0;
4679 if (Unit* unitCaster = m_caster->ToUnit())
4680 {
4681 schoolImmunityMask = m_timer!= 0 ? unitCaster->GetSchoolImmunityMask() : 0;
4682 mechanicImmunityMask = m_timer != 0 ? m_spellInfo->GetMechanicImmunityMask(unitCaster) : 0;
4683 }
4684
4685 if (schoolImmunityMask || mechanicImmunityMask)
4686 castFlags |= CAST_FLAG_IMMUNITY;
4687
4689 castFlags |= CAST_FLAG_PENDING;
4690
4692 castFlags |= CAST_FLAG_PROJECTILE;
4693
4694 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4696 && std::ranges::any_of(m_powerCost, [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }))
4697 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4698
4699 if (m_fromClient)
4700 castFlags |= CAST_FLAG_FROM_CLIENT;
4701
4703 castFlags |= CAST_FLAG_HEAL_PREDICTION;
4704
4706 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4707
4708 if (m_CastItem)
4709 castData.CasterGUID = m_CastItem->GetGUID();
4710 else
4711 castData.CasterGUID = m_caster->GetGUID();
4712
4713 castData.CasterUnit = m_caster->GetGUID();
4714 castData.CastID = m_castId;
4716 castData.SpellID = m_spellInfo->Id;
4717 castData.Visual = m_SpellVisual;
4718 castData.CastFlags = castFlags;
4719 castData.CastFlagsEx = m_castFlagsEx;
4720 castData.CastTime = m_casttime;
4721
4722 m_targets.Write(castData.Target);
4723
4724 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4725 {
4726 for (SpellPowerCost const& cost : m_powerCost)
4727 {
4729 powerData.Type = cost.Power;
4730 powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
4731 castData.RemainingPower.push_back(powerData);
4732 }
4733 }
4734
4735 if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
4736 {
4737 castData.RemainingRunes.emplace();
4738
4739 //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature
4740 //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
4741 if (Player* player = m_caster->ToPlayer())
4742 {
4743 castData.RemainingRunes->Start = m_runesState; // runes state before
4744 castData.RemainingRunes->Count = player->GetRunesState(); // runes state after
4745 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4746 {
4747 // float casts ensure the division is performed on floats as we need float result
4748 float baseCd = float(player->GetRuneBaseCooldown());
4749 castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
4750 }
4751 }
4752 else
4753 {
4754 castData.RemainingRunes->Start = 0;
4755 castData.RemainingRunes->Count = 0;
4756 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4757 castData.RemainingRunes->Cooldowns.push_back(0);
4758 }
4759 }
4760
4761 if (castFlags & CAST_FLAG_PROJECTILE)
4763
4764 if (castFlags & CAST_FLAG_IMMUNITY)
4765 {
4766 castData.Immunities.School = schoolImmunityMask;
4767 castData.Immunities.Value = mechanicImmunityMask;
4768 }
4769
4770 if (castFlags & CAST_FLAG_HEAL_PREDICTION)
4771 UpdateSpellHealPrediction(castData.Predict, false);
4772
4773 m_caster->SendMessageToSet(packet.Write(), true);
4774}
4775
4777{
4778 // not send invisible spell casting
4779 if (!IsNeedSendToClient())
4780 return;
4781
4782 TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id={}", m_spellInfo->Id);
4783
4784 uint32 castFlags = CAST_FLAG_UNKNOWN_9;
4785
4786 // triggered spells with spell visual != 0
4788 castFlags |= CAST_FLAG_PENDING;
4789
4791 castFlags |= CAST_FLAG_PROJECTILE; // arrows/bullets visual
4792
4793 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4795 && std::ranges::any_of(m_powerCost, [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }))
4796 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4797
4798 if ((m_caster->GetTypeId() == TYPEID_PLAYER)
4802 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4803
4804 if (m_targets.HasTraj())
4805 castFlags |= CAST_FLAG_ADJUST_MISSILE;
4806
4807 if (m_fromClient)
4808 castFlags |= CAST_FLAG_FROM_CLIENT;
4809
4811 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4812 if (m_CastItem)
4813 castData.CasterGUID = m_CastItem->GetGUID();
4814 else
4815 castData.CasterGUID = m_caster->GetGUID();
4816
4817 castData.CasterUnit = m_caster->GetGUID();
4818 castData.CastID = m_castId;
4820 castData.SpellID = m_spellInfo->Id;
4821 castData.Visual = m_SpellVisual;
4822 castData.CastFlags = castFlags;
4823 castData.CastFlagsEx = m_castFlagsEx;
4824 castData.CastTime = getMSTime();
4825
4827
4828 m_targets.Write(castData.Target);
4829
4830 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4831 {
4832 for (SpellPowerCost const& cost : m_powerCost)
4833 {
4835 powerData.Type = cost.Power;
4836 powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
4837 castData.RemainingPower.push_back(powerData);
4838 }
4839 }
4840
4841 if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
4842 {
4843 castData.RemainingRunes.emplace();
4844
4845 Player* player = ASSERT_NOTNULL(m_caster->ToPlayer());
4846 castData.RemainingRunes->Start = m_runesState; // runes state before
4847 castData.RemainingRunes->Count = player->GetRunesState(); // runes state after
4848 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4849 {
4850 // float casts ensure the division is performed on floats as we need float result
4851 float baseCd = float(player->GetRuneBaseCooldown());
4852 castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
4853 }
4854 }
4855
4856 if (castFlags & CAST_FLAG_ADJUST_MISSILE)
4857 {
4860 }
4861
4862 packet.LogData.Initialize(this);
4863
4865}
4866
4869{
4870 // This function also fill data for channeled spells:
4871 // m_needAliveTargetMask req for stop channeling if one target die
4872 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
4873 {
4874 if (targetInfo.EffectMask == 0) // No effect apply - all immune add state
4875 // possibly SPELL_MISS_IMMUNE2 for this??
4876 targetInfo.MissCondition = SPELL_MISS_IMMUNE2;
4877
4878 if (targetInfo.MissCondition == SPELL_MISS_NONE || (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))) // Add only hits and partial blocked
4879 {
4880 data.HitTargets.push_back(targetInfo.TargetGUID);
4881 data.HitStatus.emplace_back(SPELL_MISS_NONE);
4882
4883 m_channelTargetEffectMask |= targetInfo.EffectMask;
4884 }
4885 else // misses
4886 {
4887 data.MissTargets.push_back(targetInfo.TargetGUID);
4888 data.MissStatus.emplace_back(targetInfo.MissCondition, targetInfo.ReflectResult);
4889 }
4890 }
4891
4892 for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo)
4893 data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
4894
4895 for (CorpseTargetInfo const& targetInfo : m_UniqueCorpseTargetInfo)
4896 data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
4897
4898 // Reset m_needAliveTargetMask for non channeled spell
4899 if (!m_spellInfo->IsChanneled())
4901}
4902
4904{
4905 uint32 ammoInventoryType = 0;
4906 uint32 ammoDisplayID = 0;
4907
4908 if (Player const* playerCaster = m_caster->ToPlayer())
4909 {
4910 Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK);
4911 if (pItem)
4912 {
4913 ammoInventoryType = pItem->GetTemplate()->GetInventoryType();
4914 if (ammoInventoryType == INVTYPE_THROWN)
4915 ammoDisplayID = pItem->GetDisplayId(playerCaster);
4916 else if (playerCaster->HasAura(46699)) // Requires No Ammo
4917 {
4918 ammoDisplayID = 5996; // normal arrow
4919 ammoInventoryType = INVTYPE_AMMO;
4920 }
4921 }
4922 }
4923 else if (Unit const* unitCaster = m_caster->ToUnit())
4924 {
4925 uint32 nonRangedAmmoDisplayID = 0;
4926 uint32 nonRangedAmmoInventoryType = 0;
4927 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
4928 {
4929 if (uint32 item_id = unitCaster->GetVirtualItemId(i))
4930 {
4931 if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
4932 {
4933 if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
4934 {
4935 switch (itemEntry->SubclassID)
4936 {
4938 if (ItemModifiedAppearanceEntry const* modifiedAppearance = TransmogMgr::GetItemModifiedAppearance(item_id, unitCaster->GetVirtualItemAppearanceMod(i)))
4939 if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(modifiedAppearance->ItemAppearanceID))
4940 ammoDisplayID = itemAppearance->ItemDisplayInfoID;
4941
4942 ammoInventoryType = itemEntry->InventoryType;
4943 break;
4946 ammoDisplayID = 5996; // is this need fixing?
4947 ammoInventoryType = INVTYPE_AMMO;
4948 break;
4950 ammoDisplayID = 5998; // is this need fixing?
4951 ammoInventoryType = INVTYPE_AMMO;
4952 break;
4953 default:
4954 if (ItemModifiedAppearanceEntry const* modifiedAppearance = TransmogMgr::GetItemModifiedAppearance(item_id, unitCaster->GetVirtualItemAppearanceMod(i)))
4955 if (ItemAppearanceEntry const* itemAppearance = sItemAppearanceStore.LookupEntry(modifiedAppearance->ItemAppearanceID))
4956 nonRangedAmmoDisplayID = itemAppearance->ItemDisplayInfoID;
4957
4958 nonRangedAmmoInventoryType = itemEntry->InventoryType;
4959 break;
4960 }
4961
4962 if (ammoDisplayID)
4963 break;
4964 }
4965 }
4966 }
4967 }
4968
4969 if (!ammoDisplayID && !ammoInventoryType)
4970 {
4971 ammoDisplayID = nonRangedAmmoDisplayID;
4972 ammoInventoryType = nonRangedAmmoInventoryType;
4973 }
4974 }
4975
4976 return ammoDisplayID;
4977}
4978
4979static std::pair<SpellEffectValue, SpellHealPredictionType> CalcPredictedHealing(SpellInfo const* spellInfo, Unit const* unitCaster, Unit* target, uint32 castItemEntry, int32 castItemLevel, Spell* spell, bool withPeriodic)
4980{
4981 SpellEffectValue points = 0;
4983 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4984 {
4985 switch (spellEffectInfo.Effect)
4986 {
4987 case SPELL_EFFECT_HEAL:
4989 points += unitCaster->SpellHealingBonusDone(target,
4990 spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
4991 DIRECT_DAMAGE, spellEffectInfo, 1, spell);
4992
4993 if (target != unitCaster && (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER || spellEffectInfo.TargetB.GetTarget() == TARGET_UNIT_CASTER))
4994 type = SPELL_HEAL_PREDICTION_TARGET_AND_CASTER; // Binding Heal-like spells
4995 else if (spellEffectInfo.TargetA.GetCheckType() == TARGET_CHECK_PARTY || spellEffectInfo.TargetB.GetCheckType() == TARGET_CHECK_PARTY)
4996 type = SPELL_HEAL_PREDICTION_TARGET_PARTY; // Prayer of Healing (old party-wide targeting)
4997 break;
4998 default:
4999 break;
5000 }
5001
5002 if (withPeriodic)
5003 {
5004 switch (spellEffectInfo.ApplyAuraName)
5005 {
5008 points += unitCaster->SpellHealingBonusDone(target,
5009 spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
5010 DIRECT_DAMAGE, spellEffectInfo, 1, spell) * spellEffectInfo.GetPeriodicTickCount();
5011 break;
5013 if (SpellInfo const* triggered = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, spellInfo->Difficulty))
5014 points += CalcPredictedHealing(triggered, unitCaster, target, castItemEntry, castItemLevel, nullptr, withPeriodic).first;
5015 break;
5016 default:
5017 break;
5018 }
5019 }
5020 }
5021
5022 return { points, type };
5023}
5024
5026{
5027 healPrediction.BeaconGUID = ObjectGuid::Empty;
5028 healPrediction.Points = 0;
5029 healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET;
5030
5031 Unit const* unitCaster = m_caster->ToUnit();
5032
5033 if (Unit* target = m_targets.GetUnitTarget())
5034 {
5035 auto [points, type] = CalcPredictedHealing(m_spellInfo, unitCaster, target, m_castItemEntry, m_castItemLevel, this, withPeriodic);
5036 healPrediction.Points = static_cast<uint32>(points);
5037 healPrediction.Type = type;
5038 }
5039
5040 static constexpr uint32 beaconSpellId = 53651;
5041
5042 if (healPrediction.Type == SPELL_HEAL_PREDICTION_TARGET && unitCaster->HasAura(beaconSpellId, unitCaster->GetGUID()))
5043 {
5044 auto beacon = std::find_if(unitCaster->GetSingleCastAuras().begin(), unitCaster->GetSingleCastAuras().end(), [](Aura const* aura)
5045 {
5046 return aura->GetSpellInfo()->GetEffects().size() > EFFECT_1 && aura->GetSpellInfo()->GetEffect(EFFECT_1).TriggerSpell == beaconSpellId;
5047 });
5048
5049 if (beacon != unitCaster->GetSingleCastAuras().end())
5050 {
5051 healPrediction.BeaconGUID = (*beacon)->GetOwner()->GetGUID();
5053 }
5054 }
5055}
5056
5058{
5059 if (_executeLogEffects.empty())
5060 return;
5061
5063 spellExecuteLog.Caster = m_caster->GetGUID();
5064 spellExecuteLog.SpellID = m_spellInfo->Id;
5065 spellExecuteLog.Effects = &_executeLogEffects;
5066 spellExecuteLog.LogData.Initialize(this);
5067
5068 m_caster->SendCombatLogMessage(&spellExecuteLog);
5069
5070 _executeLogEffects.clear();
5071}
5072
5074{
5075 auto itr = std::find_if(_executeLogEffects.begin(), _executeLogEffects.end(), [effect](SpellLogEffect& log)
5076 {
5077 return log.Effect == effect;
5078 });
5079 if (itr != _executeLogEffects.end())
5080 return *itr;
5081
5082 _executeLogEffects.emplace_back();
5083 _executeLogEffects.back().Effect = effect;
5084 return _executeLogEffects.back();
5085}
5086
5087void Spell::ExecuteLogEffectTakeTargetPower(SpellEffects effect, Unit* target, Powers powerType, uint32 points, float amplitude)
5088{
5089 SpellLogEffectPowerDrainParams spellLogEffectPowerDrainParams;
5090
5091 spellLogEffectPowerDrainParams.Victim = target->GetGUID();
5092 spellLogEffectPowerDrainParams.Points = points;
5093 spellLogEffectPowerDrainParams.PowerType = powerType;
5094 spellLogEffectPowerDrainParams.Amplitude = amplitude;
5095
5096 GetExecuteLogEffectTargets(effect, &SpellLogEffect::PowerDrainTargets).push_back(spellLogEffectPowerDrainParams);
5097}
5098
5100{
5101 SpellLogEffectExtraAttacksParams spellLogEffectExtraAttacksParams;
5102 spellLogEffectExtraAttacksParams.Victim = victim->GetGUID();
5103 spellLogEffectExtraAttacksParams.NumAttacks = numAttacks;
5104
5105 GetExecuteLogEffectTargets(effect, &SpellLogEffect::ExtraAttacksTargets).push_back(spellLogEffectExtraAttacksParams);
5106}
5107
5109{
5111 data.Caster = m_caster->GetGUID();
5112 data.Victim = victim->GetGUID();
5114 data.SpellID = spellId;
5115
5116 m_caster->SendMessageToSet(data.Write(), true);
5117}
5118
5120{
5121 SpellLogEffectDurabilityDamageParams spellLogEffectDurabilityDamageParams;
5122 spellLogEffectDurabilityDamageParams.Victim = victim->GetGUID();
5123 spellLogEffectDurabilityDamageParams.ItemID = itemId;
5124 spellLogEffectDurabilityDamageParams.Amount = amount;
5125
5126 GetExecuteLogEffectTargets(effect, &SpellLogEffect::DurabilityDamageTargets).push_back(spellLogEffectDurabilityDamageParams);
5127}
5128
5130{
5131 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5132 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5133
5134 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5135}
5136
5138{
5139 SpellLogEffectTradeSkillItemParams spellLogEffectTradeSkillItemParams;
5140 spellLogEffectTradeSkillItemParams.ItemID = entry;
5141
5142 GetExecuteLogEffectTargets(effect, &SpellLogEffect::TradeSkillTargets).push_back(spellLogEffectTradeSkillItemParams);
5143}
5144
5146{
5147 SpellLogEffectFeedPetParams spellLogEffectFeedPetParams;
5148 spellLogEffectFeedPetParams.ItemID = entry;
5149
5150 GetExecuteLogEffectTargets(effect, &SpellLogEffect::FeedPetTargets).push_back(spellLogEffectFeedPetParams);
5151}
5152
5154{
5155 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5156 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5157
5158 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5159}
5160
5162{
5163 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5164 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5165
5166 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5167}
5168
5170{
5171 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5172 spellLogEffectGenericVictimParams.Victim = target->GetGUID();
5173
5174 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5175}
5176
5177void Spell::SendInterrupted(SpellCastResult result, Optional<SpellCastResult> resultOther /*= {}*/, ObjectGuid const& failedBy /*= ObjectGuid::Empty*/)
5178{
5180 failurePacket.CasterUnit = m_caster->GetGUID();
5181 failurePacket.CastID = m_castId;
5182 failurePacket.SpellID = m_spellInfo->Id;
5183 failurePacket.Visual = m_SpellVisual;
5184 failurePacket.Reason = result;
5185 failurePacket.FailedBy = failedBy;
5186 m_caster->SendMessageToSet(failurePacket.Write(), true);
5187
5189 failedPacket.CasterUnit = m_caster->GetGUID();
5190 failedPacket.CastID = m_castId;
5191 failedPacket.SpellID = m_spellInfo->Id;
5192 failedPacket.Visual = m_SpellVisual;
5193 failedPacket.Reason = resultOther.value_or(result);
5194 failedPacket.FailedBy = failedBy;
5195 m_caster->SendMessageToSet(failedPacket.Write(), true);
5196}
5197
5198void Spell::SendChannelUpdate(uint32 time, Optional<SpellCastResult> result, ObjectGuid const& failedBy /*= ObjectGuid::Empty*/)
5199{
5200 // GameObjects don't channel
5201 Unit* unitCaster = m_caster->ToUnit();
5202 if (!unitCaster)
5203 return;
5204
5205 if (time == 0)
5206 {
5207 unitCaster->ClearChannelObjects();
5208 unitCaster->SetChannelSpellId(0);
5209 unitCaster->SetChannelVisual({});
5210 unitCaster->SetChannelSpellData(0, 0);
5211 unitCaster->SetSpellEmpowerStage(-1);
5212 }
5213
5214 if (IsEmpowerSpell())
5215 {
5217 spellEmpowerUpdate.CastID = m_castId;
5218 spellEmpowerUpdate.CasterGUID = unitCaster->GetGUID();
5219 spellEmpowerUpdate.TimeRemaining = Milliseconds(time);
5220 spellEmpowerUpdate.FailedBy = failedBy;
5221 if (time > 0)
5222 spellEmpowerUpdate.StageDurations.assign(m_empower->StageDurations.begin(), m_empower->StageDurations.end());
5223 else if (result && result != SPELL_CAST_OK)
5224 spellEmpowerUpdate.Status = 1;
5225 else
5226 spellEmpowerUpdate.Status = 4;
5227
5228 unitCaster->SendMessageToSet(spellEmpowerUpdate.Write(), true);
5229 }
5230 else
5231 {
5233 spellChannelUpdate.CasterGUID = unitCaster->GetGUID();
5234 spellChannelUpdate.TimeRemaining = time;
5235 spellChannelUpdate.FailedBy = failedBy;
5236 unitCaster->SendMessageToSet(spellChannelUpdate.Write(), true);
5237 }
5238}
5239
5241{
5242 // GameObjects don't channel
5243 Unit* unitCaster = m_caster->ToUnit();
5244 if (!unitCaster)
5245 return;
5246
5247 m_timer = duration;
5248
5249 if (!m_UniqueTargetInfo.empty() || !m_UniqueGOTargetInfo.empty())
5250 {
5251 uint32 channelAuraMask = 0;
5252 uint32 explicitTargetEffectMask = 0xFFFFFFFF;
5253 // if there is an explicit target, only add channel objects from effects that also hit it
5255 {
5256 auto explicitTargetItr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo const& target)
5257 {
5258 return target.TargetGUID == m_targets.GetUnitTargetGUID();
5259 });
5260 if (explicitTargetItr != m_UniqueTargetInfo.end())
5261 explicitTargetEffectMask = explicitTargetItr->EffectMask;
5262 }
5263
5264 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5265 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && (explicitTargetEffectMask & (1u << spellEffectInfo.EffectIndex)))
5266 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
5267
5268 for (TargetInfo const& target : m_UniqueTargetInfo)
5269 {
5270 if (!(target.EffectMask & channelAuraMask))
5271 continue;
5272
5273 SpellAttr1 requiredAttribute = target.TargetGUID != unitCaster->GetGUID() ? SPELL_ATTR1_IS_CHANNELLED : SPELL_ATTR1_IS_SELF_CHANNELLED;
5274 if (!m_spellInfo->HasAttribute(requiredAttribute))
5275 continue;
5276
5277 unitCaster->AddChannelObject(target.TargetGUID);
5278 }
5279
5280 for (GOTargetInfo const& target : m_UniqueGOTargetInfo)
5281 if (target.EffectMask & channelAuraMask)
5282 unitCaster->AddChannelObject(target.TargetGUID);
5283 }
5285 unitCaster->AddChannelObject(unitCaster->GetGUID());
5286
5287 if (Creature* creatureCaster = unitCaster->ToCreature())
5288 if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
5289 if (!creatureCaster->HasSpellFocus(this))
5290 creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, unitCaster->m_unitData->ChannelObjects[0]));
5291
5292 unitCaster->SetChannelSpellId(m_spellInfo->Id);
5293 unitCaster->SetChannelVisual(m_SpellVisual);
5294 unitCaster->SetChannelSpellData(GameTime::GetGameTimeMS(), duration);
5295
5296 auto setImmunitiesAndHealPrediction = [&](Optional<WorldPackets::Spells::SpellChannelStartInterruptImmunities>& interruptImmunities, Optional<WorldPackets::Spells::SpellTargetedHealPrediction>& healPrediction)
5297 {
5298 uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
5299 uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
5300
5301 if (schoolImmunityMask || mechanicImmunityMask)
5302 {
5303 interruptImmunities.emplace();
5304 interruptImmunities->SchoolImmunities = schoolImmunityMask;
5305 interruptImmunities->Immunities = mechanicImmunityMask;
5306 }
5307
5309 {
5310 healPrediction.emplace();
5311 if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
5312 healPrediction->TargetGUID = unitCaster->m_unitData->ChannelObjects[0];
5313
5314 UpdateSpellHealPrediction(healPrediction->Predict, true);
5315 }
5316 };
5317
5318 if (IsEmpowerSpell())
5319 {
5320 unitCaster->SetSpellEmpowerStage(0);
5321
5323 spellEmpowerStart.CastID = m_castId;
5324 spellEmpowerStart.CasterGUID = unitCaster->GetGUID();
5325 spellEmpowerStart.SpellID = m_spellInfo->Id;
5326 spellEmpowerStart.Visual = m_SpellVisual;
5327 spellEmpowerStart.EmpowerDuration = std::reduce(m_empower->StageDurations.begin(), m_empower->StageDurations.end());
5328 spellEmpowerStart.MinHoldTime = m_empower->MinHoldTime;
5330 spellEmpowerStart.Targets.assign(unitCaster->m_unitData->ChannelObjects.begin(), unitCaster->m_unitData->ChannelObjects.end());
5331 spellEmpowerStart.StageDurations.assign(m_empower->StageDurations.begin(), m_empower->StageDurations.end());
5332 setImmunitiesAndHealPrediction(spellEmpowerStart.InterruptImmunities, spellEmpowerStart.HealPrediction);
5333
5334 unitCaster->SendMessageToSet(spellEmpowerStart.Write(), true);
5335 }
5336 else
5337 {
5339 spellChannelStart.CasterGUID = unitCaster->GetGUID();
5340 spellChannelStart.SpellID = m_spellInfo->Id;
5341 spellChannelStart.Visual = m_SpellVisual;
5342 spellChannelStart.ChannelDuration = duration;
5343 setImmunitiesAndHealPrediction(spellChannelStart.InterruptImmunities, spellChannelStart.HealPrediction);
5344
5345 unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
5346 }
5347}
5348
5350{
5351 // get resurrector name for creature resurrections, otherwise packet will be not accepted
5352 // for player resurrections the name is looked up by guid
5353 std::string sentName;
5356
5358 resurrectRequest.ResurrectOffererGUID = m_caster->GetGUID();
5359 if (Player const* playerCaster = m_caster->ToPlayer())
5360 resurrectRequest.ResurrectOffererVirtualRealmAddress = playerCaster->m_playerData->VirtualPlayerRealm;
5361 else
5363
5364 resurrectRequest.Name = sentName;
5365 resurrectRequest.Sickness = m_caster->IsUnit() && m_caster->ToUnit()->IsSpiritHealer(); // "you'll be afflicted with resurrection sickness"
5367 if (Pet* pet = target->GetPet())
5368 if (CharmInfo* charmInfo = pet->GetCharmInfo())
5369 resurrectRequest.PetNumber = charmInfo->GetPetNumber();
5370
5371 resurrectRequest.SpellID = m_spellInfo->Id;
5372 target->SendDirectMessage(resurrectRequest.Write());
5373}
5374
5376{
5377 if (!m_CastItem)
5378 return;
5379
5380 Player* player = m_caster->ToPlayer();
5381 if (!player)
5382 return;
5383
5384 // not remove cast item at triggered spell (equipping, weapon damage, etc)
5386 return;
5387
5388 ItemTemplate const* proto = m_CastItem->GetTemplate();
5389
5390 if (!proto)
5391 {
5392 // This code is to avoid a crash
5393 // I'm not sure, if this is really an error, but I guess every item needs a prototype
5394 TC_LOG_ERROR("spells", "Cast item has no item prototype {}", m_CastItem->GetGUID().ToString());
5395 return;
5396 }
5397
5398 bool expendable = false;
5399 bool withoutCharges = false;
5400
5401 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
5402 {
5403 // item has limited charges
5404 if (itemEffect->TriggerType == ITEM_SPELLTRIGGER_ON_USE && itemEffect->Charges)
5405 {
5406 if (itemEffect->Charges < 0)
5407 expendable = true;
5408
5409 int32 charges = m_CastItem->GetSpellCharges(itemEffect);
5410
5411 // item has charges left for this slot
5412 if (charges && itemEffect->SpellID == int32(m_spellInfo->Id))
5413 {
5414 if (charges > 0)
5415 --charges;
5416 else
5417 ++charges;
5418
5419 if (proto->GetMaxStackSize() == 1)
5420 m_CastItem->SetSpellCharges(itemEffect, charges);
5422 }
5423
5424 // all charges used
5425 withoutCharges = (charges == 0);
5426 }
5427 }
5428
5429 if (expendable && withoutCharges)
5430 {
5431 uint32 count = 1;
5432 m_caster->ToPlayer()->DestroyItemCount(m_CastItem, count, true);
5433
5434 // prevent crash at access to deleted m_targets.GetItemTarget
5436 m_targets.SetItemTarget(nullptr);
5437
5438 m_CastItem = nullptr;
5440 m_castItemEntry = 0;
5441 }
5442}
5443
5445{
5446 // GameObjects don't use power
5447 Unit* unitCaster = m_caster->ToUnit();
5448 if (!unitCaster)
5449 return;
5450
5452 return;
5453
5454 //Don't take power if the spell is cast while .cheat power is enabled.
5455 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5456 {
5457 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
5458 return;
5459 }
5460
5461 bool hit = true;
5462 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5463 {
5465 {
5466 ObjectGuid targetGUID = m_targets.GetUnitTargetGUID();
5467 if (!targetGUID.IsEmpty())
5468 hit = std::ranges::any_of(m_UniqueTargetInfo, [&](TargetInfo const& targetInfo) { return targetInfo.TargetGUID == targetGUID && targetInfo.MissCondition == SPELL_MISS_NONE; });
5469 }
5470 }
5471
5472 for (SpellPowerCost& cost : m_powerCost)
5473 {
5474 if (!hit)
5475 {
5476 // skipping granting power through negative cost only when spell has SPELL_ATTR1_DISCOUNT_POWER_ON_MISS is correct behavior
5477 // tested with 206931 - Blooddrinker
5478 if (cost.Amount < 0)
5479 continue;
5480
5481 //lower spell cost on fail (by talent aura)
5482 if (Player* modOwner = unitCaster->GetSpellModOwner())
5483 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCostOnMiss, cost.Amount);
5484 }
5485
5486 if (cost.Power == POWER_RUNES)
5487 {
5488 TakeRunePower(hit);
5489 continue;
5490 }
5491
5492 if (!cost.Amount)
5493 continue;
5494
5495 // health as power used
5496 if (cost.Power == POWER_HEALTH)
5497 {
5498 unitCaster->ModifyHealth(-cost.Amount);
5499 continue;
5500 }
5501
5502 unitCaster->ModifyPower(cost.Power, -cost.Amount);
5503 }
5504}
5505
5507{
5508 // GameObjects don't use power
5509 Unit* unitCaster = m_caster->ToUnit();
5510 if (!unitCaster)
5511 return;
5512
5514 return;
5515
5516 //Don't take power if the spell is cast while .cheat power is enabled.
5517 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5518 {
5519 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
5520 return;
5521 }
5522
5523 for (SpellPowerCost& cost : m_powerCost)
5524 {
5525 if (cost.Power == POWER_RUNES)
5526 {
5528 continue;
5529 }
5530
5531 if (!cost.Amount)
5532 continue;
5533
5534 // health as power used
5535 if (cost.Power == POWER_HEALTH)
5536 {
5537 unitCaster->ModifyHealth(cost.Amount);
5538 continue;
5539 }
5540
5541 unitCaster->ModifyPower(cost.Power, cost.Amount);
5542 }
5543}
5544
5546{
5547 int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
5548 {
5549 return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0);
5550 });
5551
5552 if (!runeCost)
5553 return SPELL_CAST_OK;
5554
5555 Player* player = m_caster->ToPlayer();
5556 if (!player)
5557 return SPELL_CAST_OK;
5558
5559 if (player->GetClass() != CLASS_DEATH_KNIGHT)
5560 return SPELL_CAST_OK;
5561
5562 int32 readyRunes = 0;
5563 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5564 if (player->GetRuneCooldown(i) == 0)
5565 ++readyRunes;
5566
5567 if (readyRunes < runeCost)
5568 return SPELL_FAILED_NO_POWER; // not sure if result code is correct
5569
5570 return SPELL_CAST_OK;
5571}
5572
5573void Spell::TakeRunePower(bool didHit)
5574{
5576 return;
5577
5578 Player* player = m_caster->ToPlayer();
5579 m_runesState = player->GetRunesState(); // store previous state
5580
5581 if (!didHit)
5582 return;
5583
5584 int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
5585 {
5586 return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0);
5587 });
5588
5589 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5590 {
5591 if (!player->GetRuneCooldown(i) && runeCost > 0)
5592 {
5593 player->SetRuneCooldown(i, player->GetRuneBaseCooldown());
5594 --runeCost;
5595 }
5596 }
5597}
5598
5600{
5602 return;
5603
5604 Player* player = m_caster->ToPlayer();
5605
5606 // restore old rune state
5607 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5608 if (m_runesState & (1 << i))
5609 player->SetRuneCooldown(i, 0);
5610}
5611
5613{
5615 return;
5616
5617 // do not take reagents for these item casts
5619 return;
5620
5621 Player* p_caster = m_caster->ToPlayer();
5622 if (p_caster->CanNoReagentCast(m_spellInfo))
5623 return;
5624
5625 for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
5626 {
5627 if (m_spellInfo->Reagent[x] <= 0)
5628 continue;
5629
5630 uint32 itemid = m_spellInfo->Reagent[x];
5631 uint32 itemcount = m_spellInfo->ReagentCount[x];
5632
5633 // if CastItem is also spell reagent
5634 if (m_CastItem && m_CastItem->GetEntry() == itemid)
5635 {
5636 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
5637 {
5638 // CastItem will be used up and does not count as reagent
5639 int32 charges = m_CastItem->GetSpellCharges(itemEffect);
5640 if (itemEffect->Charges < 0 && abs(charges) < 2)
5641 {
5642 ++itemcount;
5643 break;
5644 }
5645 }
5646
5647 m_CastItem = nullptr;
5649 m_castItemEntry = 0;
5650 }
5651
5652 // if GetItemTarget is also spell reagent
5653 if (m_targets.GetItemTargetEntry() == itemid)
5654 m_targets.SetItemTarget(nullptr);
5655
5656 p_caster->DestroyItemCount(itemid, itemcount, true);
5657 }
5658
5659 for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency)
5660 p_caster->RemoveCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount, CurrencyDestroyReason::Spell);
5661}
5662
5664{
5665 // wild GameObject spells don't cause threat
5666 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
5667 if (!unitCaster)
5668 return;
5669
5670 if (m_UniqueTargetInfo.empty())
5671 return;
5672
5674 return;
5675
5676 float threat = 0.0f;
5677 if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
5678 {
5679 if (threatEntry->apPctMod != 0.0f)
5680 threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
5681
5682 threat += threatEntry->flatMod;
5683 }
5685 threat += m_spellInfo->SpellLevel;
5686
5687 // past this point only multiplicative effects occur
5688 if (threat == 0.0f)
5689 return;
5690
5691 // since 2.0.1 threat from positive effects also is distributed among all targets, so the overall caused threat is at most the defined bonus
5692 threat /= m_UniqueTargetInfo.size();
5693
5694 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
5695 {
5696 float threatToAdd = threat;
5697 if (ihit->MissCondition != SPELL_MISS_NONE)
5698 threatToAdd = 0.0f;
5699
5700 Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit->TargetGUID);
5701 if (!target)
5702 continue;
5703
5704 // positive spells distribute threat among all units that are in combat with target, like healing
5705 if (IsPositive())
5706 target->GetThreatManager().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
5707 // for negative spells threat gets distributed among affected targets
5708 else
5709 {
5710 if (!target->CanHaveThreatList())
5711 continue;
5712
5713 target->GetThreatManager().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
5714 }
5715 }
5716 TC_LOG_DEBUG("spells", "Spell {}, added an additional {} threat for {} {} target(s)", m_spellInfo->Id, threat, IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
5717}
5718
5719void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
5720{
5721 effectHandleMode = mode;
5722 unitTarget = pUnitTarget;
5723 itemTarget = pItemTarget;
5724 gameObjTarget = pGoTarget;
5725 m_corpseTarget = pCorpseTarget;
5726 destTarget = &m_destTargets[spellEffectInfo.EffectIndex]._position;
5727 effectInfo = &spellEffectInfo;
5728
5729 effectValue = CalculateDamage(spellEffectInfo, unitTarget, &variance);
5730
5731 bool preventDefault = CallScriptEffectHandlers(spellEffectInfo.EffectIndex, mode);
5732
5733 if (!preventDefault)
5734 (this->*SpellEffectHandlers[spellEffectInfo.Effect].Value)();
5735}
5736
5738{
5739 if (SpellEvent* spellEvent = dynamic_cast<SpellEvent*>(event))
5740 return spellEvent->GetSpell();
5741
5742 return nullptr;
5743}
5744
5745SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/)
5746{
5747 // check death state
5750
5751 // Prevent cheating in case the player has an immunity effect and tries to interact with a non-allowed gameobject. The error message is handled by the client so we don't report anything here
5753 {
5756 }
5757
5758 // check cooldowns to prevent cheating
5759 if (!m_spellInfo->IsPassive())
5760 {
5761 if (Player const* playerCaster = m_caster->ToPlayer())
5762 {
5763 //can cast triggered (by aura only?) spells while have this flag
5765 {
5766 // These two auras check SpellFamilyName defined by db2 class data instead of current spell SpellFamilyName
5767 if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES)
5771 && !playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->GetClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
5773
5774 if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES))
5775 {
5776 if (!playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->GetClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
5777 {
5788 }
5789 }
5790 }
5791 }
5792
5794 {
5796 {
5799
5801 }
5802
5805 }
5806 }
5807
5809 {
5812 }
5813
5816
5817 // Check global cooldown
5820
5821 // only triggered spells can be processed an ended battleground
5824 if (bg->GetStatus() == STATUS_WAIT_LEAVE)
5826
5828 {
5830 !m_caster->IsOutdoors())
5832
5836 }
5837
5838 if (Unit* unitCaster = m_caster->ToUnit())
5839 {
5840 if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED) && unitCaster->IsCharmed())
5841 return SPELL_FAILED_CHARMED;
5842
5843 // only check at first call, Stealth auras are already removed at second call
5844 // for now, ignore triggered spells
5846 {
5847 bool checkForm = true;
5848 // Ignore form req aura
5849 Unit::AuraEffectList const& ignore = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
5850 for (AuraEffect const* aurEff : ignore)
5851 {
5852 if (!aurEff->IsAffectingSpell(m_spellInfo))
5853 continue;
5854
5855 checkForm = false;
5856 break;
5857 }
5858
5859 if (checkForm)
5860 {
5861 // Cannot be used in this stance/form
5862 SpellCastResult shapeError = m_spellInfo->CheckShapeshift(unitCaster->GetShapeshiftForm());
5863 if (shapeError != SPELL_CAST_OK)
5864 return shapeError;
5865
5866 if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(unitCaster->HasStealthAura()))
5868 }
5869 }
5870
5871 // caster state requirements
5872 // not for triggered spells (needed by execute)
5874 {
5875 if (m_spellInfo->CasterAuraState && !unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, unitCaster))
5877 if (m_spellInfo->ExcludeCasterAuraState && unitCaster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, unitCaster))
5879
5880 // Note: spell 62473 requres casterAuraSpell = triggering spell
5881 if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(m_spellInfo->CasterAuraSpell))
5885
5886 if (m_spellInfo->CasterAuraType && !unitCaster->HasAuraType(m_spellInfo->CasterAuraType))
5888 if (m_spellInfo->ExcludeCasterAuraType && unitCaster->HasAuraType(m_spellInfo->ExcludeCasterAuraType))
5890
5891 if (unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat(unitCaster))
5893
5895 {
5896 bool hasInvalidMountAura = std::ranges::any_of(unitCaster->GetAuraEffectsByType(SPELL_AURA_MOUNTED), [unitCaster](AuraEffect const* mountEffect)
5897 {
5898 uint32 mountType = mountEffect->GetSpellEffectInfo().MiscValueB;
5899 if (MountEntry const* mountEntry = sDB2Manager.GetMount(mountEffect->GetId()))
5900 mountType = mountEntry->MountTypeID;
5901
5902 MountCapabilityEntry const* mountCapability = unitCaster->GetMountCapability(mountType);
5903 return !mountCapability || mountCapability->ID != uint32(mountEffect->GetAmount());
5904 });
5905
5906 if (!hasInvalidMountAura)
5908 }
5909 }
5910
5911 // Check vehicle flags
5913 {
5914 SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(unitCaster);
5915 if (vehicleCheck != SPELL_CAST_OK)
5916 return vehicleCheck;
5917 }
5918 }
5919
5920 // check spell cast conditions from database
5921 {
5923 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL, m_spellInfo->Id, condInfo))
5924 {
5925 // mLastFailedCondition can be NULL if there was an error processing the condition in Condition::Meets (i.e. wrong data for ConditionTarget or others)
5926 if (condInfo.mLastFailedCondition && condInfo.mLastFailedCondition->ErrorType)
5927 {
5931 }
5932
5933 if (!condInfo.mLastFailedCondition || !condInfo.mLastFailedCondition->ConditionTarget)
5936 }
5937 }
5938
5939 // Don't check explicit target for passive spells (workaround) (check should be skipped only for learn case)
5940 // those spells may have incorrect target entries or not filled at all (for example 15332)
5941 // such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
5942 // also, such casts shouldn't be sent to client
5944 {
5945 // Check explicit target for m_originalCaster - todo: get rid of such workarounds
5946 WorldObject* caster = m_caster;
5947 // in case of gameobjects like traps, we need the gameobject itself to check target validity
5948 // otherwise, if originalCaster is far away and cannot detect the target, the trap would not hit the target
5949 if (m_originalCaster && !caster->ToGameObject())
5950 caster = m_originalCaster;
5951
5953 if (castResult != SPELL_CAST_OK)
5954 return castResult;
5955 }
5956
5957 if (Unit* target = m_targets.GetUnitTarget())
5958 {
5959 SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetTypeId() == TYPEID_GAMEOBJECT); // skip stealth checks for GO casts
5960 if (castResult != SPELL_CAST_OK)
5961 return castResult;
5962
5963 // If it's not a melee spell, check if vision is obscured by SPELL_AURA_INTERFERE_ENEMY_TARGETING
5964 if (m_spellInfo->DmgClass != SPELL_DAMAGE_CLASS_MELEE && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT)) // targets can be hit with spells that ignore LoS
5965 {
5966 if (Unit const* unitCaster = m_caster->ToUnit())
5967 {
5968 for (AuraEffect const* auraEff : unitCaster->GetAuraEffectsByType(SPELL_AURA_INTERFERE_ENEMY_TARGETING))
5969 if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && !target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
5971
5972 for (AuraEffect const* auraEff : target->GetAuraEffectsByType(SPELL_AURA_INTERFERE_ENEMY_TARGETING))
5973 if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && !unitCaster->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
5975
5976 for (AuraEffect const* auraEff : unitCaster->GetAuraEffectsByType(SPELL_AURA_INTERFERE_ALL_TARGETING))
5977 if (!target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
5979
5980 for (AuraEffect const* auraEff : target->GetAuraEffectsByType(SPELL_AURA_INTERFERE_ALL_TARGETING))
5981 if (!unitCaster->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
5983 }
5984 }
5985
5986 if (target != m_caster)
5987 {
5988 // Must be behind the target
5989 if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)) && target->HasInArc(static_cast<float>(M_PI), m_caster))
5991
5992 // Target must be facing you
5993 if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER)) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
5995
5996 // Ignore LOS for gameobjects casts
5998 {
5999 WorldObject* losTarget = m_caster;
6002 losTarget = dynObj;
6003
6004 if (!IsWithinLOS(losTarget, target, true, VMAP::ModelIgnoreFlags::M2))
6006 }
6007 }
6008 }
6009
6010 // Check for line of sight for spells with dest
6011 if (m_targets.HasDst())
6014
6015 // check pet presence
6016 if (Unit* unitCaster = m_caster->ToUnit())
6017 {
6019 if (!unitCaster->GetPetGUID().IsEmpty())
6021
6022 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6023 {
6024 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
6025 {
6026 if (!unitCaster->GetGuardianPet())
6027 {
6028 if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
6030 else
6031 return SPELL_FAILED_NO_PET;
6032 }
6033 break;
6034 }
6035 }
6036 }
6037
6038 // Spell cast only in battleground
6040 if (!m_caster->GetMap()->IsBattleground())
6042
6043 // do not allow spells to be cast in arenas or rated battlegrounds
6044 if (Player* player = m_caster->ToPlayer())
6045 if (player->InArena()/* || player->InRatedBattleGround() NYI*/)
6046 {
6048 if (castResult != SPELL_CAST_OK)
6049 return castResult;
6050 }
6051
6052 // zone check
6054 {
6055 uint32 zone, area;
6056 m_caster->GetZoneAndAreaId(zone, area);
6057
6059 if (locRes != SPELL_CAST_OK)
6060 return locRes;
6061 }
6062
6063 // not let players cast spells at mount (and let do it to creatures)
6065 {
6067 {
6068 if (m_caster->ToPlayer()->IsInFlight())
6070 else
6072 }
6073 }
6074
6075 // check spell focus object
6077 {
6079 {
6081 if (focusObject)
6083 else
6085 }
6086 }
6087
6088 SpellCastResult castResult = SPELL_CAST_OK;
6089
6090 // always (except passive spells) check items (only player related checks)
6091 if (!m_spellInfo->IsPassive())
6092 {
6093 castResult = CheckItems(param1, param2);
6094 if (castResult != SPELL_CAST_OK)
6095 return castResult;
6096 }
6097
6098 // Triggered spells also have range check
6100 castResult = CheckRange(strict);
6101 if (castResult != SPELL_CAST_OK)
6102 return castResult;
6103
6105 {
6106 castResult = CheckPower();
6107 if (castResult != SPELL_CAST_OK)
6108 return castResult;
6109 }
6110
6112 {
6113 castResult = CheckCasterAuras(param1);
6114 if (castResult != SPELL_CAST_OK)
6115 return castResult;
6116 }
6117
6118 // script hook
6119 castResult = CallScriptCheckCastHandlers();
6120 if (castResult != SPELL_CAST_OK)
6121 return castResult;
6122
6123 uint32 approximateAuraEffectMask = 0;
6124 uint32 nonAuraEffectMask = 0;
6125 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6126 {
6127 // for effects of spells that have only one target
6128 switch (spellEffectInfo.Effect)
6129 {
6130 case SPELL_EFFECT_DUMMY:
6131 {
6132 if (m_spellInfo->Id == 19938) // Awaken Peon
6133 {
6134 Unit* unit = m_targets.GetUnitTarget();
6135 if (!unit || !unit->HasAura(17743))
6137 }
6138 else if (m_spellInfo->Id == 31789) // Righteous Defense
6139 {
6142
6143 Unit* target = m_targets.GetUnitTarget();
6144 if (!target || !target->IsFriendlyTo(m_caster) || target->getAttackers().empty())
6146
6147 }
6148 break;
6149 }
6151 {
6152 if (spellEffectInfo.TargetA.GetTarget() != TARGET_UNIT_PET)
6153 break;
6154
6155 Pet* pet = m_caster->ToPlayer()->GetPet();
6156 if (!pet)
6157 return SPELL_FAILED_NO_PET;
6158
6159 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
6160 if (!learn_spellproto)
6162
6163 if (m_spellInfo->SpellLevel > pet->GetLevel())
6164 return SPELL_FAILED_LOWLEVEL;
6165
6166 break;
6167 }
6169 {
6172 if (Guild* guild = m_caster->ToPlayer()->GetGuild())
6173 if (guild->GetLeaderGUID() != m_caster->ToPlayer()->GetGUID())
6175 break;
6176 }
6178 {
6179 // check target only for unit target case
6180 if (Unit* unit = m_targets.GetUnitTarget())
6181 {
6184
6185 Pet* pet = unit->ToPet();
6186 if (!pet || pet->GetOwner() != m_caster)
6188
6189 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
6190
6191 if (!learn_spellproto)
6193
6194 if (m_spellInfo->SpellLevel > pet->GetLevel())
6195 return SPELL_FAILED_LOWLEVEL;
6196 }
6197 break;
6198 }
6200 {
6203
6204 Player* caster = m_caster->ToPlayer();
6205 if (!caster->HasSpell(m_misc.SpellId))
6207
6208 if (uint32 glyphId = spellEffectInfo.MiscValue)
6209 {
6210 GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId);
6211 if (!glyphProperties)
6213
6214 std::vector<uint32> const* glyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId);
6215 if (!glyphBindableSpells)
6217
6218 if (!advstd::ranges::contains(*glyphBindableSpells, m_misc.SpellId))
6220
6221 if (std::vector<ChrSpecialization> const* glyphRequiredSpecs = sDB2Manager.GetGlyphRequiredSpecs(glyphId))
6222 {
6225
6226 if (!advstd::ranges::contains(*glyphRequiredSpecs, caster->GetPrimarySpecialization()))
6228 }
6229
6230 uint32 replacedGlyph = 0;
6231 for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
6232 {
6233 if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(activeGlyphId))
6234 {
6235 if (advstd::ranges::contains(*activeGlyphBindableSpells, m_misc.SpellId))
6236 {
6237 replacedGlyph = activeGlyphId;
6238 break;
6239 }
6240 }
6241 }
6242
6243 for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
6244 {
6245 if (activeGlyphId == replacedGlyph)
6246 continue;
6247
6248 if (activeGlyphId == glyphId)
6250
6251 if (glyphProperties->GlyphExclusiveCategoryID && sGlyphPropertiesStore.AssertEntry(activeGlyphId)->GlyphExclusiveCategoryID == glyphProperties->GlyphExclusiveCategoryID)
6252 {
6253 if (param1)
6254 *param1 = glyphProperties->GlyphExclusiveCategoryID;
6256 }
6257 }
6258 }
6259 break;
6260 }
6262 {
6265
6266 Item* foodItem = m_targets.GetItemTarget();
6267 if (!foodItem)
6269
6270 Pet* pet = m_caster->ToPlayer()->GetPet();
6271 if (!pet)
6272 return SPELL_FAILED_NO_PET;
6273
6274 if (!pet->HaveInDiet(foodItem->GetTemplate()))
6276
6277 if (foodItem->GetTemplate()->GetBaseItemLevel() + 30 <= pet->GetLevel())
6279
6280 if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
6282
6283 break;
6284 }
6286 {
6287 Unit* unitCaster = m_caster->ToUnit();
6288 if (!unitCaster)
6290
6292 return SPELL_FAILED_ROOTED;
6293
6295 {
6296 Unit* target = m_targets.GetUnitTarget();
6297 if (!target)
6299
6300 // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
6301 if (!IsWithinLOS(unitCaster, target, true, VMAP::ModelIgnoreFlags::Nothing)) //Do full LoS/Path check. Don't exclude m2
6303
6304 float objSize = target->GetCombatReach();
6305 float range = m_spellInfo->GetMaxRange(true, unitCaster, this) * 1.5f + objSize; // can't be overly strict
6306
6307 m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
6308 m_preGeneratedPath->SetPathLengthLimit(range);
6309
6310 // first try with raycast, if it fails fall back to normal path
6311 bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
6312 if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
6313 return SPELL_FAILED_NOPATH;
6314 else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
6315 return SPELL_FAILED_NOPATH;
6316 else if (m_preGeneratedPath->IsInvalidDestinationZ(target)) // Check position z, if not in a straight line
6317 return SPELL_FAILED_NOPATH;
6318
6319 m_preGeneratedPath->ShortenPathUntilDist(PositionToVector3(target->GetPosition()), objSize); // move back
6320 }
6321 break;
6322 }
6324 {
6327
6330
6331 Creature* creature = m_targets.GetUnitTarget()->ToCreature();
6332 Loot* loot = creature->GetLootForPlayer(m_caster->ToPlayer());
6333 if (loot && (!loot->isLooted() || loot->loot_type == LOOT_SKINNING))
6335
6336 break;
6337 }
6339 {
6340 if (spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET &&
6341 spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET)
6342 break;
6343
6344 if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc.
6345 // we need a go target in case of TARGET_GAMEOBJECT_TARGET
6346 || (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget()))
6348
6349 Item* pTempItem = nullptr;
6351 {
6352 if (TradeData* pTrade = m_caster->ToPlayer()->GetTradeData())
6353 pTempItem = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
6354 }
6357
6358 // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
6359 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET &&
6361 (!pTempItem || !pTempItem->GetTemplate()->GetLockID() || !pTempItem->IsLocked()))
6363
6364 if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
6366 if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners
6369
6370 // get the lock entry
6371 uint32 lockId = 0;
6372 if (GameObject* go = m_targets.GetGOTarget())
6373 {
6374 lockId = go->GetGOInfo()->GetLockId();
6375 if (!lockId)
6377
6378 if (go->GetGOInfo()->GetNotInCombat() && m_caster->ToUnit()->IsInCombat())
6380 }
6381 else if (Item* itm = m_targets.GetItemTarget())
6382 lockId = itm->GetTemplate()->GetLockID();
6383
6384 SkillType skillId = SKILL_NONE;
6385 int32 reqSkillValue = 0;
6386 int32 skillValue = 0;
6387
6388 // check lock compatibility
6389 SpellCastResult res = CanOpenLock(spellEffectInfo, lockId, skillId, reqSkillValue, skillValue);
6390 if (res != SPELL_CAST_OK)
6391 return res;
6392 break;
6393 }
6395 {
6396 Player* playerCaster = m_caster->ToPlayer();
6397 if (!playerCaster || !playerCaster->GetPetStable())
6399
6400 if (Pet* pet = playerCaster->GetPet())
6401 {
6402 if (pet->IsAlive())
6404 }
6405 else
6406 {
6407 PetStable const* petStable = playerCaster->GetPetStable();
6408 auto deadPetItr = std::ranges::find_if(petStable->ActivePets, [](Optional<PetStable::PetInfo> const& petInfo)
6409 {
6410 return petInfo && !petInfo->Health;
6411 });
6412
6413 if (deadPetItr == petStable->ActivePets.end())
6415 }
6416
6417 break;
6418 }
6419 // This is generic summon effect
6421 {
6422 Unit* unitCaster = m_caster->ToUnit();
6423 if (!unitCaster)
6424 break;
6425
6426 SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(spellEffectInfo.MiscValueB);
6427 if (!SummonProperties)
6428 break;
6429
6430 switch (SummonProperties->Control)
6431 {
6435 [[fallthrough]]; // check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
6437 if (!unitCaster->GetCharmedGUID().IsEmpty())
6439 break;
6440 }
6441 break;
6442 }
6444 {
6446 {
6451 }
6452 break;
6453 }
6455 {
6456 Unit* unitCaster = m_caster->ToUnit();
6457 if (!unitCaster)
6459
6460 if (!unitCaster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
6461 {
6462 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
6463 {
6464 if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
6465 if (Pet* pet = unitCaster->ToPlayer()->GetPet())
6467 .SetOriginalCaster(pet->GetGUID())
6468 .SetTriggeringSpell(this));
6469 }
6472 }
6473
6474 if (!unitCaster->GetCharmedGUID().IsEmpty())
6476
6477 Player* playerCaster = unitCaster->ToPlayer();
6478 if (playerCaster && playerCaster->GetPetStable())
6479 {
6480 Optional<PetSaveMode> petSlot;
6481 if (!spellEffectInfo.MiscValue)
6482 {
6483 petSlot = PetSaveMode(spellEffectInfo.CalcValueAsInt());
6484
6485 // No pet can be summoned if any pet is dead
6486 for (Optional<PetStable::PetInfo> const& activePet : playerCaster->GetPetStable()->ActivePets)
6487 {
6488 if (activePet && !activePet->Health)
6489 {
6490 playerCaster->SendTameFailure(PetTameResult::Dead);
6492 }
6493 }
6494 }
6495
6496 std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, petSlot);
6497 if (info.first)
6498 {
6499 if (info.first->Type == HUNTER_PET)
6500 {
6501 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(info.first->CreatureId);
6502 CreatureDifficulty const* creatureDifficulty = creatureInfo->GetDifficulty(DIFFICULTY_NONE);
6503 if (!creatureInfo || !creatureInfo->IsTameable(playerCaster->CanTameExoticPets(), creatureDifficulty))
6504 {
6505 // if problem in exotic pet
6506 if (creatureInfo && creatureInfo->IsTameable(true, creatureDifficulty))
6508 else
6510
6512 }
6513 }
6514 }
6515 else if (!spellEffectInfo.MiscValue) // when miscvalue is present it is allowed to create new pets
6516 {
6519 }
6520 }
6521
6522 break;
6523 }
6525 {
6526 Player* playerCaster = m_caster->ToPlayer();
6527 if (!playerCaster)
6529
6530 Pet* pet = playerCaster->GetPet();
6531 if (!pet)
6532 return SPELL_FAILED_NO_PET;
6533
6534 if (!pet->IsAlive())
6536
6537 break;
6538 }
6540 {
6543
6544 if (!m_caster->ToPlayer()->GetTarget())
6546
6548 if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell
6550
6551 if (target->HasSummonPending())
6553
6554 // check if our map is dungeon
6555 if (InstanceMap const* map = m_caster->GetMap()->ToInstanceMap())
6556 {
6557 uint32 mapId = map->GetId();
6558 Difficulty difficulty = map->GetDifficultyID();
6559 if (InstanceLock const* mapLock = map->GetInstanceLock())
6560 if (sInstanceLockMgr.CanJoinInstanceLock(target->GetGUID(), { mapId, difficulty }, mapLock) != TRANSFER_ABORT_NONE)
6562 }
6563 break;
6564 }
6565 // RETURN HERE
6567 {
6570
6571 Player* playerCaster = m_caster->ToPlayer();
6572 if (!playerCaster->GetTarget())
6574
6575 Player* target = playerCaster->GetSelectedPlayer();
6576 if (!target ||
6577 !(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
6579 break;
6580 }
6581 case SPELL_EFFECT_LEAP:
6583 {
6584 //Do not allow to cast it before BG starts.
6586 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
6587 if (bg->GetStatus() != STATUS_IN_PROGRESS)
6589 break;
6590 }
6592 {
6595 break;
6596 }
6598 {
6599 Unit* unitCaster = m_caster->ToUnit();
6600 if (!unitCaster)
6602
6603 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
6604 {
6605 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
6606 return SPELL_FAILED_ROOTED;
6607 else
6609 }
6610 break;
6611 }
6612 case SPELL_EFFECT_JUMP:
6614 {
6615 Unit* unitCaster = m_caster->ToUnit();
6616 if (!unitCaster)
6618
6619 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
6620 return SPELL_FAILED_ROOTED;
6621 break;
6622 }
6624 {
6625 ChrSpecializationEntry const* spec = sChrSpecializationStore.LookupEntry(m_misc.SpecializationId);
6626 Player* player = m_caster->ToPlayer();
6627 if (!player)
6629
6630 if (!spec || (spec->ClassID != player->GetClass() && !spec->IsPetSpecialization()))
6631 return SPELL_FAILED_NO_SPEC;
6632
6633 if (spec->IsPetSpecialization())
6634 {
6635 Pet* pet = player->GetPet();
6636 if (!pet || pet->getPetType() != HUNTER_PET || !pet->GetCharmInfo())
6637 return SPELL_FAILED_NO_PET;
6638 }
6639
6640 // can't change during already started arena/battleground
6641 if (Battleground const* bg = player->GetBattleground())
6642 if (bg->GetStatus() == STATUS_IN_PROGRESS)
6644 break;
6645 }
6647 {
6648 Player* playerCaster = m_caster->ToPlayer();
6649 if (!playerCaster)
6651
6652 TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
6653 if (!talent)
6655
6656 if (playerCaster->GetSpellHistory()->HasCooldown(talent->SpellID))
6657 {
6658 if (param1)
6659 *param1 = talent->SpellID;
6661 }
6662 break;
6663 }
6665 {
6666 if (!m_caster->IsPlayer())
6668
6669 if (!m_caster->ToPlayer()->GetSession()->GetCollectionMgr()->HasHeirloom(m_misc.Raw.Data[0]))
6671
6672 break;
6673 }
6676 {
6677 Player* playerCaster = m_caster->ToPlayer();
6678 if (!playerCaster)
6680
6682 if (!artifactAura)
6684
6685 Item* artifact = playerCaster->GetItemByGuid(artifactAura->GetCastItemGUID());
6686 if (!artifact)
6688
6689 if (spellEffectInfo.Effect == SPELL_EFFECT_GIVE_ARTIFACT_POWER)
6690 {
6691 ArtifactEntry const* artifactEntry = sArtifactStore.LookupEntry(artifact->GetTemplate()->GetArtifactID());
6692 if (!artifactEntry || artifactEntry->ArtifactCategoryID != spellEffectInfo.MiscValue)
6694 }
6695 break;
6696 }
6700 {
6701 Player* playerCaster = m_caster->ToPlayer();
6702 if (!playerCaster || !m_targets.GetUnitTarget() || !m_targets.GetUnitTarget()->IsCreature())
6704
6705 BattlePets::BattlePetMgr* battlePetMgr = playerCaster->GetSession()->GetBattlePetMgr();
6706 if (!battlePetMgr->HasJournalLock())
6708
6709 if (Creature* creature = m_targets.GetUnitTarget()->ToCreature())
6710 {
6711 if (playerCaster->GetSummonedBattlePetGUID().IsEmpty() || creature->GetBattlePetCompanionGUID().IsEmpty())
6712 return SPELL_FAILED_NO_PET;
6713
6714 if (playerCaster->GetSummonedBattlePetGUID() != creature->GetBattlePetCompanionGUID())
6716
6717 if (BattlePets::BattlePet* battlePet = battlePetMgr->GetPet(creature->GetBattlePetCompanionGUID()))
6718 {
6719 if (BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(battlePet->PacketInfo.Species))
6720 {
6721 if (uint32 battlePetType = spellEffectInfo.MiscValue)
6722 if (!(battlePetType & (1 << battlePetSpecies->PetTypeEnum)))
6724
6725 if (spellEffectInfo.Effect == SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY)
6726 {
6727 auto qualityItr = std::ranges::lower_bound(sBattlePetBreedQualityStore,
6728 spellEffectInfo.CalcBaseValue(m_caster, creature, m_castItemEntry, m_castItemLevel), {},
6730
6732 if (qualityItr != sBattlePetBreedQualityStore.end())
6733 quality = BattlePets::BattlePetBreedQuality(qualityItr->QualityEnum);
6734
6735 if (battlePet->PacketInfo.Quality >= AsUnderlyingType(quality))
6737 }
6738
6739 if (spellEffectInfo.Effect == SPELL_EFFECT_GRANT_BATTLEPET_LEVEL || spellEffectInfo.Effect == SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE)
6740 if (battlePet->PacketInfo.Level >= BattlePets::MAX_BATTLE_PET_LEVEL)
6741 return GRANT_PET_LEVEL_FAIL;
6742
6743 if (battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::CantBattle))
6745 }
6746 }
6747 }
6748 break;
6749 }
6750 default:
6751 break;
6752 }
6753
6754 if (spellEffectInfo.IsAura())
6755 approximateAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6756 else if (spellEffectInfo.IsEffect())
6757 nonAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6758 }
6759
6760 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6761 {
6762 switch (spellEffectInfo.ApplyAuraName)
6763 {
6765 {
6767 return SPELL_FAILED_NO_PET;
6768
6769 Pet* pet = m_caster->ToPlayer()->GetPet();
6770 if (!pet)
6771 return SPELL_FAILED_NO_PET;
6772
6773 if (!pet->GetCharmerGUID().IsEmpty())
6775 break;
6776 }
6780 {
6781 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6782 if (!unitCaster)
6784
6785 if (!unitCaster->GetCharmerGUID().IsEmpty())
6786 return SPELL_FAILED_CHARMED;
6787
6788 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_CHARM
6789 || spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_POSSESS)
6790 {
6793
6794 if (!unitCaster->GetCharmedGUID().IsEmpty())
6796 }
6797
6798 if (Unit* target = m_targets.GetUnitTarget())
6799 {
6800 if (target->GetTypeId() == TYPEID_UNIT && target->IsVehicle())
6802
6803 if (target->IsMounted())
6805
6806 if (!target->GetCharmerGUID().IsEmpty())
6808
6809 if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER)
6811
6812 SpellEffectValue value = CalculateDamage(spellEffectInfo, target);
6813 if (value && target->GetLevelForTarget(m_caster) > value)
6815 }
6816
6817 break;
6818 }
6819 case SPELL_AURA_MOUNTED:
6820 {
6821 Unit* unitCaster = m_caster->ToUnit();
6822 if (!unitCaster)
6824
6827
6828 if (unitCaster->IsInDisallowedMountForm())
6829 {
6830 SendMountResult(MountResult::Shapeshifted); // mount result gets sent before the cast result
6832 }
6833 break;
6834 }
6836 {
6837 if (!m_targets.GetUnitTarget())
6839
6840 // can be cast at non-friendly unit or own pet/charm
6843 break;
6844 }
6845 case SPELL_AURA_FLY:
6847 {
6848 // not allow cast fly spells if not have req. skills (all spells is self target)
6849 // allow always ghost flight spells
6851 {
6852 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetMap(), m_originalCaster->GetZoneId());
6853 if (Bf && !Bf->CanFlyIn())
6854 return SPELL_FAILED_NOT_HERE;
6855 }
6856 break;
6857 }
6859 {
6860 if (spellEffectInfo.IsTargetingArea())
6861 break;
6862
6863 if (!m_targets.GetUnitTarget())
6865
6867 break;
6868
6871 break;
6872 }
6873 default:
6874 break;
6875 }
6876
6877 // check if target already has the same type, but more powerful aura
6880 && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex))
6882 if (Unit* target = m_targets.GetUnitTarget())
6883 if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, spellEffectInfo.ApplyAuraName,
6884 spellEffectInfo.CalcValue(m_caster, &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex], nullptr, nullptr, m_castItemEntry, m_castItemLevel),
6885 approximateAuraEffectMask, false))
6887 }
6888
6889 // check trade slot case (last, for allow catch any another cast problems)
6891 {
6892 if (m_CastItem)
6894
6897
6900
6901 TradeData* my_trade = m_caster->ToPlayer()->GetTradeData();
6902 if (!my_trade)
6904
6907
6908 if (!IsTriggered())
6909 if (my_trade->GetSpell())
6911 }
6912
6913 // all ok
6914 return SPELL_CAST_OK;
6915}
6916
6918{
6919 Unit* unitCaster = m_caster->ToUnit();
6920 if (unitCaster && unitCaster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
6922
6923 // dead owner (pets still alive when owners ressed?)
6924 if (Unit* owner = m_caster->GetCharmerOrOwner())
6925 if (!owner->IsAlive())
6927
6928 if (!target && m_targets.GetUnitTarget())
6929 target = m_targets.GetUnitTarget();
6930
6932 {
6933 if (!target)
6935 m_targets.SetUnitTarget(target);
6936 }
6937
6938 // check cooldown
6939 if (Creature* creatureCaster = m_caster->ToCreature())
6940 if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
6942
6943 // Check if spell is affected by GCD
6945 if (unitCaster && unitCaster->GetCharmInfo() && unitCaster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
6947
6948 return CheckCast(true);
6949}
6950
6952{
6953 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6954 if (!unitCaster)
6955 return SPELL_CAST_OK;
6956
6957 // these attributes only show the spell as usable on the client when it has related aura applied
6958 // still they need to be checked against certain mechanics
6959
6960 // SPELL_ATTR5_USABLE_WHILE_STUNNED by default only MECHANIC_STUN (ie no sleep, knockout, freeze, etc.)
6961 bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_STUNNED);
6962
6963 // SPELL_ATTR5_USABLE_WHILE_FEARED by default only fear (ie no horror)
6964 bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_FLEEING);
6965
6966 // SPELL_ATTR5_USABLE_WHILE_CONFUSED by default only disorient (ie no polymorph)
6967 bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_CONFUSED);
6968
6969 // Check whether the cast should be prevented by any state you might have.
6971
6972 // Get unit state
6973 uint32 const unitflag = unitCaster->m_unitData->Flags;
6974
6975 if (m_fromClient && unitCaster->IsCharmed() && unitCaster->IsPlayer() && !CheckSpellCancelsCharm(param1))
6976 result = SPELL_FAILED_CHARMED;
6977
6978 // spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell
6979 auto mechanicCheck = [&](AuraType type) -> SpellCastResult
6980 {
6981 bool foundNotMechanic = false;
6982 Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
6983 for (AuraEffect const* aurEff : auras)
6984 {
6985 uint64 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
6986 if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask()))
6987 {
6988 foundNotMechanic = true;
6989
6990 // fill up aura mechanic info to send client proper error message
6991 if (param1)
6992 {
6993 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6994 if (!*param1)
6995 *param1 = aurEff->GetSpellInfo()->Mechanic;
6996 }
6997
6998 break;
6999 }
7000 }
7001
7002 if (foundNotMechanic)
7003 {
7004 switch (type)
7005 {
7008 return SPELL_FAILED_STUNNED;
7010 return SPELL_FAILED_FLEEING;
7012 return SPELL_FAILED_CONFUSED;
7013 default:
7014 ABORT();
7016 }
7017 }
7018
7019 return SPELL_CAST_OK;
7020 };
7021
7022 if (unitflag & UNIT_FLAG_STUNNED)
7023 {
7024 if (usableWhileStunned)
7025 {
7026 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN);
7027 if (mechanicResult != SPELL_CAST_OK)
7028 result = mechanicResult;
7029 else
7030 {
7031 mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN_DISABLE_GRAVITY);
7032 if (mechanicResult != SPELL_CAST_OK)
7033 result = mechanicResult;
7034 }
7035 }
7036 else if (!CheckSpellCancelsStun(param1))
7037 result = SPELL_FAILED_STUNNED;
7038 }
7040 result = SPELL_FAILED_SILENCED;
7042 result = SPELL_FAILED_PACIFIED;
7043 else if (unitflag & UNIT_FLAG_FLEEING)
7044 {
7045 if (usableWhileFeared)
7046 {
7047 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_FEAR);
7048 if (mechanicResult != SPELL_CAST_OK)
7049 result = mechanicResult;
7050 }
7051 else if (!CheckSpellCancelsFear(param1))
7052 result = SPELL_FAILED_FLEEING;
7053 }
7054 else if (unitflag & UNIT_FLAG_CONFUSED)
7055 {
7056 if (usableWhileConfused)
7057 {
7058 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_CONFUSE);
7059 if (mechanicResult != SPELL_CAST_OK)
7060 result = mechanicResult;
7061 }
7062 else if (!CheckSpellCancelsConfuse(param1))
7063 result = SPELL_FAILED_CONFUSED;
7064 }
7066 result = SPELL_FAILED_NO_ACTIONS;
7067
7068 // Attr must make flag drop spell totally immune from all effects
7069 if (result != SPELL_CAST_OK)
7070 return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
7071
7072 return SPELL_CAST_OK;
7073}
7074
7076{
7077 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
7078 if (!unitCaster)
7079 return false;
7080
7081 // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
7082 Unit::AuraEffectList const& auraEffects = unitCaster->GetAuraEffectsByType(auraType);
7083 if (auraEffects.empty())
7084 return true;
7085
7086 for (AuraEffect const* aurEff : auraEffects)
7087 {
7089 continue;
7090
7091 if (param1)
7092 {
7093 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
7094 if (!*param1)
7095 *param1 = aurEff->GetSpellInfo()->Mechanic;
7096 }
7097
7098 return false;
7099 }
7100
7101 return true;
7102}
7103
7110
7116
7122
7128
7130{
7132}
7133
7138
7143
7145{
7146 bool isRatedBattleground = false; // NYI
7147 bool isArena = !isRatedBattleground;
7148
7149 // check USABLE attributes
7150 // USABLE takes precedence over NOT_USABLE
7152 return SPELL_CAST_OK;
7153
7155 return SPELL_CAST_OK;
7156
7157 // check NOT_USABLE attributes
7160
7163
7164 // check cooldowns
7165 uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
7166 if (isArena && spellCooldown > 10 * MINUTE * IN_MILLISECONDS) // not sure if still needed
7168
7169 if (isRatedBattleground && spellCooldown > 15 * MINUTE * IN_MILLISECONDS)
7171
7172 return SPELL_CAST_OK;
7173}
7174
7176{
7177 if (IsTriggered())
7178 return SPELL_CAST_OK;
7179
7180 if (Unit* unitCaster = m_caster->ToUnit())
7181 {
7182 if (!unitCaster->CanCastSpellWhileMoving(m_spellInfo))
7183 {
7185 {
7186 if (m_casttime > 0)
7188 return SPELL_FAILED_MOVING;
7189 }
7190 else if (getState() == SPELL_STATE_CHANNELING)
7192 return SPELL_FAILED_MOVING;
7193 }
7194 }
7195
7196 return SPELL_CAST_OK;
7197}
7198
7199SpellEffectValue Spell::CalculateDamage(SpellEffectInfo const& spellEffectInfo, Unit const* target, float* var /*= nullptr*/) const
7200{
7201 if (var)
7202 *var = 0.0f;
7203
7204 bool needRecalculateBasePoints = !(m_spellValue->CustomBasePointsMask & (1 << spellEffectInfo.EffectIndex));
7205 SpellEffectValue* basePoints = needRecalculateBasePoints ? nullptr : &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex];
7206 return spellEffectInfo.CalcValue(m_caster, basePoints, target, var, m_castItemEntry, m_castItemLevel);
7207}
7208
7210{
7211 if (!target)
7212 return (CheckPetCast(target) == SPELL_CAST_OK);
7213
7214 ObjectGuid targetguid = target->GetGUID();
7215
7216 // check if target already has the same or a more powerful aura
7217 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7218 {
7219 if (!spellEffectInfo.IsAura())
7220 continue;
7221
7222 AuraType const& auraType = spellEffectInfo.ApplyAuraName;
7223 Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
7224 for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
7225 {
7226 if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
7227 return false;
7228
7229 switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
7230 {
7232 return false;
7234 if (GetCaster() == (*auraIt)->GetCaster())
7235 return false;
7236 break;
7237 case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
7239 if (abs(spellEffectInfo.CalcBaseValue(m_caster, target, 0, -1)) <= abs((*auraIt)->GetAmount()))
7240 return false;
7241 break;
7243 default:
7244 break;
7245 }
7246 }
7247 }
7248
7249 SpellCastResult result = CheckPetCast(target);
7250 if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
7251 {
7252 // do not check targets for ground-targeted spells (we target them on top of the intended target anyway)
7253 if (GetSpellInfo()->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION)
7254 return true;
7256 //check if among target units, our WANTED target is as well (->only self cast spells return false)
7257 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
7258 if (ihit->TargetGUID == targetguid)
7259 return true;
7260 }
7261 // either the cast failed or the intended target wouldn't be hit
7262 return false;
7263}
7264
7266{
7267 if (!m_targets.HasSrc())
7269}
7270
7272{
7273 if (!m_targets.HasDst())
7275}
7276
7278{
7279 // Don't check for instant cast spells
7280 if (!strict && m_casttime == 0)
7281 return SPELL_CAST_OK;
7282
7283 auto [minRange, maxRange] = GetMinMaxRange(strict);
7284
7285 // dont check max_range to strictly after cast
7287 maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
7288
7289 // get square values for sqr distance checks
7290 minRange *= minRange;
7291 maxRange *= maxRange;
7292
7293 Unit* target = m_targets.GetUnitTarget();
7294 if (target && target != m_caster)
7295 {
7296 if (m_caster->GetExactDistSq(target) > maxRange)
7298
7299 if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange)
7301
7302 if (m_caster->GetTypeId() == TYPEID_PLAYER &&
7303 (((m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
7304 && !m_caster->ToPlayer()->IsWithinBoundaryRadius(target)))
7306 }
7307
7308 if (GameObject* goTarget = m_targets.GetGOTarget())
7309 {
7310 if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
7312 }
7313
7314 if (m_targets.HasDst() && !m_targets.HasTraj())
7315 {
7316 if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange)
7318 if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange)
7320 }
7321
7322 return SPELL_CAST_OK;
7323}
7324
7326{
7327 // forward running only
7329 && !unit->IsWalking();
7330}
7331
7333{
7334 float rangeMod = 0.0f;
7335 SpellRange range;
7336
7337 if (strict && m_spellInfo->IsNextMeleeSwingSpell())
7338 {
7339 range = { .Min = 0.0f, .Max = 100.0f };
7340 return range;
7341 }
7342
7343 Unit* unitCaster = m_caster->ToUnit();
7345 {
7346 Unit* target = m_targets.GetUnitTarget();
7348 {
7349 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
7350 if (unitCaster)
7351 rangeMod = unitCaster->GetMeleeRange(target ? target : unitCaster);
7352 }
7353 else
7354 {
7355 float meleeRange = 0.0f;
7357 {
7358 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
7359 if (unitCaster)
7360 meleeRange = unitCaster->GetMeleeRange(target ? target : unitCaster);
7361 }
7362
7364 range.Min += meleeRange;
7365
7366 if (target || m_targets.GetCorpseTarget())
7367 {
7368 rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
7369
7370 if (range.Min > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
7371 range.Min += rangeMod;
7372 }
7373 }
7374
7375 if (target && unitCaster && CanIncreaseRangeByMovement(target) && CanIncreaseRangeByMovement(unitCaster) &&
7377 rangeMod += 8.0f / 3.0f;
7378 }
7379
7381 if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
7382 range.Max *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
7383
7384 if (Player* modOwner = m_caster->GetSpellModOwner())
7385 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, range.Max, const_cast<Spell*>(this));
7386
7387 range.Max += rangeMod;
7388
7389 return range;
7390}
7391
7393{
7394 Unit* unitCaster = m_caster->ToUnit();
7395 if (!unitCaster)
7396 return SPELL_CAST_OK;
7397
7398 // item cast not used power
7399 if (m_CastItem)
7400 return SPELL_CAST_OK;
7401
7402 for (SpellPowerCost const& cost : m_powerCost)
7403 {
7404 // health as power used - need check health amount
7405 if (cost.Power == POWER_HEALTH)
7406 {
7407 if (int64(unitCaster->GetHealth()) <= cost.Amount)
7409 continue;
7410 }
7411 // Check valid power type
7412 if (cost.Power >= MAX_POWERS)
7413 {
7414 TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '{}'", cost.Power);
7415 return SPELL_FAILED_UNKNOWN;
7416 }
7417
7418 //check rune cost only if a spell has PowerType == POWER_RUNES
7419 if (cost.Power == POWER_RUNES)
7420 {
7421 SpellCastResult failReason = CheckRuneCost();
7422 if (failReason != SPELL_CAST_OK)
7423 return failReason;
7424
7425 continue;
7426 }
7427
7428 // Check power amount
7429 if (int32(unitCaster->GetPower(cost.Power)) < cost.Amount)
7430 return SPELL_FAILED_NO_POWER;
7431 }
7432
7433 return SPELL_CAST_OK;
7434}
7435
7436SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
7437{
7438 Player* player = m_caster->ToPlayer();
7439 if (!player)
7440 return SPELL_CAST_OK;
7441
7442 if (!m_CastItem)
7443 {
7444 if (!m_castItemGUID.IsEmpty())
7446 }
7447 else
7448 {
7449 uint32 itemid = m_CastItem->GetEntry();
7450 if (!player->HasItemCount(itemid))
7452
7453 ItemTemplate const* proto = m_CastItem->GetTemplate();
7454 if (!proto)
7456
7457 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
7458 if (itemEffect->Charges && m_CastItem->GetSpellCharges(itemEffect) == 0)
7460
7461 // consumable cast item checks
7463 {
7464 // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
7465 SpellCastResult failReason = SPELL_CAST_OK;
7466 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7467 {
7468 // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster
7469 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
7470 continue;
7471
7472 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
7473 {
7475 {
7477 continue;
7478 }
7479 else
7480 {
7481 failReason = SPELL_CAST_OK;
7482 break;
7483 }
7484 }
7485
7486 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
7487 if (spellEffectInfo.IsEffect(SPELL_EFFECT_ENERGIZE))
7488 {
7489 if (spellEffectInfo.MiscValue < 0 || spellEffectInfo.MiscValue >= int8(MAX_POWERS))
7490 {
7492 continue;
7493 }
7494
7495 Powers power = Powers(spellEffectInfo.MiscValue);
7497 {
7499 continue;
7500 }
7501 else
7502 {
7503 failReason = SPELL_CAST_OK;
7504 break;
7505 }
7506 }
7507 }
7508 if (failReason != SPELL_CAST_OK)
7509 return failReason;
7510 }
7511 }
7512
7513 // check target item
7515 {
7516 Item* item = m_targets.GetItemTarget();
7517 if (!item)
7519
7522 }
7523 // if not item target then required item must be equipped
7524 else
7525 {
7529 }
7530
7531 // do not take reagents for these item casts
7533 {
7535 // Not own traded item (in trader trade slot) requires reagents even if triggered spell
7536 if (!checkReagents)
7537 if (Item* targetItem = m_targets.GetItemTarget())
7538 if (targetItem->GetOwnerGUID() != player->GetGUID())
7539 checkReagents = true;
7540
7541 // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
7542 if (checkReagents)
7543 {
7544 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
7545 {
7546 if (m_spellInfo->Reagent[i] <= 0)
7547 continue;
7548
7549 uint32 itemid = m_spellInfo->Reagent[i];
7550 uint32 itemcount = m_spellInfo->ReagentCount[i];
7551
7552 // if CastItem is also spell reagent
7553 if (m_CastItem && m_CastItem->GetEntry() == itemid)
7554 {
7555 ItemTemplate const* proto = m_CastItem->GetTemplate();
7556 if (!proto)
7558
7559 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
7560 {
7561 // CastItem will be used up and does not count as reagent
7562 int32 charges = m_CastItem->GetSpellCharges(itemEffect);
7563 if (itemEffect->Charges < 0 && abs(charges) < 2)
7564 {
7565 ++itemcount;
7566 break;
7567 }
7568 }
7569 }
7570 if (!player->HasItemCount(itemid, itemcount))
7571 {
7572 if (param1)
7573 *param1 = itemid;
7574 return SPELL_FAILED_REAGENTS;
7575 }
7576 }
7577
7578 for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency)
7579 {
7580 if (!player->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount))
7581 {
7582 if (param1)
7583 *param1 = -1;
7584
7585 if (param2)
7586 *param2 = reagentsCurrency->CurrencyTypesID;
7587
7588 return SPELL_FAILED_REAGENTS;
7589 }
7590 }
7591 }
7592
7594 {
7595 // check totem-item requirements (items presence in inventory)
7596 for (int32 totem : m_spellInfo->Totem)
7597 {
7598 if (totem && !player->HasItemCount(totem))
7599 {
7600 if (param1)
7601 *param1 = totem;
7602 return SPELL_FAILED_TOTEMS;
7603 }
7604 }
7605
7606 // Check items for TotemCategory (items presence in inventory)
7607 for (int32 totemCategory : m_spellInfo->TotemCategory)
7608 {
7609 if (totemCategory && !player->HasItemTotemCategory(totemCategory))
7610 {
7611 if (param1)
7612 *param1 = totemCategory;
7614 }
7615 }
7616 }
7617 }
7618
7619 // special checks for spell effects
7620 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7621 {
7622 switch (spellEffectInfo.Effect)
7623 {
7626 {
7627 // m_targets.GetUnitTarget() means explicit cast, otherwise we dont check for possible equip error
7628 Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
7629 if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered())
7630 {
7631 // SPELL_EFFECT_CREATE_ITEM_2 differs from SPELL_EFFECT_CREATE_ITEM in that it picks the random item to create from a pool of potential items,
7632 // so we need to make sure there is at least one free space in the player's inventory
7633 if (spellEffectInfo.Effect == SPELL_EFFECT_CREATE_LOOT)
7635 {
7636 player->SendEquipError(EQUIP_ERR_INV_FULL, nullptr, nullptr, spellEffectInfo.ItemType);
7638 }
7639
7640 if (spellEffectInfo.ItemType)
7641 {
7642 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType);
7643 if (!itemTemplate)
7645
7646 uint32 createCount = std::clamp<uint32>(spellEffectInfo.CalcValueAsInt(), 1u, itemTemplate->GetMaxStackSize());
7647 ItemPosCountVec dest;
7648 InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, createCount);
7649 if (msg != EQUIP_ERR_OK)
7650 {
7652 if (!itemTemplate->GetItemLimitCategory())
7653 {
7654 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7656 }
7657 else
7658 {
7659 // Conjure Food/Water/Refreshment spells
7662 else if (!(target->ToPlayer()->HasItemCount(spellEffectInfo.ItemType)))
7663 {
7664 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7666 }
7667 else if (m_spellInfo->GetEffects().size() > EFFECT_1)
7669 .SetTriggeringSpell(this)); // move this to anywhere
7671 }
7672 }
7673 }
7674 }
7675 break;
7676 }
7678 if (spellEffectInfo.ItemType && m_targets.GetItemTarget()
7680 {
7681 // cannot enchant vellum for other player
7682 if (m_targets.GetItemTarget()->GetOwner() != player)
7684 // do not allow to enchant vellum from scroll made by vellum-prevent exploit
7687 ItemPosCountVec dest;
7688 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, 1);
7689 if (msg != EQUIP_ERR_OK)
7690 {
7691 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7693 }
7694 }
7695 [[fallthrough]];
7697 {
7698 Item* targetItem = m_targets.GetItemTarget();
7699 if (!targetItem)
7701
7702 // Apply item level restriction
7704 {
7705 uint32 requiredLevel = targetItem->GetRequiredLevel();
7706 if (!requiredLevel)
7707 requiredLevel = targetItem->GetItemLevel(targetItem->GetOwner());
7708
7709 if (requiredLevel < m_spellInfo->BaseLevel)
7710 return SPELL_FAILED_LOWLEVEL;
7711 }
7712 if ((m_CastItem || spellEffectInfo.IsEffect(SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC))
7713 && m_spellInfo->MaxLevel > 0 && targetItem->GetItemLevel(targetItem->GetOwner()) > m_spellInfo->MaxLevel)
7715
7716 bool isItemUsable = false;
7717 for (ItemEffectEntry const* itemEffect : targetItem->GetEffects())
7718 {
7719 if (itemEffect->SpellID && itemEffect->TriggerType == ITEM_SPELLTRIGGER_ON_USE)
7720 {
7721 isItemUsable = true;
7722 break;
7723 }
7724 }
7725
7726 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(spellEffectInfo.MiscValue);
7727 // do not allow adding usable enchantments to items that have use effect already
7728 if (enchantEntry)
7729 {
7730 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
7731 {
7732 switch (enchantEntry->Effect[s])
7733 {
7735 if (isItemUsable)
7737 break;
7739 {
7740 uint32 numSockets = 0;
7741 for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket)
7742 if (targetItem->GetSocketColor(socket))
7743 ++numSockets;
7744
7745 if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
7747 break;
7748 }
7749 }
7750 }
7751 }
7752
7753 // Not allow enchant in trade slot for some enchant type
7754 if (targetItem->GetOwner() != player)
7755 {
7756 if (!enchantEntry)
7757 return SPELL_FAILED_ERROR;
7758 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
7760 }
7761 break;
7762 }
7764 {
7765 Item* item = m_targets.GetItemTarget();
7766 if (!item)
7768 // Not allow enchant in trade slot for some enchant type
7769 if (item->GetOwner() != player)
7770 {
7771 uint32 enchant_id = spellEffectInfo.MiscValue;
7772 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
7773 if (!enchantEntry)
7774 return SPELL_FAILED_ERROR;
7775 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
7777 }
7778
7779 // Apply item level restriction
7781 {
7782 uint32 requiredLevel = item->GetRequiredLevel();
7783 if (!requiredLevel)
7784 requiredLevel = item->GetItemLevel(item->GetOwner());
7785
7786 if (requiredLevel < m_spellInfo->BaseLevel)
7787 return SPELL_FAILED_LOWLEVEL;
7788 }
7789 if (m_CastItem && m_spellInfo->MaxLevel > 0 && item->GetItemLevel(item->GetOwner()) > m_spellInfo->MaxLevel)
7791 break;
7792 }
7794 // check item existence in effect code (not output errors at offhand hold item effect to main hand for example
7795 break;
7797 {
7798 Item const* item = m_targets.GetItemTarget();
7799 if (!item)
7801
7802 // prevent disenchanting in trade slot
7803 if (item->GetOwnerGUID() != player->GetGUID())
7805
7806 ItemTemplate const* itemProto = item->GetTemplate();
7807 if (!itemProto)
7809
7810 Optional<uint16> disenchantSkillRequired = item->GetDisenchantSkillRequired();
7811 if (!disenchantSkillRequired)
7813 if (disenchantSkillRequired > player->GetSkillValue(SKILL_ENCHANTING))
7815 break;
7816 }
7818 {
7819 Item* item = m_targets.GetItemTarget();
7820 if (!item)
7822 //ensure item is a prospectable ore
7825 //prevent prospecting in trade slot
7826 if (item->GetOwnerGUID() != player->GetGUID())
7828 //Check for enough skill in jewelcrafting
7829 uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7830 if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
7832 //make sure the player has the required ores in inventory
7833 if (item->GetCount() < 5)
7834 {
7835 if (param1 && param2)
7836 {
7837 *param1 = item->GetEntry();
7838 *param2 = 5;
7839 }
7841 }
7842
7845
7846 break;
7847 }
7849 {
7850 Item* item = m_targets.GetItemTarget();
7851 if (!item)
7853 //ensure item is a millable herb
7856 //prevent milling in trade slot
7857 if (item->GetOwnerGUID() != player->GetGUID())
7859 //Check for enough skill in inscription
7860 uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7861 if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
7863 //make sure the player has the required herbs in inventory
7864 if (item->GetCount() < 5)
7865 {
7866 if (param1 && param2)
7867 {
7868 *param1 = item->GetEntry();
7869 *param2 = 5;
7870 }
7872 }
7873
7876
7877 break;
7878 }
7881 {
7883 break;
7884
7885 Item* item = player->GetWeaponForAttack(m_attackType);
7886 if (!item || item->IsBroken())
7888
7889 switch (item->GetTemplate()->GetSubClass())
7890 {
7892 {
7893 uint32 const ammo = item->GetEntry();
7894 if (!player->HasItemCount(ammo))
7895 return SPELL_FAILED_NO_AMMO;
7896 break;
7897 }
7902 break;
7903 default:
7904 break;
7905 }
7906 break;
7907 }
7909 {
7910 uint32 itemId = spellEffectInfo.ItemType;
7911
7912 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
7913 if (!proto)
7915
7916 if (Item* item = player->GetItemByEntry(itemId))
7917 for (ItemEffectEntry const* itemEffect : item->GetEffects())
7918 if (itemEffect->Charges != 0 && item->GetSpellCharges(itemEffect) == itemEffect->Charges)
7920 break;
7921 }
7923 {
7924 Item const* item = m_targets.GetItemTarget();
7925 if (!item)
7927
7928 if (item->GetOwnerGUID() != m_caster->GetGUID())
7930
7931 AzeriteEmpoweredItem const* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem();
7932 if (!azeriteEmpoweredItem)
7934
7935 bool hasSelections = false;
7936 for (int32 tier = 0; tier < MAX_AZERITE_EMPOWERED_TIER; ++tier)
7937 {
7938 if (azeriteEmpoweredItem->GetSelectedAzeritePower(tier))
7939 {
7940 hasSelections = true;
7941 break;
7942 }
7943 }
7944
7945 if (!hasSelections)
7947
7948 if (!m_caster->ToPlayer()->HasEnoughMoney(azeriteEmpoweredItem->GetRespecCost()))
7950
7951 break;
7952 }
7953 default:
7954 break;
7955 }
7956 }
7957
7958 // check weapon presence in slots for main/offhand weapons
7960 {
7961 auto weaponCheck = [&](WeaponAttackType attackType) -> SpellCastResult
7962 {
7963 Item const* item = player->GetWeaponForAttack(attackType);
7964
7965 // skip spell if no weapon in slot or broken
7966 if (!item || item->IsBroken())
7968
7969 // skip spell if weapon not fit to triggered spell
7972
7973 return SPELL_CAST_OK;
7974 };
7975
7977 {
7978 SpellCastResult mainHandResult = weaponCheck(BASE_ATTACK);
7979 if (mainHandResult != SPELL_CAST_OK)
7980 return mainHandResult;
7981 }
7982
7984 {
7985 SpellCastResult offHandResult = weaponCheck(OFF_ATTACK);
7986 if (offHandResult != SPELL_CAST_OK)
7987 return offHandResult;
7988 }
7989 }
7990
7991 return SPELL_CAST_OK;
7992}
7993
7994void Spell::Delayed() // only called in DealDamage()
7995{
7996 Unit* unitCaster = m_caster->ToUnit();
7997 if (!unitCaster)
7998 return;
7999
8000 if (IsDelayableNoMore()) // Spells may only be delayed twice
8001 return;
8002
8003 //check pushback reduce
8004 int32 delaytime = 500; // spellcasting delay is normally 500ms
8005
8006 float delayReduce = 100.0f; // must be initialized to 100 for percent modifiers
8007 if (Player* player = unitCaster->GetSpellModOwner())
8008 player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
8009 delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100.0f;
8010 if (delayReduce >= 100)
8011 return;
8012
8013 AddPct(delaytime, -delayReduce);
8014
8015 if (m_timer + delaytime > m_casttime)
8016 {
8017 delaytime = m_casttime - m_timer;
8019 }
8020 else
8021 m_timer += delaytime;
8022
8024 spellDelayed.Caster = unitCaster->GetGUID();
8025 spellDelayed.ActualDelay = delaytime;
8026
8027 unitCaster->SendMessageToSet(spellDelayed.Write(), true);
8028}
8029
8031{
8032 Unit* unitCaster = m_caster->ToUnit();
8033 if (!unitCaster)
8034 return;
8035
8037 return;
8038
8039 if (IsDelayableNoMore()) // Spells may only be delayed twice
8040 return;
8041
8042 //check pushback reduce
8043 // should be affected by modifiers, not take the dbc duration.
8045
8046 int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
8047
8048 float delayReduce = 100.0f; // must be initialized to 100 for percent modifiers
8049 if (Player* player = unitCaster->GetSpellModOwner())
8050 player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
8051 delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100.0f;
8052 if (delayReduce >= 100)
8053 return;
8054
8055 AddPct(delaytime, -delayReduce);
8056
8057 if (m_timer <= delaytime)
8058 {
8059 delaytime = m_timer;
8060 m_timer = 0;
8061 }
8062 else
8063 m_timer -= delaytime;
8064
8065 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
8066 {
8067 if (targetInfo.MissCondition != SPELL_MISS_NONE)
8068 continue;
8069
8070 Unit* unit = unitCaster;
8071 if (unitCaster->GetGUID() != targetInfo.TargetGUID)
8072 {
8073 unit = ObjectAccessor::GetUnit(*unitCaster, targetInfo.TargetGUID);
8074 if (!unit)
8075 continue;
8076 }
8077
8079 }
8080
8081 // partially interrupt persistent area auras
8082 if (DynamicObject* dynObj = unitCaster->GetDynObject(m_spellInfo->Id))
8083 dynObj->Delay(delaytime);
8084
8086}
8087
8089{
8090 return GetPowerTypeCostAmount(power).has_value();
8091}
8092
8094{
8095 auto itr = std::ranges::find(m_powerCost, power, &SpellPowerCost::Power);
8096 if (itr == m_powerCost.cend())
8097 return { };
8098
8099 return itr->Amount;
8100}
8101
8103{
8106 else
8107 {
8110 m_originalCaster = nullptr;
8111 }
8112
8115
8117 {
8119 m_castItemLevel = -1;
8120 // cast item not found, somehow the item is no longer where we expected
8121 if (!m_CastItem)
8122 return false;
8123
8124 // check if the item is really the same, in case it has been wrapped for example
8126 return false;
8127
8129 }
8130
8132
8133 // further actions done only for dest targets
8134 if (!m_targets.HasDst())
8135 return true;
8136
8137 // cache last transport
8138 WorldObject* transport = nullptr;
8139
8140 // update effect destinations (in case of moved transport dest target)
8141 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8142 {
8143 SpellDestination& dest = m_destTargets[spellEffectInfo.EffectIndex];
8144 if (!dest._transportGUID)
8145 continue;
8146
8147 if (!transport || transport->GetGUID() != dest._transportGUID)
8149
8150 if (transport)
8151 {
8152 dest._position.Relocate(transport);
8154 }
8155 }
8156
8157 return true;
8158}
8159
8161{
8163 return CURRENT_MELEE_SPELL;
8164 else if (IsAutoRepeat())
8166 else if (m_spellInfo->IsChanneled())
8168
8169 return CURRENT_GENERIC_SPELL;
8170}
8171
8176
8177bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEffectInfo, Position const* losPosition) const
8178{
8179 switch (spellEffectInfo.ApplyAuraName)
8180 {
8185 if (target->GetVehicleKit() && target->GetVehicleKit()->IsControllableVehicle())
8186 return false;
8187 if (target->IsMounted())
8188 return false;
8189 if (!target->GetCharmerGUID().IsEmpty())
8190 return false;
8191 if (SpellEffectValue value = CalculateDamage(spellEffectInfo, target))
8192 if (target->GetLevelForTarget(m_caster) > value)
8193 return false;
8194 break;
8195 default:
8196 break;
8197 }
8198
8199 // check for ignore LOS on the effect itself
8201 return true;
8202
8203 // check if gameobject ignores LOS
8204 if (GameObject const* gobCaster = m_caster->ToGameObject())
8205 if (!gobCaster->GetGOInfo()->GetRequireLOS())
8206 return true;
8207
8208 // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
8210 return true;
8211
8213 //Check targets for LOS visibility
8214 switch (spellEffectInfo.Effect)
8215 {
8217 {
8219 {
8221 return true;
8222
8223 return false;
8224 }
8225
8227 if (!corpse)
8228 return false;
8229
8230 if (target->GetGUID() != corpse->GetOwnerGUID())
8231 return false;
8232
8234 return false;
8235
8236 if (!IsWithinLOS(m_caster, corpse, true, VMAP::ModelIgnoreFlags::M2))
8237 return false;
8238
8239 break;
8240 }
8241 default:
8242 {
8244 {
8245 // Get GO cast coordinates if original caster -> GO
8246 WorldObject* caster = nullptr;
8249 if (!caster)
8250 caster = m_caster;
8251
8252 if (target != m_caster && !IsWithinLOS(caster, target, true, VMAP::ModelIgnoreFlags::M2))
8253 return false;
8254 }
8255
8256 if (losPosition)
8257 if (!IsWithinLOS(target, *losPosition, VMAP::ModelIgnoreFlags::M2))
8258 return false;
8259 }
8260 }
8261
8262 return true;
8263}
8264
8265bool Spell::CheckEffectTarget(GameObject const* target, SpellEffectInfo const& spellEffectInfo) const
8266{
8267 switch (spellEffectInfo.Effect)
8268 {
8273 return false;
8274 break;
8275 default:
8276 break;
8277 }
8278
8279 return true;
8280}
8281
8282bool Spell::CheckEffectTarget(Item const* /*target*/, SpellEffectInfo const& /*spellEffectInfo*/) const
8283{
8284 return true;
8285}
8286
8288{
8291}
8292
8297
8302
8304{
8306}
8307
8309{
8310 return m_caster->IsUnit() && m_caster->ToUnit()->GetChannelSpellId() != 0;
8311}
8312
8323
8328
8330{
8331 m_empower->IsReleasedByClient = release;
8332}
8333
8335{
8336 if (m_empower->IsReleased)
8337 return false;
8338
8339 if (!m_empower->IsReleasedByClient && m_timer)
8340 return false;
8341
8343 return passedTime >= m_empower->MinHoldTime;
8344}
8345
8355
8360
8361SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell)
8362{
8363}
8364
8366{
8368 m_Spell->cancel();
8369
8370 if (!m_Spell->IsDeletable())
8371 {
8372 TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.",
8373 (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id);
8374 ABORT();
8375 }
8376}
8377
8379{
8380 // update spell if it is not finished
8382 m_Spell->update(p_time);
8383
8384 // check spell state to process
8385 switch (m_Spell->getState())
8386 {
8388 {
8389 // spell was finished, check deletable state
8390 if (m_Spell->IsDeletable())
8391 {
8392 // check, if we do have unfinished triggered spells
8393 return true; // spell is deletable, finish event
8394 }
8395 // event will be re-added automatically at the end of routine)
8396 break;
8397 }
8399 {
8400 // first, check, if we have just started
8401 if (m_Spell->GetDelayStart() != 0)
8402 {
8403 // no, we aren't, do the typical update
8404 // check, if we have channeled spell on our hands
8405 /*
8406 if (m_Spell->m_spellInfo->IsChanneled())
8407 {
8408 // evented channeled spell is processed separately, cast once after delay, and not destroyed till finish
8409 // check, if we have casting anything else except this channeled spell and autorepeat
8410 if (m_Spell->GetCaster()->IsNonMeleeSpellCast(false, true, true))
8411 {
8412 // another non-melee non-delayed spell is cast now, abort
8413 m_Spell->cancel();
8414 }
8415 else
8416 {
8417 // Set last not triggered spell for apply spellmods
8418 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, true);
8419 // do the action (pass spell to channeling state)
8420 m_Spell->handle_immediate();
8421
8422 // And remove after effect handling
8423 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, false);
8424 }
8425 // event will be re-added automatically at the end of routine)
8426 }
8427 else
8428 */
8429 {
8430 // run the spell handler and think about what we can do next
8431 uint64 t_offset = e_time - m_Spell->GetDelayStart();
8432 uint64 n_offset = m_Spell->handle_delayed(t_offset);
8433 if (n_offset)
8434 {
8435 // re-add us to the queue
8436 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(m_Spell->GetDelayStart() + n_offset), false);
8437 return false; // event not complete
8438 }
8439 // event complete
8440 // finish update event will be re-added automatically at the end of routine)
8441 }
8442 }
8443 else
8444 {
8445 // delaying had just started, record the moment
8446 m_Spell->SetDelayStart(e_time);
8447 // handle effects on caster if the spell has travel time but also affects the caster in some way
8448 uint64 n_offset = m_Spell->handle_delayed(0);
8450 ASSERT(n_offset == uint64(std::floor(m_Spell->m_spellInfo->LaunchDelay * 1000.0f)));
8451 else
8452 ASSERT(n_offset == m_Spell->GetDelayMoment(), UI64FMTD " == " UI64FMTD, n_offset, m_Spell->GetDelayMoment());
8453 // re-plan the event for the delay moment
8454 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + n_offset), false);
8455 return false; // event not complete
8456 }
8457 break;
8458 }
8459 default:
8460 {
8461 // all other states
8462 // event will be re-added automatically at the end of routine)
8463 break;
8464 }
8465 }
8466
8467 // spell processing not complete, plan event on the next update interval
8468 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + 1), false);
8469 return false; // event not complete
8470}
8471
8473{
8474 // oops, the spell we try to do is aborted
8476 m_Spell->cancel();
8477}
8478
8480{
8481 return m_Spell->IsDeletable();
8482}
8483
8484bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
8485{
8486 if (target->IsAlive())
8489 return true;
8490 return false;
8491}
8492
8494{
8495 // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode
8496 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8497 {
8498 // don't do anything for empty effect
8499 if (!spellEffectInfo.IsEffect())
8500 continue;
8501
8502 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
8503 }
8504
8506
8507 for (TargetInfo& target : m_UniqueTargetInfo)
8508 PreprocessSpellLaunch(target);
8509
8510 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8511 {
8512 float multiplier = 1.0f;
8513 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
8514 multiplier = spellEffectInfo.CalcDamageMultiplier(m_originalCaster, this);
8515
8516 for (TargetInfo& target : m_UniqueTargetInfo)
8517 {
8518 uint32 mask = target.EffectMask;
8519 if (!(mask & (1 << spellEffectInfo.EffectIndex)))
8520 continue;
8521
8522 DoEffectOnLaunchTarget(target, multiplier, spellEffectInfo);
8523 }
8524 }
8525
8527}
8528
8530{
8531 Unit* targetUnit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
8532 if (!targetUnit)
8533 return;
8534
8535 // Check immunity now that EffectMask is known
8536 if (targetUnit->IsImmunedToSpell(GetSpellInfo(), targetInfo.EffectMask, m_caster))
8537 targetInfo.MissCondition = SPELL_MISS_IMMUNE;
8538
8539 // This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
8541 m_originalCaster->SetInCombatWith(targetUnit, true);
8542
8543 Unit* unit = nullptr;
8544 // In case spell hit target, do all effect on that target
8545 if (targetInfo.MissCondition == SPELL_MISS_NONE)
8546 unit = targetUnit;
8547 // In case spell reflect from target, do all effect on caster (if hit)
8548 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
8549 {
8550 unit = m_caster->ToUnit();
8551 if (unit && unit->IsImmunedToSpell(GetSpellInfo(), targetInfo.EffectMask, unit))
8552 targetInfo.ReflectResult = SPELL_MISS_IMMUNE;
8553 }
8554
8555 if (!unit)
8556 return;
8557
8558 float critChance = m_spellValue->CriticalChance;
8559 if (m_originalCaster)
8560 {
8561 if (!critChance)
8563 critChance = unit->SpellCritChanceTaken(m_originalCaster, this, nullptr, m_spellSchoolMask, critChance, m_attackType);
8564 }
8565
8566 targetInfo.IsCrit = roll_chance(critChance);
8567}
8568
8569void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, SpellEffectInfo const& spellEffectInfo)
8570{
8571 Unit* unit = nullptr;
8572 // In case spell hit target, do all effect on that target
8574 unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
8575 // In case spell reflect from target, do all effect on caster (if hit)
8576 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
8577 unit = m_caster->ToUnit();
8578
8579 if (!unit)
8580 return;
8581
8582 m_damage = 0;
8583 m_healing = 0;
8584
8585 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
8586
8587 if (m_originalCaster && m_damage > 0)
8588 {
8589 bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
8591 {
8593
8595 {
8598
8599 // sqrt target cap damage calculation
8603 m_damage = m_damage * std::sqrt(float(m_spellInfo->SqrtDamageAndHealingDiminishing.MaxTargets) / std::min(AOE_DAMAGE_TARGET_CAP, targetCount));
8604
8605 // cap damage of player AOE
8606 if (targetCount > AOE_DAMAGE_TARGET_CAP)
8607 m_damage = m_damage * AOE_DAMAGE_TARGET_CAP / targetCount;
8608 }
8609 }
8610 }
8611
8612 if (m_originalCaster && m_healing > 0)
8613 {
8614 bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
8616 {
8618 {
8621
8622 // sqrt target cap healing calculation
8627 }
8628 }
8629 }
8630
8631 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
8632 {
8635
8636 m_damageMultipliers[spellEffectInfo.EffectIndex] *= multiplier;
8637 }
8638
8639 targetInfo.Damage += m_damage;
8640 targetInfo.Healing += m_healing;
8641}
8642
8644{
8645 Unit* unitCaster = m_caster->ToUnit();
8646 if (!unitCaster)
8647 return;
8648
8649 unitCaster->resetAttackTimer(BASE_ATTACK);
8650 if (unitCaster->haveOffhandWeapon())
8651 unitCaster->resetAttackTimer(OFF_ATTACK);
8652 unitCaster->resetAttackTimer(RANGED_ATTACK);
8653}
8654
8655SpellCastResult Spell::CanOpenLock(SpellEffectInfo const& effect, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
8656{
8657 if (!lockId) // possible case for GO and maybe for items.
8658 return SPELL_CAST_OK;
8659
8660 Unit const* unitCaster = m_caster->ToUnit();
8661 if (!unitCaster)
8663
8664 // Get LockInfo
8665 LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
8666
8667 if (!lockInfo)
8669
8670 bool reqKey = false; // some locks not have reqs
8671
8672 for (int j = 0; j < MAX_LOCK_CASE; ++j)
8673 {
8674 switch (lockInfo->Type[j])
8675 {
8676 // check key item (many fit cases can be)
8677 case LOCK_KEY_ITEM:
8678 if (lockInfo->Index[j] && m_CastItem && int32(m_CastItem->GetEntry()) == lockInfo->Index[j])
8679 return SPELL_CAST_OK;
8680 reqKey = true;
8681 break;
8682 // check key skill (only single first fit case can be)
8683 case LOCK_KEY_SKILL:
8684 {
8685 reqKey = true;
8686
8687 // wrong locktype, skip
8688 if (effect.MiscValue != lockInfo->Index[j])
8689 continue;
8690
8691 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
8692
8693 if (skillId != SKILL_NONE || lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
8694 {
8695 reqSkillValue = lockInfo->Skill[j];
8696
8697 // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
8698 skillValue = 0;
8699 if (!m_CastItem && unitCaster->GetTypeId() == TYPEID_PLAYER)
8700 skillValue = unitCaster->ToPlayer()->GetSkillValue(skillId);
8701 else if (lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
8702 skillValue = unitCaster->GetLevel() * 5;
8703
8704 // skill bonus provided by casting spell (mostly item spells)
8705 // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.)
8707 skillValue += effect.CalcValueAsInt();
8708
8709 if (skillValue < reqSkillValue)
8711 }
8712
8713 return SPELL_CAST_OK;
8714 }
8715 case LOCK_KEY_SPELL:
8716 if (m_spellInfo->Id == uint32(lockInfo->Index[j]))
8717 return SPELL_CAST_OK;
8718 reqKey = true;
8719 break;
8720 }
8721 }
8722
8723 if (reqKey)
8725
8726 return SPELL_CAST_OK;
8727}
8728
8730{
8732 {
8735 return;
8736 }
8737
8738 switch (value.Type)
8739 {
8742 break;
8745 break;
8747 m_spellValue->Duration = value.Value.I;
8748 break;
8751 break;
8754 break;
8756 m_spellValue->RadiusMod = value.Value.F;
8757 break;
8760 break;
8762 m_spellValue->DurationMul = value.Value.F / 100.0;
8763 break;
8764 default:
8765 break;
8766 }
8767}
8768
8772
8777
8779{
8780 sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this);
8781 for (SpellScript* script : m_loadedScripts)
8782 {
8783 TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `{}` for spell `{}` is loaded now", script->GetScriptName(), m_spellInfo->Id);
8784 script->Register();
8785 }
8786}
8787
8789{
8790 for (SpellScript* script : m_loadedScripts)
8791 {
8792 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_PRECAST);
8793 script->OnPrecast();
8794 script->_FinishScriptCall();
8795 }
8796}
8797
8799{
8800 for (SpellScript* script : m_loadedScripts)
8801 {
8802 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST);
8803 for (SpellScript::CastHandler const& beforeCast : script->BeforeCast)
8804 beforeCast.Call(script);
8805
8806 script->_FinishScriptCall();
8807 }
8808}
8809
8811{
8812 for (SpellScript* script : m_loadedScripts)
8813 {
8814 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST);
8815 for (SpellScript::CastHandler const& onCast : script->OnCast)
8816 onCast.Call(script);
8817
8818 script->_FinishScriptCall();
8819 }
8820}
8821
8823{
8824 for (SpellScript* script : m_loadedScripts)
8825 {
8826 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST);
8827 for (SpellScript::CastHandler const& afterCast : script->AfterCast)
8828 afterCast.Call(script);
8829
8830 script->_FinishScriptCall();
8831 }
8832}
8833
8835{
8837 for (SpellScript* script : m_loadedScripts)
8838 {
8839 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST);
8840 for (SpellScript::CheckCastHandler const& checkCast : script->OnCheckCast)
8841 {
8842 SpellCastResult tempResult = checkCast.Call(script);
8843 if (retVal == SPELL_CAST_OK)
8844 retVal = tempResult;
8845 }
8846
8847 script->_FinishScriptCall();
8848 }
8849 return retVal;
8850}
8851
8853{
8854 for (SpellScript* script : m_loadedScripts)
8855 {
8856 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_CAST_TIME);
8857 castTime = script->CalcCastTime(castTime);
8858 script->_FinishScriptCall();
8859 }
8860 return castTime;
8861}
8862
8864{
8865 // execute script effect handler hooks and check if effects was prevented
8866 bool preventDefault = false;
8867 for (SpellScript* script : m_loadedScripts)
8868 {
8869 script->_InitHit();
8870
8872 SpellScriptHookType hookType;
8873 switch (mode)
8874 {
8876 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectLaunch.begin(), script->OnEffectLaunch.end());
8878 break;
8880 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectLaunchTarget.begin(), script->OnEffectLaunchTarget.end());
8882 break;
8884 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectHit.begin(), script->OnEffectHit.end());
8886 break;
8888 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectHitTarget.begin(), script->OnEffectHitTarget.end());
8890 break;
8891 default:
8892 ABORT();
8893 return false;
8894 }
8895 script->_PrepareScriptCall(hookType);
8896 for (SpellScript::EffectHandler const& effectHandler : effectHandlers)
8897 // effect execution can be prevented
8898 if (!script->_IsEffectPrevented(effIndex) && effectHandler.IsEffectAffected(m_spellInfo, effIndex))
8899 effectHandler.Call(script, effIndex);
8900
8901 if (!preventDefault)
8902 preventDefault = script->_IsDefaultEffectPrevented(effIndex);
8903
8904 script->_FinishScriptCall();
8905 }
8906 return preventDefault;
8907}
8908
8910{
8911 for (SpellScript* script : m_loadedScripts)
8912 {
8913 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
8914 for (SpellScript::EffectHandler const& onDispel : script->OnEffectSuccessfulDispel)
8915 onDispel.Call(script, effIndex);
8916
8917 script->_FinishScriptCall();
8918 }
8919}
8920
8922{
8923 for (SpellScript* script : m_loadedScripts)
8924 {
8925 script->_InitHit();
8926 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT);
8927 for (SpellScript::BeforeHitHandler const& beforeHit : script->BeforeHit)
8928 beforeHit.Call(script, missInfo);
8929
8930 script->_FinishScriptCall();
8931 }
8932}
8933
8935{
8936 for (SpellScript* script : m_loadedScripts)
8937 {
8938 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT);
8939 for (SpellScript::HitHandler const& onHit : script->OnHit)
8940 onHit.Call(script);
8941
8942 script->_FinishScriptCall();
8943 }
8944}
8945
8947{
8948 for (SpellScript* script : m_loadedScripts)
8949 {
8950 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT);
8951 for (SpellScript::HitHandler const& afterHit : script->AfterHit)
8952 afterHit.Call(script);
8953
8954 script->_FinishScriptCall();
8955 }
8956}
8957
8958void Spell::CallScriptCalcCritChanceHandlers(Unit const* victim, float& critChance)
8959{
8960 for (SpellScript* script : m_loadedScripts)
8961 {
8962 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE);
8963 for (SpellScript::OnCalcCritChanceHandler const& calcCritChance : script->OnCalcCritChance)
8964 calcCritChance.Call(script, victim, critChance);
8965
8966 script->_FinishScriptCall();
8967 }
8968}
8969
8970void Spell::CallScriptCalcDamageHandlers(SpellEffectInfo const& spellEffectInfo, Unit* victim, int32& damage, int32& flatMod, float& pctMod)
8971{
8972 for (SpellScript* script : m_loadedScripts)
8973 {
8974 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_DAMAGE);
8975 for (SpellScript::DamageAndHealingCalcHandler const& calcDamage : script->CalcDamage)
8976 calcDamage.Call(script, spellEffectInfo, victim, damage, flatMod, pctMod);
8977
8978 script->_FinishScriptCall();
8979 }
8980}
8981
8982void Spell::CallScriptCalcHealingHandlers(SpellEffectInfo const& spellEffectInfo, Unit* victim, int32& healing, int32& flatMod, float& pctMod)
8983{
8984 for (SpellScript* script : m_loadedScripts)
8985 {
8986 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_HEALING);
8987 for (SpellScript::DamageAndHealingCalcHandler const& calcHealing : script->CalcHealing)
8988 calcHealing.Call(script, spellEffectInfo, victim, healing, flatMod, pctMod);
8989
8990 script->_FinishScriptCall();
8991 }
8992}
8993
8994void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
8995{
8996 for (SpellScript* script : m_loadedScripts)
8997 {
8998 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT);
8999 for (SpellScript::ObjectAreaTargetSelectHandler const& objectAreaTargetSelect : script->OnObjectAreaTargetSelect)
9000 if (objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == objectAreaTargetSelect.GetTarget())
9001 objectAreaTargetSelect.Call(script, targets);
9002
9003 script->_FinishScriptCall();
9004 }
9005}
9006
9008{
9009 for (SpellScript* script : m_loadedScripts)
9010 {
9011 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT);
9012 for (SpellScript::ObjectTargetSelectHandler const& objectTargetSelect : script->OnObjectTargetSelect)
9013 if (objectTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == objectTargetSelect.GetTarget())
9014 objectTargetSelect.Call(script, target);
9015
9016 script->_FinishScriptCall();
9017 }
9018}
9019
9021{
9022 for (SpellScript* script : m_loadedScripts)
9023 {
9024 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT);
9025 for (SpellScript::DestinationTargetSelectHandler const& destinationTargetSelect : script->OnDestinationTargetSelect)
9026 if (destinationTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == destinationTargetSelect.GetTarget())
9027 destinationTargetSelect.Call(script, target);
9028
9029 script->_FinishScriptCall();
9030 }
9031}
9032
9033void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)
9034{
9035 for (SpellScript* script : m_loadedScripts)
9036 {
9037 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION);
9038 for (SpellScript::OnCalculateResistAbsorbHandler const& calculateResistAbsorb : script->OnCalculateResistAbsorb)
9039 calculateResistAbsorb.Call(script, damageInfo, resistAmount, absorbAmount);
9040
9041 script->_FinishScriptCall();
9042 }
9043}
9044
9046{
9047 for (SpellScript* script : m_loadedScripts)
9048 {
9049 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EMPOWER_STAGE_COMPLETED);
9050 for (SpellScript::EmpowerStageCompletedHandler const& empowerStageCompleted : script->OnEmpowerStageCompleted)
9051 empowerStageCompleted.Call(script, completedStagesCount);
9052
9053 script->_FinishScriptCall();
9054 }
9055}
9056
9058{
9059 for (SpellScript* script : m_loadedScripts)
9060 {
9061 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EMPOWER_COMPLETED);
9062 for (SpellScript::EmpowerStageCompletedHandler const& empowerStageCompleted : script->OnEmpowerCompleted)
9063 empowerStageCompleted.Call(script, completedStagesCount);
9064
9065 script->_FinishScriptCall();
9066 }
9067}
9068
9070{
9071 auto allEffectTargetScriptsAreShared = []<typename HookType>(HookList<HookType> const& hooks, SpellInfo const* spellInfo, uint32 effIndex, uint32 effIndexToCheck)
9072 {
9073 for (HookType const& hook : hooks)
9074 {
9075 if (!hook.IsEffectAffected(spellInfo, effIndex))
9076 continue;
9077
9078 bool otherEffectHasSameTargetFunction = std::ranges::any_of(hooks, [&](HookType const& other)
9079 {
9080 return other.IsEffectAffected(spellInfo, effIndexToCheck) && hook.HasSameTargetFunctionAs(other);
9081 });
9082 if (!otherEffectHasSameTargetFunction)
9083 return false;
9084 }
9085
9086 return true;
9087 };
9088
9089 for (SpellScript* script : m_loadedScripts)
9090 {
9091 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
9092 return false;
9093
9094 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
9095 return false;
9096
9097 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
9098 return false;
9099
9100 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
9101 return false;
9102 }
9103 return true;
9104}
9105
9106SpellScript* Spell::GetScriptByType(std::type_info const& type) const
9107{
9108 auto itr = std::ranges::find(m_loadedScripts, type, [](SpellScript* script) -> std::type_info const& { return typeid(*script); });
9109 if (itr != m_loadedScripts.end())
9110 return *itr;
9111 return nullptr;
9112}
9113
9114bool Spell::CanExecuteTriggersOnHit(Unit* unit, SpellInfo const* triggeredByAura /*= nullptr*/) const
9115{
9116 bool onlyOnTarget = (triggeredByAura && (triggeredByAura->HasAttribute(SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET)));
9117 if (!onlyOnTarget)
9118 return true;
9119
9120 // If triggeredByAura has SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET then it can only proc on either noncaster units...
9121 if (unit != m_caster)
9122 return true;
9123
9124 // ... or caster if it is the only target
9125 if (m_UniqueTargetInfo.size() == 1)
9126 return true;
9127
9128 return false;
9129}
9130
9132{
9133 Unit* unitCaster = m_caster->ToUnit();
9134 if (!unitCaster)
9135 return;
9136
9137 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
9138 // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
9139 // and to correctly calculate proc chance when combopoints are present
9140 Unit::AuraEffectList const& targetTriggers = unitCaster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
9141 for (AuraEffect const* aurEff : targetTriggers)
9142 {
9143 if (!aurEff->IsAffectingSpell(m_spellInfo))
9144 continue;
9145
9146 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo().TriggerSpell, GetCastDifficulty()))
9147 {
9148 // calculate the chance using spell base amount, because aura amount is not updated on combo-points change
9149 // this possibly needs fixing
9150 SpellEffectValue auraBaseAmount = aurEff->GetBaseAmount();
9151 // proc chance is stored in effect amount
9152 int32 chance = aurEff->GetSpellEffectInfo().CalcValueAsInt(unitCaster, &auraBaseAmount);
9153 chance *= aurEff->GetBase()->GetStackAmount();
9154
9155 // build trigger and add to the list
9156 m_hitTriggerSpells.emplace_back(spellInfo, aurEff->GetSpellInfo(), chance);
9157 }
9158 }
9159}
9160
9161// Global cooldowns management
9163{
9164 // Only players or controlled units have global cooldown
9165 if (caster->GetTypeId() != TYPEID_PLAYER && (caster->GetTypeId() != TYPEID_UNIT || !const_cast<WorldObject*>(caster)->ToCreature()->GetCharmInfo()))
9166 return false;
9167
9168 return true;
9169}
9170
9172{
9174 return false;
9175
9177}
9178
9180{
9182 return;
9183
9185 if (gcd == 0ms || !m_spellInfo->StartRecoveryCategory)
9186 return;
9187
9190 return;
9191
9192 constexpr Milliseconds MinGCD = 750ms;
9193 constexpr Milliseconds MaxGCD = 1500ms;
9194
9195 // Global cooldown can't leave range 1..1.5 secs
9196 // There are some spells (mostly not cast directly by player) that have < 1 sec and > 1.5 sec global cooldowns
9197 // but as tests show are not affected by any spell mods.
9198 if (gcd >= MinGCD && gcd <= MaxGCD)
9199 {
9200 // gcd modifier auras are applied only to own spells and only players have such mods
9201 if (Player* modOwner = m_caster->GetSpellModOwner())
9202 {
9203 int32 intGcd = gcd.count();
9204 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::StartCooldown, intGcd, this);
9205 gcd = Milliseconds(intGcd);
9206 }
9207
9208 bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
9212
9213 // Apply haste rating
9214 if (gcd > MinGCD && ((m_spellInfo->StartRecoveryCategory == 133 && !isMeleeOrRangedSpell)))
9215 {
9216 gcd = Milliseconds(int64(gcd.count() * m_caster->ToUnit()->m_unitData->ModSpellHaste));
9217 RoundToInterval(gcd, MinGCD, MaxGCD);
9218 }
9219
9221 {
9222 gcd = Milliseconds(int64(gcd.count() * m_caster->ToUnit()->m_unitData->ModHasteRegen));
9223 RoundToInterval(gcd, MinGCD, MaxGCD);
9224 }
9225 }
9226
9228}
9229
9231{
9233 return;
9234
9236 return;
9237
9238 // Cancel global cooldown when interrupting current cast
9240 return;
9241
9243}
9244
9245std::string Spell::GetDebugInfo() const
9246{
9247 std::stringstream sstr;
9248 sstr << std::boolalpha
9249 << "Id: " << GetSpellInfo()->Id << " Name: '" << (*GetSpellInfo()->SpellName)[sWorld->GetDefaultDbcLocale()] << "' OriginalCaster: " << m_originalCasterGUID.ToString()
9250 << " State: " << getState();
9251 return sstr.str();
9252}
9253
9258
9259bool Spell::IsWithinLOS(WorldObject const* source, WorldObject const* target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const
9260{
9262 return true;
9263
9265 return true;
9266
9267 if (target->IsCreature() && target->ToCreature()->CanIgnoreLineOfSightWhenCastingOnMe())
9268 return true;
9269
9270 WorldObject const* src = targetAsSourceLocation ? target : source;
9271 WorldObject const* dst = targetAsSourceLocation ? source : target;
9272 return src->IsWithinLOSInMap(dst, LINEOFSIGHT_ALL_CHECKS, ignoreFlags);
9273}
9274
9275bool Spell::IsWithinLOS(WorldObject const* source, Position const& target, VMAP::ModelIgnoreFlags ignoreFlags) const
9276{
9278 return true;
9279
9281 return true;
9282
9283 return source->IsWithinLOS(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), LINEOFSIGHT_ALL_CHECKS, ignoreFlags);
9284}
9285
9286void Spell::MovePosition(Position& pos, WorldObject const* from, float dist, float angle) const
9287{
9289 from->MovePosition(pos, dist, angle);
9290 else
9291 from->MovePositionToFirstCollision(pos, dist, angle);
9292}
9293
9294namespace Trinity
9295{
9296
9298 SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
9299 _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList), _objectType(objectType)
9300{
9301 if (condList)
9302 _condSrcInfo = std::make_unique<ConditionSourceInfo>(nullptr, caster);
9303}
9304
9308
9310{
9311 if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
9312 return false;
9313
9314 Unit* unitTarget = target->ToUnit();
9315 if (Corpse* corpseTarget = target->ToCorpse())
9316 {
9317 // use owner for party/assistance checks
9318 if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
9319 unitTarget = owner;
9320 else
9321 return false;
9322 }
9323
9324 Unit* refUnit = _referer->ToUnit();
9325 if (unitTarget)
9326 {
9327 // do only faction checks here
9328 switch (_targetSelectionType)
9329 {
9330 case TARGET_CHECK_ENEMY:
9331 if (unitTarget->IsTotem())
9332 return false;
9333 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9334 if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo))
9335 return false;
9336 break;
9337 case TARGET_CHECK_ALLY:
9338 if (unitTarget->IsTotem())
9339 return false;
9340 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9341 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9342 return false;
9343 break;
9344 case TARGET_CHECK_PARTY:
9345 if (!refUnit)
9346 return false;
9347 if (unitTarget->IsTotem())
9348 return false;
9349 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9350 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9351 return false;
9352 if (!refUnit->IsInPartyWith(unitTarget))
9353 return false;
9354 break;
9356 if (!refUnit)
9357 return false;
9358 if (refUnit->GetClass() != unitTarget->GetClass())
9359 return false;
9360 [[fallthrough]];
9361 case TARGET_CHECK_RAID:
9362 if (!refUnit)
9363 return false;
9364 if (unitTarget->IsTotem())
9365 return false;
9366 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9367 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9368 return false;
9369 if (!refUnit->IsInRaidWith(unitTarget))
9370 return false;
9371 break;
9373 if (!unitTarget->IsSummon())
9374 return false;
9375 if (unitTarget->ToTempSummon()->GetSummonerGUID() != _caster->GetGUID())
9376 return false;
9377 break;
9378 default:
9379 break;
9380 }
9381
9382 switch (_objectType)
9383 {
9387 if (unitTarget->IsAlive())
9388 return false;
9389 break;
9390 default:
9391 break;
9392 }
9393 }
9394
9395 if (!_condSrcInfo)
9396 return true;
9397 _condSrcInfo->mConditionTargets[0] = target;
9398 return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
9399}
9400
9402 SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9403 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(caster) { }
9404
9406{
9407 float dist = target->GetDistance(*_position);
9408 if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target))
9409 {
9410 _range = dist;
9411 return true;
9412 }
9413 return false;
9414}
9415
9417 WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType,
9418 WorldObjectSpellAreaTargetSearchReason searchReason /*= Area*/)
9419 : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList, objectType), _range(range), _position(position), _searchReason(searchReason) { }
9420
9422{
9423 if (GameObject* gameObjectTarget = target->ToGameObject())
9424 {
9425 // isInRange including the dimension of the GO
9426 bool isInRange = gameObjectTarget->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range.Max)
9427 && (_range.Min <= 0.0f || !gameObjectTarget->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range.Min));
9428 if (!isInRange)
9429 return false;
9430 }
9431 else
9432 {
9433 bool isInsideCylinder = target->IsInRange2d(_position, _range.Min, _range.Max) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range.Max;
9434 if (!isInsideCylinder)
9435 return false;
9436
9437 if (Unit* unitTarget = target->ToUnit())
9438 {
9439 switch (_searchReason)
9440 {
9442 if (!_spellInfo->HasAttribute(SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE) && unitTarget->GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity::AoETarget))
9443 return false;
9444 break;
9446 if (unitTarget->GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity::ChainTarget))
9447 return false;
9448 break;
9449 default:
9450 break;
9451 }
9452 }
9453 }
9454
9456}
9457
9458WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(Position const& coneSrc, float coneAngle, float lineWidth, SpellRange range, WorldObject* caster,
9459 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9460 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _coneSrc(coneSrc), _coneAngle(coneAngle), _lineWidth(lineWidth) { }
9461
9463{
9465 {
9466 if (_coneSrc.HasInArc(-std::abs(_coneAngle), target))
9467 return false;
9468 }
9470 {
9471 if (!_coneSrc.HasInLine(target, target->GetCombatReach(), _lineWidth))
9472 return false;
9473 }
9474 else
9475 {
9476 if (!_caster->IsUnit() || !_caster->ToUnit()->IsWithinBoundaryRadius(target->ToUnit()))
9477 // ConeAngle > 0 -> select targets in front
9478 // ConeAngle < 0 -> select targets in back
9479 if (_coneSrc.HasInArc(_coneAngle, target) != G3D::fuzzyGe(_coneAngle, 0.f))
9480 return false;
9481 }
9483}
9484
9485WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9486 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(position) { }
9487
9489{
9490 // return all targets on missile trajectory (0 - size of a missile)
9491 if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
9492 return false;
9493
9494 if (target->GetExactDist2d(_position) > _range)
9495 return false;
9496
9498}
9499
9500WorldObjectSpellLineTargetCheck::WorldObjectSpellLineTargetCheck(Position const* srcPosition, Position const* dstPosition, float lineWidth, SpellRange range, WorldObject* caster,
9501 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9502 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _position(*srcPosition), _lineWidth(lineWidth)
9503{
9504 if (dstPosition && *srcPosition != *dstPosition)
9505 _position.SetOrientation(srcPosition->GetAbsoluteAngle(dstPosition));
9506}
9507
9509{
9510 if (!_position.HasInLine(target, target->GetCombatReach(), _lineWidth))
9511 return false;
9512
9514}
9515
9516void SelectRandomInjuredTargets(std::list<WorldObject*>& targets, size_t maxTargets, bool prioritizePlayers, Unit const* prioritizeGroupMembersOf /*= nullptr*/)
9517{
9518 if (targets.size() <= maxTargets)
9519 return;
9520
9521 // Target priority states (bit indices)
9522 // higher value means lower selection priority
9523 // current list:
9524 // * injured player group members
9525 // * injured other players
9526 // * injured pets of group members
9527 // * injured other pets
9528 // * full health player group members
9529 // * full health other players
9530 // * full health pets of group members
9531 // * full health other pets
9532 enum
9533 {
9534 NOT_GROUPED,
9535 NOT_PLAYER,
9536 NOT_INJURED,
9537 END
9538 };
9539
9540 std::array<std::ptrdiff_t, 1 << END> countsByPriority = {};
9541 std::vector<std::pair<WorldObject*, int32>> tempTargets(targets.size());
9542
9543 // categorize each target
9544 std::ranges::transform(targets, tempTargets.begin(), [&](WorldObject* target)
9545 {
9546 int32 negativePoints = 0;
9547 if (prioritizeGroupMembersOf && (!target->IsUnit() || !target->ToUnit()->IsInRaidWith(prioritizeGroupMembersOf)))
9548 negativePoints |= 1 << NOT_GROUPED;
9549
9550 if (prioritizePlayers && !target->IsPlayer() && (!target->IsCreature() || !target->ToCreature()->IsTreatedAsRaidUnit()))
9551 negativePoints |= 1 << NOT_PLAYER;
9552
9553 if (!target->IsUnit() || target->ToUnit()->IsFullHealth())
9554 negativePoints |= 1 << NOT_INJURED;
9555
9556 ++countsByPriority[negativePoints];
9557 return std::make_pair(target, negativePoints);
9558 });
9559
9560 std::ranges::sort(tempTargets, {}, Trinity::TupleElement<1>);
9561
9562 std::size_t foundTargets = 0;
9563 for (std::ptrdiff_t countForPriority : countsByPriority)
9564 {
9565 if (foundTargets + countForPriority >= maxTargets)
9566 {
9567 // shuffle only the lower priority extras
9568 // example: our initial target list had 5 injured and 5 full health units and we want to select 7 targets
9569 // we always want to select 5 injured and 2 random full health ones
9570 Containers::RandomShuffle(tempTargets.begin() + foundTargets, tempTargets.begin() + foundTargets + countForPriority);
9571 break;
9572 }
9573
9574 foundTargets += countForPriority;
9575 }
9576
9577 targets.resize(maxTargets);
9578 std::ranges::transform(tempTargets.begin(), tempTargets.begin() + maxTargets, targets.begin(), Trinity::TupleElement<0>);
9579}
9580
9581void SortTargetsWithPriorityRules(std::list<WorldObject*>& targets, size_t maxTargets, std::span<TargetPriorityRule const> rules)
9582{
9583 if (targets.size() <= maxTargets)
9584 return;
9585
9586 std::vector<std::pair<WorldObject*, int32>> prioritizedTargets(targets.size());
9587
9588 // score each target based on how many rules they satisfy.
9589 std::ranges::transform(targets, prioritizedTargets.begin(), [&](WorldObject* target)
9590 {
9591 int32 score = 0;
9592 for (std::size_t i = 0; i < rules.size(); ++i)
9593 if (rules[i].Rule(target))
9594 score |= 1 << (rules.size() - 1 - i);
9595
9596 return std::make_pair(target, score);
9597 });
9598
9599 // the higher the value, the higher the priority is.
9600 std::ranges::sort(prioritizedTargets, std::ranges::greater(), Trinity::TupleElement<1>);
9601
9602 int32 tieScore = prioritizedTargets[maxTargets - 1].second;
9603
9604 // if there are ties at the cutoff, shuffle them to avoid selection bias.
9605 if (prioritizedTargets[maxTargets].second == tieScore)
9606 {
9607 auto toShuffle = std::equal_range(prioritizedTargets.begin(), prioritizedTargets.end(), std::pair<WorldObject*, int32>(nullptr, tieScore),
9608 [](std::pair<WorldObject*, int32> const& target1, std::pair<WorldObject*, int32> const& target2) { return target1.second > target2.second; });
9609
9610 // shuffle only the tied range to randomize final selection.
9611 Containers::RandomShuffle(toShuffle.first, toShuffle.second);
9612 }
9613
9614 targets.resize(maxTargets);
9615 std::ranges::transform(prioritizedTargets.begin(), prioritizedTargets.begin() + maxTargets, targets.begin(), Trinity::TupleElement<0>);
9616}
9617} //namespace Trinity
9618
9620{
9621 if (target)
9622 {
9623 if (Unit* unitTarget = target->ToUnit())
9624 {
9625 Targets.emplace();
9626 Targets->SetUnitTarget(unitTarget);
9627 }
9628 else if (GameObject* goTarget = target->ToGameObject())
9629 {
9630 Targets.emplace();
9631 Targets->SetGOTarget(goTarget);
9632 }
9633 // error when targeting anything other than units and gameobjects
9634 }
9635 else
9636 Targets.emplace(); // nullptr is allowed
9637}
9638
9645
9647{
9648 TriggeringSpell = triggeringSpell;
9649 if (triggeringSpell)
9650 {
9652 OriginalCastItemLevel = triggeringSpell->m_castItemLevel;
9653 if (!OriginalCastId)
9654 OriginalCastId = triggeringSpell->m_castId;
9655 }
9656 return *this;
9657}
9658
9659SpellCastVisual::operator UF::SpellCastVisual() const
9660{
9661 UF::SpellCastVisual visual;
9662 visual.SpellXSpellVisualID = SpellXSpellVisualID;
9663 visual.ScriptVisualID = ScriptVisualID;
9664 return visual;
9665}
9666
9667SpellCastVisual::operator WorldPackets::Spells::SpellCastVisual() const
9668{
9669 return { int32(SpellXSpellVisualID), int32(ScriptVisualID) };
9670}
#define sBattlefieldMgr
@ STATUS_WAIT_LEAVE
@ STATUS_IN_PROGRESS
@ IN_MILLISECONDS
Definition Common.h:38
@ MINUTE
Definition Common.h:32
#define M_PI
Definition Common.h:118
std::vector< Condition > ConditionContainer
#define sConditionMgr
@ CONDITION_SOURCE_TYPE_SPELL
@ CORPSE_FLAG_SKINNABLE
Definition Corpse.h:48
DB2Storage< ItemEntry > sItemStore("Item.db2", &ItemLoadInfo::Instance)
DB2Storage< BattlePetBreedQualityEntry > sBattlePetBreedQualityStore("BattlePetBreedQuality.db2", &BattlePetBreedQualityLoadInfo::Instance)
DB2Storage< ArtifactEntry > sArtifactStore("Artifact.db2", &ArtifactLoadInfo::Instance)
DB2Storage< ChrClassesEntry > sChrClassesStore("ChrClasses.db2", &ChrClassesLoadInfo::Instance)
DB2Storage< LockEntry > sLockStore("Lock.db2", &LockLoadInfo::Instance)
DB2Storage< ChrSpecializationEntry > sChrSpecializationStore("ChrSpecialization.db2", &ChrSpecializationLoadInfo::Instance)
DB2Storage< BattlePetSpeciesEntry > sBattlePetSpeciesStore("BattlePetSpecies.db2", &BattlePetSpeciesLoadInfo::Instance)
DB2Storage< SummonPropertiesEntry > sSummonPropertiesStore("SummonProperties.db2", &SummonPropertiesLoadInfo::Instance)
DB2Storage< GlyphPropertiesEntry > sGlyphPropertiesStore("GlyphProperties.db2", &GlyphPropertiesLoadInfo::Instance)
DB2Storage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore("SpellItemEnchantment.db2", &SpellItemEnchantmentLoadInfo::Instance)
DB2Storage< TalentEntry > sTalentStore("Talent.db2", &TalentLoadInfo::Instance)
DB2Storage< ItemAppearanceEntry > sItemAppearanceStore("ItemAppearance.db2", &ItemAppearanceLoadInfo::Instance)
#define sDB2Manager
Definition DB2Stores.h:579
#define MAX_LOCK_CASE
#define MAX_VEHICLE_SEATS
#define MAX_SPELL_REAGENTS
#define MAX_ITEM_ENCHANTMENT_EFFECTS
#define MAX_AZERITE_EMPOWERED_TIER
Definition DBCEnums.h:229
@ ITEM_ENCHANTMENT_TYPE_USE_SPELL
Definition DBCEnums.h:1232
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
Definition DBCEnums.h:1233
#define MAX_EFFECT_MASK
Definition DBCEnums.h:2451
#define MAX_ITEM_PROTO_SOCKETS
Definition DBCEnums.h:1213
Difficulty
Definition DBCEnums.h:935
@ DIFFICULTY_NONE
Definition DBCEnums.h:936
@ LandTargetedSpellOnTarget
#define UI64FMTD
Definition Define.h:138
#define TC_GAME_API
Definition Define.h:129
uint8_t uint8
Definition Define.h:156
int64_t int64
Definition Define.h:149
int8_t int8
Definition Define.h:152
int32_t int32
Definition Define.h:150
uint64_t uint64
Definition Define.h:153
uint32_t uint32
Definition Define.h:154
@ SPELL_DISABLE_LOS
Definition DisableMgr.h:49
@ DISABLE_TYPE_SPELL
Definition DisableMgr.h:27
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ABORT_MSG
Definition Errors.h:80
#define ABORT
Definition Errors.h:79
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:74
#define ASSERT
Definition Errors.h:72
@ GRID_MAP_TYPE_MASK_PLAYER
Definition GridDefines.h:80
@ GRID_MAP_TYPE_MASK_CREATURE
Definition GridDefines.h:77
@ GRID_MAP_TYPE_MASK_ALL
Definition GridDefines.h:84
@ GRID_MAP_TYPE_MASK_GAMEOBJECT
Definition GridDefines.h:79
@ GRID_MAP_TYPE_MASK_CORPSE
Definition GridDefines.h:76
#define sInstanceLockMgr
@ PRISMATIC_ENCHANTMENT_SLOT
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_INV_FULL
Definition ItemDefines.h:77
@ ITEM_CLASS_WEAPON
@ ITEM_CLASS_CONSUMABLE
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
@ ITEM_SUBCLASS_WEAPON_GUN
@ ITEM_SUBCLASS_WEAPON_BOW
@ ITEM_SUBCLASS_WEAPON_WAND
@ ITEM_SUBCLASS_WEAPON_THROWN
@ ITEM_SPELLTRIGGER_ON_USE
@ ITEM_FLAG_IS_MILLABLE
@ ITEM_FLAG_NO_REAGENT_COST
@ ITEM_FLAG_IS_PROSPECTABLE
@ INVTYPE_THROWN
@ INVTYPE_AMMO
@ ITEM_CHANGED
Definition Item.h:47
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition Log.h:173
#define TC_LOG_ERROR(filterType__, message__,...)
Definition Log.h:182
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true)
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true)
@ LOOT_SKINNING
Definition Loot.h:107
ZLiquidStatus
Definition MapDefines.h:133
@ LIQUID_MAP_IN_WATER
Definition MapDefines.h:137
@ LIQUID_MAP_WATER_WALK
Definition MapDefines.h:136
@ TRANSFER_ABORT_NONE
Definition Map.h:92
constexpr bool CanStopMovementForSpellCasting(MovementGeneratorType type)
@ MOVEMENTFLAG_FORWARD
@ MOVEMENTFLAG_NONE
@ MOVEMENTFLAG_STRAFE_LEFT
@ MOVEMENTFLAG_BACKWARD
@ MOVEMENTFLAG_FALLING
@ MOVEMENTFLAG_STRAFE_RIGHT
#define EXTRA_CELL_SEARCH_RADIUS
#define DEFAULT_PLAYER_BOUNDING_RADIUS
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:46
@ TYPEID_UNIT
Definition ObjectGuid.h:43
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
#define sObjectMgr
Definition ObjectMgr.h:1873
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition Optional.h:25
@ PATHFIND_NOPATH
@ PATHFIND_SHORT
@ PATHFIND_INCOMPLETE
#define PET_FOLLOW_DIST
Definition PetDefines.h:98
@ HUNTER_PET
Definition PetDefines.h:32
constexpr uint32 PET_SUMMONING_DISORIENTATION
Definition PetDefines.h:142
PetSaveMode
Definition PetDefines.h:41
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:827
@ CHEAT_COOLDOWN
Definition Player.h:1062
@ CHEAT_POWER
Definition Player.h:1063
float frand(float min, float max)
Definition Random.cpp:56
float rand_norm()
Definition Random.cpp:76
bool roll_chance(float chance, PseudoRandomDistributionState &state)
Definition Random.cpp:131
#define sScriptMgr
Definition ScriptMgr.h:1449
SpellEffIndex
@ EFFECT_1
@ SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY
@ SPELL_ATTR9_NOT_IN_ARENA
@ SPELL_ATTR9_IGNORE_DEFAULT_RATED_BATTLEGROUND_RESTRICTIONS
@ SPELL_ATTR9_ITEM_CAST_GRANTS_SKILL_GAIN
@ SPELL_ATTR9_MISSILE_SPEED_IS_DELAY_IN_SEC
@ SPELL_ATTR9_FORCE_DEST_LOCATION
@ SPELL_ATTR9_IGNORE_TOTEM_REQUIREMENTS_FOR_CASTING
@ SPELL_ATTR9_FORCE_CORPSE_TARGET
@ SPELL_ATTR9_ONLY_WHEN_ILLEGALLY_MOUNTED
MountResult
@ SPELL_ATTR7_ALWAYS_CAST_LOG
@ SPELL_ATTR7_CAN_CAUSE_INTERRUPT
@ SPELL_ATTR7_RESET_SWING_TIMER_AT_SPELL_START
@ SPELL_ATTR7_ALLOW_SPELL_REFLECTION
@ SPELL_ATTR7_TREAT_AS_NPC_AOE
@ SPELL_ATTR7_REPORT_SPELL_FAILURE_TO_UNIT_TARGET
@ SPELL_ATTR7_DEBUG_SPELL
SpellEffects
@ SPELL_EFFECT_DUMMY
@ SPELL_EFFECT_LEAP
@ SPELL_EFFECT_CREATE_HEIRLOOM_ITEM
@ SPELL_EFFECT_SUMMON_PET
@ SPELL_EFFECT_DISENCHANT
@ SPELL_EFFECT_PROSPECTING
@ SPELL_EFFECT_ENCHANT_HELD_ITEM
@ SPELL_EFFECT_GIVE_ARTIFACT_POWER_NO_BONUS
@ SPELL_EFFECT_ENCHANT_ITEM
@ SPELL_EFFECT_CREATE_LOOT
@ SPELL_EFFECT_GAMEOBJECT_REPAIR
@ SPELL_EFFECT_SUMMON_RAF_FRIEND
@ SPELL_EFFECT_WEAPON_DAMAGE
@ SPELL_EFFECT_APPLY_GLYPH
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_NORMALIZED_WEAPON_DMG
@ SPELL_EFFECT_FEED_PET
@ SPELL_EFFECT_SUMMON_PLAYER
@ SPELL_EFFECT_RESPEC_AZERITE_EMPOWERED_ITEM
@ SPELL_EFFECT_DISPEL
@ SPELL_EFFECT_MILLING
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
@ SPELL_EFFECT_ATTACK
@ SPELL_EFFECT_RESURRECT_PET
@ SPELL_EFFECT_SKIN_PLAYER_CORPSE
@ SPELL_EFFECT_RECHARGE_ITEM
@ SPELL_EFFECT_ADD_EXTRA_ATTACKS
@ SPELL_EFFECT_CHANGE_ACTIVE_COMBAT_TRAIT_CONFIG
@ SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY
@ SPELL_EFFECT_WEAPON_PERCENT_DAMAGE
@ SPELL_EFFECT_GRANT_BATTLEPET_LEVEL
@ SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_EFFECT_LEAP_BACK
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_TELEPORT_WITH_SPELL_VISUAL_KIT_LOADING_SCREEN
@ SPELL_EFFECT_ENERGIZE
@ SPELL_EFFECT_BIND
@ SPELL_EFFECT_UNLOCK_GUILD_VAULT_TAB
@ SPELL_EFFECT_CHARGE
@ SPELL_EFFECT_DISMISS_PET
@ SPELL_EFFECT_TALENT_SPEC_SELECT
@ SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE
@ TOTAL_SPELL_EFFECTS
@ SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE
@ SPELL_EFFECT_GAMEOBJECT_DAMAGE
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_GIVE_ARTIFACT_POWER
@ SPELL_EFFECT_JUMP
@ SPELL_EFFECT_HEAL_PCT
@ SPELL_EFFECT_SKINNING
@ SPELL_EFFECT_REMOVE_TALENT
@ SPELL_EFFECT_TELEPORT_UNITS
@ SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC
@ SPELL_EFFECT_CREATE_TAMED_PET
@ SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY
@ SPELL_EFFECT_OPEN_LOCK
@ SPELL_EFFECT_STEAL_BENEFICIAL_BUFF
@ SPELL_EFFECT_CREATE_ITEM
@ SPELL_EFFECT_APPLY_AURA
@ SPELL_EFFECT_LEARN_PET_SPELL
@ CLASS_DEATH_KNIGHT
#define CLASSMASK_WAND_USERS
@ SPELL_PREVENTION_TYPE_SILENCE
@ SPELL_PREVENTION_TYPE_NO_ACTIONS
@ SPELL_PREVENTION_TYPE_PACIFY
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_RITUAL
@ GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
@ SPELL_ATTR5_TREAT_AS_AREA_EFFECT
@ SPELL_ATTR5_ALLOW_WHILE_STUNNED
@ SPELL_ATTR5_ALLOW_WHILE_FLEEING
@ SPELL_ATTR5_ALWAYS_LINE_OF_SIGHT
@ SPELL_ATTR5_MELEE_CHAIN_TARGETING
@ SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT
@ SPELL_ATTR5_NOT_ON_PLAYER
@ SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED
@ SPELL_ATTR5_ALLOW_WHILE_CONFUSED
SpellTargetIndex
SpellMissInfo
@ SPELL_MISS_IMMUNE
@ SPELL_MISS_IMMUNE2
@ SPELL_MISS_NONE
@ SPELL_MISS_RESIST
@ SPELL_MISS_MISS
@ SPELL_MISS_EVADE
@ SPELL_MISS_REFLECT
@ SPELL_MISS_BLOCK
Targets
@ TARGET_UNIT_PASSENGER_1
@ TARGET_DEST_TARGET_ANY
@ TARGET_UNIT_TARGET_CHAINHEAL_ALLY
@ TARGET_DEST_CASTER_RANDOM
@ TARGET_DEST_CASTER_GROUND_2
@ TARGET_UNIT_CONE_180_DEG_ENEMY
@ TARGET_DEST_DB
@ TARGET_DEST_DYNOBJ_ENEMY
@ TARGET_DEST_DEST_TARGET_TOWARDS_CASTER
@ TARGET_UNIT_PASSENGER_6
@ TARGET_DEST_DEST_GROUND
@ TARGET_DEST_CASTER_FRONT_LEAP
@ TARGET_UNIT_CASTER_AND_PASSENGERS
@ TARGET_DEST_CHANNEL_TARGET
@ TARGET_DEST_CASTER_FRONT_LEFT
@ TARGET_DEST_CASTER_BACK_RIGHT
@ TARGET_DEST_NEARBY_DB
@ TARGET_DEST_CASTER_GROUND
@ TARGET_UNIT_SRC_AREA_FURTHEST_ENEMY
@ TARGET_UNIT_VEHICLE
@ TARGET_UNIT_CASTER_AND_SUMMONS
@ TARGET_DEST_NEARBY_ENTRY_OR_DB
@ TARGET_UNIT_AREA_THREAT_LIST
@ TARGET_UNIT_PASSENGER_2
@ TARGET_UNIT_CHANNEL_TARGET
@ TARGET_DEST_CASTER_FISHING
@ TARGET_UNIT_TARGET_TAP_LIST
@ TARGET_DEST_DEST
@ TARGET_UNIT_PASSENGER_4
@ TARGET_UNIT_PASSENGER_7
@ TARGET_DEST_TARGET_ENEMY
@ TARGET_UNIT_PET
@ TARGET_DEST_DYNOBJ_NONE
@ TARGET_DEST_DYNOBJ_ALLY
@ TARGET_UNIT_TARGET_ALLY_OR_RAID
@ TARGET_UNIT_MASTER
@ TARGET_DEST_CASTER_MOVEMENT_DIRECTION
@ TARGET_UNIT_AREA_TAP_LIST
@ TARGET_UNIT_PASSENGER_5
@ TARGET_DEST_SUMMONER
@ TARGET_UNIT_PASSENGER_3
@ TARGET_DEST_CASTER_BACK_LEFT
@ TARGET_DEST_CASTER_SUMMON
@ TARGET_DEST_CASTER
@ TARGET_UNIT_CASTER
@ TARGET_GAMEOBJECT_TARGET
@ TARGET_DEST_TARGET_ALLY
@ TARGET_GAMEOBJECT_ITEM_TARGET
@ TARGET_DEST_CASTER_FRONT_RIGHT
@ TARGET_UNIT_OWN_CRITTER
@ TARGET_UNIT_SUMMONER
@ TARGET_UNIT_PASSENGER_0
@ TARGET_DEST_HOME
SpellSchoolMask
@ SPELL_ATTR2_AUTO_REPEAT
@ SPELL_ATTR2_CHAIN_FROM_CASTER
@ SPELL_ATTR2_ENCHANT_OWN_ITEM_ONLY
@ SPELL_ATTR2_DO_NOT_REPORT_SPELL_FAILURE
@ SPELL_ATTR2_NOT_AN_ACTION
@ SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF
@ SPELL_ATTR2_INITIATE_COMBAT_POST_CAST_ENABLES_AUTO_ATTACK
@ SPELL_ATTR2_NO_ACTIVE_PETS
@ SPELL_ATTR2_IGNORE_LINE_OF_SIGHT
@ SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE
@ SPELL_ATTR2_DO_NOT_RESET_COMBAT_TIMERS
LockType
@ LOCKTYPE_LOCKPICKING
SpellAttr1
@ SPELL_ATTR1_REQUIRE_ALL_TARGETS
@ SPELL_ATTR1_IS_SELF_CHANNELLED
@ SPELL_ATTR1_TRACK_TARGET_IN_CHANNEL
@ SPELL_ATTR1_FAILURE_BREAKS_STEALTH
@ SPELL_ATTR1_IS_CHANNELLED
@ SPELL_ATTR1_NO_REFLECTION
@ SPELL_ATTR1_INITIATES_COMBAT_ENABLES_AUTO_ATTACK
@ SPELL_ATTR1_DISMISS_PET_FIRST
@ SPELL_ATTR1_DISCOUNT_POWER_ON_MISS
@ SPELL_ATTR3_TREAT_AS_PERIODIC
@ SPELL_ATTR3_ONLY_BATTLEGROUNDS
@ SPELL_ATTR3_ONLY_ON_GHOSTS
@ SPELL_ATTR3_NO_RES_TIMER
@ SPELL_ATTR3_DO_NOT_TRIGGER_TARGET_STAND
@ SPELL_ATTR3_PVP_ENABLING
@ SPELL_ATTR3_REQUIRES_MAIN_HAND_WEAPON
@ SPELL_ATTR3_REQUIRES_OFF_HAND_WEAPON
@ SPELL_ATTR3_COMPLETELY_BLOCKED
@ SPELL_ATTR3_ONLY_ON_PLAYER
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ LOCK_KEY_ITEM
@ LOCK_KEY_SKILL
@ LOCK_KEY_SPELL
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
SpellCustomErrors
@ SPELL_CUSTOM_ERROR_NONE
@ SPELL_CUSTOM_ERROR_GM_ONLY
Powers
@ MAX_POWERS
@ POWER_HEALTH
@ POWER_RUNES
@ POWER_MANA
@ SPELL_ATTR0_ONLY_INDOORS
@ SPELL_ATTR0_ONLY_OUTDOORS
@ SPELL_ATTR0_ALLOW_WHILE_MOUNTED
@ SPELL_ATTR0_COOLDOWN_ON_EVENT
@ SPELL_ATTR0_IS_ABILITY
@ SPELL_ATTR0_NO_IMMUNITIES
@ SPELL_ATTR0_CANCELS_AUTO_ATTACK_COMBAT
@ SPELL_ATTR0_USES_RANGED_SLOT
@ SPELL_ATTR0_ALLOW_CAST_WHILE_DEAD
@ SPELL_ATTR0_ONLY_STEALTHED
DiminishingLevels
@ DIMINISHING_LEVEL_1
@ LINEOFSIGHT_ALL_CHECKS
@ SPELL_ATTR12_START_COOLDOWN_ON_CAST_START
@ SPELL_ATTR12_IGNORE_CASTING_DISABLED
SpellCastResult
@ SPELL_FAILED_TARGET_NOT_LOOTED
@ SPELL_FAILED_UNIT_NOT_INFRONT
@ SPELL_FAILED_NEED_EXOTIC_AMMO
@ SPELL_FAILED_NOT_INFRONT
@ SPELL_FAILED_MOVING
@ SPELL_FAILED_STUNNED
@ GRANT_PET_LEVEL_FAIL
@ SPELL_FAILED_FISHING_TOO_LOW
@ SPELL_FAILED_CANT_BE_MILLED
@ SPELL_FAILED_NOT_MOUNTED
@ SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND
@ SPELL_FAILED_AFFECTING_COMBAT
@ SPELL_FAILED_CASTER_AURASTATE
@ SPELL_FAILED_EQUIPPED_ITEM_CLASS
@ SPELL_FAILED_WRONG_ARTIFACT_EQUIPPED
@ SPELL_FAILED_ITEM_AT_MAX_CHARGES
@ SPELL_FAILED_TARGET_NOT_PLAYER
@ SPELL_FAILED_CANT_UNTALENT
@ SPELL_FAILED_MIN_SKILL
@ SPELL_FAILED_NOT_IN_RATED_BATTLEGROUND
@ SPELL_FAILED_INTERRUPTED_COMBAT
@ SPELL_FAILED_NO_POWER
@ SPELL_FAILED_NOT_KNOWN
@ SPELL_FAILED_FOOD_LOWLEVEL
@ SPELL_FAILED_NO_SPEC
@ SPELL_FAILED_NOT_HERE
@ SPELL_FAILED_NO_LIQUID
@ SPELL_FAILED_ROOTED
@ SPELL_FAILED_GLYPH_INVALID_SPEC
@ SPELL_FAILED_ALREADY_HAVE_PET
@ SPELL_FAILED_WRONG_PET_FOOD
@ SPELL_FAILED_CUSTOM_ERROR
@ SPELL_FAILED_SUMMON_PENDING
@ SPELL_FAILED_UNKNOWN
@ SPELL_FAILED_BAD_IMPLICIT_TARGETS
@ SPELL_FAILED_TRY_AGAIN
@ SPELL_FAILED_CANT_UPGRADE_BATTLE_PET
@ SPELL_FAILED_ALREADY_HAVE_SUMMON
@ SPELL_FAILED_ALREADY_AT_FULL_POWER
@ SPELL_FAILED_NOT_TRADEABLE
@ SPELL_FAILED_ITEM_NOT_READY
@ SPELL_FAILED_TOO_SHALLOW
@ SPELL_FAILED_NOT_TRADING
@ SPELL_FAILED_NO_CHARGES_REMAIN
@ SPELL_FAILED_ITEM_GONE
@ SPELL_FAILED_NO_AMMO
@ SPELL_FAILED_ITEM_NOT_FOUND
@ SPELL_FAILED_OUT_OF_RANGE
@ SPELL_FAILED_NOT_IN_BATTLEGROUND
@ SPELL_FAILED_IMMUNE
@ SPELL_FAILED_EQUIPPED_ITEM
@ SPELL_FAILED_NOT_BEHIND
@ SPELL_FAILED_ALREADY_AT_FULL_HEALTH
@ SPELL_FAILED_PREVENTED_BY_MECHANIC
@ SPELL_FAILED_ALREADY_HAVE_CHARM
@ SPELL_FAILED_AZERITE_EMPOWERED_NO_CHOICES_TO_UNDO
@ SPELL_FAILED_HIGHLEVEL
@ SPELL_FAILED_DONT_REPORT
@ SPELL_FAILED_CANT_BE_SALVAGED_SKILL
@ SPELL_FAILED_AZERITE_EMPOWERED_ONLY
@ SPELL_FAILED_ON_USE_ENCHANT
@ SPELL_FAILED_TARGET_AURASTATE
@ SPELL_FAILED_TOTEMS
@ SPELL_FAILED_ERROR
@ SPELL_FAILED_LOWLEVEL
@ SPELL_FAILED_NOT_READY
@ SPELL_FAILED_WRONG_BATTLE_PET_TYPE
@ SPELL_FAILED_ONLY_BATTLEGROUNDS
@ SPELL_FAILED_NOT_IN_ARENA
@ SPELL_FAILED_ITEM_ALREADY_ENCHANTED
@ SPELL_FAILED_ONLY_STEALTHED
@ SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW
@ SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED
@ SPELL_FAILED_NO_ARTIFACT_EQUIPPED
@ SPELL_FAILED_REAGENTS
@ SPELL_FAILED_ONLY_ABOVEWATER
@ SPELL_FAILED_TARGETS_DEAD
@ SPELL_FAILED_AURA_BOUNCED
@ SPELL_FAILED_GLYPH_NO_SPEC
@ SPELL_FAILED_CANT_BE_CHARMED
@ SPELL_FAILED_MAX_SOCKETS
@ SPELL_FAILED_CASTER_DEAD
@ SPELL_FAILED_BAD_TARGETS
@ SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW
@ SPELL_FAILED_GLYPH_EXCLUSIVE_CATEGORY
@ SPELL_FAILED_TOO_MANY_OF_ITEM
@ SPELL_FAILED_CANT_BE_SALVAGED
@ SPELL_FAILED_CONFUSED
@ SPELL_FAILED_TARGET_UNSKINNABLE
@ SPELL_FAILED_SILENCED
@ SPELL_FAILED_NO_ACTIONS
@ SPELL_FAILED_UNIQUE_GLYPH
@ SPELL_FAILED_NEED_MORE_ITEMS
@ SPELL_FAILED_ONLY_OUTDOORS
@ SPELL_CAST_OK
@ SPELL_FAILED_NO_VALID_TARGETS
@ SPELL_FAILED_CHARMED
@ SPELL_FAILED_INVALID_GLYPH
@ SPELL_FAILED_LOW_CASTLEVEL
@ SPELL_FAILED_CANT_BE_PROSPECTED
@ SPELL_FAILED_ONLY_MOUNTED
@ SPELL_FAILED_LINE_OF_SIGHT
@ SPELL_FAILED_FLEEING
@ SPELL_FAILED_PACIFIED
@ SPELL_FAILED_VISION_OBSCURED
@ SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND
@ SPELL_FAILED_SPELL_IN_PROGRESS
@ SPELL_FAILED_NO_PET
@ SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE
@ SPELL_FAILED_REQUIRES_SPELL_FOCUS
@ SPELL_FAILED_NOPATH
@ SPELL_FAILED_TOTEM_CATEGORY
@ SPELL_FAILED_SPELL_UNAVAILABLE
@ SPELL_FAILED_REQUIRES_AREA
@ SPELL_FAILED_INTERRUPTED
@ SPELL_FAILED_ONLY_INDOORS
@ SPELL_FAILED_NOT_ON_TAXI
@ SPELL_FAILED_TARGET_FRIENDLY
AuraStateType
DiminishingReturnsType
@ DRTYPE_PLAYER
@ DRTYPE_ALL
@ SPELLFAMILY_MAGE
@ SPELL_ATTR13_PERIODIC_REFRESH_EXTENDS_DURATION
constexpr SkillType SkillByLockType(LockType locktype)
@ DISPEL_STEALTH
@ SPELL_ATTR4_BOUNCY_CHAIN_MISSILES
@ SPELL_ATTR4_IGNORE_DEFAULT_ARENA_RESTRICTIONS
@ SPELL_ATTR4_SUPPRESS_WEAPON_PROCS
@ SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET
@ SPELL_ATTR4_NOT_IN_ARENA_OR_RATED_BATTLEGROUND
@ SPELL_ATTR4_USE_FACING_FROM_SPELL
@ SPELL_ATTR4_AURA_NEVER_BOUNCES
@ SPELL_ATTR4_AURA_BOUNCE_FAILS_SPELL
@ SPELL_ATTR4_ALLOW_CAST_WHILE_CASTING
@ SUMMON_CATEGORY_PET
@ SUMMON_CATEGORY_PUPPET
@ CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES
@ SPELL_ATTR8_ONLY_PLAYERS_CAN_CAST_THIS_SPELL
@ SPELL_ATTR8_IGNORE_SANCTUARY
@ SPELL_ATTR8_HEAL_PREDICTION
@ SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE
@ SPELL_ATTR8_HASTE_AFFECTS_DURATION
@ SPELL_ATTR8_AURA_POINTS_ON_CLIENT
@ SPELL_ATTR8_REQUIRES_LOCATION_TO_BE_ON_LIQUID_SURFACE
SkillType
@ SKILL_INSCRIPTION
@ SKILL_NONE
@ SKILL_ENCHANTING
@ SKILL_JEWELCRAFTING
@ SPELL_ATTR6_ORIGINATE_FROM_CONTROLLER
@ SPELL_ATTR6_DOESNT_RESET_SWING_TIMER_IF_INSTANT
@ SPELL_ATTR6_DO_NOT_CONSUME_RESOURCES
@ SPELL_ATTR6_TAPS_IMMEDIATELY
@ AURA_REMOVE_BY_CANCEL
@ AURA_REMOVE_NONE
@ SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES
@ SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES
@ SPELL_AURA_OBS_MOD_HEALTH
@ SPELL_AURA_MOD_IGNORE_SHAPESHIFT
@ SPELL_AURA_PERIODIC_MANA_LEECH
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_MOD_NO_ACTIONS
@ SPELL_AURA_REFLECT_SPELLS
@ SPELL_AURA_PERIODIC_HEAL
@ SPELL_AURA_MOD_STUN_DISABLE_GRAVITY
@ SPELL_AURA_FLY
@ SPELL_AURA_MOD_PACIFY
@ SPELL_AURA_MOD_SILENCE
@ SPELL_AURA_ADD_TARGET_TRIGGER
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOD_GLOBAL_COOLDOWN_BY_HASTE_REGEN
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_PACIFY_SILENCE
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_PROVIDE_SPELL_FOCUS
@ SPELL_AURA_REDUCE_PUSHBACK
@ SPELL_AURA_INTERFERE_ALL_TARGETING
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_INTERFERE_ENEMY_TARGETING
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ SPELL_AURA_MOD_STUN
@ SPELLVALUE_AURA_STACK
@ SPELLVALUE_PARENT_SPELL_TARGET_COUNT
@ SPELLVALUE_PARENT_SPELL_TARGET_INDEX
@ SPELLVALUE_MAX_TARGETS
@ SPELLVALUE_DURATION
double SpellEffectValue
This is a double instead of float to be able to store full range of int32.
@ TARGET_FLAG_TRADE_ITEM
@ TARGET_FLAG_GAMEOBJECT
@ TARGET_FLAG_STRING
@ TARGET_FLAG_UNIT_ENEMY
@ TARGET_FLAG_CORPSE_ALLY
@ TARGET_FLAG_ITEM
@ TARGET_FLAG_UNIT_MINIPET
@ TARGET_FLAG_UNIT_PASSENGER
@ TARGET_FLAG_GAMEOBJECT_ITEM
@ TARGET_FLAG_DEST_LOCATION
@ TARGET_FLAG_SOURCE_LOCATION
@ TARGET_FLAG_ITEM_MASK
@ TARGET_FLAG_UNIT
@ TARGET_FLAG_UNIT_MASK
@ TARGET_FLAG_UNIT_DEAD
@ TARGET_FLAG_CORPSE_ENEMY
@ TARGET_FLAG_CORPSE_MASK
@ TARGET_FLAG_GAMEOBJECT_MASK
TriggerCastFlags
@ TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT
Will ignore equipped item requirements.
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
@ TRIGGERED_DONT_RESET_PERIODIC_TIMER
Will allow periodic aura timers to keep ticking (instead of resetting)
@ TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
Will ignore Spell and Category cooldowns.
@ TRIGGERED_CAST_DIRECTLY
In Spell::prepare, will be cast directly without setting containers for executed spell.
@ TRIGGERED_IGNORE_TARGET_CHECK
Will ignore most target checks (mostly DBC target checks)
@ TRIGGERED_IGNORE_CASTER_AURASTATE
Will ignore caster aura states including combat requirements and death state.
@ TRIGGERED_IGNORE_CAST_IN_PROGRESS
Will not check if a current cast is in progress.
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
@ TRIGGERED_IGNORE_SHAPESHIFT
Will ignore shapeshift checks.
@ TRIGGERED_IGNORE_POWER_COST
Will ignore power and reagent cost.
@ TRIGGERED_IGNORE_CAST_ITEM
Will not take away cast item or update related achievement criteria.
@ TRIGGERED_IGNORE_REAGENT_COST
Will ignore reagent cost.
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
@ TRIGGERED_DISALLOW_PROC_EVENTS
Disallows proc events from triggered spell (default)
@ TRIGGERED_IGNORE_CASTER_AURAS
Will ignore caster aura restrictions or requirements.
@ TRIGGERED_DONT_REPORT_CAST_ERROR
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ TRIGGERED_SUPPRESS_CASTER_ANIM
Will not play cast animations on caster.
@ TRIGGERED_IGNORE_CAST_TIME
Will always be instantly cast.
@ TRIGGERED_IS_TRIGGERED_MASK
Will be recognized by Spell::IsTriggered as triggered.
@ TRIGGERED_IGNORE_SET_FACING
Will not adjust facing to target (if any)
@ SPELLVALUE_DURATION_PCT
@ SPELLVALUE_BASE_POINT_END
@ SPELLVALUE_RADIUS_MOD
@ SPELLVALUE_BASE_POINT0
@ SPELLVALUE_CRIT_CHANCE
@ SPELL_FACING_FLAG_INFRONT
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
Definition SpellInfo.cpp:44
SpellTargetCheckTypes
Definition SpellInfo.h:80
@ TARGET_CHECK_PARTY
Definition SpellInfo.h:85
@ TARGET_CHECK_ENEMY
Definition SpellInfo.h:83
@ TARGET_CHECK_DEFAULT
Definition SpellInfo.h:81
@ TARGET_CHECK_SUMMONED
Definition SpellInfo.h:89
@ TARGET_CHECK_ENTRY
Definition SpellInfo.h:82
@ TARGET_CHECK_RAID_CLASS
Definition SpellInfo.h:87
@ TARGET_CHECK_ALLY
Definition SpellInfo.h:84
@ TARGET_CHECK_RAID
Definition SpellInfo.h:86
@ EFFECT_IMPLICIT_TARGET_CASTER
Definition SpellInfo.h:111
@ EFFECT_IMPLICIT_TARGET_EXPLICIT
Definition SpellInfo.h:110
@ TARGET_SELECT_CATEGORY_CONE
Definition SpellInfo.h:47
@ TARGET_SELECT_CATEGORY_AREA
Definition SpellInfo.h:48
@ TARGET_SELECT_CATEGORY_DEFAULT
Definition SpellInfo.h:44
@ TARGET_SELECT_CATEGORY_NEARBY
Definition SpellInfo.h:46
@ TARGET_SELECT_CATEGORY_NYI
Definition SpellInfo.h:43
@ TARGET_SELECT_CATEGORY_LINE
Definition SpellInfo.h:50
@ TARGET_SELECT_CATEGORY_TRAJ
Definition SpellInfo.h:49
@ TARGET_SELECT_CATEGORY_CHANNEL
Definition SpellInfo.h:45
SpellTargetObjectTypes
Definition SpellInfo.h:64
@ TARGET_OBJECT_TYPE_UNIT
Definition SpellInfo.h:68
@ TARGET_OBJECT_TYPE_CORPSE
Definition SpellInfo.h:73
@ TARGET_OBJECT_TYPE_UNIT_AND_DEST
Definition SpellInfo.h:69
@ TARGET_OBJECT_TYPE_NONE
Definition SpellInfo.h:65
@ TARGET_OBJECT_TYPE_DEST
Definition SpellInfo.h:67
@ TARGET_OBJECT_TYPE_GOBJ
Definition SpellInfo.h:70
@ TARGET_OBJECT_TYPE_CORPSE_ALLY
Definition SpellInfo.h:76
@ TARGET_OBJECT_TYPE_CORPSE_ENEMY
Definition SpellInfo.h:75
@ TARGET_OBJECT_TYPE_GOBJ_ITEM
Definition SpellInfo.h:71
@ TARGET_OBJECT_TYPE_SRC
Definition SpellInfo.h:66
@ SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER
Definition SpellInfo.h:160
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition SpellInfo.h:161
@ SPELL_ATTR0_CU_CONE_BACK
Definition SpellInfo.h:145
@ SPELL_ATTR0_CU_NEEDS_AMMO_DATA
Definition SpellInfo.h:163
@ SPELL_ATTR0_CU_CONE_LINE
Definition SpellInfo.h:146
@ SPELL_ATTR0_CU_NO_INITIAL_THREAT
Definition SpellInfo.h:148
@ TARGET_REFERENCE_TYPE_SRC
Definition SpellInfo.h:59
@ TARGET_REFERENCE_TYPE_TARGET
Definition SpellInfo.h:57
@ TARGET_REFERENCE_TYPE_LAST
Definition SpellInfo.h:58
@ TARGET_REFERENCE_TYPE_CASTER
Definition SpellInfo.h:56
@ TARGET_REFERENCE_TYPE_DEST
Definition SpellInfo.h:60
ProcFlagsSpellPhase
Definition SpellMgr.h:222
@ PROC_SPELL_PHASE_FINISH
Definition SpellMgr.h:226
@ PROC_SPELL_PHASE_NONE
Definition SpellMgr.h:223
@ PROC_SPELL_PHASE_CAST
Definition SpellMgr.h:224
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:225
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER
Definition SpellMgr.h:347
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE
Definition SpellMgr.h:346
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition SpellMgr.h:345
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:348
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition SpellMgr.h:349
#define sSpellMgr
Definition SpellMgr.h:812
ProcFlagsSpellType
Definition SpellMgr.h:211
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:212
@ PROC_SPELL_TYPE_HEAL
Definition SpellMgr.h:214
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:216
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:213
@ PROC_SPELL_TYPE_NO_DMG_HEAL
Definition SpellMgr.h:215
@ SPELL_LINK_HIT
Definition SpellMgr.h:84
@ SPELL_LINK_CAST
Definition SpellMgr.h:83
ProcFlags
Definition SpellMgr.h:91
@ PROC_FLAG_DEAL_MELEE_ABILITY
Definition SpellMgr.h:100
@ PROC_FLAG_TAKE_HARMFUL_PERIODIC
Definition SpellMgr.h:122
@ PROC_FLAG_MAIN_HAND_WEAPON_SWING
Definition SpellMgr.h:128
@ PROC_FLAG_TAKE_ANY_DAMAGE
Definition SpellMgr.h:124
@ PROC_FLAG_CAST_ENDED
Definition SpellMgr.h:141
@ PROC_FLAG_TAKE_HELPFUL_ABILITY
Definition SpellMgr.h:110
@ PROC_FLAG_DEAL_RANGED_ABILITY
Definition SpellMgr.h:106
@ PROC_FLAG_TAKE_HELPFUL_SPELL
Definition SpellMgr.h:116
@ PROC_FLAG_DEAL_HELPFUL_ABILITY
Definition SpellMgr.h:109
@ PROC_FLAG_DEAL_RANGED_ATTACK
Definition SpellMgr.h:103
@ PROC_FLAG_TAKE_HARMFUL_SPELL
Definition SpellMgr.h:119
@ PROC_FLAG_TAKE_MELEE_ABILITY
Definition SpellMgr.h:101
@ PROC_FLAG_DEAL_HARMFUL_ABILITY
Definition SpellMgr.h:112
@ PROC_FLAG_DEAL_HARMFUL_PERIODIC
Definition SpellMgr.h:121
@ PROC_FLAG_OFF_HAND_WEAPON_SWING
Definition SpellMgr.h:129
@ PROC_FLAG_DEAL_HELPFUL_SPELL
Definition SpellMgr.h:115
@ PROC_FLAG_DEAL_HELPFUL_PERIODIC
Definition SpellMgr.h:126
@ PROC_FLAG_DEAL_HARMFUL_SPELL
Definition SpellMgr.h:118
@ PROC_FLAG_TAKE_RANGED_ABILITY
Definition SpellMgr.h:107
@ PROC_FLAG_TAKE_HELPFUL_PERIODIC
Definition SpellMgr.h:145
@ PROC_FLAG_TAKE_RANGED_ATTACK
Definition SpellMgr.h:104
@ PROC_FLAG_NONE
Definition SpellMgr.h:92
@ PROC_FLAG_TAKE_HARMFUL_ABILITY
Definition SpellMgr.h:113
@ PROC_FLAG_2_CAST_SUCCESSFUL
Definition SpellMgr.h:192
ProcFlagsHit
Definition SpellMgr.h:233
@ PROC_HIT_NONE
Definition SpellMgr.h:234
@ PROC_HIT_IMMUNE
Definition SpellMgr.h:243
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:236
@ PROC_HIT_NORMAL
Definition SpellMgr.h:235
@ PROC_HIT_REFLECT
Definition SpellMgr.h:246
SpellScriptHookType
@ SPELL_SCRIPT_HOOK_AFTER_CAST
@ SPELL_SCRIPT_HOOK_EFFECT_HIT
@ SPELL_SCRIPT_HOOK_AFTER_HIT
@ SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL
@ SPELL_SCRIPT_HOOK_CALC_HEALING
@ SPELL_SCRIPT_HOOK_EFFECT_LAUNCH
@ SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT
@ SPELL_SCRIPT_HOOK_BEFORE_HIT
@ SPELL_SCRIPT_HOOK_CALC_DAMAGE
@ SPELL_SCRIPT_HOOK_CHECK_CAST
@ SPELL_SCRIPT_HOOK_EFFECT_LAUNCH_TARGET
@ SPELL_SCRIPT_HOOK_CALC_CAST_TIME
@ SPELL_SCRIPT_HOOK_EMPOWER_STAGE_COMPLETED
@ SPELL_SCRIPT_HOOK_EMPOWER_COMPLETED
@ SPELL_SCRIPT_HOOK_HIT
@ SPELL_SCRIPT_HOOK_BEFORE_CAST
@ SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION
@ SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT
@ SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT
@ SPELL_SCRIPT_HOOK_EFFECT_HIT_TARGET
@ SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE
@ SPELL_SCRIPT_HOOK_ON_CAST
@ SPELL_SCRIPT_HOOK_ON_PRECAST
bool CanHaveGlobalCooldown(WorldObject const *caster)
Definition Spell.cpp:9162
static std::pair< SpellEffectValue, SpellHealPredictionType > CalcPredictedHealing(SpellInfo const *spellInfo, Unit const *unitCaster, Unit *target, uint32 castItemEntry, int32 castItemLevel, Spell *spell, bool withPeriodic)
Definition Spell.cpp:4979
void FillSpellCastFailedArgs(T &packet, ObjectGuid castId, SpellInfo const *spellInfo, SpellCastResult result, SpellCustomErrors customError, int32 *param1, int32 *param2, ObjectGuid const &failedBy)
Definition Spell.cpp:4454
float tangent(float x)
Definition Spell.cpp:1866
NonDefaultConstructible< SpellEffectHandlerFn > SpellEffectHandlers[TOTAL_SPELL_EFFECTS]
#define SPELL_EMPOWER_HARDCODED_GCD
Definition Spell.h:89
@ SPELL_CAST_SOURCE_NORMAL
Definition Spell.h:168
@ SPELL_RANGE_MELEE
Definition Spell.h:187
@ SPELL_RANGE_RANGED
Definition Spell.h:188
#define MAX_SPELL_RANGE_TOLERANCE
Definition Spell.h:85
@ CAST_FLAG_EX_SUPPRESS_CASTER_ANIM
Definition Spell.h:159
@ CAST_FLAG_EX_DONT_CONSUME_CHARGES
Definition Spell.h:133
@ CAST_FLAG_EX_IGNORE_COOLDOWN
Definition Spell.h:140
SpellEffectHandleMode
Definition Spell.h:265
@ SPELL_EFFECT_HANDLE_LAUNCH_TARGET
Definition Spell.h:267
@ SPELL_EFFECT_HANDLE_LAUNCH
Definition Spell.h:266
@ SPELL_EFFECT_HANDLE_HIT
Definition Spell.h:268
@ SPELL_EFFECT_HANDLE_HIT_TARGET
Definition Spell.h:269
#define AOE_DAMAGE_TARGET_CAP
Definition Spell.h:87
SpellState
Definition Spell.h:255
@ SPELL_STATE_CHANNELING
Definition Spell.h:259
@ SPELL_STATE_NULL
Definition Spell.h:256
@ SPELL_STATE_FINISHED
Definition Spell.h:260
@ SPELL_STATE_PREPARING
Definition Spell.h:257
@ SPELL_STATE_LAUNCHED
Definition Spell.h:258
@ SPELL_STATE_IDLE
Definition Spell.h:261
static const uint32 SPELL_INTERRUPT_NONPLAYER
Definition Spell.h:274
@ CAST_FLAG_ADJUST_MISSILE
Definition Spell.h:111
@ CAST_FLAG_HEAL_PREDICTION
Definition Spell.h:124
@ CAST_FLAG_FROM_CLIENT
Definition Spell.h:112
@ CAST_FLAG_UNKNOWN_9
Definition Spell.h:102
@ CAST_FLAG_PROJECTILE
Definition Spell.h:99
@ CAST_FLAG_POWER_LEFT_SELF
Definition Spell.h:105
@ CAST_FLAG_HAS_TRAJECTORY
Definition Spell.h:95
@ CAST_FLAG_RUNE_LIST
Definition Spell.h:115
@ CAST_FLAG_PENDING
Definition Spell.h:94
@ CAST_FLAG_IMMUNITY
Definition Spell.h:120
#define TRAJECTORY_MISSILE_SIZE
Definition Spell.h:86
#define SPELL_EMPOWER_HOLD_TIME_AT_MAX
Definition Spell.h:88
SpellHealPredictionType
Definition Spell.h:177
@ SPELL_HEAL_PREDICTION_TARGET_AND_BEACON
Definition Spell.h:180
@ SPELL_HEAL_PREDICTION_TARGET
Definition Spell.h:178
@ SPELL_HEAL_PREDICTION_TARGET_PARTY
Definition Spell.h:181
@ SPELL_HEAL_PREDICTION_TARGET_AND_CASTER
Definition Spell.h:179
uint32 getMSTime()
Definition Timer.h:33
@ TRADE_SLOT_NONTRADED
Definition TradeData.h:27
@ UNIT_FLAG2_ALLOW_CHEAT_SPELLS
@ UNIT_FLAG2_NO_ACTIONS
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:42
@ DIRECT_DAMAGE
@ NODAMAGE
@ SPELL_DIRECT_DAMAGE
@ UNIT_FLAG_STUNNED
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_POSSESSED
@ UNIT_FLAG_IMMUNE
@ UNIT_FLAG_PACIFIED
@ UNIT_FLAG_CONFUSED
@ UNIT_FLAG_FLEEING
@ UNIT_FLAG_PLAYER_CONTROLLED
@ UNIT_FLAG_SKINNABLE
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition Unit.cpp:10475
@ UNIT_MASK_PUPPET
Definition Unit.h:376
@ JUST_DIED
Definition Unit.h:267
CurrentSpellTypes
Definition Unit.h:608
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:611
@ CURRENT_GENERIC_SPELL
Definition Unit.h:610
@ CURRENT_MELEE_SPELL
Definition Unit.h:609
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:612
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:289
@ UNIT_STATE_ROOT
Definition Unit.h:285
@ UNIT_STATE_CASTING
Definition Unit.h:290
@ NULL_BAG
Definition Unit.h:63
@ NULL_SLOT
Definition Unit.h:64
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition Unit.h:38
float DegToRad(float degrees)
Definition Util.cpp:880
T AddPct(T &base, U pct)
Definition Util.h:85
T RoundToInterval(T &num, T floor, T ceil)
Definition Util.h:97
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:565
T CalculatePct(T base, U pct)
Definition Util.h:72
#define VMAP_INVALID_HEIGHT_VALUE
Definition VMapManager.h:71
Aura * GetBase() const
Definition SpellAuras.h:82
SpellInfo const * GetSpellInfo() const
bool IsPeriodic() const
Aura * GetBase() const
UnitAura * ToUnitAura()
Definition SpellAuras.h:348
int32 GetMaxDuration() const
Definition SpellAuras.h:217
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
int32 GetCastItemLevel() const
Definition SpellAuras.h:190
Trinity::IteratorPair< DBStorageIterator< AuraEffect * > > GetAuraEffects()
Definition SpellAuras.h:362
int32 GetDuration() const
Definition SpellAuras.h:222
int32 CalcMaxDuration() const
Definition SpellAuras.h:219
void SetDuration(int32 duration, bool withMods=false)
ObjectGuid GetCastItemGUID() const
Definition SpellAuras.h:188
uint32 GetEffectMask() const
void SetMaxDuration(int32 duration)
Definition SpellAuras.h:218
static uint32 BuildEffectMaskForOwner(SpellInfo const *spellProto, uint32 availableEffectMask, WorldObject *owner)
bool IsPassive() const
uint32 GetSelectedAzeritePower(int32 tier) const
bool IsUnit() const
Definition BaseEntity.h:171
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
bool IsInWorld() const
Definition BaseEntity.h:158
bool IsCorpse() const
Definition BaseEntity.h:176
bool IsCreature() const
Definition BaseEntity.h:172
bool IsPlayer() const
Definition BaseEntity.h:173
TypeID GetTypeId() const
Definition BaseEntity.h:166
virtual void Abort(uint64)
virtual bool IsDeletable() const
virtual bool Execute(uint64, uint32)
BattlePet * GetPet(ObjectGuid guid)
bool CanFlyIn()
Return if we can use mount in battlefield.
bool HasHeirloom(uint32 itemId) const
void InheritCombatStatesFrom(Unit const *who)
bool HasCorpseFlag(CorpseFlags flags) const
Definition Corpse.h:96
ObjectGuid GetOwnerGUID() const override
Definition Corpse.h:108
virtual void SpellHitTarget(WorldObject *, SpellInfo const *)
Definition CreatureAI.h:135
bool CanIgnoreLineOfSightWhenCastingOnMe() const
Definition Creature.h:241
Loot * GetLootForPlayer(Player const *player) const override
void SetSpellFocus(Spell const *focusSpell, WorldObject const *target)
CreatureAI * AI() const
Definition Creature.h:235
constexpr bool HasFlag(T flag) const
Definition EnumFlag.h:106
void AddEvent(BasicEvent *event, Milliseconds e_time, bool set_addtime=true)
void ModifyEventTime(BasicEvent *event, Milliseconds newTime)
Milliseconds CalculateTime(Milliseconds t_offset) const
virtual void SpellHit(WorldObject *, SpellInfo const *)
virtual void SpellHitTarget(WorldObject *, SpellInfo const *)
GameObjectTemplate const * GetGOInfo() const
Definition GameObject.h:209
GameObjectAI * AI() const
Definition GameObject.h:390
GameobjectTypes GetGoType() const
Definition GameObject.h:288
Definition Guild.h:329
Definition Item.h:185
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition Item.cpp:1258
std::span< ItemEffectEntry const *const > GetEffects() const
Definition Item.h:370
uint32 GetSocketColor(uint32 index) const
Definition Item.h:359
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:314
bool IsVellum() const
Definition Item.h:350
bool IsLocked() const
Definition Item.h:267
ItemTemplate const * GetTemplate() const
Definition Item.cpp:1233
bool IsBroken() const
Definition Item.h:273
Optional< uint16 > GetDisenchantSkillRequired() const
Definition Item.cpp:2428
void SetSpellCharges(ItemEffectEntry const *effect, int32 value)
Definition Item.cpp:632
Player * GetOwner() const
Definition Item.cpp:1238
ObjectGuid GetOwnerGUID() const
Definition Item.h:203
uint32 GetDisplayId(Player const *owner) const
Definition Item.cpp:2480
uint32 GetItemLevel(Player const *owner) const
Definition Item.cpp:2283
uint32 GetCount() const
Definition Item.h:289
AzeriteEmpoweredItem * ToAzeriteEmpoweredItem()
Definition Item.h:261
int32 GetRequiredLevel() const
Definition Item.cpp:2896
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition Item.cpp:1477
int32 GetSpellCharges(ItemEffectEntry const *effect=nullptr) const
Definition Item.cpp:623
bool HaveLootFor(uint32 loot_id) const
Definition LootMgr.h:92
Definition Map.h:227
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition Map.cpp:2555
ZLiquidStatus GetLiquidStatus(PhaseShift const &phaseShift, float x, float y, float z, Optional< map_liquidHeaderTypeFlags > ReqLiquidType={}, LiquidData *data=nullptr, float collisionHeight=2.03128f)
Definition Map.cpp:1704
bool IsBattleground() const
Definition Map.cpp:3395
ObjectGuid::LowType GenerateLowGuid()
Definition Map.h:564
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:3588
Difficulty GetDifficultyID() const
Definition Map.h:363
InstanceMap * ToInstanceMap()
Definition Map.h:495
MovementGeneratorType GetCurrentMovementGeneratorType() const
static ObjectGuid const Empty
Definition ObjectGuid.h:314
static std::string_view GetTypeName(HighGuid high)
bool IsAnyTypeGameObject() const
Definition ObjectGuid.h:377
bool IsCorpse() const
Definition ObjectGuid.h:374
bool IsEmpty() const
Definition ObjectGuid.h:362
bool IsUnit() const
Definition ObjectGuid.h:370
std::string ToString() const
bool IsGameObject() const
Definition ObjectGuid.h:372
static ObjectGuid const TradeItem
Definition ObjectGuid.h:317
void Clear()
Definition ObjectGuid.h:329
Corpse * ToCorpse()
Definition Object.h:136
Player * ToPlayer()
Definition Object.h:126
GameObject * ToGameObject()
Definition Object.h:131
uint32 GetEntry() const
Definition Object.h:89
Creature * ToCreature()
Definition Object.h:121
Unit * ToUnit()
Definition Object.h:116
std::array< Optional< PetInfo >, MAX_ACTIVE_PETS > ActivePets
Definition PetDefines.h:169
Definition Pet.h:40
Player * GetOwner() const
Definition Pet.cpp:1809
static std::pair< PetStable::PetInfo const *, PetSaveMode > GetLoadPetInfo(PetStable const &stable, uint32 petEntry, uint32 petnumber, Optional< PetSaveMode > slot)
Definition Pet.cpp:105
PetType getPetType() const
Definition Pet.h:51
bool HaveInDiet(ItemTemplate const *item) const
Definition Pet.cpp:1101
static PhaseShift const & GetAlwaysVisiblePhaseShift()
ChrSpecialization GetPrimarySpecialization() const
Definition Player.h:1993
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13048
void SetSpellModTakingSpell(Spell *spell, bool apply)
Definition Player.cpp:22967
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2060
bool HasItemFitToSpellRequirements(SpellInfo const *spellInfo, Item const *ignoreItem=nullptr) const
Definition Player.cpp:26152
ObjectGuid GetSummonedBattlePetGUID() const
Definition Player.h:2979
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition Player.cpp:1548
void SetRuneCooldown(uint8 index, uint32 cooldown)
Definition Player.cpp:27063
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6193
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5920
bool CanTameExoticPets() const
Definition Player.h:2482
uint32 GetRuneBaseCooldown() const
Definition Player.cpp:27051
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition Player.cpp:9824
bool HasCurrency(uint32 id, uint32 amount) const
Definition Player.cpp:7341
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition Player.cpp:26930
bool InBattleground() const
Definition Player.h:2570
Item * GetItemByEntry(uint32 entry, ItemSearchLocation where=ItemSearchLocation::Default) const
Definition Player.cpp:12393
std::vector< uint32 > const & GetGlyphs(uint8 spec) const
Definition Player.h:2030
PetStable * GetPetStable()
Definition Player.h:1339
bool IsLoading() const override
Definition Player.cpp:17925
Pet * GetPet() const
Definition Player.cpp:22007
Guild * GetGuild()
Definition Player.cpp:30428
bool HasItemTotemCategory(uint32 TotemCategory) const
Definition Player.cpp:9983
uint8 GetRunesState() const
Definition Player.cpp:27046
bool GetCommandStatus(uint32 command) const
Definition Player.h:1323
bool HasSummonPending() const
Definition Player.cpp:26000
WorldSession * GetSession() const
Definition Player.h:2256
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:8591
bool CanNoReagentCast(SpellInfo const *spellInfo) const
Definition Player.cpp:26217
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition Player.cpp:12140
uint32 GetRuneCooldown(uint8 index) const
Definition Player.h:2818
void SendTameFailure(PetTameResult result)
Definition Player.cpp:22168
Battleground * GetBattleground() const
Definition Player.cpp:25650
TradeData * GetTradeData() const
Definition Player.h:1640
uint32 GetFreeInventorySlotCount(EnumFlag< ItemSearchLocation > location=ItemSearchLocation::Inventory) const
Definition Player.cpp:9391
bool IsGameMaster() const
Definition Player.h:1293
void RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Definition Player.cpp:7181
uint8 GetActiveTalentGroup() const
Definition Player.h:1995
Player * GetSelectedPlayer() const
Definition Player.cpp:24852
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9577
bool HasSpell(uint32 spell) const override
Definition Player.cpp:3626
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9522
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:24056
Spell * m_spellModTakingSpell
Definition Player.h:2847
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition Player.cpp:9970
bool HasEnoughMoney(uint64 amount) const
Definition Player.h:1892
ProcReflectDelayed(Unit *owner, ObjectGuid casterGuid)
Definition Spell.cpp:2415
bool Execute(uint64, uint32) override
Definition Spell.cpp:2417
ObjectGuid _casterGuid
Definition Spell.cpp:2435
void SetPitch(float pitch)
SpellDestination const * GetSrc() const
Definition Spell.cpp:292
void SetItemTarget(Item *item)
Definition Spell.cpp:263
void RemoveObjectTarget()
Definition Spell.cpp:256
ObjectGuid m_objectTargetGUID
WorldObject * GetObjectTarget() const
Definition Spell.cpp:246
ObjectGuid GetUnitTargetGUID() const
Definition Spell.cpp:178
void ModDst(Position const &pos)
Definition Spell.cpp:371
GameObject * GetGOTarget() const
Definition Spell.cpp:212
void SetTradeItemTarget(Player *caster)
Definition Spell.cpp:274
SpellDestination m_dst
bool HasSrc() const
Definition Spell.cpp:388
bool HasTraj() const
Corpse * GetCorpseTarget() const
Definition Spell.cpp:238
void SetDst(float x, float y, float z, float orientation, uint32 mapId=MAPID_INVALID)
Definition Spell.cpp:341
void SetSpeed(float speed)
void SetSrc(float x, float y, float z)
Definition Spell.cpp:302
void SetTargetFlag(SpellCastTargetFlags flag)
SpellDestination const * GetDst() const
Definition Spell.cpp:331
void SetGOTarget(GameObject *target)
Definition Spell.cpp:220
std::string m_strTarget
void UpdateTradeSlotItem()
Definition Spell.cpp:283
SpellDestination m_src
ObjectGuid GetCorpseTargetGUID() const
Definition Spell.cpp:230
ObjectGuid GetObjectTargetGUID() const
Definition Spell.cpp:251
void SetUnitTarget(Unit *target)
Definition Spell.cpp:194
bool HasDst() const
Definition Spell.cpp:393
ObjectGuid GetItemTargetGUID() const
WorldObject * m_objectTarget
Item * GetItemTarget() const
uint32 GetTargetMask() const
uint32 GetItemTargetEntry() const
Unit * GetUnitTarget() const
Definition Spell.cpp:186
ObjectGuid m_itemTargetGUID
float GetSpeedXY() const
float GetDist2d() const
void Update(WorldObject *caster)
Definition Spell.cpp:398
void ModSrc(Position const &pos)
Definition Spell.cpp:320
void RemoveDst()
Definition Spell.cpp:383
void Write(WorldPackets::Spells::SpellTargetData &data)
Definition Spell.cpp:144
void RemoveSrc()
Definition Spell.cpp:326
float GetPitch() const
Position const * GetSrcPos() const
Definition Spell.cpp:297
ObjectGuid GetGOTargetGUID() const
Definition Spell.cpp:204
WorldLocation const * GetDstPos() const
Definition Spell.cpp:336
float PositionFacing
Definition SpellInfo.h:227
bool HasRadius(SpellTargetIndex targetIndex) const
SpellEffectValue CalcValue(WorldObject const *caster=nullptr, SpellEffectValue const *basePoints=nullptr, Unit const *target=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
AuraType ApplyAuraName
Definition SpellInfo.h:216
uint32 TriggerSpell
Definition SpellInfo.h:234
uint32 GetMissingTargetMask(bool srcSet=false, bool dstSet=false, uint32 mask=0) const
SpellEffects Effect
Definition SpellInfo.h:215
bool IsAreaAuraEffect() const
std::shared_ptr< std::vector< Condition > > ImplicitTargetConditions
Definition SpellInfo.h:237
bool IsEffect() const
bool IsTargetingArea() const
SpellEffectImplicitTargetTypes GetImplicitTargetType() const
int32 CalcValueAsInt(WorldObject const *caster=nullptr, SpellEffectValue const *basePoints=nullptr, Unit const *target=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
SpellRange CalcRadius(WorldObject const *caster=nullptr, SpellTargetIndex targetIndex=SpellTargetIndex::TargetA, Spell *spell=nullptr) const
EnumFlag< SpellEffectAttributes > EffectAttributes
Definition SpellInfo.h:238
SpellEffIndex EffectIndex
Definition SpellInfo.h:214
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:228
SpellImplicitTargetInfo TargetB
Definition SpellInfo.h:229
bool IsDeletable() const override
Definition Spell.cpp:8479
Trinity::unique_trackable_ptr< Spell > m_Spell
Definition Spell.cpp:470
std::string GetDebugInfo() const
Definition Spell.cpp:467
void Abort(uint64 e_time) override
Definition Spell.cpp:8472
Trinity::unique_weak_ptr< Spell > GetSpellWeakPtr() const
Definition Spell.cpp:465
SpellEvent(Spell *spell)
Definition Spell.cpp:8361
bool Execute(uint64 e_time, uint32 p_time) override
Definition Spell.cpp:8378
Spell const * GetSpell() const
Definition Spell.cpp:464
void HandleCooldowns(SpellInfo const *spellInfo, uint32 itemId, Spell *spell=nullptr)
bool HasGlobalCooldown(SpellInfo const *spellInfo) const
void ResetCooldown(uint32 spellId, bool update=false)
bool IsReady(SpellInfo const *spellInfo, uint32 itemId=0) const
void AddGlobalCooldown(SpellInfo const *spellInfo, Duration duration)
void RestoreCharge(uint32 chargeCategoryId)
bool HasCooldownOnHold(uint32 spellId) const
void CancelGlobalCooldown(SpellInfo const *spellInfo)
bool HasCooldown(SpellInfo const *spellInfo, uint32 itemId=0) const
SpellTargetCheckTypes GetCheckType() const
Definition SpellInfo.cpp:98
SpellTargetReferenceTypes GetReferenceType() const
Definition SpellInfo.cpp:88
SpellTargetSelectionCategories GetSelectionCategory() const
Definition SpellInfo.cpp:83
SpellTargetObjectTypes GetObjectType() const
Definition SpellInfo.cpp:93
float CalcDirectionAngle() const
Targets GetTarget() const
uint32 RequiresSpellFocus
Definition SpellInfo.h:356
uint32 MaxLevel
Definition SpellInfo.h:387
uint32 SpellLevel
Definition SpellInfo.h:389
std::array< int32, MAX_SPELL_TOTEMS > Totem
Definition SpellInfo.h:397
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition SpellInfo.h:399
SpellRange GetMinMaxRange(bool positive=false, WorldObject const *caster=nullptr, Spell *spell=nullptr) const
uint32 PreventionType
Definition SpellInfo.h:417
uint32 CasterAuraSpell
Definition SpellInfo.h:362
float Width
Definition SpellInfo.h:411
Optional< SpellPowerCost > CalcPowerCost(Powers powerType, bool optionalCost, WorldObject const *caster, SpellSchoolMask schoolMask, Spell *spell=nullptr) const
float GetMaxRange(bool positive=false, WorldObject const *caster=nullptr, Spell *spell=nullptr) const
SpellCastResult CheckShapeshift(uint32 form) const
std::array< uint16, MAX_SPELL_TOTEMS > TotemCategory
Definition SpellInfo.h:398
bool IsRequiringDeadTarget() const
uint32 const Id
Definition SpellInfo.h:328
int32 NumNonDiminishedTargets
Definition SpellInfo.h:437
uint64 GetMechanicImmunityMask(Unit const *caster) const
float MinDuration
Definition SpellInfo.h:395
std::vector< Milliseconds > EmpowerStageThresholds
Definition SpellInfo.h:422
std::array< int16, MAX_SPELL_REAGENTS > ReagentCount
Definition SpellInfo.h:400
bool IsCooldownStartedOnEvent() const
EnumFlag< SpellAuraInterruptFlags > ChannelInterruptFlags
Definition SpellInfo.h:379
bool IsPassive() const
uint32 StackAmount
Definition SpellInfo.h:396
::Difficulty const Difficulty
Definition SpellInfo.h:329
SpellRangeEntry const * RangeEntry
Definition SpellInfo.h:392
bool IsAutoShot() const
uint32 CalcCastTime(Spell *spell=nullptr) const
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const *player=nullptr) const
uint32 GetRecoveryTime() const
DiminishingReturnsType GetDiminishingReturnsGroupType() const
bool HasHitDelay() const
uint32 ExcludeCasterAuraState
Definition SpellInfo.h:360
float Speed
Definition SpellInfo.h:393
int32 GetMaxDuration() const
int32 EquippedItemClass
Definition SpellInfo.h:402
bool HasInitialAggro() const
DiminishingGroup GetDiminishingReturnsGroupForSpell() const
uint32 SchoolMask
Definition SpellInfo.h:419
uint32 CasterAuraState
Definition SpellInfo.h:358
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
EnumFlag< SpellInterruptFlags > InterruptFlags
Definition SpellInfo.h:376
flag128 SpellFamilyFlags
Definition SpellInfo.h:415
bool IsAllowingDeadTarget() const
float LaunchDelay
Definition SpellInfo.h:394
WeaponAttackType GetAttackType() const
SpellSchoolMask GetSchoolMask() const
std::vector< SpellReagentsCurrencyEntry const * > ReagentsCurrency
Definition SpellInfo.h:401
bool IsChanneled() const
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:456
bool IsNextMeleeSwingSpell() const
uint32 ChargeCategoryId
Definition SpellInfo.h:420
bool SpellCancelsAuraEffect(AuraEffect const *aurEff) const
uint32 IconFileDataId
Definition SpellInfo.h:405
uint32 MaxAffectedTargets
Definition SpellInfo.h:413
int32 GetDuration() const
SpellCastResult CheckVehicle(Unit const *caster) const
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:590
std::vector< SpellEffectInfo > const & GetEffects() const
Definition SpellInfo.h:589
int32 EquippedItemSubClassMask
Definition SpellInfo.h:403
bool IsEmpowerSpell() const
uint32 GetExplicitTargetMask() const
uint32 FacingCasterFlags
Definition SpellInfo.h:357
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
uint32 StartRecoveryTime
Definition SpellInfo.h:374
LocalizedString const * SpellName
Definition SpellInfo.h:409
bool NeedsExplicitUnitTarget() const
EnumFlag< SpellAuraInterruptFlags2 > ChannelInterruptFlags2
Definition SpellInfo.h:380
struct SpellInfo::@328 SqrtDamageAndHealingDiminishing
bool HasEffect(SpellEffects effect) const
AuraType ExcludeCasterAuraType
Definition SpellInfo.h:368
bool IsPositive() const
bool IsAutoRepeatRangedSpell() const
bool IsMoveAllowedChannel() const
uint32 DmgClass
Definition SpellInfo.h:416
AuraType CasterAuraType
Definition SpellInfo.h:366
uint32 ExcludeCasterAuraSpell
Definition SpellInfo.h:364
bool HasAura(AuraType aura) const
bool IsTargetingArea() const
uint32 StartRecoveryCategory
Definition SpellInfo.h:373
int32 MaxTargets
Definition SpellInfo.h:436
uint32 CategoryId
Definition SpellInfo.h:330
float ConeAngle
Definition SpellInfo.h:410
uint32 SpellFamilyName
Definition SpellInfo.h:414
bool IsPositiveEffect(uint8 effIndex) const
bool CanBeUsedInCombat(Unit const *caster) const
Definition Spell.h:277
SpellState getState() const
Definition Spell.h:550
void CheckDst()
Definition Spell.cpp:7271
SpellScript * GetScriptByType(std::type_info const &type) const
Definition Spell.cpp:9106
SpellInfo const * GetSpellInfo() const
Definition Spell.h:702
float m_damageMultipliers[MAX_SPELL_EFFECTS]
Definition Spell.h:794
SpellCastResult CheckItems(int32 *param1, int32 *param2) const
Definition Spell.cpp:7436
bool m_fromClient
Definition Spell.h:606
void CallScriptAfterCastHandlers()
Definition Spell.cpp:8822
std::vector< SpellPowerCost > m_powerCost
Definition Spell.h:757
uint32 m_castFlagsEx
Definition Spell.h:607
void AddCorpseTarget(Corpse *target, uint32 effectMask)
Definition Spell.cpp:2638
void RefundRunePower()
Definition Spell.cpp:5599
uint64 CalculateDelayMomentForDst(float launchDelay) const
Definition Spell.cpp:880
GameObject * SearchSpellFocus()
Definition Spell.cpp:2325
bool CheckSpellCancelsStun(int32 *param1) const
Definition Spell.cpp:7111
std::vector< SpellScript * > m_loadedScripts
Definition Spell.h:961
void SendInterrupted(SpellCastResult result, Optional< SpellCastResult > resultOther={}, ObjectGuid const &failedBy=ObjectGuid::Empty)
Definition Spell.cpp:5177
GameObject * gameObjTarget
Definition Spell.h:799
void PrepareTriggersExecutedOnHit()
Definition Spell.cpp:9131
SpellMissInfo targetMissInfo
Definition Spell.h:804
bool m_referencedFromCurrentSpell
Definition Spell.h:791
bool m_canReflect
Definition Spell.h:760
void ExecuteLogEffectTakeTargetPower(SpellEffects effect, Unit *target, Powers powerType, uint32 points, float amplitude)
Definition Spell.cpp:5087
void PreprocessSpellLaunch(TargetInfo &targetInfo)
Definition Spell.cpp:8529
void UpdateDelayMomentForUnitTarget(Unit *unit, uint64 hitDelay)
Definition Spell.cpp:918
bool CheckSpellCancelsNoActions(int32 *param1) const
Definition Spell.cpp:7139
bool HasPowerTypeCost(Powers power) const
Definition Spell.cpp:8088
Unit * m_originalCaster
Definition Spell.h:751
void LoadScripts()
Definition Spell.cpp:8778
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction &healPrediction, bool withPeriodic)
Definition Spell.cpp:5025
void SelectImplicitTrajTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1878
DynObjAura * _dynObjAura
Definition Spell.h:811
void RefundPower()
Definition Spell.cpp:5506
uint32 m_channelTargetEffectMask
Definition Spell.h:879
void cast(bool skipCheck=false)
Definition Spell.cpp:3679
void SendChannelStart(uint32 duration)
Definition Spell.cpp:5240
uint64 m_delayStart
Definition Spell.h:785
int64 GetCorpseTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2736
SpellCastTargets m_targets
Definition Spell.h:651
void SelectImplicitNearbyTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition Spell.cpp:1089
static bool CanIncreaseRangeByMovement(Unit const *unit)
Definition Spell.cpp:7325
std::unique_ptr< PathGenerator > m_preGeneratedPath
Definition Spell.h:1001
Difficulty GetCastDifficulty() const
Definition Spell.cpp:8172
void CallScriptBeforeHitHandlers(SpellMissInfo missInfo)
Definition Spell.cpp:8921
SpellCastResult CheckRuneCost() const
Definition Spell.cpp:5545
void ExecuteLogEffectExtraAttacks(SpellEffects effect, Unit *victim, uint32 numAttacks)
Definition Spell.cpp:5099
void CallScriptCalcDamageHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &damage, int32 &flatMod, float &pctMod)
Definition Spell.cpp:8970
void SelectExplicitTargets()
Definition Spell.cpp:691
void handle_immediate()
Definition Spell.cpp:3997
void SendSpellGo()
Definition Spell.cpp:4776
int32 m_procChainLength
Definition Spell.h:999
SpellCastResult CanOpenLock(SpellEffectInfo const &effect, uint32 lockid, SkillType &skillid, int32 &reqSkillValue, int32 &skillValue)
Definition Spell.cpp:8655
void DoTriggersOnSpellHit(Unit *unit)
Definition Spell.cpp:3310
TriggerCastFlags _triggeredCastFlags
Definition Spell.h:993
bool IsAutoRepeat() const
Definition Spell.h:662
void HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, Corpse *pCorpseTarget, SpellEffectInfo const &spellEffectInfo, SpellEffectHandleMode mode)
Definition Spell.cpp:5719
void prepareDataForTriggerSystem()
Definition Spell.cpp:2334
SpellEffectHandleMode effectHandleMode
Definition Spell.h:806
void TakeReagents()
Definition Spell.cpp:5612
bool IsValidDeadOrAliveTarget(Unit const *target) const
Definition Spell.cpp:8484
SpellCastResult CheckMovement() const
Definition Spell.cpp:7175
std::unique_ptr< EmpowerData > m_empower
Definition Spell.h:782
void DoProcessTargetContainer(Container &targetContainer)
Definition Spell.cpp:3983
void ExecuteLogEffectDurabilityDamage(SpellEffects effect, Unit *victim, int32 itemId, int32 amount)
Definition Spell.cpp:5119
bool IsNeedSendToClient() const
Definition Spell.cpp:8346
WorldObject * SearchNearbyTarget(SpellEffectInfo const &spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const *condList=nullptr)
Definition Spell.cpp:2189
bool IsIgnoringCooldowns() const
Definition Spell.cpp:8293
void SelectImplicitDestDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition Spell.cpp:1690
std::pair< ProcFlagsInit, ProcFlagsInit > FinalizeDataForTriggerSystem(bool positive) const
Definition Spell.cpp:2379
std::vector< TargetInfo > m_UniqueTargetInfo
Definition Spell.h:878
SpellDestination m_destTargets[MAX_SPELL_EFFECTS]
Definition Spell.h:910
void ExecuteLogEffectCreateItem(SpellEffects effect, uint32 entry)
Definition Spell.cpp:5137
void _handle_finish_phase()
Definition Spell.cpp:4212
void UpdateDelayMomentForDst(uint64 hitDelay)
Definition Spell.cpp:910
bool CanExecuteTriggersOnHit(Unit *unit, SpellInfo const *triggeredByAura=nullptr) const
Definition Spell.cpp:9114
void PrepareTargetProcessing()
Definition Spell.cpp:8769
Trinity::unique_weak_ptr< Spell > GetWeakPtr() const
Definition Spell.cpp:9254
void SetExecutedCurrently(bool yes)
Definition Spell.h:684
void AddUnitTarget(Unit *target, uint32 effectMask, bool checkIfValid=true, bool implicit=true, Position const *losPosition=nullptr)
Definition Spell.cpp:2438
void SendSpellStart()
Definition Spell.cpp:4669
bool IsEmpowerSpell() const
Definition Spell.h:673
ObjectGuid m_originalCastId
Definition Spell.h:605
uint8 m_delayAtDamageCount
Definition Spell.h:764
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition Spell.cpp:5737
void SearchAreaTargets(std::list< WorldObject * > &targets, SpellEffectInfo const &spellEffectInfo, SpellRange range, Position const *position, WorldObject *referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, Trinity::WorldObjectSpellAreaTargetSearchReason searchReason)
Definition Spell.cpp:2202
ProcFlagsSpellType m_procSpellType
Definition Spell.h:827
void cancel(SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={}, ObjectGuid const &failedBy=ObjectGuid::Empty)
Definition Spell.cpp:3613
uint64 m_delayMoment
Definition Spell.h:786
WeaponAttackType m_attackType
Definition Spell.h:755
void _cast(bool skipCheck=false)
Definition Spell.cpp:3696
bool IsProcDisabled() const
Definition Spell.cpp:8303
bool m_immediateHandled
Definition Spell.h:788
SpellEffectValue CalculateDamage(SpellEffectInfo const &spellEffectInfo, Unit const *target, float *var=nullptr) const
Definition Spell.cpp:7199
void SendSpellInterruptLog(Unit *victim, uint32 spellId)
Definition Spell.cpp:5108
bool IsFocusDisabled() const
Definition Spell.cpp:8298
std::any m_customArg
Definition Spell.h:649
int32 GetSpellCastDataAmmo()
Definition Spell.cpp:4903
ObjectGuid m_originalCasterGUID
Definition Spell.h:749
WorldObject *const m_caster
Definition Spell.h:745
int64 GetItemTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2728
std::string GetDebugInfo() const
Definition Spell.cpp:9245
bool IsDeletable() const
Definition Spell.h:681
bool UpdateChanneledTargetList()
Definition Spell.cpp:3363
void CleanupTargetList()
Definition Spell.cpp:2404
void TriggerGlobalCooldown()
Definition Spell.cpp:9179
int32 m_timer
Definition Spell.h:990
int32 m_casttime
Definition Spell.h:758
void ExecuteLogEffectOpenLock(SpellEffects effect, Object *obj)
Definition Spell.cpp:5129
void SendMountResult(MountResult result)
Definition Spell.cpp:4652
Item * itemTarget
Definition Spell.h:798
void AddGOTarget(GameObject *target, uint32 effectMask)
Definition Spell.cpp:2557
void HandleThreatSpells()
Definition Spell.cpp:5663
float variance
Definition Spell.h:805
int32 m_damage
Definition Spell.h:818
std::vector< CorpseTargetInfo > m_UniqueCorpseTargetInfo
Definition Spell.h:905
void CancelGlobalCooldown()
Definition Spell.cpp:9230
bool CheckSpellCancelsAuraEffect(AuraType auraType, int32 *param1) const
Definition Spell.cpp:7075
void SearchChainTargets(std::list< WorldObject * > &targets, uint32 chainTargets, WorldObject *target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const &spellEffectInfo, bool isChainHeal)
Definition Spell.cpp:2216
bool m_executedCurrently
Definition Spell.h:792
void SelectImplicitAreaTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition Spell.cpp:1326
bool CheckSpellCancelsSilence(int32 *param1) const
Definition Spell.cpp:7117
SpellEffectValue effectValue
Definition Spell.h:802
void CallScriptOnCastHandlers()
Definition Spell.cpp:8810
void AddDestTarget(SpellDestination const &dest, uint32 effIndex)
Definition Spell.cpp:2690
int64 GetGameObjectTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2720
void SetEmpowerReleasedByClient(bool release)
Definition Spell.cpp:8329
void SendChannelUpdate(uint32 time, Optional< SpellCastResult > result={}, ObjectGuid const &failedBy=ObjectGuid::Empty)
Definition Spell.cpp:5198
void SelectImplicitCasterObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1742
void _handle_immediate_phase()
Definition Spell.cpp:4192
int32 m_channelDuration
Definition Spell.h:759
void SendSpellCooldown()
Definition Spell.cpp:4229
void CallScriptBeforeCastHandlers()
Definition Spell.cpp:8798
bool CheckSpellCancelsCharm(int32 *param1) const
Definition Spell.cpp:7104
void HandleLaunchPhase()
Definition Spell.cpp:8493
bool UpdatePointers()
Definition Spell.cpp:8102
SpellCustomErrors m_customError
Definition Spell.h:652
void SelectImplicitLineTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition Spell.cpp:1964
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode)
Definition Spell.cpp:8863
std::vector< GOTargetInfo > m_UniqueGOTargetInfo
Definition Spell.h:888
void ExecuteLogEffectDestroyItem(SpellEffects effect, uint32 entry)
Definition Spell.cpp:5145
void DoSpellEffectHit(Unit *unit, SpellEffectInfo const &spellEffectInfo, TargetInfo &targetInfo)
Definition Spell.cpp:3222
HitTriggerSpellList m_hitTriggerSpells
Definition Spell.h:977
void ExecuteLogEffectSummonObject(SpellEffects effect, WorldObject *obj)
Definition Spell.cpp:5153
void SetSpellValue(CastSpellExtraArgsInit::SpellValueOverride const &value)
Definition Spell.cpp:8729
int32 m_healing
Definition Spell.h:819
void SelectImplicitTargetDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition Spell.cpp:1653
void SetDelayStart(uint64 m_time)
Definition Spell.h:686
void ResetCombatTimers()
Definition Spell.cpp:8643
void CallScriptOnPrecastHandler()
Definition Spell.cpp:8788
void SelectImplicitCasterDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition Spell.cpp:1465
SpellEffectInfo const * effectInfo
Definition Spell.h:807
Unit * GetUnitCasterForEffectHandlers() const
Definition Spell.cpp:8356
SpellInfo const * m_triggeredByAuraSpell
Definition Spell.h:998
uint64 handle_delayed(uint64 t_offset)
Definition Spell.cpp:4087
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:9033
bool CheckSpellCancelsPacify(int32 *param1) const
Definition Spell.cpp:7123
int32 m_castItemLevel
Definition Spell.h:603
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:8160
UnitAura * _spellAura
Definition Spell.h:810
uint32 m_applyMultiplierMask
Definition Spell.h:793
Unit * unitTarget
Definition Spell.h:797
void Delayed()
Definition Spell.cpp:7994
SpellSchoolMask m_spellSchoolMask
Definition Spell.h:754
void SendSpellExecuteLog()
Definition Spell.cpp:5057
Optional< int32 > GetPowerTypeCostAmount(Powers power) const
Definition Spell.cpp:8093
WorldObject * GetCaster() const
Definition Spell.h:699
SpellEvent * _spellEvent
Definition Spell.h:992
void SelectImplicitChannelTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1029
union Spell::@323 m_misc
void SelectSpellTargets()
Definition Spell.cpp:720
SpellRange GetMinMaxRange(bool strict) const
Definition Spell.cpp:7332
bool CheckSpellCancelsConfuse(int32 *param1) const
Definition Spell.cpp:7134
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3432
SpellCastResult CheckCast(bool strict, int32 *param1=nullptr, int32 *param2=nullptr)
Definition Spell.cpp:5745
void CallScriptEmpowerStageCompletedHandlers(int32 completedStagesCount)
Definition Spell.cpp:9045
bool IsChannelActive() const
Definition Spell.cpp:8308
~Spell()
Definition Spell.cpp:598
void TakePower()
Definition Spell.cpp:5444
SpellCastResult CheckPetCast(Unit *target)
Definition Spell.cpp:6917
void RecalculateDelayMomentForDst()
Definition Spell.cpp:905
Corpse * m_corpseTarget
Definition Spell.h:800
void ReSetTimer()
Definition Spell.h:664
SpellLogEffect & GetExecuteLogEffect(SpellEffects effect)
Definition Spell.cpp:5073
void SelectImplicitChainTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, WorldObject *target, uint32 effMask)
Definition Spell.cpp:1832
int32 CallScriptCalcCastTimeHandlers(int32 originalCastTime)
Definition Spell.cpp:8852
SpellCastResult CallScriptCheckCastHandlers()
Definition Spell.cpp:8834
void CallScriptCalcHealingHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition Spell.cpp:8982
std::vector< T > & GetExecuteLogEffectTargets(SpellEffects effect, Optional< std::vector< T > > SpellLogEffect::*member)
Definition Spell.h:572
bool IsPositive() const
Definition Spell.cpp:8324
void InitExplicitTargets(SpellCastTargets const &targets)
Definition Spell.cpp:621
bool IsWithinLOS(WorldObject const *source, WorldObject const *target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition Spell.cpp:9259
void SendPetCastResult(SpellCastResult result, int32 *param1=nullptr, int32 *param2=nullptr) const
Definition Spell.cpp:4624
WorldLocation * destTarget
Definition Spell.h:801
bool CheckSpellCancelsFear(int32 *param1) const
Definition Spell.cpp:7129
Spell ** m_selfContainer
Definition Spell.h:714
bool IsTriggered() const
Definition Spell.cpp:8287
bool CanReleaseEmpowerSpell() const
Definition Spell.cpp:8334
bool m_scriptWaitsForSpellHit
Definition Spell.h:657
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:682
bool IsDelayableNoMore()
Definition Spell.h:765
void SelectEffectTypeImplicitTargets(SpellEffectInfo const &spellEffectInfo)
Definition Spell.cpp:2025
static void SendCastResult(Player const *caster, SpellInfo const *spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, int32 *param1=nullptr, int32 *param2=nullptr)
Definition Spell.cpp:4641
void update(uint32 difftime)
Definition Spell.cpp:4240
void SelectImplicitConeTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition Spell.cpp:1273
uint64 GetDelayStart() const
Definition Spell.h:685
bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
Definition Spell.cpp:9069
SpellState m_spellState
Definition Spell.h:989
ProcFlagsInit m_procVictim
Definition Spell.h:825
Item * m_CastItem
Definition Spell.h:600
std::vector< SpellLogEffect > _executeLogEffects
Definition Spell.h:1003
void CallScriptSuccessfulDispel(SpellEffIndex effIndex)
Definition Spell.cpp:8909
void DoEffectOnLaunchTarget(TargetInfo &targetInfo, float multiplier, SpellEffectInfo const &spellEffectInfo)
Definition Spell.cpp:8569
uint32 m_castItemEntry
Definition Spell.h:602
uint64 GetDelayMoment() const
Definition Spell.h:687
void AddItemTarget(Item *item, uint32 effectMask)
Definition Spell.cpp:2610
int32 GetUnitTargetIndexForEffect(ObjectGuid const &target, SpellEffIndex effect) const
Definition Spell.cpp:2695
void TakeCastItem()
Definition Spell.cpp:5375
void CallScriptEmpowerCompletedHandlers(int32 completedStagesCount)
Definition Spell.cpp:9057
void CheckSrc()
Definition Spell.cpp:7265
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition Spell.cpp:8958
ObjectGuid m_focusObjectGUID
Definition Spell.h:814
SpellValue *const m_spellValue
Definition Spell.h:747
Scripting::v2::ActionResultSetter< SpellCastResult > m_scriptResult
Definition Spell.h:656
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition Spell.cpp:4359
bool CheckEffectTarget(Unit const *target, SpellEffectInfo const &spellEffectInfo, Position const *losPosition) const
Definition Spell.cpp:8177
void SendResurrectRequest(Player *target)
Definition Spell.cpp:5349
void SelectEffectImplicitTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effectMask)
Definition Spell.cpp:945
void MovePosition(Position &pos, WorldObject const *from, float dist, float angle) const
Definition Spell.cpp:9286
SpellMissInfo PreprocessSpellHit(Unit *unit, TargetInfo &targetInfo)
Definition Spell.cpp:3105
SpellCastResult CheckCasterAuras(int32 *param1) const
Definition Spell.cpp:6951
static uint32 GetSearcherTypeMask(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const *condList)
Definition Spell.cpp:2125
static void SearchTargets(SEARCHER &searcher, uint32 containerMask, WorldObject *referer, Position const *pos, float radius)
Definition Spell.cpp:2163
std::vector< ItemTargetInfo > m_UniqueItemInfo
Definition Spell.h:896
bool IsAutoActionResetSpell() const
Definition Spell.cpp:8313
void DelayedChannel()
Definition Spell.cpp:8030
ProcFlagsInit m_procAttacker
Definition Spell.h:824
ObjectGuid m_castItemGUID
Definition Spell.h:601
SpellCastVisual m_SpellVisual
Definition Spell.h:650
Spell(WorldObject *caster, SpellInfo const *info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID=ObjectGuid::Empty, ObjectGuid originalCastId=ObjectGuid::Empty)
Definition Spell.cpp:473
int64 GetUnitTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2712
void ExecuteLogEffectUnsummonObject(SpellEffects effect, WorldObject *obj)
Definition Spell.cpp:5161
SpellCastResult CheckPower() const
Definition Spell.cpp:7392
GameObject * focusObject
Definition Spell.h:815
void CallScriptDestinationTargetSelectHandlers(SpellDestination &target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:9020
ProcFlagsHit m_hitMask
Definition Spell.h:826
ObjectGuid m_castId
Definition Spell.h:604
bool m_launchHandled
Definition Spell.h:787
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData &data)
Writes miss and hit targets for a SMSG_SPELL_GO packet.
Definition Spell.cpp:4868
void ExecuteLogEffectResurrect(SpellEffects effect, Unit *target)
Definition Spell.cpp:5169
SpellInfo const *const m_spellInfo
Definition Spell.h:599
bool HasGlobalCooldown() const
Definition Spell.cpp:9171
uint8 m_runesState
Definition Spell.h:762
void FinishTargetProcessing()
Definition Spell.cpp:8773
void CallScriptOnHitHandlers()
Definition Spell.cpp:8934
SpellCastResult CheckRange(bool strict) const
Definition Spell.cpp:7277
bool m_autoRepeat
Definition Spell.h:761
void CallScriptObjectTargetSelectHandlers(WorldObject *&target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:9007
void TakeRunePower(bool didHit)
Definition Spell.cpp:5573
void CallScriptObjectAreaTargetSelectHandlers(std::list< WorldObject * > &targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8994
SpellCastResult CheckArenaAndRatedBattlegroundCastRules()
Definition Spell.cpp:7144
void SelectImplicitTargetObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1807
void CallScriptAfterHitHandlers()
Definition Spell.cpp:8946
bool CanAutoCast(Unit *target)
Definition Spell.cpp:7209
ObjectGuid GetSummonerGUID() const
void ForwardThreatForAssistingMe(Unit *assistant, float baseAmount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false)
== AFFECT OTHERS' THREAT LISTS ==
void AddThreat(Unit *target, float amount, SpellInfo const *spell=nullptr, bool ignoreModifiers=false, bool ignoreRedirects=false)
== AFFECT MY THREAT LIST ==
uint32 GetSpell() const
Definition TradeData.h:49
Utility class to enable range for loop syntax for multimap.equal_range uses.
Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std...
Trinity::unique_trackable_ptr companion class, replicating what std::weak_ptr is to std::shared_ptr.
void SetDiminishGroup(DiminishingGroup group)
Definition SpellAuras.h:447
void AddStaticApplication(Unit *target, uint32 effMask)
Definition Unit.h:647
Unit * GetCharmed() const
Definition Unit.h:1232
void ClearUnitState(uint32 f)
Definition Unit.h:756
uint32 GetChannelSpellId() const
Definition Unit.h:1443
void SetLastDamagedTargetGuid(ObjectGuid guid)
Definition Unit.h:976
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8716
bool IsCharmed() const
Definition Unit.h:1256
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition Unit.cpp:712
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5436
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1362
uint32 GetSchoolImmunityMask() const
Definition Unit.cpp:7834
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true, bool skipChanneledAllowingActions=false) const
Definition Unit.cpp:3219
uint32 m_lastSanctuaryTime
Definition Unit.h:1617
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7329
Pet * ToPet()
Definition Unit.h:1838
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1045
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3846
int64 ModifyHealth(int64 val)
Definition Unit.cpp:8618
void SetCurrentCastSpell(Spell *pSpell)
Definition Unit.cpp:3068
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition Unit.cpp:10804
ThreatManager & GetThreatManager()
Definition Unit.h:1093
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition Unit.cpp:4845
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1075
void DelayOwnedAuras(uint32 spellId, ObjectGuid caster, int32 delaytime)
Definition Unit.cpp:4591
uint8 GetClass() const
Definition Unit.h:776
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:804
uint64 GetMechanicImmunityMask() const
Definition Unit.cpp:7854
void CalculateSpellDamageTaken(SpellNonMeleeDamage *damageInfo, int32 damage, SpellInfo const *spellInfo, WeaponAttackType attackType=BASE_ATTACK, bool crit=false, bool blocked=false, Spell *spell=nullptr)
Definition Unit.cpp:1198
void StopMoving(bool force=false)
Definition Unit.cpp:10753
std::forward_list< AuraEffect * > AuraEffectList
Definition Unit.h:664
bool IsInDisallowedMountForm() const
Definition Unit.cpp:9565
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1308
bool IsPvP() const
Definition Unit.h:901
bool haveOffhandWeapon() const
Definition Unit.cpp:530
MotionMaster * GetMotionMaster()
Definition Unit.h:1750
bool IsPet() const
Definition Unit.h:763
Powers GetPowerType() const
Definition Unit.h:823
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:860
bool CanProc() const
Definition Unit.h:1788
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1231
void UpdateInterruptMask()
Definition Unit.cpp:746
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition Unit.cpp:9363
void AddChannelObject(ObjectGuid guid)
Definition Unit.cpp:3046
void SetChannelSpellId(uint32 channelSpellId)
Definition Unit.h:1444
bool IsFullHealth() const
Definition Unit.h:803
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:865
bool IsAlive() const
Definition Unit.h:1205
float GetCombatReach() const override
Definition Unit.h:717
int32 GetMaxPower(Powers power) const
Definition Unit.cpp:10105
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6795
GameObject * GetGameObject(uint32 spellId) const
Definition Unit.cpp:5369
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5559
bool IsStandState() const
Definition Unit.cpp:10798
bool IsSilenced(SpellSchoolMask schoolMask) const
Definition Unit.h:1517
TempSummon * ToTempSummon()
Definition Unit.h:1844
CharmInfo * GetCharmInfo()
Definition Unit.h:1262
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1236
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6601
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition Unit.cpp:7140
void SetChannelVisual(SpellCastVisual channelVisual)
Definition Unit.h:1453
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:698
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:12201
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1237
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7936
void SetChannelSpellData(uint32 startTimeMs, uint32 durationMs)
Definition Unit.h:1464
bool IsInFlight() const
Definition Unit.h:1042
bool IsAIEnabled() const
Definition Unit.h:678
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition Unit.cpp:7194
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition Unit.cpp:12512
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4718
uint64 GetHealth() const
Definition Unit.h:800
bool IsSummon() const
Definition Unit.h:761
bool IsInWater() const
Definition Unit.cpp:3349
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5348
AttackerSet const & getAttackers() const
Definition Unit.h:736
void SetSpellEmpowerStage(int8 stage)
Definition Unit.h:1471
float GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:5087
bool HasAuraType(AuraType auraType) const
Definition Unit.cpp:4832
bool isMoving() const
Definition Unit.h:1820
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8513
bool IsImmunedToSpell(SpellInfo const *spellInfo, uint32 effectMask, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7742
uint8 GetLevelForTarget(WorldObject const *) const override
Definition Unit.h:771
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition Unit.cpp:4259
bool IsMounted() const
Definition Unit.h:927
void RemoveAppliedAuras(std::function< bool(AuraApplication const *)> const &check, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3919
Unit * GetVictim() const
Definition Unit.h:738
UF::UpdateField< UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT > m_unitData
Definition Unit.h:1897
int32 GetPower(Powers power) const
Definition Unit.cpp:10096
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition Unit.cpp:9975
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7874
DeathState getDeathState() const
Definition Unit.h:1208
bool HasUnitState(const uint32 f) const
Definition Unit.h:755
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:12272
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5332
int32 GetProcChainLength() const
Definition Unit.h:1790
bool HasUnitMovementFlag(MovementFlags f) const
Definition Unit.h:1761
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition Unit.cpp:4822
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:706
SpellHistory * GetSpellHistory()
Definition Unit.h:1521
bool IsControlledByPlayer() const
Definition Unit.h:1234
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:9350
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1228
virtual void setDeathState(DeathState s)
Definition Unit.cpp:9180
CombatManager & GetCombatManager()
Definition Unit.h:1053
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4854
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition Unit.h:713
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:9374
bool IsSpiritHealer() const
Definition Unit.h:1031
bool IsTotem() const
Definition Unit.h:765
AuraList & GetSingleCastAuras()
Definition Unit.h:1364
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4664
Vehicle * GetVehicleKit() const
Definition Unit.h:1798
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:670
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:5589
virtual bool IsEngaged() const
Definition Unit.h:1049
void ClearChannelObjects()
Definition Unit.cpp:3063
bool AttackStop()
Definition Unit.cpp:5984
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:12253
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3992
int32 SpellHealingBonusDone(Unit *victim, SpellInfo const *spellProto, int32 healamount, DamageEffectType damagetype, SpellEffectInfo const &spellEffectInfo, uint32 stack=1, Spell *spell=nullptr, AuraEffect const *aurEff=nullptr) const
Definition Unit.cpp:7347
ObjectGuid GetTarget() const
Definition Unit.h:1847
uint8 GetLevel() const
Definition Unit.h:769
bool IsInCombat() const
Definition Unit.h:1073
bool IsWalking() const
Definition Unit.h:1165
ObjectGuid GetPetGUID() const
Definition Unit.h:1217
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1490
static VMapManager * createOrGetVMapManager()
bool isLineOfSightCalcEnabled() const
bool IsControllableVehicle() const
Definition Vehicle.cpp:621
constexpr uint32 GetMapId() const
Definition Position.h:216
Unit * GetMagicHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo)
Definition Object.cpp:2600
void MovePosition(Position &pos, float dist, float angle, float maxHeightChange=6.0f) const
Definition Object.cpp:2787
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1099
Map * GetMap() const
Definition Object.h:411
virtual float GetCollisionHeight() const
Definition Object.h:553
Unit * GetCharmerOrOwner() const
Definition Object.cpp:1608
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:1996
bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:513
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition Object.cpp:1138
bool IsInRange2d(Position const *pos, float minRange, float maxRange) const
Definition Object.cpp:615
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition Object.cpp:2754
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition Object.cpp:3131
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2222
float GetMapWaterOrGroundLevel(float x, float y, float z, float *ground=nullptr) const
Definition Object.cpp:3116
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2329
PhaseShift & GetPhaseShift()
Definition Object.h:310
bool GetDistanceOrder(WorldObject const *obj1, WorldObject const *obj2, bool is3D=true) const
Definition Object.cpp:567
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect, bool canImmune) const
Definition Object.cpp:1947
bool IsOutdoors() const
Definition Object.h:336
int32 ModSpellDuration(SpellInfo const *spellInfo, WorldObject const *target, int32 duration, bool positive, uint32 effectMask) const
Definition Object.cpp:1725
std::string GetNameForLocaleIdx(LocaleConstant) const override
Definition Object.h:345
SpellRange GetSpellMinMaxRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition Object.cpp:1670
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:533
Player * GetSpellModOwner() const
Definition Object.cpp:1646
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:1626
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:499
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2487
EventProcessor m_Events
Definition Object.h:561
void MovePositionToFirstCollision(Position &pos, float dist, float angle) const
Definition Object.cpp:2833
float GetVisibilityRange() const
Definition Object.cpp:785
bool IsInRange3d(Position const *pos, float minRange, float maxRange) const
Definition Object.cpp:633
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition Object.cpp:2637
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:430
uint32 GetZoneId() const
Definition Object.h:332
MovementInfo m_movementInfo
Definition Object.h:548
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition Object.h:334
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:494
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2191
virtual float GetCombatReach() const
Definition Object.h:302
void ModSpellDurationTime(SpellInfo const *spellInfo, int32 &durationTime, Spell *spell=nullptr) const
Definition Object.cpp:1816
std::vector< SpellLogEffect > const * Effects
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< SpellTargetedHealPrediction > HealPrediction
Optional< SpellChannelStartInterruptImmunities > InterruptImmunities
WorldPacket const * Write() override
ObjectGuid FailedBy
Unit that caused the spell to fail, set for SPELL_FAILED_INTERRUPTED_COMBAT.
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< SpellTargetedHealPrediction > HealPrediction
Duration< Milliseconds, uint32 > EmpowerDuration
Duration< Milliseconds, uint32 > MinHoldTime
std::vector< Duration< Milliseconds, uint32 > > StageDurations
std::vector< ObjectGuid > Targets
Optional< SpellChannelStartInterruptImmunities > InterruptImmunities
Duration< Milliseconds, uint32 > HoldAtMaxTime
WorldPacket const * Write() override
ObjectGuid FailedBy
Unit that caused the spell to fail, set for SPELL_FAILED_INTERRUPTED_COMBAT.
std::vector< Duration< Milliseconds, uint32 > > StageDurations
Duration< Milliseconds, int32 > TimeRemaining
WorldPacket const * Write() override
ObjectGuid FailedBy
Unit that caused the spell to fail, set for SPELL_FAILED_INTERRUPTED_COMBAT.
WorldPacket const * Write() override
ObjectGuid FailedBy
Unit that caused the spell to fail, set for SPELL_FAILED_INTERRUPTED_COMBAT.
WorldPacket const * Write() override
WorldPacket const * Write() override
LocaleConstant GetSessionDbLocaleIndex() const
uint32 GetRecruiterId() const
uint32 GetAccountId() const
CollectionMgr * GetCollectionMgr() const
BattlePets::BattlePetMgr * GetBattlePetMgr() const
#define sWorld
Definition World.h:919
uint32 GetVirtualRealmAddress()
Definition World.cpp:3500
static constexpr uint16 MAX_BATTLE_PET_LEVEL
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
uint32 GetGameTimeMS()
Definition GameTime.cpp:57
TC_GAME_API WorldObject * GetWorldObject(WorldObject const &, ObjectGuid const &)
TC_GAME_API Unit * GetUnit(WorldObject const &, ObjectGuid const &guid)
TC_GAME_API GameObject * GetGameObject(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * GetPlayer(Map const *, ObjectGuid const &guid)
TC_GAME_API Corpse * GetCorpse(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
ItemModifiedAppearanceEntry const * GetItemModifiedAppearance(uint32 itemId, uint32 appearanceModId)
void RandomShuffle(Iterator begin, Iterator end)
Reorder the elements of the iterator range randomly.
Definition Containers.h:171
auto SelectRandomContainerElement(C const &container) -> std::add_const_t< decltype(*std::ranges::begin(container))> &
Definition Containers.h:110
constexpr IteratorPair< iterator, end_iterator > MakeIteratorPair(iterator first, end_iterator second)
void RandomResize(C &container, std::size_t requestedSize)
Definition Containers.h:67
WorldObjectSpellAreaTargetSearchReason
Definition Spell.h:1040
void SelectRandomInjuredTargets(std::list< WorldObject * > &targets, size_t maxTargets, bool prioritizePlayers, Unit const *prioritizeGroupMembersOf)
Definition Spell.cpp:9516
void SortTargetsWithPriorityRules(std::list< WorldObject * > &targets, size_t maxTargets, std::span< TargetPriorityRule const > rules)
Definition Spell.cpp:9581
struct advstd::ranges::Contains contains
uint8 ArtifactCategoryID
AuraCreateInfo & SetSpellVisual(SpellCastVisual const &spellVisual)
Definition SpellAuras.h:122
AuraCreateInfo & SetCastItem(ObjectGuid const &guid, uint32 itemId, int32 itemLevel)
Definition SpellAuras.h:117
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
Definition SpellAuras.h:114
AuraCreateInfo & SetBaseAmount(SpellEffectValue const *bp)
Definition SpellAuras.h:116
AuraCreateInfo & SetIsRefresh(bool *isRefresh)
Definition SpellAuras.h:119
AuraCreateInfo & SetOwnerEffectMask(uint32 effMask)
Definition SpellAuras.h:121
AuraCreateInfo & SetStackAmount(int32 stackAmount)
Definition SpellAuras.h:120
AuraCreateInfo & SetPeriodicReset(bool reset)
Definition SpellAuras.h:118
union CastSpellExtraArgsInit::SpellValueOverride::@327 Value
Spell const * TriggeringSpell
Optional< int32 > OriginalCastItemLevel
CastSpellExtraArgs & SetTriggeringSpell(Spell const *triggeringSpell)
Definition Spell.cpp:9646
CastSpellExtraArgs & SetCastDifficulty(Difficulty castDifficulty)
CastSpellExtraArgs & SetOriginalCaster(ObjectGuid const &guid)
CastSpellExtraArgs & operator=(CastSpellExtraArgs const &other)
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:150
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius)
Definition CellImpl.h:140
bool IsPetSpecialization() const
Condition const * mLastFailedCondition
uint32 ErrorType
uint8 ConditionTarget
uint32 ErrorTextId
CreatureDifficulty const * GetDifficulty(Difficulty difficulty) const
Definition Creature.cpp:252
bool IsTameable(bool canTameExotic, CreatureDifficulty const *creatureDifficulty) const
uint32 GetNoDamageImmune() const
uint32 GetRequiredSkillRank() const
uint32 GetBaseItemLevel() const
uint32 GetMaxStackSize() const
InventoryType GetInventoryType() const
uint8 GetArtifactID() const
uint32 GetItemLimitCategory() const
bool HasFlag(ItemFlags flag) const
uint32 GetSubClass() const
uint32 GetLockID() const
uint32 GetClass() const
float level
Definition MapDefines.h:149
std::array< uint8, MAX_LOCK_CASE > Type
std::array< uint16, MAX_LOCK_CASE > Skill
std::array< int32, MAX_LOCK_CASE > Index
Definition Loot.h:286
bool isLooted() const
Definition Loot.h:312
LootType loot_type
Definition Loot.h:293
MovementFlags GetMovementFlags() const
constexpr void SetOrientation(float orientation)
Definition Position.h:82
constexpr float GetPositionX() const
Definition Position.h:87
float m_positionZ
Definition Position.h:66
constexpr float GetPositionY() const
Definition Position.h:88
float GetExactDist2d(const float x, const float y) const
Definition Position.h:117
float GetRelativeAngle(float x, float y) const
Definition Position.h:147
float GetExactDist(float x, float y, float z) const
Definition Position.h:129
Position GetPositionOffsetTo(Position const &endPos) const
Definition Position.cpp:47
float m_positionX
Definition Position.h:64
float m_positionY
Definition Position.h:65
bool HasInLine(Position const *pos, float objSize, float width) const
Definition Position.cpp:192
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Position.cpp:173
float GetAbsoluteAngle(float x, float y) const
Definition Position.h:136
constexpr void GetPosition(float &x, float &y) const
Definition Position.h:92
constexpr void Relocate(float x, float y)
Definition Position.h:74
constexpr float GetExactDistSq(float x, float y, float z) const
Definition Position.h:121
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition Position.h:155
void RelocateOffset(Position const &offset)
Definition Position.cpp:34
constexpr float GetOrientation() const
Definition Position.h:90
constexpr float GetPositionZ() const
Definition Position.h:89
uint32 SpellXSpellVisualID
void RelocateOffset(Position const &offset)
Definition Spell.cpp:90
Position _transportOffset
WorldLocation _position
void Relocate(Position const &pos)
Definition Spell.cpp:82
ObjectGuid _transportGUID
std::array< uint8, MAX_ITEM_ENCHANTMENT_EFFECTS > Effect
EnumFlag< SpellItemEnchantmentFlags > GetFlags() const
Optional< std::vector< SpellLogEffectTradeSkillItemParams > > TradeSkillTargets
Definition Spell.h:235
Optional< std::vector< SpellLogEffectFeedPetParams > > FeedPetTargets
Definition Spell.h:236
Optional< std::vector< SpellLogEffectPowerDrainParams > > PowerDrainTargets
Definition Spell.h:231
Optional< std::vector< SpellLogEffectDurabilityDamageParams > > DurabilityDamageTargets
Definition Spell.h:233
Optional< std::vector< SpellLogEffectGenericVictimParams > > GenericVictimTargets
Definition Spell.h:234
Optional< std::vector< SpellLogEffectExtraAttacksParams > > ExtraAttacksTargets
Definition Spell.h:232
Unit * attacker
Definition Unit.h:571
uint32 reflectingSpellId
Definition Unit.h:582
float RadiusMod
Definition Spell.h:245
Optional< int32 > Duration
Definition Spell.h:249
Optional< int32 > ParentSpellTargetIndex
Definition Spell.h:251
uint32 CustomBasePointsMask
Definition Spell.h:243
uint32 MaxAffectedTargets
Definition Spell.h:244
int32 AuraStackAmount
Definition Spell.h:246
float CriticalChance
Definition Spell.h:248
Optional< int32 > ParentSpellTargetCount
Definition Spell.h:250
float DurationMul
Definition Spell.h:247
SpellEffectValue EffectBasePoints[MAX_SPELL_EFFECTS]
Definition Spell.h:242
SpellValue(SpellInfo const *proto, WorldObject const *caster)
Definition Spell.cpp:439
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:3091
ObjectGuid TargetGUID
Definition Spell.h:902
ObjectGuid TargetGUID
Definition Spell.h:885
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:3058
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:3081
UnitAura * HitAura
Definition Spell.h:871
void PreprocessTarget(Spell *spell) override
Definition Spell.cpp:2744
SpellMissInfo MissCondition
Definition Spell.h:860
uint32 ReflectingSpellId
Definition Spell.h:862
SpellEffectValue AuraBasePoints[MAX_SPELL_EFFECTS]
Definition Spell.h:870
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2792
void DoDamageAndTriggers(Spell *spell) override
Definition Spell.cpp:2821
SpellMissInfo ReflectResult
Definition Spell.h:861
uint64 TimeDelay
Definition Spell.h:855
ObjectGuid TargetGUID
Definition Spell.h:854
Unit * _spellHitTarget
Definition Spell.h:875
int32 AuraDuration
Definition Spell.h:869
DiminishingGroup DRGroup
Definition Spell.h:868
WorldObjectSpellAreaTargetSearchReason _searchReason
Definition Spell.h:1049
bool operator()(WorldObject *target) const
Definition Spell.cpp:9421
WorldObjectSpellAreaTargetCheck(SpellRange range, Position const *position, WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType, WorldObjectSpellAreaTargetSearchReason searchReason=WorldObjectSpellAreaTargetSearchReason::Area)
Definition Spell.cpp:9416
bool operator()(WorldObject *target) const
Definition Spell.cpp:9462
WorldObjectSpellConeTargetCheck(Position const &coneSrc, float coneAngle, float lineWidth, SpellRange range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition Spell.cpp:9458
WorldObjectSpellLineTargetCheck(Position const *srcPosition, Position const *dstPosition, float lineWidth, SpellRange range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition Spell.cpp:9500
bool operator()(WorldObject *target) const
Definition Spell.cpp:9508
WorldObjectSpellNearbyTargetCheck(float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition Spell.cpp:9401
bool operator()(WorldObject *target)
Definition Spell.cpp:9405
SpellTargetCheckTypes _targetSelectionType
Definition Spell.h:1017
WorldObjectSpellTargetCheck(WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition Spell.cpp:9297
std::unique_ptr< ConditionSourceInfo > _condSrcInfo
Definition Spell.h:1018
bool operator()(WorldObject *target) const
Definition Spell.cpp:9309
ConditionContainer const * _condList
Definition Spell.h:1019
SpellTargetObjectTypes _objectType
Definition Spell.h:1020
WorldObjectSpellTrajTargetCheck(float range, Position const *position, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition Spell.cpp:9485
bool operator()(WorldObject *target) const
Definition Spell.cpp:9488
std::vector< ObjectGuid > HitTargets
Optional< RuneData > RemainingRunes
std::vector< SpellMissStatus > MissStatus
MissileTrajectoryResult MissileTrajectory
std::vector< ObjectGuid > MissTargets
std::vector< SpellHitStatus > HitStatus
std::vector< SpellPowerData > RemainingPower
MissileTrajectoryRequest MissileTrajectory
Optional< TargetLocation > SrcLocation
Optional< TargetLocation > DstLocation