TrinityCore
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 "UniqueTrackablePtr.h"
65#include "Util.h"
66#include "VMapFactory.h"
67#include "Vehicle.h"
68#include "VMapManager2.h"
69#include "World.h"
70#include "WorldSession.h"
71#include <numeric>
72#include <sstream>
73
75
76SpellDestination::SpellDestination(WorldObject const& wObj) : _position(wObj.GetMapId(), wObj),
77 _transportGUID(wObj.GetTransGUID()), _transportOffset(wObj.GetTransOffset())
78{
79}
80
82{
84 {
85 Position offset;
86 _position.GetPositionOffsetTo(pos, offset);
88 }
90}
91
93{
96
98}
99
100SpellCastTargets::SpellCastTargets() : m_targetMask(0), m_objectTarget(nullptr), m_itemTarget(nullptr),
101 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f)
102{
103}
104
106 m_targetMask(spellCastRequest.Target.Flags), m_objectTarget(nullptr), m_itemTarget(nullptr),
107 m_objectTargetGUID(spellCastRequest.Target.Unit), m_itemTargetGUID(spellCastRequest.Target.Item),
108 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f), m_strTarget(spellCastRequest.Target.Name)
109{
110 if (spellCastRequest.Target.SrcLocation)
111 {
112 m_src._transportGUID = spellCastRequest.Target.SrcLocation->Transport;
113 Position* pos;
115 pos = &m_src._transportOffset;
116 else
117 pos = &m_src._position;
118
119 pos->Relocate(spellCastRequest.Target.SrcLocation->Location.Pos);
120 if (spellCastRequest.Target.Orientation)
121 pos->SetOrientation(*spellCastRequest.Target.Orientation);
122 }
123
124 if (spellCastRequest.Target.DstLocation)
125 {
126 m_dst._transportGUID = spellCastRequest.Target.DstLocation->Transport;
127 Position* pos;
129 pos = &m_dst._transportOffset;
130 else
131 pos = &m_dst._position;
132
133 pos->Relocate(spellCastRequest.Target.DstLocation->Location.Pos);
134 if (spellCastRequest.Target.Orientation)
135 pos->SetOrientation(*spellCastRequest.Target.Orientation);
136 }
137
138 SetPitch(spellCastRequest.MissileTrajectory.Pitch);
139 SetSpeed(spellCastRequest.MissileTrajectory.Speed);
140
141 Update(caster);
142}
143
145
147{
148 data.Flags = m_targetMask;
149
152
154 data.Item = m_itemTarget->GetGUID();
155
157 {
158 data.SrcLocation.emplace();
159 data.SrcLocation->Transport = m_src._transportGUID; // relative position guid here - transport for example
161 data.SrcLocation->Location = m_src._transportOffset;
162 else
163 data.SrcLocation->Location = m_src._position;
164 }
165
167 {
168 data.DstLocation.emplace();
169 data.DstLocation->Transport = m_dst._transportGUID; // relative position guid here - transport for example
171 data.DstLocation->Location = m_dst._transportOffset;
172 else
173 data.DstLocation->Location = m_dst._position;
174 }
175
177 data.Name = m_strTarget;
178}
179
181{
183 return m_objectTargetGUID;
184
185 return ObjectGuid::Empty;
186}
187
189{
190 if (m_objectTarget)
191 return m_objectTarget->ToUnit();
192
193 return nullptr;
194}
195
197{
198 if (!target)
199 return;
200
201 m_objectTarget = target;
202 m_objectTargetGUID = target->GetGUID();
204}
205
207{
209 return m_objectTargetGUID;
210
211 return ObjectGuid::Empty;
212}
213
215{
216 if (m_objectTarget)
218
219 return nullptr;
220}
221
223{
224 if (!target)
225 return;
226
227 m_objectTarget = target;
228 m_objectTargetGUID = target->GetGUID();
230}
231
233{
235 return m_objectTargetGUID;
236
237 return ObjectGuid::Empty;
238}
239
241{
242 if (m_objectTarget)
243 return m_objectTarget->ToCorpse();
244
245 return nullptr;
246}
247
249{
250 return m_objectTarget;
251}
252
254{
255 return m_objectTargetGUID;
256}
257
259{
260 m_objectTarget = nullptr;
263}
264
266{
267 if (!item)
268 return;
269
270 m_itemTarget = item;
271 m_itemTargetGUID = item->GetGUID();
272 m_itemTargetEntry = item->GetEntry();
274}
275
277{
281
282 Update(caster);
283}
284
286{
288 {
291 }
292}
293
295{
296 return &m_src;
297}
298
300{
301 return &m_src._position;
302}
303
304void SpellCastTargets::SetSrc(float x, float y, float z)
305{
306 m_src = SpellDestination(x, y, z);
308}
309
311{
312 m_src = SpellDestination(pos);
314}
315
317{
318 m_src = SpellDestination(wObj);
320}
321
323{
325 m_src.Relocate(pos);
326}
327
329{
331}
332
334{
335 return &m_dst;
336}
337
339{
340 return &m_dst._position;
341}
342
343void SpellCastTargets::SetDst(float x, float y, float z, float orientation, uint32 mapId)
344{
345 m_dst = SpellDestination(x, y, z, orientation, mapId);
347}
348
350{
351 m_dst = SpellDestination(pos);
353}
354
356{
357 m_dst = SpellDestination(wObj);
359}
360
362{
363 m_dst = spellDest;
365}
366
368{
369 m_dst = spellTargets.m_dst;
371}
372
374{
376 m_dst.Relocate(pos);
377}
378
380{
382 m_dst = spellDest;
383}
384
386{
388}
389
391{
393}
394
396{
398}
399
401{
403
404 m_itemTarget = nullptr;
405 if (caster->GetTypeId() == TYPEID_PLAYER)
406 {
407 Player* player = caster->ToPlayer();
411 {
413 if (TradeData* pTrade = player->GetTradeData())
414 m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
415 }
416
417 if (m_itemTarget)
419 }
420
421 // update positions by transport move
423 {
425 {
426 m_src._position.Relocate(transport);
428 }
429 }
430
432 {
434 {
435 m_dst._position.Relocate(transport);
437 }
438 }
439}
440
441SpellValue::SpellValue(SpellInfo const* proto, WorldObject const* caster)
442{
443 memset(EffectBasePoints, 0, sizeof(EffectBasePoints));
444 for (SpellEffectInfo const& spellEffectInfo : proto->GetEffects())
445 EffectBasePoints[spellEffectInfo.EffectIndex] = spellEffectInfo.CalcBaseValue(caster, nullptr, 0, -1);
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 modOwner->ApplySpellMod(info, SpellModOp::Doses, m_spellValue->AuraStackAmount, this);
506
507 if (!originalCasterGUID.IsEmpty())
508 m_originalCasterGUID = originalCasterGUID;
509 else
511
514 else
515 {
518 m_originalCaster = nullptr;
519 }
520
522 _triggeredCastFlags = triggerFlags;
523
526
529
530 m_CastItem = nullptr;
532 m_castItemEntry = 0;
533 m_castItemLevel = -1;
534 m_castFlagsEx = 0;
535
538
539 unitTarget = nullptr;
540 itemTarget = nullptr;
541 gameObjTarget = nullptr;
542 m_corpseTarget = nullptr;
543 destTarget = nullptr;
544 damage = 0;
546 variance = 0.0f;
548 effectInfo = nullptr;
549 m_damage = 0;
550 m_healing = 0;
553 focusObject = nullptr;
555 m_originalCastId = originalCastId;
556 memset(m_misc.Raw.Data, 0, sizeof(m_misc.Raw.Data));
558 m_triggeredByAuraSpell = nullptr;
559 m_procChainLength = caster->IsUnit() ? caster->ToUnit()->GetProcChainLength() : 0;
560 _spellAura = nullptr;
561 _dynObjAura = nullptr;
562
563 //Auto Shot & Shoot (wand)
565
566 m_runesState = 0;
567 m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before.
568 m_timer = 0; // will set to castime in prepare
569 m_channeledDuration = 0; // will be setup in Spell::handle_immediate
570 m_launchHandled = false;
571 m_immediateHandled = false;
572
574
576 m_empower = std::make_unique<EmpowerData>();
577
578 // Determine if spell can be reflected back to the caster
579 // Patch 1.2 notes: Spell Reflection no longer reflects abilities
580 m_canReflect = caster->IsUnit()
583 && !m_spellInfo->IsPassive();
584
585 std::ranges::fill(m_destTargets, SpellDestination(*m_caster));
586}
587
589{
590 // unload scripts
591 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
592 {
593 (*itr)->_Unload();
594 delete (*itr);
595 }
596
598 {
599 // Clean the reference to avoid later crash.
600 // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
601 TC_LOG_ERROR("spells", "SPELL: deleting spell for spell ID {}. However, spell still referenced.", m_spellInfo->Id);
602 *m_selfContainer = nullptr;
603 }
604
607
608 delete m_spellValue;
609}
610
612{
613 m_targets = targets;
614
615 // this function tries to correct spell explicit targets for spell
616 // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
617 // this also makes sure that we correctly send explicit targets to client (removes redundant data)
618 uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
619
620 if (WorldObject* target = m_targets.GetObjectTarget())
621 {
622 // check if object target is valid with needed target flags
623 // for unit case allow corpse target mask because player with not released corpse is a unit target
624 if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)))
625 || (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
626 || (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK)))
628 }
629 else
630 {
631 // try to select correct unit target if not provided by client or by serverside cast
632 if (neededTargets & (TARGET_FLAG_UNIT_MASK))
633 {
634 Unit* unit = nullptr;
635 // try to use player selection as a target
636 if (Player* playerCaster = m_caster->ToPlayer())
637 {
638 // selection has to be found and to be valid target for the spell
639 if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget()))
641 unit = selectedUnit;
642 }
643 // try to use attacked unit as a target
644 else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
645 unit = m_caster->ToUnit()->GetVictim();
646
647 // didn't find anything - let's use self as target
648 if (!unit && neededTargets & (TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY))
649 unit = m_caster->ToUnit();
650
652 }
653 }
654
655 // check if spell needs dst target
656 if (neededTargets & TARGET_FLAG_DEST_LOCATION)
657 {
658 // and target isn't set
659 if (!m_targets.HasDst())
660 {
661 // try to use unit target if provided
662 if (WorldObject* target = targets.GetObjectTarget())
663 m_targets.SetDst(*target);
664 // or use self if not available
665 else
667 }
668 }
669 else
671
672 if (neededTargets & TARGET_FLAG_SOURCE_LOCATION)
673 {
674 if (!targets.HasSrc())
676 }
677 else
679}
680
682{
683 // here go all explicit target changes made to explicit targets after spell prepare phase is finished
684 if (Unit* target = m_targets.GetUnitTarget())
685 {
686 // check for explicit target redirection, for Grounding Totem for example
689 {
690 Unit* redirect = nullptr;
691 switch (m_spellInfo->DmgClass)
692 {
695 break;
698 // should gameobjects cast damagetype melee/ranged spells this needs to be changed
699 redirect = ASSERT_NOTNULL(m_caster->ToUnit())->GetMeleeHitRedirectTarget(target, m_spellInfo);
700 break;
701 default:
702 break;
703 }
704 if (redirect && (redirect != target))
705 m_targets.SetUnitTarget(redirect);
706 }
707 }
708}
709
711{
712 // select targets for cast phase
714
715 uint32 processedAreaEffectsMask = 0;
716
717 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
718 {
719 // not call for empty effect.
720 // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
721 if (!spellEffectInfo.IsEffect())
722 continue;
723
724 // set expected type of implicit targets to be sent to client
725 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
726 if (implicitTargetMask & TARGET_FLAG_UNIT)
728 if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
730
731 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, SpellTargetIndex::TargetA, processedAreaEffectsMask);
732 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, SpellTargetIndex::TargetB, processedAreaEffectsMask);
733
734 // Select targets of effect based on effect type
735 // those are used when no valid target could be added for spell effect based on spell target type
736 // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
737 // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
738 // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
739 SelectEffectTypeImplicitTargets(spellEffectInfo);
740
741 if (m_targets.HasDst())
742 AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex);
743
744 if (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
745 || spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST
746 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
747 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST)
748 {
750 {
751 bool noTargetFound = std::ranges::none_of(m_UniqueTargetInfo, [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target)
752 {
753 return target.EffectMask & effectMask;
754 });
755
756 if (noTargetFound)
757 {
760 return;
761 }
762 }
763 }
764
766 {
767 // maybe do this for all spells?
768 if (!focusObject && m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst())
769 {
772 return;
773 }
774
775 uint32 mask = (1 << spellEffectInfo.EffectIndex);
776 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
777 {
778 if (ihit->EffectMask & mask)
779 {
781 break;
782 }
783 }
784 }
785 }
786
788 {
789 bool anyNonImmuneTargetFound = std::ranges::any_of(m_UniqueTargetInfo, [](TargetInfo const& target)
790 {
792 });
793
794 if (!anyNonImmuneTargetFound)
795 {
798 return;
799 }
800 }
801
802 if (m_targets.HasDst())
803 {
805 {
808 if (!(status & (LIQUID_MAP_WATER_WALK | LIQUID_MAP_IN_WATER)))
809 {
812 return;
813 }
814 }
815 }
816
818 m_delayMoment = dstDelay;
819}
820
822{
823 if (m_targets.HasDst())
824 {
825 if (m_targets.HasTraj())
826 {
827 float speed = m_targets.GetSpeedXY();
828 if (speed > 0.0f)
829 return uint64(std::floor((m_targets.GetDist2d() / speed + launchDelay) * 1000.0f));
830 }
832 return uint64(std::floor((m_spellInfo->Speed + launchDelay) * 1000.0f));
833 else if (m_spellInfo->Speed > 0.0f)
834 {
835 // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP)
836 float dist = m_caster->GetExactDist(*m_targets.GetDstPos());
837 return uint64(std::floor((dist / m_spellInfo->Speed + launchDelay) * 1000.0f));
838 }
839
840 return uint64(std::floor(launchDelay * 1000.0f));
841 }
842
843 return 0;
844}
845
847{
849}
850
852{
853 m_delayMoment = hitDelay;
854
855 if (GetDelayStart())
857}
858
860{
861 auto itr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [unit](Spell::TargetInfo const& targetInfo)
862 {
863 return targetInfo.TargetGUID == unit->GetGUID();
864 });
865
866 uint64 oldDelay = itr->TimeDelay;
867 itr->TimeDelay = hitDelay;
868
869 if (hitDelay && (!m_delayMoment || m_delayMoment > hitDelay))
870 m_delayMoment = hitDelay;
871 else if (m_delayMoment && oldDelay < hitDelay)
872 {
873 // 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
874 auto minDelayTargetItr = std::min_element(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [](Spell::TargetInfo const& itr, Spell::TargetInfo const& smallest)
875 {
876 return itr.TimeDelay && itr.TimeDelay < smallest.TimeDelay;
877 });
878
879 m_delayMoment = minDelayTargetItr->TimeDelay;
880 }
881
882 if (GetDelayStart())
884}
885
886void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32& processedEffectMask)
887{
888 if (!targetType.GetTarget())
889 return;
890
891 uint32 effectMask = 1 << spellEffectInfo.EffectIndex;
892 // set the same target list for all effects
893 // some spells appear to need this, however this requires more research
894 switch (targetType.GetSelectionCategory())
895 {
900 {
901 // targets for effect already selected
902 if (effectMask & processedEffectMask)
903 return;
904 std::vector<SpellEffectInfo> const& effects = GetSpellInfo()->GetEffects();
905 // choose which targets we can select at once
906 for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j)
907 {
908 if (effects[j].IsEffect() &&
909 spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
910 spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
911 spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
912 spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetA) == effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetA) &&
913 spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetB) == effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetB) &&
914 spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) == effects[j].EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) &&
916 {
917 effectMask |= 1 << j;
918 }
919 }
920 processedEffectMask |= effectMask;
921 break;
922 }
923 default:
924 break;
925 }
926
927 switch (targetType.GetSelectionCategory())
928 {
930 SelectImplicitChannelTargets(spellEffectInfo, targetType);
931 break;
933 SelectImplicitNearbyTargets(spellEffectInfo, targetType, targetIndex, effectMask);
934 break;
936 SelectImplicitConeTargets(spellEffectInfo, targetType, targetIndex, effectMask);
937 break;
939 SelectImplicitAreaTargets(spellEffectInfo, targetType, targetIndex, effectMask);
940 break;
942 // just in case there is no dest, explanation in SelectImplicitDestDestTargets
943 CheckDst();
944
945 SelectImplicitTrajTargets(spellEffectInfo, targetType);
946 break;
948 SelectImplicitLineTargets(spellEffectInfo, targetType, targetIndex, effectMask);
949 break;
951 switch (targetType.GetObjectType())
952 {
954 switch (targetType.GetReferenceType())
955 {
958 break;
959 default:
960 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
961 break;
962 }
963 break;
965 switch (targetType.GetReferenceType())
966 {
968 SelectImplicitCasterDestTargets(spellEffectInfo, targetType, targetIndex);
969 break;
971 SelectImplicitTargetDestTargets(spellEffectInfo, targetType, targetIndex);
972 break;
974 SelectImplicitDestDestTargets(spellEffectInfo, targetType, targetIndex);
975 break;
976 default:
977 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
978 break;
979 }
980 break;
981 default:
982 switch (targetType.GetReferenceType())
983 {
985 SelectImplicitCasterObjectTargets(spellEffectInfo, targetType);
986 break;
988 SelectImplicitTargetObjectTargets(spellEffectInfo, targetType);
989 break;
990 default:
991 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
992 break;
993 }
994 break;
995 }
996 break;
998 TC_LOG_DEBUG("spells", "SPELL: target type {}, found in spellID {}, effect {} is not implemented yet!", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex), targetType.GetTarget());
999 break;
1000 default:
1001 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target category");
1002 break;
1003 }
1004}
1005
1007{
1009 {
1010 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target reference type");
1011 return;
1012 }
1013
1015 if (!channeledSpell)
1016 {
1017 TC_LOG_DEBUG("spells", "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1018 return;
1019 }
1020 switch (targetType.GetTarget())
1021 {
1023 {
1024 for (ObjectGuid const& channelTarget : m_originalCaster->m_unitData->ChannelObjects)
1025 {
1026 WorldObject* target = ObjectAccessor::GetUnit(*m_caster, channelTarget);
1027 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1028 // unit target may be no longer avalible - teleported out of map for example
1029 Unit* unitTarget = target ? target->ToUnit() : nullptr;
1030 if (unitTarget)
1031 AddUnitTarget(unitTarget, 1 << spellEffectInfo.EffectIndex);
1032 else
1033 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1034 }
1035 break;
1036 }
1038 if (channeledSpell->m_targets.HasDst())
1039 m_targets.SetDst(channeledSpell->m_targets);
1040 else
1041 {
1042 auto const& channelObjects = m_originalCaster->m_unitData->ChannelObjects;
1043 WorldObject* target = !channelObjects.empty() ? ObjectAccessor::GetWorldObject(*m_caster, *channelObjects.begin()) : nullptr;
1044 if (target)
1045 {
1046 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1047 if (target)
1048 {
1049 SpellDestination dest(*target);
1051 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1052
1053 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1054 m_targets.SetDst(dest);
1055 }
1056 }
1057 else
1058 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1059 }
1060 break;
1061 default:
1062 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
1063 break;
1064 }
1065}
1066
1067void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1068{
1070 {
1071 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
1072 return;
1073 }
1074
1075 float range = 0.0f;
1076 switch (targetType.GetCheckType())
1077 {
1078 case TARGET_CHECK_ENEMY:
1079 range = m_spellInfo->GetMaxRange(false, m_caster, this);
1080 break;
1081 case TARGET_CHECK_ALLY:
1082 case TARGET_CHECK_PARTY:
1083 case TARGET_CHECK_RAID:
1085 range = m_spellInfo->GetMaxRange(true, m_caster, this);
1086 break;
1087 case TARGET_CHECK_ENTRY:
1089 range = m_spellInfo->GetMaxRange(IsPositive(), m_caster, this);
1090 break;
1091 default:
1092 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
1093 break;
1094 }
1095
1096 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1097
1098 // handle emergency case - try to use other provided targets if no conditions provided
1099 if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
1100 {
1101 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));
1102 switch (targetType.GetObjectType())
1103 {
1106 {
1107 if (focusObject)
1108 AddGOTarget(focusObject, effMask);
1109 else
1110 {
1113 }
1114 return;
1115 }
1116 break;
1119 {
1120 if (focusObject)
1121 {
1124 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1125
1126 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1127 m_targets.SetDst(dest);
1128 }
1129 else
1130 {
1133 }
1134 return;
1135 }
1136 if (targetType.GetTarget() == TARGET_DEST_NEARBY_ENTRY_OR_DB)
1137 {
1138 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1139 {
1141 if (st->GetMapId() == m_caster->GetMapId() && m_caster->IsInDist(st, range))
1142 dest = st->GetPosition();
1143 else
1144 {
1145 float randomRadius = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1146 if (randomRadius > 0.0f)
1147 MovePosition(dest._position, m_caster, randomRadius, targetType.CalcDirectionAngle());
1148 }
1149
1150 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1151 m_targets.SetDst(dest);
1152 return;
1153 }
1154 }
1155 break;
1156 default:
1157 break;
1158 }
1159 }
1160
1161 WorldObject* target = SearchNearbyTarget(spellEffectInfo, range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
1162 float randomRadius = 0.0f;
1163 switch (targetType.GetTarget())
1164 {
1166 // if we are here then there was no db target
1167 if (!target)
1168 {
1169 target = m_caster;
1170 // radius is only meant to be randomized when using caster fallback
1171 randomRadius = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1172 }
1173 break;
1174 default:
1175 break;
1176 }
1177
1178 if (!target)
1179 {
1180 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1183 return;
1184 }
1185
1186 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1187 if (!target)
1188 {
1189 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set NULL target, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1192 return;
1193 }
1194
1195 switch (targetType.GetObjectType())
1196 {
1198 if (Unit* unit = target->ToUnit())
1199 AddUnitTarget(unit, effMask, true, false);
1200 else
1201 {
1202 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);
1205 return;
1206 }
1207 break;
1209 if (GameObject* gobjTarget = target->ToGameObject())
1210 AddGOTarget(gobjTarget, effMask);
1211 else
1212 {
1213 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);
1216 return;
1217 }
1218 break;
1220 if (Corpse* corpseTarget = target->ToCorpse())
1221 AddCorpseTarget(corpseTarget, effMask);
1222 else
1223 {
1224 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);
1227 return;
1228 }
1229 break;
1231 {
1232 SpellDestination dest(*target);
1233 if (randomRadius > 0.0f)
1234 MovePosition(dest._position, target, randomRadius, targetType.CalcDirectionAngle());
1235
1237 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1238
1239 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1240 m_targets.SetDst(dest);
1241 break;
1242 }
1243 default:
1244 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target object type");
1245 break;
1246 }
1247
1248 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1249}
1250
1251void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1252{
1253 Position coneSrc(*m_caster);
1254 float coneAngle = m_spellInfo->ConeAngle;
1255 switch (targetType.GetReferenceType())
1256 {
1258 break;
1262 break;
1263 default:
1264 break;
1265 }
1266
1267 switch (targetType.GetTarget())
1268 {
1270 if (coneAngle == 0.0f)
1271 coneAngle = 180.0f;
1272 break;
1273 default:
1274 break;
1275 }
1276
1277 std::list<WorldObject*> targets;
1278 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1279 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1280 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1281 float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1282
1283 if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
1284 {
1285 float extraSearchRadius = radius > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1286 Trinity::WorldObjectSpellConeTargetCheck check(coneSrc, DegToRad(coneAngle), m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
1288 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius + extraSearchRadius);
1289
1290 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1291
1292 if (!targets.empty())
1293 {
1294 // Other special target selection goes here
1295 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1296 Trinity::Containers::RandomResize(targets, maxTargets);
1297
1298 for (WorldObject* itr : targets)
1299 {
1300 if (Unit* unit = itr->ToUnit())
1301 AddUnitTarget(unit, effMask, false);
1302 else if (GameObject* gObjTarget = itr->ToGameObject())
1303 AddGOTarget(gObjTarget, effMask);
1304 else if (Corpse* corpse = itr->ToCorpse())
1305 AddCorpseTarget(corpse, effMask);
1306 }
1307 }
1308 }
1309}
1310
1311void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1312{
1313 WorldObject* referer = nullptr;
1314 switch (targetType.GetReferenceType())
1315 {
1319 referer = m_caster;
1320 break;
1322 referer = m_targets.GetUnitTarget();
1323 break;
1325 {
1326 referer = m_caster;
1327
1328 // find last added target for this effect
1329 for (auto ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
1330 {
1331 if (ihit->EffectMask & (1 << spellEffectInfo.EffectIndex))
1332 {
1333 referer = ObjectAccessor::GetUnit(*m_caster, ihit->TargetGUID);
1334 break;
1335 }
1336 }
1337 break;
1338 }
1339 default:
1340 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1341 return;
1342 }
1343
1344 if (!referer)
1345 return;
1346
1347 Position const* center = nullptr;
1348 switch (targetType.GetReferenceType())
1349 {
1351 center = m_targets.GetSrcPos();
1352 break;
1354 center = m_targets.GetDstPos();
1355 break;
1359 center = referer;
1360 break;
1361 default:
1362 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1363 return;
1364 }
1365
1366 float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1367 std::list<WorldObject*> targets;
1368 switch (targetType.GetTarget())
1369 {
1371 targets.push_back(m_caster);
1372 if (Unit* unit = m_caster->ToUnit())
1373 if (Vehicle const* vehicleKit = unit->GetVehicleKit())
1374 for (int8 seat = 0; seat < MAX_VEHICLE_SEATS; ++seat)
1375 if (Unit* passenger = vehicleKit->GetPassenger(seat))
1376 targets.push_back(passenger);
1377 break;
1379 if (Unit* targetedUnit = m_targets.GetUnitTarget())
1380 {
1381 if (!m_caster->IsUnit() || !m_caster->ToUnit()->IsInRaidWith(targetedUnit))
1382 targets.push_back(m_targets.GetUnitTarget());
1383 else
1384 SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1386 }
1387 break;
1389 targets.push_back(m_caster);
1390 SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1392 break;
1394 if (Unit* unit = m_caster->ToUnit())
1395 for (ThreatReference const* threatRef : unit->GetThreatManager().GetUnsortedThreatList())
1396 if (Unit* threateningUnit = threatRef->GetVictim())
1397 targets.push_back(threateningUnit);
1398 break;
1400 if (Creature* creature = m_caster->ToCreature())
1401 for (ObjectGuid const& tapperGuid : creature->GetTapList())
1402 if (Player* tapper = ObjectAccessor::GetPlayer(*m_caster, tapperGuid))
1403 targets.push_back(tapper);
1404 break;
1405 default:
1406 SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1408 break;
1409 }
1410
1412 {
1413 SpellDestination dest(*referer);
1415 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1416
1417 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1418
1419 m_targets.ModDst(dest);
1420 }
1421
1422 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1423
1425 targets.sort(Trinity::ObjectDistanceOrderPred(referer, false));
1426
1427 if (!targets.empty())
1428 {
1429 // Other special target selection goes here
1430 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1431 {
1433 Trinity::Containers::RandomResize(targets, maxTargets);
1434 else if (targets.size() > maxTargets)
1435 targets.resize(maxTargets);
1436 }
1437
1438 for (WorldObject* itr : targets)
1439 {
1440 if (Unit* unit = itr->ToUnit())
1441 AddUnitTarget(unit, effMask, false, true, center);
1442 else if (GameObject* gObjTarget = itr->ToGameObject())
1443 AddGOTarget(gObjTarget, effMask);
1444 else if (Corpse* corpse = itr->ToCorpse())
1445 AddCorpseTarget(corpse, effMask);
1446 }
1447 }
1448}
1449
1451{
1453
1454 switch (targetType.GetTarget())
1455 {
1456 case TARGET_DEST_CASTER:
1457 break;
1458 case TARGET_DEST_HOME:
1459 if (Player* playerCaster = m_caster->ToPlayer())
1460 dest = SpellDestination(playerCaster->m_homebind);
1461 break;
1462 case TARGET_DEST_DB:
1463 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1464 {
1467 dest = *st;
1468 else if (st->GetMapId() == m_caster->GetMapId())
1469 dest = st->GetPosition();
1470 }
1471 else
1472 {
1473 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1474 if (WorldObject* target = m_targets.GetObjectTarget())
1475 dest = *target;
1476 }
1477 break;
1479 {
1480 float minDist = m_spellInfo->GetMinRange(true);
1481 float maxDist = m_spellInfo->GetMaxRange(true);
1482 float dist = frand(minDist, maxDist);
1483 float x, y, z;
1484 float angle = rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
1486
1487 float ground = m_caster->GetMapHeight(x, y, z);
1488 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
1489 LiquidData liquidData;
1490 if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(), x, y, z, {}, &liquidData, m_caster->GetCollisionHeight()))
1491 liquidLevel = liquidData.level;
1492
1493 if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
1494 {
1498 return;
1499 }
1500
1501 if (ground + 0.75 > liquidLevel)
1502 {
1506 return;
1507 }
1508
1509 dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation());
1510 break;
1511 }
1514 {
1515 Unit* unitCaster = m_caster->ToUnit();
1516 if (!unitCaster)
1517 break;
1518
1519 float dist = spellEffectInfo.CalcRadius(unitCaster, targetIndex);
1520 float angle = targetType.CalcDirectionAngle();
1522 {
1523 angle = [&]()
1524 {
1526 {
1527 case MOVEMENTFLAG_NONE:
1533 return 0.0f;
1536 return static_cast<float>(M_PI);
1539 return static_cast<float>(M_PI / 2);
1541 return static_cast<float>(M_PI / 4);
1543 return static_cast<float>(3 * M_PI / 4);
1546 return static_cast<float>(-M_PI / 2);
1548 return static_cast<float>(-M_PI / 4);
1550 return static_cast<float>(-3 * M_PI / 4);
1551 default:
1552 return 0.0f;
1553 }
1554 }();
1555 }
1556
1557 Position pos = dest._position;
1558
1559 MovePosition(pos, unitCaster, dist, angle);
1560 dest.Relocate(pos);
1561 break;
1562 }
1566 break;
1568 if (Unit const* unitCaster = m_caster->ToUnit())
1569 if (TempSummon const* casterSummon = unitCaster->ToTempSummon())
1570 if (WorldObject const* summoner = casterSummon->GetSummoner())
1571 dest = SpellDestination(*summoner);
1572 break;
1574 {
1575 Optional<std::pair<float, float>> radiusBounds = spellEffectInfo.CalcRadiusBounds(m_caster, targetIndex, this);
1576 std::vector<SpellTargetPosition const*> positionsInRange;
1577 for (auto const& [_, position] : sSpellMgr->GetSpellTargetPositions(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1578 if (m_caster->GetMapId() == position.GetMapId() && (!radiusBounds || (!m_caster->IsInDist(position, radiusBounds->first) && m_caster->IsInDist(position, radiusBounds->second))))
1579 positionsInRange.push_back(&position);
1580
1581 if (positionsInRange.empty())
1582 {
1583 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1586 return;
1587 }
1588
1589 dest = Trinity::Containers::SelectRandomContainerElement(positionsInRange)->GetPosition();
1590 break;
1591 }
1592 default:
1593 {
1594 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1595 float angle = targetType.CalcDirectionAngle();
1596 float objSize = m_caster->GetCombatReach();
1597
1598 switch (targetType.GetTarget())
1599 {
1601 dist = PET_FOLLOW_DIST;
1602 break;
1604 if (dist > objSize)
1605 dist = objSize + (dist - objSize);
1606 break;
1611 {
1612 static constexpr float DefaultTotemDistance = 3.0f;
1613 if (!spellEffectInfo.HasRadius(targetIndex))
1614 dist = DefaultTotemDistance;
1615 break;
1616 }
1617 default:
1618 break;
1619 }
1620
1621 if (dist < objSize)
1622 dist = objSize;
1623
1624 Position pos = dest._position;
1625 MovePosition(pos, m_caster, dist, angle);
1626
1627 dest.Relocate(pos);
1628 break;
1629 }
1630 }
1631
1633 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1634
1635 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1636 m_targets.SetDst(dest);
1637}
1638
1640{
1642 "Spell::SelectImplicitTargetDestTargets - no explicit object target available!");
1643
1645 if (!target)
1646 return;
1647
1648 SpellDestination dest(*target);
1649
1650 switch (targetType.GetTarget())
1651 {
1655 break;
1656 default:
1657 {
1658 float angle = targetType.CalcDirectionAngle();
1659 float dist = spellEffectInfo.CalcRadius(nullptr, targetIndex);
1660
1661 Position pos = dest._position;
1662 MovePosition(pos, target, dist, angle);
1663
1664 dest.Relocate(pos);
1665 break;
1666 }
1667 }
1668
1670 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1671
1672 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1673 m_targets.SetDst(dest);
1674}
1675
1676void Spell::SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex)
1677{
1678 // set destination to caster if no dest provided
1679 // can only happen if previous destination target could not be set for some reason
1680 // (not found nearby target, or channel target for example
1681 // maybe we should abort the spell in such case?
1682 CheckDst();
1683
1685
1686 switch (targetType.GetTarget())
1687 {
1691 case TARGET_DEST_DEST:
1692 break;
1695 break;
1697 {
1698 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1699 Position pos = dest._position;
1700 float angle = pos.GetAbsoluteAngle(m_caster) - m_caster->GetOrientation();
1701
1702 MovePosition(pos, m_caster, dist, angle);
1704
1705 dest.Relocate(pos);
1706 break;
1707 }
1708 default:
1709 {
1710 float angle = targetType.CalcDirectionAngle();
1711 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1712
1713 Position pos = dest._position;
1714 MovePosition(pos, m_caster, dist, angle);
1715
1716 dest.Relocate(pos);
1717 break;
1718 }
1719 }
1720
1722 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1723
1724 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1725 m_targets.ModDst(dest);
1726}
1727
1729{
1730 WorldObject* target = nullptr;
1731 bool checkIfValid = true;
1732
1733 switch (targetType.GetTarget())
1734 {
1735 case TARGET_UNIT_CASTER:
1736 target = m_caster;
1737 checkIfValid = false;
1738 break;
1739 case TARGET_UNIT_MASTER:
1740 target = m_caster->GetCharmerOrOwner();
1741 break;
1742 case TARGET_UNIT_PET:
1743 if (Unit* unitCaster = m_caster->ToUnit())
1744 target = unitCaster->GetGuardianPet();
1745 break;
1747 if (Unit* unitCaster = m_caster->ToUnit())
1748 if (unitCaster->IsSummon())
1749 target = unitCaster->ToTempSummon()->GetSummonerUnit();
1750 break;
1752 if (Unit* unitCaster = m_caster->ToUnit())
1753 target = unitCaster->GetVehicleBase();
1754 break;
1763 if (Creature* vehicleBase = m_caster->ToCreature())
1764 if (vehicleBase->IsVehicle())
1765 target = vehicleBase->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
1766 break;
1768 if (Creature* creatureCaster = m_caster->ToCreature())
1769 if (!creatureCaster->GetTapList().empty())
1770 target = ObjectAccessor::GetWorldObject(*creatureCaster, Trinity::Containers::SelectRandomContainerElement(creatureCaster->GetTapList()));
1771 break;
1773 if (Unit const* unitCaster = m_caster->ToUnit())
1774 target = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetCritterGUID());
1775 break;
1776 default:
1777 break;
1778 }
1779
1780 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1781
1782 if (target)
1783 {
1784 if (Unit* unit = target->ToUnit())
1785 AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, checkIfValid);
1786 else if (GameObject* go = target->ToGameObject())
1787 AddGOTarget(go, 1 << spellEffectInfo.EffectIndex);
1788 else if (Corpse* corpse = target->ToCorpse())
1789 AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
1790 }
1791}
1792
1794{
1796 "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!");
1797
1799
1800 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1801
1802 if (target)
1803 {
1804 if (Unit* unit = target->ToUnit())
1805 AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, true, false);
1806 else if (GameObject* gobj = target->ToGameObject())
1807 AddGOTarget(gobj, 1 << spellEffectInfo.EffectIndex);
1808 else if (Corpse* corpse = target->ToCorpse())
1809 AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
1810
1811 SelectImplicitChainTargets(spellEffectInfo, targetType, target, 1 << spellEffectInfo.EffectIndex);
1812 }
1813 // Script hook can remove object target and we would wrongly land here
1814 else if (Item* item = m_targets.GetItemTarget())
1815 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
1816}
1817
1818void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask)
1819{
1820 int32 maxTargets = spellEffectInfo.ChainTargets;
1821 if (Player* modOwner = m_caster->GetSpellModOwner())
1822 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainTargets, maxTargets, this);
1823
1824 if (maxTargets > 1)
1825 {
1826 // mark damage multipliers as used
1827 for (size_t k = spellEffectInfo.EffectIndex; k < m_spellInfo->GetEffects().size(); ++k)
1828 if (effMask & (1 << k))
1829 m_damageMultipliers[k] = 1.0f;
1830 m_applyMultiplierMask |= effMask;
1831
1832 std::list<WorldObject*> targets;
1833 SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
1834 , spellEffectInfo, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
1835
1836 // Chain primary target is added earlier
1837 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1838
1840
1841 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
1842 {
1843 if (Unit* unit = (*itr)->ToUnit())
1844 AddUnitTarget(unit, effMask, false, true, losPosition);
1845
1847 losPosition = *itr;
1848 }
1849 }
1850}
1851
1852float tangent(float x)
1853{
1854 x = std::tan(x);
1855 //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
1856 //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
1857 //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
1858 if (x < 100000.0f && x > -100000.0f) return x;
1859 if (x >= 100000.0f) return 100000.0f;
1860 if (x <= 100000.0f) return -100000.0f;
1861 return 0.0f;
1862}
1863
1864void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType)
1865{
1866 if (!m_targets.HasTraj())
1867 return;
1868
1869 float dist2d = m_targets.GetDist2d();
1870 if (!dist2d)
1871 return;
1872
1873 Position srcPos = *m_targets.GetSrcPos();
1875 float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
1876
1877 std::list<WorldObject*> targets;
1880 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
1881 if (targets.empty())
1882 return;
1883
1885
1886 float b = tangent(m_targets.GetPitch());
1887 float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
1888 if (a > -0.0001f)
1889 a = 0.f;
1890
1891 // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
1892 // limit max range to 300 yards, sometimes triggered spells can have 50000yds
1893 float bestDist = m_spellInfo->GetMaxRange(false);
1894 if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, GetCastDifficulty()))
1895 bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
1896
1897 // GameObjects don't cast traj
1898 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
1899 for (auto itr = targets.begin(); itr != targets.end(); ++itr)
1900 {
1901 if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
1902 continue;
1903
1904 if (Unit* unit = (*itr)->ToUnit())
1905 {
1906 if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
1907 continue;
1908
1909 if (Creature* creatureTarget = unit->ToCreature())
1910 {
1911 if (!(creatureTarget->GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES))
1912 continue;
1913 }
1914 }
1915
1916 float const size = std::max((*itr)->GetCombatReach(), 1.0f);
1917 float const objDist2d = srcPos.GetExactDist2d(*itr);
1918 float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
1919
1920 float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
1921 float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
1922 float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
1923 float const height = distToHitPoint * (a * distToHitPoint + b);
1924
1925 if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
1926 continue;
1927
1928 if (distToHitPoint < bestDist)
1929 {
1930 bestDist = distToHitPoint;
1931 break;
1932 }
1933 }
1934
1935 if (dist2d > bestDist)
1936 {
1937 float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
1938 float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
1939 float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
1940
1941 SpellDestination dest(x, y, z, unitCaster->GetOrientation());
1943 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1944
1945 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1946 m_targets.ModDst(dest);
1947 }
1948}
1949
1950void Spell::SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1951{
1952 std::list<WorldObject*> targets;
1953 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1954 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1955 Position const* dst = nullptr;
1956 switch (targetType.GetReferenceType())
1957 {
1959 dst = m_targets.GetSrcPos();
1960 break;
1962 dst = m_targets.GetDstPos();
1963 break;
1965 dst = m_caster;
1966 break;
1968 dst = m_targets.GetUnitTarget();
1969 break;
1970 default:
1971 ABORT_MSG("Spell::SelectImplicitLineTargets: received not implemented target reference type");
1972 return;
1973 }
1974
1975 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1976 float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1977
1978 if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
1979 {
1980 Trinity::WorldObjectSpellLineTargetCheck check(m_caster, dst, m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
1982 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellLineTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, radius);
1983
1984 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1985
1986 if (!targets.empty())
1987 {
1988 // Other special target selection goes here
1989 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1990 {
1991 if (maxTargets < targets.size())
1992 {
1994 targets.resize(maxTargets);
1995 }
1996 }
1997
1998 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
1999 {
2000 if (Unit* unit = (*itr)->ToUnit())
2001 AddUnitTarget(unit, effMask, false);
2002 else if (GameObject* gObjTarget = (*itr)->ToGameObject())
2003 AddGOTarget(gObjTarget, effMask);
2004 else if (Corpse* corpse = (*itr)->ToCorpse())
2005 AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
2006 }
2007 }
2008 }
2009}
2010
2012{
2013 // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER, queue them on map for later execution
2014 switch (spellEffectInfo.Effect)
2015 {
2019 {
2022
2023 // scripts may modify the target - recheck
2024 if (target && target->GetTypeId() == TYPEID_PLAYER)
2025 {
2026 // target is not stored in target map for those spells
2027 // since we're completely skipping AddUnitTarget logic, we need to check immunity manually
2028 // eg. aura 21546 makes target immune to summons
2029 Player* player = target->ToPlayer();
2030 if (player->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, nullptr))
2031 return;
2032
2033 target->GetMap()->AddFarSpellCallback([spell = this, &spellEffectInfo, targetGuid = target->GetGUID()](Map* map)
2034 {
2035 Player* player = ObjectAccessor::GetPlayer(map, targetGuid);
2036 if (!player)
2037 return;
2038
2039 // check immunity again in case it changed during update
2040 if (player->IsImmunedToSpellEffect(spell->GetSpellInfo(), spellEffectInfo, nullptr))
2041 return;
2042
2043 spell->HandleEffects(player, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2044 });
2045 }
2046 }
2047 return;
2048 default:
2049 break;
2050 }
2051
2052 // select spell implicit targets based on effect type
2053 if (!spellEffectInfo.GetImplicitTargetType())
2054 return;
2055
2056 uint32 targetMask = spellEffectInfo.GetMissingTargetMask();
2057
2058 if (!targetMask)
2059 return;
2060
2061 WorldObject* target = nullptr;
2062
2063 switch (spellEffectInfo.GetImplicitTargetType())
2064 {
2065 // add explicit object target or self to the target map
2067 // player which not released his spirit is Unit, but target flag for it is TARGET_FLAG_CORPSE_MASK
2069 {
2070 if (Unit* unit = m_targets.GetUnitTarget())
2071 target = unit;
2072 else if (targetMask & TARGET_FLAG_CORPSE_MASK)
2073 {
2074 if (Corpse* corpseTarget = m_targets.GetCorpseTarget())
2075 target = corpseTarget;
2076 }
2077 else //if (targetMask & TARGET_FLAG_UNIT_MASK)
2078 target = m_caster;
2079 }
2080 if (targetMask & TARGET_FLAG_ITEM_MASK)
2081 {
2082 if (Item* item = m_targets.GetItemTarget())
2083 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
2084 return;
2085 }
2086 if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK)
2087 target = m_targets.GetGOTarget();
2088 break;
2089 // add self to the target map
2091 if (targetMask & TARGET_FLAG_UNIT_MASK)
2092 target = m_caster;
2093 break;
2094 default:
2095 break;
2096 }
2097
2099
2100 if (target)
2101 {
2102 if (target->ToUnit())
2103 AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex, false);
2104 else if (target->ToGameObject())
2105 AddGOTarget(target->ToGameObject(), 1 << spellEffectInfo.EffectIndex);
2106 else if (target->ToCorpse())
2107 AddCorpseTarget(target->ToCorpse(), 1 << spellEffectInfo.EffectIndex);
2108 }
2109}
2110
2111uint32 Spell::GetSearcherTypeMask(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const* condList)
2112{
2113 // this function selects which containers need to be searched for spell target
2115
2116 // filter searchers based on searched object type
2117 switch (objType)
2118 {
2122 break;
2127 break;
2131 break;
2132 default:
2133 break;
2134 }
2135
2139 retMask &= GRID_MAP_TYPE_MASK_PLAYER;
2141 retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
2142
2143 if (condList)
2144 retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
2145 return retMask;
2146}
2147
2148template<class SEARCHER>
2149void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius)
2150{
2151 if (!containerMask)
2152 return;
2153
2154 // search world and grid for possible targets
2155 bool searchInGrid = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT)) != 0;
2156 bool searchInWorld = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE)) != 0;
2157 if (searchInGrid || searchInWorld)
2158 {
2159 float x, y;
2160 x = pos->GetPositionX();
2161 y = pos->GetPositionY();
2162
2164 Cell cell(p);
2165 cell.SetNoCreate();
2166
2167 Map* map = referer->GetMap();
2168
2169 if (searchInWorld)
2170 Cell::VisitWorldObjects(x, y, map, searcher, radius);
2171
2172 if (searchInGrid)
2173 Cell::VisitGridObjects(x, y, map, searcher, radius);
2174 }
2175}
2176
2177template TC_GAME_API void Spell::SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
2178template TC_GAME_API void Spell::SearchTargets<Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(Trinity::UnitListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius);
2179
2180WorldObject* Spell::SearchNearbyTarget(SpellEffectInfo const& spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
2181{
2182 WorldObject* target = nullptr;
2183 uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
2184 if (!containerTypeMask)
2185 return nullptr;
2186
2187 Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList, objectType);
2190 SearchTargets<Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, range);
2191 return target;
2192}
2193
2194void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, SpellEffectInfo const& spellEffectInfo, float range, Position const* position, WorldObject* referer,
2195 SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList,
2197{
2198 uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
2199 if (!containerTypeMask)
2200 return;
2201
2202 float extraSearchRadius = range > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
2203 Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList, objectType, searchReason);
2206 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(searcher, containerTypeMask, m_caster, position, range + extraSearchRadius);
2207}
2208
2209void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType,
2210 SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal)
2211{
2212 // max dist for jump target selection
2213 float jumpRadius = 0.0f;
2214 switch (m_spellInfo->DmgClass)
2215 {
2217 // 7.5y for multi shot
2218 jumpRadius = 7.5f;
2219 break;
2221 // 5y for swipe, cleave and similar
2222 jumpRadius = 5.0f;
2223 break;
2226 // 12.5y for chain heal spell since 3.2 patch
2227 if (isChainHeal)
2228 jumpRadius = 12.5f;
2229 // 10y as default for magic chain spells
2230 else
2231 jumpRadius = 10.0f;
2232 break;
2233 }
2234
2235 if (Player* modOwner = m_caster->GetSpellModOwner())
2236 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainJumpDistance, jumpRadius, this);
2237
2238 // max dist which spell can reach
2239 float searchRadius = [&]()
2240 {
2242 return GetMinMaxRange(false).second;
2243
2245 return jumpRadius;
2246
2247 return jumpRadius * chainTargets;
2248 }();
2249
2251 std::list<WorldObject*> tempTargets;
2252 SearchAreaTargets(tempTargets, spellEffectInfo, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions.get(),
2254 tempTargets.remove(target);
2255
2256 // remove targets which are always invalid for chain spells
2257 // for some spells allow only chain targets in front of caster (swipe for example)
2259 {
2260 tempTargets.remove_if([&](WorldObject* object)
2261 {
2262 return !m_caster->HasInArc(static_cast<float>(M_PI), object);
2263 });
2264 }
2265
2266 while (chainTargets)
2267 {
2268 // try to get unit for next chain jump
2269 std::list<WorldObject*>::iterator foundItr = tempTargets.end();
2270 // get unit with highest hp deficit in dist
2271 if (isChainHeal)
2272 {
2273 uint32 maxHPDeficit = 0;
2274 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2275 {
2276 if (Unit* unit = (*itr)->ToUnit())
2277 {
2278 uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
2279 if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && chainSource->IsWithinDist(unit, jumpRadius) && IsWithinLOS(chainSource, unit, false, VMAP::ModelIgnoreFlags::M2))
2280 {
2281 foundItr = itr;
2282 maxHPDeficit = deficit;
2283 }
2284 }
2285 }
2286 }
2287 // get closest object
2288 else
2289 {
2290 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2291 {
2292 bool isBestDistanceMatch = foundItr != tempTargets.end() ? chainSource->GetDistanceOrder(*itr, *foundItr) : chainSource->IsWithinDist(*itr, jumpRadius);
2293 if (!isBestDistanceMatch)
2294 continue;
2295
2296 if (!IsWithinLOS(chainSource, *itr, false, VMAP::ModelIgnoreFlags::M2))
2297 continue;
2298
2300 continue;
2301
2302 foundItr = itr;
2303 }
2304 }
2305 // not found any valid target - chain ends
2306 if (foundItr == tempTargets.end())
2307 break;
2308
2310 chainSource = *foundItr;
2311
2312 targets.push_back(*foundItr);
2313 tempTargets.erase(foundItr);
2314 --chainTargets;
2315 }
2316}
2317
2319{
2320 GameObject* focus = nullptr;
2324 return focus;
2325}
2326
2328{
2329 //==========================================================================================
2330 // Now fill data for trigger system, need know:
2331 // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
2332 //==========================================================================================
2333
2335 // Get data for type of attack and fill base info for trigger
2336 switch (m_spellInfo->DmgClass)
2337 {
2340 if (m_attackType == OFF_ATTACK)
2342 else
2345 break;
2347 // Auto attack
2349 {
2352 }
2353 else // Ranged spell attack
2354 {
2357 }
2358 break;
2359 default:
2362 && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT)) // Wands auto attack
2363 {
2366 }
2367 // For other spells trigger procflags are set in Spell::TargetInfo::DoDamageAndTriggers
2368 // Because spell positivity is dependant on target
2369 }
2370}
2371
2373{
2374 m_UniqueTargetInfo.clear();
2375 m_UniqueGOTargetInfo.clear();
2376 m_UniqueItemInfo.clear();
2377 m_delayMoment = 0;
2378}
2379
2381{
2382 public:
2383 ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
2384
2385 bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
2386 {
2388 if (!caster)
2389 return true;
2390
2391 ProcFlags const typeMaskActor = PROC_FLAG_NONE;
2394 ProcFlagsSpellPhase const spellPhaseMask = PROC_SPELL_PHASE_NONE;
2395 ProcFlagsHit const hitMask = PROC_HIT_REFLECT;
2396
2397 Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
2398 return true;
2399 }
2400
2401 private:
2404};
2405
2406void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
2407{
2408 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2409 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(target, spellEffectInfo, losPosition))
2410 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2411
2412 // no effects left
2413 if (!effectMask)
2414 return;
2415
2416 if (checkIfValid)
2417 if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
2418 return;
2419
2420 // Check for effect immune skip if immuned
2421 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2422 if (target->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, m_caster))
2423 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2424
2425 ObjectGuid targetGUID = target->GetGUID();
2426
2427 // Lookup target in already in list
2428 auto ihit = std::find_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [targetGUID](TargetInfo const& target) { return target.TargetGUID == targetGUID; });
2429 if (ihit != std::end(m_UniqueTargetInfo)) // Found in list
2430 {
2431 // Immune effects removed from mask
2432 ihit->EffectMask |= effectMask;
2433 return;
2434 }
2435
2436 // This is new target calculate data for him
2437
2438 // Get spell hit result on target
2439 TargetInfo targetInfo;
2440 targetInfo.TargetGUID = targetGUID; // Store target GUID
2441 targetInfo.EffectMask = effectMask; // Store all effects not immune
2442 targetInfo.IsAlive = target->IsAlive();
2443 targetInfo.Damage = 0;
2444 targetInfo.Healing = 0;
2445 targetInfo.IsCrit = false;
2446
2447 // Calculate hit result
2449 targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
2450
2451 // Spell have speed - need calculate incoming time
2452 // Incoming time is zero for self casts. At least I think so.
2453 if (m_caster != target)
2454 {
2455 float hitDelay = m_spellInfo->LaunchDelay;
2456 WorldObject const* missileSource = m_caster;
2458 {
2459 auto previousTargetItr = std::find_if(m_UniqueTargetInfo.rbegin(), m_UniqueTargetInfo.rend(), [effectMask](TargetInfo const& target)
2460 {
2461 return (target.EffectMask & effectMask) != 0;
2462 });
2463 if (previousTargetItr != std::rend(m_UniqueTargetInfo))
2464 {
2465 hitDelay = 0.0f; // this is not the first target in chain, LaunchDelay was already included
2466
2467 if (WorldObject* previousTarget = ObjectAccessor::GetWorldObject(*m_caster, previousTargetItr->TargetGUID))
2468 missileSource = previousTarget;
2469
2470 targetInfo.TimeDelay += previousTargetItr->TimeDelay;
2471 }
2472 }
2473
2475 hitDelay += m_spellInfo->Speed;
2476 else if (m_spellInfo->Speed > 0.0f)
2477 {
2478 // calculate spell incoming interval
2480 float dist = std::max(missileSource->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), 5.0f);
2481 hitDelay += dist / m_spellInfo->Speed;
2482 }
2483
2484 targetInfo.TimeDelay += uint64(std::floor(hitDelay * 1000.0f));
2485 }
2486 else
2487 targetInfo.TimeDelay = 0ULL;
2488
2489 // If target reflect spell back to caster
2490 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
2491 {
2492 // Calculate reflected spell result on caster (shouldn't be able to reflect gameobject spells)
2493 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
2494 targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice
2495
2496 // Proc spell reflect aura when missile hits the original target
2498
2499 // Increase time interval for reflected spells by 1.5
2500 targetInfo.TimeDelay += targetInfo.TimeDelay >> 1;
2501 }
2502 else
2503 targetInfo.ReflectResult = SPELL_MISS_NONE;
2504
2505 // Calculate minimum incoming time
2506 if (targetInfo.TimeDelay && (!m_delayMoment || m_delayMoment > targetInfo.TimeDelay))
2507 m_delayMoment = targetInfo.TimeDelay;
2508
2509 // Add target to list
2510 m_UniqueTargetInfo.emplace_back(std::move(targetInfo));
2511}
2512
2514{
2515 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2516 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(go, spellEffectInfo))
2517 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2518
2519 // no effects left
2520 if (!effectMask)
2521 return;
2522
2523 ObjectGuid targetGUID = go->GetGUID();
2524
2525 // Lookup target in already in list
2526 auto ihit = std::find_if(std::begin(m_UniqueGOTargetInfo), std::end(m_UniqueGOTargetInfo), [targetGUID](GOTargetInfo const& target) { return target.TargetGUID == targetGUID; });
2527 if (ihit != std::end(m_UniqueGOTargetInfo)) // Found in list
2528 {
2529 // Add only effect mask
2530 ihit->EffectMask |= effectMask;
2531 return;
2532 }
2533
2534 // This is new target calculate data for him
2535
2536 GOTargetInfo target;
2537 target.TargetGUID = targetGUID;
2538 target.EffectMask = effectMask;
2539
2540 // Spell have speed - need calculate incoming time
2541 if (static_cast<WorldObject*>(m_caster) != go)
2542 {
2543 float hitDelay = m_spellInfo->LaunchDelay;
2545 hitDelay += m_spellInfo->Speed;
2546 else if (m_spellInfo->Speed > 0.0f)
2547 {
2548 // calculate spell incoming interval
2549 float dist = std::max(m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()), 5.0f);
2550 hitDelay += dist / m_spellInfo->Speed;
2551 }
2552
2553 target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
2554 }
2555 else
2556 target.TimeDelay = 0ULL;
2557
2558 // Calculate minimum incoming time
2559 if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
2560 m_delayMoment = target.TimeDelay;
2561
2562 // Add target to list
2563 m_UniqueGOTargetInfo.emplace_back(std::move(target));
2564}
2565
2566void Spell::AddItemTarget(Item* item, uint32 effectMask)
2567{
2568 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2569 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(item, spellEffectInfo))
2570 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2571
2572 // no effects left
2573 if (!effectMask)
2574 return;
2575
2576 // Lookup target in already in list
2577 auto ihit = std::find_if(std::begin(m_UniqueItemInfo), std::end(m_UniqueItemInfo), [item](ItemTargetInfo const& target) { return target.TargetItem == item; });
2578 if (ihit != std::end(m_UniqueItemInfo)) // Found in list
2579 {
2580 // Add only effect mask
2581 ihit->EffectMask |= effectMask;
2582 return;
2583 }
2584
2585 // This is new target add data
2586
2587 ItemTargetInfo target;
2588 target.TargetItem = item;
2589 target.EffectMask = effectMask;
2590
2591 m_UniqueItemInfo.emplace_back(std::move(target));
2592}
2593
2594void Spell::AddCorpseTarget(Corpse* corpse, uint32 effectMask)
2595{
2596 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2597 if (!spellEffectInfo.IsEffect())
2598 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2599
2600 // no effects left
2601 if (!effectMask)
2602 return;
2603
2604 ObjectGuid targetGUID = corpse->GetGUID();
2605
2606 // Lookup target in already in list
2607 auto ihit = std::find_if(std::begin(m_UniqueCorpseTargetInfo), std::end(m_UniqueCorpseTargetInfo), [targetGUID](CorpseTargetInfo const& target) { return target.TargetGUID == targetGUID; });
2608 if (ihit != std::end(m_UniqueCorpseTargetInfo)) // Found in list
2609 {
2610 // Add only effect mask
2611 ihit->EffectMask |= effectMask;
2612 return;
2613 }
2614
2615 // This is new target calculate data for him
2616 CorpseTargetInfo target;
2617 target.TargetGUID = targetGUID;
2618 target.EffectMask = effectMask;
2619
2620 // Spell have speed - need calculate incoming time
2621 if (m_caster != corpse)
2622 {
2623 float hitDelay = m_spellInfo->LaunchDelay;
2625 hitDelay += m_spellInfo->Speed;
2626 else if (m_spellInfo->Speed > 0.0f)
2627 {
2628 // calculate spell incoming interval
2629 float dist = std::max(m_caster->GetDistance(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ()), 5.0f);
2630 hitDelay += dist / m_spellInfo->Speed;
2631 }
2632
2633 target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
2634 }
2635 else
2636 target.TimeDelay = 0LL;
2637
2638 // Calculate minimum incoming time
2639 if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
2640 m_delayMoment = target.TimeDelay;
2641
2642 // Add target to list
2643 m_UniqueCorpseTargetInfo.emplace_back(std::move(target));
2644}
2645
2647{
2648 m_destTargets[effIndex] = dest;
2649}
2650
2652{
2653 int32 index = 0;
2654 for (TargetInfo const& uniqueTargetInfo : m_UniqueTargetInfo)
2655 {
2656 if (uniqueTargetInfo.MissCondition == SPELL_MISS_NONE && uniqueTargetInfo.EffectMask & (1 << effect))
2657 {
2658 if (uniqueTargetInfo.TargetGUID == target)
2659 break;
2660
2661 ++index;
2662 }
2663 }
2664
2665 return index;
2666}
2667
2669{
2670 return std::count_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effect](TargetInfo const& targetInfo)
2671 {
2672 return targetInfo.MissCondition == SPELL_MISS_NONE && targetInfo.EffectMask & (1 << effect);
2673 });
2674}
2675
2677{
2678 return std::count_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [effect](GOTargetInfo const& targetInfo)
2679 {
2680 return targetInfo.EffectMask & (1 << effect);
2681 });
2682}
2683
2685{
2686 return std::count_if(m_UniqueItemInfo.begin(), m_UniqueItemInfo.end(), [effect](ItemTargetInfo const& targetInfo)
2687 {
2688 return targetInfo.EffectMask & (1 << effect);
2689 });
2690}
2691
2693{
2694 return std::count_if(m_UniqueCorpseTargetInfo.begin(), m_UniqueCorpseTargetInfo.end(), [effect](CorpseTargetInfo const& targetInfo)
2695 {
2696 return targetInfo.EffectMask & (1 << effect);
2697 });
2698}
2699
2701{
2702 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2703 if (!unit)
2704 return;
2705
2706 // Need init unitTarget by default unit (can changed in code on reflect)
2707 spell->unitTarget = unit;
2708
2709 // Reset damage/healing counter
2710 spell->m_damage = Damage;
2711 spell->m_healing = Healing;
2712
2713 _spellHitTarget = nullptr;
2715 _spellHitTarget = unit;
2717 _spellHitTarget = spell->m_caster->ToUnit();
2718
2720 unit->SetInCombatWith(spell->m_originalCaster);
2721
2722 // if target is flagged for pvp also flag caster if a player
2723 // but respect current pvp rules (buffing/healing npcs flagged for pvp only flags you if they are in combat)
2725 && unit->IsPvP() && (unit->IsInCombat() || unit->IsCharmedOwnedByPlayerOrPlayer()) && spell->m_caster->GetTypeId() == TYPEID_PLAYER; // need to check PvP state before spell effects, but act on it afterwards
2726
2727 if (_spellHitTarget)
2728 {
2729 SpellMissInfo missInfo = spell->PreprocessSpellHit(_spellHitTarget, *this);
2730 if (missInfo != SPELL_MISS_NONE)
2731 {
2732 if (missInfo != SPELL_MISS_MISS)
2733 spell->m_caster->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
2734 spell->m_damage = 0;
2735 spell->m_healing = 0;
2736 _spellHitTarget = nullptr;
2737 }
2738 }
2739
2740 spell->CallScriptOnHitHandlers();
2741
2742 // scripts can modify damage/healing for current target, save them
2743 Damage = spell->m_damage;
2744 Healing = spell->m_healing;
2745}
2746
2748{
2749 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2750 if (!unit)
2751 return;
2752
2753 // Need init unitTarget by default unit (can changed in code on reflect)
2754 // Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
2755 spell->unitTarget = unit;
2756 spell->targetMissInfo = MissCondition;
2757
2758 // Reset damage/healing counter
2759 spell->m_damage = Damage;
2760 spell->m_healing = Healing;
2761
2762 if (unit->IsAlive() != IsAlive && !spell->m_spellInfo->HasAttribute(SPELL_ATTR9_FORCE_CORPSE_TARGET))
2763 return;
2764
2766 return; // No missinfo in that case
2767
2768 if (_spellHitTarget)
2769 spell->DoSpellEffectHit(_spellHitTarget, spellEffectInfo, *this);
2770
2771 // scripts can modify damage/healing for current target, save them
2772 Damage = spell->m_damage;
2773 Healing = spell->m_healing;
2774}
2775
2777{
2778 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2779 if (!unit)
2780 return;
2781
2782 // other targets executed before this one changed pointer
2783 spell->unitTarget = unit;
2784 if (_spellHitTarget)
2785 spell->unitTarget = _spellHitTarget;
2786
2787 // Reset damage/healing counter
2788 spell->m_damage = Damage;
2789 spell->m_healing = Healing;
2790
2791 // Get original caster (if exist) and calculate damage/healing from him data
2792 // Skip if m_originalCaster not available
2793 Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit();
2794 if (caster)
2795 {
2796 // Fill base trigger info
2797 ProcFlagsInit procAttacker = spell->m_procAttacker;
2798 ProcFlagsInit procVictim = spell->m_procVictim;
2800
2801 // Spells with this flag cannot trigger if effect is cast on self
2802 bool const canEffectTrigger = spell->unitTarget->CanProc();
2803
2804 // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
2805 if (canEffectTrigger && !procAttacker && !procVictim)
2806 {
2807 bool positive = true;
2808 if (spell->m_damage > 0)
2809 positive = false;
2810 else if (!spell->m_healing)
2811 {
2812 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
2813 {
2814 // in case of immunity, check all effects to choose correct procFlags, as none has technically hit
2815 if (EffectMask && !(EffectMask & (1 << i)))
2816 continue;
2817
2818 if (!spell->m_spellInfo->IsPositiveEffect(i))
2819 {
2820 positive = false;
2821 break;
2822 }
2823 }
2824 }
2825
2826 switch (spell->m_spellInfo->DmgClass)
2827 {
2831 {
2832 if (positive)
2833 {
2834 procAttacker |= PROC_FLAG_DEAL_HELPFUL_PERIODIC;
2835 procVictim |= PROC_FLAG_TAKE_HELPFUL_PERIODIC;
2836 }
2837 else
2838 {
2839 procAttacker |= PROC_FLAG_DEAL_HARMFUL_PERIODIC;
2840 procVictim |= PROC_FLAG_TAKE_HARMFUL_PERIODIC;
2841 }
2842 }
2844 {
2845 if (positive)
2846 {
2847 procAttacker |= PROC_FLAG_DEAL_HELPFUL_ABILITY;
2848 procVictim |= PROC_FLAG_TAKE_HELPFUL_ABILITY;
2849 }
2850 else
2851 {
2852 procAttacker |= PROC_FLAG_DEAL_HARMFUL_ABILITY;
2853 procVictim |= PROC_FLAG_TAKE_HARMFUL_ABILITY;
2854 }
2855 }
2856 else
2857 {
2858 if (positive)
2859 {
2860 procAttacker |= PROC_FLAG_DEAL_HELPFUL_SPELL;
2861 procVictim |= PROC_FLAG_TAKE_HELPFUL_SPELL;
2862 }
2863 else
2864 {
2865 procAttacker |= PROC_FLAG_DEAL_HARMFUL_SPELL;
2866 procVictim |= PROC_FLAG_TAKE_HARMFUL_SPELL;
2867 }
2868 }
2869 break;
2870 }
2871 }
2872
2873 // All calculated do it!
2874 // Do healing
2875 bool hasHealing = false;
2876 std::unique_ptr<DamageInfo> spellDamageInfo;
2877 std::unique_ptr<HealInfo> healInfo;
2878 if (spell->m_healing > 0)
2879 {
2880 hasHealing = true;
2881 uint32 addhealth = spell->m_healing;
2882 if (IsCrit)
2883 {
2884 ProcHitMask |= PROC_HIT_CRITICAL;
2885 addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr);
2886 }
2887 else
2888 ProcHitMask |= PROC_HIT_NORMAL;
2889
2890 healInfo = std::make_unique<HealInfo>(caster, spell->unitTarget, addhealth, spell->m_spellInfo, spell->m_spellInfo->GetSchoolMask());
2891 caster->HealBySpell(*healInfo, IsCrit);
2892 spell->unitTarget->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo->GetEffectiveHeal()) * 0.5f, spell->m_spellInfo);
2893 spell->m_healing = healInfo->GetEffectiveHeal();
2894
2895 procSpellType |= PROC_SPELL_TYPE_HEAL;
2896 }
2897
2898 // Do damage
2899 bool hasDamage = false;
2900 if (spell->m_damage > 0)
2901 {
2902 hasDamage = true;
2903 // Fill base damage struct (unitTarget - is real spell target)
2904 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo, spell->m_SpellVisual, spell->m_spellSchoolMask, spell->m_castId);
2905 // Check damage immunity
2906 if (spell->unitTarget->IsImmunedToDamage(caster, spell->m_spellInfo))
2907 {
2908 ProcHitMask = PROC_HIT_IMMUNE;
2909 spell->m_damage = 0;
2910
2911 // no packet found in sniffs
2912 }
2913 else
2914 {
2915 caster->SetLastDamagedTargetGuid(spell->unitTarget->GetGUID());
2916
2917 // Add bonuses and fill damageInfo struct
2918 caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit, MissCondition == SPELL_MISS_BLOCK, spell);
2919 Unit::DealDamageMods(damageInfo.attacker, damageInfo.target, damageInfo.damage, &damageInfo.absorb);
2920
2921 ProcHitMask |= createProcHitMask(&damageInfo, MissCondition);
2922 procVictim |= PROC_FLAG_TAKE_ANY_DAMAGE;
2923
2924 // sparring
2925 if (damageInfo.target != damageInfo.attacker)
2926 {
2927 if (Creature* victimCreature = damageInfo.target->ToCreature())
2928 damageInfo.damage = victimCreature->CalculateDamageForSparring(damageInfo.attacker, damageInfo.damage);
2929 }
2930 spell->m_damage = damageInfo.damage;
2931
2932 caster->DealSpellDamage(&damageInfo, true);
2933
2934 // Send log damage message to client
2935 caster->SendSpellNonMeleeDamageLog(&damageInfo);
2936 }
2937
2938 // Do triggers for unit
2939 if (canEffectTrigger)
2940 {
2941 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, SPELL_DIRECT_DAMAGE, spell->m_attackType, ProcHitMask);
2942 procSpellType |= PROC_SPELL_TYPE_DAMAGE;
2943 }
2944 }
2945
2946 // Passive spell hits/misses or active spells only misses (only triggers)
2947 if (!hasHealing && !hasDamage)
2948 {
2949 // Fill base damage struct (unitTarget - is real spell target)
2950 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo, spell->m_SpellVisual, spell->m_spellSchoolMask);
2951 ProcHitMask |= createProcHitMask(&damageInfo, MissCondition);
2952 // Do triggers for unit
2953 if (canEffectTrigger)
2954 {
2955 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, ProcHitMask);
2956 procSpellType |= PROC_SPELL_TYPE_NO_DMG_HEAL;
2957 }
2958
2959 // Failed Pickpocket, reveal rogue
2961 {
2962 Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit());
2964 spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster);
2965 }
2966 }
2967
2968 // Do triggers for unit
2969 if (canEffectTrigger)
2970 {
2971 Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, ProcHitMask, spell, spellDamageInfo.get(), healInfo.get());
2972
2973 // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
2974 if (caster->GetTypeId() == TYPEID_PLAYER && (procSpellType & (PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL)))
2975 {
2978 caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo);
2979 }
2980 }
2981
2982 // set hitmask for finish procs
2983 spell->m_hitMask |= ProcHitMask;
2984 spell->m_procSpellType |= procSpellType;
2985
2986 // _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit
2987 if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
2988 {
2989 if (Unit* unitCaster = spell->m_caster->ToUnit())
2990 {
2991 unitCaster->AtTargetAttacked(unit, spell->m_spellInfo->HasInitialAggro());
2992
2994 if (Creature* targetCreature = unit->ToCreature())
2995 if (unitCaster->IsPlayer())
2996 targetCreature->SetTappedBy(unitCaster);
2997 }
2998
3001 }
3002
3003 // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
3005 caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, spell);
3006 }
3007
3008 if (_spellHitTarget)
3009 {
3010 //AI functions
3011 if (Creature* cHitTarget = _spellHitTarget->ToCreature())
3012 if (CreatureAI* hitTargetAI = cHitTarget->AI())
3013 hitTargetAI->SpellHit(spell->m_caster, spell->m_spellInfo);
3014
3015 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
3016 spell->m_caster->ToCreature()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
3017 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
3018 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
3019
3020 if (HitAura)
3021 {
3022 if (AuraApplication* aurApp = HitAura->GetApplicationOfTarget(_spellHitTarget->GetGUID()))
3023 {
3024 // only apply unapplied effects (for reapply case)
3025 uint32 effMask = EffectMask & aurApp->GetEffectsToApply();
3026 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
3027 if ((effMask & (1 << i)) && aurApp->HasEffect(i))
3028 effMask &= ~(1 << i);
3029
3030 if (effMask)
3031 _spellHitTarget->_ApplyAura(aurApp, effMask);
3032
3033 if (aurApp->IsNeedClientUpdate() && aurApp->GetRemoveMode() == AURA_REMOVE_NONE)
3034 {
3035 aurApp->ClientUpdate(false);
3036 _spellHitTarget->RemoveVisibleAuraUpdate(aurApp);
3037 }
3038 }
3039 }
3040
3041 // Needs to be called after dealing damage/healing to not remove breaking on damage auras
3042 spell->DoTriggersOnSpellHit(_spellHitTarget);
3043 }
3044
3045 if (_enablePVP)
3046 spell->m_caster->ToPlayer()->UpdatePvP(true);
3047
3048 spell->_spellAura = HitAura;
3050 spell->_spellAura = nullptr;
3051}
3052
3054{
3055 GameObject* go = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToGameObject() : ObjectAccessor::GetGameObject(*spell->m_caster, TargetGUID);
3056 if (!go)
3057 return;
3058
3060
3061 spell->HandleEffects(nullptr, nullptr, go, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3062
3063 // AI functions
3064 if (go->AI())
3065 go->AI()->SpellHit(spell->m_caster, spell->m_spellInfo);
3066
3067 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
3068 spell->m_caster->ToCreature()->AI()->SpellHitTarget(go, spell->m_spellInfo);
3069 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
3070 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(go, spell->m_spellInfo);
3071
3072 spell->CallScriptOnHitHandlers();
3074}
3075
3077{
3079
3080 spell->HandleEffects(nullptr, TargetItem, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3081
3082 spell->CallScriptOnHitHandlers();
3084}
3085
3087{
3088 Corpse* corpse = ObjectAccessor::GetCorpse(*spell->m_caster, TargetGUID);
3089 if (!corpse)
3090 return;
3091
3093
3094 spell->HandleEffects(nullptr, nullptr, nullptr, corpse, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3095
3096 spell->CallScriptOnHitHandlers();
3098}
3099
3101{
3102 if (!unit)
3103 return SPELL_MISS_EVADE;
3104
3105 // Target may have begun evading between launch and hit phases - re-check now
3106 if (Creature* creatureTarget = unit->ToCreature())
3107 if (creatureTarget->IsEvadingAttacks())
3108 return SPELL_MISS_EVADE;
3109
3110 // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
3111 if (hitInfo.TimeDelay && unit->IsImmunedToSpell(m_spellInfo, m_caster))
3112 return SPELL_MISS_IMMUNE;
3113
3115
3116 if (Player* player = unit->ToPlayer())
3117 {
3118 player->FailCriteria(CriteriaFailEvent::BeSpellTarget, m_spellInfo->Id);
3119 player->StartCriteria(CriteriaStartEvent::BeSpellTarget, m_spellInfo->Id);
3120 player->UpdateCriteria(CriteriaType::BeSpellTarget, m_spellInfo->Id, 0, 0, m_caster);
3121 }
3122
3123 if (Player* player = m_caster->ToPlayer())
3124 player->UpdateCriteria(CriteriaType::LandTargetedSpellOnTarget, m_spellInfo->Id, 0, 0, unit);
3125
3126 if (m_caster != unit)
3127 {
3128 // Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
3130 return SPELL_MISS_EVADE;
3131
3134 else if (m_caster->IsFriendlyTo(unit))
3135 {
3136 // for delayed spells ignore negative spells (after duel end) for friendly targets
3137 if (hitInfo.TimeDelay && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidAssistTarget(unit, m_spellInfo))
3138 return SPELL_MISS_EVADE;
3139
3140 // assisting case, healing and resurrection
3142 {
3144 {
3145 playerOwner->SetContestedPvP();
3146 playerOwner->UpdatePvP(true);
3147 }
3148 }
3149
3151 {
3152 if (m_originalCaster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // only do explicit combat forwarding for PvP enabled units
3153 m_originalCaster->GetCombatManager().InheritCombatStatesFrom(unit); // for creature v creature combat, the threat forward does it for us
3155 }
3156 }
3157 }
3158
3159 // original caster for auras
3160 WorldObject* origCaster = m_caster;
3161 if (m_originalCaster)
3162 origCaster = m_originalCaster;
3163
3164 // check immunity due to diminishing returns
3166 {
3167 for (SpellEffectInfo const& auraSpellEffect : m_spellInfo->GetEffects())
3168 hitInfo.AuraBasePoints[auraSpellEffect.EffectIndex] = (m_spellValue->CustomBasePointsMask & (1 << auraSpellEffect.EffectIndex))
3169 ? m_spellValue->EffectBasePoints[auraSpellEffect.EffectIndex]
3170 : auraSpellEffect.CalcBaseValue(m_originalCaster, unit, m_castItemEntry, m_castItemLevel);
3171
3172 // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
3174
3175 DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1;
3176 if (hitInfo.DRGroup)
3177 {
3178 diminishLevel = unit->GetDiminishing(hitInfo.DRGroup);
3180 // Increase Diminishing on unit, current informations for actually casts will use values above
3181 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && unit->IsAffectedByDiminishingReturns()))
3183 }
3184
3185 // Now Reduce spell duration using data received at spell hit
3186 // check whatever effects we're going to apply, diminishing returns only apply to negative aura effects
3187 hitInfo.Positive = true;
3188 if (origCaster == unit || !origCaster->IsFriendlyTo(unit))
3189 {
3190 for (SpellEffectInfo const& auraSpellEffect : m_spellInfo->GetEffects())
3191 {
3192 // mod duration only for effects applying aura!
3193 if (hitInfo.EffectMask & (1 << auraSpellEffect.EffectIndex) &&
3194 auraSpellEffect.IsUnitOwnedAuraEffect() &&
3195 !m_spellInfo->IsPositiveEffect(auraSpellEffect.EffectIndex))
3196 {
3197 hitInfo.Positive = false;
3198 break;
3199 }
3200 }
3201 }
3202
3204
3205 // unit is immune to aura if it was diminished to 0 duration
3206 if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(m_spellInfo, hitInfo.AuraDuration, origCaster, diminishLevel))
3207 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; }))
3208 return SPELL_MISS_IMMUNE;
3209 }
3210
3211 return SPELL_MISS_NONE;
3212}
3213
3214void Spell::DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo, TargetInfo& hitInfo)
3215{
3216 if (uint32 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << spellEffectInfo.EffectIndex, unit))
3217 {
3218 WorldObject* caster = m_caster;
3219 if (m_originalCaster)
3220 caster = m_originalCaster;
3221
3222 if (caster)
3223 {
3224 bool refresh = false;
3225
3226 if (!hitInfo.HitAura)
3227 {
3228 bool const resetPeriodicTimer = (m_spellInfo->StackAmount < 2) && !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER);
3229 uint32 const allAuraEffectMask = Aura::BuildEffectMaskForOwner(m_spellInfo, MAX_EFFECT_MASK, unit);
3230
3231 AuraCreateInfo createInfo(m_castId, m_spellInfo, GetCastDifficulty(), allAuraEffectMask, unit);
3232 createInfo
3233 .SetCasterGUID(caster->GetGUID())
3234 .SetBaseAmount(&hitInfo.AuraBasePoints[0])
3236 .SetPeriodicReset(resetPeriodicTimer)
3237 .SetOwnerEffectMask(aura_effmask)
3238 .SetIsRefresh(&refresh)
3240
3241 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo, false))
3242 {
3243 hitInfo.HitAura = aura->ToUnitAura();
3244
3245 hitInfo.HitAura->SetDiminishGroup(hitInfo.DRGroup);
3246
3247 if (!m_spellValue->Duration)
3248 {
3249 hitInfo.AuraDuration = caster->ModSpellDuration(m_spellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask());
3250
3251 if (hitInfo.AuraDuration > 0)
3252 {
3254
3255 // Haste modifies duration of channeled spells
3256 if (m_spellInfo->IsChanneled())
3257 caster->ModSpellDurationTime(m_spellInfo, hitInfo.AuraDuration, this);
3259 {
3260 int32 origDuration = hitInfo.AuraDuration;
3261 hitInfo.AuraDuration = 0;
3262 for (AuraEffect const* auraEff : hitInfo.HitAura->GetAuraEffects())
3263 if (int32 period = auraEff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED
3264 hitInfo.AuraDuration = std::max(std::max(origDuration / period, 1) * period, hitInfo.AuraDuration);
3265
3266 // if there is no periodic effect
3267 if (!hitInfo.AuraDuration)
3268 hitInfo.AuraDuration = int32(origDuration * m_originalCaster->m_unitData->ModCastingSpeed);
3269 }
3270
3272 {
3273 int32 newDuration = hitInfo.AuraDuration + hitInfo.HitAura->GetDuration();
3274 hitInfo.AuraDuration = std::min(newDuration, CalculatePct(hitInfo.AuraDuration, 130));
3275 }
3276 }
3277 }
3278 else
3280
3281 if (hitInfo.AuraDuration != hitInfo.HitAura->GetMaxDuration())
3282 {
3283 hitInfo.HitAura->SetMaxDuration(hitInfo.AuraDuration);
3284 hitInfo.HitAura->SetDuration(hitInfo.AuraDuration);
3285 }
3286
3287 if (refresh)
3288 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
3289 }
3290 }
3291 else
3292 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
3293 }
3294 }
3295
3296 _spellAura = hitInfo.HitAura;
3297 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3298 _spellAura = nullptr;
3299}
3300
3302{
3303 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras
3304 // this is executed after spell proc spells on target hit
3305 // spells are triggered for each hit spell target
3306 // info confirmed with retail sniffs of permafrost and shadow weaving
3307 if (!m_hitTriggerSpells.empty())
3308 {
3309 int32 _duration = 0;
3310 for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
3311 {
3312 if (CanExecuteTriggersOnHit(unit, i->triggeredByAura) && roll_chance_i(i->chance))
3313 {
3314 m_caster->CastSpell(unit, i->triggeredSpell->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
3315 .SetTriggeringSpell(this)
3316 .SetCastDifficulty(i->triggeredSpell->Difficulty));
3317 TC_LOG_DEBUG("spells", "Spell {} triggered spell {} by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id);
3318
3319 // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
3320 // set duration of current aura to the triggered spell
3321 if (i->triggeredSpell->GetDuration() == -1)
3322 {
3323 if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID()))
3324 {
3325 // get duration from aura-only once
3326 if (!_duration)
3327 {
3328 Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
3329 _duration = aur ? aur->GetDuration() : -1;
3330 }
3331 triggeredAur->SetDuration(_duration);
3332 }
3333 }
3334 }
3335 }
3336 }
3337
3338 // trigger linked auras remove/apply
3340 if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_HIT, m_spellInfo->Id))
3341 {
3342 for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
3343 {
3344 if (*i < 0)
3345 unit->RemoveAurasDueToSpell(-(*i));
3346 else
3348 .SetOriginalCaster(m_caster->GetGUID())
3349 .SetTriggeringSpell(this));
3350 }
3351 }
3352}
3353
3355{
3356 // Not need check return true
3358 return true;
3359
3360 uint32 channelTargetEffectMask = m_channelTargetEffectMask;
3361 uint32 channelAuraMask = 0;
3362 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3363 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3364 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
3365
3366 channelAuraMask &= channelTargetEffectMask;
3367
3368 float range = 0;
3369 if (channelAuraMask)
3370 {
3372 if (Player* modOwner = m_caster->GetSpellModOwner())
3373 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, range, this);
3374
3375 // add little tolerance level
3376 range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
3377 }
3378
3379 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
3380 {
3381 if (targetInfo.MissCondition == SPELL_MISS_NONE && (channelTargetEffectMask & targetInfo.EffectMask))
3382 {
3383 Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
3384 if (!unit)
3385 {
3386 if (Unit* unitCaster =m_caster->ToUnit())
3387 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3388 continue;
3389 }
3390
3391 if (IsValidDeadOrAliveTarget(unit))
3392 {
3393 if (channelAuraMask & targetInfo.EffectMask)
3394 {
3396 {
3397 if (m_caster != unit && !m_caster->IsWithinDistInMap(unit, range))
3398 {
3399 targetInfo.EffectMask &= ~aurApp->GetEffectMask();
3400 unit->RemoveAura(aurApp);
3401 if (Unit* unitCaster = m_caster->ToUnit())
3402 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3403 continue;
3404 }
3405 }
3406 else // aura is dispelled
3407 {
3408 if (Unit* unitCaster = m_caster->ToUnit())
3409 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3410 continue;
3411 }
3412 }
3413
3414 channelTargetEffectMask &= ~targetInfo.EffectMask; // remove from need alive mask effect that have alive target
3415 }
3416 }
3417 }
3418
3419 // is all effects from m_needAliveTargetMask have alive targets
3420 return channelTargetEffectMask == 0;
3421}
3422
3423SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura)
3424{
3425 if (m_CastItem)
3426 {
3429
3430 if (Player* owner = m_CastItem->GetOwner())
3432 else if (m_CastItem->GetOwnerGUID() == m_caster->GetGUID())
3434 else
3435 {
3439 }
3440 }
3441
3442 InitExplicitTargets(targets);
3443
3445
3446 if (triggeredByAura)
3447 {
3448 m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
3449 m_castItemLevel = triggeredByAura->GetBase()->GetCastItemLevel();
3450 }
3451
3452 // create and add update event for this spell
3453 _spellEvent = new SpellEvent(this);
3455
3456 // check disables
3458 {
3462 }
3463
3464 // Prevent casting at cast another spell (ServerSide check)
3466 {
3470 }
3471
3472 LoadScripts();
3473
3474 // Fill cost data (do not use power for item casts)
3475 if (!m_CastItem)
3477
3478 int32 param1 = 0, param2 = 0;
3479 SpellCastResult result = CheckCast(true, &param1, &param2);
3480 // target is checked in too many locations and with different results to handle each of them
3481 // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
3483 result = SPELL_CAST_OK;
3484 if (result != SPELL_CAST_OK)
3485 {
3486 // Periodic auras should be interrupted when aura triggers a spell which can't be cast
3487 // for example bladestorm aura should be removed on disarm as of patch 3.3.5
3488 // channeled periodic spells should be affected by this (arcane missiles, penance, etc)
3489 // a possible alternative sollution for those would be validating aura target on unit state change
3490 if (triggeredByAura && triggeredByAura->IsPeriodic() && !triggeredByAura->GetBase()->IsPassive())
3491 {
3492 SendChannelUpdate(0, result);
3493 triggeredByAura->GetBase()->SetDuration(0);
3494 }
3495
3496 if (param1 || param2)
3497 SendCastResult(result, &param1, &param2);
3498 else
3499 SendCastResult(result);
3500
3501 // queue autorepeat spells for future repeating
3504
3505 finish(result);
3506 return result;
3507 }
3508
3509 // Prepare data for triggers
3511
3515
3516 SpellCastResult movementResult = SPELL_CAST_OK;
3517 if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving())
3518 movementResult = CheckMovement();
3519
3520 // Creatures focus their target when possible
3522 {
3523 // 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
3524 bool const focusTarget = !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING);
3525 if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
3527 else
3528 m_caster->ToCreature()->SetSpellFocus(this, nullptr);
3529 }
3530
3531 if (movementResult != SPELL_CAST_OK)
3532 {
3534 {
3535 SendCastResult(movementResult);
3536 finish(movementResult);
3537 return movementResult;
3538 }
3539 else
3540 {
3541 // Creatures (not controlled) give priority to spell casting over movement.
3542 // We assume that the casting is always valid and the current movement
3543 // is stopped immediately (because spells are updated before movement, so next Unit::Update would cancel the spell before stopping movement)
3544 // and future attempts are stopped by by Unit::IsMovementPreventedByCasting in movement generators to prevent casting interruption.
3546 }
3547 }
3548
3550
3551 // set timer base at cast time
3552 ReSetTimer();
3553
3554 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());
3555
3558
3561
3562 //Containers for channeled spells have to be set
3564 // Why check duration? 29350: channelled triggers channelled
3566 cast(true);
3567 else
3568 {
3569 // commented out !m_spellInfo->StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
3570 // as a result a spell that passed CheckCast and should be processed instantly may suffer from this delayed process
3571 // 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
3572 // 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)
3573 bool willCastDirectly = !m_casttime && GetCurrentContainer() == CURRENT_GENERIC_SPELL;
3574
3575 if (Unit* unitCaster = m_caster->ToUnit())
3576 {
3577 // stealth must be removed at cast starting (at show channel bar)
3578 // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
3580 unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action, m_spellInfo);
3581
3582 // Do not register as current spell when requested to ignore cast in progress
3583 // We don't want to interrupt that other spell with cast time
3584 if (!willCastDirectly || !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS))
3585 unitCaster->SetCurrentCastSpell(this);
3586 }
3588
3591
3592 // Call CreatureAI hook OnSpellStart
3593 if (Creature* caster = m_caster->ToCreature())
3594 if (caster->IsAIEnabled())
3595 caster->AI()->OnSpellStart(GetSpellInfo());
3596
3597 if (willCastDirectly)
3598 cast(true);
3599 }
3600
3601 return SPELL_CAST_OK;
3602}
3603
3605{
3607 return;
3608
3609 SpellState oldState = m_spellState;
3611
3612 m_autoRepeat = false;
3613 switch (oldState)
3614 {
3617 [[fallthrough]];
3619 SendInterrupted(0);
3621 break;
3623 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
3624 if (targetInfo.MissCondition == SPELL_MISS_NONE)
3625 if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
3626 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3627
3629 SendInterrupted(0);
3631
3632 m_appliedMods.clear();
3633 break;
3634 default:
3635 break;
3636 }
3637
3639 if (m_selfContainer && *m_selfContainer == this)
3640 *m_selfContainer = nullptr;
3641
3642 // originalcaster handles gameobjects/dynobjects for gob caster
3643 if (m_originalCaster)
3644 {
3646 if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
3648 }
3649
3650 //set state back so finish will be processed
3651 m_spellState = oldState;
3652
3654}
3655
3656void Spell::cast(bool skipCheck)
3657{
3658 Player* modOwner = m_caster->GetSpellModOwner();
3659 Spell* lastSpellMod = nullptr;
3660 if (modOwner)
3661 {
3662 lastSpellMod = modOwner->m_spellModTakingSpell;
3663 if (lastSpellMod)
3664 modOwner->SetSpellModTakingSpell(lastSpellMod, false);
3665 }
3666
3667 _cast(skipCheck);
3668
3669 if (lastSpellMod)
3670 modOwner->SetSpellModTakingSpell(lastSpellMod, true);
3671}
3672
3673void Spell::_cast(bool skipCheck)
3674{
3675 // update pointers base at GUIDs to prevent access to non-existed already object
3676 if (!UpdatePointers())
3677 {
3678 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3679 cancel();
3680 return;
3681 }
3682
3683 // cancel at lost explicit target during cast
3685 {
3686 cancel();
3687 return;
3688 }
3689
3690 if (Player* playerCaster = m_caster->ToPlayer())
3691 {
3692 // now that we've done the basic check, now run the scripts
3693 // should be done before the spell is actually executed
3694 sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
3695
3696 // As of 3.0.2 pets begin attacking their owner's target immediately
3697 // Let any pets know we've attacked something. Check DmgClass for harmful spells only
3698 // This prevents spells such as Hunter's Mark from triggering pet attack
3699 if (GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE)
3700 if (Unit* target = m_targets.GetUnitTarget())
3701 for (Unit* controlled : playerCaster->m_Controlled)
3702 if (Creature* cControlled = controlled->ToCreature())
3703 if (CreatureAI* controlledAI = cControlled->AI())
3704 controlledAI->OwnerAttacked(target);
3705 }
3706
3708
3709 // Should this be done for original caster?
3710 Player* modOwner = m_caster->GetSpellModOwner();
3711 if (modOwner)
3712 {
3713 // Set spell which will drop charges for triggered cast spells
3714 // if not successfully cast, will be remove in finish(false)
3715 modOwner->SetSpellModTakingSpell(this, true);
3716 }
3717
3719
3720 // skip check if done already (for instant cast spells for example)
3721 if (!skipCheck)
3722 {
3723 auto cleanupSpell = [this, modOwner](SpellCastResult res, int32* p1 = nullptr, int32* p2 = nullptr)
3724 {
3725 SendCastResult(res, p1, p2);
3726 SendInterrupted(0);
3727
3728 if (modOwner)
3729 modOwner->SetSpellModTakingSpell(this, false);
3730
3731 finish(res);
3732 SetExecutedCurrently(false);
3733 };
3734
3735 int32 param1 = 0, param2 = 0;
3736 SpellCastResult castResult = CheckCast(false, &param1, &param2);
3737 if (castResult != SPELL_CAST_OK)
3738 {
3739 cleanupSpell(castResult, &param1, &param2);
3740 return;
3741 }
3742
3743 // additional check after cast bar completes (must not be in CheckCast)
3744 // if trade not complete then remember it in trade data
3746 {
3747 if (modOwner)
3748 {
3749 if (TradeData* my_trade = modOwner->GetTradeData())
3750 {
3751 if (!my_trade->IsInAcceptProcess())
3752 {
3753 // Spell will be cast after completing the trade. Silently ignore at this place
3754 my_trade->SetSpell(m_spellInfo->Id, m_CastItem);
3755 cleanupSpell(SPELL_FAILED_DONT_REPORT);
3756 return;
3757 }
3758 }
3759 }
3760 }
3761
3762 // check diminishing returns (again, only after finish cast bar, tested on retail)
3763 if (Unit* target = m_targets.GetUnitTarget())
3764 {
3765 uint32 aura_effmask = 0;
3766 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3767 if (spellEffectInfo.IsUnitOwnedAuraEffect())
3768 aura_effmask |= 1 << spellEffectInfo.EffectIndex;
3769
3770 if (aura_effmask)
3771 {
3773 {
3775 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
3776 {
3778 {
3779 if (target->HasStrongerAuraWithDR(m_spellInfo, caster))
3780 {
3781 cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
3782 return;
3783 }
3784 }
3785 }
3786 }
3787 }
3788 }
3789 }
3790 // 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.
3791 if (Creature* creatureCaster = m_caster->ToCreature())
3792 if (!creatureCaster->GetTarget().IsEmpty() && !creatureCaster->HasUnitFlag(UNIT_FLAG_POSSESSED))
3793 if (WorldObject const* target = ObjectAccessor::GetUnit(*creatureCaster, creatureCaster->GetTarget()))
3794 creatureCaster->SetInFront(target);
3795
3797
3798 // Spell may be finished after target map check
3800 {
3801 SendInterrupted(0);
3802
3803 // cleanup after mod system
3804 // triggered spell pointer can be not removed in some cases
3806 m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
3807
3809 SetExecutedCurrently(false);
3810 return;
3811 }
3812
3813 if (Unit* unitCaster = m_caster->ToUnit())
3815 if (Creature* pet = ObjectAccessor::GetCreature(*m_caster, unitCaster->GetPetGUID()))
3816 pet->DespawnOrUnsummon();
3817
3819
3821
3822 // traded items have trade slot instead of guid in m_itemTargetGUID
3823 // set to real guid to be sent later to the client
3825
3826 if (Player* player = m_caster->ToPlayer())
3827 {
3829 {
3830 player->StartCriteria(CriteriaStartEvent::UseItem, m_CastItem->GetEntry());
3831 player->UpdateCriteria(CriteriaType::UseItem, m_CastItem->GetEntry());
3832 }
3833
3834 player->FailCriteria(CriteriaFailEvent::CastSpell, m_spellInfo->Id);
3835 player->StartCriteria(CriteriaStartEvent::CastSpell, m_spellInfo->Id);
3836 player->UpdateCriteria(CriteriaType::CastSpell, m_spellInfo->Id);
3837 }
3838
3839 // Spells that don't create items can have this attribute - handle here
3841 if (Player* playerCaster = m_caster->ToPlayer())
3842 playerCaster->UpdateCraftSkill(m_spellInfo);
3843
3844 // Powers have to be taken before SendSpellGo
3846 TakePower();
3847
3849 TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
3850 else if (Item* targetItem = m_targets.GetItemTarget())
3851 {
3853 if (targetItem->GetOwnerGUID() != m_caster->GetGUID())
3854 TakeReagents();
3855 }
3856
3857 // CAST SPELL
3860
3862
3864 {
3866 m_launchHandled = true;
3867 }
3868
3871
3872 // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
3873 SendSpellGo();
3874
3875 if (!m_spellInfo->IsChanneled())
3876 if (Creature* creatureCaster = m_caster->ToCreature())
3877 creatureCaster->ReleaseSpellFocus(this);
3878
3879 // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
3881 {
3882 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3883 // in case delayed spell remove item at cast delay start
3884 TakeCastItem();
3885
3886 // Okay, maps created, now prepare flags
3887 m_immediateHandled = false;
3888 SetDelayStart(0);
3889
3890 if (Unit* unitCaster = m_caster->ToUnit())
3891 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
3892 unitCaster->ClearUnitState(UNIT_STATE_CASTING);
3893 }
3894 else
3895 {
3896 // Immediate spell, no big deal
3898 }
3899
3901 m_scriptResult->SetResult(SPELL_CAST_OK);
3902
3904
3905 if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(SPELL_LINK_CAST, m_spellInfo->Id))
3906 {
3907 for (int32 id : *spell_triggered)
3908 {
3909 if (id < 0)
3910 {
3911 if (Unit* unitCaster = m_caster->ToUnit())
3912 unitCaster->RemoveAurasDueToSpell(-id);
3913 }
3914 else
3916 .SetTriggeringSpell(this));
3917 }
3918 }
3919
3920 if (modOwner)
3921 {
3922 modOwner->SetSpellModTakingSpell(this, false);
3923
3924 //Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
3926 {
3929 }
3930 }
3931
3932 SetExecutedCurrently(false);
3933
3934 if (!m_originalCaster)
3935 return;
3936
3937 // Handle procs on cast
3938 ProcFlagsInit procAttacker = m_procAttacker;
3939 if (!procAttacker)
3940 {
3942 {
3943 if (IsPositive())
3944 procAttacker |= PROC_FLAG_DEAL_HELPFUL_PERIODIC;
3945 else
3946 procAttacker |= PROC_FLAG_DEAL_HARMFUL_PERIODIC;
3947 }
3949 {
3950 if (IsPositive())
3951 procAttacker |= PROC_FLAG_DEAL_HELPFUL_ABILITY;
3952 else
3953 procAttacker |= PROC_FLAG_DEAL_HARMFUL_ABILITY;
3954 }
3955 else
3956 {
3957 if (IsPositive())
3958 procAttacker |= PROC_FLAG_DEAL_HELPFUL_SPELL;
3959 else
3960 procAttacker |= PROC_FLAG_DEAL_HARMFUL_SPELL;
3961 }
3962 }
3963
3964 procAttacker |= PROC_FLAG_2_CAST_SUCCESSFUL;
3965
3966 ProcFlagsHit hitMask = m_hitMask;
3967 if (!(hitMask & PROC_HIT_CRITICAL))
3968 hitMask |= PROC_HIT_NORMAL;
3969
3972
3973 Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
3974
3975 // Call CreatureAI hook OnSpellCast
3976 if (Creature* caster = m_originalCaster->ToCreature())
3977 if (caster->IsAIEnabled())
3978 caster->AI()->OnSpellCast(GetSpellInfo());
3979}
3980
3981template <class Container>
3982void Spell::DoProcessTargetContainer(Container& targetContainer)
3983{
3984 for (TargetInfoBase& target : targetContainer)
3985 target.PreprocessTarget(this);
3986
3987 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3988 for (TargetInfoBase& target : targetContainer)
3989 if (target.EffectMask & (1 << spellEffectInfo.EffectIndex))
3990 target.DoTargetSpellHit(this, spellEffectInfo);
3991
3992 for (TargetInfoBase& target : targetContainer)
3993 target.DoDamageAndTriggers(this);
3994}
3995
3997{
3998 // start channeling if applicable
3999 if (m_spellInfo->IsChanneled())
4000 {
4001 int32 duration = m_spellInfo->GetDuration();
4002 if (duration > 0 || m_spellValue->Duration > 0)
4003 {
4004 if (!m_spellValue->Duration)
4005 {
4006 int32 originalDuration = duration;
4007
4008 // First mod_duration then haste - see Missile Barrage
4009 // Apply duration mod
4010 if (Player* modOwner = m_caster->GetSpellModOwner())
4011 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Duration, duration);
4012
4013 duration *= m_spellValue->DurationMul;
4014
4015 // Apply haste mods
4016 m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
4017
4018 if (IsEmpowerSpell())
4019 {
4020 float ratio = float(duration) / float(originalDuration);
4021 m_empower->StageDurations.resize(m_spellInfo->EmpowerStageThresholds.size());
4022 Milliseconds totalExceptLastStage = 0ms;
4023 for (std::size_t i = 0; i < m_empower->StageDurations.size() - 1; ++i)
4024 {
4025 m_empower->StageDurations[i] = Milliseconds(int64(m_spellInfo->EmpowerStageThresholds[i].count() * ratio));
4026 totalExceptLastStage += m_empower->StageDurations[i];
4027 }
4028
4029 m_empower->StageDurations.back() = Milliseconds(duration) - totalExceptLastStage;
4030
4031 if (Player const* playerCaster = m_caster->ToPlayer())
4032 m_empower->MinHoldTime = Milliseconds(int64(m_empower->StageDurations[0].count() * playerCaster->GetEmpowerMinHoldStagePercent()));
4033 else
4034 m_empower->MinHoldTime = m_empower->StageDurations[0];
4035
4037 }
4038 }
4039 else
4040 duration = *m_spellValue->Duration;
4041
4042 m_channeledDuration = duration;
4043 SendChannelStart(duration);
4044 }
4045 else if (duration == -1)
4046 SendChannelStart(duration);
4047
4048 if (duration != 0)
4049 {
4051 // GameObjects shouldn't cast channeled spells
4053 }
4054 }
4055
4057
4058 // process immediate effects (items, ground, etc.) also initialize some variables
4060
4061 // consider spell hit for some spells without target, so they may proc on finish phase correctly
4062 if (m_UniqueTargetInfo.empty())
4063 {
4066 }
4067 else
4069
4071
4073
4075
4076 // spell is finished, perform some last features of the spell here
4078
4079 // Remove used for cast item if need (it can be already NULL after TakeReagents call
4080 TakeCastItem();
4081
4083 finish(); // successfully finish spell cast (not last in case autorepeat or channel spell)
4084}
4085
4087{
4088 if (!UpdatePointers())
4089 {
4090 // finish the spell if UpdatePointers() returned false, something wrong happened there
4092 return 0;
4093 }
4094
4095 // when spell has a single missile we hit all targets (except caster) at the same time
4096 bool single_missile = m_targets.HasDst();
4097 bool ignoreTargetInfoTimeDelay = single_missile;
4098 uint64 next_time = 0;
4099
4100 if (!m_launchHandled)
4101 {
4102 uint64 launchMoment = uint64(std::floor(m_spellInfo->LaunchDelay * 1000.0f));
4103 if (launchMoment > t_offset)
4104 return launchMoment;
4105
4107 m_launchHandled = true;
4108 }
4109
4110 if (m_delayMoment > t_offset)
4111 {
4112 ignoreTargetInfoTimeDelay = false;
4113 next_time = m_delayMoment;
4114 }
4115
4116 Player* modOwner = m_caster->GetSpellModOwner();
4117 if (modOwner)
4118 modOwner->SetSpellModTakingSpell(this, true);
4119
4121
4122 if (!m_immediateHandled && m_delayMoment <= t_offset)
4123 {
4125 m_immediateHandled = true;
4126 }
4127
4128 // 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)
4129 {
4130 std::vector<TargetInfo> delayedTargets;
4131 m_UniqueTargetInfo.erase(std::remove_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo& target) -> bool
4132 {
4133 if (ignoreTargetInfoTimeDelay || target.TimeDelay <= t_offset)
4134 {
4135 target.TimeDelay = t_offset;
4136 delayedTargets.emplace_back(std::move(target));
4137 return true;
4138 }
4139 else if (!single_missile && (next_time == 0 || target.TimeDelay < next_time))
4140 next_time = target.TimeDelay;
4141
4142 return false;
4143 }), m_UniqueTargetInfo.end());
4144
4145 DoProcessTargetContainer(delayedTargets);
4146 }
4147
4148 // now recheck gameobject targeting correctness
4149 {
4150 std::vector<GOTargetInfo> delayedGOTargets;
4151 m_UniqueGOTargetInfo.erase(std::remove_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [&](GOTargetInfo& goTarget) -> bool
4152 {
4153 if (ignoreTargetInfoTimeDelay || goTarget.TimeDelay <= t_offset)
4154 {
4155 goTarget.TimeDelay = t_offset;
4156 delayedGOTargets.emplace_back(std::move(goTarget));
4157 return true;
4158 }
4159 else if (!single_missile && (next_time == 0 || goTarget.TimeDelay < next_time))
4160 next_time = goTarget.TimeDelay;
4161
4162 return false;
4163 }), m_UniqueGOTargetInfo.end());
4164
4165 DoProcessTargetContainer(delayedGOTargets);
4166 }
4167
4169
4170 if (modOwner)
4171 modOwner->SetSpellModTakingSpell(this, false);
4172
4173 // All targets passed - need finish phase
4174 if (next_time == 0)
4175 {
4176 // spell is finished, perform some last features of the spell here
4178
4179 finish(); // successfully finish spell cast
4180
4181 // return zero, spell is finished now
4182 return 0;
4183 }
4184 else
4185 {
4186 // spell is unfinished, return next execution time
4187 return next_time;
4188 }
4189}
4190
4192{
4193 // handle some immediate features of the spell here
4195
4196 // handle effects with SPELL_EFFECT_HANDLE_HIT mode
4197 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
4198 {
4199 // don't do anything for empty effect
4200 if (!spellEffectInfo.IsEffect())
4201 continue;
4202
4203 // call effect handlers to handle destination hit
4204 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
4205 }
4206
4207 // process items
4209}
4210
4212{
4213 if (Unit* unitCaster = m_caster->ToUnit())
4215 unitCaster->SetLastExtraAttackSpell(m_spellInfo->Id);
4216
4217 // Handle procs on finish
4218 if (!m_originalCaster)
4219 return;
4220
4221 ProcFlagsInit procAttacker = m_procAttacker;
4222 if (!procAttacker)
4223 {
4225 {
4226 if (IsPositive())
4227 procAttacker |= PROC_FLAG_DEAL_HELPFUL_PERIODIC;
4228 else
4229 procAttacker |= PROC_FLAG_DEAL_HARMFUL_PERIODIC;
4230 }
4232 {
4233 if (IsPositive())
4234 procAttacker |= PROC_FLAG_DEAL_HELPFUL_ABILITY;
4235 else
4236 procAttacker |= PROC_FLAG_DEAL_HARMFUL_ABILITY;
4237 }
4238 else
4239 {
4240 if (IsPositive())
4241 procAttacker |= PROC_FLAG_DEAL_HELPFUL_SPELL;
4242 else
4243 procAttacker |= PROC_FLAG_DEAL_HARMFUL_SPELL;
4244 }
4245 }
4246
4248}
4249
4251{
4252 if (!m_caster->IsUnit())
4253 return;
4254
4255 if (m_CastItem)
4257 else
4259
4260 if (IsAutoRepeat())
4262}
4263
4264void Spell::update(uint32 difftime)
4265{
4266 // update pointers based at it's GUIDs
4267 if (!UpdatePointers())
4268 {
4269 // cancel the spell if UpdatePointers() returned false, something wrong happened there
4270 cancel();
4271 return;
4272 }
4273
4275 {
4276 TC_LOG_DEBUG("spells", "Spell {} is cancelled due to removal of target.", m_spellInfo->Id);
4277 cancel();
4278 return;
4279 }
4280
4281 // check if the unit caster has moved before the spell finished
4282 if (m_timer != 0 && m_caster->IsUnit() && m_caster->ToUnit()->isMoving() && CheckMovement() != SPELL_CAST_OK)
4283 cancel();
4284
4285 switch (m_spellState)
4286 {
4288 {
4289 if (m_timer > 0)
4290 {
4291 if (difftime >= (uint32)m_timer)
4292 m_timer = 0;
4293 else
4294 m_timer -= difftime;
4295 }
4296
4298 // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
4299 cast(!m_casttime);
4300 break;
4301 }
4303 {
4304 if (m_timer)
4305 {
4306 // check if there are alive targets left
4308 {
4309 TC_LOG_DEBUG("spells", "Channeled spell {} is removed due to lack of targets", m_spellInfo->Id);
4310 m_timer = 0;
4311
4312 // Also remove applied auras
4313 for (TargetInfo const& target : m_UniqueTargetInfo)
4314 if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
4315 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
4316 }
4317
4318 if (m_timer > 0)
4319 {
4320 if (difftime >= (uint32)m_timer)
4321 m_timer = 0;
4322 else
4323 m_timer -= difftime;
4324 }
4325 }
4326
4327 if (IsEmpowerSpell())
4328 {
4329 int32 completedStages = [&]() -> int32
4330 {
4332 for (std::size_t i = 0; i < m_empower->StageDurations.size(); ++i)
4333 {
4334 passed -= m_empower->StageDurations[i];
4335 if (passed < 0ms)
4336 return i;
4337 }
4338
4339 return m_empower->StageDurations.size();
4340 }();
4341
4342 if (completedStages != m_empower->CompletedStages)
4343 {
4345 empowerSetStage.CastID = m_castId;
4346 empowerSetStage.CasterGUID = m_caster->GetGUID();
4347 empowerSetStage.Stage = m_empower->CompletedStages;
4348 m_caster->SendMessageToSet(empowerSetStage.Write(), true);
4349
4350 m_empower->CompletedStages = completedStages;
4351 if (Unit* unitCaster = m_caster->ToUnit())
4352 unitCaster->SetSpellEmpowerStage(completedStages);
4353
4355 }
4356
4358 {
4359 m_empower->IsReleased = true;
4360 m_timer = 0;
4363 }
4364 }
4365
4366 if (m_timer == 0)
4367 {
4369 finish();
4370
4371 // 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
4372 if (Creature* creatureCaster = m_caster->ToCreature())
4373 if (creatureCaster->IsAIEnabled())
4374 creatureCaster->AI()->OnChannelFinished(m_spellInfo);
4375 }
4376 break;
4377 }
4378 default:
4379 break;
4380 }
4381}
4382
4384{
4386 return;
4388
4390 m_scriptResult->SetResult(result);
4391
4392 if (!m_caster)
4393 return;
4394
4395 Unit* unitCaster = m_caster->ToUnit();
4396 if (!unitCaster)
4397 return;
4398
4399 // successful cast of the initial autorepeat spell is moved to idle state so that it is not deleted as long as autorepeat is active
4400 if (IsAutoRepeat() && unitCaster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) == this)
4402
4403 if (m_spellInfo->IsChanneled())
4404 unitCaster->UpdateInterruptMask();
4405
4406 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
4408
4409 // Unsummon summon as possessed creatures on spell cancel
4410 if (m_spellInfo->IsChanneled() && unitCaster->GetTypeId() == TYPEID_PLAYER)
4411 {
4412 if (Unit* charm = unitCaster->GetCharmed())
4413 if (charm->GetTypeId() == TYPEID_UNIT
4414 && charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
4415 && charm->m_unitData->CreatedBySpell == int32(m_spellInfo->Id))
4416 ((Puppet*)charm)->UnSummon();
4417 }
4418
4419 if (Creature* creatureCaster = unitCaster->ToCreature())
4420 creatureCaster->ReleaseSpellFocus(this);
4421
4423
4424 if (IsEmpowerSpell())
4425 {
4426 // Empower spells trigger gcd at the end of cast instead of at start
4427 if (SpellInfo const* gcd = sSpellMgr->GetSpellInfo(SPELL_EMPOWER_HARDCODED_GCD, DIFFICULTY_NONE))
4428 unitCaster->GetSpellHistory()->AddGlobalCooldown(gcd, Milliseconds(gcd->StartRecoveryTime));
4429 }
4430
4431 if (result != SPELL_CAST_OK)
4432 {
4433 // on failure (or manual cancel) send TraitConfigCommitFailed to revert talent UI saved config selection
4435 if (WorldPackets::Traits::TraitConfig const* traitConfig = std::any_cast<WorldPackets::Traits::TraitConfig>(&m_customArg))
4437
4438 if (IsEmpowerSpell())
4439 {
4440 unitCaster->GetSpellHistory()->ResetCooldown(m_spellInfo->Id, true);
4441 RefundPower();
4442 }
4443
4444 return;
4445 }
4446
4447 if (unitCaster->GetTypeId() == TYPEID_UNIT && unitCaster->IsSummon())
4448 {
4449 // Unsummon statue
4450 uint32 spell = unitCaster->m_unitData->CreatedBySpell;
4451 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, GetCastDifficulty());
4452 if (spellInfo && spellInfo->IconFileDataId == 134230)
4453 {
4454 TC_LOG_DEBUG("spells", "Statue {} is unsummoned in spell {} finish", unitCaster->GetGUID().ToString(), m_spellInfo->Id);
4455 // Avoid infinite loops with setDeathState(JUST_DIED) being called over and over
4456 // It might make sense to do this check in Unit::setDeathState() and all overloaded functions
4457 if (unitCaster->getDeathState() != JUST_DIED)
4458 unitCaster->setDeathState(JUST_DIED);
4459 return;
4460 }
4461 }
4462
4463 // potions disabled by client, send event "not in combat" if need
4464 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4465 {
4467 unitCaster->ToPlayer()->UpdatePotionCooldown(this);
4468 }
4469
4470 // Stop Attack for some spells
4472 unitCaster->AttackStop();
4473}
4474
4475template<class T>
4476inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/, Player* caster)
4477{
4478 packet.CastID = castId;
4479 packet.SpellID = spellInfo->Id;
4480 packet.Reason = result;
4481
4482 switch (result)
4483 {
4485 if (param1)
4486 packet.FailedArg1 = *param1;
4487 else
4488 packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
4489 break;
4491 if (param1)
4492 packet.FailedArg1 = *param1;
4493 else
4494 packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
4495 break;
4496 case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
4497 if (param1)
4498 packet.FailedArg1 = *param1;
4499 else
4500 {
4501 // hardcode areas limitation case
4502 switch (spellInfo->Id)
4503 {
4504 case 41617: // Cenarion Mana Salve
4505 case 41619: // Cenarion Healing Salve
4506 packet.FailedArg1 = 3905;
4507 break;
4508 case 41618: // Bottled Nethergon Energy
4509 case 41620: // Bottled Nethergon Vapor
4510 packet.FailedArg1 = 3842;
4511 break;
4512 case 45373: // Bloodberry Elixir
4513 packet.FailedArg1 = 4075;
4514 break;
4515 default: // default case (don't must be)
4516 packet.FailedArg1 = 0;
4517 break;
4518 }
4519 }
4520 break;
4522 if (param1)
4523 {
4524 packet.FailedArg1 = *param1;
4525 if (param2)
4526 packet.FailedArg2 = *param2;
4527 }
4528 else
4529 {
4530 if (spellInfo->Totem[0])
4531 packet.FailedArg1 = spellInfo->Totem[0];
4532 if (spellInfo->Totem[1])
4533 packet.FailedArg2 = spellInfo->Totem[1];
4534 }
4535 break;
4537 if (param1)
4538 {
4539 packet.FailedArg1 = *param1;
4540 if (param2)
4541 packet.FailedArg2 = *param2;
4542 }
4543 else
4544 {
4545 if (spellInfo->TotemCategory[0])
4546 packet.FailedArg1 = spellInfo->TotemCategory[0];
4547 if (spellInfo->TotemCategory[1])
4548 packet.FailedArg2 = spellInfo->TotemCategory[1];
4549 }
4550 break;
4554 if (param1 && param2)
4555 {
4556 packet.FailedArg1 = *param1;
4557 packet.FailedArg2 = *param2;
4558 }
4559 else
4560 {
4561 packet.FailedArg1 = spellInfo->EquippedItemClass;
4562 packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
4563 }
4564 break;
4566 {
4567 if (param1)
4568 packet.FailedArg1 = *param1;
4569 else
4570 {
4571 uint32 item = 0;
4572 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4573 {
4574 if (uint32 itemType = spellEffectInfo.ItemType)
4575 {
4576 item = itemType;
4577 break;
4578 }
4579 }
4580
4581 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
4582 if (proto && proto->GetItemLimitCategory())
4583 packet.FailedArg1 = proto->GetItemLimitCategory();
4584 }
4585 break;
4586 }
4588 if (param1)
4589 packet.FailedArg1 = *param1;
4590 else
4591 packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
4592 break;
4594 if (param1)
4595 packet.FailedArg1 = *param1;
4596 else
4597 packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct...
4598 break;
4600 if (param1 && param2)
4601 {
4602 packet.FailedArg1 = *param1;
4603 packet.FailedArg2 = *param2;
4604 }
4605 else
4606 {
4607 packet.FailedArg1 = 0; // Item id
4608 packet.FailedArg2 = 0; // Item count?
4609 }
4610 break;
4612 if (param1 && param2)
4613 {
4614 packet.FailedArg1 = *param1;
4615 packet.FailedArg2 = *param2;
4616 }
4617 else
4618 {
4619 packet.FailedArg1 = 0; // SkillLine.dbc id
4620 packet.FailedArg2 = 0; // required skill value
4621 }
4622 break;
4624 if (param1)
4625 packet.FailedArg1 = *param1;
4626 else
4627 packet.FailedArg1 = 0; // required fishing skill
4628 break;
4630 packet.FailedArg1 = customError;
4631 break;
4633 if (param1)
4634 packet.FailedArg1 = *param1;
4635 else
4636 packet.FailedArg1 = 0; // Unknown
4637 break;
4639 {
4640 if (param1)
4641 packet.FailedArg1 = *param1;
4642 else
4643 {
4644 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
4645 {
4646 if (spellInfo->Reagent[i] <= 0)
4647 continue;
4648
4649 uint32 itemid = spellInfo->Reagent[i];
4650 uint32 itemcount = spellInfo->ReagentCount[i];
4651
4652 if (caster && !caster->HasItemCount(itemid, itemcount))
4653 {
4654 packet.FailedArg1 = itemid; // first missing item
4655 break;
4656 }
4657 }
4658 }
4659
4660 if (param2)
4661 packet.FailedArg2 = *param2;
4662 else if (!param1)
4663 {
4664 for (SpellReagentsCurrencyEntry const* reagentsCurrency : spellInfo->ReagentsCurrency)
4665 {
4666 if (caster && !caster->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount))
4667 {
4668 packet.FailedArg1 = -1;
4669 packet.FailedArg2 = reagentsCurrency->CurrencyTypesID;
4670 break;
4671 }
4672 }
4673 }
4674
4675 break;
4676 }
4678 {
4679 ASSERT(param1);
4680 packet.FailedArg1 = *param1;
4681 break;
4682 }
4683 // TODO: SPELL_FAILED_NOT_STANDING
4684 default:
4685 break;
4686 }
4687}
4688
4689void Spell::SendCastResult(SpellCastResult result, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
4690{
4691 if (result == SPELL_CAST_OK)
4692 return;
4693
4694 Player const* receiver = m_caster->ToPlayer();
4696 if (Player const* target = Object::ToPlayer(m_targets.GetUnitTarget()))
4697 receiver = target;
4698
4699 if (!receiver)
4700 return;
4701
4702 if (receiver->IsLoading()) // don't send cast results at loading time
4703 return;
4704
4706 result = SPELL_FAILED_DONT_REPORT;
4707
4709 castFailed.Visual = m_SpellVisual;
4710 FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster->ToPlayer());
4711 receiver->SendDirectMessage(castFailed.Write());
4712}
4713
4714void Spell::SendPetCastResult(SpellCastResult result, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
4715{
4716 if (result == SPELL_CAST_OK)
4717 return;
4718
4719 Unit* owner = m_caster->GetCharmerOrOwner();
4720 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
4721 return;
4722
4724 result = SPELL_FAILED_DONT_REPORT;
4725
4727 FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SPELL_CUSTOM_ERROR_NONE, param1, param2, owner->ToPlayer());
4728 owner->ToPlayer()->SendDirectMessage(petCastFailed.Write());
4729}
4730
4731void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/)
4732{
4733 if (result == SPELL_CAST_OK)
4734 return;
4735
4737 packet.Visual = spellVisual;
4738 FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, caster);
4739 caster->SendDirectMessage(packet.Write());
4740}
4741
4743{
4744 if (result == MountResult::Ok)
4745 return;
4746
4747 if (!m_caster->IsPlayer())
4748 return;
4749
4750 Player* caster = m_caster->ToPlayer();
4751 if (caster->IsLoading()) // don't send mount results at loading time
4752 return;
4753
4755 packet.Result = AsUnderlyingType(result);
4756 caster->SendDirectMessage(packet.Write());
4757}
4758
4760{
4761 if (!IsNeedSendToClient())
4762 return;
4763
4764 TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id={}", m_spellInfo->Id);
4765
4766 uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
4767 uint32 schoolImmunityMask = 0;
4768 uint32 mechanicImmunityMask = 0;
4769 if (Unit* unitCaster = m_caster->ToUnit())
4770 {
4771 schoolImmunityMask = m_timer!= 0 ? unitCaster->GetSchoolImmunityMask() : 0;
4772 mechanicImmunityMask = m_timer != 0 ? m_spellInfo->GetMechanicImmunityMask(unitCaster) : 0;
4773 }
4774
4775 if (schoolImmunityMask || mechanicImmunityMask)
4776 castFlags |= CAST_FLAG_IMMUNITY;
4777
4779 castFlags |= CAST_FLAG_PENDING;
4780
4782 castFlags |= CAST_FLAG_PROJECTILE;
4783
4784 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4786 && std::ranges::any_of(m_powerCost, [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }))
4787 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4788
4790 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4791
4793 castFlags |= CAST_FLAG_HEAL_PREDICTION;
4794
4796 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4797
4798 if (m_CastItem)
4799 castData.CasterGUID = m_CastItem->GetGUID();
4800 else
4801 castData.CasterGUID = m_caster->GetGUID();
4802
4803 castData.CasterUnit = m_caster->GetGUID();
4804 castData.CastID = m_castId;
4806 castData.SpellID = m_spellInfo->Id;
4807 castData.Visual = m_SpellVisual;
4808 castData.CastFlags = castFlags;
4809 castData.CastFlagsEx = m_castFlagsEx;
4810 castData.CastTime = m_casttime;
4811
4812 m_targets.Write(castData.Target);
4813
4814 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4815 {
4816 for (SpellPowerCost const& cost : m_powerCost)
4817 {
4819 powerData.Type = cost.Power;
4820 powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
4821 castData.RemainingPower.push_back(powerData);
4822 }
4823 }
4824
4825 if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
4826 {
4827 castData.RemainingRunes.emplace();
4828
4829 //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature
4830 //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
4831 if (Player* player = m_caster->ToPlayer())
4832 {
4833 castData.RemainingRunes->Start = m_runesState; // runes state before
4834 castData.RemainingRunes->Count = player->GetRunesState(); // runes state after
4835 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4836 {
4837 // float casts ensure the division is performed on floats as we need float result
4838 float baseCd = float(player->GetRuneBaseCooldown());
4839 castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
4840 }
4841 }
4842 else
4843 {
4844 castData.RemainingRunes->Start = 0;
4845 castData.RemainingRunes->Count = 0;
4846 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4847 castData.RemainingRunes->Cooldowns.push_back(0);
4848 }
4849 }
4850
4851 if (castFlags & CAST_FLAG_PROJECTILE)
4853
4854 if (castFlags & CAST_FLAG_IMMUNITY)
4855 {
4856 castData.Immunities.School = schoolImmunityMask;
4857 castData.Immunities.Value = mechanicImmunityMask;
4858 }
4859
4860 if (castFlags & CAST_FLAG_HEAL_PREDICTION)
4861 UpdateSpellHealPrediction(castData.Predict, false);
4862
4863 m_caster->SendMessageToSet(packet.Write(), true);
4864}
4865
4867{
4868 // not send invisible spell casting
4869 if (!IsNeedSendToClient())
4870 return;
4871
4872 TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id={}", m_spellInfo->Id);
4873
4874 uint32 castFlags = CAST_FLAG_UNKNOWN_9;
4875
4876 // triggered spells with spell visual != 0
4878 castFlags |= CAST_FLAG_PENDING;
4879
4881 castFlags |= CAST_FLAG_PROJECTILE; // arrows/bullets visual
4882
4883 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4885 && std::ranges::any_of(m_powerCost, [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }))
4886 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4887
4888 if ((m_caster->GetTypeId() == TYPEID_PLAYER)
4892 {
4893 castFlags |= CAST_FLAG_NO_GCD; // not needed, but it's being sent according to sniffs
4894 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4895 }
4896
4897 if (m_targets.HasTraj())
4898 castFlags |= CAST_FLAG_ADJUST_MISSILE;
4899
4901 castFlags |= CAST_FLAG_NO_GCD;
4902
4904 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4905 if (m_CastItem)
4906 castData.CasterGUID = m_CastItem->GetGUID();
4907 else
4908 castData.CasterGUID = m_caster->GetGUID();
4909
4910 castData.CasterUnit = m_caster->GetGUID();
4911 castData.CastID = m_castId;
4913 castData.SpellID = m_spellInfo->Id;
4914 castData.Visual = m_SpellVisual;
4915 castData.CastFlags = castFlags;
4916 castData.CastFlagsEx = m_castFlagsEx;
4917 castData.CastTime = getMSTime();
4918
4920
4921 m_targets.Write(castData.Target);
4922
4923 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4924 {
4925 for (SpellPowerCost const& cost : m_powerCost)
4926 {
4928 powerData.Type = cost.Power;
4929 powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
4930 castData.RemainingPower.push_back(powerData);
4931 }
4932 }
4933
4934 if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
4935 {
4936 castData.RemainingRunes.emplace();
4937
4938 Player* player = ASSERT_NOTNULL(m_caster->ToPlayer());
4939 castData.RemainingRunes->Start = m_runesState; // runes state before
4940 castData.RemainingRunes->Count = player->GetRunesState(); // runes state after
4941 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4942 {
4943 // float casts ensure the division is performed on floats as we need float result
4944 float baseCd = float(player->GetRuneBaseCooldown());
4945 castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
4946 }
4947 }
4948
4949 if (castFlags & CAST_FLAG_ADJUST_MISSILE)
4950 {
4953 }
4954
4955 packet.LogData.Initialize(this);
4956
4958}
4959
4962{
4963 // This function also fill data for channeled spells:
4964 // m_needAliveTargetMask req for stop channeling if one target die
4965 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
4966 {
4967 if (targetInfo.EffectMask == 0) // No effect apply - all immune add state
4968 // possibly SPELL_MISS_IMMUNE2 for this??
4969 targetInfo.MissCondition = SPELL_MISS_IMMUNE2;
4970
4971 if (targetInfo.MissCondition == SPELL_MISS_NONE || (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))) // Add only hits and partial blocked
4972 {
4973 data.HitTargets.push_back(targetInfo.TargetGUID);
4974 data.HitStatus.emplace_back(SPELL_MISS_NONE);
4975
4976 m_channelTargetEffectMask |= targetInfo.EffectMask;
4977 }
4978 else // misses
4979 {
4980 data.MissTargets.push_back(targetInfo.TargetGUID);
4981 data.MissStatus.emplace_back(targetInfo.MissCondition, targetInfo.ReflectResult);
4982 }
4983 }
4984
4985 for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo)
4986 data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
4987
4988 for (CorpseTargetInfo const& targetInfo : m_UniqueCorpseTargetInfo)
4989 data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
4990
4991 // Reset m_needAliveTargetMask for non channeled spell
4992 if (!m_spellInfo->IsChanneled())
4994}
4995
4997{
4998 uint32 ammoInventoryType = 0;
4999 uint32 ammoDisplayID = 0;
5000
5001 if (Player const* playerCaster = m_caster->ToPlayer())
5002 {
5003 Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK);
5004 if (pItem)
5005 {
5006 ammoInventoryType = pItem->GetTemplate()->GetInventoryType();
5007 if (ammoInventoryType == INVTYPE_THROWN)
5008 ammoDisplayID = pItem->GetDisplayId(playerCaster);
5009 else if (playerCaster->HasAura(46699)) // Requires No Ammo
5010 {
5011 ammoDisplayID = 5996; // normal arrow
5012 ammoInventoryType = INVTYPE_AMMO;
5013 }
5014 }
5015 }
5016 else if (Unit const* unitCaster = m_caster->ToUnit())
5017 {
5018 uint32 nonRangedAmmoDisplayID = 0;
5019 uint32 nonRangedAmmoInventoryType = 0;
5020 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
5021 {
5022 if (uint32 item_id = unitCaster->GetVirtualItemId(i))
5023 {
5024 if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
5025 {
5026 if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
5027 {
5028 switch (itemEntry->SubclassID)
5029 {
5031 ammoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i));
5032 ammoInventoryType = itemEntry->InventoryType;
5033 break;
5036 ammoDisplayID = 5996; // is this need fixing?
5037 ammoInventoryType = INVTYPE_AMMO;
5038 break;
5040 ammoDisplayID = 5998; // is this need fixing?
5041 ammoInventoryType = INVTYPE_AMMO;
5042 break;
5043 default:
5044 nonRangedAmmoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i));
5045 nonRangedAmmoInventoryType = itemEntry->InventoryType;
5046 break;
5047 }
5048
5049 if (ammoDisplayID)
5050 break;
5051 }
5052 }
5053 }
5054 }
5055
5056 if (!ammoDisplayID && !ammoInventoryType)
5057 {
5058 ammoDisplayID = nonRangedAmmoDisplayID;
5059 ammoInventoryType = nonRangedAmmoInventoryType;
5060 }
5061 }
5062
5063 return ammoDisplayID;
5064}
5065
5066static std::pair<int32, SpellHealPredictionType> CalcPredictedHealing(SpellInfo const* spellInfo, Unit const* unitCaster, Unit* target, uint32 castItemEntry, int32 castItemLevel, Spell* spell, bool withPeriodic)
5067{
5068 int32 points = 0;
5070 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
5071 {
5072 switch (spellEffectInfo.Effect)
5073 {
5074 case SPELL_EFFECT_HEAL:
5076 points += unitCaster->SpellHealingBonusDone(target,
5077 spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
5078 DIRECT_DAMAGE, spellEffectInfo, 1, spell);
5079
5080 if (target != unitCaster && (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER || spellEffectInfo.TargetB.GetTarget() == TARGET_UNIT_CASTER))
5081 type = SPELL_HEAL_PREDICTION_TARGET_AND_CASTER; // Binding Heal-like spells
5082 else if (spellEffectInfo.TargetA.GetCheckType() == TARGET_CHECK_PARTY || spellEffectInfo.TargetB.GetCheckType() == TARGET_CHECK_PARTY)
5083 type = SPELL_HEAL_PREDICTION_TARGET_PARTY; // Prayer of Healing (old party-wide targeting)
5084 break;
5085 default:
5086 break;
5087 }
5088
5089 if (withPeriodic)
5090 {
5091 switch (spellEffectInfo.ApplyAuraName)
5092 {
5095 points += unitCaster->SpellHealingBonusDone(target,
5096 spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
5097 DIRECT_DAMAGE, spellEffectInfo, 1, spell) * spellInfo->GetMaxTicks();
5098 break;
5100 if (SpellInfo const* triggered = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, spellInfo->Difficulty))
5101 points += CalcPredictedHealing(triggered, unitCaster, target, castItemEntry, castItemLevel, nullptr, withPeriodic).first;
5102 break;
5103 default:
5104 break;
5105 }
5106 }
5107 }
5108
5109 return { points, type };
5110}
5111
5113{
5114 healPrediction.BeaconGUID = ObjectGuid::Empty;
5115 healPrediction.Points = 0;
5116 healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET;
5117
5118 Unit const* unitCaster = m_caster->ToUnit();
5119
5120 if (Unit* target = m_targets.GetUnitTarget())
5121 {
5122 auto [points, type] = CalcPredictedHealing(m_spellInfo, unitCaster, target, m_castItemEntry, m_castItemLevel, this, withPeriodic);
5123 healPrediction.Points = points;
5124 healPrediction.Type = type;
5125 }
5126
5127 static constexpr uint32 beaconSpellId = 53651;
5128
5129 if (healPrediction.Type == SPELL_HEAL_PREDICTION_TARGET && unitCaster->HasAura(beaconSpellId, unitCaster->GetGUID()))
5130 {
5131 auto beacon = std::find_if(unitCaster->GetSingleCastAuras().begin(), unitCaster->GetSingleCastAuras().end(), [](Aura const* aura)
5132 {
5133 return aura->GetSpellInfo()->GetEffects().size() > EFFECT_1 && aura->GetSpellInfo()->GetEffect(EFFECT_1).TriggerSpell == beaconSpellId;
5134 });
5135
5136 if (beacon != unitCaster->GetSingleCastAuras().end())
5137 {
5138 healPrediction.BeaconGUID = (*beacon)->GetOwner()->GetGUID();
5140 }
5141 }
5142}
5143
5145{
5146 if (_executeLogEffects.empty())
5147 return;
5148
5150 spellExecuteLog.Caster = m_caster->GetGUID();
5151 spellExecuteLog.SpellID = m_spellInfo->Id;
5152 spellExecuteLog.Effects = &_executeLogEffects;
5153 spellExecuteLog.LogData.Initialize(this);
5154
5155 m_caster->SendCombatLogMessage(&spellExecuteLog);
5156
5157 _executeLogEffects.clear();
5158}
5159
5161{
5162 auto itr = std::find_if(_executeLogEffects.begin(), _executeLogEffects.end(), [effect](SpellLogEffect& log)
5163 {
5164 return log.Effect == effect;
5165 });
5166 if (itr != _executeLogEffects.end())
5167 return *itr;
5168
5169 _executeLogEffects.emplace_back();
5170 _executeLogEffects.back().Effect = effect;
5171 return _executeLogEffects.back();
5172}
5173
5174void Spell::ExecuteLogEffectTakeTargetPower(SpellEffectName effect, Unit* target, Powers powerType, uint32 points, float amplitude)
5175{
5176 SpellLogEffectPowerDrainParams spellLogEffectPowerDrainParams;
5177
5178 spellLogEffectPowerDrainParams.Victim = target->GetGUID();
5179 spellLogEffectPowerDrainParams.Points = points;
5180 spellLogEffectPowerDrainParams.PowerType = powerType;
5181 spellLogEffectPowerDrainParams.Amplitude = amplitude;
5182
5183 GetExecuteLogEffectTargets(effect, &SpellLogEffect::PowerDrainTargets).push_back(spellLogEffectPowerDrainParams);
5184}
5185
5187{
5188 SpellLogEffectExtraAttacksParams spellLogEffectExtraAttacksParams;
5189 spellLogEffectExtraAttacksParams.Victim = victim->GetGUID();
5190 spellLogEffectExtraAttacksParams.NumAttacks = numAttacks;
5191
5192 GetExecuteLogEffectTargets(effect, &SpellLogEffect::ExtraAttacksTargets).push_back(spellLogEffectExtraAttacksParams);
5193}
5194
5196{
5198 data.Caster = m_caster->GetGUID();
5199 data.Victim = victim->GetGUID();
5201 data.SpellID = spellId;
5202
5203 m_caster->SendMessageToSet(data.Write(), true);
5204}
5205
5207{
5208 SpellLogEffectDurabilityDamageParams spellLogEffectDurabilityDamageParams;
5209 spellLogEffectDurabilityDamageParams.Victim = victim->GetGUID();
5210 spellLogEffectDurabilityDamageParams.ItemID = itemId;
5211 spellLogEffectDurabilityDamageParams.Amount = amount;
5212
5213 GetExecuteLogEffectTargets(effect, &SpellLogEffect::DurabilityDamageTargets).push_back(spellLogEffectDurabilityDamageParams);
5214}
5215
5217{
5218 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5219 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5220
5221 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5222}
5223
5225{
5226 SpellLogEffectTradeSkillItemParams spellLogEffectTradeSkillItemParams;
5227 spellLogEffectTradeSkillItemParams.ItemID = entry;
5228
5229 GetExecuteLogEffectTargets(effect, &SpellLogEffect::TradeSkillTargets).push_back(spellLogEffectTradeSkillItemParams);
5230}
5231
5233{
5234 SpellLogEffectFeedPetParams spellLogEffectFeedPetParams;
5235 spellLogEffectFeedPetParams.ItemID = entry;
5236
5237 GetExecuteLogEffectTargets(effect, &SpellLogEffect::FeedPetTargets).push_back(spellLogEffectFeedPetParams);
5238}
5239
5241{
5242 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5243 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5244
5245 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5246}
5247
5249{
5250 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5251 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5252
5253 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5254}
5255
5257{
5258 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5259 spellLogEffectGenericVictimParams.Victim = target->GetGUID();
5260
5261 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5262}
5263
5265{
5267 failurePacket.CasterUnit = m_caster->GetGUID();
5268 failurePacket.CastID = m_castId;
5269 failurePacket.SpellID = m_spellInfo->Id;
5270 failurePacket.Visual = m_SpellVisual;
5271 failurePacket.Reason = result;
5272 m_caster->SendMessageToSet(failurePacket.Write(), true);
5273
5275 failedPacket.CasterUnit = m_caster->GetGUID();
5276 failedPacket.CastID = m_castId;
5277 failedPacket.SpellID = m_spellInfo->Id;
5278 failedPacket.Visual = m_SpellVisual;
5279 failedPacket.Reason = result;
5280 m_caster->SendMessageToSet(failedPacket.Write(), true);
5281}
5282
5284{
5285 // GameObjects don't channel
5286 Unit* unitCaster = m_caster->ToUnit();
5287 if (!unitCaster)
5288 return;
5289
5290 if (time == 0)
5291 {
5292 unitCaster->ClearChannelObjects();
5293 unitCaster->SetChannelSpellId(0);
5294 unitCaster->SetChannelVisual({});
5295 unitCaster->SetSpellEmpowerStage(-1);
5296 }
5297
5298 if (IsEmpowerSpell())
5299 {
5301 spellEmpowerUpdate.CastID = m_castId;
5302 spellEmpowerUpdate.CasterGUID = unitCaster->GetGUID();
5303 spellEmpowerUpdate.TimeRemaining = Milliseconds(time);
5304 if (time > 0)
5305 spellEmpowerUpdate.StageDurations.assign(m_empower->StageDurations.begin(), m_empower->StageDurations.end());
5306 else if (result && result != SPELL_CAST_OK)
5307 spellEmpowerUpdate.Status = 1;
5308 else
5309 spellEmpowerUpdate.Status = 4;
5310
5311 unitCaster->SendMessageToSet(spellEmpowerUpdate.Write(), true);
5312 }
5313 else
5314 {
5316 spellChannelUpdate.CasterGUID = unitCaster->GetGUID();
5317 spellChannelUpdate.TimeRemaining = time;
5318 unitCaster->SendMessageToSet(spellChannelUpdate.Write(), true);
5319 }
5320}
5321
5323{
5324 // GameObjects don't channel
5325 Unit* unitCaster = m_caster->ToUnit();
5326 if (!unitCaster)
5327 return;
5328
5329 m_timer = duration;
5330
5331 if (!m_UniqueTargetInfo.empty() || !m_UniqueGOTargetInfo.empty())
5332 {
5333 uint32 channelAuraMask = 0;
5334 uint32 explicitTargetEffectMask = 0xFFFFFFFF;
5335 // if there is an explicit target, only add channel objects from effects that also hit it
5337 {
5338 auto explicitTargetItr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo const& target)
5339 {
5340 return target.TargetGUID == m_targets.GetUnitTargetGUID();
5341 });
5342 if (explicitTargetItr != m_UniqueTargetInfo.end())
5343 explicitTargetEffectMask = explicitTargetItr->EffectMask;
5344 }
5345
5346 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5347 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && (explicitTargetEffectMask & (1u << spellEffectInfo.EffectIndex)))
5348 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
5349
5350 for (TargetInfo const& target : m_UniqueTargetInfo)
5351 {
5352 if (!(target.EffectMask & channelAuraMask))
5353 continue;
5354
5355 SpellAttr1 requiredAttribute = target.TargetGUID != unitCaster->GetGUID() ? SPELL_ATTR1_IS_CHANNELLED : SPELL_ATTR1_IS_SELF_CHANNELLED;
5356 if (!m_spellInfo->HasAttribute(requiredAttribute))
5357 continue;
5358
5359 unitCaster->AddChannelObject(target.TargetGUID);
5360 }
5361
5362 for (GOTargetInfo const& target : m_UniqueGOTargetInfo)
5363 if (target.EffectMask & channelAuraMask)
5364 unitCaster->AddChannelObject(target.TargetGUID);
5365 }
5367 unitCaster->AddChannelObject(unitCaster->GetGUID());
5368
5369 if (Creature* creatureCaster = unitCaster->ToCreature())
5370 if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
5371 if (!creatureCaster->HasSpellFocus(this))
5372 creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, unitCaster->m_unitData->ChannelObjects[0]));
5373
5374 unitCaster->SetChannelSpellId(m_spellInfo->Id);
5375 unitCaster->SetChannelVisual(m_SpellVisual);
5376
5377 auto setImmunitiesAndHealPrediction = [&](Optional<WorldPackets::Spells::SpellChannelStartInterruptImmunities>& interruptImmunities, Optional<WorldPackets::Spells::SpellTargetedHealPrediction>& healPrediction)
5378 {
5379 uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
5380 uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
5381
5382 if (schoolImmunityMask || mechanicImmunityMask)
5383 {
5384 interruptImmunities.emplace();
5385 interruptImmunities->SchoolImmunities = schoolImmunityMask;
5386 interruptImmunities->Immunities = mechanicImmunityMask;
5387 }
5388
5390 {
5391 healPrediction.emplace();
5392 if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
5393 healPrediction->TargetGUID = unitCaster->m_unitData->ChannelObjects[0];
5394
5395 UpdateSpellHealPrediction(healPrediction->Predict, true);
5396 }
5397 };
5398
5399 if (IsEmpowerSpell())
5400 {
5401 unitCaster->SetSpellEmpowerStage(0);
5402
5404 spellEmpowerStart.CastID = m_castId;
5405 spellEmpowerStart.CasterGUID = unitCaster->GetGUID();
5406 spellEmpowerStart.SpellID = m_spellInfo->Id;
5407 spellEmpowerStart.Visual = m_SpellVisual;
5408 spellEmpowerStart.EmpowerDuration = std::reduce(m_empower->StageDurations.begin(), m_empower->StageDurations.end());
5409 spellEmpowerStart.MinHoldTime = m_empower->MinHoldTime;
5411 spellEmpowerStart.Targets.assign(unitCaster->m_unitData->ChannelObjects.begin(), unitCaster->m_unitData->ChannelObjects.end());
5412 spellEmpowerStart.StageDurations.assign(m_empower->StageDurations.begin(), m_empower->StageDurations.end());
5413 setImmunitiesAndHealPrediction(spellEmpowerStart.InterruptImmunities, spellEmpowerStart.HealPrediction);
5414
5415 unitCaster->SendMessageToSet(spellEmpowerStart.Write(), true);
5416 }
5417 else
5418 {
5420 spellChannelStart.CasterGUID = unitCaster->GetGUID();
5421 spellChannelStart.SpellID = m_spellInfo->Id;
5422 spellChannelStart.Visual = m_SpellVisual;
5423 spellChannelStart.ChannelDuration = duration;
5424 setImmunitiesAndHealPrediction(spellChannelStart.InterruptImmunities, spellChannelStart.HealPrediction);
5425
5426 unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
5427 }
5428}
5429
5431{
5432 // get resurrector name for creature resurrections, otherwise packet will be not accepted
5433 // for player resurrections the name is looked up by guid
5434 std::string sentName;
5437
5439 resurrectRequest.ResurrectOffererGUID = m_caster->GetGUID();
5440 if (Player const* playerCaster = m_caster->ToPlayer())
5441 resurrectRequest.ResurrectOffererVirtualRealmAddress = playerCaster->m_playerData->VirtualPlayerRealm;
5442 else
5444
5445 resurrectRequest.Name = sentName;
5446 resurrectRequest.Sickness = m_caster->IsUnit() && m_caster->ToUnit()->IsSpiritHealer(); // "you'll be afflicted with resurrection sickness"
5448 if (Pet* pet = target->GetPet())
5449 if (CharmInfo* charmInfo = pet->GetCharmInfo())
5450 resurrectRequest.PetNumber = charmInfo->GetPetNumber();
5451
5452 resurrectRequest.SpellID = m_spellInfo->Id;
5453 target->SendDirectMessage(resurrectRequest.Write());
5454}
5455
5457{
5458 if (!m_CastItem)
5459 return;
5460
5461 Player* player = m_caster->ToPlayer();
5462 if (!player)
5463 return;
5464
5465 // not remove cast item at triggered spell (equipping, weapon damage, etc)
5467 return;
5468
5469 ItemTemplate const* proto = m_CastItem->GetTemplate();
5470
5471 if (!proto)
5472 {
5473 // This code is to avoid a crash
5474 // I'm not sure, if this is really an error, but I guess every item needs a prototype
5475 TC_LOG_ERROR("spells", "Cast item has no item prototype {}", m_CastItem->GetGUID().ToString());
5476 return;
5477 }
5478
5479 bool expendable = false;
5480 bool withoutCharges = false;
5481
5482 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
5483 {
5484 // item has limited charges
5485 if (itemEffect->Charges)
5486 {
5487 if (itemEffect->Charges < 0)
5488 expendable = true;
5489
5490 int32 charges = m_CastItem->GetSpellCharges(itemEffect);
5491
5492 // item has charges left for this slot
5493 if (charges && itemEffect->SpellID == int32(m_spellInfo->Id))
5494 {
5495 if (charges > 0)
5496 --charges;
5497 else
5498 ++charges;
5499
5500 if (proto->GetMaxStackSize() == 1)
5501 m_CastItem->SetSpellCharges(itemEffect, charges);
5503 }
5504
5505 // all charges used
5506 withoutCharges = (charges == 0);
5507 }
5508 }
5509
5510 if (expendable && withoutCharges)
5511 {
5512 uint32 count = 1;
5513 m_caster->ToPlayer()->DestroyItemCount(m_CastItem, count, true);
5514
5515 // prevent crash at access to deleted m_targets.GetItemTarget
5517 m_targets.SetItemTarget(nullptr);
5518
5519 m_CastItem = nullptr;
5521 m_castItemEntry = 0;
5522 }
5523}
5524
5526{
5527 // GameObjects don't use power
5528 Unit* unitCaster = m_caster->ToUnit();
5529 if (!unitCaster)
5530 return;
5531
5533 return;
5534
5535 //Don't take power if the spell is cast while .cheat power is enabled.
5536 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5537 {
5538 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
5539 return;
5540 }
5541
5542 bool hit = true;
5543 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5544 {
5546 {
5547 ObjectGuid targetGUID = m_targets.GetUnitTargetGUID();
5548 if (!targetGUID.IsEmpty())
5549 hit = std::ranges::any_of(m_UniqueTargetInfo, [&](TargetInfo const& targetInfo) { return targetInfo.TargetGUID == targetGUID && targetInfo.MissCondition == SPELL_MISS_NONE; });
5550 }
5551 }
5552
5553 for (SpellPowerCost& cost : m_powerCost)
5554 {
5555 if (!hit)
5556 {
5557 // skipping granting power through negative cost only when spell has SPELL_ATTR1_DISCOUNT_POWER_ON_MISS is correct behavior
5558 // tested with 206931 - Blooddrinker
5559 if (cost.Amount < 0)
5560 continue;
5561
5562 //lower spell cost on fail (by talent aura)
5563 if (Player* modOwner = unitCaster->GetSpellModOwner())
5564 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCostOnMiss, cost.Amount);
5565 }
5566
5567 if (cost.Power == POWER_RUNES)
5568 {
5569 TakeRunePower(hit);
5570 continue;
5571 }
5572
5573 if (!cost.Amount)
5574 continue;
5575
5576 // health as power used
5577 if (cost.Power == POWER_HEALTH)
5578 {
5579 unitCaster->ModifyHealth(-cost.Amount);
5580 continue;
5581 }
5582
5583 unitCaster->ModifyPower(cost.Power, -cost.Amount);
5584 }
5585}
5586
5588{
5589 // GameObjects don't use power
5590 Unit* unitCaster = m_caster->ToUnit();
5591 if (!unitCaster)
5592 return;
5593
5595 return;
5596
5597 //Don't take power if the spell is cast while .cheat power is enabled.
5598 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5599 {
5600 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
5601 return;
5602 }
5603
5604 for (SpellPowerCost& cost : m_powerCost)
5605 {
5606 if (cost.Power == POWER_RUNES)
5607 {
5609 continue;
5610 }
5611
5612 if (!cost.Amount)
5613 continue;
5614
5615 // health as power used
5616 if (cost.Power == POWER_HEALTH)
5617 {
5618 unitCaster->ModifyHealth(cost.Amount);
5619 continue;
5620 }
5621
5622 unitCaster->ModifyPower(cost.Power, cost.Amount);
5623 }
5624}
5625
5627{
5628 int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
5629 {
5630 return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0);
5631 });
5632
5633 if (!runeCost)
5634 return SPELL_CAST_OK;
5635
5636 Player* player = m_caster->ToPlayer();
5637 if (!player)
5638 return SPELL_CAST_OK;
5639
5640 if (player->GetClass() != CLASS_DEATH_KNIGHT)
5641 return SPELL_CAST_OK;
5642
5643 int32 readyRunes = 0;
5644 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5645 if (player->GetRuneCooldown(i) == 0)
5646 ++readyRunes;
5647
5648 if (readyRunes < runeCost)
5649 return SPELL_FAILED_NO_POWER; // not sure if result code is correct
5650
5651 return SPELL_CAST_OK;
5652}
5653
5654void Spell::TakeRunePower(bool didHit)
5655{
5657 return;
5658
5659 Player* player = m_caster->ToPlayer();
5660 m_runesState = player->GetRunesState(); // store previous state
5661
5662 if (!didHit)
5663 return;
5664
5665 int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
5666 {
5667 return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0);
5668 });
5669
5670 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5671 {
5672 if (!player->GetRuneCooldown(i) && runeCost > 0)
5673 {
5674 player->SetRuneCooldown(i, player->GetRuneBaseCooldown());
5675 --runeCost;
5676 }
5677 }
5678}
5679
5681{
5683 return;
5684
5685 Player* player = m_caster->ToPlayer();
5686
5687 // restore old rune state
5688 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5689 if (m_runesState & (1 << i))
5690 player->SetRuneCooldown(i, 0);
5691}
5692
5694{
5696 return;
5697
5698 // do not take reagents for these item casts
5700 return;
5701
5702 Player* p_caster = m_caster->ToPlayer();
5703 if (p_caster->CanNoReagentCast(m_spellInfo))
5704 return;
5705
5706 for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
5707 {
5708 if (m_spellInfo->Reagent[x] <= 0)
5709 continue;
5710
5711 uint32 itemid = m_spellInfo->Reagent[x];
5712 uint32 itemcount = m_spellInfo->ReagentCount[x];
5713
5714 // if CastItem is also spell reagent
5715 if (m_CastItem && m_CastItem->GetEntry() == itemid)
5716 {
5717 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
5718 {
5719 // CastItem will be used up and does not count as reagent
5720 int32 charges = m_CastItem->GetSpellCharges(itemEffect);
5721 if (itemEffect->Charges < 0 && abs(charges) < 2)
5722 {
5723 ++itemcount;
5724 break;
5725 }
5726 }
5727
5728 m_CastItem = nullptr;
5730 m_castItemEntry = 0;
5731 }
5732
5733 // if GetItemTarget is also spell reagent
5734 if (m_targets.GetItemTargetEntry() == itemid)
5735 m_targets.SetItemTarget(nullptr);
5736
5737 p_caster->DestroyItemCount(itemid, itemcount, true);
5738 }
5739
5740 for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency)
5741 p_caster->RemoveCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount, CurrencyDestroyReason::Spell);
5742}
5743
5745{
5746 // wild GameObject spells don't cause threat
5747 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
5748 if (!unitCaster)
5749 return;
5750
5751 if (m_UniqueTargetInfo.empty())
5752 return;
5753
5755 return;
5756
5757 float threat = 0.0f;
5758 if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
5759 {
5760 if (threatEntry->apPctMod != 0.0f)
5761 threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
5762
5763 threat += threatEntry->flatMod;
5764 }
5766 threat += m_spellInfo->SpellLevel;
5767
5768 // past this point only multiplicative effects occur
5769 if (threat == 0.0f)
5770 return;
5771
5772 // 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
5773 threat /= m_UniqueTargetInfo.size();
5774
5775 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
5776 {
5777 float threatToAdd = threat;
5778 if (ihit->MissCondition != SPELL_MISS_NONE)
5779 threatToAdd = 0.0f;
5780
5781 Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit->TargetGUID);
5782 if (!target)
5783 continue;
5784
5785 // positive spells distribute threat among all units that are in combat with target, like healing
5786 if (IsPositive())
5787 target->GetThreatManager().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
5788 // for negative spells threat gets distributed among affected targets
5789 else
5790 {
5791 if (!target->CanHaveThreatList())
5792 continue;
5793
5794 target->GetThreatManager().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
5795 }
5796 }
5797 TC_LOG_DEBUG("spells", "Spell {}, added an additional {} threat for {} {} target(s)", m_spellInfo->Id, threat, IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
5798}
5799
5800void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
5801{
5802 effectHandleMode = mode;
5803 unitTarget = pUnitTarget;
5804 itemTarget = pItemTarget;
5805 gameObjTarget = pGoTarget;
5806 m_corpseTarget = pCorpseTarget;
5807 destTarget = &m_destTargets[spellEffectInfo.EffectIndex]._position;
5808 effectInfo = &spellEffectInfo;
5809
5810 damage = CalculateDamage(spellEffectInfo, unitTarget, &variance);
5811
5812 bool preventDefault = CallScriptEffectHandlers(spellEffectInfo.EffectIndex, mode);
5813
5814 if (!preventDefault)
5815 (this->*SpellEffectHandlers[spellEffectInfo.Effect].Value)();
5816}
5817
5819{
5820 if (SpellEvent* spellEvent = dynamic_cast<SpellEvent*>(event))
5821 return spellEvent->GetSpell();
5822
5823 return nullptr;
5824}
5825
5826SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/)
5827{
5828 // check death state
5831
5832 // 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
5834 {
5837 }
5838
5839 // check cooldowns to prevent cheating
5840 if (!m_spellInfo->IsPassive())
5841 {
5842 if (Player const* playerCaster = m_caster->ToPlayer())
5843 {
5844 //can cast triggered (by aura only?) spells while have this flag
5846 {
5847 // These two auras check SpellFamilyName defined by db2 class data instead of current spell SpellFamilyName
5848 if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES)
5852 && !playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->GetClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
5854
5855 if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES))
5856 {
5857 if (!playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->GetClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
5858 {
5869 }
5870 }
5871 }
5872
5873 // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
5874 if (!IsIgnoringCooldowns() && playerCaster->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
5876 }
5877
5879 {
5881 {
5884 else
5886 }
5887
5890 }
5891 }
5892
5894 {
5897 }
5898
5901
5902 // Check global cooldown
5905
5906 // only triggered spells can be processed an ended battleground
5909 if (bg->GetStatus() == STATUS_WAIT_LEAVE)
5911
5913 {
5915 !m_caster->IsOutdoors())
5917
5921 }
5922
5923 if (Unit* unitCaster = m_caster->ToUnit())
5924 {
5925 if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED) && unitCaster->IsCharmed())
5926 return SPELL_FAILED_CHARMED;
5927
5928 // only check at first call, Stealth auras are already removed at second call
5929 // for now, ignore triggered spells
5931 {
5932 bool checkForm = true;
5933 // Ignore form req aura
5934 Unit::AuraEffectList const& ignore = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
5935 for (AuraEffect const* aurEff : ignore)
5936 {
5937 if (!aurEff->IsAffectingSpell(m_spellInfo))
5938 continue;
5939
5940 checkForm = false;
5941 break;
5942 }
5943
5944 if (checkForm)
5945 {
5946 // Cannot be used in this stance/form
5947 SpellCastResult shapeError = m_spellInfo->CheckShapeshift(unitCaster->GetShapeshiftForm());
5948 if (shapeError != SPELL_CAST_OK)
5949 return shapeError;
5950
5951 if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(unitCaster->HasStealthAura()))
5953 }
5954 }
5955
5956 // caster state requirements
5957 // not for triggered spells (needed by execute)
5959 {
5960 if (m_spellInfo->CasterAuraState && !unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, unitCaster))
5962 if (m_spellInfo->ExcludeCasterAuraState && unitCaster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, unitCaster))
5964
5965 // Note: spell 62473 requres casterAuraSpell = triggering spell
5966 if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(m_spellInfo->CasterAuraSpell))
5970
5971 if (m_spellInfo->CasterAuraType && !unitCaster->HasAuraType(m_spellInfo->CasterAuraType))
5973 if (m_spellInfo->ExcludeCasterAuraType && unitCaster->HasAuraType(m_spellInfo->ExcludeCasterAuraType))
5975
5976 if (unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat(unitCaster))
5978
5980 {
5981 bool hasInvalidMountAura = std::ranges::any_of(unitCaster->GetAuraEffectsByType(SPELL_AURA_MOUNTED), [unitCaster](AuraEffect const* mountEffect)
5982 {
5983 uint32 mountType = mountEffect->GetSpellEffectInfo().MiscValueB;
5984 if (MountEntry const* mountEntry = sDB2Manager.GetMount(mountEffect->GetId()))
5985 mountType = mountEntry->MountTypeID;
5986
5987 MountCapabilityEntry const* mountCapability = unitCaster->GetMountCapability(mountType);
5988 return !mountCapability || mountCapability->ID != uint32(mountEffect->GetAmount());
5989 });
5990
5991 if (!hasInvalidMountAura)
5993 }
5994 }
5995
5996 // Check vehicle flags
5998 {
5999 SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(unitCaster);
6000 if (vehicleCheck != SPELL_CAST_OK)
6001 return vehicleCheck;
6002 }
6003 }
6004
6005 // check spell cast conditions from database
6006 {
6008 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL, m_spellInfo->Id, condInfo))
6009 {
6010 // mLastFailedCondition can be NULL if there was an error processing the condition in Condition::Meets (i.e. wrong data for ConditionTarget or others)
6011 if (condInfo.mLastFailedCondition && condInfo.mLastFailedCondition->ErrorType)
6012 {
6016 }
6017
6018 if (!condInfo.mLastFailedCondition || !condInfo.mLastFailedCondition->ConditionTarget)
6021 }
6022 }
6023
6024 // Don't check explicit target for passive spells (workaround) (check should be skipped only for learn case)
6025 // those spells may have incorrect target entries or not filled at all (for example 15332)
6026 // such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
6027 // also, such casts shouldn't be sent to client
6029 {
6030 // Check explicit target for m_originalCaster - todo: get rid of such workarounds
6031 WorldObject* caster = m_caster;
6032 // in case of gameobjects like traps, we need the gameobject itself to check target validity
6033 // otherwise, if originalCaster is far away and cannot detect the target, the trap would not hit the target
6034 if (m_originalCaster && !caster->ToGameObject())
6035 caster = m_originalCaster;
6036
6038 if (castResult != SPELL_CAST_OK)
6039 return castResult;
6040 }
6041
6042 if (Unit* target = m_targets.GetUnitTarget())
6043 {
6044 SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetTypeId() == TYPEID_GAMEOBJECT); // skip stealth checks for GO casts
6045 if (castResult != SPELL_CAST_OK)
6046 return castResult;
6047
6048 // If it's not a melee spell, check if vision is obscured by SPELL_AURA_INTERFERE_TARGETTING
6050 {
6051 if (Unit const* unitCaster = m_caster->ToUnit())
6052 {
6053 for (AuraEffect const* auraEff : unitCaster->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
6054 if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && !target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
6056
6057 for (AuraEffect const* auraEff : target->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
6058 if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && (!target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()) || !unitCaster->HasAura(auraEff->GetId(), auraEff->GetCasterGUID())))
6060 }
6061 }
6062
6063 if (target != m_caster)
6064 {
6065 // Must be behind the target
6066 if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)) && target->HasInArc(static_cast<float>(M_PI), m_caster))
6068
6069 // Target must be facing you
6070 if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER)) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
6072
6073 // Ignore LOS for gameobjects casts
6075 {
6076 WorldObject* losTarget = m_caster;
6079 losTarget = dynObj;
6080
6081 if (!IsWithinLOS(losTarget, target, true, VMAP::ModelIgnoreFlags::M2))
6083 }
6084 }
6085 }
6086
6087 // Check for line of sight for spells with dest
6088 if (m_targets.HasDst())
6091
6092 // check pet presence
6093 if (Unit* unitCaster = m_caster->ToUnit())
6094 {
6096 if (!unitCaster->GetPetGUID().IsEmpty())
6098
6099 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6100 {
6101 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
6102 {
6103 if (!unitCaster->GetGuardianPet())
6104 {
6105 if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
6107 else
6108 return SPELL_FAILED_NO_PET;
6109 }
6110 break;
6111 }
6112 }
6113 }
6114
6115 // Spell cast only in battleground
6117 if (!m_caster->GetMap()->IsBattleground())
6119
6120 // do not allow spells to be cast in arenas or rated battlegrounds
6121 if (Player* player = m_caster->ToPlayer())
6122 if (player->InArena()/* || player->InRatedBattleGround() NYI*/)
6123 {
6125 if (castResult != SPELL_CAST_OK)
6126 return castResult;
6127 }
6128
6129 // zone check
6131 {
6132 uint32 zone, area;
6133 m_caster->GetZoneAndAreaId(zone, area);
6134
6136 if (locRes != SPELL_CAST_OK)
6137 return locRes;
6138 }
6139
6140 // not let players cast spells at mount (and let do it to creatures)
6142 {
6144 {
6145 if (m_caster->ToPlayer()->IsInFlight())
6147 else
6149 }
6150 }
6151
6152 // check spell focus object
6154 {
6156 {
6158 if (!focusObject)
6160 }
6161 }
6162
6163 SpellCastResult castResult = SPELL_CAST_OK;
6164
6165 // always (except passive spells) check items (only player related checks)
6166 if (!m_spellInfo->IsPassive())
6167 {
6168 castResult = CheckItems(param1, param2);
6169 if (castResult != SPELL_CAST_OK)
6170 return castResult;
6171 }
6172
6173 // Triggered spells also have range check
6175 castResult = CheckRange(strict);
6176 if (castResult != SPELL_CAST_OK)
6177 return castResult;
6178
6180 {
6181 castResult = CheckPower();
6182 if (castResult != SPELL_CAST_OK)
6183 return castResult;
6184 }
6185
6187 {
6188 castResult = CheckCasterAuras(param1);
6189 if (castResult != SPELL_CAST_OK)
6190 return castResult;
6191 }
6192
6193 // script hook
6194 castResult = CallScriptCheckCastHandlers();
6195 if (castResult != SPELL_CAST_OK)
6196 return castResult;
6197
6198 uint32 approximateAuraEffectMask = 0;
6199 uint32 nonAuraEffectMask = 0;
6200 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6201 {
6202 // for effects of spells that have only one target
6203 switch (spellEffectInfo.Effect)
6204 {
6205 case SPELL_EFFECT_DUMMY:
6206 {
6207 if (m_spellInfo->Id == 19938) // Awaken Peon
6208 {
6209 Unit* unit = m_targets.GetUnitTarget();
6210 if (!unit || !unit->HasAura(17743))
6212 }
6213 else if (m_spellInfo->Id == 31789) // Righteous Defense
6214 {
6217
6218 Unit* target = m_targets.GetUnitTarget();
6219 if (!target || !target->IsFriendlyTo(m_caster) || target->getAttackers().empty())
6221
6222 }
6223 break;
6224 }
6226 {
6227 if (spellEffectInfo.TargetA.GetTarget() != TARGET_UNIT_PET)
6228 break;
6229
6230 Pet* pet = m_caster->ToPlayer()->GetPet();
6231 if (!pet)
6232 return SPELL_FAILED_NO_PET;
6233
6234 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
6235 if (!learn_spellproto)
6237
6238 if (m_spellInfo->SpellLevel > pet->GetLevel())
6239 return SPELL_FAILED_LOWLEVEL;
6240
6241 break;
6242 }
6244 {
6247 if (Guild* guild = m_caster->ToPlayer()->GetGuild())
6248 if (guild->GetLeaderGUID() != m_caster->ToPlayer()->GetGUID())
6250 break;
6251 }
6253 {
6254 // check target only for unit target case
6255 if (Unit* unit = m_targets.GetUnitTarget())
6256 {
6259
6260 Pet* pet = unit->ToPet();
6261 if (!pet || pet->GetOwner() != m_caster)
6263
6264 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
6265
6266 if (!learn_spellproto)
6268
6269 if (m_spellInfo->SpellLevel > pet->GetLevel())
6270 return SPELL_FAILED_LOWLEVEL;
6271 }
6272 break;
6273 }
6275 {
6278
6279 Player* caster = m_caster->ToPlayer();
6280 if (!caster->HasSpell(m_misc.SpellId))
6282
6283 if (uint32 glyphId = spellEffectInfo.MiscValue)
6284 {
6285 GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId);
6286 if (!glyphProperties)
6288
6289 std::vector<uint32> const* glyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId);
6290 if (!glyphBindableSpells)
6292
6293 if (std::find(glyphBindableSpells->begin(), glyphBindableSpells->end(), m_misc.SpellId) == glyphBindableSpells->end())
6295
6296 if (std::vector<ChrSpecialization> const* glyphRequiredSpecs = sDB2Manager.GetGlyphRequiredSpecs(glyphId))
6297 {
6300
6301 if (std::find(glyphRequiredSpecs->begin(), glyphRequiredSpecs->end(), caster->GetPrimarySpecialization()) == glyphRequiredSpecs->end())
6303 }
6304
6305 uint32 replacedGlyph = 0;
6306 for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
6307 {
6308 if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(activeGlyphId))
6309 {
6310 if (std::find(activeGlyphBindableSpells->begin(), activeGlyphBindableSpells->end(), m_misc.SpellId) != activeGlyphBindableSpells->end())
6311 {
6312 replacedGlyph = activeGlyphId;
6313 break;
6314 }
6315 }
6316 }
6317
6318 for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
6319 {
6320 if (activeGlyphId == replacedGlyph)
6321 continue;
6322
6323 if (activeGlyphId == glyphId)
6325
6326 if (sGlyphPropertiesStore.AssertEntry(activeGlyphId)->GlyphExclusiveCategoryID == glyphProperties->GlyphExclusiveCategoryID)
6328 }
6329 }
6330 break;
6331 }
6333 {
6336
6337 Item* foodItem = m_targets.GetItemTarget();
6338 if (!foodItem)
6340
6341 Pet* pet = m_caster->ToPlayer()->GetPet();
6342 if (!pet)
6343 return SPELL_FAILED_NO_PET;
6344
6345 if (!pet->HaveInDiet(foodItem->GetTemplate()))
6347
6348 if (foodItem->GetTemplate()->GetBaseItemLevel() + 30 <= pet->GetLevel())
6350
6351 if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
6353
6354 break;
6355 }
6357 {
6358 Unit* unitCaster = m_caster->ToUnit();
6359 if (!unitCaster)
6361
6363 return SPELL_FAILED_ROOTED;
6364
6365 if (GetSpellInfo()->NeedsExplicitUnitTarget())
6366 {
6367 Unit* target = m_targets.GetUnitTarget();
6368 if (!target)
6370
6371 // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
6372 if (!IsWithinLOS(unitCaster, target, true, VMAP::ModelIgnoreFlags::Nothing)) //Do full LoS/Path check. Don't exclude m2
6374
6375 float objSize = target->GetCombatReach();
6376 float range = m_spellInfo->GetMaxRange(true, unitCaster, this) * 1.5f + objSize; // can't be overly strict
6377
6378 m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
6379 m_preGeneratedPath->SetPathLengthLimit(range);
6380
6381 // first try with raycast, if it fails fall back to normal path
6382 bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
6383 if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
6384 return SPELL_FAILED_NOPATH;
6385 else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
6386 return SPELL_FAILED_NOPATH;
6387 else if (m_preGeneratedPath->IsInvalidDestinationZ(target)) // Check position z, if not in a straight line
6388 return SPELL_FAILED_NOPATH;
6389
6390 m_preGeneratedPath->ShortenPathUntilDist(PositionToVector3(target), objSize); // move back
6391 }
6392 break;
6393 }
6395 {
6398
6401
6402 Creature* creature = m_targets.GetUnitTarget()->ToCreature();
6403 Loot* loot = creature->GetLootForPlayer(m_caster->ToPlayer());
6404 if (loot && (!loot->isLooted() || loot->loot_type == LOOT_SKINNING))
6406
6407 break;
6408 }
6410 {
6411 if (spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET &&
6412 spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET)
6413 break;
6414
6415 if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc.
6416 // we need a go target in case of TARGET_GAMEOBJECT_TARGET
6417 || (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget()))
6419
6420 Item* pTempItem = nullptr;
6422 {
6423 if (TradeData* pTrade = m_caster->ToPlayer()->GetTradeData())
6424 pTempItem = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
6425 }
6428
6429 // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
6430 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET &&
6432 (!pTempItem || !pTempItem->GetTemplate()->GetLockID() || !pTempItem->IsLocked()))
6434
6435 if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
6437 if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners
6440
6441 // get the lock entry
6442 uint32 lockId = 0;
6443 if (GameObject* go = m_targets.GetGOTarget())
6444 {
6445 lockId = go->GetGOInfo()->GetLockId();
6446 if (!lockId)
6448
6449 if (go->GetGOInfo()->GetNotInCombat() && m_caster->ToUnit()->IsInCombat())
6451 }
6452 else if (Item* itm = m_targets.GetItemTarget())
6453 lockId = itm->GetTemplate()->GetLockID();
6454
6455 SkillType skillId = SKILL_NONE;
6456 int32 reqSkillValue = 0;
6457 int32 skillValue = 0;
6458
6459 // check lock compatibility
6460 SpellCastResult res = CanOpenLock(spellEffectInfo, lockId, skillId, reqSkillValue, skillValue);
6461 if (res != SPELL_CAST_OK)
6462 return res;
6463 break;
6464 }
6466 {
6467 Player* playerCaster = m_caster->ToPlayer();
6468 if (!playerCaster || !playerCaster->GetPetStable())
6470
6471 Pet* pet = playerCaster->GetPet();
6472 if (pet && pet->IsAlive())
6474
6475 PetStable const* petStable = playerCaster->GetPetStable();
6476 auto deadPetItr = std::find_if(petStable->ActivePets.begin(), petStable->ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
6477 {
6478 return petInfo && !petInfo->Health;
6479 });
6480
6481 if (deadPetItr == petStable->ActivePets.end())
6483
6484 break;
6485 }
6486 // This is generic summon effect
6488 {
6489 Unit* unitCaster = m_caster->ToUnit();
6490 if (!unitCaster)
6491 break;
6492
6493 SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(spellEffectInfo.MiscValueB);
6494 if (!SummonProperties)
6495 break;
6496
6497 switch (SummonProperties->Control)
6498 {
6502 [[fallthrough]]; // check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
6504 if (!unitCaster->GetCharmedGUID().IsEmpty())
6506 break;
6507 }
6508 break;
6509 }
6511 {
6513 {
6518 }
6519 break;
6520 }
6522 {
6523 Unit* unitCaster = m_caster->ToUnit();
6524 if (!unitCaster)
6526
6527 if (!unitCaster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
6528 {
6529 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
6530 {
6531 if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
6532 if (Pet* pet = unitCaster->ToPlayer()->GetPet())
6534 .SetOriginalCaster(pet->GetGUID())
6535 .SetTriggeringSpell(this));
6536 }
6539 }
6540
6541 if (!unitCaster->GetCharmedGUID().IsEmpty())
6543
6544 Player* playerCaster = unitCaster->ToPlayer();
6545 if (playerCaster && playerCaster->GetPetStable())
6546 {
6547 Optional<PetSaveMode> petSlot;
6548 if (!spellEffectInfo.MiscValue)
6549 {
6550 petSlot = PetSaveMode(spellEffectInfo.CalcValue());
6551
6552 // No pet can be summoned if any pet is dead
6553 for (Optional<PetStable::PetInfo> const& activePet : playerCaster->GetPetStable()->ActivePets)
6554 {
6555 if (activePet && !activePet->Health)
6556 {
6557 playerCaster->SendTameFailure(PetTameResult::Dead);
6559 }
6560 }
6561 }
6562
6563 std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, petSlot);
6564 if (info.first)
6565 {
6566 if (info.first->Type == HUNTER_PET)
6567 {
6568 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(info.first->CreatureId);
6569 CreatureDifficulty const* creatureDifficulty = creatureInfo->GetDifficulty(DIFFICULTY_NONE);
6570 if (!creatureInfo || !creatureInfo->IsTameable(playerCaster->CanTameExoticPets(), creatureDifficulty))
6571 {
6572 // if problem in exotic pet
6573 if (creatureInfo && creatureInfo->IsTameable(true, creatureDifficulty))
6575 else
6577
6579 }
6580 }
6581 }
6582 else if (!spellEffectInfo.MiscValue) // when miscvalue is present it is allowed to create new pets
6583 {
6586 }
6587 }
6588
6589 break;
6590 }
6592 {
6593 Player* playerCaster = m_caster->ToPlayer();
6594 if (!playerCaster)
6596
6597 Pet* pet = playerCaster->GetPet();
6598 if (!pet)
6599 return SPELL_FAILED_NO_PET;
6600
6601 if (!pet->IsAlive())
6603
6604 break;
6605 }
6607 {
6610
6611 if (!m_caster->ToPlayer()->GetTarget())
6613
6615 if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell
6617
6618 if (target->HasSummonPending())
6620
6621 // check if our map is dungeon
6622 if (InstanceMap const* map = m_caster->GetMap()->ToInstanceMap())
6623 {
6624 uint32 mapId = map->GetId();
6625 Difficulty difficulty = map->GetDifficultyID();
6626 if (InstanceLock const* mapLock = map->GetInstanceLock())
6627 if (sInstanceLockMgr.CanJoinInstanceLock(target->GetGUID(), { mapId, difficulty }, mapLock) != TRANSFER_ABORT_NONE)
6629
6630 if (!target->Satisfy(sObjectMgr->GetAccessRequirement(mapId, difficulty), mapId))
6632 }
6633 break;
6634 }
6635 // RETURN HERE
6637 {
6640
6641 Player* playerCaster = m_caster->ToPlayer();
6642 if (!playerCaster->GetTarget())
6644
6645 Player* target = playerCaster->GetSelectedPlayer();
6646 if (!target ||
6647 !(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
6649 break;
6650 }
6651 case SPELL_EFFECT_LEAP:
6653 {
6654 //Do not allow to cast it before BG starts.
6656 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
6657 if (bg->GetStatus() != STATUS_IN_PROGRESS)
6659 break;
6660 }
6662 {
6665 break;
6666 }
6668 {
6669 Unit* unitCaster = m_caster->ToUnit();
6670 if (!unitCaster)
6672
6673 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
6674 {
6675 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
6676 return SPELL_FAILED_ROOTED;
6677 else
6679 }
6680 break;
6681 }
6682 case SPELL_EFFECT_JUMP:
6684 {
6685 Unit* unitCaster = m_caster->ToUnit();
6686 if (!unitCaster)
6688
6689 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
6690 return SPELL_FAILED_ROOTED;
6691 break;
6692 }
6694 {
6695 ChrSpecializationEntry const* spec = sChrSpecializationStore.LookupEntry(m_misc.SpecializationId);
6696 Player* player = m_caster->ToPlayer();
6697 if (!player)
6699
6700 if (!spec || (spec->ClassID != player->GetClass() && !spec->IsPetSpecialization()))
6701 return SPELL_FAILED_NO_SPEC;
6702
6703 if (spec->IsPetSpecialization())
6704 {
6705 Pet* pet = player->GetPet();
6706 if (!pet || pet->getPetType() != HUNTER_PET || !pet->GetCharmInfo())
6707 return SPELL_FAILED_NO_PET;
6708 }
6709
6710 // can't change during already started arena/battleground
6711 if (Battleground const* bg = player->GetBattleground())
6712 if (bg->GetStatus() == STATUS_IN_PROGRESS)
6714 break;
6715 }
6717 {
6718 Player* playerCaster = m_caster->ToPlayer();
6719 if (!playerCaster)
6721
6722 TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
6723 if (!talent)
6725
6726 if (playerCaster->GetSpellHistory()->HasCooldown(talent->SpellID))
6727 {
6728 if (param1)
6729 *param1 = talent->SpellID;
6731 }
6732 break;
6733 }
6735 {
6736 if (!m_caster->IsPlayer())
6738
6739 if (!m_caster->ToPlayer()->GetSession()->GetCollectionMgr()->HasHeirloom(m_misc.Raw.Data[0]))
6741
6742 break;
6743 }
6746 {
6747 Player* playerCaster = m_caster->ToPlayer();
6748 if (!playerCaster)
6750
6752 if (!artifactAura)
6754
6755 Item* artifact = playerCaster->GetItemByGuid(artifactAura->GetCastItemGUID());
6756 if (!artifact)
6758
6759 if (spellEffectInfo.Effect == SPELL_EFFECT_GIVE_ARTIFACT_POWER)
6760 {
6761 ArtifactEntry const* artifactEntry = sArtifactStore.LookupEntry(artifact->GetTemplate()->GetArtifactID());
6762 if (!artifactEntry || artifactEntry->ArtifactCategoryID != spellEffectInfo.MiscValue)
6764 }
6765 break;
6766 }
6770 {
6771 Player* playerCaster = m_caster->ToPlayer();
6772 if (!playerCaster || !m_targets.GetUnitTarget() || !m_targets.GetUnitTarget()->IsCreature())
6774
6775 BattlePets::BattlePetMgr* battlePetMgr = playerCaster->GetSession()->GetBattlePetMgr();
6776 if (!battlePetMgr->HasJournalLock())
6778
6779 if (Creature* creature = m_targets.GetUnitTarget()->ToCreature())
6780 {
6781 if (playerCaster->GetSummonedBattlePetGUID().IsEmpty() || creature->GetBattlePetCompanionGUID().IsEmpty())
6782 return SPELL_FAILED_NO_PET;
6783
6784 if (playerCaster->GetSummonedBattlePetGUID() != creature->GetBattlePetCompanionGUID())
6786
6787 if (BattlePets::BattlePet* battlePet = battlePetMgr->GetPet(creature->GetBattlePetCompanionGUID()))
6788 {
6789 if (BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(battlePet->PacketInfo.Species))
6790 {
6791 if (uint32 battlePetType = spellEffectInfo.MiscValue)
6792 if (!(battlePetType & (1 << battlePetSpecies->PetTypeEnum)))
6794
6795 if (spellEffectInfo.Effect == SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY)
6796 {
6797 auto qualityItr = std::lower_bound(sBattlePetBreedQualityStore.begin(), sBattlePetBreedQualityStore.end(), spellEffectInfo.CalcBaseValue(m_caster, creature, m_castItemEntry, m_castItemLevel), [](BattlePetBreedQualityEntry const* a1, int32 selector)
6798 {
6799 return a1->MaxQualityRoll < selector;
6800 });
6801
6803 if (qualityItr != sBattlePetBreedQualityStore.end())
6804 quality = BattlePets::BattlePetBreedQuality(qualityItr->QualityEnum);
6805
6806 if (battlePet->PacketInfo.Quality >= AsUnderlyingType(quality))
6808 }
6809
6810 if (spellEffectInfo.Effect == SPELL_EFFECT_GRANT_BATTLEPET_LEVEL || spellEffectInfo.Effect == SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE)
6811 if (battlePet->PacketInfo.Level >= BattlePets::MAX_BATTLE_PET_LEVEL)
6812 return GRANT_PET_LEVEL_FAIL;
6813
6814 if (battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::CantBattle))
6816 }
6817 }
6818 }
6819 break;
6820 }
6821 default:
6822 break;
6823 }
6824
6825 if (spellEffectInfo.IsAura())
6826 approximateAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6827 else if (spellEffectInfo.IsEffect())
6828 nonAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6829 }
6830
6831 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6832 {
6833 switch (spellEffectInfo.ApplyAuraName)
6834 {
6836 {
6838 return SPELL_FAILED_NO_PET;
6839
6840 Pet* pet = m_caster->ToPlayer()->GetPet();
6841 if (!pet)
6842 return SPELL_FAILED_NO_PET;
6843
6844 if (!pet->GetCharmerGUID().IsEmpty())
6846 break;
6847 }
6851 {
6852 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6853 if (!unitCaster)
6855
6856 if (!unitCaster->GetCharmerGUID().IsEmpty())
6857 return SPELL_FAILED_CHARMED;
6858
6859 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_CHARM
6860 || spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_POSSESS)
6861 {
6864
6865 if (!unitCaster->GetCharmedGUID().IsEmpty())
6867 }
6868
6869 if (Unit* target = m_targets.GetUnitTarget())
6870 {
6871 if (target->GetTypeId() == TYPEID_UNIT && target->IsVehicle())
6873
6874 if (target->IsMounted())
6876
6877 if (!target->GetCharmerGUID().IsEmpty())
6879
6880 if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER)
6882
6883 int32 value = CalculateDamage(spellEffectInfo, target);
6884 if (value && int32(target->GetLevelForTarget(m_caster)) > value)
6886 }
6887
6888 break;
6889 }
6890 case SPELL_AURA_MOUNTED:
6891 {
6892 Unit* unitCaster = m_caster->ToUnit();
6893 if (!unitCaster)
6895
6898
6899 if (unitCaster->IsInDisallowedMountForm())
6900 {
6901 SendMountResult(MountResult::Shapeshifted); // mount result gets sent before the cast result
6903 }
6904 break;
6905 }
6907 {
6908 if (!m_targets.GetUnitTarget())
6910
6911 // can be cast at non-friendly unit or own pet/charm
6914 break;
6915 }
6916 case SPELL_AURA_FLY:
6918 {
6919 // not allow cast fly spells if not have req. skills (all spells is self target)
6920 // allow always ghost flight spells
6922 {
6923 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetMap(), m_originalCaster->GetZoneId());
6924 if (Bf && !Bf->CanFlyIn())
6925 return SPELL_FAILED_NOT_HERE;
6926 }
6927 break;
6928 }
6930 {
6931 if (spellEffectInfo.IsTargetingArea())
6932 break;
6933
6934 if (!m_targets.GetUnitTarget())
6936
6938 break;
6939
6942 break;
6943 }
6944 default:
6945 break;
6946 }
6947
6948 // check if target already has the same type, but more powerful aura
6951 && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex))
6953 if (Unit* target = m_targets.GetUnitTarget())
6954 if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, spellEffectInfo.ApplyAuraName,
6955 spellEffectInfo.CalcValue(m_caster, &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex], nullptr, nullptr, m_castItemEntry, m_castItemLevel),
6956 approximateAuraEffectMask, false))
6958 }
6959
6960 // check trade slot case (last, for allow catch any another cast problems)
6962 {
6963 if (m_CastItem)
6965
6968
6971
6972 TradeData* my_trade = m_caster->ToPlayer()->GetTradeData();
6973 if (!my_trade)
6975
6978
6979 if (!IsTriggered())
6980 if (my_trade->GetSpell())
6982 }
6983
6984 // all ok
6985 return SPELL_CAST_OK;
6986}
6987
6989{
6990 Unit* unitCaster = m_caster->ToUnit();
6991 if (unitCaster && unitCaster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
6993
6994 // dead owner (pets still alive when owners ressed?)
6995 if (Unit* owner = m_caster->GetCharmerOrOwner())
6996 if (!owner->IsAlive())
6998
6999 if (!target && m_targets.GetUnitTarget())
7000 target = m_targets.GetUnitTarget();
7001
7003 {
7004 if (!target)
7006 m_targets.SetUnitTarget(target);
7007 }
7008
7009 // check cooldown
7010 if (Creature* creatureCaster = m_caster->ToCreature())
7011 if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
7013
7014 // Check if spell is affected by GCD
7016 if (unitCaster && unitCaster->GetCharmInfo() && unitCaster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
7018
7019 return CheckCast(true);
7020}
7021
7023{
7024 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
7025 if (!unitCaster)
7026 return SPELL_CAST_OK;
7027
7028 // these attributes only show the spell as usable on the client when it has related aura applied
7029 // still they need to be checked against certain mechanics
7030
7031 // SPELL_ATTR5_USABLE_WHILE_STUNNED by default only MECHANIC_STUN (ie no sleep, knockout, freeze, etc.)
7032 bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_STUNNED);
7033
7034 // SPELL_ATTR5_USABLE_WHILE_FEARED by default only fear (ie no horror)
7035 bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_FLEEING);
7036
7037 // SPELL_ATTR5_USABLE_WHILE_CONFUSED by default only disorient (ie no polymorph)
7038 bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_CONFUSED);
7039
7040 // Check whether the cast should be prevented by any state you might have.
7042
7043 // Get unit state
7044 uint32 const unitflag = unitCaster->m_unitData->Flags;
7045
7046 // this check should only be done when player does cast directly
7047 // (ie not when it's called from a script) Breaks for example PlayerAI when charmed
7048 /*
7049 if (!unitCaster->GetCharmerGUID().IsEmpty())
7050 {
7051 if (Unit* charmer = unitCaster->GetCharmer())
7052 if (charmer->GetUnitBeingMoved() != unitCaster && !CheckSpellCancelsCharm(param1))
7053 result = SPELL_FAILED_CHARMED;
7054 }
7055 */
7056
7057 // spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell
7058 auto mechanicCheck = [&](AuraType type) -> SpellCastResult
7059 {
7060 bool foundNotMechanic = false;
7061 Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
7062 for (AuraEffect const* aurEff : auras)
7063 {
7064 uint64 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
7065 if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask()))
7066 {
7067 foundNotMechanic = true;
7068
7069 // fill up aura mechanic info to send client proper error message
7070 if (param1)
7071 {
7072 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
7073 if (!*param1)
7074 *param1 = aurEff->GetSpellInfo()->Mechanic;
7075 }
7076
7077 break;
7078 }
7079 }
7080
7081 if (foundNotMechanic)
7082 {
7083 switch (type)
7084 {
7087 return SPELL_FAILED_STUNNED;
7089 return SPELL_FAILED_FLEEING;
7091 return SPELL_FAILED_CONFUSED;
7092 default:
7093 ABORT();
7095 }
7096 }
7097
7098 return SPELL_CAST_OK;
7099 };
7100
7101 if (unitflag & UNIT_FLAG_STUNNED)
7102 {
7103 if (usableWhileStunned)
7104 {
7105 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN);
7106 if (mechanicResult != SPELL_CAST_OK)
7107 result = mechanicResult;
7108 else
7109 {
7110 mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN_DISABLE_GRAVITY);
7111 if (mechanicResult != SPELL_CAST_OK)
7112 result = mechanicResult;
7113 }
7114 }
7115 else if (!CheckSpellCancelsStun(param1))
7116 result = SPELL_FAILED_STUNNED;
7117 }
7119 result = SPELL_FAILED_SILENCED;
7121 result = SPELL_FAILED_PACIFIED;
7122 else if (unitflag & UNIT_FLAG_FLEEING)
7123 {
7124 if (usableWhileFeared)
7125 {
7126 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_FEAR);
7127 if (mechanicResult != SPELL_CAST_OK)
7128 result = mechanicResult;
7129 }
7130 else if (!CheckSpellCancelsFear(param1))
7131 result = SPELL_FAILED_FLEEING;
7132 }
7133 else if (unitflag & UNIT_FLAG_CONFUSED)
7134 {
7135 if (usableWhileConfused)
7136 {
7137 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_CONFUSE);
7138 if (mechanicResult != SPELL_CAST_OK)
7139 result = mechanicResult;
7140 }
7141 else if (!CheckSpellCancelsConfuse(param1))
7142 result = SPELL_FAILED_CONFUSED;
7143 }
7145 result = SPELL_FAILED_NO_ACTIONS;
7146
7147 // Attr must make flag drop spell totally immune from all effects
7148 if (result != SPELL_CAST_OK)
7149 return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
7150
7151 return SPELL_CAST_OK;
7152}
7153
7155{
7156 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
7157 if (!unitCaster)
7158 return false;
7159
7160 // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
7161 Unit::AuraEffectList const& auraEffects = unitCaster->GetAuraEffectsByType(auraType);
7162 if (auraEffects.empty())
7163 return true;
7164
7165 for (AuraEffect const* aurEff : auraEffects)
7166 {
7168 continue;
7169
7170 if (param1)
7171 {
7172 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
7173 if (!*param1)
7174 *param1 = aurEff->GetSpellInfo()->Mechanic;
7175 }
7176
7177 return false;
7178 }
7179
7180 return true;
7181}
7182
7184{
7188}
7189
7191{
7194}
7195
7197{
7200}
7201
7203{
7206}
7207
7209{
7211}
7212
7214{
7216}
7217
7219{
7221}
7222
7224{
7225 bool isRatedBattleground = false; // NYI
7226 bool isArena = !isRatedBattleground;
7227
7228 // check USABLE attributes
7229 // USABLE takes precedence over NOT_USABLE
7231 return SPELL_CAST_OK;
7232
7234 return SPELL_CAST_OK;
7235
7236 // check NOT_USABLE attributes
7239
7242
7243 // check cooldowns
7244 uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
7245 if (isArena && spellCooldown > 10 * MINUTE * IN_MILLISECONDS) // not sure if still needed
7247
7248 if (isRatedBattleground && spellCooldown > 15 * MINUTE * IN_MILLISECONDS)
7250
7251 return SPELL_CAST_OK;
7252}
7253
7255{
7256 if (IsTriggered())
7257 return SPELL_CAST_OK;
7258
7259 if (Unit* unitCaster = m_caster->ToUnit())
7260 {
7261 if (!unitCaster->CanCastSpellWhileMoving(m_spellInfo))
7262 {
7264 {
7265 if (m_casttime > 0)
7267 return SPELL_FAILED_MOVING;
7268 }
7269 else if (getState() == SPELL_STATE_CHANNELING)
7271 return SPELL_FAILED_MOVING;
7272 }
7273 }
7274
7275 return SPELL_CAST_OK;
7276}
7277
7278int32 Spell::CalculateDamage(SpellEffectInfo const& spellEffectInfo, Unit const* target, float* var /*= nullptr*/) const
7279{
7280 bool needRecalculateBasePoints = !(m_spellValue->CustomBasePointsMask & (1 << spellEffectInfo.EffectIndex));
7281 return m_caster->CalculateSpellDamage(target, spellEffectInfo, needRecalculateBasePoints ? nullptr : &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex], var, m_castItemEntry, m_castItemLevel);
7282}
7283
7285{
7286 if (!target)
7287 return (CheckPetCast(target) == SPELL_CAST_OK);
7288
7289 ObjectGuid targetguid = target->GetGUID();
7290
7291 // check if target already has the same or a more powerful aura
7292 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7293 {
7294 if (!spellEffectInfo.IsAura())
7295 continue;
7296
7297 AuraType const& auraType = spellEffectInfo.ApplyAuraName;
7298 Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
7299 for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
7300 {
7301 if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
7302 return false;
7303
7304 switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
7305 {
7307 return false;
7309 if (GetCaster() == (*auraIt)->GetCaster())
7310 return false;
7311 break;
7312 case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
7314 if (abs(spellEffectInfo.CalcBaseValue(m_caster, target, 0, -1)) <= abs((*auraIt)->GetAmount()))
7315 return false;
7316 break;
7318 default:
7319 break;
7320 }
7321 }
7322 }
7323
7324 SpellCastResult result = CheckPetCast(target);
7325 if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
7326 {
7327 // do not check targets for ground-targeted spells (we target them on top of the intended target anyway)
7328 if (GetSpellInfo()->GetExplicitTargetMask() & TARGET_FLAG_DEST_LOCATION)
7329 return true;
7331 //check if among target units, our WANTED target is as well (->only self cast spells return false)
7332 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
7333 if (ihit->TargetGUID == targetguid)
7334 return true;
7335 }
7336 // either the cast failed or the intended target wouldn't be hit
7337 return false;
7338}
7339
7341{
7342 if (!m_targets.HasSrc())
7344}
7345
7347{
7348 if (!m_targets.HasDst())
7350}
7351
7353{
7354 // Don't check for instant cast spells
7355 if (!strict && m_casttime == 0)
7356 return SPELL_CAST_OK;
7357
7358 auto [minRange, maxRange] = GetMinMaxRange(strict);
7359
7360 // dont check max_range to strictly after cast
7362 maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
7363
7364 // get square values for sqr distance checks
7365 minRange *= minRange;
7366 maxRange *= maxRange;
7367
7368 Unit* target = m_targets.GetUnitTarget();
7369 if (target && target != m_caster)
7370 {
7371 if (m_caster->GetExactDistSq(target) > maxRange)
7373
7374 if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange)
7376
7377 if (m_caster->GetTypeId() == TYPEID_PLAYER &&
7378 (((m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
7379 && !m_caster->ToPlayer()->IsWithinBoundaryRadius(target)))
7381 }
7382
7383 if (GameObject* goTarget = m_targets.GetGOTarget())
7384 {
7385 if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
7387 }
7388
7389 if (m_targets.HasDst() && !m_targets.HasTraj())
7390 {
7391 if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange)
7393 if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange)
7395 }
7396
7397 return SPELL_CAST_OK;
7398}
7399
7401{
7402 // forward running only
7404 && !unit->IsWalking();
7405}
7406
7407std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
7408{
7409 float rangeMod = 0.0f;
7410 float minRange = 0.0f;
7411 float maxRange = 0.0f;
7412
7413 if (strict && m_spellInfo->IsNextMeleeSwingSpell())
7414 return { 0.0f, 100.0f };
7415
7416 Unit* unitCaster = m_caster->ToUnit();
7418 {
7419 Unit* target = m_targets.GetUnitTarget();
7421 {
7422 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
7423 if (unitCaster)
7424 rangeMod = unitCaster->GetMeleeRange(target ? target : unitCaster);
7425 }
7426 else
7427 {
7428 float meleeRange = 0.0f;
7430 {
7431 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
7432 if (unitCaster)
7433 meleeRange = unitCaster->GetMeleeRange(target ? target : unitCaster);
7434 }
7435
7436 minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
7437 maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
7438
7439 if (target || m_targets.GetCorpseTarget())
7440 {
7441 rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
7442
7443 if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
7444 minRange += rangeMod;
7445 }
7446 }
7447
7448 if (target && unitCaster && CanIncreaseRangeByMovement(target) && CanIncreaseRangeByMovement(unitCaster) &&
7450 rangeMod += 8.0f / 3.0f;
7451 }
7452
7454 if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
7455 maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
7456
7457 if (Player* modOwner = m_caster->GetSpellModOwner())
7458 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, maxRange, const_cast<Spell*>(this));
7459
7460 maxRange += rangeMod;
7461
7462 return { minRange, maxRange };
7463}
7464
7466{
7467 Unit* unitCaster = m_caster->ToUnit();
7468 if (!unitCaster)
7469 return SPELL_CAST_OK;
7470
7471 // item cast not used power
7472 if (m_CastItem)
7473 return SPELL_CAST_OK;
7474
7475 for (SpellPowerCost const& cost : m_powerCost)
7476 {
7477 // health as power used - need check health amount
7478 if (cost.Power == POWER_HEALTH)
7479 {
7480 if (int64(unitCaster->GetHealth()) <= cost.Amount)
7482 continue;
7483 }
7484 // Check valid power type
7485 if (cost.Power >= MAX_POWERS)
7486 {
7487 TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '{}'", cost.Power);
7488 return SPELL_FAILED_UNKNOWN;
7489 }
7490
7491 //check rune cost only if a spell has PowerType == POWER_RUNES
7492 if (cost.Power == POWER_RUNES)
7493 {
7494 SpellCastResult failReason = CheckRuneCost();
7495 if (failReason != SPELL_CAST_OK)
7496 return failReason;
7497
7498 continue;
7499 }
7500
7501 // Check power amount
7502 if (int32(unitCaster->GetPower(cost.Power)) < cost.Amount)
7503 return SPELL_FAILED_NO_POWER;
7504 }
7505
7506 return SPELL_CAST_OK;
7507}
7508
7509SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
7510{
7511 Player* player = m_caster->ToPlayer();
7512 if (!player)
7513 return SPELL_CAST_OK;
7514
7515 if (!m_CastItem)
7516 {
7517 if (!m_castItemGUID.IsEmpty())
7519 }
7520 else
7521 {
7522 uint32 itemid = m_CastItem->GetEntry();
7523 if (!player->HasItemCount(itemid))
7525
7526 ItemTemplate const* proto = m_CastItem->GetTemplate();
7527 if (!proto)
7529
7530 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
7531 if (itemEffect->Charges && m_CastItem->GetSpellCharges(itemEffect) == 0)
7533
7534 // consumable cast item checks
7536 {
7537 // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
7538 SpellCastResult failReason = SPELL_CAST_OK;
7539 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7540 {
7541 // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster
7542 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
7543 continue;
7544
7545 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
7546 {
7548 {
7550 continue;
7551 }
7552 else
7553 {
7554 failReason = SPELL_CAST_OK;
7555 break;
7556 }
7557 }
7558
7559 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
7560 if (spellEffectInfo.IsEffect(SPELL_EFFECT_ENERGIZE))
7561 {
7562 if (spellEffectInfo.MiscValue < 0 || spellEffectInfo.MiscValue >= int8(MAX_POWERS))
7563 {
7565 continue;
7566 }
7567
7568 Powers power = Powers(spellEffectInfo.MiscValue);
7570 {
7572 continue;
7573 }
7574 else
7575 {
7576 failReason = SPELL_CAST_OK;
7577 break;
7578 }
7579 }
7580 }
7581 if (failReason != SPELL_CAST_OK)
7582 return failReason;
7583 }
7584 }
7585
7586 // check target item
7588 {
7589 Item* item = m_targets.GetItemTarget();
7590 if (!item)
7592
7595 }
7596 // if not item target then required item must be equipped
7597 else
7598 {
7602 }
7603
7604 // do not take reagents for these item casts
7606 {
7608 // Not own traded item (in trader trade slot) requires reagents even if triggered spell
7609 if (!checkReagents)
7610 if (Item* targetItem = m_targets.GetItemTarget())
7611 if (targetItem->GetOwnerGUID() != player->GetGUID())
7612 checkReagents = true;
7613
7614 // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
7615 if (checkReagents)
7616 {
7617 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
7618 {
7619 if (m_spellInfo->Reagent[i] <= 0)
7620 continue;
7621
7622 uint32 itemid = m_spellInfo->Reagent[i];
7623 uint32 itemcount = m_spellInfo->ReagentCount[i];
7624
7625 // if CastItem is also spell reagent
7626 if (m_CastItem && m_CastItem->GetEntry() == itemid)
7627 {
7628 ItemTemplate const* proto = m_CastItem->GetTemplate();
7629 if (!proto)
7631
7632 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
7633 {
7634 // CastItem will be used up and does not count as reagent
7635 int32 charges = m_CastItem->GetSpellCharges(itemEffect);
7636 if (itemEffect->Charges < 0 && abs(charges) < 2)
7637 {
7638 ++itemcount;
7639 break;
7640 }
7641 }
7642 }
7643 if (!player->HasItemCount(itemid, itemcount))
7644 {
7645 if (param1)
7646 *param1 = itemid;
7647 return SPELL_FAILED_REAGENTS;
7648 }
7649 }
7650
7651 for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency)
7652 {
7653 if (!player->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount))
7654 {
7655 if (param1)
7656 *param1 = -1;
7657
7658 if (param2)
7659 *param2 = reagentsCurrency->CurrencyTypesID;
7660
7661 return SPELL_FAILED_REAGENTS;
7662 }
7663 }
7664 }
7665
7667 {
7668 // check totem-item requirements (items presence in inventory)
7669 for (int32 totem : m_spellInfo->Totem)
7670 {
7671 if (totem && !player->HasItemCount(totem))
7672 {
7673 if (param1)
7674 *param1 = totem;
7675 return SPELL_FAILED_TOTEMS;
7676 }
7677 }
7678
7679 // Check items for TotemCategory (items presence in inventory)
7680 for (int32 totemCategory : m_spellInfo->TotemCategory)
7681 {
7682 if (totemCategory && !player->HasItemTotemCategory(totemCategory))
7683 {
7684 if (param1)
7685 *param1 = totemCategory;
7687 }
7688 }
7689 }
7690 }
7691
7692 // special checks for spell effects
7693 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7694 {
7695 switch (spellEffectInfo.Effect)
7696 {
7699 {
7700 // m_targets.GetUnitTarget() means explicit cast, otherwise we dont check for possible equip error
7701 Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
7702 if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered())
7703 {
7704 // 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,
7705 // so we need to make sure there is at least one free space in the player's inventory
7706 if (spellEffectInfo.Effect == SPELL_EFFECT_CREATE_LOOT)
7708 {
7709 player->SendEquipError(EQUIP_ERR_INV_FULL, nullptr, nullptr, spellEffectInfo.ItemType);
7711 }
7712
7713 if (spellEffectInfo.ItemType)
7714 {
7715 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType);
7716 if (!itemTemplate)
7718
7719 uint32 createCount = std::clamp<uint32>(spellEffectInfo.CalcValue(), 1u, itemTemplate->GetMaxStackSize());
7720 ItemPosCountVec dest;
7721 InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, createCount);
7722 if (msg != EQUIP_ERR_OK)
7723 {
7725 if (!itemTemplate->GetItemLimitCategory())
7726 {
7727 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7729 }
7730 else
7731 {
7732 // Conjure Food/Water/Refreshment spells
7735 else if (!(target->ToPlayer()->HasItemCount(spellEffectInfo.ItemType)))
7736 {
7737 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7739 }
7740 else if (m_spellInfo->GetEffects().size() > EFFECT_1)
7742 .SetTriggeringSpell(this)); // move this to anywhere
7744 }
7745 }
7746 }
7747 }
7748 break;
7749 }
7751 if (spellEffectInfo.ItemType && m_targets.GetItemTarget()
7753 {
7754 // cannot enchant vellum for other player
7755 if (m_targets.GetItemTarget()->GetOwner() != player)
7757 // do not allow to enchant vellum from scroll made by vellum-prevent exploit
7760 ItemPosCountVec dest;
7761 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, 1);
7762 if (msg != EQUIP_ERR_OK)
7763 {
7764 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7766 }
7767 }
7768 [[fallthrough]];
7770 {
7771 Item* targetItem = m_targets.GetItemTarget();
7772 if (!targetItem)
7774
7775 // Apply item level restriction
7777 {
7778 uint32 requiredLevel = targetItem->GetRequiredLevel();
7779 if (!requiredLevel)
7780 requiredLevel = targetItem->GetItemLevel(targetItem->GetOwner());
7781
7782 if (requiredLevel < m_spellInfo->BaseLevel)
7783 return SPELL_FAILED_LOWLEVEL;
7784 }
7785 if ((m_CastItem || spellEffectInfo.IsEffect(SPELL_EFFECT_ENCHANT_ITEM_PRISMATIC))
7786 && m_spellInfo->MaxLevel > 0 && targetItem->GetItemLevel(targetItem->GetOwner()) > m_spellInfo->MaxLevel)
7788
7789 bool isItemUsable = false;
7790 for (ItemEffectEntry const* itemEffect : targetItem->GetEffects())
7791 {
7792 if (itemEffect->SpellID && itemEffect->TriggerType == ITEM_SPELLTRIGGER_ON_USE)
7793 {
7794 isItemUsable = true;
7795 break;
7796 }
7797 }
7798
7799 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(spellEffectInfo.MiscValue);
7800 // do not allow adding usable enchantments to items that have use effect already
7801 if (enchantEntry)
7802 {
7803 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
7804 {
7805 switch (enchantEntry->Effect[s])
7806 {
7808 if (isItemUsable)
7810 break;
7812 {
7813 uint32 numSockets = 0;
7814 for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket)
7815 if (targetItem->GetSocketColor(socket))
7816 ++numSockets;
7817
7818 if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
7820 break;
7821 }
7822 }
7823 }
7824 }
7825
7826 // Not allow enchant in trade slot for some enchant type
7827 if (targetItem->GetOwner() != player)
7828 {
7829 if (!enchantEntry)
7830 return SPELL_FAILED_ERROR;
7831 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
7833 }
7834 break;
7835 }
7837 {
7838 Item* item = m_targets.GetItemTarget();
7839 if (!item)
7841 // Not allow enchant in trade slot for some enchant type
7842 if (item->GetOwner() != player)
7843 {
7844 uint32 enchant_id = spellEffectInfo.MiscValue;
7845 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
7846 if (!enchantEntry)
7847 return SPELL_FAILED_ERROR;
7848 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
7850 }
7851
7852 // Apply item level restriction
7854 {
7855 uint32 requiredLevel = item->GetRequiredLevel();
7856 if (!requiredLevel)
7857 requiredLevel = item->GetItemLevel(item->GetOwner());
7858
7859 if (requiredLevel < m_spellInfo->BaseLevel)
7860 return SPELL_FAILED_LOWLEVEL;
7861 }
7862 if (m_CastItem && m_spellInfo->MaxLevel > 0 && item->GetItemLevel(item->GetOwner()) > m_spellInfo->MaxLevel)
7864 break;
7865 }
7867 // check item existence in effect code (not output errors at offhand hold item effect to main hand for example
7868 break;
7870 {
7871 Item const* item = m_targets.GetItemTarget();
7872 if (!item)
7874
7875 // prevent disenchanting in trade slot
7876 if (item->GetOwnerGUID() != player->GetGUID())
7878
7879 ItemTemplate const* itemProto = item->GetTemplate();
7880 if (!itemProto)
7882
7883 Optional<uint16> disenchantSkillRequired = item->GetDisenchantSkillRequired();
7884 if (!disenchantSkillRequired)
7886 if (disenchantSkillRequired > player->GetSkillValue(SKILL_ENCHANTING))
7888 break;
7889 }
7891 {
7892 Item* item = m_targets.GetItemTarget();
7893 if (!item)
7895 //ensure item is a prospectable ore
7898 //prevent prospecting in trade slot
7899 if (item->GetOwnerGUID() != player->GetGUID())
7901 //Check for enough skill in jewelcrafting
7902 uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7903 if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
7905 //make sure the player has the required ores in inventory
7906 if (item->GetCount() < 5)
7907 {
7908 if (param1 && param2)
7909 {
7910 *param1 = item->GetEntry();
7911 *param2 = 5;
7912 }
7914 }
7915
7918
7919 break;
7920 }
7922 {
7923 Item* item = m_targets.GetItemTarget();
7924 if (!item)
7926 //ensure item is a millable herb
7929 //prevent milling in trade slot
7930 if (item->GetOwnerGUID() != player->GetGUID())
7932 //Check for enough skill in inscription
7933 uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7934 if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
7936 //make sure the player has the required herbs in inventory
7937 if (item->GetCount() < 5)
7938 {
7939 if (param1 && param2)
7940 {
7941 *param1 = item->GetEntry();
7942 *param2 = 5;
7943 }
7945 }
7946
7949
7950 break;
7951 }
7954 {
7956 break;
7957
7958 Item* item = player->GetWeaponForAttack(m_attackType);
7959 if (!item || item->IsBroken())
7961
7962 switch (item->GetTemplate()->GetSubClass())
7963 {
7965 {
7966 uint32 const ammo = item->GetEntry();
7967 if (!player->HasItemCount(ammo))
7968 return SPELL_FAILED_NO_AMMO;
7969 break;
7970 }
7975 break;
7976 default:
7977 break;
7978 }
7979 break;
7980 }
7982 {
7983 uint32 itemId = spellEffectInfo.ItemType;
7984
7985 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
7986 if (!proto)
7988
7989 if (Item* item = player->GetItemByEntry(itemId))
7990 for (ItemEffectEntry const* itemEffect : item->GetEffects())
7991 if (itemEffect->Charges != 0 && item->GetSpellCharges(itemEffect) == itemEffect->Charges)
7993 break;
7994 }
7996 {
7997 Item const* item = m_targets.GetItemTarget();
7998 if (!item)
8000
8001 if (item->GetOwnerGUID() != m_caster->GetGUID())
8003
8004 AzeriteEmpoweredItem const* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem();
8005 if (!azeriteEmpoweredItem)
8007
8008 bool hasSelections = false;
8009 for (int32 tier = 0; tier < MAX_AZERITE_EMPOWERED_TIER; ++tier)
8010 {
8011 if (azeriteEmpoweredItem->GetSelectedAzeritePower(tier))
8012 {
8013 hasSelections = true;
8014 break;
8015 }
8016 }
8017
8018 if (!hasSelections)
8020
8021 if (!m_caster->ToPlayer()->HasEnoughMoney(azeriteEmpoweredItem->GetRespecCost()))
8023
8024 break;
8025 }
8026 default:
8027 break;
8028 }
8029 }
8030
8031 // check weapon presence in slots for main/offhand weapons
8033 {
8034 auto weaponCheck = [&](WeaponAttackType attackType) -> SpellCastResult
8035 {
8036 Item const* item = player->GetWeaponForAttack(attackType);
8037
8038 // skip spell if no weapon in slot or broken
8039 if (!item || item->IsBroken())
8041
8042 // skip spell if weapon not fit to triggered spell
8045
8046 return SPELL_CAST_OK;
8047 };
8048
8050 {
8051 SpellCastResult mainHandResult = weaponCheck(BASE_ATTACK);
8052 if (mainHandResult != SPELL_CAST_OK)
8053 return mainHandResult;
8054 }
8055
8057 {
8058 SpellCastResult offHandResult = weaponCheck(OFF_ATTACK);
8059 if (offHandResult != SPELL_CAST_OK)
8060 return offHandResult;
8061 }
8062 }
8063
8064 return SPELL_CAST_OK;
8065}
8066
8067void Spell::Delayed() // only called in DealDamage()
8068{
8069 Unit* unitCaster = m_caster->ToUnit();
8070 if (!unitCaster)
8071 return;
8072
8073 if (IsDelayableNoMore()) // Spells may only be delayed twice
8074 return;
8075
8076 //check pushback reduce
8077 int32 delaytime = 500; // spellcasting delay is normally 500ms
8078
8079 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
8080 if (Player* player = unitCaster->GetSpellModOwner())
8081 player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
8082 delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
8083 if (delayReduce >= 100)
8084 return;
8085
8086 AddPct(delaytime, -delayReduce);
8087
8088 if (m_timer + delaytime > m_casttime)
8089 {
8090 delaytime = m_casttime - m_timer;
8092 }
8093 else
8094 m_timer += delaytime;
8095
8097 spellDelayed.Caster = unitCaster->GetGUID();
8098 spellDelayed.ActualDelay = delaytime;
8099
8100 unitCaster->SendMessageToSet(spellDelayed.Write(), true);
8101}
8102
8104{
8105 Unit* unitCaster = m_caster->ToUnit();
8106 if (!unitCaster)
8107 return;
8108
8110 return;
8111
8112 if (IsDelayableNoMore()) // Spells may only be delayed twice
8113 return;
8114
8115 //check pushback reduce
8116 // should be affected by modifiers, not take the dbc duration.
8118
8119 int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
8120
8121 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
8122 if (Player* player = unitCaster->GetSpellModOwner())
8123 player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
8124 delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
8125 if (delayReduce >= 100)
8126 return;
8127
8128 AddPct(delaytime, -delayReduce);
8129
8130 if (m_timer <= delaytime)
8131 {
8132 delaytime = m_timer;
8133 m_timer = 0;
8134 }
8135 else
8136 m_timer -= delaytime;
8137
8138 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
8139 if (targetInfo.MissCondition == SPELL_MISS_NONE)
8140 if (Unit* unit = (unitCaster->GetGUID() == targetInfo.TargetGUID) ? unitCaster : ObjectAccessor::GetUnit(*unitCaster, targetInfo.TargetGUID))
8141 unit->DelayOwnedAuras(m_spellInfo->Id, m_originalCasterGUID, delaytime);
8142
8143 // partially interrupt persistent area auras
8144 if (DynamicObject* dynObj = unitCaster->GetDynObject(m_spellInfo->Id))
8145 dynObj->Delay(delaytime);
8146
8148}
8149
8151{
8152 return GetPowerTypeCostAmount(power).has_value();
8153}
8154
8156{
8157 auto itr = std::ranges::find(m_powerCost, power, &SpellPowerCost::Power);
8158 if (itr == m_powerCost.cend())
8159 return { };
8160
8161 return itr->Amount;
8162}
8163
8165{
8168 else
8169 {
8172 m_originalCaster = nullptr;
8173 }
8174
8176 {
8178 m_castItemLevel = -1;
8179 // cast item not found, somehow the item is no longer where we expected
8180 if (!m_CastItem)
8181 return false;
8182
8183 // check if the item is really the same, in case it has been wrapped for example
8185 return false;
8186
8188 }
8189
8191
8192 // further actions done only for dest targets
8193 if (!m_targets.HasDst())
8194 return true;
8195
8196 // cache last transport
8197 WorldObject* transport = nullptr;
8198
8199 // update effect destinations (in case of moved transport dest target)
8200 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8201 {
8202 SpellDestination& dest = m_destTargets[spellEffectInfo.EffectIndex];
8203 if (!dest._transportGUID)
8204 continue;
8205
8206 if (!transport || transport->GetGUID() != dest._transportGUID)
8208
8209 if (transport)
8210 {
8211 dest._position.Relocate(transport);
8213 }
8214 }
8215
8216 return true;
8217}
8218
8220{
8222 return CURRENT_MELEE_SPELL;
8223 else if (IsAutoRepeat())
8225 else if (m_spellInfo->IsChanneled())
8227
8228 return CURRENT_GENERIC_SPELL;
8229}
8230
8232{
8233 return m_caster->GetMap()->GetDifficultyID();
8234}
8235
8236bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEffectInfo, Position const* losPosition) const
8237{
8238 switch (spellEffectInfo.ApplyAuraName)
8239 {
8244 if (target->GetVehicleKit() && target->GetVehicleKit()->IsControllableVehicle())
8245 return false;
8246 if (target->IsMounted())
8247 return false;
8248 if (!target->GetCharmerGUID().IsEmpty())
8249 return false;
8250 if (int32 value = CalculateDamage(spellEffectInfo, target))
8251 if ((int32)target->GetLevelForTarget(m_caster) > value)
8252 return false;
8253 break;
8254 default:
8255 break;
8256 }
8257
8258 // check for ignore LOS on the effect itself
8260 return true;
8261
8262 // check if gameobject ignores LOS
8263 if (GameObject const* gobCaster = m_caster->ToGameObject())
8264 if (!gobCaster->GetGOInfo()->GetRequireLOS())
8265 return true;
8266
8267 // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
8269 return true;
8270
8272 //Check targets for LOS visibility
8273 switch (spellEffectInfo.Effect)
8274 {
8276 {
8278 {
8280 return true;
8281
8282 return false;
8283 }
8284
8286 if (!corpse)
8287 return false;
8288
8289 if (target->GetGUID() != corpse->GetOwnerGUID())
8290 return false;
8291
8293 return false;
8294
8295 if (!IsWithinLOS(m_caster, corpse, true, VMAP::ModelIgnoreFlags::M2))
8296 return false;
8297
8298 break;
8299 }
8300 default:
8301 {
8303 {
8304 // Get GO cast coordinates if original caster -> GO
8305 WorldObject* caster = nullptr;
8308 if (!caster)
8309 caster = m_caster;
8310
8311 if (target != m_caster && !IsWithinLOS(caster, target, true, VMAP::ModelIgnoreFlags::M2))
8312 return false;
8313 }
8314
8315 if (losPosition)
8316 if (!IsWithinLOS(target, *losPosition, VMAP::ModelIgnoreFlags::M2))
8317 return false;
8318 }
8319 }
8320
8321 return true;
8322}
8323
8324bool Spell::CheckEffectTarget(GameObject const* target, SpellEffectInfo const& spellEffectInfo) const
8325{
8326 switch (spellEffectInfo.Effect)
8327 {
8332 return false;
8333 break;
8334 default:
8335 break;
8336 }
8337
8338 return true;
8339}
8340
8341bool Spell::CheckEffectTarget(Item const* /*target*/, SpellEffectInfo const& /*spellEffectInfo*/) const
8342{
8343 return true;
8344}
8345
8347{
8350}
8351
8353{
8355}
8356
8358{
8360}
8361
8363{
8365}
8366
8368{
8369 return m_caster->IsUnit() && m_caster->ToUnit()->GetChannelSpellId() != 0;
8370}
8371
8373{
8375 return false;
8376
8378 return false;
8379
8380 return true;
8381}
8382
8384{
8386}
8387
8389{
8390 m_empower->IsReleasedByClient = release;
8391}
8392
8394{
8395 if (m_empower->IsReleased)
8396 return false;
8397
8398 if (!m_empower->IsReleasedByClient && m_timer)
8399 return false;
8400
8402 return passedTime >= m_empower->MinHoldTime;
8403}
8404
8406{
8413}
8414
8416{
8418}
8419
8420SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell)
8421{
8422}
8423
8425{
8427 m_Spell->cancel();
8428
8429 if (!m_Spell->IsDeletable())
8430 {
8431 TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.",
8432 (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id);
8433 ABORT();
8434 }
8435}
8436
8438{
8439 // update spell if it is not finished
8441 m_Spell->update(p_time);
8442
8443 // check spell state to process
8444 switch (m_Spell->getState())
8445 {
8447 {
8448 // spell was finished, check deletable state
8449 if (m_Spell->IsDeletable())
8450 {
8451 // check, if we do have unfinished triggered spells
8452 return true; // spell is deletable, finish event
8453 }
8454 // event will be re-added automatically at the end of routine)
8455 break;
8456 }
8458 {
8459 // first, check, if we have just started
8460 if (m_Spell->GetDelayStart() != 0)
8461 {
8462 // no, we aren't, do the typical update
8463 // check, if we have channeled spell on our hands
8464 /*
8465 if (m_Spell->m_spellInfo->IsChanneled())
8466 {
8467 // evented channeled spell is processed separately, cast once after delay, and not destroyed till finish
8468 // check, if we have casting anything else except this channeled spell and autorepeat
8469 if (m_Spell->GetCaster()->IsNonMeleeSpellCast(false, true, true))
8470 {
8471 // another non-melee non-delayed spell is cast now, abort
8472 m_Spell->cancel();
8473 }
8474 else
8475 {
8476 // Set last not triggered spell for apply spellmods
8477 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, true);
8478 // do the action (pass spell to channeling state)
8479 m_Spell->handle_immediate();
8480
8481 // And remove after effect handling
8482 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, false);
8483 }
8484 // event will be re-added automatically at the end of routine)
8485 }
8486 else
8487 */
8488 {
8489 // run the spell handler and think about what we can do next
8490 uint64 t_offset = e_time - m_Spell->GetDelayStart();
8491 uint64 n_offset = m_Spell->handle_delayed(t_offset);
8492 if (n_offset)
8493 {
8494 // re-add us to the queue
8495 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(m_Spell->GetDelayStart() + n_offset), false);
8496 return false; // event not complete
8497 }
8498 // event complete
8499 // finish update event will be re-added automatically at the end of routine)
8500 }
8501 }
8502 else
8503 {
8504 // delaying had just started, record the moment
8505 m_Spell->SetDelayStart(e_time);
8506 // handle effects on caster if the spell has travel time but also affects the caster in some way
8507 uint64 n_offset = m_Spell->handle_delayed(0);
8509 ASSERT(n_offset == uint64(std::floor(m_Spell->m_spellInfo->LaunchDelay * 1000.0f)));
8510 else
8511 ASSERT(n_offset == m_Spell->GetDelayMoment(), UI64FMTD " == " UI64FMTD, n_offset, m_Spell->GetDelayMoment());
8512 // re-plan the event for the delay moment
8513 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + n_offset), false);
8514 return false; // event not complete
8515 }
8516 break;
8517 }
8518 default:
8519 {
8520 // all other states
8521 // event will be re-added automatically at the end of routine)
8522 break;
8523 }
8524 }
8525
8526 // spell processing not complete, plan event on the next update interval
8527 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + 1), false);
8528 return false; // event not complete
8529}
8530
8532{
8533 // oops, the spell we try to do is aborted
8535 m_Spell->cancel();
8536}
8537
8539{
8540 return m_Spell->IsDeletable();
8541}
8542
8543bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
8544{
8545 if (target->IsAlive())
8548 return true;
8549 return false;
8550}
8551
8553{
8554 // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode
8555 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8556 {
8557 // don't do anything for empty effect
8558 if (!spellEffectInfo.IsEffect())
8559 continue;
8560
8561 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
8562 }
8563
8565
8566 for (TargetInfo& target : m_UniqueTargetInfo)
8567 PreprocessSpellLaunch(target);
8568
8569 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8570 {
8571 float multiplier = 1.0f;
8572 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
8573 multiplier = spellEffectInfo.CalcDamageMultiplier(m_originalCaster, this);
8574
8575 for (TargetInfo& target : m_UniqueTargetInfo)
8576 {
8577 uint32 mask = target.EffectMask;
8578 if (!(mask & (1 << spellEffectInfo.EffectIndex)))
8579 continue;
8580
8581 DoEffectOnLaunchTarget(target, multiplier, spellEffectInfo);
8582 }
8583 }
8584
8586}
8587
8589{
8590 Unit* targetUnit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
8591 if (!targetUnit)
8592 return;
8593
8594 // This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
8596 m_originalCaster->SetInCombatWith(targetUnit, true);
8597
8598 Unit* unit = nullptr;
8599 // In case spell hit target, do all effect on that target
8600 if (targetInfo.MissCondition == SPELL_MISS_NONE)
8601 unit = targetUnit;
8602 // In case spell reflect from target, do all effect on caster (if hit)
8603 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
8604 unit = m_caster->ToUnit();
8605
8606 if (!unit)
8607 return;
8608
8609 float critChance = m_spellValue->CriticalChance;
8610 if (m_originalCaster)
8611 {
8612 if (!critChance)
8614 critChance = unit->SpellCritChanceTaken(m_originalCaster, this, nullptr, m_spellSchoolMask, critChance, m_attackType);
8615 }
8616
8617 targetInfo.IsCrit = roll_chance_f(critChance);
8618}
8619
8620void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, SpellEffectInfo const& spellEffectInfo)
8621{
8622 Unit* unit = nullptr;
8623 // In case spell hit target, do all effect on that target
8625 unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
8626 // In case spell reflect from target, do all effect on caster (if hit)
8627 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
8628 unit = m_caster->ToUnit();
8629
8630 if (!unit)
8631 return;
8632
8633 m_damage = 0;
8634 m_healing = 0;
8635
8636 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
8637
8638 if (m_originalCaster && m_damage > 0)
8639 {
8640 bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
8642 {
8644
8646 {
8649
8650 // sqrt target cap damage calculation
8654 m_damage = m_damage * std::sqrt(float(m_spellInfo->SqrtDamageAndHealingDiminishing.MaxTargets) / std::min(AOE_DAMAGE_TARGET_CAP, targetCount));
8655
8656 // cap damage of player AOE
8657 if (targetCount > AOE_DAMAGE_TARGET_CAP)
8658 m_damage = m_damage * AOE_DAMAGE_TARGET_CAP / targetCount;
8659 }
8660 }
8661 }
8662
8663 if (m_originalCaster && m_healing > 0)
8664 {
8665 bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
8667 {
8669 {
8672
8673 // sqrt target cap healing calculation
8678 }
8679 }
8680 }
8681
8682 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
8683 {
8686
8687 m_damageMultipliers[spellEffectInfo.EffectIndex] *= multiplier;
8688 }
8689
8690 targetInfo.Damage += m_damage;
8691 targetInfo.Healing += m_healing;
8692}
8693
8695{
8696 Unit* unitCaster = m_caster->ToUnit();
8697 if (!unitCaster)
8698 return;
8699
8700 unitCaster->resetAttackTimer(BASE_ATTACK);
8701 if (unitCaster->haveOffhandWeapon())
8702 unitCaster->resetAttackTimer(OFF_ATTACK);
8703 unitCaster->resetAttackTimer(RANGED_ATTACK);
8704}
8705
8706SpellCastResult Spell::CanOpenLock(SpellEffectInfo const& effect, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
8707{
8708 if (!lockId) // possible case for GO and maybe for items.
8709 return SPELL_CAST_OK;
8710
8711 Unit const* unitCaster = m_caster->ToUnit();
8712 if (!unitCaster)
8714
8715 // Get LockInfo
8716 LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
8717
8718 if (!lockInfo)
8720
8721 bool reqKey = false; // some locks not have reqs
8722
8723 for (int j = 0; j < MAX_LOCK_CASE; ++j)
8724 {
8725 switch (lockInfo->Type[j])
8726 {
8727 // check key item (many fit cases can be)
8728 case LOCK_KEY_ITEM:
8729 if (lockInfo->Index[j] && m_CastItem && int32(m_CastItem->GetEntry()) == lockInfo->Index[j])
8730 return SPELL_CAST_OK;
8731 reqKey = true;
8732 break;
8733 // check key skill (only single first fit case can be)
8734 case LOCK_KEY_SKILL:
8735 {
8736 reqKey = true;
8737
8738 // wrong locktype, skip
8739 if (effect.MiscValue != lockInfo->Index[j])
8740 continue;
8741
8742 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
8743
8744 if (skillId != SKILL_NONE || lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
8745 {
8746 reqSkillValue = lockInfo->Skill[j];
8747
8748 // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
8749 skillValue = 0;
8750 if (!m_CastItem && unitCaster->GetTypeId() == TYPEID_PLAYER)
8751 skillValue = unitCaster->ToPlayer()->GetSkillValue(skillId);
8752 else if (lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
8753 skillValue = unitCaster->GetLevel() * 5;
8754
8755 // skill bonus provided by casting spell (mostly item spells)
8756 // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.)
8758 skillValue += effect.CalcValue();
8759
8760 if (skillValue < reqSkillValue)
8762 }
8763
8764 return SPELL_CAST_OK;
8765 }
8766 case LOCK_KEY_SPELL:
8767 if (m_spellInfo->Id == uint32(lockInfo->Index[j]))
8768 return SPELL_CAST_OK;
8769 reqKey = true;
8770 break;
8771 }
8772 }
8773
8774 if (reqKey)
8776
8777 return SPELL_CAST_OK;
8778}
8779
8781{
8783 {
8786 return;
8787 }
8788
8789 switch (value.Type)
8790 {
8793 break;
8796 break;
8798 m_spellValue->Duration = value.Value.I;
8799 break;
8802 break;
8805 break;
8807 m_spellValue->RadiusMod = value.Value.F;
8808 break;
8811 break;
8813 m_spellValue->DurationMul = value.Value.F / 100.0f;
8814 break;
8815 default:
8816 break;
8817 }
8818}
8819
8821{
8822}
8823
8825{
8827}
8828
8830{
8831 sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this);
8832 for (SpellScript* script : m_loadedScripts)
8833 {
8834 TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `{}` for spell `{}` is loaded now", script->GetScriptName(), m_spellInfo->Id);
8835 script->Register();
8836 }
8837}
8838
8840{
8841 for (SpellScript* script : m_loadedScripts)
8842 {
8843 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_PRECAST);
8844 script->OnPrecast();
8845 script->_FinishScriptCall();
8846 }
8847}
8848
8850{
8851 for (SpellScript* script : m_loadedScripts)
8852 {
8853 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST);
8854 for (SpellScript::CastHandler const& beforeCast : script->BeforeCast)
8855 beforeCast.Call(script);
8856
8857 script->_FinishScriptCall();
8858 }
8859}
8860
8862{
8863 for (SpellScript* script : m_loadedScripts)
8864 {
8865 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST);
8866 for (SpellScript::CastHandler const& onCast : script->OnCast)
8867 onCast.Call(script);
8868
8869 script->_FinishScriptCall();
8870 }
8871}
8872
8874{
8875 for (SpellScript* script : m_loadedScripts)
8876 {
8877 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST);
8878 for (SpellScript::CastHandler const& afterCast : script->AfterCast)
8879 afterCast.Call(script);
8880
8881 script->_FinishScriptCall();
8882 }
8883}
8884
8886{
8888 for (SpellScript* script : m_loadedScripts)
8889 {
8890 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST);
8891 for (SpellScript::CheckCastHandler const& checkCast : script->OnCheckCast)
8892 {
8893 SpellCastResult tempResult = checkCast.Call(script);
8894 if (retVal == SPELL_CAST_OK)
8895 retVal = tempResult;
8896 }
8897
8898 script->_FinishScriptCall();
8899 }
8900 return retVal;
8901}
8902
8904{
8905 for (SpellScript* script : m_loadedScripts)
8906 {
8907 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_CAST_TIME);
8908 castTime = script->CalcCastTime(castTime);
8909 script->_FinishScriptCall();
8910 }
8911 return castTime;
8912}
8913
8915{
8916 // execute script effect handler hooks and check if effects was prevented
8917 bool preventDefault = false;
8918 for (SpellScript* script : m_loadedScripts)
8919 {
8920 script->_InitHit();
8921
8923 SpellScriptHookType hookType;
8924 switch (mode)
8925 {
8927 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectLaunch.begin(), script->OnEffectLaunch.end());
8929 break;
8931 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectLaunchTarget.begin(), script->OnEffectLaunchTarget.end());
8933 break;
8935 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectHit.begin(), script->OnEffectHit.end());
8937 break;
8939 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectHitTarget.begin(), script->OnEffectHitTarget.end());
8941 break;
8942 default:
8943 ABORT();
8944 return false;
8945 }
8946 script->_PrepareScriptCall(hookType);
8947 for (SpellScript::EffectHandler const& effectHandler : effectHandlers)
8948 // effect execution can be prevented
8949 if (!script->_IsEffectPrevented(effIndex) && effectHandler.IsEffectAffected(m_spellInfo, effIndex))
8950 effectHandler.Call(script, effIndex);
8951
8952 if (!preventDefault)
8953 preventDefault = script->_IsDefaultEffectPrevented(effIndex);
8954
8955 script->_FinishScriptCall();
8956 }
8957 return preventDefault;
8958}
8959
8961{
8962 for (SpellScript* script : m_loadedScripts)
8963 {
8964 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
8965 for (SpellScript::EffectHandler const& onDispel : script->OnEffectSuccessfulDispel)
8966 onDispel.Call(script, effIndex);
8967
8968 script->_FinishScriptCall();
8969 }
8970}
8971
8973{
8974 for (SpellScript* script : m_loadedScripts)
8975 {
8976 script->_InitHit();
8977 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT);
8978 for (SpellScript::BeforeHitHandler const& beforeHit : script->BeforeHit)
8979 beforeHit.Call(script, missInfo);
8980
8981 script->_FinishScriptCall();
8982 }
8983}
8984
8986{
8987 for (SpellScript* script : m_loadedScripts)
8988 {
8989 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT);
8990 for (SpellScript::HitHandler const& onHit : script->OnHit)
8991 onHit.Call(script);
8992
8993 script->_FinishScriptCall();
8994 }
8995}
8996
8998{
8999 for (SpellScript* script : m_loadedScripts)
9000 {
9001 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT);
9002 for (SpellScript::HitHandler const& afterHit : script->AfterHit)
9003 afterHit.Call(script);
9004
9005 script->_FinishScriptCall();
9006 }
9007}
9008
9009void Spell::CallScriptCalcCritChanceHandlers(Unit const* victim, float& critChance)
9010{
9011 for (SpellScript* script : m_loadedScripts)
9012 {
9013 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE);
9014 for (SpellScript::OnCalcCritChanceHandler const& calcCritChance : script->OnCalcCritChance)
9015 calcCritChance.Call(script, victim, critChance);
9016
9017 script->_FinishScriptCall();
9018 }
9019}
9020
9021void Spell::CallScriptCalcDamageHandlers(SpellEffectInfo const& spellEffectInfo, Unit* victim, int32& damage, int32& flatMod, float& pctMod)
9022{
9023 for (SpellScript* script : m_loadedScripts)
9024 {
9025 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_DAMAGE);
9026 for (SpellScript::DamageAndHealingCalcHandler const& calcDamage : script->CalcDamage)
9027 calcDamage.Call(script, spellEffectInfo, victim, damage, flatMod, pctMod);
9028
9029 script->_FinishScriptCall();
9030 }
9031}
9032
9033void Spell::CallScriptCalcHealingHandlers(SpellEffectInfo const& spellEffectInfo, Unit* victim, int32& healing, int32& flatMod, float& pctMod)
9034{
9035 for (SpellScript* script : m_loadedScripts)
9036 {
9037 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_HEALING);
9038 for (SpellScript::DamageAndHealingCalcHandler const& calcHealing : script->CalcHealing)
9039 calcHealing.Call(script, spellEffectInfo, victim, healing, flatMod, pctMod);
9040
9041 script->_FinishScriptCall();
9042 }
9043}
9044
9045void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
9046{
9047 for (SpellScript* script : m_loadedScripts)
9048 {
9049 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT);
9050 for (SpellScript::ObjectAreaTargetSelectHandler const& objectAreaTargetSelect : script->OnObjectAreaTargetSelect)
9051 if (objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == objectAreaTargetSelect.GetTarget())
9052 objectAreaTargetSelect.Call(script, targets);
9053
9054 script->_FinishScriptCall();
9055 }
9056}
9057
9059{
9060 for (SpellScript* script : m_loadedScripts)
9061 {
9062 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT);
9063 for (SpellScript::ObjectTargetSelectHandler const& objectTargetSelect : script->OnObjectTargetSelect)
9064 if (objectTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == objectTargetSelect.GetTarget())
9065 objectTargetSelect.Call(script, target);
9066
9067 script->_FinishScriptCall();
9068 }
9069}
9070
9072{
9073 for (SpellScript* script : m_loadedScripts)
9074 {
9075 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT);
9076 for (SpellScript::DestinationTargetSelectHandler const& destinationTargetSelect : script->OnDestinationTargetSelect)
9077 if (destinationTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == destinationTargetSelect.GetTarget())
9078 destinationTargetSelect.Call(script, target);
9079
9080 script->_FinishScriptCall();
9081 }
9082}
9083
9084void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)
9085{
9086 for (SpellScript* script : m_loadedScripts)
9087 {
9088 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION);
9089 for (SpellScript::OnCalculateResistAbsorbHandler const& calculateResistAbsorb : script->OnCalculateResistAbsorb)
9090 calculateResistAbsorb.Call(script, damageInfo, resistAmount, absorbAmount);
9091
9092 script->_FinishScriptCall();
9093 }
9094}
9095
9097{
9098 for (SpellScript* script : m_loadedScripts)
9099 {
9100 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EMPOWER_STAGE_COMPLETED);
9101 for (SpellScript::EmpowerStageCompletedHandler const& empowerStageCompleted : script->OnEmpowerStageCompleted)
9102 empowerStageCompleted.Call(script, completedStagesCount);
9103
9104 script->_FinishScriptCall();
9105 }
9106}
9107
9109{
9110 for (SpellScript* script : m_loadedScripts)
9111 {
9112 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EMPOWER_COMPLETED);
9113 for (SpellScript::EmpowerStageCompletedHandler const& empowerStageCompleted : script->OnEmpowerCompleted)
9114 empowerStageCompleted.Call(script, completedStagesCount);
9115
9116 script->_FinishScriptCall();
9117 }
9118}
9119
9121{
9122 auto allEffectTargetScriptsAreShared = []<typename HookType>(HookList<HookType> const& hooks, SpellInfo const* spellInfo, uint32 effIndex, uint32 effIndexToCheck)
9123 {
9124 for (HookType const& hook : hooks)
9125 {
9126 if (!hook.IsEffectAffected(spellInfo, effIndex))
9127 continue;
9128
9129 bool otherEffectHasSameTargetFunction = std::ranges::any_of(hooks, [&](HookType const& other)
9130 {
9131 return other.IsEffectAffected(spellInfo, effIndexToCheck) && hook.HasSameTargetFunctionAs(other);
9132 });
9133 if (!otherEffectHasSameTargetFunction)
9134 return false;
9135 }
9136
9137 return true;
9138 };
9139
9140 for (SpellScript* script : m_loadedScripts)
9141 {
9142 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
9143 return false;
9144
9145 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
9146 return false;
9147
9148 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
9149 return false;
9150
9151 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
9152 return false;
9153 }
9154 return true;
9155}
9156
9157bool Spell::CanExecuteTriggersOnHit(Unit* unit, SpellInfo const* triggeredByAura /*= nullptr*/) const
9158{
9159 bool onlyOnTarget = (triggeredByAura && (triggeredByAura->HasAttribute(SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET)));
9160 if (!onlyOnTarget)
9161 return true;
9162
9163 // If triggeredByAura has SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET then it can only proc on either noncaster units...
9164 if (unit != m_caster)
9165 return true;
9166
9167 // ... or caster if it is the only target
9168 if (m_UniqueTargetInfo.size() == 1)
9169 return true;
9170
9171 return false;
9172}
9173
9175{
9176 Unit* unitCaster = m_caster->ToUnit();
9177 if (!unitCaster)
9178 return;
9179
9180 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
9181 // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
9182 // and to correctly calculate proc chance when combopoints are present
9183 Unit::AuraEffectList const& targetTriggers = unitCaster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
9184 for (AuraEffect const* aurEff : targetTriggers)
9185 {
9186 if (!aurEff->IsAffectingSpell(m_spellInfo))
9187 continue;
9188
9189 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo().TriggerSpell, GetCastDifficulty()))
9190 {
9191 // calculate the chance using spell base amount, because aura amount is not updated on combo-points change
9192 // this possibly needs fixing
9193 int32 auraBaseAmount = aurEff->GetBaseAmount();
9194 // proc chance is stored in effect amount
9195 int32 chance = unitCaster->CalculateSpellDamage(nullptr, aurEff->GetSpellEffectInfo(), &auraBaseAmount);
9196 chance *= aurEff->GetBase()->GetStackAmount();
9197
9198 // build trigger and add to the list
9199 m_hitTriggerSpells.emplace_back(spellInfo, aurEff->GetSpellInfo(), chance);
9200 }
9201 }
9202}
9203
9204// Global cooldowns management
9206{
9207 // Only players or controlled units have global cooldown
9208 if (caster->GetTypeId() != TYPEID_PLAYER && (caster->GetTypeId() != TYPEID_UNIT || !const_cast<WorldObject*>(caster)->ToCreature()->GetCharmInfo()))
9209 return false;
9210
9211 return true;
9212}
9213
9215{
9217 return false;
9218
9220}
9221
9223{
9225 return;
9226
9228 if (gcd == 0ms || !m_spellInfo->StartRecoveryCategory)
9229 return;
9230
9233 return;
9234
9235 constexpr Milliseconds MinGCD = 750ms;
9236 constexpr Milliseconds MaxGCD = 1500ms;
9237
9238 // Global cooldown can't leave range 1..1.5 secs
9239 // There are some spells (mostly not cast directly by player) that have < 1 sec and > 1.5 sec global cooldowns
9240 // but as tests show are not affected by any spell mods.
9241 if (gcd >= MinGCD && gcd <= MaxGCD)
9242 {
9243 // gcd modifier auras are applied only to own spells and only players have such mods
9244 if (Player* modOwner = m_caster->GetSpellModOwner())
9245 {
9246 int32 intGcd = gcd.count();
9247 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::StartCooldown, intGcd, this);
9248 gcd = Milliseconds(intGcd);
9249 }
9250
9251 bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
9255
9256 // Apply haste rating
9257 if (gcd > MinGCD && ((m_spellInfo->StartRecoveryCategory == 133 && !isMeleeOrRangedSpell)))
9258 {
9259 gcd = Milliseconds(int64(gcd.count() * m_caster->ToUnit()->m_unitData->ModSpellHaste));
9260 RoundToInterval(gcd, MinGCD, MaxGCD);
9261 }
9262
9264 {
9265 gcd = Milliseconds(int64(gcd.count() * m_caster->ToUnit()->m_unitData->ModHasteRegen));
9266 RoundToInterval(gcd, MinGCD, MaxGCD);
9267 }
9268 }
9269
9271}
9272
9274{
9276 return;
9277
9279 return;
9280
9281 // Cancel global cooldown when interrupting current cast
9283 return;
9284
9286}
9287
9288std::string Spell::GetDebugInfo() const
9289{
9290 std::stringstream sstr;
9291 sstr << std::boolalpha
9292 << "Id: " << GetSpellInfo()->Id << " Name: '" << (*GetSpellInfo()->SpellName)[sWorld->GetDefaultDbcLocale()] << "' OriginalCaster: " << m_originalCasterGUID.ToString()
9293 << " State: " << getState();
9294 return sstr.str();
9295}
9296
9298{
9299 return _spellEvent->GetSpellWeakPtr();
9300}
9301
9302bool Spell::IsWithinLOS(WorldObject const* source, WorldObject const* target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const
9303{
9305 return true;
9306
9308 return true;
9309
9310 if (target->IsCreature() && target->ToCreature()->CanIgnoreLineOfSightWhenCastingOnMe())
9311 return true;
9312
9313 WorldObject const* src = targetAsSourceLocation ? target : source;
9314 WorldObject const* dst = targetAsSourceLocation ? source : target;
9315 return src->IsWithinLOSInMap(dst, LINEOFSIGHT_ALL_CHECKS, ignoreFlags);
9316}
9317
9318bool Spell::IsWithinLOS(WorldObject const* source, Position const& target, VMAP::ModelIgnoreFlags ignoreFlags) const
9319{
9321 return true;
9322
9324 return true;
9325
9326 return source->IsWithinLOS(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), LINEOFSIGHT_ALL_CHECKS, ignoreFlags);
9327}
9328
9329void Spell::MovePosition(Position& pos, WorldObject const* from, float dist, float angle) const
9330{
9332 from->MovePosition(pos, dist, angle);
9333 else
9334 from->MovePositionToFirstCollision(pos, dist, angle);
9335}
9336
9337namespace Trinity
9338{
9339
9341 SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
9342 _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList), _objectType(objectType)
9343{
9344 if (condList)
9345 _condSrcInfo = std::make_unique<ConditionSourceInfo>(nullptr, caster);
9346}
9347
9349{
9350}
9351
9353{
9354 if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
9355 return false;
9356
9357 Unit* unitTarget = target->ToUnit();
9358 if (Corpse* corpseTarget = target->ToCorpse())
9359 {
9360 // use owner for party/assistance checks
9361 if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
9362 unitTarget = owner;
9363 else
9364 return false;
9365 }
9366
9367 Unit* refUnit = _referer->ToUnit();
9368 if (unitTarget)
9369 {
9370 // do only faction checks here
9371 switch (_targetSelectionType)
9372 {
9373 case TARGET_CHECK_ENEMY:
9374 if (unitTarget->IsTotem())
9375 return false;
9376 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9377 if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo))
9378 return false;
9379 break;
9380 case TARGET_CHECK_ALLY:
9381 if (unitTarget->IsTotem())
9382 return false;
9383 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9384 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9385 return false;
9386 break;
9387 case TARGET_CHECK_PARTY:
9388 if (!refUnit)
9389 return false;
9390 if (unitTarget->IsTotem())
9391 return false;
9392 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9393 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9394 return false;
9395 if (!refUnit->IsInPartyWith(unitTarget))
9396 return false;
9397 break;
9399 if (!refUnit)
9400 return false;
9401 if (refUnit->GetClass() != unitTarget->GetClass())
9402 return false;
9403 [[fallthrough]];
9404 case TARGET_CHECK_RAID:
9405 if (!refUnit)
9406 return false;
9407 if (unitTarget->IsTotem())
9408 return false;
9409 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9410 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9411 return false;
9412 if (!refUnit->IsInRaidWith(unitTarget))
9413 return false;
9414 break;
9416 if (!unitTarget->IsSummon())
9417 return false;
9418 if (unitTarget->ToTempSummon()->GetSummonerGUID() != _caster->GetGUID())
9419 return false;
9420 break;
9421 default:
9422 break;
9423 }
9424
9425 switch (_objectType)
9426 {
9430 if (unitTarget->IsAlive())
9431 return false;
9432 break;
9433 default:
9434 break;
9435 }
9436 }
9437
9438 if (!_condSrcInfo)
9439 return true;
9440 _condSrcInfo->mConditionTargets[0] = target;
9441 return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
9442}
9443
9445 SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9446 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(caster) { }
9447
9449{
9450 float dist = target->GetDistance(*_position);
9451 if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target))
9452 {
9453 _range = dist;
9454 return true;
9455 }
9456 return false;
9457}
9458
9460 WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType,
9461 WorldObjectSpellAreaTargetSearchReason searchReason /*= Area*/)
9462 : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList, objectType), _range(range), _position(position), _searchReason(searchReason) { }
9463
9465{
9466 if (GameObject* gameObjectTarget = target->ToGameObject())
9467 {
9468 // isInRange including the dimension of the GO
9469 bool isInRange = gameObjectTarget->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range);
9470 if (!isInRange)
9471 return false;
9472 }
9473 else
9474 {
9475 bool isInsideCylinder = target->IsWithinDist2d(_position, _range) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range;
9476 if (!isInsideCylinder)
9477 return false;
9478
9479 if (Unit* unitTarget = target->ToUnit())
9480 {
9481 switch (_searchReason)
9482 {
9484 if (!_spellInfo->HasAttribute(SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE) && unitTarget->GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity::AoETarget))
9485 return false;
9486 break;
9488 if (unitTarget->GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity::ChainTarget))
9489 return false;
9490 break;
9491 default:
9492 break;
9493 }
9494 }
9495 }
9496
9498}
9499
9500WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(Position const& coneSrc, float coneAngle, float lineWidth, float range, WorldObject* caster,
9501 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9502 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _coneSrc(coneSrc), _coneAngle(coneAngle), _lineWidth(lineWidth) { }
9503
9505{
9507 {
9508 if (_coneSrc.HasInArc(-std::abs(_coneAngle), target))
9509 return false;
9510 }
9512 {
9513 if (!_coneSrc.HasInLine(target, target->GetCombatReach(), _lineWidth))
9514 return false;
9515 }
9516 else
9517 {
9518 if (!_caster->IsUnit() || !_caster->ToUnit()->IsWithinBoundaryRadius(target->ToUnit()))
9519 // ConeAngle > 0 -> select targets in front
9520 // ConeAngle < 0 -> select targets in back
9521 if (_coneSrc.HasInArc(_coneAngle, target) != G3D::fuzzyGe(_coneAngle, 0.f))
9522 return false;
9523 }
9525}
9526
9527WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9528 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(position) { }
9529
9531{
9532 // return all targets on missile trajectory (0 - size of a missile)
9533 if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
9534 return false;
9535
9536 if (target->GetExactDist2d(_position) > _range)
9537 return false;
9538
9540}
9541
9542WorldObjectSpellLineTargetCheck::WorldObjectSpellLineTargetCheck(Position const* srcPosition, Position const* dstPosition, float lineWidth, float range, WorldObject* caster,
9543 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9544 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _position(*srcPosition), _lineWidth(lineWidth)
9545{
9546 if (dstPosition && *srcPosition != *dstPosition)
9547 _position.SetOrientation(srcPosition->GetAbsoluteAngle(dstPosition));
9548}
9549
9551{
9552 if (!_position.HasInLine(target, target->GetCombatReach(), _lineWidth))
9553 return false;
9554
9556}
9557
9558void SelectRandomInjuredTargets(std::list<WorldObject*>& targets, size_t maxTargets, bool prioritizePlayers, Unit const* prioritizeGroupMembersOf /*= nullptr*/)
9559{
9560 if (targets.size() <= maxTargets)
9561 return;
9562
9563 // Target priority states (bit indices)
9564 // higher value means lower selection priority
9565 // current list:
9566 // * injured player group members
9567 // * injured other players
9568 // * injured pets of group members
9569 // * injured other pets
9570 // * full health player group members
9571 // * full health other players
9572 // * full health pets of group members
9573 // * full health other pets
9574 enum
9575 {
9576 NOT_GROUPED,
9577 NOT_PLAYER,
9578 NOT_INJURED,
9579 END
9580 };
9581
9582 std::array<std::ptrdiff_t, 1 << END> countsByPriority = {};
9583 std::vector<std::pair<WorldObject*, int32>> tempTargets;
9584 tempTargets.resize(targets.size());
9585
9586 // categorize each target
9587 std::ranges::transform(targets, tempTargets.begin(), [&](WorldObject* target)
9588 {
9589 int32 negativePoints = 0;
9590 if (prioritizeGroupMembersOf && (!target->IsUnit() || target->ToUnit()->IsInRaidWith(prioritizeGroupMembersOf)))
9591 negativePoints |= 1 << NOT_GROUPED;
9592
9593 if (prioritizePlayers && !target->IsPlayer() && (!target->IsCreature() || !target->ToCreature()->IsTreatedAsRaidUnit()))
9594 negativePoints |= 1 << NOT_PLAYER;
9595
9596 if (!target->IsUnit() || target->ToUnit()->IsFullHealth())
9597 negativePoints |= 1 << NOT_INJURED;
9598
9599 ++countsByPriority[negativePoints];
9600 return std::make_pair(target, negativePoints);
9601 });
9602
9603 std::ranges::sort(tempTargets, {}, Trinity::TupleElement<1>);
9604
9605 std::size_t foundTargets = 0;
9606 for (std::ptrdiff_t countForPriority : countsByPriority)
9607 {
9608 if (foundTargets + countForPriority >= maxTargets)
9609 {
9610 // shuffle only the lower priority extras
9611 // example: our initial target list had 5 injured and 5 full health units and we want to select 7 targets
9612 // we always want to select 5 injured and 2 random full health ones
9613 Containers::RandomShuffle(tempTargets.begin() + foundTargets, tempTargets.begin() + foundTargets + countForPriority);
9614 break;
9615 }
9616
9617 foundTargets += countForPriority;
9618 }
9619
9620 targets.resize(maxTargets);
9621 std::ranges::transform(tempTargets.begin(), tempTargets.begin() + maxTargets, targets.begin(), Trinity::TupleElement<0>);
9622}
9623} //namespace Trinity
9624
9626{
9627 if (target)
9628 {
9629 if (Unit* unitTarget = target->ToUnit())
9630 {
9631 Targets.emplace();
9632 Targets->SetUnitTarget(unitTarget);
9633 }
9634 else if (GameObject* goTarget = target->ToGameObject())
9635 {
9636 Targets.emplace();
9637 Targets->SetGOTarget(goTarget);
9638 }
9639 // error when targeting anything other than units and gameobjects
9640 }
9641 else
9642 Targets.emplace(); // nullptr is allowed
9643}
9644
9651
9653{
9654 TriggeringSpell = triggeringSpell;
9655 if (triggeringSpell)
9656 {
9658 OriginalCastItemLevel = triggeringSpell->m_castItemLevel;
9659 if (!OriginalCastId)
9660 OriginalCastId = triggeringSpell->m_castId;
9661 }
9662 return *this;
9663}
9664
9665SpellCastVisual::operator UF::SpellCastVisual() const
9666{
9667 UF::SpellCastVisual visual;
9668 visual.SpellXSpellVisualID = SpellXSpellVisualID;
9669 visual.ScriptVisualID = ScriptVisualID;
9670 return visual;
9671}
9672
9673SpellCastVisual::operator WorldPackets::Spells::SpellCastVisual() const
9674{
9675 return { int32(SpellXSpellVisualID), int32(ScriptVisualID) };
9676}
#define sBattlefieldMgr
@ STATUS_WAIT_LEAVE
Definition: Battleground.h:168
@ STATUS_IN_PROGRESS
Definition: Battleground.h:167
@ IN_MILLISECONDS
Definition: Common.h:35
@ MINUTE
Definition: Common.h:29
#define M_PI
Definition: Common.h:115
std::vector< Condition > ConditionContainer
Definition: ConditionMgr.h:293
#define sConditionMgr
Definition: ConditionMgr.h:369
@ CONDITION_SOURCE_TYPE_SPELL
Definition: ConditionMgr.h:172
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)
#define sDB2Manager
Definition: DB2Stores.h:557
#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:233
@ ITEM_ENCHANTMENT_TYPE_USE_SPELL
Definition: DBCEnums.h:1062
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
Definition: DBCEnums.h:1063
Difficulty
Definition: DBCEnums.h:919
@ DIFFICULTY_NONE
Definition: DBCEnums.h:920
#define MAX_EFFECT_MASK
Definition: DBCEnums.h:2145
#define MAX_ITEM_PROTO_SOCKETS
Definition: DBCEnums.h:1043
@ LandTargetedSpellOnTarget
#define UI64FMTD
Definition: Define.h:132
#define TC_GAME_API
Definition: Define.h:129
uint8_t uint8
Definition: Define.h:150
int64_t int64
Definition: Define.h:143
int8_t int8
Definition: Define.h:146
int32_t int32
Definition: Define.h:144
uint64_t uint64
Definition: Define.h:147
uint32_t uint32
Definition: Define.h:148
@ 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:75
#define ABORT
Definition: Errors.h:74
#define ASSERT_NOTNULL(pointer)
Definition: Errors.h:84
#define ASSERT
Definition: Errors.h:68
@ 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 VMAP_INVALID_HEIGHT_VALUE
Definition: IVMapManager.h:44
#define sInstanceLockMgr
@ PRISMATIC_ENCHANTMENT_SLOT
Definition: ItemDefines.h:197
InventoryResult
Definition: ItemDefines.h:25
@ EQUIP_ERR_OK
Definition: ItemDefines.h:26
@ EQUIP_ERR_INV_FULL
Definition: ItemDefines.h:77
@ ITEM_CLASS_WEAPON
Definition: ItemTemplate.h:447
@ ITEM_CLASS_CONSUMABLE
Definition: ItemTemplate.h:445
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
Definition: ItemTemplate.h:525
@ ITEM_SUBCLASS_WEAPON_GUN
Definition: ItemTemplate.h:510
@ ITEM_SUBCLASS_WEAPON_BOW
Definition: ItemTemplate.h:509
@ ITEM_SUBCLASS_WEAPON_WAND
Definition: ItemTemplate.h:526
@ ITEM_SUBCLASS_WEAPON_THROWN
Definition: ItemTemplate.h:523
@ ITEM_SPELLTRIGGER_ON_USE
Definition: ItemTemplate.h:104
@ ITEM_FLAG_IS_MILLABLE
Definition: ItemTemplate.h:211
@ ITEM_FLAG_NO_REAGENT_COST
Definition: ItemTemplate.h:210
@ ITEM_FLAG_IS_PROSPECTABLE
Definition: ItemTemplate.h:200
@ INVTYPE_THROWN
Definition: ItemTemplate.h:415
@ INVTYPE_AMMO
Definition: ItemTemplate.h:414
@ ITEM_CHANGED
Definition: Item.h:54
#define TC_LOG_DEBUG(filterType__, message__,...)
Definition: Log.h:179
#define TC_LOG_ERROR(filterType__, message__,...)
Definition: Log.h:188
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:125
@ LIQUID_MAP_IN_WATER
Definition: MapDefines.h:129
@ LIQUID_MAP_WATER_WALK
Definition: MapDefines.h:128
@ TRANSFER_ABORT_NONE
Definition: Map.h:89
constexpr bool CanStopMovementForSpellCasting(MovementGeneratorType type)
#define EXTRA_CELL_SEARCH_RADIUS
Definition: ObjectDefines.h:47
#define DEFAULT_PLAYER_BOUNDING_RADIUS
Definition: ObjectDefines.h:39
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:45
@ TYPEID_UNIT
Definition: ObjectGuid.h:42
@ TYPEID_PLAYER
Definition: ObjectGuid.h:43
#define sObjectMgr
Definition: ObjectMgr.h:1985
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
@ PATHFIND_NOPATH
Definition: PathGenerator.h:47
@ PATHFIND_SHORT
Definition: PathGenerator.h:49
@ PATHFIND_INCOMPLETE
Definition: PathGenerator.h:46
#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:779
@ CHEAT_COOLDOWN
Definition: Player.h:994
@ CHEAT_POWER
Definition: Player.h:995
float frand(float min, float max)
Definition: Random.cpp:55
float rand_norm()
Definition: Random.cpp:75
bool roll_chance_f(float chance)
Definition: Random.h:53
bool roll_chance_i(int chance)
Definition: Random.h:59
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define sScriptMgr
Definition: ScriptMgr.h:1417
SpellEffIndex
Definition: SharedDefines.h:29
@ EFFECT_1
Definition: SharedDefines.h:31
@ 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
@ 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_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
Definition: SharedDefines.h:65
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
@ CORPSE_DYNFLAG_LOOTABLE
@ 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
SpellEffectName
@ 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
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_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_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)
@ 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
AuraType
@ 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_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_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_INTERFERE_TARGETTING
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_PERIODIC_TRIGGER_SPELL
@ SPELL_AURA_MOD_STUN
@ SPELLVALUE_AURA_STACK
Definition: SpellDefines.h:235
@ SPELLVALUE_BASE_POINT_END
Definition: SpellDefines.h:232
@ SPELLVALUE_PARENT_SPELL_TARGET_COUNT
Definition: SpellDefines.h:237
@ SPELLVALUE_PARENT_SPELL_TARGET_INDEX
Definition: SpellDefines.h:238
@ SPELLVALUE_MAX_TARGETS
Definition: SpellDefines.h:234
@ SPELLVALUE_BASE_POINT0
Definition: SpellDefines.h:199
@ SPELLVALUE_DURATION
Definition: SpellDefines.h:236
@ TARGET_FLAG_TRADE_ITEM
Definition: SpellDefines.h:307
@ TARGET_FLAG_GAMEOBJECT
Definition: SpellDefines.h:306
@ TARGET_FLAG_STRING
Definition: SpellDefines.h:308
@ TARGET_FLAG_UNIT_RAID
Definition: SpellDefines.h:297
@ TARGET_FLAG_UNIT_ENEMY
Definition: SpellDefines.h:302
@ TARGET_FLAG_CORPSE_ALLY
Definition: SpellDefines.h:310
@ TARGET_FLAG_ITEM
Definition: SpellDefines.h:299
@ TARGET_FLAG_UNIT_MINIPET
Definition: SpellDefines.h:311
@ TARGET_FLAG_GAMEOBJECT_ITEM
Definition: SpellDefines.h:309
@ TARGET_FLAG_DEST_LOCATION
Definition: SpellDefines.h:301
@ TARGET_FLAG_UNIT_ALLY
Definition: SpellDefines.h:303
@ TARGET_FLAG_SOURCE_LOCATION
Definition: SpellDefines.h:300
@ TARGET_FLAG_ITEM_MASK
Definition: SpellDefines.h:326
@ TARGET_FLAG_UNIT
Definition: SpellDefines.h:296
@ TARGET_FLAG_UNIT_MASK
Definition: SpellDefines.h:322
@ TARGET_FLAG_CORPSE_ENEMY
Definition: SpellDefines.h:304
@ TARGET_FLAG_CORPSE_MASK
Definition: SpellDefines.h:325
@ TARGET_FLAG_GAMEOBJECT_MASK
Definition: SpellDefines.h:324
@ TARGET_FLAG_UNIT_PARTY
Definition: SpellDefines.h:298
TriggerCastFlags
Definition: SpellDefines.h:256
@ TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT
Will ignore equipped item requirements.
Definition: SpellDefines.h:284
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:277
@ TRIGGERED_DONT_RESET_PERIODIC_TIMER
Will allow periodic aura timers to keep ticking (instead of resetting)
Definition: SpellDefines.h:275
@ TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
Will ignore Spell and Category cooldowns.
Definition: SpellDefines.h:259
@ TRIGGERED_CAST_DIRECTLY
In Spell::prepare, will be cast directly without setting containers for executed spell.
Definition: SpellDefines.h:265
@ TRIGGERED_IGNORE_TARGET_CHECK
Will ignore most target checks (mostly DBC target checks)
Definition: SpellDefines.h:285
@ TRIGGERED_IGNORE_CASTER_AURASTATE
Will ignore caster aura states including combat requirements and death state.
Definition: SpellDefines.h:286
@ TRIGGERED_IGNORE_CAST_IN_PROGRESS
Will not check if a current cast is in progress.
Definition: SpellDefines.h:263
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
Definition: SpellDefines.h:271
@ TRIGGERED_IGNORE_SHAPESHIFT
Will ignore shapeshift checks.
Definition: SpellDefines.h:268
@ TRIGGERED_IGNORE_POWER_COST
Will ignore power and reagent cost.
Definition: SpellDefines.h:260
@ TRIGGERED_IGNORE_CAST_ITEM
Will not take away cast item or update related achievement criteria.
Definition: SpellDefines.h:261
@ TRIGGERED_IGNORE_REAGENT_COST
Will ignore reagent cost.
Definition: SpellDefines.h:266
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
Definition: SpellDefines.h:258
@ TRIGGERED_DISALLOW_PROC_EVENTS
Disallows proc events from triggered spell (default)
Definition: SpellDefines.h:270
@ TRIGGERED_IGNORE_CASTER_AURAS
Will ignore caster aura restrictions or requirements.
Definition: SpellDefines.h:274
@ TRIGGERED_DONT_REPORT_CAST_ERROR
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
Definition: SpellDefines.h:276
@ TRIGGERED_IGNORE_CAST_TIME
Will always be instantly cast.
Definition: SpellDefines.h:264
@ TRIGGERED_IS_TRIGGERED_MASK
Will be recognized by Spell::IsTriggered as triggered.
Definition: SpellDefines.h:278
@ TRIGGERED_IGNORE_SET_FACING
Will not adjust facing to target (if any)
Definition: SpellDefines.h:267
@ SPELLVALUE_DURATION_PCT
Definition: SpellDefines.h:247
@ SPELLVALUE_RADIUS_MOD
Definition: SpellDefines.h:245
@ SPELLVALUE_CRIT_CHANCE
Definition: SpellDefines.h:246
@ SPELL_FACING_FLAG_INFRONT
Definition: SpellDefines.h:252
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
Definition: SpellInfo.cpp:42
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:346
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE
Definition: SpellMgr.h:345
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition: SpellMgr.h:344
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition: SpellMgr.h:347
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition: SpellMgr.h:348
#define sSpellMgr
Definition: SpellMgr.h:811
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
Definition: SpellScript.h:219
@ SPELL_SCRIPT_HOOK_AFTER_CAST
Definition: SpellScript.h:235
@ SPELL_SCRIPT_HOOK_EFFECT_HIT
Definition: SpellScript.h:222
@ SPELL_SCRIPT_HOOK_AFTER_HIT
Definition: SpellScript.h:227
@ SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL
Definition: SpellScript.h:224
@ SPELL_SCRIPT_HOOK_CALC_HEALING
Definition: SpellScript.h:238
@ SPELL_SCRIPT_HOOK_EFFECT_LAUNCH
Definition: SpellScript.h:220
@ SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT
Definition: SpellScript.h:228
@ SPELL_SCRIPT_HOOK_BEFORE_HIT
Definition: SpellScript.h:225
@ SPELL_SCRIPT_HOOK_CALC_DAMAGE
Definition: SpellScript.h:237
@ SPELL_SCRIPT_HOOK_CHECK_CAST
Definition: SpellScript.h:231
@ SPELL_SCRIPT_HOOK_EFFECT_LAUNCH_TARGET
Definition: SpellScript.h:221
@ SPELL_SCRIPT_HOOK_CALC_CAST_TIME
Definition: SpellScript.h:240
@ SPELL_SCRIPT_HOOK_EMPOWER_STAGE_COMPLETED
Definition: SpellScript.h:241
@ SPELL_SCRIPT_HOOK_EMPOWER_COMPLETED
Definition: SpellScript.h:242
@ SPELL_SCRIPT_HOOK_HIT
Definition: SpellScript.h:226
@ SPELL_SCRIPT_HOOK_BEFORE_CAST
Definition: SpellScript.h:232
@ SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION
Definition: SpellScript.h:234
@ SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT
Definition: SpellScript.h:230
@ SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT
Definition: SpellScript.h:229
@ SPELL_SCRIPT_HOOK_EFFECT_HIT_TARGET
Definition: SpellScript.h:223
@ SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE
Definition: SpellScript.h:236
@ SPELL_SCRIPT_HOOK_ON_CAST
Definition: SpellScript.h:233
@ SPELL_SCRIPT_HOOK_ON_PRECAST
Definition: SpellScript.h:239
bool CanHaveGlobalCooldown(WorldObject const *caster)
Definition: Spell.cpp:9205
void FillSpellCastFailedArgs(T &packet, ObjectGuid castId, SpellInfo const *spellInfo, SpellCastResult result, SpellCustomErrors customError, int32 *param1, int32 *param2, Player *caster)
Definition: Spell.cpp:4476
float tangent(float x)
Definition: Spell.cpp:1852
static std::pair< int32, SpellHealPredictionType > CalcPredictedHealing(SpellInfo const *spellInfo, Unit const *unitCaster, Unit *target, uint32 castItemEntry, int32 castItemLevel, Spell *spell, bool withPeriodic)
Definition: Spell.cpp:5066
NonDefaultConstructible< SpellEffectHandlerFn > SpellEffectHandlers[TOTAL_SPELL_EFFECTS]
#define SPELL_EMPOWER_HARDCODED_GCD
Definition: Spell.h:86
@ SPELL_CAST_SOURCE_NORMAL
Definition: Spell.h:153
@ SPELL_RANGE_MELEE
Definition: Spell.h:172
@ SPELL_RANGE_RANGED
Definition: Spell.h:173
#define MAX_SPELL_RANGE_TOLERANCE
Definition: Spell.h:82
@ CAST_FLAG_EX_IGNORE_COOLDOWN
Definition: Spell.h:137
SpellEffectHandleMode
Definition: Spell.h:250
@ SPELL_EFFECT_HANDLE_LAUNCH_TARGET
Definition: Spell.h:252
@ SPELL_EFFECT_HANDLE_LAUNCH
Definition: Spell.h:251
@ SPELL_EFFECT_HANDLE_HIT
Definition: Spell.h:253
@ SPELL_EFFECT_HANDLE_HIT_TARGET
Definition: Spell.h:254
#define AOE_DAMAGE_TARGET_CAP
Definition: Spell.h:84
SpellState
Definition: Spell.h:240
@ SPELL_STATE_CHANNELING
Definition: Spell.h:244
@ SPELL_STATE_NULL
Definition: Spell.h:241
@ SPELL_STATE_FINISHED
Definition: Spell.h:245
@ SPELL_STATE_PREPARING
Definition: Spell.h:242
@ SPELL_STATE_LAUNCHED
Definition: Spell.h:243
@ SPELL_STATE_IDLE
Definition: Spell.h:246
static const uint32 SPELL_INTERRUPT_NONPLAYER
Definition: Spell.h:259
@ CAST_FLAG_ADJUST_MISSILE
Definition: Spell.h:108
@ CAST_FLAG_HEAL_PREDICTION
Definition: Spell.h:121
@ CAST_FLAG_UNKNOWN_9
Definition: Spell.h:99
@ CAST_FLAG_NO_GCD
Definition: Spell.h:109
@ CAST_FLAG_PROJECTILE
Definition: Spell.h:96
@ CAST_FLAG_POWER_LEFT_SELF
Definition: Spell.h:102
@ CAST_FLAG_HAS_TRAJECTORY
Definition: Spell.h:92
@ CAST_FLAG_RUNE_LIST
Definition: Spell.h:112
@ CAST_FLAG_PENDING
Definition: Spell.h:91
@ CAST_FLAG_IMMUNITY
Definition: Spell.h:117
#define TRAJECTORY_MISSILE_SIZE
Definition: Spell.h:83
#define SPELL_EMPOWER_HOLD_TIME_AT_MAX
Definition: Spell.h:85
SpellHealPredictionType
Definition: Spell.h:162
@ SPELL_HEAL_PREDICTION_TARGET_AND_BEACON
Definition: Spell.h:165
@ SPELL_HEAL_PREDICTION_TARGET
Definition: Spell.h:163
@ SPELL_HEAL_PREDICTION_TARGET_PARTY
Definition: Spell.h:166
@ SPELL_HEAL_PREDICTION_TARGET_AND_CASTER
Definition: Spell.h:164
uint32 getMSTime()
Definition: Timer.h:33
@ TRADE_SLOT_NONTRADED
Definition: TradeData.h:27
@ UNIT_FLAG2_ALLOW_CHEAT_SPELLS
Definition: UnitDefines.h:235
@ UNIT_FLAG2_NO_ACTIONS
Definition: UnitDefines.h:240
@ UNIT_STAND_STATE_STAND
Definition: UnitDefines.h:42
@ MOVEMENTFLAG_FORWARD
Definition: UnitDefines.h:386
@ MOVEMENTFLAG_NONE
Definition: UnitDefines.h:385
@ MOVEMENTFLAG_STRAFE_LEFT
Definition: UnitDefines.h:388
@ MOVEMENTFLAG_BACKWARD
Definition: UnitDefines.h:387
@ MOVEMENTFLAG_FALLING
Definition: UnitDefines.h:397
@ MOVEMENTFLAG_STRAFE_RIGHT
Definition: UnitDefines.h:389
@ DIRECT_DAMAGE
Definition: UnitDefines.h:155
@ NODAMAGE
Definition: UnitDefines.h:159
@ SPELL_DIRECT_DAMAGE
Definition: UnitDefines.h:156
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:185
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:168
@ UNIT_FLAG_POSSESSED
Definition: UnitDefines.h:191
@ UNIT_FLAG_IMMUNE
Definition: UnitDefines.h:198
@ UNIT_FLAG_PACIFIED
Definition: UnitDefines.h:184
@ UNIT_FLAG_CONFUSED
Definition: UnitDefines.h:189
@ UNIT_FLAG_FLEEING
Definition: UnitDefines.h:190
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:170
@ UNIT_FLAG_SKINNABLE
Definition: UnitDefines.h:193
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition: Unit.cpp:10175
@ UNIT_MASK_PUPPET
Definition: Unit.h:359
@ JUST_DIED
Definition: Unit.h:250
CurrentSpellTypes
Definition: Unit.h:592
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:595
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:594
@ CURRENT_MELEE_SPELL
Definition: Unit.h:593
@ CURRENT_AUTOREPEAT_SPELL
Definition: Unit.h:596
@ UNIT_STATE_ATTACK_PLAYER
Definition: Unit.h:272
@ UNIT_STATE_ROOT
Definition: Unit.h:268
@ UNIT_STATE_CASTING
Definition: Unit.h:273
@ 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:870
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:526
T CalculatePct(T base, U pct)
Definition: Util.h:72
SpellInfo const * GetSpellInfo() const
bool IsPeriodic() const
Aura * GetBase() const
UnitAura * ToUnitAura()
Definition: SpellAuras.h:302
int32 GetMaxDuration() const
Definition: SpellAuras.h:171
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
Definition: SpellAuras.cpp:349
int32 GetCastItemLevel() const
Definition: SpellAuras.h:145
Trinity::IteratorPair< DBStorageIterator< AuraEffect * > > GetAuraEffects()
Definition: SpellAuras.h:316
int32 GetDuration() const
Definition: SpellAuras.h:176
int32 CalcMaxDuration() const
Definition: SpellAuras.h:173
void SetDuration(int32 duration, bool withMods=false)
Definition: SpellAuras.cpp:926
ObjectGuid GetCastItemGUID() const
Definition: SpellAuras.h:143
uint32 GetEffectMask() const
void SetMaxDuration(int32 duration)
Definition: SpellAuras.h:172
static uint32 BuildEffectMaskForOwner(SpellInfo const *spellProto, uint32 availableEffectMask, WorldObject *owner)
Definition: SpellAuras.cpp:319
bool IsPassive() const
uint32 GetSelectedAzeritePower(int32 tier) const
virtual void Abort(uint64)
virtual bool IsDeletable() const
virtual bool Execute(uint64, uint32)
BattlePet * GetPet(ObjectGuid guid)
bool HasJournalLock() const
Definition: BattlePetMgr.h:201
bool CanFlyIn()
Return if we can use mount in battlefield.
Definition: Battlefield.h:276
bool HasHeirloom(uint32 itemId) const
void InheritCombatStatesFrom(Unit const *who)
Definition: Corpse.h:53
ObjectGuid GetOwnerGUID() const override
Definition: Corpse.h:98
virtual void SpellHitTarget(WorldObject *, SpellInfo const *)
Definition: CreatureAI.h:133
bool CanIgnoreLineOfSightWhenCastingOnMe() const
Definition: Creature.h:234
Loot * GetLootForPlayer(Player const *player) const override
Definition: Creature.cpp:1413
void SetSpellFocus(Spell const *focusSpell, WorldObject const *target)
Definition: Creature.cpp:3519
CreatureAI * AI() const
Definition: Creature.h:228
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 *)
Definition: GameObjectAI.h:108
virtual void SpellHitTarget(WorldObject *, SpellInfo const *)
Definition: GameObjectAI.h:111
GameObjectTemplate const * GetGOInfo() const
Definition: GameObject.h:202
GameObjectAI * AI() const
Definition: GameObject.h:383
GameobjectTypes GetGoType() const
Definition: GameObject.h:281
Definition: Guild.h:329
Definition: Util.h:451
Definition: Item.h:170
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition: Item.cpp:1204
std::span< ItemEffectEntry const *const > GetEffects() const
Definition: Item.h:356
uint32 GetSocketColor(uint32 index) const
Definition: Item.h:345
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition: Item.h:298
bool IsVellum() const
Definition: Item.h:335
bool IsLocked() const
Definition: Item.h:251
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1179
bool IsPotion() const
Definition: Item.h:334
bool IsBroken() const
Definition: Item.h:257
Optional< uint16 > GetDisenchantSkillRequired() const
Definition: Item.cpp:2374
void SetSpellCharges(ItemEffectEntry const *effect, int32 value)
Definition: Item.cpp:591
Player * GetOwner() const
Definition: Item.cpp:1184
ObjectGuid GetOwnerGUID() const
Definition: Item.h:188
uint32 GetDisplayId(Player const *owner) const
Definition: Item.cpp:2426
uint32 GetItemLevel(Player const *owner) const
Definition: Item.cpp:2275
uint32 GetCount() const
Definition: Item.h:273
AzeriteEmpoweredItem * ToAzeriteEmpoweredItem()
Definition: Item.h:245
int32 GetRequiredLevel() const
Definition: Item.cpp:2829
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition: Item.cpp:1425
int32 GetSpellCharges(ItemEffectEntry const *effect=nullptr) const
Definition: Item.cpp:582
bool HaveLootFor(uint32 loot_id) const
Definition: LootMgr.h:94
Definition: Map.h:223
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition: Map.cpp:2527
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:1698
bool IsBattleground() const
Definition: Map.cpp:3311
ObjectGuid::LowType GenerateLowGuid()
Definition: Map.h:553
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3504
Difficulty GetDifficultyID() const
Definition: Map.h:358
InstanceMap * ToInstanceMap()
Definition: Map.h:488
MovementGeneratorType GetCurrentMovementGeneratorType() const
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
static std::string_view GetTypeName(HighGuid high)
Definition: ObjectGuid.cpp:749
bool IsAnyTypeGameObject() const
Definition: ObjectGuid.h:337
bool IsCorpse() const
Definition: ObjectGuid.h:334
bool IsEmpty() const
Definition: ObjectGuid.h:322
bool IsUnit() const
Definition: ObjectGuid.h:330
std::string ToString() const
Definition: ObjectGuid.cpp:757
bool IsGameObject() const
Definition: ObjectGuid.h:332
static ObjectGuid const TradeItem
Definition: ObjectGuid.h:277
void Clear()
Definition: ObjectGuid.h:289
Definition: Object.h:186
static Creature * ToCreature(Object *o)
Definition: Object.h:255
bool IsPlayer() const
Definition: Object.h:248
static Unit * ToUnit(Object *o)
Definition: Object.h:261
Player * ToPlayer()
Definition: Object.h:251
static GameObject * ToGameObject(Object *o)
Definition: Object.h:267
bool IsInWorld() const
Definition: Object.h:190
bool HasDynamicFlag(uint32 flag) const
Definition: Object.h:204
bool IsCorpse() const
Definition: Object.h:272
bool IsUnit() const
Definition: Object.h:260
TypeID GetTypeId() const
Definition: Object.h:209
uint32 GetEntry() const
Definition: Object.h:197
bool IsCreature() const
Definition: Object.h:254
static Corpse * ToCorpse(Object *o)
Definition: Object.h:273
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:195
static Player * ToPlayer(Object *o)
Definition: Object.h:249
std::array< Optional< PetInfo >, MAX_ACTIVE_PETS > ActivePets
Definition: PetDefines.h:169
Definition: Pet.h:40
Player * GetOwner() const
Definition: Pet.cpp:1801
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:1092
static PhaseShift const & GetAlwaysVisiblePhaseShift()
ChrSpecialization GetPrimarySpecialization() const
Definition: Player.h:1933
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition: Player.cpp:13179
void SetSpellModTakingSpell(Spell *spell, bool apply)
Definition: Player.cpp:22794
bool Satisfy(AccessRequirement const *ar, uint32 target_map, TransferAbortParams *params=nullptr, bool report=false)
Definition: Player.cpp:19965
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2153
bool HasItemFitToSpellRequirements(SpellInfo const *spellInfo, Item const *ignoreItem=nullptr) const
Definition: Player.cpp:25890
ObjectGuid GetSummonedBattlePetGUID() const
Definition: Player.h:2925
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition: Player.cpp:1601
void SetRuneCooldown(uint8 index, uint32 cooldown)
Definition: Player.cpp:26781
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6319
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6047
void UpdatePotionCooldown(Spell *spell=nullptr)
Definition: Player.cpp:23803
bool CanTameExoticPets() const
Definition: Player.h:2408
uint32 GetRuneBaseCooldown() const
Definition: Player.cpp:26759
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition: Player.cpp:9938
bool HasCurrency(uint32 id, uint32 amount) const
Definition: Player.cpp:7471
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition: Player.cpp:26638
bool InBattleground() const
Definition: Player.h:2497
Item * GetItemByEntry(uint32 entry, ItemSearchLocation where=ItemSearchLocation::Default) const
Definition: Player.cpp:12517
std::vector< uint32 > const & GetGlyphs(uint8 spec) const
Definition: Player.h:1969
PetStable * GetPetStable()
Definition: Player.h:1292
bool IsLoading() const override
Definition: Player.cpp:17779
Pet * GetPet() const
Definition: Player.cpp:21830
Guild * GetGuild()
Definition: Player.cpp:30000
bool HasItemTotemCategory(uint32 TotemCategory) const
Definition: Player.cpp:10095
uint8 GetRunesState() const
Definition: Player.cpp:26754
bool GetCommandStatus(uint32 command) const
Definition: Player.h:1276
bool HasSummonPending() const
Definition: Player.cpp:25748
WorldSession * GetSession() const
Definition: Player.h:2196
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition: Player.cpp:8696
bool CanNoReagentCast(SpellInfo const *spellInfo) const
Definition: Player.cpp:25955
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition: Player.cpp:12209
uint32 GetRuneCooldown(uint8 index) const
Definition: Player.h:2746
void SendTameFailure(PetTameResult result)
Definition: Player.cpp:21988
Battleground * GetBattleground() const
Definition: Player.cpp:25401
TradeData * GetTradeData() const
Definition: Player.h:1582
uint32 GetFreeInventorySlotCount(EnumFlag< ItemSearchLocation > location=ItemSearchLocation::Inventory) const
Definition: Player.cpp:9496
bool IsGameMaster() const
Definition: Player.h:1248
void RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Definition: Player.cpp:7311
uint8 GetActiveTalentGroup() const
Definition: Player.h:1935
Player * GetSelectedPlayer() const
Definition: Player.cpp:24582
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition: Player.cpp:9691
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3791
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9636
void UpdatePvP(bool state, bool override=false)
Definition: Player.cpp:23789
Spell * m_spellModTakingSpell
Definition: Player.h:2775
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition: Player.cpp:10082
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1832
ProcReflectDelayed(Unit *owner, ObjectGuid casterGuid)
Definition: Spell.cpp:2383
bool Execute(uint64, uint32) override
Definition: Spell.cpp:2385
ObjectGuid _casterGuid
Definition: Spell.cpp:2403
void SetPitch(float pitch)
Definition: SpellDefines.h:405
SpellDestination const * GetSrc() const
Definition: Spell.cpp:294
void SetItemTarget(Item *item)
Definition: Spell.cpp:265
void RemoveObjectTarget()
Definition: Spell.cpp:258
ObjectGuid m_objectTargetGUID
Definition: SpellDefines.h:424
WorldObject * GetObjectTarget() const
Definition: Spell.cpp:248
ObjectGuid GetUnitTargetGUID() const
Definition: Spell.cpp:180
void ModDst(Position const &pos)
Definition: Spell.cpp:373
GameObject * GetGOTarget() const
Definition: Spell.cpp:214
void SetTradeItemTarget(Player *caster)
Definition: Spell.cpp:276
SpellDestination m_dst
Definition: SpellDefines.h:429
bool HasSrc() const
Definition: Spell.cpp:390
bool HasTraj() const
Definition: SpellDefines.h:402
Corpse * GetCorpseTarget() const
Definition: Spell.cpp:240
void SetDst(float x, float y, float z, float orientation, uint32 mapId=MAPID_INVALID)
Definition: Spell.cpp:343
void SetSpeed(float speed)
Definition: SpellDefines.h:407
void SetSrc(float x, float y, float z)
Definition: Spell.cpp:304
void SetTargetFlag(SpellCastTargetFlags flag)
Definition: SpellDefines.h:357
SpellDestination const * GetDst() const
Definition: Spell.cpp:333
void SetGOTarget(GameObject *target)
Definition: Spell.cpp:222
std::string m_strTarget
Definition: SpellDefines.h:432
void UpdateTradeSlotItem()
Definition: Spell.cpp:285
SpellDestination m_src
Definition: SpellDefines.h:428
ObjectGuid GetCorpseTargetGUID() const
Definition: Spell.cpp:232
ObjectGuid GetObjectTargetGUID() const
Definition: Spell.cpp:253
void SetUnitTarget(Unit *target)
Definition: Spell.cpp:196
bool HasDst() const
Definition: Spell.cpp:395
ObjectGuid GetItemTargetGUID() const
Definition: SpellDefines.h:374
WorldObject * m_objectTarget
Definition: SpellDefines.h:420
Item * GetItemTarget() const
Definition: SpellDefines.h:375
uint32 GetTargetMask() const
Definition: SpellDefines.h:354
uint32 GetItemTargetEntry() const
Definition: SpellDefines.h:376
Unit * GetUnitTarget() const
Definition: Spell.cpp:188
ObjectGuid m_itemTargetGUID
Definition: SpellDefines.h:425
float GetSpeedXY() const
Definition: SpellDefines.h:410
float GetDist2d() const
Definition: SpellDefines.h:409
uint32 m_itemTargetEntry
Definition: SpellDefines.h:426
void Update(WorldObject *caster)
Definition: Spell.cpp:400
void ModSrc(Position const &pos)
Definition: Spell.cpp:322
void RemoveDst()
Definition: Spell.cpp:385
void Write(WorldPackets::Spells::SpellTargetData &data)
Definition: Spell.cpp:146
void RemoveSrc()
Definition: Spell.cpp:328
float GetPitch() const
Definition: SpellDefines.h:404
Position const * GetSrcPos() const
Definition: Spell.cpp:299
ObjectGuid GetGOTargetGUID() const
Definition: Spell.cpp:206
WorldLocation const * GetDstPos() const
Definition: Spell.cpp:338
float PositionFacing
Definition: SpellInfo.h:226
bool HasRadius(SpellTargetIndex targetIndex) const
Definition: SpellInfo.cpp:665
AuraType ApplyAuraName
Definition: SpellInfo.h:215
int32 CalcValue(WorldObject const *caster=nullptr, int32 const *basePoints=nullptr, Unit const *target=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
Definition: SpellInfo.cpp:496
uint32 TriggerSpell
Definition: SpellInfo.h:233
uint32 GetMissingTargetMask(bool srcSet=false, bool dstSet=false, uint32 mask=0) const
Definition: SpellInfo.cpp:761
float CalcRadius(WorldObject *caster=nullptr, SpellTargetIndex targetIndex=SpellTargetIndex::TargetA, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:678
Optional< std::pair< float, float > > CalcRadiusBounds(WorldObject *caster, SpellTargetIndex targetIndex, Spell *spell) const
Definition: SpellInfo.cpp:723
bool IsAreaAuraEffect() const
Definition: SpellInfo.cpp:477
SpellEffectName Effect
Definition: SpellInfo.h:214
std::shared_ptr< std::vector< Condition > > ImplicitTargetConditions
Definition: SpellInfo.h:236
bool IsEffect() const
Definition: SpellInfo.cpp:452
bool IsTargetingArea() const
Definition: SpellInfo.cpp:472
int32 ChainTargets
Definition: SpellInfo.h:231
SpellEffectImplicitTargetTypes GetImplicitTargetType() const
Definition: SpellInfo.cpp:785
EnumFlag< SpellEffectAttributes > EffectAttributes
Definition: SpellInfo.h:237
SpellEffIndex EffectIndex
Definition: SpellInfo.h:213
SpellImplicitTargetInfo TargetA
Definition: SpellInfo.h:227
SpellImplicitTargetInfo TargetB
Definition: SpellInfo.h:228
~SpellEvent()
Definition: Spell.cpp:8424
bool IsDeletable() const override
Definition: Spell.cpp:8538
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:8531
Trinity::unique_weak_ptr< Spell > GetSpellWeakPtr() const
Definition: Spell.cpp:465
SpellEvent(Spell *spell)
Definition: Spell.cpp:8420
bool Execute(uint64 e_time, uint32 p_time) override
Definition: Spell.cpp:8437
Spell const * GetSpell() const
Definition: Spell.cpp:464
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)
void CancelGlobalCooldown(SpellInfo const *spellInfo)
void HandleCooldowns(SpellInfo const *spellInfo, Item const *item, Spell *spell=nullptr)
bool HasCooldown(SpellInfo const *spellInfo, uint32 itemId=0) const
SpellTargetCheckTypes GetCheckType() const
Definition: SpellInfo.cpp:96
SpellTargetReferenceTypes GetReferenceType() const
Definition: SpellInfo.cpp:86
SpellTargetSelectionCategories GetSelectionCategory() const
Definition: SpellInfo.cpp:81
SpellTargetObjectTypes GetObjectType() const
Definition: SpellInfo.cpp:91
float CalcDirectionAngle() const
Definition: SpellInfo.cpp:106
Targets GetTarget() const
Definition: SpellInfo.cpp:133
uint32 RequiresSpellFocus
Definition: SpellInfo.h:349
uint32 MaxLevel
Definition: SpellInfo.h:380
uint32 SpellLevel
Definition: SpellInfo.h:382
std::array< int32, MAX_SPELL_TOTEMS > Totem
Definition: SpellInfo.h:389
uint32 GetMaxTicks() const
Definition: SpellInfo.cpp:3900
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition: SpellInfo.h:391
uint32 PreventionType
Definition: SpellInfo.h:409
uint32 CasterAuraSpell
Definition: SpellInfo.h:355
float Width
Definition: SpellInfo.h:403
Optional< SpellPowerCost > CalcPowerCost(Powers powerType, bool optionalCost, WorldObject const *caster, SpellSchoolMask schoolMask, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3947
float GetMaxRange(bool positive=false, WorldObject *caster=nullptr, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3845
bool HasEffect(SpellEffectName effect) const
Definition: SpellInfo.cpp:1463
SpellCastResult CheckShapeshift(uint32 form) const
Definition: SpellInfo.cpp:2018
std::array< uint16, MAX_SPELL_TOTEMS > TotemCategory
Definition: SpellInfo.h:390
uint64 GetAllEffectsMechanicMask() const
Definition: SpellInfo.cpp:2542
bool IsRequiringDeadTarget() const
Definition: SpellInfo.cpp:1740
uint32 const Id
Definition: SpellInfo.h:322
int32 NumNonDiminishedTargets
Definition: SpellInfo.h:430
uint64 GetMechanicImmunityMask(Unit const *caster) const
Definition: SpellInfo.cpp:3821
std::vector< Milliseconds > EmpowerStageThresholds
Definition: SpellInfo.h:414
std::array< int16, MAX_SPELL_REAGENTS > ReagentCount
Definition: SpellInfo.h:392
bool IsCooldownStartedOnEvent() const
Definition: SpellInfo.cpp:1726
EnumFlag< SpellAuraInterruptFlags > ChannelInterruptFlags
Definition: SpellInfo.h:372
bool IsPassive() const
Definition: SpellInfo.cpp:1664
uint32 StackAmount
Definition: SpellInfo.h:388
::Difficulty const Difficulty
Definition: SpellInfo.h:323
SpellRangeEntry const * RangeEntry
Definition: SpellInfo.h:385
uint32 CalcCastTime(Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3882
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const *player=nullptr) const
Definition: SpellInfo.cpp:2067
uint32 GetRecoveryTime() const
Definition: SpellInfo.cpp:3942
DiminishingReturnsType GetDiminishingReturnsGroupType() const
Definition: SpellInfo.cpp:3364
uint64 GetAllowedMechanicMask() const
Definition: SpellInfo.cpp:3816
bool HasHitDelay() const
Definition: SpellInfo.cpp:1833
uint32 ExcludeCasterAuraState
Definition: SpellInfo.h:353
float Speed
Definition: SpellInfo.h:386
float GetMinRange(bool positive=false) const
Definition: SpellInfo.cpp:3838
int32 GetMaxDuration() const
Definition: SpellInfo.cpp:3875
int32 EquippedItemClass
Definition: SpellInfo.h:394
bool HasInitialAggro() const
Definition: SpellInfo.cpp:1828
DiminishingGroup GetDiminishingReturnsGroupForSpell() const
Definition: SpellInfo.cpp:3359
uint32 SchoolMask
Definition: SpellInfo.h:411
uint32 CasterAuraState
Definition: SpellInfo.h:351
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
Definition: SpellInfo.cpp:2236
EnumFlag< SpellInterruptFlags > InterruptFlags
Definition: SpellInfo.h:369
flag128 SpellFamilyFlags
Definition: SpellInfo.h:407
bool IsAllowingDeadTarget() const
Definition: SpellInfo.cpp:1745
float LaunchDelay
Definition: SpellInfo.h:387
WeaponAttackType GetAttackType() const
Definition: SpellInfo.cpp:1838
SpellSchoolMask GetSchoolMask() const
Definition: SpellInfo.cpp:2537
std::vector< SpellReagentsCurrencyEntry const * > ReagentsCurrency
Definition: SpellInfo.h:393
bool IsChanneled() const
Definition: SpellInfo.cpp:1796
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
bool IsNextMeleeSwingSpell() const
Definition: SpellInfo.cpp:1806
struct SpellInfo::@327 SqrtDamageAndHealingDiminishing
uint32 ChargeCategoryId
Definition: SpellInfo.h:412
bool SpellCancelsAuraEffect(AuraEffect const *aurEff) const
Definition: SpellInfo.cpp:3798
uint32 IconFileDataId
Definition: SpellInfo.h:397
uint32 MaxAffectedTargets
Definition: SpellInfo.h:405
int32 GetDuration() const
Definition: SpellInfo.cpp:3868
SpellCastResult CheckVehicle(Unit const *caster) const
Definition: SpellInfo.cpp:2467
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition: SpellInfo.h:581
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:580
int32 EquippedItemSubClassMask
Definition: SpellInfo.h:395
bool IsEmpowerSpell() const
Definition: SpellInfo.cpp:1823
uint32 GetExplicitTargetMask() const
Definition: SpellInfo.cpp:2605
uint32 FacingCasterFlags
Definition: SpellInfo.h:350
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
Definition: SpellInfo.cpp:2431
uint32 StartRecoveryTime
Definition: SpellInfo.h:367
LocalizedString const * SpellName
Definition: SpellInfo.h:401
bool NeedsExplicitUnitTarget() const
Definition: SpellInfo.cpp:1623
EnumFlag< SpellAuraInterruptFlags2 > ChannelInterruptFlags2
Definition: SpellInfo.h:373
AuraType ExcludeCasterAuraType
Definition: SpellInfo.h:361
bool IsPositive() const
Definition: SpellInfo.cpp:1786
bool IsAutoRepeatRangedSpell() const
Definition: SpellInfo.cpp:1818
bool IsMoveAllowedChannel() const
Definition: SpellInfo.cpp:1801
uint32 DmgClass
Definition: SpellInfo.h:408
AuraType CasterAuraType
Definition: SpellInfo.h:359
uint32 ExcludeCasterAuraSpell
Definition: SpellInfo.h:357
bool HasAura(AuraType aura) const
Definition: SpellInfo.cpp:1472
bool IsTargetingArea() const
Definition: SpellInfo.cpp:1614
uint32 StartRecoveryCategory
Definition: SpellInfo.h:366
int32 MaxTargets
Definition: SpellInfo.h:429
uint32 CategoryId
Definition: SpellInfo.h:324
float ConeAngle
Definition: SpellInfo.h:402
uint32 SpellFamilyName
Definition: SpellInfo.h:406
bool IsPositiveEffect(uint8 effIndex) const
Definition: SpellInfo.cpp:1791
bool CanBeUsedInCombat(Unit const *caster) const
Definition: SpellInfo.cpp:1780
bool IsEffectAffected(SpellInfo const *spellInfo, uint8 effIndex) const
void Call(SpellScript *spellScript, SpellMissInfo missInfo) const
Definition: SpellScript.h:414
void Call(SpellScript *spellScript) const
Definition: SpellScript.h:278
SpellCastResult Call(SpellScript *spellScript) const
Definition: SpellScript.h:330
void Call(SpellScript *spellScript, SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &damageOrHealing, int32 &flatMod, float &pctMod) const
Definition: SpellScript.h:739
void Call(SpellScript *spellScript, SpellDestination &target) const
Definition: SpellScript.h:687
void Call(SpellScript *spellScript, SpellEffIndex effIndex) const
Definition: SpellScript.h:380
void Call(SpellScript *spellScript, int32 completedStagesCount) const
Definition: SpellScript.h:825
void Call(SpellScript *spellScript) const
Definition: SpellScript.h:448
void Call(SpellScript *spellScript, std::list< WorldObject * > &targets) const
Definition: SpellScript.h:571
void Call(SpellScript *spellScript, WorldObject *&target) const
Definition: SpellScript.h:629
void Call(SpellScript *spellScript, Unit const *victim, float &critChance) const
Definition: SpellScript.h:500
void Call(SpellScript *spellScript, DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount) const
Definition: SpellScript.h:791
uint16 GetTarget() const
Definition: SpellScript.h:520
Definition: Spell.h:262
SpellState getState() const
Definition: Spell.h:528
int32 CalculateDamage(SpellEffectInfo const &spellEffectInfo, Unit const *target, float *var=nullptr) const
Definition: Spell.cpp:7278
void CheckDst()
Definition: Spell.cpp:7346
void SelectImplicitTargetObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1793
SpellInfo const * GetSpellInfo() const
Definition: Spell.h:671
float m_damageMultipliers[MAX_SPELL_EFFECTS]
Definition: Spell.h:763
SpellCastResult CheckItems(int32 *param1, int32 *param2) const
Definition: Spell.cpp:7509
void ExecuteLogEffectSummonObject(SpellEffectName effect, WorldObject *obj)
Definition: Spell.cpp:5240
bool m_fromClient
Definition: Spell.h:584
void CallScriptAfterCastHandlers()
Definition: Spell.cpp:8873
std::vector< SpellPowerCost > m_powerCost
Definition: Spell.h:726
uint32 m_castFlagsEx
Definition: Spell.h:585
void AddCorpseTarget(Corpse *target, uint32 effectMask)
Definition: Spell.cpp:2594
void RefundRunePower()
Definition: Spell.cpp:5680
uint64 CalculateDelayMomentForDst(float launchDelay) const
Definition: Spell.cpp:821
GameObject * SearchSpellFocus()
Definition: Spell.cpp:2318
bool CheckSpellCancelsStun(int32 *param1) const
Definition: Spell.cpp:7190
std::vector< SpellScript * > m_loadedScripts
Definition: Spell.h:923
GameObject * gameObjTarget
Definition: Spell.h:768
std::pair< float, float > GetMinMaxRange(bool strict) const
Definition: Spell.cpp:7407
void PrepareTriggersExecutedOnHit()
Definition: Spell.cpp:9174
SpellMissInfo targetMissInfo
Definition: Spell.h:772
bool m_referencedFromCurrentSpell
Definition: Spell.h:760
bool m_canReflect
Definition: Spell.h:729
void PreprocessSpellLaunch(TargetInfo &targetInfo)
Definition: Spell.cpp:8588
void UpdateDelayMomentForUnitTarget(Unit *unit, uint64 hitDelay)
Definition: Spell.cpp:859
bool CheckSpellCancelsNoActions(int32 *param1) const
Definition: Spell.cpp:7218
bool HasPowerTypeCost(Powers power) const
Definition: Spell.cpp:8150
Unit * m_originalCaster
Definition: Spell.h:720
void LoadScripts()
Definition: Spell.cpp:8829
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction &healPrediction, bool withPeriodic)
Definition: Spell.cpp:5112
void SelectImplicitTrajTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1864
DynObjAura * _dynObjAura
Definition: Spell.h:779
void RefundPower()
Definition: Spell.cpp:5587
void ExecuteLogEffectUnsummonObject(SpellEffectName effect, WorldObject *obj)
Definition: Spell.cpp:5248
uint32 m_channelTargetEffectMask
Definition: Spell.h:844
void ExecuteLogEffectResurrect(SpellEffectName effect, Unit *target)
Definition: Spell.cpp:5256
void cast(bool skipCheck=false)
Definition: Spell.cpp:3656
void ExecuteLogEffectDestroyItem(SpellEffectName effect, uint32 entry)
Definition: Spell.cpp:5232
void SendChannelStart(uint32 duration)
Definition: Spell.cpp:5322
void ExecuteLogEffectOpenLock(SpellEffectName effect, Object *obj)
Definition: Spell.cpp:5216
uint64 m_delayStart
Definition: Spell.h:754
int64 GetCorpseTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2692
SpellCastTargets m_targets
Definition: Spell.h:621
void SelectImplicitNearbyTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1067
static bool CanIncreaseRangeByMovement(Unit const *unit)
Definition: Spell.cpp:7400
std::unique_ptr< PathGenerator > m_preGeneratedPath
Definition: Spell.h:964
Difficulty GetCastDifficulty() const
Definition: Spell.cpp:8231
void CallScriptBeforeHitHandlers(SpellMissInfo missInfo)
Definition: Spell.cpp:8972
void SelectEffectImplicitTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 &processedEffectMask)
Definition: Spell.cpp:886
SpellCastResult CheckRuneCost() const
Definition: Spell.cpp:5626
void CallScriptCalcDamageHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &damage, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:9021
void SelectExplicitTargets()
Definition: Spell.cpp:681
void handle_immediate()
Definition: Spell.cpp:3996
void SendSpellGo()
Definition: Spell.cpp:4866
int32 m_procChainLength
Definition: Spell.h:962
SpellCastResult CanOpenLock(SpellEffectInfo const &effect, uint32 lockid, SkillType &skillid, int32 &reqSkillValue, int32 &skillValue)
Definition: Spell.cpp:8706
void DoTriggersOnSpellHit(Unit *unit)
Definition: Spell.cpp:3301
TriggerCastFlags _triggeredCastFlags
Definition: Spell.h:956
bool IsAutoRepeat() const
Definition: Spell.h:631
int32 damage
Definition: Spell.h:771
void HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, Corpse *pCorpseTarget, SpellEffectInfo const &spellEffectInfo, SpellEffectHandleMode mode)
Definition: Spell.cpp:5800
void prepareDataForTriggerSystem()
Definition: Spell.cpp:2327
void SearchAreaTargets(std::list< WorldObject * > &targets, SpellEffectInfo const &spellEffectInfo, float range, Position const *position, WorldObject *referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, Trinity::WorldObjectSpellAreaTargetSearchReason searchReason)
Definition: Spell.cpp:2194
SpellEffectHandleMode effectHandleMode
Definition: Spell.h:774
void TakeReagents()
Definition: Spell.cpp:5693
bool IsValidDeadOrAliveTarget(Unit const *target) const
Definition: Spell.cpp:8543
int32 m_channeledDuration
Definition: Spell.h:728
SpellCastResult CheckMovement() const
Definition: Spell.cpp:7254
std::unique_ptr< EmpowerData > m_empower
Definition: Spell.h:751
void DoProcessTargetContainer(Container &targetContainer)
Definition: Spell.cpp:3982
bool IsNeedSendToClient() const
Definition: Spell.cpp:8405
WorldObject * SearchNearbyTarget(SpellEffectInfo const &spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const *condList=nullptr)
Definition: Spell.cpp:2180
bool IsIgnoringCooldowns() const
Definition: Spell.cpp:8352
void SelectImplicitDestDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition: Spell.cpp:1676
uint32 Id
Definition: Spell.h:604
std::vector< TargetInfo > m_UniqueTargetInfo
Definition: Spell.h:843
SpellDestination m_destTargets[MAX_SPELL_EFFECTS]
Definition: Spell.h:875
void _handle_finish_phase()
Definition: Spell.cpp:4211
void UpdateDelayMomentForDst(uint64 hitDelay)
Definition: Spell.cpp:851
bool CanExecuteTriggersOnHit(Unit *unit, SpellInfo const *triggeredByAura=nullptr) const
Definition: Spell.cpp:9157
void PrepareTargetProcessing()
Definition: Spell.cpp:8820
Trinity::unique_weak_ptr< Spell > GetWeakPtr() const
Definition: Spell.cpp:9297
void SetExecutedCurrently(bool yes)
Definition: Spell.h:653
void AddUnitTarget(Unit *target, uint32 effectMask, bool checkIfValid=true, bool implicit=true, Position const *losPosition=nullptr)
Definition: Spell.cpp:2406
void SendSpellStart()
Definition: Spell.cpp:4759
bool IsEmpowerSpell() const
Definition: Spell.h:642
ObjectGuid m_originalCastId
Definition: Spell.h:583
uint8 m_delayAtDamageCount
Definition: Spell.h:733
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition: Spell.cpp:5818
ProcFlagsSpellType m_procSpellType
Definition: Spell.h:794
uint64 m_delayMoment
Definition: Spell.h:755
void ExecuteLogEffectExtraAttacks(SpellEffectName effect, Unit *victim, uint32 numAttacks)
Definition: Spell.cpp:5186
WeaponAttackType m_attackType
Definition: Spell.h:724
void ExecuteLogEffectTakeTargetPower(SpellEffectName effect, Unit *target, Powers powerType, uint32 points, float amplitude)
Definition: Spell.cpp:5174
void _cast(bool skipCheck=false)
Definition: Spell.cpp:3673
void SendInterrupted(uint8 result)
Definition: Spell.cpp:5264
bool IsProcDisabled() const
Definition: Spell.cpp:8362
bool m_immediateHandled
Definition: Spell.h:757
void SendSpellInterruptLog(Unit *victim, uint32 spellId)
Definition: Spell.cpp:5195
bool IsFocusDisabled() const
Definition: Spell.cpp:8357
std::any m_customArg
Definition: Spell.h:619
int32 GetSpellCastDataAmmo()
Definition: Spell.cpp:4996
ObjectGuid m_originalCasterGUID
Definition: Spell.h:718
WorldObject *const m_caster
Definition: Spell.h:714
int64 GetItemTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2684
std::string GetDebugInfo() const
Definition: Spell.cpp:9288
bool IsDeletable() const
Definition: Spell.h:650
bool UpdateChanneledTargetList()
Definition: Spell.cpp:3354
void CleanupTargetList()
Definition: Spell.cpp:2372
void TriggerGlobalCooldown()
Definition: Spell.cpp:9222
int32 m_timer
Definition: Spell.h:953
int32 m_casttime
Definition: Spell.h:727
void ExecuteLogEffectDurabilityDamage(SpellEffectName effect, Unit *victim, int32 itemId, int32 amount)
Definition: Spell.cpp:5206
void SendMountResult(MountResult result)
Definition: Spell.cpp:4742
Item * itemTarget
Definition: Spell.h:767
void AddGOTarget(GameObject *target, uint32 effectMask)
Definition: Spell.cpp:2513
static void SendCastResult(Player *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:4731
void HandleThreatSpells()
Definition: Spell.cpp:5744
float variance
Definition: Spell.h:773
int32 m_damage
Definition: Spell.h:785
std::vector< CorpseTargetInfo > m_UniqueCorpseTargetInfo
Definition: Spell.h:870
void CancelGlobalCooldown()
Definition: Spell.cpp:9273
bool CheckSpellCancelsAuraEffect(AuraType auraType, int32 *param1) const
Definition: Spell.cpp:7154
void SearchChainTargets(std::list< WorldObject * > &targets, uint32 chainTargets, WorldObject *target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const &spellEffectInfo, bool isChainHeal)
Definition: Spell.cpp:2209
bool m_executedCurrently
Definition: Spell.h:761
void SelectImplicitAreaTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1311
bool CheckSpellCancelsSilence(int32 *param1) const
Definition: Spell.cpp:7196
void CallScriptOnCastHandlers()
Definition: Spell.cpp:8861
void AddDestTarget(SpellDestination const &dest, uint32 effIndex)
Definition: Spell.cpp:2646
int64 GetGameObjectTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2676
void SetEmpowerReleasedByClient(bool release)
Definition: Spell.cpp:8388
void _handle_immediate_phase()
Definition: Spell.cpp:4191
void SendSpellCooldown()
Definition: Spell.cpp:4250
void CallScriptBeforeCastHandlers()
Definition: Spell.cpp:8849
bool CheckSpellCancelsCharm(int32 *param1) const
Definition: Spell.cpp:7183
void HandleLaunchPhase()
Definition: Spell.cpp:8552
bool UpdatePointers()
Definition: Spell.cpp:8164
SpellCustomErrors m_customError
Definition: Spell.h:622
void SelectImplicitLineTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1950
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode)
Definition: Spell.cpp:8914
std::vector< GOTargetInfo > m_UniqueGOTargetInfo
Definition: Spell.h:853
void DoSpellEffectHit(Unit *unit, SpellEffectInfo const &spellEffectInfo, TargetInfo &targetInfo)
Definition: Spell.cpp:3214
HitTriggerSpellList m_hitTriggerSpells
Definition: Spell.h:939
void SetSpellValue(CastSpellExtraArgsInit::SpellValueOverride const &value)
Definition: Spell.cpp:8780
int32 m_healing
Definition: Spell.h:786
void SelectImplicitTargetDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition: Spell.cpp:1639
void SetDelayStart(uint64 m_time)
Definition: Spell.h:655
void ResetCombatTimers()
Definition: Spell.cpp:8694
void CallScriptOnPrecastHandler()
Definition: Spell.cpp:8839
void SelectImplicitCasterDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition: Spell.cpp:1450
SpellEffectInfo const * effectInfo
Definition: Spell.h:775
Unit * GetUnitCasterForEffectHandlers() const
Definition: Spell.cpp:8415
SpellInfo const * m_triggeredByAuraSpell
Definition: Spell.h:961
uint64 handle_delayed(uint64 t_offset)
Definition: Spell.cpp:4086
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition: Spell.cpp:9084
bool CheckSpellCancelsPacify(int32 *param1) const
Definition: Spell.cpp:7202
int32 m_castItemLevel
Definition: Spell.h:581
CurrentSpellTypes GetCurrentContainer() const
Definition: Spell.cpp:8219
UnitAura * _spellAura
Definition: Spell.h:778
uint32 m_applyMultiplierMask
Definition: Spell.h:762
Unit * unitTarget
Definition: Spell.h:766
void Delayed()
Definition: Spell.cpp:8067
SpellSchoolMask m_spellSchoolMask
Definition: Spell.h:723
void SendSpellExecuteLog()
Definition: Spell.cpp:5144
Optional< int32 > GetPowerTypeCostAmount(Powers power) const
Definition: Spell.cpp:8155
void cancel()
Definition: Spell.cpp:3604
WorldObject * GetCaster() const
Definition: Spell.h:668
void SendChannelUpdate(uint32 time, Optional< SpellCastResult > result={})
Definition: Spell.cpp:5283
SpellEvent * _spellEvent
Definition: Spell.h:955
union Spell::@323 m_misc
void SelectSpellTargets()
Definition: Spell.cpp:710
bool CheckSpellCancelsConfuse(int32 *param1) const
Definition: Spell.cpp:7213
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3423
SpellCastResult CheckCast(bool strict, int32 *param1=nullptr, int32 *param2=nullptr)
Definition: Spell.cpp:5826
void CallScriptEmpowerStageCompletedHandlers(int32 completedStagesCount)
Definition: Spell.cpp:9096
bool IsChannelActive() const
Definition: Spell.cpp:8367
~Spell()
Definition: Spell.cpp:588
void TakePower()
Definition: Spell.cpp:5525
SpellCastResult CheckPetCast(Unit *target)
Definition: Spell.cpp:6988
void RecalculateDelayMomentForDst()
Definition: Spell.cpp:846
Corpse * m_corpseTarget
Definition: Spell.h:769
SpellLogEffect & GetExecuteLogEffect(SpellEffectName effect)
Definition: Spell.cpp:5160
void ReSetTimer()
Definition: Spell.h:633
void SelectImplicitChainTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, WorldObject *target, uint32 effMask)
Definition: Spell.cpp:1818
int32 CallScriptCalcCastTimeHandlers(int32 originalCastTime)
Definition: Spell.cpp:8903
SpellCastResult CallScriptCheckCastHandlers()
Definition: Spell.cpp:8885
void ExecuteLogEffectCreateItem(SpellEffectName effect, uint32 entry)
Definition: Spell.cpp:5224
Optional< Scripting::v2::ActionResultSetter< SpellCastResult > > m_scriptResult
Definition: Spell.h:626
void CallScriptCalcHealingHandlers(SpellEffectInfo const &spellEffectInfo, Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:9033
bool IsPositive() const
Definition: Spell.cpp:8383
void InitExplicitTargets(SpellCastTargets const &targets)
Definition: Spell.cpp:611
bool IsWithinLOS(WorldObject const *source, WorldObject const *target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition: Spell.cpp:9302
void SendPetCastResult(SpellCastResult result, int32 *param1=nullptr, int32 *param2=nullptr) const
Definition: Spell.cpp:4714
WorldLocation * destTarget
Definition: Spell.h:770
bool CheckSpellCancelsFear(int32 *param1) const
Definition: Spell.cpp:7208
Spell ** m_selfContainer
Definition: Spell.h:683
bool IsTriggered() const
Definition: Spell.cpp:8346
bool CanReleaseEmpowerSpell() const
Definition: Spell.cpp:8393
bool m_scriptWaitsForSpellHit
Definition: Spell.h:627
void SelectImplicitCasterObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1728
void SetReferencedFromCurrent(bool yes)
Definition: Spell.h:651
bool IsDelayableNoMore()
Definition: Spell.h:734
void SelectEffectTypeImplicitTargets(SpellEffectInfo const &spellEffectInfo)
Definition: Spell.cpp:2011
void update(uint32 difftime)
Definition: Spell.cpp:4264
void SelectImplicitConeTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1251
uint64 GetDelayStart() const
Definition: Spell.h:654
bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
Definition: Spell.cpp:9120
SpellState m_spellState
Definition: Spell.h:952
ProcFlagsInit m_procVictim
Definition: Spell.h:792
Item * m_CastItem
Definition: Spell.h:578
std::vector< SpellLogEffect > _executeLogEffects
Definition: Spell.h:966
void CallScriptSuccessfulDispel(SpellEffIndex effIndex)
Definition: Spell.cpp:8960
void DoEffectOnLaunchTarget(TargetInfo &targetInfo, float multiplier, SpellEffectInfo const &spellEffectInfo)
Definition: Spell.cpp:8620
uint32 m_castItemEntry
Definition: Spell.h:580
uint64 GetDelayMoment() const
Definition: Spell.h:656
void AddItemTarget(Item *item, uint32 effectMask)
Definition: Spell.cpp:2566
int32 GetUnitTargetIndexForEffect(ObjectGuid const &target, SpellEffIndex effect) const
Definition: Spell.cpp:2651
UsedSpellMods m_appliedMods
Definition: Spell.h:624
void TakeCastItem()
Definition: Spell.cpp:5456
void CallScriptEmpowerCompletedHandlers(int32 completedStagesCount)
Definition: Spell.cpp:9108
void CheckSrc()
Definition: Spell.cpp:7340
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition: Spell.cpp:9009
SpellValue *const m_spellValue
Definition: Spell.h:716
void SelectImplicitChannelTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1006
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition: Spell.cpp:4383
bool CheckEffectTarget(Unit const *target, SpellEffectInfo const &spellEffectInfo, Position const *losPosition) const
Definition: Spell.cpp:8236
void SendResurrectRequest(Player *target)
Definition: Spell.cpp:5430
void MovePosition(Position &pos, WorldObject const *from, float dist, float angle) const
Definition: Spell.cpp:9329
SpellMissInfo PreprocessSpellHit(Unit *unit, TargetInfo &targetInfo)
Definition: Spell.cpp:3100
SpellCastResult CheckCasterAuras(int32 *param1) const
Definition: Spell.cpp:7022
static uint32 GetSearcherTypeMask(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const *condList)
Definition: Spell.cpp:2111
static void SearchTargets(SEARCHER &searcher, uint32 containerMask, WorldObject *referer, Position const *pos, float radius)
Definition: Spell.cpp:2149
std::vector< ItemTargetInfo > m_UniqueItemInfo
Definition: Spell.h:861
bool IsAutoActionResetSpell() const
Definition: Spell.cpp:8372
void DelayedChannel()
Definition: Spell.cpp:8103
ProcFlagsInit m_procAttacker
Definition: Spell.h:791
ObjectGuid m_castItemGUID
Definition: Spell.h:579
SpellCastVisual m_SpellVisual
Definition: Spell.h:620
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:2668
SpellCastResult CheckPower() const
Definition: Spell.cpp:7465
GameObject * focusObject
Definition: Spell.h:782
void CallScriptDestinationTargetSelectHandlers(SpellDestination &target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:9071
ProcFlagsHit m_hitMask
Definition: Spell.h:793
ObjectGuid m_castId
Definition: Spell.h:582
bool m_launchHandled
Definition: Spell.h:756
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData &data)
Writes miss and hit targets for a SMSG_SPELL_GO packet.
Definition: Spell.cpp:4961
SpellInfo const *const m_spellInfo
Definition: Spell.h:577
std::vector< T > & GetExecuteLogEffectTargets(SpellEffectName effect, Optional< std::vector< T > > SpellLogEffect::*member)
Definition: Spell.h:550
bool HasGlobalCooldown() const
Definition: Spell.cpp:9214
uint8 m_runesState
Definition: Spell.h:731
void FinishTargetProcessing()
Definition: Spell.cpp:8824
void CallScriptOnHitHandlers()
Definition: Spell.cpp:8985
SpellCastResult CheckRange(bool strict) const
Definition: Spell.cpp:7352
bool m_autoRepeat
Definition: Spell.h:730
void CallScriptObjectTargetSelectHandlers(WorldObject *&target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:9058
void TakeRunePower(bool didHit)
Definition: Spell.cpp:5654
void CallScriptObjectAreaTargetSelectHandlers(std::list< WorldObject * > &targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:9045
SpellCastResult CheckArenaAndRatedBattlegroundCastRules()
Definition: Spell.cpp:7223
void CallScriptAfterHitHandlers()
Definition: Spell.cpp:8997
bool CanAutoCast(Unit *target)
Definition: Spell.cpp:7284
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.
Definition: IteratorPair.h:32
Trinity::unique_trackable_ptr companion class, replicating what std::weak_ptr is to std::shared_ptr.
void SetDiminishGroup(DiminishingGroup group)
Definition: SpellAuras.h:401
void AddStaticApplication(Unit *target, uint32 effMask)
Definition: Unit.h:631
Unit * GetCharmed() const
Definition: Unit.h:1203
void ClearUnitState(uint32 f)
Definition: Unit.h:740
uint32 GetChannelSpellId() const
Definition: Unit.h:1414
void SetLastDamagedTargetGuid(ObjectGuid guid)
Definition: Unit.h:956
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:8499
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition: Unit.cpp:701
void RemoveGameObject(GameObject *gameObj, bool del)
Definition: Unit.cpp:5322
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1333
uint32 GetSchoolImmunityMask() const
Definition: Unit.cpp:7618
uint32 m_lastSanctuaryTime
Definition: Unit.h:1580
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition: Unit.cpp:7231
Pet * ToPet()
Definition: Unit.h:1794
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition: Unit.h:1025
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3765
int64 ModifyHealth(int64 val)
Definition: Unit.cpp:8401
void SetCurrentCastSpell(Spell *pSpell)
Definition: Unit.cpp:3015
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10499
ThreatManager & GetThreatManager()
Definition: Unit.h:1073
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4771
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition: Unit.h:1055
uint8 GetClass() const
Definition: Unit.h:760
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition: Unit.cpp:777
uint64 GetMechanicImmunityMask() const
Definition: Unit.cpp:7638
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:1165
std::forward_list< AuraEffect * > AuraEffectList
Definition: Unit.h:648
bool IsInDisallowedMountForm() const
Definition: Unit.cpp:9309
bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7526
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition: Unit.cpp:1275
bool IsPvP() const
Definition: Unit.h:882
bool haveOffhandWeapon() const
Definition: Unit.cpp:525
MotionMaster * GetMotionMaster()
Definition: Unit.h:1695
bool IsPet() const
Definition: Unit.h:747
Powers GetPowerType() const
Definition: Unit.h:807
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:841
bool CanProc() const
Definition: Unit.h:1744
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1202
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3135
void UpdateInterruptMask()
Definition: Unit.cpp:725
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition: Unit.cpp:9127
void AddChannelObject(ObjectGuid guid)
Definition: Unit.h:1431
void SetChannelSpellId(uint32 channelSpellId)
Definition: Unit.h:1415
bool IsFullHealth() const
Definition: Unit.h:787
bool HasUnitFlag2(UnitFlags2 flags) const
Definition: Unit.h:846
bool IsAlive() const
Definition: Unit.h:1176
float GetCombatReach() const override
Definition: Unit.h:701
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9806
void StopMoving()
Definition: Unit.cpp:10448
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition: Unit.cpp:6697
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition: Unit.cpp:5462
bool IsStandState() const
Definition: Unit.cpp:10493
bool IsSilenced(SpellSchoolMask schoolMask) const
Definition: Unit.h:1484
TempSummon * ToTempSummon()
Definition: Unit.h:1800
CharmInfo * GetCharmInfo()
Definition: Unit.h:1233
ControlList m_Controlled
Definition: Unit.h:1223
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1207
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:7042
void SetChannelVisual(SpellCastVisual channelVisual)
Definition: Unit.h:1424
virtual bool IsAffectedByDiminishingReturns() const
Definition: Unit.h:682
bool IsOnVehicle(Unit const *vehicle) const
Definition: Unit.cpp:11874
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition: Unit.h:1208
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7720
bool IsInFlight() const
Definition: Unit.h:1022
bool IsAIEnabled() const
Definition: Unit.h:662
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:7096
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition: Unit.cpp:12185
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4644
bool HasUnitMovementFlag(uint32 f) const
Definition: Unit.h:1706
uint64 GetHealth() const
Definition: Unit.h:784
bool IsSummon() const
Definition: Unit.h:745
bool IsInWater() const
Definition: Unit.cpp:3265
void RemoveDynObject(uint32 spellId)
Definition: Unit.cpp:5264
AttackerSet const & getAttackers() const
Definition: Unit.h:720
void SetSpellEmpowerStage(int8 stage)
Definition: Unit.h:1441
bool isMoving() const
Definition: Unit.h:1776
void EngageWithTarget(Unit *who)
Definition: Unit.cpp:8296
uint8 GetLevelForTarget(WorldObject const *) const override
Definition: Unit.h:755
int32 GetTotalAuraModifier(AuraType auraType) const
Definition: Unit.cpp:5013
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4185
bool IsMounted() const
Definition: Unit.h:907
Unit * GetVictim() const
Definition: Unit.h:722
UF::UpdateField< UF::UnitData, int32(WowCS::EntityFragment::CGObject), TYPEID_UNIT > m_unitData
Definition: Unit.h:1858
int32 GetPower(Powers power) const
Definition: Unit.cpp:9797
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition: Unit.cpp:9681
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition: Unit.cpp:7658
DeathState getDeathState() const
Definition: Unit.h:1179
bool HasUnitState(const uint32 f) const
Definition: Unit.h:739
bool IsInRaidWith(Unit const *unit) const
Definition: Unit.cpp:11945
DynamicObject * GetDynObject(uint32 spellId) const
Definition: Unit.cpp:5248
int32 GetProcChainLength() const
Definition: Unit.h:1746
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4748
float GetMeleeRange(Unit const *target) const
Definition: Unit.cpp:695
SpellHistory * GetSpellHistory()
Definition: Unit.h:1488
bool IsControlledByPlayer() const
Definition: Unit.h:1205
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition: Unit.cpp:9114
ObjectGuid GetCharmerGUID() const
Definition: Unit.h:1199
virtual void setDeathState(DeathState s)
Definition: Unit.cpp:8953
CombatManager & GetCombatManager()
Definition: Unit.h:1033
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:4780
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:697
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition: Unit.cpp:9138
bool IsSpiritHealer() const
Definition: Unit.h:1011
bool IsTotem() const
Definition: Unit.h:749
AuraList & GetSingleCastAuras()
Definition: Unit.h:1335
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4590
Vehicle * GetVehicleKit() const
Definition: Unit.h:1754
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition: Unit.cpp:659
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:5491
virtual bool IsEngaged() const
Definition: Unit.h:1029
void ClearChannelObjects()
Definition: Unit.h:1439
bool AttackStop()
Definition: Unit.cpp:5887
bool IsInPartyWith(Unit const *unit) const
Definition: Unit.cpp:11926
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3911
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:7249
ObjectGuid GetTarget() const
Definition: Unit.h:1803
uint8 GetLevel() const
Definition: Unit.h:753
bool IsInCombat() const
Definition: Unit.h:1053
bool IsWalking() const
Definition: Unit.h:1145
ObjectGuid GetPetGUID() const
Definition: Unit.h:1188
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1456
bool isLineOfSightCalcEnabled() const
Definition: IVMapManager.h:113
static VMapManager2 * createOrGetVMapManager()
Definition: VMapFactory.cpp:27
bool IsControllableVehicle() const
Definition: Vehicle.cpp:603
constexpr uint32 GetMapId() const
Definition: Position.h:215
Unit * GetMagicHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo)
Definition: Object.cpp:3360
void MovePosition(Position &pos, float dist, float angle, float maxHeightChange=6.0f) const
Definition: Object.cpp:3547
bool IsWithinDist2d(float x, float y, float dist) const
Definition: Object.cpp:1199
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition: Object.cpp:1817
Map * GetMap() const
Definition: Object.h:762
virtual float GetCollisionHeight() const
Definition: Object.h:909
Unit * GetCharmerOrOwner() const
Definition: Object.cpp:2331
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition: Object.cpp:2769
bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1228
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition: Object.cpp:1856
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition: Object.cpp:3514
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition: Object.cpp:3888
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2995
float GetMapWaterOrGroundLevel(float x, float y, float z, float *ground=nullptr) const
Definition: Object.cpp:3873
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3102
PhaseShift & GetPhaseShift()
Definition: Object.h:661
bool GetDistanceOrder(WorldObject const *obj1, WorldObject const *obj2, bool is3D=true) const
Definition: Object.cpp:1282
bool IsOutdoors() const
Definition: Object.h:687
int32 ModSpellDuration(SpellInfo const *spellInfo, WorldObject const *target, int32 duration, bool positive, uint32 effectMask) const
Definition: Object.cpp:2498
std::string GetNameForLocaleIdx(LocaleConstant) const override
Definition: Object.h:696
int32 CalculateSpellDamage(Unit const *target, SpellEffectInfo const &spellEffectInfo, int32 const *basePoints=nullptr, float *variance=nullptr, uint32 castItemId=0, int32 itemLevel=-1) const
Definition: Object.cpp:2394
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1248
Player * GetSpellModOwner() const
Definition: Object.cpp:2369
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Object.cpp:2349
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1214
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3255
EventProcessor m_Events
Definition: Object.h:917
void MovePositionToFirstCollision(Position &pos, float dist, float angle) const
Definition: Object.cpp:3593
float GetVisibilityRange() const
Definition: Object.cpp:1514
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition: Object.cpp:3397
float GetSpellMinRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition: Object.cpp:2416
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition: Object.cpp:2720
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1145
uint32 GetZoneId() const
Definition: Object.h:683
MovementInfo m_movementInfo
Definition: Object.h:901
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition: Object.h:685
float GetSpellMaxRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition: Object.cpp:2402
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1209
bool IsFriendlyTo(WorldObject const *target) const
Definition: Object.cpp:2964
virtual float GetCombatReach() const
Definition: Object.h:652
void ModSpellDurationTime(SpellInfo const *spellInfo, int32 &durationTime, Spell *spell=nullptr) const
Definition: Object.cpp:2589
std::vector< SpellLogEffect > const * Effects
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< SpellTargetedHealPrediction > HealPrediction
Definition: SpellPackets.h:847
Optional< SpellChannelStartInterruptImmunities > InterruptImmunities
Definition: SpellPackets.h:845
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
Optional< SpellTargetedHealPrediction > HealPrediction
Definition: SpellPackets.h:879
Duration< Milliseconds, uint32 > EmpowerDuration
Definition: SpellPackets.h:873
Duration< Milliseconds, uint32 > MinHoldTime
Definition: SpellPackets.h:874
std::vector< Duration< Milliseconds, uint32 > > StageDurations
Definition: SpellPackets.h:877
std::vector< ObjectGuid > Targets
Definition: SpellPackets.h:876
Optional< SpellChannelStartInterruptImmunities > InterruptImmunities
Definition: SpellPackets.h:878
Duration< Milliseconds, uint32 > HoldAtMaxTime
Definition: SpellPackets.h:875
WorldPacket const * Write() override
std::vector< Duration< Milliseconds, uint32 > > StageDurations
Definition: SpellPackets.h:892
Duration< Milliseconds, int32 > TimeRemaining
Definition: SpellPackets.h:891
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
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:927
uint32 GetVirtualRealmAddress()
Definition: World.cpp:4016
static constexpr uint16 MAX_BATTLE_PET_LEVEL
Definition: BattlePetMgr.h:41
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
Definition: DisableMgr.cpp:296
uint32 GetGameTimeMS()
Definition: GameTime.cpp:49
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 Creature * GetCreature(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Corpse * GetCorpse(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
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)
Definition: IteratorPair.h:48
void RandomResize(C &container, std::size_t requestedSize)
Definition: Containers.h:67
WorldObjectSpellAreaTargetSearchReason
Definition: Spell.h:1003
void SelectRandomInjuredTargets(std::list< WorldObject * > &targets, size_t maxTargets, bool prioritizePlayers, Unit const *prioritizeGroupMembersOf)
Definition: Spell.cpp:9558
CellCoord ComputeCellCoord(float x, float y)
Definition: GridDefines.h:202
constexpr std::size_t size()
Definition: UpdateField.h:769
uint8 ArtifactCategoryID
Definition: DB2Structure.h:212
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCastItem(ObjectGuid const &guid, uint32 itemId, int32 itemLevel)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
AuraCreateInfo & SetIsRefresh(bool *isRefresh)
AuraCreateInfo & SetOwnerEffectMask(uint32 effMask)
AuraCreateInfo & SetStackAmount(int32 stackAmount)
AuraCreateInfo & SetPeriodicReset(bool reset)
union CastSpellExtraArgsInit::SpellValueOverride::@326 Value
Spell const * TriggeringSpell
Definition: SpellDefines.h:468
Optional< int32 > OriginalCastItemLevel
Definition: SpellDefines.h:472
CastSpellExtraArgs & SetTriggeringSpell(Spell const *triggeringSpell)
Definition: Spell.cpp:9652
CastSpellExtraArgs & operator=(CastSpellExtraArgs const &other)
Definition: Cell.h:47
void SetNoCreate()
Definition: Cell.h:76
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:179
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition: CellImpl.h:191
bool IsPetSpecialization() const
Definition: DB2Structure.h:898
Condition const * mLastFailedCondition
Definition: ConditionMgr.h:225
uint32 ErrorType
Definition: ConditionMgr.h:259
uint8 ConditionTarget
Definition: ConditionMgr.h:263
uint32 ErrorTextId
Definition: ConditionMgr.h:260
CreatureDifficulty const * GetDifficulty(Difficulty difficulty) const
Definition: Creature.cpp:244
bool IsTameable(bool canTameExotic, CreatureDifficulty const *creatureDifficulty) const
Definition: CreatureData.h:550
uint32 GetNoDamageImmune() const
uint32 GetRequiredSkillRank() const
Definition: ItemTemplate.h:840
uint32 GetBaseItemLevel() const
Definition: ItemTemplate.h:837
uint32 GetMaxStackSize() const
Definition: ItemTemplate.h:895
InventoryType GetInventoryType() const
Definition: ItemTemplate.h:834
uint8 GetArtifactID() const
Definition: ItemTemplate.h:872
uint32 GetItemLimitCategory() const
Definition: ItemTemplate.h:869
bool HasFlag(ItemFlags flag) const
Definition: ItemTemplate.h:919
uint32 GetSubClass() const
Definition: ItemTemplate.h:826
uint32 GetLockID() const
Definition: ItemTemplate.h:858
uint32 GetClass() const
Definition: ItemTemplate.h:825
float level
Definition: MapDefines.h:141
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
uint32 GetMovementFlags() const
Definition: MovementInfo.h:117
constexpr void SetOrientation(float orientation)
Definition: Position.h:81
constexpr float GetPositionX() const
Definition: Position.h:86
float m_positionZ
Definition: Position.h:65
constexpr float GetPositionY() const
Definition: Position.h:87
float GetExactDist2d(const float x, const float y) const
Definition: Position.h:116
float GetRelativeAngle(float x, float y) const
Definition: Position.h:146
float GetExactDist(float x, float y, float z) const
Definition: Position.h:128
float m_positionX
Definition: Position.h:63
float m_positionY
Definition: Position.h:64
bool HasInLine(Position const *pos, float objSize, float width) const
Definition: Position.cpp:189
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition: Position.cpp:170
float GetAbsoluteAngle(float x, float y) const
Definition: Position.h:135
constexpr void Relocate(float x, float y)
Definition: Position.h:73
void GetPositionOffsetTo(Position const &endPos, Position &retOffset) const
Definition: Position.cpp:47
constexpr float GetExactDistSq(float x, float y, float z) const
Definition: Position.h:120
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition: Position.h:154
void RelocateOffset(Position const &offset)
Definition: Position.cpp:34
constexpr float GetOrientation() const
Definition: Position.h:89
constexpr float GetPositionZ() const
Definition: Position.h:88
uint32 ScriptVisualID
Definition: SpellDefines.h:530
uint32 SpellXSpellVisualID
Definition: SpellDefines.h:529
void RelocateOffset(Position const &offset)
Definition: Spell.cpp:92
Position _transportOffset
Definition: SpellDefines.h:342
WorldLocation _position
Definition: SpellDefines.h:340
void Relocate(Position const &pos)
Definition: Spell.cpp:81
ObjectGuid _transportGUID
Definition: SpellDefines.h:341
std::array< uint8, MAX_ITEM_ENCHANTMENT_EFFECTS > Effect
EnumFlag< SpellItemEnchantmentFlags > GetFlags() const
Optional< std::vector< SpellLogEffectTradeSkillItemParams > > TradeSkillTargets
Definition: Spell.h:220
Optional< std::vector< SpellLogEffectFeedPetParams > > FeedPetTargets
Definition: Spell.h:221
Optional< std::vector< SpellLogEffectPowerDrainParams > > PowerDrainTargets
Definition: Spell.h:216
Optional< std::vector< SpellLogEffectDurabilityDamageParams > > DurabilityDamageTargets
Definition: Spell.h:218
Optional< std::vector< SpellLogEffectGenericVictimParams > > GenericVictimTargets
Definition: Spell.h:219
Optional< std::vector< SpellLogEffectExtraAttacksParams > > ExtraAttacksTargets
Definition: Spell.h:217
Unit * target
Definition: Unit.h:555
uint32 damage
Definition: Unit.h:560
uint32 absorb
Definition: Unit.h:563
Unit * attacker
Definition: Unit.h:556
Powers Power
Definition: SpellInfo.h:313
float RadiusMod
Definition: Spell.h:230
Optional< int32 > Duration
Definition: Spell.h:234
Optional< int32 > ParentSpellTargetIndex
Definition: Spell.h:236
int32 EffectBasePoints[MAX_SPELL_EFFECTS]
Definition: Spell.h:227
uint32 CustomBasePointsMask
Definition: Spell.h:228
uint32 MaxAffectedTargets
Definition: Spell.h:229
int32 AuraStackAmount
Definition: Spell.h:231
float CriticalChance
Definition: Spell.h:233
Optional< int32 > ParentSpellTargetCount
Definition: Spell.h:235
float DurationMul
Definition: Spell.h:232
SpellValue(SpellInfo const *proto, WorldObject const *caster)
Definition: Spell.cpp:441
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition: Spell.cpp:3086
ObjectGuid TargetGUID
Definition: Spell.h:867
uint64 TimeDelay
Definition: Spell.h:851
ObjectGuid TargetGUID
Definition: Spell.h:850
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition: Spell.cpp:3053
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition: Spell.cpp:3076
UnitAura * HitAura
Definition: Spell.h:836
void PreprocessTarget(Spell *spell) override
Definition: Spell.cpp:2700
SpellMissInfo MissCondition
Definition: Spell.h:825
int32 AuraBasePoints[MAX_SPELL_EFFECTS]
Definition: Spell.h:834
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition: Spell.cpp:2747
void DoDamageAndTriggers(Spell *spell) override
Definition: Spell.cpp:2776
SpellMissInfo ReflectResult
Definition: Spell.h:826
bool _enablePVP
Definition: Spell.h:841
uint64 TimeDelay
Definition: Spell.h:821
ObjectGuid TargetGUID
Definition: Spell.h:820
Unit * _spellHitTarget
Definition: Spell.h:840
int32 Damage
Definition: Spell.h:822
int32 Healing
Definition: Spell.h:823
int32 AuraDuration
Definition: Spell.h:833
DiminishingGroup DRGroup
Definition: Spell.h:832
uint32 SpellID
WorldObjectSpellAreaTargetSearchReason _searchReason
Definition: Spell.h:1012
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9464
WorldObjectSpellAreaTargetCheck(float 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:9459
WorldObjectSpellConeTargetCheck(Position const &coneSrc, float coneAngle, float lineWidth, float 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:9504
WorldObjectSpellLineTargetCheck(Position const *srcPosition, Position const *dstPosition, float lineWidth, float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9542
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9550
WorldObjectSpellNearbyTargetCheck(float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9444
bool operator()(WorldObject *target)
Definition: Spell.cpp:9448
SpellTargetCheckTypes _targetSelectionType
Definition: Spell.h:980
WorldObjectSpellTargetCheck(WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9340
std::unique_ptr< ConditionSourceInfo > _condSrcInfo
Definition: Spell.h:981
SpellInfo const * _spellInfo
Definition: Spell.h:979
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9352
ConditionContainer const * _condList
Definition: Spell.h:982
SpellTargetObjectTypes _objectType
Definition: Spell.h:983
WorldObjectSpellTrajTargetCheck(float range, Position const *position, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9527
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9530
std::vector< ObjectGuid > HitTargets
Definition: SpellPackets.h:366
Optional< RuneData > RemainingRunes
Definition: SpellPackets.h:372
std::vector< SpellMissStatus > MissStatus
Definition: SpellPackets.h:369
MissileTrajectoryResult MissileTrajectory
Definition: SpellPackets.h:373
std::vector< ObjectGuid > MissTargets
Definition: SpellPackets.h:367
std::vector< SpellHitStatus > HitStatus
Definition: SpellPackets.h:368
std::vector< SpellPowerData > RemainingPower
Definition: SpellPackets.h:371
MissileTrajectoryRequest MissileTrajectory
Definition: SpellPackets.h:248
Optional< TargetLocation > SrcLocation
Definition: SpellPackets.h:207
Optional< TargetLocation > DstLocation
Definition: SpellPackets.h:208