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 "ObjectAccessor.h"
47#include "ObjectMgr.h"
48#include "PathGenerator.h"
49#include "Pet.h"
50#include "PhasingHandler.h"
51#include "Player.h"
52#include "ScriptMgr.h"
53#include "SharedDefines.h"
54#include "SpellAuraEffects.h"
55#include "SpellHistory.h"
56#include "SpellInfo.h"
57#include "SpellMgr.h"
58#include "SpellPackets.h"
59#include "SpellScript.h"
60#include "TemporarySummon.h"
61#include "TradeData.h"
62#include "TraitPackets.h"
63#include "UniqueTrackablePtr.h"
64#include "Util.h"
65#include "VMapFactory.h"
66#include "Vehicle.h"
67#include "VMapManager2.h"
68#include "World.h"
69#include "WorldSession.h"
70#include <numeric>
71#include <sstream>
72
74
76{
77 _position.Relocate(0, 0, 0, 0);
79 _transportOffset.Relocate(0, 0, 0, 0);
80}
81
82SpellDestination::SpellDestination(float x, float y, float z, float orientation, uint32 mapId)
83{
84 _position.Relocate(x, y, z, orientation);
86 _position.m_mapId = mapId;
87 _transportOffset.Relocate(0, 0, 0, 0);
88}
89
91{
94 _transportOffset.Relocate(0, 0, 0, 0);
95}
96
98{
101 _transportOffset.Relocate(0, 0, 0, 0);
102}
103
105{
108 _position.Relocate(wObj);
109}
110
112{
113 if (!_transportGUID.IsEmpty())
114 {
115 Position offset;
116 _position.GetPositionOffsetTo(pos, offset);
118 }
119 _position.Relocate(pos);
120}
121
123{
124 if (!_transportGUID.IsEmpty())
126
128}
129
130SpellCastTargets::SpellCastTargets() : m_targetMask(0), m_objectTarget(nullptr), m_itemTarget(nullptr),
131 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f)
132{
133}
134
136 m_targetMask(spellCastRequest.Target.Flags), m_objectTarget(nullptr), m_itemTarget(nullptr),
137 m_objectTargetGUID(spellCastRequest.Target.Unit), m_itemTargetGUID(spellCastRequest.Target.Item),
138 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f), m_strTarget(spellCastRequest.Target.Name)
139{
140 if (spellCastRequest.Target.SrcLocation)
141 {
142 m_src._transportGUID = spellCastRequest.Target.SrcLocation->Transport;
143 Position* pos;
145 pos = &m_src._transportOffset;
146 else
147 pos = &m_src._position;
148
149 pos->Relocate(spellCastRequest.Target.SrcLocation->Location.Pos);
150 if (spellCastRequest.Target.Orientation)
151 pos->SetOrientation(*spellCastRequest.Target.Orientation);
152 }
153
154 if (spellCastRequest.Target.DstLocation)
155 {
156 m_dst._transportGUID = spellCastRequest.Target.DstLocation->Transport;
157 Position* pos;
159 pos = &m_dst._transportOffset;
160 else
161 pos = &m_dst._position;
162
163 pos->Relocate(spellCastRequest.Target.DstLocation->Location.Pos);
164 if (spellCastRequest.Target.Orientation)
165 pos->SetOrientation(*spellCastRequest.Target.Orientation);
166 }
167
168 SetPitch(spellCastRequest.MissileTrajectory.Pitch);
169 SetSpeed(spellCastRequest.MissileTrajectory.Speed);
170
171 Update(caster);
172}
173
175
177{
178 data.Flags = m_targetMask;
179
182
184 data.Item = m_itemTarget->GetGUID();
185
187 {
188 data.SrcLocation.emplace();
189 data.SrcLocation->Transport = m_src._transportGUID; // relative position guid here - transport for example
191 data.SrcLocation->Location = m_src._transportOffset;
192 else
193 data.SrcLocation->Location = m_src._position;
194 }
195
197 {
198 data.DstLocation.emplace();
199 data.DstLocation->Transport = m_dst._transportGUID; // relative position guid here - transport for example
201 data.DstLocation->Location = m_dst._transportOffset;
202 else
203 data.DstLocation->Location = m_dst._position;
204 }
205
207 data.Name = m_strTarget;
208}
209
211{
213 return m_objectTargetGUID;
214
215 return ObjectGuid::Empty;
216}
217
219{
220 if (m_objectTarget)
221 return m_objectTarget->ToUnit();
222
223 return nullptr;
224}
225
227{
228 if (!target)
229 return;
230
231 m_objectTarget = target;
232 m_objectTargetGUID = target->GetGUID();
234}
235
237{
239 return m_objectTargetGUID;
240
241 return ObjectGuid::Empty;
242}
243
245{
246 if (m_objectTarget)
248
249 return nullptr;
250}
251
253{
254 if (!target)
255 return;
256
257 m_objectTarget = target;
258 m_objectTargetGUID = target->GetGUID();
260}
261
263{
265 return m_objectTargetGUID;
266
267 return ObjectGuid::Empty;
268}
269
271{
272 if (m_objectTarget)
273 return m_objectTarget->ToCorpse();
274
275 return nullptr;
276}
277
279{
280 return m_objectTarget;
281}
282
284{
285 return m_objectTargetGUID;
286}
287
289{
290 m_objectTarget = nullptr;
293}
294
296{
297 if (!item)
298 return;
299
300 m_itemTarget = item;
301 m_itemTargetGUID = item->GetGUID();
302 m_itemTargetEntry = item->GetEntry();
304}
305
307{
311
312 Update(caster);
313}
314
316{
318 {
321 }
322}
323
325{
326 return &m_src;
327}
328
330{
331 return &m_src._position;
332}
333
334void SpellCastTargets::SetSrc(float x, float y, float z)
335{
336 m_src = SpellDestination(x, y, z);
338}
339
341{
342 m_src = SpellDestination(pos);
344}
345
347{
348 m_src = SpellDestination(wObj);
350}
351
353{
355 m_src.Relocate(pos);
356}
357
359{
361}
362
364{
365 return &m_dst;
366}
367
369{
370 return &m_dst._position;
371}
372
373void SpellCastTargets::SetDst(float x, float y, float z, float orientation, uint32 mapId)
374{
375 m_dst = SpellDestination(x, y, z, orientation, mapId);
377}
378
380{
381 m_dst = SpellDestination(pos);
383}
384
386{
387 m_dst = SpellDestination(wObj);
389}
390
392{
393 m_dst = spellDest;
395}
396
398{
399 m_dst = spellTargets.m_dst;
401}
402
404{
406 m_dst.Relocate(pos);
407}
408
410{
412 m_dst = spellDest;
413}
414
416{
418}
419
421{
423}
424
426{
428}
429
431{
433
434 m_itemTarget = nullptr;
435 if (caster->GetTypeId() == TYPEID_PLAYER)
436 {
437 Player* player = caster->ToPlayer();
441 {
443 if (TradeData* pTrade = player->GetTradeData())
444 m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
445 }
446
447 if (m_itemTarget)
449 }
450
451 // update positions by transport move
453 {
455 {
456 m_src._position.Relocate(transport);
458 }
459 }
460
462 {
464 {
465 m_dst._position.Relocate(transport);
467 }
468 }
469}
470
471SpellValue::SpellValue(SpellInfo const* proto, WorldObject const* caster)
472{
473 memset(EffectBasePoints, 0, sizeof(EffectBasePoints));
474 for (SpellEffectInfo const& spellEffectInfo : proto->GetEffects())
475 EffectBasePoints[spellEffectInfo.EffectIndex] = spellEffectInfo.CalcBaseValue(caster, nullptr, 0, -1);
476
479 RadiusMod = 1.0f;
480 AuraStackAmount = 1;
481 CriticalChance = 0.0f;
482 DurationMul = 1;
483}
484
486{
487public:
488 explicit SpellEvent(Spell* spell);
489 ~SpellEvent();
490
491 bool Execute(uint64 e_time, uint32 p_time) override;
492 void Abort(uint64 e_time) override;
493 bool IsDeletable() const override;
494 Spell const* GetSpell() const { return m_Spell.get(); }
496
497 std::string GetDebugInfo() const { return m_Spell->GetDebugInfo(); }
498
499protected:
501};
502
503Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID /*= ObjectGuid::Empty*/,
504 ObjectGuid originalCastId /*= ObjectGuid::Empty*/) :
505m_spellInfo(info), m_caster((info->HasAttribute(SPELL_ATTR6_ORIGINATE_FROM_CONTROLLER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster),
506m_spellValue(new SpellValue(m_spellInfo, caster)), _spellEvent(nullptr)
507{
509 m_fromClient = false;
510 m_selfContainer = nullptr;
512 m_executedCurrently = false;
513 m_delayStart = 0;
515
517 memset(m_damageMultipliers, 0, sizeof(m_damageMultipliers));
518
519 // Get data for type of attack
520 m_attackType = info->GetAttackType();
521
522 m_spellSchoolMask = info->GetSchoolMask(); // Can be override for some spell (wand shoot for example)
523
524 if (Player const* playerCaster = m_caster->ToPlayer())
525 {
526 // wand case
528 if ((playerCaster->GetClassMask() & CLASSMASK_WAND_USERS) != 0)
529 if (Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK))
530 m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->GetDamageType());
531 }
532
533 if (Player const* modOwner = caster->GetSpellModOwner())
534 modOwner->ApplySpellMod(info, SpellModOp::Doses, m_spellValue->AuraStackAmount, this);
535
536 if (!originalCasterGUID.IsEmpty())
537 m_originalCasterGUID = originalCasterGUID;
538 else
540
543 else
544 {
547 m_originalCaster = nullptr;
548 }
549
551 _triggeredCastFlags = triggerFlags;
552
555
558
559 m_CastItem = nullptr;
561 m_castItemEntry = 0;
562 m_castItemLevel = -1;
563 m_castFlagsEx = 0;
564
567
568 unitTarget = nullptr;
569 itemTarget = nullptr;
570 gameObjTarget = nullptr;
571 m_corpseTarget = nullptr;
572 destTarget = nullptr;
573 damage = 0;
575 variance = 0.0f;
577 effectInfo = nullptr;
578 m_damage = 0;
579 m_healing = 0;
582 focusObject = nullptr;
584 m_originalCastId = originalCastId;
585 memset(m_misc.Raw.Data, 0, sizeof(m_misc.Raw.Data));
587 m_triggeredByAuraSpell = nullptr;
588 m_procChainLength = caster->IsUnit() ? caster->ToUnit()->GetProcChainLength() : 0;
589 _spellAura = nullptr;
590 _dynObjAura = nullptr;
591
592 //Auto Shot & Shoot (wand)
594
595 m_runesState = 0;
596 m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before.
597 m_timer = 0; // will set to castime in prepare
598 m_channeledDuration = 0; // will be setup in Spell::handle_immediate
599 m_launchHandled = false;
600 m_immediateHandled = false;
601
603
604 // Determine if spell can be reflected back to the caster
605 // Patch 1.2 notes: Spell Reflection no longer reflects abilities
606 m_canReflect = caster->IsUnit()
609 && !m_spellInfo->IsPassive();
610
612
613 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
615}
616
618{
619 // unload scripts
620 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
621 {
622 (*itr)->_Unload();
623 delete (*itr);
624 }
625
627 {
628 // Clean the reference to avoid later crash.
629 // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
630 TC_LOG_ERROR("spells", "SPELL: deleting spell for spell ID {}. However, spell still referenced.", m_spellInfo->Id);
631 *m_selfContainer = nullptr;
632 }
633
636
637 delete m_spellValue;
638}
639
641{
642 m_targets = targets;
643
644 // this function tries to correct spell explicit targets for spell
645 // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
646 // this also makes sure that we correctly send explicit targets to client (removes redundant data)
647 uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
648
649 if (WorldObject* target = m_targets.GetObjectTarget())
650 {
651 // check if object target is valid with needed target flags
652 // for unit case allow corpse target mask because player with not released corpse is a unit target
653 if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)))
654 || (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
655 || (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK)))
657 }
658 else
659 {
660 // try to select correct unit target if not provided by client or by serverside cast
661 if (neededTargets & (TARGET_FLAG_UNIT_MASK))
662 {
663 Unit* unit = nullptr;
664 // try to use player selection as a target
665 if (Player* playerCaster = m_caster->ToPlayer())
666 {
667 // selection has to be found and to be valid target for the spell
668 if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget()))
670 unit = selectedUnit;
671 }
672 // try to use attacked unit as a target
673 else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
674 unit = m_caster->ToUnit()->GetVictim();
675
676 // didn't find anything - let's use self as target
677 if (!unit && neededTargets & (TARGET_FLAG_UNIT_RAID | TARGET_FLAG_UNIT_PARTY | TARGET_FLAG_UNIT_ALLY))
678 unit = m_caster->ToUnit();
679
681 }
682 }
683
684 // check if spell needs dst target
685 if (neededTargets & TARGET_FLAG_DEST_LOCATION)
686 {
687 // and target isn't set
688 if (!m_targets.HasDst())
689 {
690 // try to use unit target if provided
691 if (WorldObject* target = targets.GetObjectTarget())
692 m_targets.SetDst(*target);
693 // or use self if not available
694 else
696 }
697 }
698 else
700
701 if (neededTargets & TARGET_FLAG_SOURCE_LOCATION)
702 {
703 if (!targets.HasSrc())
705 }
706 else
708}
709
711{
712 // here go all explicit target changes made to explicit targets after spell prepare phase is finished
713 if (Unit* target = m_targets.GetUnitTarget())
714 {
715 // check for explicit target redirection, for Grounding Totem for example
718 {
719 Unit* redirect = nullptr;
720 switch (m_spellInfo->DmgClass)
721 {
724 break;
727 // should gameobjects cast damagetype melee/ranged spells this needs to be changed
728 redirect = ASSERT_NOTNULL(m_caster->ToUnit())->GetMeleeHitRedirectTarget(target, m_spellInfo);
729 break;
730 default:
731 break;
732 }
733 if (redirect && (redirect != target))
734 m_targets.SetUnitTarget(redirect);
735 }
736 }
737}
738
740{
741 // select targets for cast phase
743
744 uint32 processedAreaEffectsMask = 0;
745
746 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
747 {
748 // not call for empty effect.
749 // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
750 if (!spellEffectInfo.IsEffect())
751 continue;
752
753 // set expected type of implicit targets to be sent to client
754 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
755 if (implicitTargetMask & TARGET_FLAG_UNIT)
757 if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
759
760 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, SpellTargetIndex::TargetA, processedAreaEffectsMask);
761 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, SpellTargetIndex::TargetB, processedAreaEffectsMask);
762
763 // Select targets of effect based on effect type
764 // those are used when no valid target could be added for spell effect based on spell target type
765 // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
766 // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
767 // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
768 SelectEffectTypeImplicitTargets(spellEffectInfo);
769
770 if (m_targets.HasDst())
771 AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex);
772
773 if (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
774 || spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST
775 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
776 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST)
777 {
779 {
780 bool noTargetFound = std::none_of(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target)
781 {
782 return target.EffectMask & effectMask;
783 });
784
785 if (noTargetFound)
786 {
789 return;
790 }
791 }
793 {
794 bool anyNonImmuneTargetFound = std::any_of(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effectMask = 1u << spellEffectInfo.EffectIndex](TargetInfo const& target)
795 {
796 return target.EffectMask & effectMask && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2;
797 });
798
799 if (!anyNonImmuneTargetFound)
800 {
803 return;
804 }
805 }
806 }
807
809 {
810 // maybe do this for all spells?
811 if (!focusObject && m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst())
812 {
815 return;
816 }
817
818 uint32 mask = (1 << spellEffectInfo.EffectIndex);
819 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
820 {
821 if (ihit->EffectMask & mask)
822 {
824 break;
825 }
826 }
827 }
828 }
829
830 if (m_targets.HasDst())
831 {
833 {
836 if (!(status & (LIQUID_MAP_WATER_WALK | LIQUID_MAP_IN_WATER)))
837 {
840 return;
841 }
842 }
843 }
844
846 m_delayMoment = dstDelay;
847}
848
850{
851 if (m_targets.HasDst())
852 {
853 if (m_targets.HasTraj())
854 {
855 float speed = m_targets.GetSpeedXY();
856 if (speed > 0.0f)
857 return uint64(std::floor((m_targets.GetDist2d() / speed + launchDelay) * 1000.0f));
858 }
860 return uint64(std::floor((m_spellInfo->Speed + launchDelay) * 1000.0f));
861 else if (m_spellInfo->Speed > 0.0f)
862 {
863 // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP)
864 float dist = m_caster->GetExactDist(*m_targets.GetDstPos());
865 return uint64(std::floor((dist / m_spellInfo->Speed + launchDelay) * 1000.0f));
866 }
867
868 return uint64(std::floor(launchDelay * 1000.0f));
869 }
870
871 return 0;
872}
873
875{
877}
878
880{
881 m_delayMoment = hitDelay;
882
883 if (GetDelayStart())
885}
886
888{
889 auto itr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [unit](Spell::TargetInfo const& targetInfo)
890 {
891 return targetInfo.TargetGUID == unit->GetGUID();
892 });
893
894 uint64 oldDelay = itr->TimeDelay;
895 itr->TimeDelay = hitDelay;
896
897 if (hitDelay && (!m_delayMoment || m_delayMoment > hitDelay))
898 m_delayMoment = hitDelay;
899 else if (m_delayMoment && oldDelay < hitDelay)
900 {
901 // 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
902 auto minDelayTargetItr = std::min_element(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [](Spell::TargetInfo const& itr, Spell::TargetInfo const& smallest)
903 {
904 return itr.TimeDelay && itr.TimeDelay < smallest.TimeDelay;
905 });
906
907 m_delayMoment = minDelayTargetItr->TimeDelay;
908 }
909
910 if (GetDelayStart())
912}
913
914void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32& processedEffectMask)
915{
916 if (!targetType.GetTarget())
917 return;
918
919 uint32 effectMask = 1 << spellEffectInfo.EffectIndex;
920 // set the same target list for all effects
921 // some spells appear to need this, however this requires more research
922 switch (targetType.GetSelectionCategory())
923 {
928 {
929 // targets for effect already selected
930 if (effectMask & processedEffectMask)
931 return;
932 std::vector<SpellEffectInfo> const& effects = GetSpellInfo()->GetEffects();
933 // choose which targets we can select at once
934 for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j)
935 {
936 if (effects[j].IsEffect() &&
937 spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
938 spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
939 spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
940 spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetA) == effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetA) &&
941 spellEffectInfo.CalcRadius(m_caster, SpellTargetIndex::TargetB) == effects[j].CalcRadius(m_caster, SpellTargetIndex::TargetB) &&
942 spellEffectInfo.EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) == effects[j].EffectAttributes.HasFlag(SpellEffectAttributes::PlayersOnly) &&
944 {
945 effectMask |= 1 << j;
946 }
947 }
948 processedEffectMask |= effectMask;
949 break;
950 }
951 default:
952 break;
953 }
954
955 switch (targetType.GetSelectionCategory())
956 {
958 SelectImplicitChannelTargets(spellEffectInfo, targetType);
959 break;
961 SelectImplicitNearbyTargets(spellEffectInfo, targetType, targetIndex, effectMask);
962 break;
964 SelectImplicitConeTargets(spellEffectInfo, targetType, targetIndex, effectMask);
965 break;
967 SelectImplicitAreaTargets(spellEffectInfo, targetType, targetIndex, effectMask);
968 break;
970 // just in case there is no dest, explanation in SelectImplicitDestDestTargets
971 CheckDst();
972
973 SelectImplicitTrajTargets(spellEffectInfo, targetType);
974 break;
976 SelectImplicitLineTargets(spellEffectInfo, targetType, targetIndex, effectMask);
977 break;
979 switch (targetType.GetObjectType())
980 {
982 switch (targetType.GetReferenceType())
983 {
986 break;
987 default:
988 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
989 break;
990 }
991 break;
993 switch (targetType.GetReferenceType())
994 {
996 SelectImplicitCasterDestTargets(spellEffectInfo, targetType, targetIndex);
997 break;
999 SelectImplicitTargetDestTargets(spellEffectInfo, targetType, targetIndex);
1000 break;
1002 SelectImplicitDestDestTargets(spellEffectInfo, targetType, targetIndex);
1003 break;
1004 default:
1005 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
1006 break;
1007 }
1008 break;
1009 default:
1010 switch (targetType.GetReferenceType())
1011 {
1013 SelectImplicitCasterObjectTargets(spellEffectInfo, targetType);
1014 break;
1016 SelectImplicitTargetObjectTargets(spellEffectInfo, targetType);
1017 break;
1018 default:
1019 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
1020 break;
1021 }
1022 break;
1023 }
1024 break;
1026 TC_LOG_DEBUG("spells", "SPELL: target type {}, found in spellID {}, effect {} is not implemented yet!", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex), targetType.GetTarget());
1027 break;
1028 default:
1029 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target category");
1030 break;
1031 }
1032}
1033
1035{
1037 {
1038 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target reference type");
1039 return;
1040 }
1041
1043 if (!channeledSpell)
1044 {
1045 TC_LOG_DEBUG("spells", "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1046 return;
1047 }
1048 switch (targetType.GetTarget())
1049 {
1051 {
1052 for (ObjectGuid const& channelTarget : m_originalCaster->m_unitData->ChannelObjects)
1053 {
1054 WorldObject* target = ObjectAccessor::GetUnit(*m_caster, channelTarget);
1055 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1056 // unit target may be no longer avalible - teleported out of map for example
1057 Unit* unitTarget = target ? target->ToUnit() : nullptr;
1058 if (unitTarget)
1059 AddUnitTarget(unitTarget, 1 << spellEffectInfo.EffectIndex);
1060 else
1061 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1062 }
1063 break;
1064 }
1066 if (channeledSpell->m_targets.HasDst())
1067 m_targets.SetDst(channeledSpell->m_targets);
1068 else
1069 {
1070 auto const& channelObjects = m_originalCaster->m_unitData->ChannelObjects;
1071 WorldObject* target = !channelObjects.empty() ? ObjectAccessor::GetWorldObject(*m_caster, *channelObjects.begin()) : nullptr;
1072 if (target)
1073 {
1074 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1075 if (target)
1076 {
1077 SpellDestination dest(*target);
1079 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1080
1081 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1082 m_targets.SetDst(dest);
1083 }
1084 }
1085 else
1086 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1087 }
1088 break;
1090 {
1091 SpellDestination dest(*channeledSpell->GetCaster());
1093 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1094
1095 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1096 m_targets.SetDst(dest);
1097 break;
1098 }
1099 default:
1100 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
1101 break;
1102 }
1103}
1104
1105void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1106{
1108 {
1109 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
1110 return;
1111 }
1112
1113 float range = 0.0f;
1114 switch (targetType.GetCheckType())
1115 {
1116 case TARGET_CHECK_ENEMY:
1117 range = m_spellInfo->GetMaxRange(false, m_caster, this);
1118 break;
1119 case TARGET_CHECK_ALLY:
1120 case TARGET_CHECK_PARTY:
1121 case TARGET_CHECK_RAID:
1123 range = m_spellInfo->GetMaxRange(true, m_caster, this);
1124 break;
1125 case TARGET_CHECK_ENTRY:
1127 range = m_spellInfo->GetMaxRange(IsPositive(), m_caster, this);
1128 break;
1129 default:
1130 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
1131 break;
1132 }
1133
1134 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1135
1136 // handle emergency case - try to use other provided targets if no conditions provided
1137 if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
1138 {
1139 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));
1140 switch (targetType.GetObjectType())
1141 {
1144 {
1145 if (focusObject)
1146 AddGOTarget(focusObject, effMask);
1147 else
1148 {
1151 }
1152 return;
1153 }
1154 break;
1157 {
1158 if (focusObject)
1159 {
1162 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1163
1164 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1165 m_targets.SetDst(dest);
1166 }
1167 else
1168 {
1171 }
1172 return;
1173 }
1174 if (targetType.GetTarget() == TARGET_DEST_NEARBY_ENTRY_OR_DB)
1175 {
1176 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1177 {
1179 if (st->target_mapId == m_caster->GetMapId() && m_caster->IsInDist(st->target_X, st->target_Y, st->target_Z, range))
1180 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
1181 else
1182 {
1183 float randomRadius = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1184 if (randomRadius > 0.0f)
1185 m_caster->MovePositionToFirstCollision(dest._position, randomRadius, targetType.CalcDirectionAngle());
1186 }
1187
1188 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1189 m_targets.SetDst(dest);
1190 return;
1191 }
1192 }
1193 break;
1194 default:
1195 break;
1196 }
1197 }
1198
1199 WorldObject* target = SearchNearbyTarget(spellEffectInfo, range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
1200 float randomRadius = 0.0f;
1201 switch (targetType.GetTarget())
1202 {
1204 // if we are here then there was no db target
1205 if (!target)
1206 {
1207 target = m_caster;
1208 // radius is only meant to be randomized when using caster fallback
1209 randomRadius = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1210 }
1211 break;
1212 default:
1213 break;
1214 }
1215
1216 if (!target)
1217 {
1218 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1221 return;
1222 }
1223
1224 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1225 if (!target)
1226 {
1227 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set NULL target, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1230 return;
1231 }
1232
1233 switch (targetType.GetObjectType())
1234 {
1236 if (Unit* unit = target->ToUnit())
1237 AddUnitTarget(unit, effMask, true, false);
1238 else
1239 {
1240 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);
1243 return;
1244 }
1245 break;
1247 if (GameObject* gobjTarget = target->ToGameObject())
1248 AddGOTarget(gobjTarget, effMask);
1249 else
1250 {
1251 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);
1254 return;
1255 }
1256 break;
1258 if (Corpse* corpseTarget = target->ToCorpse())
1259 AddCorpseTarget(corpseTarget, effMask);
1260 else
1261 {
1262 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);
1265 return;
1266 }
1267 break;
1269 {
1270 SpellDestination dest(*target);
1271 if (randomRadius > 0.0f)
1272 target->MovePositionToFirstCollision(dest._position, randomRadius, targetType.CalcDirectionAngle());
1273
1275 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1276
1277 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1278 m_targets.SetDst(dest);
1279 break;
1280 }
1281 default:
1282 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target object type");
1283 break;
1284 }
1285
1286 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1287}
1288
1289void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1290{
1291 Position coneSrc(*m_caster);
1292 float coneAngle = m_spellInfo->ConeAngle;
1293 switch (targetType.GetReferenceType())
1294 {
1296 break;
1300 break;
1301 default:
1302 break;
1303 }
1304
1305 switch (targetType.GetTarget())
1306 {
1308 if (coneAngle == 0.0f)
1309 coneAngle = 180.0f;
1310 break;
1311 default:
1312 break;
1313 }
1314
1315 std::list<WorldObject*> targets;
1316 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1317 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1318 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1319 float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1320
1321 if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
1322 {
1323 float extraSearchRadius = radius > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1324 Trinity::WorldObjectSpellConeTargetCheck check(coneSrc, DegToRad(coneAngle), m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
1326 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius + extraSearchRadius);
1327
1328 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1329
1330 if (!targets.empty())
1331 {
1332 // Other special target selection goes here
1333 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1334 Trinity::Containers::RandomResize(targets, maxTargets);
1335
1336 for (WorldObject* itr : targets)
1337 {
1338 if (Unit* unit = itr->ToUnit())
1339 AddUnitTarget(unit, effMask, false);
1340 else if (GameObject* gObjTarget = itr->ToGameObject())
1341 AddGOTarget(gObjTarget, effMask);
1342 else if (Corpse* corpse = itr->ToCorpse())
1343 AddCorpseTarget(corpse, effMask);
1344 }
1345 }
1346 }
1347}
1348
1349void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1350{
1351 WorldObject* referer = nullptr;
1352 switch (targetType.GetReferenceType())
1353 {
1357 referer = m_caster;
1358 break;
1360 referer = m_targets.GetUnitTarget();
1361 break;
1363 {
1364 referer = m_caster;
1365
1366 // find last added target for this effect
1367 for (auto ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
1368 {
1369 if (ihit->EffectMask & (1 << spellEffectInfo.EffectIndex))
1370 {
1371 referer = ObjectAccessor::GetUnit(*m_caster, ihit->TargetGUID);
1372 break;
1373 }
1374 }
1375 break;
1376 }
1377 default:
1378 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1379 return;
1380 }
1381
1382 if (!referer)
1383 return;
1384
1385 Position const* center = nullptr;
1386 switch (targetType.GetReferenceType())
1387 {
1389 center = m_targets.GetSrcPos();
1390 break;
1392 center = m_targets.GetDstPos();
1393 break;
1397 center = referer;
1398 break;
1399 default:
1400 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1401 return;
1402 }
1403
1404 float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1405 std::list<WorldObject*> targets;
1406 switch (targetType.GetTarget())
1407 {
1409 targets.push_back(m_caster);
1410 if (Unit* unit = m_caster->ToUnit())
1411 if (Vehicle const* vehicleKit = unit->GetVehicleKit())
1412 for (int8 seat = 0; seat < MAX_VEHICLE_SEATS; ++seat)
1413 if (Unit* passenger = vehicleKit->GetPassenger(seat))
1414 targets.push_back(passenger);
1415 break;
1417 if (Unit* targetedUnit = m_targets.GetUnitTarget())
1418 {
1419 if (!m_caster->IsUnit() || !m_caster->ToUnit()->IsInRaidWith(targetedUnit))
1420 targets.push_back(m_targets.GetUnitTarget());
1421 else
1422 SearchAreaTargets(targets, spellEffectInfo, radius, targetedUnit, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1424 }
1425 break;
1427 targets.push_back(m_caster);
1428 SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1430 break;
1431 default:
1432 SearchAreaTargets(targets, spellEffectInfo, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(),
1434 break;
1435 }
1436
1438 {
1439 SpellDestination dest(*referer);
1441 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1442
1443 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1444
1445 m_targets.ModDst(dest);
1446 }
1447
1448 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1449
1451 targets.sort(Trinity::ObjectDistanceOrderPred(referer, false));
1452
1453 if (!targets.empty())
1454 {
1455 // Other special target selection goes here
1456 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1457 {
1459 Trinity::Containers::RandomResize(targets, maxTargets);
1460 else if (targets.size() > maxTargets)
1461 targets.resize(maxTargets);
1462 }
1463
1464 for (WorldObject* itr : targets)
1465 {
1466 if (Unit* unit = itr->ToUnit())
1467 AddUnitTarget(unit, effMask, false, true, center);
1468 else if (GameObject* gObjTarget = itr->ToGameObject())
1469 AddGOTarget(gObjTarget, effMask);
1470 else if (Corpse* corpse = itr->ToCorpse())
1471 AddCorpseTarget(corpse, effMask);
1472 }
1473 }
1474}
1475
1477{
1479
1480 switch (targetType.GetTarget())
1481 {
1482 case TARGET_DEST_CASTER:
1483 break;
1484 case TARGET_DEST_HOME:
1485 if (Player* playerCaster = m_caster->ToPlayer())
1486 dest = SpellDestination(playerCaster->m_homebind);
1487 break;
1488 case TARGET_DEST_DB:
1489 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1490 {
1493 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
1494 else if (st->target_mapId == m_caster->GetMapId())
1495 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
1496 }
1497 else
1498 {
1499 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1500 if (WorldObject* target = m_targets.GetObjectTarget())
1501 dest = SpellDestination(*target);
1502 }
1503 break;
1505 {
1506 float minDist = m_spellInfo->GetMinRange(true);
1507 float maxDist = m_spellInfo->GetMaxRange(true);
1508 float dist = frand(minDist, maxDist);
1509 float x, y, z;
1510 float angle = rand_norm() * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
1512
1513 float ground = m_caster->GetMapHeight(x, y, z);
1514 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
1515 LiquidData liquidData;
1516 if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseShift(), x, y, z, {}, &liquidData, m_caster->GetCollisionHeight()))
1517 liquidLevel = liquidData.level;
1518
1519 if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
1520 {
1524 return;
1525 }
1526
1527 if (ground + 0.75 > liquidLevel)
1528 {
1532 return;
1533 }
1534
1535 dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation());
1536 break;
1537 }
1540 {
1541 Unit* unitCaster = m_caster->ToUnit();
1542 if (!unitCaster)
1543 break;
1544
1545 float dist = spellEffectInfo.CalcRadius(unitCaster, targetIndex);
1546 float angle = targetType.CalcDirectionAngle();
1548 {
1549 angle = [&]()
1550 {
1552 {
1553 case MOVEMENTFLAG_NONE:
1559 return 0.0f;
1562 return static_cast<float>(M_PI);
1565 return static_cast<float>(M_PI / 2);
1567 return static_cast<float>(M_PI / 4);
1569 return static_cast<float>(3 * M_PI / 4);
1572 return static_cast<float>(-M_PI / 2);
1574 return static_cast<float>(-M_PI / 4);
1576 return static_cast<float>(-3 * M_PI / 4);
1577 default:
1578 return 0.0f;
1579 }
1580 }();
1581 }
1582
1583 Position pos = dest._position;
1584
1585 unitCaster->MovePositionToFirstCollision(pos, dist, angle);
1586 dest.Relocate(pos);
1587 break;
1588 }
1592 break;
1594 if (Unit const* unitCaster = m_caster->ToUnit())
1595 if (TempSummon const* casterSummon = unitCaster->ToTempSummon())
1596 if (WorldObject const* summoner = casterSummon->GetSummoner())
1597 dest = SpellDestination(*summoner);
1598 break;
1599 default:
1600 {
1601 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1602 float angle = targetType.CalcDirectionAngle();
1603 float objSize = m_caster->GetCombatReach();
1604
1605 switch (targetType.GetTarget())
1606 {
1608 dist = PET_FOLLOW_DIST;
1609 break;
1611 if (dist > objSize)
1612 dist = objSize + (dist - objSize);
1613 break;
1618 {
1619 static float const DefaultTotemDistance = 3.0f;
1620 if (!spellEffectInfo.HasRadius(targetIndex))
1621 dist = DefaultTotemDistance;
1622 break;
1623 }
1624 default:
1625 break;
1626 }
1627
1628 if (dist < objSize)
1629 dist = objSize;
1630
1631 Position pos = dest._position;
1632 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1633
1634 dest.Relocate(pos);
1635 break;
1636 }
1637 }
1638
1640 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1641
1642 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1643 m_targets.SetDst(dest);
1644}
1645
1647{
1648 ASSERT(m_targets.GetObjectTarget() && "Spell::SelectImplicitTargetDestTargets - no explicit object target available!");
1650
1651 SpellDestination dest(*target);
1652
1653 switch (targetType.GetTarget())
1654 {
1658 break;
1659 default:
1660 {
1661 float angle = targetType.CalcDirectionAngle();
1662 float dist = spellEffectInfo.CalcRadius(nullptr, targetIndex);
1663
1664 Position pos = dest._position;
1665 target->MovePositionToFirstCollision(pos, dist, angle);
1666
1667 dest.Relocate(pos);
1668 break;
1669 }
1670 }
1671
1673 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1674
1675 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1676 m_targets.SetDst(dest);
1677}
1678
1679void Spell::SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex)
1680{
1681 // set destination to caster if no dest provided
1682 // can only happen if previous destination target could not be set for some reason
1683 // (not found nearby target, or channel target for example
1684 // maybe we should abort the spell in such case?
1685 CheckDst();
1686
1688
1689 switch (targetType.GetTarget())
1690 {
1694 case TARGET_DEST_DEST:
1695 break;
1698 break;
1700 {
1701 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1702 Position pos = dest._position;
1703 float angle = pos.GetAbsoluteAngle(m_caster) - m_caster->GetOrientation();
1704
1705 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1707
1708 dest.Relocate(pos);
1709 break;
1710 }
1711 default:
1712 {
1713 float angle = targetType.CalcDirectionAngle();
1714 float dist = spellEffectInfo.CalcRadius(m_caster, targetIndex);
1715
1716 Position pos = dest._position;
1717 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1718
1719 dest.Relocate(pos);
1720 break;
1721 }
1722 }
1723
1725 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1726
1727 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1728 m_targets.ModDst(dest);
1729}
1730
1732{
1733 WorldObject* target = nullptr;
1734 bool checkIfValid = true;
1735
1736 switch (targetType.GetTarget())
1737 {
1738 case TARGET_UNIT_CASTER:
1739 target = m_caster;
1740 checkIfValid = false;
1741 break;
1742 case TARGET_UNIT_MASTER:
1743 target = m_caster->GetCharmerOrOwner();
1744 break;
1745 case TARGET_UNIT_PET:
1746 if (Unit* unitCaster = m_caster->ToUnit())
1747 target = unitCaster->GetGuardianPet();
1748 break;
1750 if (Unit* unitCaster = m_caster->ToUnit())
1751 if (unitCaster->IsSummon())
1752 target = unitCaster->ToTempSummon()->GetSummonerUnit();
1753 break;
1755 if (Unit* unitCaster = m_caster->ToUnit())
1756 target = unitCaster->GetVehicleBase();
1757 break;
1766 if (Creature* vehicleBase = m_caster->ToCreature())
1767 if (vehicleBase->IsVehicle())
1768 target = vehicleBase->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
1769 break;
1771 if (Creature* creatureCaster = m_caster->ToCreature())
1772 if (!creatureCaster->GetTapList().empty())
1773 target = ObjectAccessor::GetWorldObject(*creatureCaster, Trinity::Containers::SelectRandomContainerElement(creatureCaster->GetTapList()));
1774 break;
1776 if (Unit const* unitCaster = m_caster->ToUnit())
1777 target = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetCritterGUID());
1778 break;
1779 default:
1780 break;
1781 }
1782
1783 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1784
1785 if (target)
1786 {
1787 if (Unit* unit = target->ToUnit())
1788 AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, checkIfValid);
1789 else if (GameObject* go = target->ToGameObject())
1790 AddGOTarget(go, 1 << spellEffectInfo.EffectIndex);
1791 else if (Corpse* corpse = target->ToCorpse())
1792 AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
1793 }
1794}
1795
1797{
1798 ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!");
1799
1801
1802 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1803
1804 if (target)
1805 {
1806 if (Unit* unit = target->ToUnit())
1807 AddUnitTarget(unit, 1 << spellEffectInfo.EffectIndex, true, false);
1808 else if (GameObject* gobj = target->ToGameObject())
1809 AddGOTarget(gobj, 1 << spellEffectInfo.EffectIndex);
1810 else if (Corpse* corpse = target->ToCorpse())
1811 AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
1812
1813 SelectImplicitChainTargets(spellEffectInfo, targetType, target, 1 << spellEffectInfo.EffectIndex);
1814 }
1815 // Script hook can remove object target and we would wrongly land here
1816 else if (Item* item = m_targets.GetItemTarget())
1817 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
1818}
1819
1820void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask)
1821{
1822 int32 maxTargets = spellEffectInfo.ChainTargets;
1823 if (Player* modOwner = m_caster->GetSpellModOwner())
1824 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainTargets, maxTargets, this);
1825
1826 if (maxTargets > 1)
1827 {
1828 // mark damage multipliers as used
1829 for (size_t k = spellEffectInfo.EffectIndex; k < m_spellInfo->GetEffects().size(); ++k)
1830 if (effMask & (1 << k))
1831 m_damageMultipliers[k] = 1.0f;
1832 m_applyMultiplierMask |= effMask;
1833
1834 std::list<WorldObject*> targets;
1835 SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
1836 , spellEffectInfo, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
1837
1838 // Chain primary target is added earlier
1839 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1840
1842
1843 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
1844 {
1845 if (Unit* unit = (*itr)->ToUnit())
1846 AddUnitTarget(unit, effMask, false, true, losPosition);
1847
1849 losPosition = *itr;
1850 }
1851 }
1852}
1853
1854float tangent(float x)
1855{
1856 x = std::tan(x);
1857 //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
1858 //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
1859 //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
1860 if (x < 100000.0f && x > -100000.0f) return x;
1861 if (x >= 100000.0f) return 100000.0f;
1862 if (x <= 100000.0f) return -100000.0f;
1863 return 0.0f;
1864}
1865
1866void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType)
1867{
1868 if (!m_targets.HasTraj())
1869 return;
1870
1871 float dist2d = m_targets.GetDist2d();
1872 if (!dist2d)
1873 return;
1874
1875 Position srcPos = *m_targets.GetSrcPos();
1877 float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
1878
1879 std::list<WorldObject*> targets;
1882 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
1883 if (targets.empty())
1884 return;
1885
1887
1888 float b = tangent(m_targets.GetPitch());
1889 float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
1890 if (a > -0.0001f)
1891 a = 0.f;
1892
1893 // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
1894 // limit max range to 300 yards, sometimes triggered spells can have 50000yds
1895 float bestDist = m_spellInfo->GetMaxRange(false);
1896 if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, GetCastDifficulty()))
1897 bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
1898
1899 // GameObjects don't cast traj
1900 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
1901 for (auto itr = targets.begin(); itr != targets.end(); ++itr)
1902 {
1903 if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
1904 continue;
1905
1906 if (Unit* unit = (*itr)->ToUnit())
1907 {
1908 if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
1909 continue;
1910
1911 if (Creature* creatureTarget = unit->ToCreature())
1912 {
1913 if (!(creatureTarget->GetCreatureDifficulty()->TypeFlags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES))
1914 continue;
1915 }
1916 }
1917
1918 float const size = std::max((*itr)->GetCombatReach(), 1.0f);
1919 float const objDist2d = srcPos.GetExactDist2d(*itr);
1920 float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
1921
1922 float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
1923 float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
1924 float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
1925 float const height = distToHitPoint * (a * distToHitPoint + b);
1926
1927 if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
1928 continue;
1929
1930 if (distToHitPoint < bestDist)
1931 {
1932 bestDist = distToHitPoint;
1933 break;
1934 }
1935 }
1936
1937 if (dist2d > bestDist)
1938 {
1939 float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
1940 float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
1941 float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
1942
1943 SpellDestination dest(x, y, z, unitCaster->GetOrientation());
1945 dest._position.SetOrientation(spellEffectInfo.PositionFacing);
1946
1947 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1948 m_targets.ModDst(dest);
1949 }
1950}
1951
1952void Spell::SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask)
1953{
1954 std::list<WorldObject*> targets;
1955 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1956 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1957 Position const* dst = nullptr;
1958 switch (targetType.GetReferenceType())
1959 {
1961 dst = m_targets.GetSrcPos();
1962 break;
1964 dst = m_targets.GetDstPos();
1965 break;
1967 dst = m_caster;
1968 break;
1970 dst = m_targets.GetUnitTarget();
1971 break;
1972 default:
1973 ABORT_MSG("Spell::SelectImplicitLineTargets: received not implemented target reference type");
1974 return;
1975 }
1976
1977 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions.get();
1978 float radius = spellEffectInfo.CalcRadius(m_caster, targetIndex) * m_spellValue->RadiusMod;
1979
1980 if (uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList))
1981 {
1982 Trinity::WorldObjectSpellLineTargetCheck check(m_caster, dst, m_spellInfo->Width ? m_spellInfo->Width : m_caster->GetCombatReach(), radius, m_caster, m_spellInfo, selectionType, condList, objectType);
1984 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellLineTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, radius);
1985
1986 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1987
1988 if (!targets.empty())
1989 {
1990 // Other special target selection goes here
1991 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1992 {
1993 if (maxTargets < targets.size())
1994 {
1996 targets.resize(maxTargets);
1997 }
1998 }
1999
2000 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
2001 {
2002 if (Unit* unit = (*itr)->ToUnit())
2003 AddUnitTarget(unit, effMask, false);
2004 else if (GameObject* gObjTarget = (*itr)->ToGameObject())
2005 AddGOTarget(gObjTarget, effMask);
2006 else if (Corpse* corpse = (*itr)->ToCorpse())
2007 AddCorpseTarget(corpse, 1 << spellEffectInfo.EffectIndex);
2008 }
2009 }
2010 }
2011}
2012
2014{
2015 // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER, queue them on map for later execution
2016 switch (spellEffectInfo.Effect)
2017 {
2021 {
2024
2025 // scripts may modify the target - recheck
2026 if (target && target->GetTypeId() == TYPEID_PLAYER)
2027 {
2028 // target is not stored in target map for those spells
2029 // since we're completely skipping AddUnitTarget logic, we need to check immunity manually
2030 // eg. aura 21546 makes target immune to summons
2031 Player* player = target->ToPlayer();
2032 if (player->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, nullptr))
2033 return;
2034
2035 target->GetMap()->AddFarSpellCallback([spell = this, &spellEffectInfo, targetGuid = target->GetGUID()](Map* map)
2036 {
2037 Player* player = ObjectAccessor::GetPlayer(map, targetGuid);
2038 if (!player)
2039 return;
2040
2041 // check immunity again in case it changed during update
2042 if (player->IsImmunedToSpellEffect(spell->GetSpellInfo(), spellEffectInfo, nullptr))
2043 return;
2044
2045 spell->HandleEffects(player, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2046 });
2047 }
2048 }
2049 return;
2050 default:
2051 break;
2052 }
2053
2054 // select spell implicit targets based on effect type
2055 if (!spellEffectInfo.GetImplicitTargetType())
2056 return;
2057
2058 uint32 targetMask = spellEffectInfo.GetMissingTargetMask();
2059
2060 if (!targetMask)
2061 return;
2062
2063 WorldObject* target = nullptr;
2064
2065 switch (spellEffectInfo.GetImplicitTargetType())
2066 {
2067 // add explicit object target or self to the target map
2069 // player which not released his spirit is Unit, but target flag for it is TARGET_FLAG_CORPSE_MASK
2071 {
2072 if (Unit* unit = m_targets.GetUnitTarget())
2073 target = unit;
2074 else if (targetMask & TARGET_FLAG_CORPSE_MASK)
2075 {
2076 if (Corpse* corpseTarget = m_targets.GetCorpseTarget())
2077 target = corpseTarget;
2078 }
2079 else //if (targetMask & TARGET_FLAG_UNIT_MASK)
2080 target = m_caster;
2081 }
2082 if (targetMask & TARGET_FLAG_ITEM_MASK)
2083 {
2084 if (Item* item = m_targets.GetItemTarget())
2085 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
2086 return;
2087 }
2088 if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK)
2089 target = m_targets.GetGOTarget();
2090 break;
2091 // add self to the target map
2093 if (targetMask & TARGET_FLAG_UNIT_MASK)
2094 target = m_caster;
2095 break;
2096 default:
2097 break;
2098 }
2099
2101
2102 if (target)
2103 {
2104 if (target->ToUnit())
2105 AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex, false);
2106 else if (target->ToGameObject())
2107 AddGOTarget(target->ToGameObject(), 1 << spellEffectInfo.EffectIndex);
2108 else if (target->ToCorpse())
2109 AddCorpseTarget(target->ToCorpse(), 1 << spellEffectInfo.EffectIndex);
2110 }
2111}
2112
2113uint32 Spell::GetSearcherTypeMask(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const* condList)
2114{
2115 // this function selects which containers need to be searched for spell target
2117
2118 // filter searchers based on searched object type
2119 switch (objType)
2120 {
2124 break;
2129 break;
2133 break;
2134 default:
2135 break;
2136 }
2137
2141 retMask &= GRID_MAP_TYPE_MASK_PLAYER;
2143 retMask &= ~GRID_MAP_TYPE_MASK_PLAYER;
2144
2145 if (condList)
2146 retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
2147 return retMask;
2148}
2149
2150template<class SEARCHER>
2151void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius)
2152{
2153 if (!containerMask)
2154 return;
2155
2156 // search world and grid for possible targets
2157 bool searchInGrid = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT)) != 0;
2158 bool searchInWorld = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE)) != 0;
2159 if (searchInGrid || searchInWorld)
2160 {
2161 float x, y;
2162 x = pos->GetPositionX();
2163 y = pos->GetPositionY();
2164
2166 Cell cell(p);
2167 cell.SetNoCreate();
2168
2169 Map* map = referer->GetMap();
2170
2171 if (searchInWorld)
2172 Cell::VisitWorldObjects(x, y, map, searcher, radius);
2173
2174 if (searchInGrid)
2175 Cell::VisitGridObjects(x, y, map, searcher, radius);
2176 }
2177}
2178
2179WorldObject* Spell::SearchNearbyTarget(SpellEffectInfo const& spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
2180{
2181 WorldObject* target = nullptr;
2182 uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
2183 if (!containerTypeMask)
2184 return nullptr;
2185
2186 Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList, objectType);
2189 SearchTargets<Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, range);
2190 return target;
2191}
2192
2193void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, SpellEffectInfo const& spellEffectInfo, float range, Position const* position, WorldObject* referer,
2194 SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList,
2196{
2197 uint32 containerTypeMask = GetSearcherTypeMask(m_spellInfo, spellEffectInfo, objectType, condList);
2198 if (!containerTypeMask)
2199 return;
2200
2201 float extraSearchRadius = range > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
2202 Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList, objectType, searchReason);
2205 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(searcher, containerTypeMask, m_caster, position, range + extraSearchRadius);
2206}
2207
2208void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType,
2209 SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal)
2210{
2211 // max dist for jump target selection
2212 float jumpRadius = 0.0f;
2213 switch (m_spellInfo->DmgClass)
2214 {
2216 // 7.5y for multi shot
2217 jumpRadius = 7.5f;
2218 break;
2220 // 5y for swipe, cleave and similar
2221 jumpRadius = 5.0f;
2222 break;
2225 // 12.5y for chain heal spell since 3.2 patch
2226 if (isChainHeal)
2227 jumpRadius = 12.5f;
2228 // 10y as default for magic chain spells
2229 else
2230 jumpRadius = 10.0f;
2231 break;
2232 }
2233
2234 if (Player* modOwner = m_caster->GetSpellModOwner())
2235 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::ChainJumpDistance, jumpRadius, this);
2236
2237 // max dist which spell can reach
2238 float searchRadius = [&]()
2239 {
2241 return GetMinMaxRange(false).second;
2242
2244 return jumpRadius;
2245
2246 return jumpRadius * chainTargets;
2247 }();
2248
2250 std::list<WorldObject*> tempTargets;
2251 SearchAreaTargets(tempTargets, spellEffectInfo, searchRadius, chainSource, m_caster, objectType, selectType, spellEffectInfo.ImplicitTargetConditions.get(),
2253 tempTargets.remove(target);
2254
2255 // remove targets which are always invalid for chain spells
2256 // for some spells allow only chain targets in front of caster (swipe for example)
2258 {
2259 tempTargets.remove_if([&](WorldObject* object)
2260 {
2261 return !m_caster->HasInArc(static_cast<float>(M_PI), object);
2262 });
2263 }
2264
2265 while (chainTargets)
2266 {
2267 // try to get unit for next chain jump
2268 std::list<WorldObject*>::iterator foundItr = tempTargets.end();
2269 // get unit with highest hp deficit in dist
2270 if (isChainHeal)
2271 {
2272 uint32 maxHPDeficit = 0;
2273 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2274 {
2275 if (Unit* unit = (*itr)->ToUnit())
2276 {
2277 uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
2278 if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && chainSource->IsWithinDist(unit, jumpRadius) && IsWithinLOS(chainSource, unit, false, VMAP::ModelIgnoreFlags::M2))
2279 {
2280 foundItr = itr;
2281 maxHPDeficit = deficit;
2282 }
2283 }
2284 }
2285 }
2286 // get closest object
2287 else
2288 {
2289 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2290 {
2291 bool isBestDistanceMatch = foundItr != tempTargets.end() ? chainSource->GetDistanceOrder(*itr, *foundItr) : chainSource->IsWithinDist(*itr, jumpRadius);
2292 if (!isBestDistanceMatch)
2293 continue;
2294
2295 if (!IsWithinLOS(chainSource, *itr, false, VMAP::ModelIgnoreFlags::M2))
2296 continue;
2297
2299 continue;
2300
2301 foundItr = itr;
2302 }
2303 }
2304 // not found any valid target - chain ends
2305 if (foundItr == tempTargets.end())
2306 break;
2307
2309 chainSource = *foundItr;
2310
2311 targets.push_back(*foundItr);
2312 tempTargets.erase(foundItr);
2313 --chainTargets;
2314 }
2315}
2316
2318{
2319 GameObject* focus = nullptr;
2323 return focus;
2324}
2325
2327{
2328 //==========================================================================================
2329 // Now fill data for trigger system, need know:
2330 // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
2331 //==========================================================================================
2332
2334 // Get data for type of attack and fill base info for trigger
2335 switch (m_spellInfo->DmgClass)
2336 {
2339 if (m_attackType == OFF_ATTACK)
2341 else
2344 break;
2346 // Auto attack
2348 {
2351 }
2352 else // Ranged spell attack
2353 {
2356 }
2357 break;
2358 default:
2361 && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTO_REPEAT)) // Wands auto attack
2362 {
2365 }
2366 // For other spells trigger procflags are set in Spell::TargetInfo::DoDamageAndTriggers
2367 // Because spell positivity is dependant on target
2368 }
2369}
2370
2372{
2373 m_UniqueTargetInfo.clear();
2374 m_UniqueGOTargetInfo.clear();
2375 m_UniqueItemInfo.clear();
2376 m_delayMoment = 0;
2377}
2378
2380{
2381 public:
2382 ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
2383
2384 bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
2385 {
2387 if (!caster)
2388 return true;
2389
2390 ProcFlags const typeMaskActor = PROC_FLAG_NONE;
2393 ProcFlagsSpellPhase const spellPhaseMask = PROC_SPELL_PHASE_NONE;
2394 ProcFlagsHit const hitMask = PROC_HIT_REFLECT;
2395
2396 Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
2397 return true;
2398 }
2399
2400 private:
2403};
2404
2405void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
2406{
2407 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2408 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(target, spellEffectInfo, losPosition))
2409 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2410
2411 // no effects left
2412 if (!effectMask)
2413 return;
2414
2415 if (checkIfValid)
2416 if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
2417 return;
2418
2419 // Check for effect immune skip if immuned
2420 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2421 if (target->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, m_caster))
2422 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2423
2424 ObjectGuid targetGUID = target->GetGUID();
2425
2426 // Lookup target in already in list
2427 auto ihit = std::find_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [targetGUID](TargetInfo const& target) { return target.TargetGUID == targetGUID; });
2428 if (ihit != std::end(m_UniqueTargetInfo)) // Found in list
2429 {
2430 // Immune effects removed from mask
2431 ihit->EffectMask |= effectMask;
2432 return;
2433 }
2434
2435 // This is new target calculate data for him
2436
2437 // Get spell hit result on target
2438 TargetInfo targetInfo;
2439 targetInfo.TargetGUID = targetGUID; // Store target GUID
2440 targetInfo.EffectMask = effectMask; // Store all effects not immune
2441 targetInfo.IsAlive = target->IsAlive();
2442 targetInfo.Damage = 0;
2443 targetInfo.Healing = 0;
2444 targetInfo.IsCrit = false;
2445
2446 // Calculate hit result
2448 targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
2449
2450 // Spell have speed - need calculate incoming time
2451 // Incoming time is zero for self casts. At least I think so.
2452 if (m_caster != target)
2453 {
2454 float hitDelay = m_spellInfo->LaunchDelay;
2455 WorldObject const* missileSource = m_caster;
2457 {
2458 auto previousTargetItr = std::find_if(m_UniqueTargetInfo.rbegin(), m_UniqueTargetInfo.rend(), [effectMask](TargetInfo const& target)
2459 {
2460 return (target.EffectMask & effectMask) != 0;
2461 });
2462 if (previousTargetItr != std::rend(m_UniqueTargetInfo))
2463 {
2464 hitDelay = 0.0f; // this is not the first target in chain, LaunchDelay was already included
2465
2466 if (WorldObject* previousTarget = ObjectAccessor::GetWorldObject(*m_caster, previousTargetItr->TargetGUID))
2467 missileSource = previousTarget;
2468
2469 targetInfo.TimeDelay += previousTargetItr->TimeDelay;
2470 }
2471 }
2472
2474 hitDelay += m_spellInfo->Speed;
2475 else if (m_spellInfo->Speed > 0.0f)
2476 {
2477 // calculate spell incoming interval
2479 float dist = std::max(missileSource->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ()), 5.0f);
2480 hitDelay += dist / m_spellInfo->Speed;
2481 }
2482
2483 targetInfo.TimeDelay += uint64(std::floor(hitDelay * 1000.0f));
2484 }
2485 else
2486 targetInfo.TimeDelay = 0ULL;
2487
2488 // If target reflect spell back to caster
2489 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
2490 {
2491 // Calculate reflected spell result on caster (shouldn't be able to reflect gameobject spells)
2492 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
2493 targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice
2494
2495 // Proc spell reflect aura when missile hits the original target
2497
2498 // Increase time interval for reflected spells by 1.5
2499 targetInfo.TimeDelay += targetInfo.TimeDelay >> 1;
2500 }
2501 else
2502 targetInfo.ReflectResult = SPELL_MISS_NONE;
2503
2504 // Calculate minimum incoming time
2505 if (targetInfo.TimeDelay && (!m_delayMoment || m_delayMoment > targetInfo.TimeDelay))
2506 m_delayMoment = targetInfo.TimeDelay;
2507
2508 // Add target to list
2509 m_UniqueTargetInfo.emplace_back(std::move(targetInfo));
2510}
2511
2513{
2514 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2515 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(go, spellEffectInfo))
2516 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2517
2518 // no effects left
2519 if (!effectMask)
2520 return;
2521
2522 ObjectGuid targetGUID = go->GetGUID();
2523
2524 // Lookup target in already in list
2525 auto ihit = std::find_if(std::begin(m_UniqueGOTargetInfo), std::end(m_UniqueGOTargetInfo), [targetGUID](GOTargetInfo const& target) { return target.TargetGUID == targetGUID; });
2526 if (ihit != std::end(m_UniqueGOTargetInfo)) // Found in list
2527 {
2528 // Add only effect mask
2529 ihit->EffectMask |= effectMask;
2530 return;
2531 }
2532
2533 // This is new target calculate data for him
2534
2535 GOTargetInfo target;
2536 target.TargetGUID = targetGUID;
2537 target.EffectMask = effectMask;
2538
2539 // Spell have speed - need calculate incoming time
2540 if (static_cast<WorldObject*>(m_caster) != go)
2541 {
2542 float hitDelay = m_spellInfo->LaunchDelay;
2544 hitDelay += m_spellInfo->Speed;
2545 else if (m_spellInfo->Speed > 0.0f)
2546 {
2547 // calculate spell incoming interval
2548 float dist = std::max(m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ()), 5.0f);
2549 hitDelay += dist / m_spellInfo->Speed;
2550 }
2551
2552 target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
2553 }
2554 else
2555 target.TimeDelay = 0ULL;
2556
2557 // Calculate minimum incoming time
2558 if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
2559 m_delayMoment = target.TimeDelay;
2560
2561 // Add target to list
2562 m_UniqueGOTargetInfo.emplace_back(std::move(target));
2563}
2564
2565void Spell::AddItemTarget(Item* item, uint32 effectMask)
2566{
2567 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2568 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(item, spellEffectInfo))
2569 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2570
2571 // no effects left
2572 if (!effectMask)
2573 return;
2574
2575 // Lookup target in already in list
2576 auto ihit = std::find_if(std::begin(m_UniqueItemInfo), std::end(m_UniqueItemInfo), [item](ItemTargetInfo const& target) { return target.TargetItem == item; });
2577 if (ihit != std::end(m_UniqueItemInfo)) // Found in list
2578 {
2579 // Add only effect mask
2580 ihit->EffectMask |= effectMask;
2581 return;
2582 }
2583
2584 // This is new target add data
2585
2586 ItemTargetInfo target;
2587 target.TargetItem = item;
2588 target.EffectMask = effectMask;
2589
2590 m_UniqueItemInfo.emplace_back(std::move(target));
2591}
2592
2593void Spell::AddCorpseTarget(Corpse* corpse, uint32 effectMask)
2594{
2595 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2596 if (!spellEffectInfo.IsEffect())
2597 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2598
2599 // no effects left
2600 if (!effectMask)
2601 return;
2602
2603 ObjectGuid targetGUID = corpse->GetGUID();
2604
2605 // Lookup target in already in list
2606 auto ihit = std::find_if(std::begin(m_UniqueCorpseTargetInfo), std::end(m_UniqueCorpseTargetInfo), [targetGUID](CorpseTargetInfo const& target) { return target.TargetGUID == targetGUID; });
2607 if (ihit != std::end(m_UniqueCorpseTargetInfo)) // Found in list
2608 {
2609 // Add only effect mask
2610 ihit->EffectMask |= effectMask;
2611 return;
2612 }
2613
2614 // This is new target calculate data for him
2615 CorpseTargetInfo target;
2616 target.TargetGUID = targetGUID;
2617 target.EffectMask = effectMask;
2618
2619 // Spell have speed - need calculate incoming time
2620 if (m_caster != corpse)
2621 {
2622 float hitDelay = m_spellInfo->LaunchDelay;
2624 hitDelay += m_spellInfo->Speed;
2625 else if (m_spellInfo->Speed > 0.0f)
2626 {
2627 // calculate spell incoming interval
2628 float dist = std::max(m_caster->GetDistance(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ()), 5.0f);
2629 hitDelay += dist / m_spellInfo->Speed;
2630 }
2631
2632 target.TimeDelay = uint64(std::floor(hitDelay * 1000.0f));
2633 }
2634 else
2635 target.TimeDelay = 0LL;
2636
2637 // Calculate minimum incoming time
2638 if (target.TimeDelay && (!m_delayMoment || m_delayMoment > target.TimeDelay))
2639 m_delayMoment = target.TimeDelay;
2640
2641 // Add target to list
2642 m_UniqueCorpseTargetInfo.emplace_back(std::move(target));
2643}
2644
2646{
2647 m_destTargets[effIndex] = dest;
2648}
2649
2651{
2652 int32 index = 0;
2653 for (TargetInfo const& uniqueTargetInfo : m_UniqueTargetInfo)
2654 {
2655 if (uniqueTargetInfo.MissCondition == SPELL_MISS_NONE && uniqueTargetInfo.EffectMask & (1 << effect))
2656 {
2657 if (uniqueTargetInfo.TargetGUID == target)
2658 break;
2659
2660 ++index;
2661 }
2662 }
2663
2664 return index;
2665}
2666
2668{
2669 return std::count_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effect](TargetInfo const& targetInfo)
2670 {
2671 return targetInfo.MissCondition == SPELL_MISS_NONE && targetInfo.EffectMask & (1 << effect);
2672 });
2673}
2674
2676{
2677 return std::count_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [effect](GOTargetInfo const& targetInfo)
2678 {
2679 return targetInfo.EffectMask & (1 << effect);
2680 });
2681}
2682
2684{
2685 return std::count_if(m_UniqueItemInfo.begin(), m_UniqueItemInfo.end(), [effect](ItemTargetInfo const& targetInfo)
2686 {
2687 return targetInfo.EffectMask & (1 << effect);
2688 });
2689}
2690
2692{
2693 return std::count_if(m_UniqueCorpseTargetInfo.begin(), m_UniqueCorpseTargetInfo.end(), [effect](CorpseTargetInfo const& targetInfo)
2694 {
2695 return targetInfo.EffectMask & (1 << effect);
2696 });
2697}
2698
2700{
2701 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2702 if (!unit)
2703 return;
2704
2705 // Need init unitTarget by default unit (can changed in code on reflect)
2706 spell->unitTarget = unit;
2707
2708 // Reset damage/healing counter
2709 spell->m_damage = Damage;
2710 spell->m_healing = Healing;
2711
2712 _spellHitTarget = nullptr;
2714 _spellHitTarget = unit;
2716 _spellHitTarget = spell->m_caster->ToUnit();
2717
2719 unit->SetInCombatWith(spell->m_originalCaster);
2720
2721 // if target is flagged for pvp also flag caster if a player
2722 // but respect current pvp rules (buffing/healing npcs flagged for pvp only flags you if they are in combat)
2724 && 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
2725
2726 if (_spellHitTarget)
2727 {
2728 SpellMissInfo missInfo = spell->PreprocessSpellHit(_spellHitTarget, *this);
2729 if (missInfo != SPELL_MISS_NONE)
2730 {
2731 if (missInfo != SPELL_MISS_MISS)
2732 spell->m_caster->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
2733 spell->m_damage = 0;
2734 spell->m_healing = 0;
2735 _spellHitTarget = nullptr;
2736 }
2737 }
2738
2739 spell->CallScriptOnHitHandlers();
2740
2741 // scripts can modify damage/healing for current target, save them
2742 Damage = spell->m_damage;
2743 Healing = spell->m_healing;
2744}
2745
2747{
2748 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2749 if (!unit)
2750 return;
2751
2752 // Need init unitTarget by default unit (can changed in code on reflect)
2753 // Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
2754 spell->unitTarget = unit;
2755 spell->targetMissInfo = MissCondition;
2756
2757 // Reset damage/healing counter
2758 spell->m_damage = Damage;
2759 spell->m_healing = Healing;
2760
2761 if (unit->IsAlive() != IsAlive)
2762 return;
2763
2765 return; // No missinfo in that case
2766
2767 if (_spellHitTarget)
2768 spell->DoSpellEffectHit(_spellHitTarget, spellEffectInfo, *this);
2769
2770 // scripts can modify damage/healing for current target, save them
2771 Damage = spell->m_damage;
2772 Healing = spell->m_healing;
2773}
2774
2776{
2777 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2778 if (!unit)
2779 return;
2780
2781 // other targets executed before this one changed pointer
2782 spell->unitTarget = unit;
2783 if (_spellHitTarget)
2784 spell->unitTarget = _spellHitTarget;
2785
2786 // Reset damage/healing counter
2787 spell->m_damage = Damage;
2788 spell->m_healing = Healing;
2789
2790 // Get original caster (if exist) and calculate damage/healing from him data
2791 // Skip if m_originalCaster not available
2792 Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit();
2793 if (caster)
2794 {
2795 // Fill base trigger info
2796 ProcFlagsInit procAttacker = spell->m_procAttacker;
2797 ProcFlagsInit procVictim = spell->m_procVictim;
2799 ProcFlagsHit hitMask = PROC_HIT_NONE;
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 hitMask |= PROC_HIT_CRITICAL;
2885 addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr);
2886 }
2887 else
2888 hitMask |= 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(spell->m_spellInfo))
2907 {
2908 hitMask = 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 hitMask |= 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, hitMask);
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 hitMask |= createProcHitMask(&damageInfo, MissCondition);
2952 // Do triggers for unit
2953 if (canEffectTrigger)
2954 {
2955 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, hitMask);
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, hitMask, 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 |= hitMask;
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
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
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 .IsRefresh = &refresh;
3239
3240 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo, false))
3241 {
3242 hitInfo.HitAura = aura->ToUnitAura();
3243
3244 // Set aura stack amount to desired value
3246 {
3247 if (!refresh)
3249 else
3251 }
3252
3253 hitInfo.HitAura->SetDiminishGroup(hitInfo.DRGroup);
3254
3255 if (!m_spellValue->Duration)
3256 {
3257 hitInfo.AuraDuration = caster->ModSpellDuration(m_spellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask());
3258
3259 if (hitInfo.AuraDuration > 0)
3260 {
3262
3263 // Haste modifies duration of channeled spells
3264 if (m_spellInfo->IsChanneled())
3265 caster->ModSpellDurationTime(m_spellInfo, hitInfo.AuraDuration, this);
3267 {
3268 int32 origDuration = hitInfo.AuraDuration;
3269 hitInfo.AuraDuration = 0;
3270 for (AuraEffect const* auraEff : hitInfo.HitAura->GetAuraEffects())
3271 if (auraEff)
3272 if (int32 period = auraEff->GetPeriod()) // period is hastened by UNIT_MOD_CAST_SPEED
3273 hitInfo.AuraDuration = std::max(std::max(origDuration / period, 1) * period, hitInfo.AuraDuration);
3274
3275 // if there is no periodic effect
3276 if (!hitInfo.AuraDuration)
3277 hitInfo.AuraDuration = int32(origDuration * m_originalCaster->m_unitData->ModCastingSpeed);
3278 }
3279 }
3280 }
3281 else
3283
3284 if (hitInfo.AuraDuration != hitInfo.HitAura->GetMaxDuration())
3285 {
3286 hitInfo.HitAura->SetMaxDuration(hitInfo.AuraDuration);
3287 hitInfo.HitAura->SetDuration(hitInfo.AuraDuration);
3288 }
3289
3290 if (refresh)
3291 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
3292 }
3293 }
3294 else
3295 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
3296 }
3297 }
3298
3299 _spellAura = hitInfo.HitAura;
3300 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
3301 _spellAura = nullptr;
3302}
3303
3305{
3306 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras
3307 // this is executed after spell proc spells on target hit
3308 // spells are triggered for each hit spell target
3309 // info confirmed with retail sniffs of permafrost and shadow weaving
3310 if (!m_hitTriggerSpells.empty())
3311 {
3312 int32 _duration = 0;
3313 for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
3314 {
3315 if (CanExecuteTriggersOnHit(unit, i->triggeredByAura) && roll_chance_i(i->chance))
3316 {
3317 m_caster->CastSpell(unit, i->triggeredSpell->Id, CastSpellExtraArgs(TRIGGERED_FULL_MASK)
3318 .SetTriggeringSpell(this)
3319 .SetCastDifficulty(i->triggeredSpell->Difficulty));
3320 TC_LOG_DEBUG("spells", "Spell {} triggered spell {} by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id);
3321
3322 // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
3323 // set duration of current aura to the triggered spell
3324 if (i->triggeredSpell->GetDuration() == -1)
3325 {
3326 if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID()))
3327 {
3328 // get duration from aura-only once
3329 if (!_duration)
3330 {
3331 Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
3332 _duration = aur ? aur->GetDuration() : -1;
3333 }
3334 triggeredAur->SetDuration(_duration);
3335 }
3336 }
3337 }
3338 }
3339 }
3340
3341 // trigger linked auras remove/apply
3343 if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_HIT, m_spellInfo->Id))
3344 {
3345 for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
3346 {
3347 if (*i < 0)
3348 unit->RemoveAurasDueToSpell(-(*i));
3349 else
3351 .SetOriginalCaster(m_caster->GetGUID())
3352 .SetTriggeringSpell(this));
3353 }
3354 }
3355}
3356
3358{
3359 // Not need check return true
3361 return true;
3362
3363 uint32 channelTargetEffectMask = m_channelTargetEffectMask;
3364 uint32 channelAuraMask = 0;
3365 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3366 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3367 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
3368
3369 channelAuraMask &= channelTargetEffectMask;
3370
3371 float range = 0;
3372 if (channelAuraMask)
3373 {
3375 if (Player* modOwner = m_caster->GetSpellModOwner())
3376 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, range, this);
3377
3378 // add little tolerance level
3379 range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
3380 }
3381
3382 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
3383 {
3384 if (targetInfo.MissCondition == SPELL_MISS_NONE && (channelTargetEffectMask & targetInfo.EffectMask))
3385 {
3386 Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
3387 if (!unit)
3388 {
3389 if (Unit* unitCaster =m_caster->ToUnit())
3390 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3391 continue;
3392 }
3393
3394 if (IsValidDeadOrAliveTarget(unit))
3395 {
3396 if (channelAuraMask & targetInfo.EffectMask)
3397 {
3399 {
3400 if (m_caster != unit && !m_caster->IsWithinDistInMap(unit, range))
3401 {
3402 targetInfo.EffectMask &= ~aurApp->GetEffectMask();
3403 unit->RemoveAura(aurApp);
3404 if (Unit* unitCaster = m_caster->ToUnit())
3405 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3406 continue;
3407 }
3408 }
3409 else // aura is dispelled
3410 {
3411 if (Unit* unitCaster = m_caster->ToUnit())
3412 unitCaster->RemoveChannelObject(targetInfo.TargetGUID);
3413 continue;
3414 }
3415 }
3416
3417 channelTargetEffectMask &= ~targetInfo.EffectMask; // remove from need alive mask effect that have alive target
3418 }
3419 }
3420 }
3421
3422 // is all effects from m_needAliveTargetMask have alive targets
3423 return channelTargetEffectMask == 0;
3424}
3425
3426SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura)
3427{
3428 if (m_CastItem)
3429 {
3432
3433 if (Player* owner = m_CastItem->GetOwner())
3435 else if (m_CastItem->GetOwnerGUID() == m_caster->GetGUID())
3437 else
3438 {
3442 }
3443 }
3444
3445 InitExplicitTargets(targets);
3446
3448
3449 if (triggeredByAura)
3450 {
3451 m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
3452 m_castItemLevel = triggeredByAura->GetBase()->GetCastItemLevel();
3453 }
3454
3455 // create and add update event for this spell
3456 _spellEvent = new SpellEvent(this);
3458
3459 // check disables
3461 {
3465 }
3466
3467 // Prevent casting at cast another spell (ServerSide check)
3469 {
3473 }
3474
3475 LoadScripts();
3476
3477 // Fill cost data (do not use power for item casts)
3478 if (!m_CastItem)
3480
3481 int32 param1 = 0, param2 = 0;
3482 SpellCastResult result = CheckCast(true, &param1, &param2);
3483 // target is checked in too many locations and with different results to handle each of them
3484 // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
3486 result = SPELL_CAST_OK;
3487 if (result != SPELL_CAST_OK)
3488 {
3489 // Periodic auras should be interrupted when aura triggers a spell which can't be cast
3490 // for example bladestorm aura should be removed on disarm as of patch 3.3.5
3491 // channeled periodic spells should be affected by this (arcane missiles, penance, etc)
3492 // a possible alternative sollution for those would be validating aura target on unit state change
3493 if (triggeredByAura && triggeredByAura->IsPeriodic() && !triggeredByAura->GetBase()->IsPassive())
3494 {
3496 triggeredByAura->GetBase()->SetDuration(0);
3497 }
3498
3499 if (param1 || param2)
3500 SendCastResult(result, &param1, &param2);
3501 else
3502 SendCastResult(result);
3503
3504 // queue autorepeat spells for future repeating
3507
3508 finish(result);
3509 return result;
3510 }
3511
3512 // Prepare data for triggers
3514
3516
3517 if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving())
3518 {
3519 result = CheckMovement();
3520 if (result != SPELL_CAST_OK)
3521 {
3522 SendCastResult(result);
3523 finish(result);
3524 return result;
3525 }
3526 }
3527
3528 // Creatures focus their target when possible
3530 {
3531 // 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
3532 bool const focusTarget = !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING);
3533 if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
3535 else
3536 m_caster->ToCreature()->SetSpellFocus(this, nullptr);
3537 }
3538
3540
3541 // set timer base at cast time
3542 ReSetTimer();
3543
3544 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());
3545
3548
3551
3552 //Containers for channeled spells have to be set
3554 // Why check duration? 29350: channelled triggers channelled
3556 cast(true);
3557 else
3558 {
3559 // commented out !m_spellInfo->StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
3560 // as a result a spell that passed CheckCast and should be processed instantly may suffer from this delayed process
3561 // 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
3562 // 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)
3563 bool willCastDirectly = !m_casttime && GetCurrentContainer() == CURRENT_GENERIC_SPELL;
3564
3565 if (Unit* unitCaster = m_caster->ToUnit())
3566 {
3567 // stealth must be removed at cast starting (at show channel bar)
3568 // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
3570 unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action, m_spellInfo);
3571
3572 // Do not register as current spell when requested to ignore cast in progress
3573 // We don't want to interrupt that other spell with cast time
3574 if (!willCastDirectly || !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS))
3575 unitCaster->SetCurrentCastSpell(this);
3576 }
3578
3581
3582 // Call CreatureAI hook OnSpellStart
3583 if (Creature* caster = m_caster->ToCreature())
3584 if (caster->IsAIEnabled())
3585 caster->AI()->OnSpellStart(GetSpellInfo());
3586
3587 if (willCastDirectly)
3588 cast(true);
3589 }
3590
3591 return SPELL_CAST_OK;
3592}
3593
3595{
3597 return;
3598
3599 uint32 oldState = m_spellState;
3601
3602 m_autoRepeat = false;
3603 switch (oldState)
3604 {
3607 [[fallthrough]];
3609 SendInterrupted(0);
3611 break;
3612
3614 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
3615 if (targetInfo.MissCondition == SPELL_MISS_NONE)
3616 if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
3617 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3618
3620 SendInterrupted(0);
3622
3623 m_appliedMods.clear();
3624 break;
3625
3626 default:
3627 break;
3628 }
3629
3631 if (m_selfContainer && *m_selfContainer == this)
3632 *m_selfContainer = nullptr;
3633
3634 // originalcaster handles gameobjects/dynobjects for gob caster
3635 if (m_originalCaster)
3636 {
3638 if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
3640 }
3641
3642 //set state back so finish will be processed
3643 m_spellState = oldState;
3644
3646}
3647
3648void Spell::cast(bool skipCheck)
3649{
3650 Player* modOwner = m_caster->GetSpellModOwner();
3651 Spell* lastSpellMod = nullptr;
3652 if (modOwner)
3653 {
3654 lastSpellMod = modOwner->m_spellModTakingSpell;
3655 if (lastSpellMod)
3656 modOwner->SetSpellModTakingSpell(lastSpellMod, false);
3657 }
3658
3659 _cast(skipCheck);
3660
3661 if (lastSpellMod)
3662 modOwner->SetSpellModTakingSpell(lastSpellMod, true);
3663}
3664
3665void Spell::_cast(bool skipCheck)
3666{
3667 // update pointers base at GUIDs to prevent access to non-existed already object
3668 if (!UpdatePointers())
3669 {
3670 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3671 cancel();
3672 return;
3673 }
3674
3675 // cancel at lost explicit target during cast
3677 {
3678 cancel();
3679 return;
3680 }
3681
3682 if (Player* playerCaster = m_caster->ToPlayer())
3683 {
3684 // now that we've done the basic check, now run the scripts
3685 // should be done before the spell is actually executed
3686 sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
3687
3688 // As of 3.0.2 pets begin attacking their owner's target immediately
3689 // Let any pets know we've attacked something. Check DmgClass for harmful spells only
3690 // This prevents spells such as Hunter's Mark from triggering pet attack
3691 if (GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE)
3692 if (Unit* target = m_targets.GetUnitTarget())
3693 for (Unit* controlled : playerCaster->m_Controlled)
3694 if (Creature* cControlled = controlled->ToCreature())
3695 if (CreatureAI* controlledAI = cControlled->AI())
3696 controlledAI->OwnerAttacked(target);
3697 }
3698
3700
3701 // Should this be done for original caster?
3702 Player* modOwner = m_caster->GetSpellModOwner();
3703 if (modOwner)
3704 {
3705 // Set spell which will drop charges for triggered cast spells
3706 // if not successfully cast, will be remove in finish(false)
3707 modOwner->SetSpellModTakingSpell(this, true);
3708 }
3709
3711
3712 // skip check if done already (for instant cast spells for example)
3713 if (!skipCheck)
3714 {
3715 auto cleanupSpell = [this, modOwner](SpellCastResult res, int32* p1 = nullptr, int32* p2 = nullptr)
3716 {
3717 SendCastResult(res, p1, p2);
3718 SendInterrupted(0);
3719
3720 if (modOwner)
3721 modOwner->SetSpellModTakingSpell(this, false);
3722
3723 finish(res);
3724 SetExecutedCurrently(false);
3725 };
3726
3727 int32 param1 = 0, param2 = 0;
3728 SpellCastResult castResult = CheckCast(false, &param1, &param2);
3729 if (castResult != SPELL_CAST_OK)
3730 {
3731 cleanupSpell(castResult, &param1, &param2);
3732 return;
3733 }
3734
3735 // additional check after cast bar completes (must not be in CheckCast)
3736 // if trade not complete then remember it in trade data
3738 {
3739 if (modOwner)
3740 {
3741 if (TradeData* my_trade = modOwner->GetTradeData())
3742 {
3743 if (!my_trade->IsInAcceptProcess())
3744 {
3745 // Spell will be cast after completing the trade. Silently ignore at this place
3746 my_trade->SetSpell(m_spellInfo->Id, m_CastItem);
3747 cleanupSpell(SPELL_FAILED_DONT_REPORT);
3748 return;
3749 }
3750 }
3751 }
3752 }
3753
3754 // check diminishing returns (again, only after finish cast bar, tested on retail)
3755 if (Unit* target = m_targets.GetUnitTarget())
3756 {
3757 uint32 aura_effmask = 0;
3758 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3759 if (spellEffectInfo.IsUnitOwnedAuraEffect())
3760 aura_effmask |= 1 << spellEffectInfo.EffectIndex;
3761
3762 if (aura_effmask)
3763 {
3765 {
3767 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
3768 {
3770 {
3771 if (target->HasStrongerAuraWithDR(m_spellInfo, caster))
3772 {
3773 cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
3774 return;
3775 }
3776 }
3777 }
3778 }
3779 }
3780 }
3781 }
3782 // 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.
3783 if (Creature* creatureCaster = m_caster->ToCreature())
3784 if (!creatureCaster->GetTarget().IsEmpty() && !creatureCaster->HasUnitFlag(UNIT_FLAG_POSSESSED))
3785 if (WorldObject const* target = ObjectAccessor::GetUnit(*creatureCaster, creatureCaster->GetTarget()))
3786 creatureCaster->SetInFront(target);
3787
3789
3790 // Spell may be finished after target map check
3792 {
3793 SendInterrupted(0);
3794
3795 // cleanup after mod system
3796 // triggered spell pointer can be not removed in some cases
3798 m_caster->ToPlayer()->SetSpellModTakingSpell(this, false);
3799
3801 SetExecutedCurrently(false);
3802 return;
3803 }
3804
3805 if (Unit* unitCaster = m_caster->ToUnit())
3807 if (Creature* pet = ObjectAccessor::GetCreature(*m_caster, unitCaster->GetPetGUID()))
3808 pet->DespawnOrUnsummon();
3809
3811
3813
3814 // traded items have trade slot instead of guid in m_itemTargetGUID
3815 // set to real guid to be sent later to the client
3817
3818 if (Player* player = m_caster->ToPlayer())
3819 {
3821 {
3822 player->StartCriteria(CriteriaStartEvent::UseItem, m_CastItem->GetEntry());
3823 player->UpdateCriteria(CriteriaType::UseItem, m_CastItem->GetEntry());
3824 }
3825
3826 player->FailCriteria(CriteriaFailEvent::CastSpell, m_spellInfo->Id);
3827 player->StartCriteria(CriteriaStartEvent::CastSpell, m_spellInfo->Id);
3828 player->UpdateCriteria(CriteriaType::CastSpell, m_spellInfo->Id);
3829 }
3830
3832 {
3833 // Powers have to be taken before SendSpellGo
3834 TakePower();
3835 TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
3836 }
3837 else if (Item* targetItem = m_targets.GetItemTarget())
3838 {
3840 if (targetItem->GetOwnerGUID() != m_caster->GetGUID())
3841 TakeReagents();
3842 }
3843
3844 // CAST SPELL
3847
3849 {
3851 m_launchHandled = true;
3852 }
3853
3856
3857 // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
3858 SendSpellGo();
3859
3860 if (!m_spellInfo->IsChanneled())
3861 if (Creature* creatureCaster = m_caster->ToCreature())
3862 creatureCaster->ReleaseSpellFocus(this);
3863
3864 // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
3866 {
3867 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3868 // in case delayed spell remove item at cast delay start
3869 TakeCastItem();
3870
3871 // Okay, maps created, now prepare flags
3872 m_immediateHandled = false;
3874 SetDelayStart(0);
3875
3876 if (Unit* unitCaster = m_caster->ToUnit())
3877 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
3878 unitCaster->ClearUnitState(UNIT_STATE_CASTING);
3879 }
3880 else
3881 {
3882 // Immediate spell, no big deal
3884 }
3885
3887
3888 if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(SPELL_LINK_CAST, m_spellInfo->Id))
3889 {
3890 for (int32 id : *spell_triggered)
3891 {
3892 if (id < 0)
3893 {
3894 if (Unit* unitCaster = m_caster->ToUnit())
3895 unitCaster->RemoveAurasDueToSpell(-id);
3896 }
3897 else
3899 .SetTriggeringSpell(this));
3900 }
3901 }
3902
3903 if (modOwner)
3904 {
3905 modOwner->SetSpellModTakingSpell(this, false);
3906
3907 //Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
3909 {
3912 }
3913 }
3914
3915 SetExecutedCurrently(false);
3916
3917 if (!m_originalCaster)
3918 return;
3919
3920 // Handle procs on cast
3921 ProcFlagsInit procAttacker = m_procAttacker;
3922 if (!procAttacker)
3923 {
3925 {
3926 if (IsPositive())
3927 procAttacker |= PROC_FLAG_DEAL_HELPFUL_PERIODIC;
3928 else
3929 procAttacker |= PROC_FLAG_DEAL_HARMFUL_PERIODIC;
3930 }
3932 {
3933 if (IsPositive())
3934 procAttacker |= PROC_FLAG_DEAL_HELPFUL_ABILITY;
3935 else
3936 procAttacker |= PROC_FLAG_DEAL_HARMFUL_ABILITY;
3937 }
3938 else
3939 {
3940 if (IsPositive())
3941 procAttacker |= PROC_FLAG_DEAL_HELPFUL_SPELL;
3942 else
3943 procAttacker |= PROC_FLAG_DEAL_HARMFUL_SPELL;
3944 }
3945 }
3946
3947 procAttacker |= PROC_FLAG_2_CAST_SUCCESSFUL;
3948
3949 ProcFlagsHit hitMask = m_hitMask;
3950 if (!(hitMask & PROC_HIT_CRITICAL))
3951 hitMask |= PROC_HIT_NORMAL;
3952
3955
3956 Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
3957
3958 // Call CreatureAI hook OnSpellCast
3959 if (Creature* caster = m_originalCaster->ToCreature())
3960 if (caster->IsAIEnabled())
3961 caster->AI()->OnSpellCast(GetSpellInfo());
3962}
3963
3964template <class Container>
3965void Spell::DoProcessTargetContainer(Container& targetContainer)
3966{
3967 for (TargetInfoBase& target : targetContainer)
3968 target.PreprocessTarget(this);
3969
3970 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3971 for (TargetInfoBase& target : targetContainer)
3972 if (target.EffectMask & (1 << spellEffectInfo.EffectIndex))
3973 target.DoTargetSpellHit(this, spellEffectInfo);
3974
3975 for (TargetInfoBase& target : targetContainer)
3976 target.DoDamageAndTriggers(this);
3977}
3978
3980{
3981 // start channeling if applicable
3982 if (m_spellInfo->IsChanneled())
3983 {
3984 int32 duration = m_spellInfo->GetDuration();
3985 if (duration > 0 || m_spellValue->Duration)
3986 {
3987 if (!m_spellValue->Duration)
3988 {
3989 // First mod_duration then haste - see Missile Barrage
3990 // Apply duration mod
3991 if (Player* modOwner = m_caster->GetSpellModOwner())
3992 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Duration, duration);
3993
3994 duration *= m_spellValue->DurationMul;
3995
3996 // Apply haste mods
3997 m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
3998 }
3999 else
4000 duration = *m_spellValue->Duration;
4001
4002 m_channeledDuration = duration;
4003 SendChannelStart(duration);
4004 }
4005 else if (duration == -1)
4006 SendChannelStart(duration);
4007
4008 if (duration != 0)
4009 {
4011 // GameObjects shouldn't cast channeled spells
4013 }
4014 }
4015
4017
4018 // process immediate effects (items, ground, etc.) also initialize some variables
4020
4021 // consider spell hit for some spells without target, so they may proc on finish phase correctly
4022 if (m_UniqueTargetInfo.empty())
4023 {
4026 }
4027 else
4029
4031
4033
4035
4036 // spell is finished, perform some last features of the spell here
4038
4039 // Remove used for cast item if need (it can be already NULL after TakeReagents call
4040 TakeCastItem();
4041
4043 finish(); // successfully finish spell cast (not last in case autorepeat or channel spell)
4044}
4045
4047{
4048 if (!UpdatePointers())
4049 {
4050 // finish the spell if UpdatePointers() returned false, something wrong happened there
4052 return 0;
4053 }
4054
4055 // when spell has a single missile we hit all targets (except caster) at the same time
4056 bool single_missile = m_targets.HasDst();
4057 bool ignoreTargetInfoTimeDelay = single_missile;
4058 uint64 next_time = 0;
4059
4060 if (!m_launchHandled)
4061 {
4062 uint64 launchMoment = uint64(std::floor(m_spellInfo->LaunchDelay * 1000.0f));
4063 if (launchMoment > t_offset)
4064 return launchMoment;
4065
4067 m_launchHandled = true;
4068 }
4069
4070 if (m_delayMoment > t_offset)
4071 {
4072 ignoreTargetInfoTimeDelay = false;
4073 next_time = m_delayMoment;
4074 }
4075
4076 Player* modOwner = m_caster->GetSpellModOwner();
4077 if (modOwner)
4078 modOwner->SetSpellModTakingSpell(this, true);
4079
4081
4082 if (!m_immediateHandled && m_delayMoment <= t_offset)
4083 {
4085 m_immediateHandled = true;
4086 }
4087
4088 // 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)
4089 {
4090 std::vector<TargetInfo> delayedTargets;
4091 m_UniqueTargetInfo.erase(std::remove_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo& target) -> bool
4092 {
4093 if (ignoreTargetInfoTimeDelay || target.TimeDelay <= t_offset)
4094 {
4095 target.TimeDelay = t_offset;
4096 delayedTargets.emplace_back(std::move(target));
4097 return true;
4098 }
4099 else if (!single_missile && (next_time == 0 || target.TimeDelay < next_time))
4100 next_time = target.TimeDelay;
4101
4102 return false;
4103 }), m_UniqueTargetInfo.end());
4104
4105 DoProcessTargetContainer(delayedTargets);
4106 }
4107
4108 // now recheck gameobject targeting correctness
4109 {
4110 std::vector<GOTargetInfo> delayedGOTargets;
4111 m_UniqueGOTargetInfo.erase(std::remove_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [&](GOTargetInfo& goTarget) -> bool
4112 {
4113 if (ignoreTargetInfoTimeDelay || goTarget.TimeDelay <= t_offset)
4114 {
4115 goTarget.TimeDelay = t_offset;
4116 delayedGOTargets.emplace_back(std::move(goTarget));
4117 return true;
4118 }
4119 else if (!single_missile && (next_time == 0 || goTarget.TimeDelay < next_time))
4120 next_time = goTarget.TimeDelay;
4121
4122 return false;
4123 }), m_UniqueGOTargetInfo.end());
4124
4125 DoProcessTargetContainer(delayedGOTargets);
4126 }
4127
4129
4130 if (modOwner)
4131 modOwner->SetSpellModTakingSpell(this, false);
4132
4133 // All targets passed - need finish phase
4134 if (next_time == 0)
4135 {
4136 // spell is finished, perform some last features of the spell here
4138
4139 finish(); // successfully finish spell cast
4140
4141 // return zero, spell is finished now
4142 return 0;
4143 }
4144 else
4145 {
4146 // spell is unfinished, return next execution time
4147 return next_time;
4148 }
4149}
4150
4152{
4153 // handle some immediate features of the spell here
4155
4156 // handle effects with SPELL_EFFECT_HANDLE_HIT mode
4157 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
4158 {
4159 // don't do anything for empty effect
4160 if (!spellEffectInfo.IsEffect())
4161 continue;
4162
4163 // call effect handlers to handle destination hit
4164 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
4165 }
4166
4167 // process items
4169}
4170
4172{
4173 if (Unit* unitCaster = m_caster->ToUnit())
4175 unitCaster->SetLastExtraAttackSpell(m_spellInfo->Id);
4176
4177 // Handle procs on finish
4178 if (!m_originalCaster)
4179 return;
4180
4181 ProcFlagsInit procAttacker = m_procAttacker;
4182 if (!procAttacker)
4183 {
4185 {
4186 if (IsPositive())
4187 procAttacker |= PROC_FLAG_DEAL_HELPFUL_PERIODIC;
4188 else
4189 procAttacker |= PROC_FLAG_DEAL_HARMFUL_PERIODIC;
4190 }
4192 {
4193 if (IsPositive())
4194 procAttacker |= PROC_FLAG_DEAL_HELPFUL_ABILITY;
4195 else
4196 procAttacker |= PROC_FLAG_DEAL_HARMFUL_ABILITY;
4197 }
4198 else
4199 {
4200 if (IsPositive())
4201 procAttacker |= PROC_FLAG_DEAL_HELPFUL_SPELL;
4202 else
4203 procAttacker |= PROC_FLAG_DEAL_HARMFUL_SPELL;
4204 }
4205 }
4206
4208}
4209
4211{
4212 if (!m_caster->IsUnit())
4213 return;
4214
4215 if (m_CastItem)
4217 else
4219
4220 if (IsAutoRepeat())
4222}
4223
4224void Spell::update(uint32 difftime)
4225{
4226 // update pointers based at it's GUIDs
4227 if (!UpdatePointers())
4228 {
4229 // cancel the spell if UpdatePointers() returned false, something wrong happened there
4230 cancel();
4231 return;
4232 }
4233
4235 {
4236 TC_LOG_DEBUG("spells", "Spell {} is cancelled due to removal of target.", m_spellInfo->Id);
4237 cancel();
4238 return;
4239 }
4240
4241 // check if the player caster has moved before the spell finished
4242 // with the exception of spells affected with SPELL_AURA_CAST_WHILE_WALKING effect
4243 if (m_timer != 0 && m_caster->IsUnit() && m_caster->ToUnit()->isMoving() && CheckMovement() != SPELL_CAST_OK)
4244 {
4245 // if charmed by creature, trust the AI not to cheat and allow the cast to proceed
4246 // @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now
4247 // however, checking what type of movement the spline is for every single spline would be really expensive
4249 cancel();
4250 }
4251
4252 switch (m_spellState)
4253 {
4255 {
4256 if (m_timer > 0)
4257 {
4258 if (difftime >= (uint32)m_timer)
4259 m_timer = 0;
4260 else
4261 m_timer -= difftime;
4262 }
4263
4265 // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
4266 cast(!m_casttime);
4267 break;
4268 }
4270 {
4271 if (m_timer)
4272 {
4273 // check if there are alive targets left
4275 {
4276 TC_LOG_DEBUG("spells", "Channeled spell {} is removed due to lack of targets", m_spellInfo->Id);
4277 m_timer = 0;
4278
4279 // Also remove applied auras
4280 for (TargetInfo const& target : m_UniqueTargetInfo)
4281 if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
4282 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
4283 }
4284
4285 if (m_timer > 0)
4286 {
4287 if (difftime >= (uint32)m_timer)
4288 m_timer = 0;
4289 else
4290 m_timer -= difftime;
4291 }
4292 }
4293
4294 if (m_timer == 0)
4295 {
4297 finish();
4298
4299 // 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
4300 if (Creature* creatureCaster = m_caster->ToCreature())
4301 if (creatureCaster->IsAIEnabled())
4302 creatureCaster->AI()->OnChannelFinished(m_spellInfo);
4303 }
4304 break;
4305 }
4306 default:
4307 break;
4308 }
4309}
4310
4312{
4314 return;
4316
4317 if (!m_caster)
4318 return;
4319
4320 Unit* unitCaster = m_caster->ToUnit();
4321 if (!unitCaster)
4322 return;
4323
4324 // successful cast of the initial autorepeat spell is moved to idle state so that it is not deleted as long as autorepeat is active
4325 if (IsAutoRepeat() && unitCaster->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) == this)
4327
4328 if (m_spellInfo->IsChanneled())
4329 unitCaster->UpdateInterruptMask();
4330
4331 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
4333
4334 // Unsummon summon as possessed creatures on spell cancel
4335 if (m_spellInfo->IsChanneled() && unitCaster->GetTypeId() == TYPEID_PLAYER)
4336 {
4337 if (Unit* charm = unitCaster->GetCharmed())
4338 if (charm->GetTypeId() == TYPEID_UNIT
4339 && charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
4340 && charm->m_unitData->CreatedBySpell == int32(m_spellInfo->Id))
4341 ((Puppet*)charm)->UnSummon();
4342 }
4343
4344 if (Creature* creatureCaster = unitCaster->ToCreature())
4345 creatureCaster->ReleaseSpellFocus(this);
4346
4348
4349 if (result != SPELL_CAST_OK)
4350 {
4351 // on failure (or manual cancel) send TraitConfigCommitFailed to revert talent UI saved config selection
4353 if (WorldPackets::Traits::TraitConfig const* traitConfig = std::any_cast<WorldPackets::Traits::TraitConfig>(&m_customArg))
4355
4356 return;
4357 }
4358
4359 if (unitCaster->GetTypeId() == TYPEID_UNIT && unitCaster->IsSummon())
4360 {
4361 // Unsummon statue
4362 uint32 spell = unitCaster->m_unitData->CreatedBySpell;
4363 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell, GetCastDifficulty());
4364 if (spellInfo && spellInfo->IconFileDataId == 134230)
4365 {
4366 TC_LOG_DEBUG("spells", "Statue {} is unsummoned in spell {} finish", unitCaster->GetGUID().ToString(), m_spellInfo->Id);
4367 // Avoid infinite loops with setDeathState(JUST_DIED) being called over and over
4368 // It might make sense to do this check in Unit::setDeathState() and all overloaded functions
4369 if (unitCaster->getDeathState() != JUST_DIED)
4370 unitCaster->setDeathState(JUST_DIED);
4371 return;
4372 }
4373 }
4374
4375 // potions disabled by client, send event "not in combat" if need
4376 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4377 {
4379 unitCaster->ToPlayer()->UpdatePotionCooldown(this);
4380 }
4381
4382 // Stop Attack for some spells
4384 unitCaster->AttackStop();
4385}
4386
4387template<class T>
4388inline void FillSpellCastFailedArgs(T& packet, ObjectGuid castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/, Player* caster)
4389{
4390 packet.CastID = castId;
4391 packet.SpellID = spellInfo->Id;
4392 packet.Reason = result;
4393
4394 switch (result)
4395 {
4397 if (param1)
4398 packet.FailedArg1 = *param1;
4399 else
4400 packet.FailedArg1 = 0; // unknown (value 1 update cooldowns on client flag)
4401 break;
4403 if (param1)
4404 packet.FailedArg1 = *param1;
4405 else
4406 packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
4407 break;
4408 case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
4409 if (param1)
4410 packet.FailedArg1 = *param1;
4411 else
4412 {
4413 // hardcode areas limitation case
4414 switch (spellInfo->Id)
4415 {
4416 case 41617: // Cenarion Mana Salve
4417 case 41619: // Cenarion Healing Salve
4418 packet.FailedArg1 = 3905;
4419 break;
4420 case 41618: // Bottled Nethergon Energy
4421 case 41620: // Bottled Nethergon Vapor
4422 packet.FailedArg1 = 3842;
4423 break;
4424 case 45373: // Bloodberry Elixir
4425 packet.FailedArg1 = 4075;
4426 break;
4427 default: // default case (don't must be)
4428 packet.FailedArg1 = 0;
4429 break;
4430 }
4431 }
4432 break;
4434 if (param1)
4435 {
4436 packet.FailedArg1 = *param1;
4437 if (param2)
4438 packet.FailedArg2 = *param2;
4439 }
4440 else
4441 {
4442 if (spellInfo->Totem[0])
4443 packet.FailedArg1 = spellInfo->Totem[0];
4444 if (spellInfo->Totem[1])
4445 packet.FailedArg2 = spellInfo->Totem[1];
4446 }
4447 break;
4449 if (param1)
4450 {
4451 packet.FailedArg1 = *param1;
4452 if (param2)
4453 packet.FailedArg2 = *param2;
4454 }
4455 else
4456 {
4457 if (spellInfo->TotemCategory[0])
4458 packet.FailedArg1 = spellInfo->TotemCategory[0];
4459 if (spellInfo->TotemCategory[1])
4460 packet.FailedArg2 = spellInfo->TotemCategory[1];
4461 }
4462 break;
4466 if (param1 && param2)
4467 {
4468 packet.FailedArg1 = *param1;
4469 packet.FailedArg2 = *param2;
4470 }
4471 else
4472 {
4473 packet.FailedArg1 = spellInfo->EquippedItemClass;
4474 packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
4475 }
4476 break;
4478 {
4479 if (param1)
4480 packet.FailedArg1 = *param1;
4481 else
4482 {
4483 uint32 item = 0;
4484 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4485 {
4486 if (uint32 itemType = spellEffectInfo.ItemType)
4487 {
4488 item = itemType;
4489 break;
4490 }
4491 }
4492
4493 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
4494 if (proto && proto->GetItemLimitCategory())
4495 packet.FailedArg1 = proto->GetItemLimitCategory();
4496 }
4497 break;
4498 }
4500 if (param1)
4501 packet.FailedArg1 = *param1;
4502 else
4503 packet.FailedArg1 = spellInfo->GetAllEffectsMechanicMask(); // SpellMechanic.dbc id
4504 break;
4506 if (param1)
4507 packet.FailedArg1 = *param1;
4508 else
4509 packet.FailedArg1 = spellInfo->EquippedItemSubClassMask; // seems correct...
4510 break;
4512 if (param1 && param2)
4513 {
4514 packet.FailedArg1 = *param1;
4515 packet.FailedArg2 = *param2;
4516 }
4517 else
4518 {
4519 packet.FailedArg1 = 0; // Item id
4520 packet.FailedArg2 = 0; // Item count?
4521 }
4522 break;
4524 if (param1 && param2)
4525 {
4526 packet.FailedArg1 = *param1;
4527 packet.FailedArg2 = *param2;
4528 }
4529 else
4530 {
4531 packet.FailedArg1 = 0; // SkillLine.dbc id
4532 packet.FailedArg2 = 0; // required skill value
4533 }
4534 break;
4536 if (param1)
4537 packet.FailedArg1 = *param1;
4538 else
4539 packet.FailedArg1 = 0; // required fishing skill
4540 break;
4542 packet.FailedArg1 = customError;
4543 break;
4545 if (param1)
4546 packet.FailedArg1 = *param1;
4547 else
4548 packet.FailedArg1 = 0; // Unknown
4549 break;
4551 {
4552 if (param1)
4553 packet.FailedArg1 = *param1;
4554 else
4555 {
4556 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
4557 {
4558 if (spellInfo->Reagent[i] <= 0)
4559 continue;
4560
4561 uint32 itemid = spellInfo->Reagent[i];
4562 uint32 itemcount = spellInfo->ReagentCount[i];
4563
4564 if (caster && !caster->HasItemCount(itemid, itemcount))
4565 {
4566 packet.FailedArg1 = itemid; // first missing item
4567 break;
4568 }
4569 }
4570 }
4571
4572 if (param2)
4573 packet.FailedArg2 = *param2;
4574 else if (!param1)
4575 {
4576 for (SpellReagentsCurrencyEntry const* reagentsCurrency : spellInfo->ReagentsCurrency)
4577 {
4578 if (caster && !caster->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount))
4579 {
4580 packet.FailedArg1 = -1;
4581 packet.FailedArg2 = reagentsCurrency->CurrencyTypesID;
4582 break;
4583 }
4584 }
4585 }
4586
4587 break;
4588 }
4590 {
4591 ASSERT(param1);
4592 packet.FailedArg1 = *param1;
4593 break;
4594 }
4595 // TODO: SPELL_FAILED_NOT_STANDING
4596 default:
4597 break;
4598 }
4599}
4600
4601void Spell::SendCastResult(SpellCastResult result, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
4602{
4603 if (result == SPELL_CAST_OK)
4604 return;
4605
4606 Player const* receiver = m_caster->ToPlayer();
4608 if (Player const* target = Object::ToPlayer(m_targets.GetUnitTarget()))
4609 receiver = target;
4610
4611 if (!receiver)
4612 return;
4613
4614 if (receiver->IsLoading()) // don't send cast results at loading time
4615 return;
4616
4618 result = SPELL_FAILED_DONT_REPORT;
4619
4621 castFailed.Visual = m_SpellVisual;
4622 FillSpellCastFailedArgs(castFailed, m_castId, m_spellInfo, result, m_customError, param1, param2, m_caster->ToPlayer());
4623 receiver->SendDirectMessage(castFailed.Write());
4624}
4625
4626void Spell::SendPetCastResult(SpellCastResult result, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
4627{
4628 if (result == SPELL_CAST_OK)
4629 return;
4630
4631 Unit* owner = m_caster->GetCharmerOrOwner();
4632 if (!owner || owner->GetTypeId() != TYPEID_PLAYER)
4633 return;
4634
4636 result = SPELL_FAILED_DONT_REPORT;
4637
4639 FillSpellCastFailedArgs(petCastFailed, m_castId, m_spellInfo, result, SPELL_CUSTOM_ERROR_NONE, param1, param2, owner->ToPlayer());
4640 owner->ToPlayer()->SendDirectMessage(petCastFailed.Write());
4641}
4642
4643void 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*/)
4644{
4645 if (result == SPELL_CAST_OK)
4646 return;
4647
4649 packet.Visual = spellVisual;
4650 FillSpellCastFailedArgs(packet, cast_count, spellInfo, result, customError, param1, param2, caster);
4651 caster->SendDirectMessage(packet.Write());
4652}
4653
4655{
4656 if (result == MountResult::Ok)
4657 return;
4658
4659 if (!m_caster->IsPlayer())
4660 return;
4661
4662 Player* caster = m_caster->ToPlayer();
4663 if (caster->IsLoading()) // don't send mount results at loading time
4664 return;
4665
4667 packet.Result = AsUnderlyingType(result);
4668 caster->SendDirectMessage(packet.Write());
4669}
4670
4672{
4673 if (!IsNeedSendToClient())
4674 return;
4675
4676 TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id={}", m_spellInfo->Id);
4677
4678 uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
4679 uint32 schoolImmunityMask = 0;
4680 uint32 mechanicImmunityMask = 0;
4681 if (Unit* unitCaster = m_caster->ToUnit())
4682 {
4683 schoolImmunityMask = m_timer!= 0 ? unitCaster->GetSchoolImmunityMask() : 0;
4684 mechanicImmunityMask = m_timer != 0 ? m_spellInfo->GetMechanicImmunityMask(unitCaster) : 0;
4685 }
4686
4687 if (schoolImmunityMask || mechanicImmunityMask)
4688 castFlags |= CAST_FLAG_IMMUNITY;
4689
4691 castFlags |= CAST_FLAG_PENDING;
4692
4694 castFlags |= CAST_FLAG_PROJECTILE;
4695
4696 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4698 && std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end())
4699 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4700
4702 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4703
4705 castFlags |= CAST_FLAG_HEAL_PREDICTION;
4706
4708 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4709
4710 if (m_CastItem)
4711 castData.CasterGUID = m_CastItem->GetGUID();
4712 else
4713 castData.CasterGUID = m_caster->GetGUID();
4714
4715 castData.CasterUnit = m_caster->GetGUID();
4716 castData.CastID = m_castId;
4718 castData.SpellID = m_spellInfo->Id;
4719 castData.Visual = m_SpellVisual;
4720 castData.CastFlags = castFlags;
4721 castData.CastFlagsEx = m_castFlagsEx;
4722 castData.CastTime = m_casttime;
4723
4724 m_targets.Write(castData.Target);
4725
4726 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4727 {
4728 for (SpellPowerCost const& cost : m_powerCost)
4729 {
4731 powerData.Type = cost.Power;
4732 powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
4733 castData.RemainingPower.push_back(powerData);
4734 }
4735 }
4736
4737 if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
4738 {
4739 castData.RemainingRunes.emplace();
4740
4741 //TODO: There is a crash caused by a spell with CAST_FLAG_RUNE_LIST casted by a creature
4742 //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
4743 if (Player* player = m_caster->ToPlayer())
4744 {
4745 castData.RemainingRunes->Start = m_runesState; // runes state before
4746 castData.RemainingRunes->Count = player->GetRunesState(); // runes state after
4747 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4748 {
4749 // float casts ensure the division is performed on floats as we need float result
4750 float baseCd = float(player->GetRuneBaseCooldown());
4751 castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
4752 }
4753 }
4754 else
4755 {
4756 castData.RemainingRunes->Start = 0;
4757 castData.RemainingRunes->Count = 0;
4758 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4759 castData.RemainingRunes->Cooldowns.push_back(0);
4760 }
4761 }
4762
4763 if (castFlags & CAST_FLAG_PROJECTILE)
4765
4766 if (castFlags & CAST_FLAG_IMMUNITY)
4767 {
4768 castData.Immunities.School = schoolImmunityMask;
4769 castData.Immunities.Value = mechanicImmunityMask;
4770 }
4771
4772 if (castFlags & CAST_FLAG_HEAL_PREDICTION)
4773 UpdateSpellHealPrediction(castData.Predict, false);
4774
4775 m_caster->SendMessageToSet(packet.Write(), true);
4776}
4777
4779{
4780 // not send invisible spell casting
4781 if (!IsNeedSendToClient())
4782 return;
4783
4784 TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id={}", m_spellInfo->Id);
4785
4786 uint32 castFlags = CAST_FLAG_UNKNOWN_9;
4787
4788 // triggered spells with spell visual != 0
4790 castFlags |= CAST_FLAG_PENDING;
4791
4793 castFlags |= CAST_FLAG_PROJECTILE; // arrows/bullets visual
4794
4795 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4797 && std::find_if(m_powerCost.begin(), m_powerCost.end(), [](SpellPowerCost const& cost) { return cost.Power != POWER_HEALTH; }) != m_powerCost.end())
4798 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4799
4800 if ((m_caster->GetTypeId() == TYPEID_PLAYER)
4804 {
4805 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4806 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4807 }
4808
4809 if (m_targets.HasTraj())
4810 castFlags |= CAST_FLAG_ADJUST_MISSILE;
4811
4813 castFlags |= CAST_FLAG_NO_GCD;
4814
4816 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4817 if (m_CastItem)
4818 castData.CasterGUID = m_CastItem->GetGUID();
4819 else
4820 castData.CasterGUID = m_caster->GetGUID();
4821
4822 castData.CasterUnit = m_caster->GetGUID();
4823 castData.CastID = m_castId;
4825 castData.SpellID = m_spellInfo->Id;
4826 castData.Visual = m_SpellVisual;
4827 castData.CastFlags = castFlags;
4828 castData.CastFlagsEx = m_castFlagsEx;
4829 castData.CastTime = getMSTime();
4830
4832
4833 m_targets.Write(castData.Target);
4834
4835 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4836 {
4837 for (SpellPowerCost const& cost : m_powerCost)
4838 {
4840 powerData.Type = cost.Power;
4841 powerData.Cost = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(cost.Power);
4842 castData.RemainingPower.push_back(powerData);
4843 }
4844 }
4845
4846 if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list
4847 {
4848 castData.RemainingRunes.emplace();
4849
4850 Player* player = ASSERT_NOTNULL(m_caster->ToPlayer());
4851 castData.RemainingRunes->Start = m_runesState; // runes state before
4852 castData.RemainingRunes->Count = player->GetRunesState(); // runes state after
4853 for (uint8 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
4854 {
4855 // float casts ensure the division is performed on floats as we need float result
4856 float baseCd = float(player->GetRuneBaseCooldown());
4857 castData.RemainingRunes->Cooldowns.push_back((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed
4858 }
4859 }
4860
4861 if (castFlags & CAST_FLAG_ADJUST_MISSILE)
4862 {
4865 }
4866
4867 packet.LogData.Initialize(this);
4868
4870}
4871
4874{
4875 // This function also fill data for channeled spells:
4876 // m_needAliveTargetMask req for stop channeling if one target die
4877 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
4878 {
4879 if (targetInfo.EffectMask == 0) // No effect apply - all immune add state
4880 // possibly SPELL_MISS_IMMUNE2 for this??
4881 targetInfo.MissCondition = SPELL_MISS_IMMUNE2;
4882
4883 if (targetInfo.MissCondition == SPELL_MISS_NONE || (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))) // Add only hits and partial blocked
4884 {
4885 data.HitTargets.push_back(targetInfo.TargetGUID);
4886 data.HitStatus.emplace_back(SPELL_MISS_NONE);
4887
4888 m_channelTargetEffectMask |= targetInfo.EffectMask;
4889 }
4890 else // misses
4891 {
4892 data.MissTargets.push_back(targetInfo.TargetGUID);
4893 data.MissStatus.emplace_back(targetInfo.MissCondition, targetInfo.ReflectResult);
4894 }
4895 }
4896
4897 for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo)
4898 data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
4899
4900 for (CorpseTargetInfo const& targetInfo : m_UniqueCorpseTargetInfo)
4901 data.HitTargets.push_back(targetInfo.TargetGUID); // Always hits
4902
4903 // Reset m_needAliveTargetMask for non channeled spell
4904 if (!m_spellInfo->IsChanneled())
4906}
4907
4909{
4910 uint32 ammoInventoryType = 0;
4911 uint32 ammoDisplayID = 0;
4912
4913 if (Player const* playerCaster = m_caster->ToPlayer())
4914 {
4915 Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK);
4916 if (pItem)
4917 {
4918 ammoInventoryType = pItem->GetTemplate()->GetInventoryType();
4919 if (ammoInventoryType == INVTYPE_THROWN)
4920 ammoDisplayID = pItem->GetDisplayId(playerCaster);
4921 else if (playerCaster->HasAura(46699)) // Requires No Ammo
4922 {
4923 ammoDisplayID = 5996; // normal arrow
4924 ammoInventoryType = INVTYPE_AMMO;
4925 }
4926 }
4927 }
4928 else if (Unit const* unitCaster = m_caster->ToUnit())
4929 {
4930 uint32 nonRangedAmmoDisplayID = 0;
4931 uint32 nonRangedAmmoInventoryType = 0;
4932 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
4933 {
4934 if (uint32 item_id = unitCaster->GetVirtualItemId(i))
4935 {
4936 if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
4937 {
4938 if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
4939 {
4940 switch (itemEntry->SubclassID)
4941 {
4943 ammoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i));
4944 ammoInventoryType = itemEntry->InventoryType;
4945 break;
4948 ammoDisplayID = 5996; // is this need fixing?
4949 ammoInventoryType = INVTYPE_AMMO;
4950 break;
4952 ammoDisplayID = 5998; // is this need fixing?
4953 ammoInventoryType = INVTYPE_AMMO;
4954 break;
4955 default:
4956 nonRangedAmmoDisplayID = sDB2Manager.GetItemDisplayId(item_id, unitCaster->GetVirtualItemAppearanceMod(i));
4957 nonRangedAmmoInventoryType = itemEntry->InventoryType;
4958 break;
4959 }
4960
4961 if (ammoDisplayID)
4962 break;
4963 }
4964 }
4965 }
4966 }
4967
4968 if (!ammoDisplayID && !ammoInventoryType)
4969 {
4970 ammoDisplayID = nonRangedAmmoDisplayID;
4971 ammoInventoryType = nonRangedAmmoInventoryType;
4972 }
4973 }
4974
4975 return ammoDisplayID;
4976}
4977
4978static std::pair<int32, SpellHealPredictionType> CalcPredictedHealing(SpellInfo const* spellInfo, Unit const* unitCaster, Unit* target, uint32 castItemEntry, int32 castItemLevel, Spell* spell, bool withPeriodic)
4979{
4980 int32 points = 0;
4982 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4983 {
4984 switch (spellEffectInfo.Effect)
4985 {
4986 case SPELL_EFFECT_HEAL:
4988 points += unitCaster->SpellHealingBonusDone(target,
4989 spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
4990 DIRECT_DAMAGE, spellEffectInfo, 1, spell);
4991
4992 if (target != unitCaster && (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER || spellEffectInfo.TargetB.GetTarget() == TARGET_UNIT_CASTER))
4993 type = SPELL_HEAL_PREDICTION_TARGET_AND_CASTER; // Binding Heal-like spells
4994 else if (spellEffectInfo.TargetA.GetCheckType() == TARGET_CHECK_PARTY || spellEffectInfo.TargetB.GetCheckType() == TARGET_CHECK_PARTY)
4995 type = SPELL_HEAL_PREDICTION_TARGET_PARTY; // Prayer of Healing (old party-wide targeting)
4996 break;
4997 default:
4998 break;
4999 }
5000
5001 if (withPeriodic)
5002 {
5003 switch (spellEffectInfo.ApplyAuraName)
5004 {
5007 points += unitCaster->SpellHealingBonusDone(target,
5008 spellInfo, spellEffectInfo.CalcValue(unitCaster, nullptr, target, nullptr, castItemEntry, castItemLevel),
5009 DIRECT_DAMAGE, spellEffectInfo, 1, spell) * spellInfo->GetMaxTicks();
5010 break;
5012 if (SpellInfo const* triggered = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, spellInfo->Difficulty))
5013 points += CalcPredictedHealing(triggered, unitCaster, target, castItemEntry, castItemLevel, nullptr, withPeriodic).first;
5014 break;
5015 default:
5016 break;
5017 }
5018 }
5019 }
5020
5021 return { points, type };
5022}
5023
5025{
5026 healPrediction.BeaconGUID = ObjectGuid::Empty;
5027 healPrediction.Points = 0;
5028 healPrediction.Type = SPELL_HEAL_PREDICTION_TARGET;
5029
5030 Unit const* unitCaster = m_caster->ToUnit();
5031
5032 if (Unit* target = m_targets.GetUnitTarget())
5033 {
5034 auto [points, type] = CalcPredictedHealing(m_spellInfo, unitCaster, target, m_castItemEntry, m_castItemLevel, this, withPeriodic);
5035 healPrediction.Points = points;
5036 healPrediction.Type = type;
5037 }
5038
5039 static constexpr uint32 beaconSpellId = 53651;
5040
5041 if (healPrediction.Type == SPELL_HEAL_PREDICTION_TARGET && unitCaster->HasAura(beaconSpellId, unitCaster->GetGUID()))
5042 {
5043 auto beacon = std::find_if(unitCaster->GetSingleCastAuras().begin(), unitCaster->GetSingleCastAuras().end(), [](Aura const* aura)
5044 {
5045 return aura->GetSpellInfo()->GetEffects().size() > EFFECT_1 && aura->GetSpellInfo()->GetEffect(EFFECT_1).TriggerSpell == beaconSpellId;
5046 });
5047
5048 if (beacon != unitCaster->GetSingleCastAuras().end())
5049 {
5050 healPrediction.BeaconGUID = (*beacon)->GetOwner()->GetGUID();
5052 }
5053 }
5054}
5055
5057{
5058 if (_executeLogEffects.empty())
5059 return;
5060
5062 spellExecuteLog.Caster = m_caster->GetGUID();
5063 spellExecuteLog.SpellID = m_spellInfo->Id;
5064 spellExecuteLog.Effects = &_executeLogEffects;
5065 spellExecuteLog.LogData.Initialize(this);
5066
5067 m_caster->SendCombatLogMessage(&spellExecuteLog);
5068
5069 _executeLogEffects.clear();
5070}
5071
5073{
5074 auto itr = std::find_if(_executeLogEffects.begin(), _executeLogEffects.end(), [effect](SpellLogEffect& log)
5075 {
5076 return log.Effect == effect;
5077 });
5078 if (itr != _executeLogEffects.end())
5079 return *itr;
5080
5081 _executeLogEffects.emplace_back();
5082 _executeLogEffects.back().Effect = effect;
5083 return _executeLogEffects.back();
5084}
5085
5086void Spell::ExecuteLogEffectTakeTargetPower(SpellEffectName effect, Unit* target, uint32 powerType, uint32 points, float amplitude)
5087{
5088 SpellLogEffectPowerDrainParams spellLogEffectPowerDrainParams;
5089
5090 spellLogEffectPowerDrainParams.Victim = target->GetGUID();
5091 spellLogEffectPowerDrainParams.Points = points;
5092 spellLogEffectPowerDrainParams.PowerType = powerType;
5093 spellLogEffectPowerDrainParams.Amplitude = amplitude;
5094
5095 GetExecuteLogEffectTargets(effect, &SpellLogEffect::PowerDrainTargets).push_back(spellLogEffectPowerDrainParams);
5096}
5097
5099{
5100 SpellLogEffectExtraAttacksParams spellLogEffectExtraAttacksParams;
5101 spellLogEffectExtraAttacksParams.Victim = victim->GetGUID();
5102 spellLogEffectExtraAttacksParams.NumAttacks = numAttacks;
5103
5104 GetExecuteLogEffectTargets(effect, &SpellLogEffect::ExtraAttacksTargets).push_back(spellLogEffectExtraAttacksParams);
5105}
5106
5108{
5110 data.Caster = m_caster->GetGUID();
5111 data.Victim = victim->GetGUID();
5113 data.SpellID = spellId;
5114
5115 m_caster->SendMessageToSet(data.Write(), true);
5116}
5117
5119{
5120 SpellLogEffectDurabilityDamageParams spellLogEffectDurabilityDamageParams;
5121 spellLogEffectDurabilityDamageParams.Victim = victim->GetGUID();
5122 spellLogEffectDurabilityDamageParams.ItemID = itemId;
5123 spellLogEffectDurabilityDamageParams.Amount = amount;
5124
5125 GetExecuteLogEffectTargets(effect, &SpellLogEffect::DurabilityDamageTargets).push_back(spellLogEffectDurabilityDamageParams);
5126}
5127
5129{
5130 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5131 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5132
5133 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5134}
5135
5137{
5138 SpellLogEffectTradeSkillItemParams spellLogEffectTradeSkillItemParams;
5139 spellLogEffectTradeSkillItemParams.ItemID = entry;
5140
5141 GetExecuteLogEffectTargets(effect, &SpellLogEffect::TradeSkillTargets).push_back(spellLogEffectTradeSkillItemParams);
5142}
5143
5145{
5146 SpellLogEffectFeedPetParams spellLogEffectFeedPetParams;
5147 spellLogEffectFeedPetParams.ItemID = entry;
5148
5149 GetExecuteLogEffectTargets(effect, &SpellLogEffect::FeedPetTargets).push_back(spellLogEffectFeedPetParams);
5150}
5151
5153{
5154 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5155 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5156
5157 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5158}
5159
5161{
5162 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5163 spellLogEffectGenericVictimParams.Victim = obj->GetGUID();
5164
5165 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5166}
5167
5169{
5170 SpellLogEffectGenericVictimParams spellLogEffectGenericVictimParams;
5171 spellLogEffectGenericVictimParams.Victim = target->GetGUID();
5172
5173 GetExecuteLogEffectTargets(effect, &SpellLogEffect::GenericVictimTargets).push_back(spellLogEffectGenericVictimParams);
5174}
5175
5177{
5179 failurePacket.CasterUnit = m_caster->GetGUID();
5180 failurePacket.CastID = m_castId;
5181 failurePacket.SpellID = m_spellInfo->Id;
5182 failurePacket.Visual = m_SpellVisual;
5183 failurePacket.Reason = result;
5184 m_caster->SendMessageToSet(failurePacket.Write(), true);
5185
5187 failedPacket.CasterUnit = m_caster->GetGUID();
5188 failedPacket.CastID = m_castId;
5189 failedPacket.SpellID = m_spellInfo->Id;
5190 failedPacket.Visual = m_SpellVisual;
5191 failedPacket.Reason = result;
5192 m_caster->SendMessageToSet(failedPacket.Write(), true);
5193}
5194
5196{
5197 // GameObjects don't channel
5198 Unit* unitCaster = m_caster->ToUnit();
5199 if (!unitCaster)
5200 return;
5201
5202 if (time == 0)
5203 {
5204 unitCaster->ClearChannelObjects();
5205 unitCaster->SetChannelSpellId(0);
5206 unitCaster->SetChannelVisual({});
5207 }
5208
5210 spellChannelUpdate.CasterGUID = unitCaster->GetGUID();
5211 spellChannelUpdate.TimeRemaining = time;
5212 unitCaster->SendMessageToSet(spellChannelUpdate.Write(), true);
5213}
5214
5216{
5217 // GameObjects don't channel
5218 Unit* unitCaster = m_caster->ToUnit();
5219 if (!unitCaster)
5220 return;
5221
5222 m_timer = duration;
5223
5224 if (!m_targets.HasDst())
5225 {
5226 uint32 channelAuraMask = 0;
5227 uint32 explicitTargetEffectMask = 0xFFFFFFFF;
5228 // if there is an explicit target, only add channel objects from effects that also hit it
5230 {
5231 auto explicitTargetItr = std::find_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo const& target)
5232 {
5233 return target.TargetGUID == m_targets.GetUnitTargetGUID();
5234 });
5235 if (explicitTargetItr != m_UniqueTargetInfo.end())
5236 explicitTargetEffectMask = explicitTargetItr->EffectMask;
5237 }
5238
5239 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5240 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA) && (explicitTargetEffectMask & (1u << spellEffectInfo.EffectIndex)))
5241 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
5242
5243 for (TargetInfo const& target : m_UniqueTargetInfo)
5244 {
5245 if (!(target.EffectMask & channelAuraMask))
5246 continue;
5247
5248 SpellAttr1 requiredAttribute = target.TargetGUID != unitCaster->GetGUID() ? SPELL_ATTR1_IS_CHANNELLED : SPELL_ATTR1_IS_SELF_CHANNELLED;
5249 if (!m_spellInfo->HasAttribute(requiredAttribute))
5250 continue;
5251
5252 unitCaster->AddChannelObject(target.TargetGUID);
5253 }
5254
5255 for (GOTargetInfo const& target : m_UniqueGOTargetInfo)
5256 if (target.EffectMask & channelAuraMask)
5257 unitCaster->AddChannelObject(target.TargetGUID);
5258 }
5260 unitCaster->AddChannelObject(unitCaster->GetGUID());
5261
5262 if (Creature* creatureCaster = unitCaster->ToCreature())
5263 if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
5264 if (!creatureCaster->HasSpellFocus(this))
5265 creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, unitCaster->m_unitData->ChannelObjects[0]));
5266
5267 unitCaster->SetChannelSpellId(m_spellInfo->Id);
5268 unitCaster->SetChannelVisual(m_SpellVisual);
5269
5271 spellChannelStart.CasterGUID = unitCaster->GetGUID();
5272 spellChannelStart.SpellID = m_spellInfo->Id;
5273 spellChannelStart.Visual = m_SpellVisual;
5274 spellChannelStart.ChannelDuration = duration;
5275
5276 uint32 schoolImmunityMask = unitCaster->GetSchoolImmunityMask();
5277 uint32 mechanicImmunityMask = unitCaster->GetMechanicImmunityMask();
5278
5279 if (schoolImmunityMask || mechanicImmunityMask)
5280 {
5281 spellChannelStart.InterruptImmunities.emplace();
5282 spellChannelStart.InterruptImmunities->SchoolImmunities = schoolImmunityMask;
5283 spellChannelStart.InterruptImmunities->Immunities = mechanicImmunityMask;
5284 }
5285
5287 {
5288 WorldPackets::Spells::SpellTargetedHealPrediction& healPrediction = spellChannelStart.HealPrediction.emplace();
5289 if (unitCaster->m_unitData->ChannelObjects.size() == 1 && unitCaster->m_unitData->ChannelObjects[0].IsUnit())
5290 healPrediction.TargetGUID = unitCaster->m_unitData->ChannelObjects[0];
5291
5292 UpdateSpellHealPrediction(healPrediction.Predict, true);
5293 }
5294
5295 unitCaster->SendMessageToSet(spellChannelStart.Write(), true);
5296}
5297
5299{
5300 // get resurrector name for creature resurrections, otherwise packet will be not accepted
5301 // for player resurrections the name is looked up by guid
5302 std::string sentName;
5305
5307 resurrectRequest.ResurrectOffererGUID = m_caster->GetGUID();
5309 resurrectRequest.Name = sentName;
5310 resurrectRequest.Sickness = m_caster->IsUnit() && m_caster->ToUnit()->IsSpiritHealer(); // "you'll be afflicted with resurrection sickness"
5312 if (Pet* pet = target->GetPet())
5313 if (CharmInfo* charmInfo = pet->GetCharmInfo())
5314 resurrectRequest.PetNumber = charmInfo->GetPetNumber();
5315
5316 resurrectRequest.SpellID = m_spellInfo->Id;
5317 target->SendDirectMessage(resurrectRequest.Write());
5318}
5319
5321{
5322 if (!m_CastItem)
5323 return;
5324
5325 Player* player = m_caster->ToPlayer();
5326 if (!player)
5327 return;
5328
5329 // not remove cast item at triggered spell (equipping, weapon damage, etc)
5331 return;
5332
5333 ItemTemplate const* proto = m_CastItem->GetTemplate();
5334
5335 if (!proto)
5336 {
5337 // This code is to avoid a crash
5338 // I'm not sure, if this is really an error, but I guess every item needs a prototype
5339 TC_LOG_ERROR("spells", "Cast item has no item prototype {}", m_CastItem->GetGUID().ToString());
5340 return;
5341 }
5342
5343 bool expendable = false;
5344 bool withoutCharges = false;
5345
5346 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
5347 {
5348 if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
5349 continue;
5350
5351 // item has limited charges
5352 if (itemEffect->Charges)
5353 {
5354 if (itemEffect->Charges < 0)
5355 expendable = true;
5356
5357 int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
5358
5359 // item has charges left for this slot
5360 if (charges && itemEffect->SpellID == int32(m_spellInfo->Id))
5361 {
5362 (charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
5363 if (proto->GetMaxStackSize() == 1)
5364 m_CastItem->SetSpellCharges(itemEffect->LegacySlotIndex, charges);
5366 }
5367
5368 // all charges used
5369 withoutCharges = (charges == 0);
5370 }
5371 }
5372
5373 if (expendable && withoutCharges)
5374 {
5375 uint32 count = 1;
5376 m_caster->ToPlayer()->DestroyItemCount(m_CastItem, count, true);
5377
5378 // prevent crash at access to deleted m_targets.GetItemTarget
5380 m_targets.SetItemTarget(nullptr);
5381
5382 m_CastItem = nullptr;
5384 m_castItemEntry = 0;
5385 }
5386}
5387
5389{
5390 // GameObjects don't use power
5391 Unit* unitCaster = m_caster->ToUnit();
5392 if (!unitCaster)
5393 return;
5394
5396 return;
5397
5398 //Don't take power if the spell is cast while .cheat power is enabled.
5399 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5400 {
5401 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
5402 return;
5403 }
5404
5405 for (SpellPowerCost& cost : m_powerCost)
5406 {
5407 Powers powerType = Powers(cost.Power);
5408 bool hit = true;
5409 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5410 {
5412 {
5413 ObjectGuid targetGUID = m_targets.GetUnitTargetGUID();
5414 if (!targetGUID.IsEmpty())
5415 {
5416 auto ihit = std::find_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [&](TargetInfo const& targetInfo) { return targetInfo.TargetGUID == targetGUID && targetInfo.MissCondition != SPELL_MISS_NONE; });
5417 if (ihit != std::end(m_UniqueTargetInfo))
5418 {
5419 hit = false;
5420 //lower spell cost on fail (by talent aura)
5421 if (Player* modOwner = unitCaster->GetSpellModOwner())
5422 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::PowerCostOnMiss, cost.Amount);
5423 }
5424 }
5425 }
5426 }
5427
5428 if (powerType == POWER_RUNES)
5429 {
5430 TakeRunePower(hit);
5431 continue;
5432 }
5433
5434 if (!cost.Amount)
5435 continue;
5436
5437 // health as power used
5438 if (powerType == POWER_HEALTH)
5439 {
5440 unitCaster->ModifyHealth(-cost.Amount);
5441 continue;
5442 }
5443
5444 if (powerType >= MAX_POWERS)
5445 {
5446 TC_LOG_ERROR("spells", "Spell::TakePower: Unknown power type '{}'", powerType);
5447 continue;
5448 }
5449
5450 unitCaster->ModifyPower(powerType, -cost.Amount);
5451 }
5452}
5453
5455{
5456 int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
5457 {
5458 return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0);
5459 });
5460
5461 if (!runeCost)
5462 return SPELL_CAST_OK;
5463
5464 Player* player = m_caster->ToPlayer();
5465 if (!player)
5466 return SPELL_CAST_OK;
5467
5468 if (player->GetClass() != CLASS_DEATH_KNIGHT)
5469 return SPELL_CAST_OK;
5470
5471 int32 readyRunes = 0;
5472 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5473 if (player->GetRuneCooldown(i) == 0)
5474 ++readyRunes;
5475
5476 if (readyRunes < runeCost)
5477 return SPELL_FAILED_NO_POWER; // not sure if result code is correct
5478
5479 return SPELL_CAST_OK;
5480}
5481
5482void Spell::TakeRunePower(bool didHit)
5483{
5485 return;
5486
5487 Player* player = m_caster->ToPlayer();
5488 m_runesState = player->GetRunesState(); // store previous state
5489
5490 int32 runeCost = std::accumulate(m_powerCost.begin(), m_powerCost.end(), 0, [](int32 totalCost, SpellPowerCost const& cost)
5491 {
5492 return totalCost + (cost.Power == POWER_RUNES ? cost.Amount : 0);
5493 });
5494
5495 for (int32 i = 0; i < player->GetMaxPower(POWER_RUNES); ++i)
5496 {
5497 if (!player->GetRuneCooldown(i) && runeCost > 0)
5498 {
5499 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown() : uint32(RUNE_MISS_COOLDOWN));
5500 --runeCost;
5501 }
5502 }
5503}
5504
5506{
5508 return;
5509
5510 // do not take reagents for these item casts
5512 return;
5513
5514 Player* p_caster = m_caster->ToPlayer();
5515 if (p_caster->CanNoReagentCast(m_spellInfo))
5516 return;
5517
5518 for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
5519 {
5520 if (m_spellInfo->Reagent[x] <= 0)
5521 continue;
5522
5523 uint32 itemid = m_spellInfo->Reagent[x];
5524 uint32 itemcount = m_spellInfo->ReagentCount[x];
5525
5526 // if CastItem is also spell reagent
5527 if (m_CastItem && m_CastItem->GetEntry() == itemid)
5528 {
5529 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
5530 {
5531 if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
5532 continue;
5533
5534 // CastItem will be used up and does not count as reagent
5535 int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
5536 if (itemEffect->Charges < 0 && abs(charges) < 2)
5537 {
5538 ++itemcount;
5539 break;
5540 }
5541 }
5542
5543 m_CastItem = nullptr;
5545 m_castItemEntry = 0;
5546 }
5547
5548 // if GetItemTarget is also spell reagent
5549 if (m_targets.GetItemTargetEntry() == itemid)
5550 m_targets.SetItemTarget(nullptr);
5551
5552 p_caster->DestroyItemCount(itemid, itemcount, true);
5553 }
5554
5555 for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency)
5556 p_caster->RemoveCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount, CurrencyDestroyReason::Spell);
5557}
5558
5560{
5561 // wild GameObject spells don't cause threat
5562 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
5563 if (!unitCaster)
5564 return;
5565
5566 if (m_UniqueTargetInfo.empty())
5567 return;
5568
5570 return;
5571
5572 float threat = 0.0f;
5573 if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
5574 {
5575 if (threatEntry->apPctMod != 0.0f)
5576 threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
5577
5578 threat += threatEntry->flatMod;
5579 }
5581 threat += m_spellInfo->SpellLevel;
5582
5583 // past this point only multiplicative effects occur
5584 if (threat == 0.0f)
5585 return;
5586
5587 // 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
5588 threat /= m_UniqueTargetInfo.size();
5589
5590 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
5591 {
5592 float threatToAdd = threat;
5593 if (ihit->MissCondition != SPELL_MISS_NONE)
5594 threatToAdd = 0.0f;
5595
5596 Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit->TargetGUID);
5597 if (!target)
5598 continue;
5599
5600 // positive spells distribute threat among all units that are in combat with target, like healing
5601 if (IsPositive())
5602 target->GetThreatManager().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
5603 // for negative spells threat gets distributed among affected targets
5604 else
5605 {
5606 if (!target->CanHaveThreatList())
5607 continue;
5608
5609 target->GetThreatManager().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
5610 }
5611 }
5612 TC_LOG_DEBUG("spells", "Spell {}, added an additional {} threat for {} {} target(s)", m_spellInfo->Id, threat, IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
5613}
5614
5615void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
5616{
5617 effectHandleMode = mode;
5618 unitTarget = pUnitTarget;
5619 itemTarget = pItemTarget;
5620 gameObjTarget = pGoTarget;
5621 m_corpseTarget = pCorpseTarget;
5622 destTarget = &m_destTargets[spellEffectInfo.EffectIndex]._position;
5623 effectInfo = &spellEffectInfo;
5624
5625 damage = CalculateDamage(spellEffectInfo, unitTarget, &variance);
5626
5627 bool preventDefault = CallScriptEffectHandlers(spellEffectInfo.EffectIndex, mode);
5628
5629 if (!preventDefault)
5630 (this->*SpellEffectHandlers[spellEffectInfo.Effect].Value)();
5631}
5632
5634{
5635 if (SpellEvent* spellEvent = dynamic_cast<SpellEvent*>(event))
5636 return spellEvent->GetSpell();
5637
5638 return nullptr;
5639}
5640
5641SpellCastResult Spell::CheckCast(bool strict, int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/)
5642{
5643 // check death state
5646
5647 // 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
5649 {
5652 }
5653
5654 // check cooldowns to prevent cheating
5655 if (!m_spellInfo->IsPassive())
5656 {
5657 if (Player const* playerCaster = m_caster->ToPlayer())
5658 {
5659 //can cast triggered (by aura only?) spells while have this flag
5661 {
5662 // These two auras check SpellFamilyName defined by db2 class data instead of current spell SpellFamilyName
5663 if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES)
5667 && !playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_CASTING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->GetClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
5669
5670 if (playerCaster->HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES))
5671 {
5672 if (!playerCaster->HasAuraTypeWithFamilyFlags(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES, sChrClassesStore.AssertEntry(playerCaster->GetClass())->SpellClassSet, m_spellInfo->SpellFamilyFlags))
5673 {
5684 }
5685 }
5686 }
5687
5688 // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
5689 if (!IsIgnoringCooldowns() && playerCaster->GetLastPotionId() && m_CastItem && (m_CastItem->IsPotion() || m_spellInfo->IsCooldownStartedOnEvent()))
5691 }
5692
5694 {
5696 {
5699 else
5701 }
5702
5705 }
5706 }
5707
5709 {
5712 }
5713
5716
5717 // Check global cooldown
5720
5721 // only triggered spells can be processed an ended battleground
5724 if (bg->GetStatus() == STATUS_WAIT_LEAVE)
5726
5728 {
5730 !m_caster->IsOutdoors())
5732
5736 }
5737
5738 if (Unit* unitCaster = m_caster->ToUnit())
5739 {
5740 if (m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_AVAILABLE_WHILE_CHARMED) && unitCaster->IsCharmed())
5741 return SPELL_FAILED_CHARMED;
5742
5743 // only check at first call, Stealth auras are already removed at second call
5744 // for now, ignore triggered spells
5746 {
5747 bool checkForm = true;
5748 // Ignore form req aura
5749 Unit::AuraEffectList const& ignore = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
5750 for (AuraEffect const* aurEff : ignore)
5751 {
5752 if (!aurEff->IsAffectingSpell(m_spellInfo))
5753 continue;
5754
5755 checkForm = false;
5756 break;
5757 }
5758
5759 if (checkForm)
5760 {
5761 // Cannot be used in this stance/form
5762 SpellCastResult shapeError = m_spellInfo->CheckShapeshift(unitCaster->GetShapeshiftForm());
5763 if (shapeError != SPELL_CAST_OK)
5764 return shapeError;
5765
5766 if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(unitCaster->HasStealthAura()))
5768 }
5769 }
5770
5771 // caster state requirements
5772 // not for triggered spells (needed by execute)
5774 {
5775 if (m_spellInfo->CasterAuraState && !unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, unitCaster))
5777 if (m_spellInfo->ExcludeCasterAuraState && unitCaster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, unitCaster))
5779
5780 // Note: spell 62473 requres casterAuraSpell = triggering spell
5781 if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(m_spellInfo->CasterAuraSpell))
5785
5786 if (m_spellInfo->CasterAuraType && !unitCaster->HasAuraType(m_spellInfo->CasterAuraType))
5788 if (m_spellInfo->ExcludeCasterAuraType && unitCaster->HasAuraType(m_spellInfo->ExcludeCasterAuraType))
5790
5791 if (unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat(unitCaster))
5793 }
5794
5795 // Check vehicle flags
5797 {
5798 SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(unitCaster);
5799 if (vehicleCheck != SPELL_CAST_OK)
5800 return vehicleCheck;
5801 }
5802 }
5803
5804 // check spell cast conditions from database
5805 {
5807 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL, m_spellInfo->Id, condInfo))
5808 {
5809 // mLastFailedCondition can be NULL if there was an error processing the condition in Condition::Meets (i.e. wrong data for ConditionTarget or others)
5810 if (condInfo.mLastFailedCondition && condInfo.mLastFailedCondition->ErrorType)
5811 {
5815 }
5816
5817 if (!condInfo.mLastFailedCondition || !condInfo.mLastFailedCondition->ConditionTarget)
5820 }
5821 }
5822
5823 // Don't check explicit target for passive spells (workaround) (check should be skipped only for learn case)
5824 // those spells may have incorrect target entries or not filled at all (for example 15332)
5825 // such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
5826 // also, such casts shouldn't be sent to client
5828 {
5829 // Check explicit target for m_originalCaster - todo: get rid of such workarounds
5830 WorldObject* caster = m_caster;
5831 // in case of gameobjects like traps, we need the gameobject itself to check target validity
5832 // otherwise, if originalCaster is far away and cannot detect the target, the trap would not hit the target
5833 if (m_originalCaster && !caster->ToGameObject())
5834 caster = m_originalCaster;
5835
5837 if (castResult != SPELL_CAST_OK)
5838 return castResult;
5839 }
5840
5841 if (Unit* target = m_targets.GetUnitTarget())
5842 {
5843 SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetTypeId() == TYPEID_GAMEOBJECT); // skip stealth checks for GO casts
5844 if (castResult != SPELL_CAST_OK)
5845 return castResult;
5846
5847 // If it's not a melee spell, check if vision is obscured by SPELL_AURA_INTERFERE_TARGETTING
5849 {
5850 if (Unit const* unitCaster = m_caster->ToUnit())
5851 {
5852 for (AuraEffect const* auraEff : unitCaster->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
5853 if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && !target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()))
5855
5856 for (AuraEffect const* auraEff : target->GetAuraEffectsByType(SPELL_AURA_INTERFERE_TARGETTING))
5857 if (!unitCaster->IsFriendlyTo(auraEff->GetCaster()) && (!target->HasAura(auraEff->GetId(), auraEff->GetCasterGUID()) || !unitCaster->HasAura(auraEff->GetId(), auraEff->GetCasterGUID())))
5859 }
5860 }
5861
5862 if (target != m_caster)
5863 {
5864 // Must be behind the target
5865 if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET)) && target->HasInArc(static_cast<float>(M_PI), m_caster))
5867
5868 // Target must be facing you
5869 if ((m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER)) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
5871
5872 // Ignore LOS for gameobjects casts
5874 {
5875 WorldObject* losTarget = m_caster;
5878 losTarget = dynObj;
5879
5880 if (!IsWithinLOS(losTarget, target, true, VMAP::ModelIgnoreFlags::M2))
5882 }
5883 }
5884 }
5885
5886 // Check for line of sight for spells with dest
5887 if (m_targets.HasDst())
5890
5891 // check pet presence
5892 if (Unit* unitCaster = m_caster->ToUnit())
5893 {
5895 if (!unitCaster->GetPetGUID().IsEmpty())
5897
5898 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5899 {
5900 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
5901 {
5902 if (!unitCaster->GetGuardianPet())
5903 {
5904 if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
5906 else
5907 return SPELL_FAILED_NO_PET;
5908 }
5909 break;
5910 }
5911 }
5912 }
5913
5914 // Spell cast only in battleground
5916 if (!m_caster->GetMap()->IsBattleground())
5918
5919 // do not allow spells to be cast in arenas or rated battlegrounds
5920 if (Player* player = m_caster->ToPlayer())
5921 if (player->InArena()/* || player->InRatedBattleGround() NYI*/)
5922 {
5924 if (castResult != SPELL_CAST_OK)
5925 return castResult;
5926 }
5927
5928 // zone check
5930 {
5931 uint32 zone, area;
5932 m_caster->GetZoneAndAreaId(zone, area);
5933
5935 if (locRes != SPELL_CAST_OK)
5936 return locRes;
5937 }
5938
5939 // not let players cast spells at mount (and let do it to creatures)
5941 {
5943 {
5944 if (m_caster->ToPlayer()->IsInFlight())
5946 else
5948 }
5949 }
5950
5951 // check spell focus object
5953 {
5955 {
5957 if (!focusObject)
5959 }
5960 }
5961
5962 SpellCastResult castResult = SPELL_CAST_OK;
5963
5964 // always (except passive spells) check items (only player related checks)
5965 if (!m_spellInfo->IsPassive())
5966 {
5967 castResult = CheckItems(param1, param2);
5968 if (castResult != SPELL_CAST_OK)
5969 return castResult;
5970 }
5971
5972 // Triggered spells also have range check
5974 castResult = CheckRange(strict);
5975 if (castResult != SPELL_CAST_OK)
5976 return castResult;
5977
5979 {
5980 castResult = CheckPower();
5981 if (castResult != SPELL_CAST_OK)
5982 return castResult;
5983 }
5984
5986 {
5987 castResult = CheckCasterAuras(param1);
5988 if (castResult != SPELL_CAST_OK)
5989 return castResult;
5990 }
5991
5992 // script hook
5993 castResult = CallScriptCheckCastHandlers();
5994 if (castResult != SPELL_CAST_OK)
5995 return castResult;
5996
5997 uint32 approximateAuraEffectMask = 0;
5998 uint32 nonAuraEffectMask = 0;
5999 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6000 {
6001 // for effects of spells that have only one target
6002 switch (spellEffectInfo.Effect)
6003 {
6004 case SPELL_EFFECT_DUMMY:
6005 {
6006 if (m_spellInfo->Id == 19938) // Awaken Peon
6007 {
6008 Unit* unit = m_targets.GetUnitTarget();
6009 if (!unit || !unit->HasAura(17743))
6011 }
6012 else if (m_spellInfo->Id == 31789) // Righteous Defense
6013 {
6016
6017 Unit* target = m_targets.GetUnitTarget();
6018 if (!target || !target->IsFriendlyTo(m_caster) || target->getAttackers().empty())
6020
6021 }
6022 break;
6023 }
6025 {
6026 if (spellEffectInfo.TargetA.GetTarget() != TARGET_UNIT_PET)
6027 break;
6028
6029 Pet* pet = m_caster->ToPlayer()->GetPet();
6030 if (!pet)
6031 return SPELL_FAILED_NO_PET;
6032
6033 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
6034 if (!learn_spellproto)
6036
6037 if (m_spellInfo->SpellLevel > pet->GetLevel())
6038 return SPELL_FAILED_LOWLEVEL;
6039
6040 break;
6041 }
6043 {
6046 if (Guild* guild = m_caster->ToPlayer()->GetGuild())
6047 if (guild->GetLeaderGUID() != m_caster->ToPlayer()->GetGUID())
6049 break;
6050 }
6052 {
6053 // check target only for unit target case
6054 if (Unit* unit = m_targets.GetUnitTarget())
6055 {
6058
6059 Pet* pet = unit->ToPet();
6060 if (!pet || pet->GetOwner() != m_caster)
6062
6063 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell, DIFFICULTY_NONE);
6064
6065 if (!learn_spellproto)
6067
6068 if (m_spellInfo->SpellLevel > pet->GetLevel())
6069 return SPELL_FAILED_LOWLEVEL;
6070 }
6071 break;
6072 }
6074 {
6077
6078 Player* caster = m_caster->ToPlayer();
6079 if (!caster->HasSpell(m_misc.SpellId))
6081
6082 if (uint32 glyphId = spellEffectInfo.MiscValue)
6083 {
6084 GlyphPropertiesEntry const* glyphProperties = sGlyphPropertiesStore.LookupEntry(glyphId);
6085 if (!glyphProperties)
6087
6088 std::vector<uint32> const* glyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(glyphId);
6089 if (!glyphBindableSpells)
6091
6092 if (std::find(glyphBindableSpells->begin(), glyphBindableSpells->end(), m_misc.SpellId) == glyphBindableSpells->end())
6094
6095 if (std::vector<ChrSpecialization> const* glyphRequiredSpecs = sDB2Manager.GetGlyphRequiredSpecs(glyphId))
6096 {
6099
6100 if (std::find(glyphRequiredSpecs->begin(), glyphRequiredSpecs->end(), caster->GetPrimarySpecialization()) == glyphRequiredSpecs->end())
6102 }
6103
6104 uint32 replacedGlyph = 0;
6105 for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
6106 {
6107 if (std::vector<uint32> const* activeGlyphBindableSpells = sDB2Manager.GetGlyphBindableSpells(activeGlyphId))
6108 {
6109 if (std::find(activeGlyphBindableSpells->begin(), activeGlyphBindableSpells->end(), m_misc.SpellId) != activeGlyphBindableSpells->end())
6110 {
6111 replacedGlyph = activeGlyphId;
6112 break;
6113 }
6114 }
6115 }
6116
6117 for (uint32 activeGlyphId : caster->GetGlyphs(caster->GetActiveTalentGroup()))
6118 {
6119 if (activeGlyphId == replacedGlyph)
6120 continue;
6121
6122 if (activeGlyphId == glyphId)
6124
6125 if (sGlyphPropertiesStore.AssertEntry(activeGlyphId)->GlyphExclusiveCategoryID == glyphProperties->GlyphExclusiveCategoryID)
6127 }
6128 }
6129 break;
6130 }
6132 {
6135
6136 Item* foodItem = m_targets.GetItemTarget();
6137 if (!foodItem)
6139
6140 Pet* pet = m_caster->ToPlayer()->GetPet();
6141 if (!pet)
6142 return SPELL_FAILED_NO_PET;
6143
6144 if (!pet->HaveInDiet(foodItem->GetTemplate()))
6146
6147 if (foodItem->GetTemplate()->GetBaseItemLevel() + 30 <= pet->GetLevel())
6149
6150 if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
6152
6153 break;
6154 }
6156 {
6157 Unit* unitCaster = m_caster->ToUnit();
6158 if (!unitCaster)
6160
6162 return SPELL_FAILED_ROOTED;
6163
6164 if (GetSpellInfo()->NeedsExplicitUnitTarget())
6165 {
6166 Unit* target = m_targets.GetUnitTarget();
6167 if (!target)
6169
6170 // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
6171 if (!IsWithinLOS(unitCaster, target, true, VMAP::ModelIgnoreFlags::Nothing)) //Do full LoS/Path check. Don't exclude m2
6173
6174 float objSize = target->GetCombatReach();
6175 float range = m_spellInfo->GetMaxRange(true, unitCaster, this) * 1.5f + objSize; // can't be overly strict
6176
6177 m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
6178 m_preGeneratedPath->SetPathLengthLimit(range);
6179
6180 // first try with raycast, if it fails fall back to normal path
6181 bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
6182 if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
6183 return SPELL_FAILED_NOPATH;
6184 else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
6185 return SPELL_FAILED_NOPATH;
6186 else if (m_preGeneratedPath->IsInvalidDestinationZ(target)) // Check position z, if not in a straight line
6187 return SPELL_FAILED_NOPATH;
6188
6189 m_preGeneratedPath->ShortenPathUntilDist(PositionToVector3(target), objSize); // move back
6190 }
6191 break;
6192 }
6194 {
6197
6200
6201 Creature* creature = m_targets.GetUnitTarget()->ToCreature();
6202 Loot* loot = creature->GetLootForPlayer(m_caster->ToPlayer());
6203 if (loot && (!loot->isLooted() || loot->loot_type == LOOT_SKINNING))
6205
6206 break;
6207 }
6209 {
6210 if (spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET &&
6211 spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET)
6212 break;
6213
6214 if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc.
6215 // we need a go target in case of TARGET_GAMEOBJECT_TARGET
6216 || (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget()))
6218
6219 Item* pTempItem = nullptr;
6221 {
6222 if (TradeData* pTrade = m_caster->ToPlayer()->GetTradeData())
6223 pTempItem = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
6224 }
6227
6228 // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
6229 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET &&
6231 (!pTempItem || !pTempItem->GetTemplate()->GetLockID() || !pTempItem->IsLocked()))
6233
6234 if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
6236 if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners
6239
6240 // get the lock entry
6241 uint32 lockId = 0;
6242 if (GameObject* go = m_targets.GetGOTarget())
6243 {
6244 lockId = go->GetGOInfo()->GetLockId();
6245 if (!lockId)
6247
6248 if (go->GetGOInfo()->GetNotInCombat() && m_caster->ToUnit()->IsInCombat())
6250 }
6251 else if (Item* itm = m_targets.GetItemTarget())
6252 lockId = itm->GetTemplate()->GetLockID();
6253
6254 SkillType skillId = SKILL_NONE;
6255 int32 reqSkillValue = 0;
6256 int32 skillValue = 0;
6257
6258 // check lock compatibility
6259 SpellCastResult res = CanOpenLock(spellEffectInfo, lockId, skillId, reqSkillValue, skillValue);
6260 if (res != SPELL_CAST_OK)
6261 return res;
6262 break;
6263 }
6265 {
6266 Player* playerCaster = m_caster->ToPlayer();
6267 if (!playerCaster || !playerCaster->GetPetStable())
6269
6270 Pet* pet = playerCaster->GetPet();
6271 if (pet && pet->IsAlive())
6273
6274 PetStable const* petStable = playerCaster->GetPetStable();
6275 auto deadPetItr = std::find_if(petStable->ActivePets.begin(), petStable->ActivePets.end(), [](Optional<PetStable::PetInfo> const& petInfo)
6276 {
6277 return petInfo && !petInfo->Health;
6278 });
6279
6280 if (deadPetItr == petStable->ActivePets.end())
6282
6283 break;
6284 }
6285 // This is generic summon effect
6287 {
6288 Unit* unitCaster = m_caster->ToUnit();
6289 if (!unitCaster)
6290 break;
6291
6292 SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(spellEffectInfo.MiscValueB);
6293 if (!SummonProperties)
6294 break;
6295
6296 switch (SummonProperties->Control)
6297 {
6301 [[fallthrough]]; // check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
6303 if (!unitCaster->GetCharmedGUID().IsEmpty())
6305 break;
6306 }
6307 break;
6308 }
6310 {
6312 {
6317 }
6318 break;
6319 }
6321 {
6322 Unit* unitCaster = m_caster->ToUnit();
6323 if (!unitCaster)
6325
6326 if (!unitCaster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
6327 {
6328 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
6329 {
6330 if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
6331 if (Pet* pet = unitCaster->ToPlayer()->GetPet())
6333 .SetOriginalCaster(pet->GetGUID())
6334 .SetTriggeringSpell(this));
6335 }
6338 }
6339
6340 if (!unitCaster->GetCharmedGUID().IsEmpty())
6342
6343 Player* playerCaster = unitCaster->ToPlayer();
6344 if (playerCaster && playerCaster->GetPetStable())
6345 {
6346 Optional<PetSaveMode> petSlot;
6347 if (!spellEffectInfo.MiscValue)
6348 {
6349 petSlot = PetSaveMode(spellEffectInfo.CalcValue());
6350
6351 // No pet can be summoned if any pet is dead
6352 for (Optional<PetStable::PetInfo> const& activePet : playerCaster->GetPetStable()->ActivePets)
6353 {
6354 if (activePet && !activePet->Health)
6355 {
6356 playerCaster->SendTameFailure(PetTameResult::Dead);
6358 }
6359 }
6360 }
6361
6362 std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, petSlot);
6363 if (info.first)
6364 {
6365 if (info.first->Type == HUNTER_PET)
6366 {
6367 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(info.first->CreatureId);
6368 CreatureDifficulty const* creatureDifficulty = creatureInfo->GetDifficulty(DIFFICULTY_NONE);
6369 if (!creatureInfo || !creatureInfo->IsTameable(playerCaster->CanTameExoticPets(), creatureDifficulty))
6370 {
6371 // if problem in exotic pet
6372 if (creatureInfo && creatureInfo->IsTameable(true, creatureDifficulty))
6374 else
6376
6378 }
6379 }
6380 }
6381 else if (!spellEffectInfo.MiscValue) // when miscvalue is present it is allowed to create new pets
6382 {
6385 }
6386 }
6387
6388 break;
6389 }
6391 {
6392 Player* playerCaster = m_caster->ToPlayer();
6393 if (!playerCaster)
6395
6396 Pet* pet = playerCaster->GetPet();
6397 if (!pet)
6398 return SPELL_FAILED_NO_PET;
6399
6400 if (!pet->IsAlive())
6402
6403 break;
6404 }
6406 {
6409
6410 if (!m_caster->ToPlayer()->GetTarget())
6412
6414 if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell
6416
6417 if (target->HasSummonPending())
6419
6420 // check if our map is dungeon
6421 if (InstanceMap const* map = m_caster->GetMap()->ToInstanceMap())
6422 {
6423 uint32 mapId = map->GetId();
6424 Difficulty difficulty = map->GetDifficultyID();
6425 if (InstanceLock const* mapLock = map->GetInstanceLock())
6426 if (sInstanceLockMgr.CanJoinInstanceLock(target->GetGUID(), { mapId, difficulty }, mapLock) != TRANSFER_ABORT_NONE)
6428
6429 if (!target->Satisfy(sObjectMgr->GetAccessRequirement(mapId, difficulty), mapId))
6431 }
6432 break;
6433 }
6434 // RETURN HERE
6436 {
6439
6440 Player* playerCaster = m_caster->ToPlayer();
6441 if (!playerCaster->GetTarget())
6443
6444 Player* target = playerCaster->GetSelectedPlayer();
6445 if (!target ||
6446 !(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
6448 break;
6449 }
6450 case SPELL_EFFECT_LEAP:
6452 {
6453 //Do not allow to cast it before BG starts.
6455 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
6456 if (bg->GetStatus() != STATUS_IN_PROGRESS)
6458 break;
6459 }
6461 {
6464 break;
6465 }
6467 {
6468 Unit* unitCaster = m_caster->ToUnit();
6469 if (!unitCaster)
6471
6472 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
6473 {
6474 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
6475 return SPELL_FAILED_ROOTED;
6476 else
6478 }
6479 break;
6480 }
6481 case SPELL_EFFECT_JUMP:
6483 {
6484 Unit* unitCaster = m_caster->ToUnit();
6485 if (!unitCaster)
6487
6488 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
6489 return SPELL_FAILED_ROOTED;
6490 break;
6491 }
6493 {
6494 ChrSpecializationEntry const* spec = sChrSpecializationStore.LookupEntry(m_misc.SpecializationId);
6495 Player* player = m_caster->ToPlayer();
6496 if (!player)
6498
6499 if (!spec || (spec->ClassID != player->GetClass() && !spec->IsPetSpecialization()))
6500 return SPELL_FAILED_NO_SPEC;
6501
6502 if (spec->IsPetSpecialization())
6503 {
6504 Pet* pet = player->GetPet();
6505 if (!pet || pet->getPetType() != HUNTER_PET || !pet->GetCharmInfo())
6506 return SPELL_FAILED_NO_PET;
6507 }
6508
6509 // can't change during already started arena/battleground
6510 if (Battleground const* bg = player->GetBattleground())
6511 if (bg->GetStatus() == STATUS_IN_PROGRESS)
6513 break;
6514 }
6516 {
6517 Player* playerCaster = m_caster->ToPlayer();
6518 if (!playerCaster)
6520
6521 TalentEntry const* talent = sTalentStore.LookupEntry(m_misc.TalentId);
6522 if (!talent)
6524
6525 if (playerCaster->GetSpellHistory()->HasCooldown(talent->SpellID))
6526 {
6527 if (param1)
6528 *param1 = talent->SpellID;
6530 }
6531 break;
6532 }
6534 {
6535 if (!m_caster->IsPlayer())
6537
6538 if (!m_caster->ToPlayer()->GetSession()->GetCollectionMgr()->HasHeirloom(m_misc.Raw.Data[0]))
6540
6541 break;
6542 }
6545 {
6546 Player* playerCaster = m_caster->ToPlayer();
6547 if (!playerCaster)
6549
6551 if (!artifactAura)
6553
6554 Item* artifact = playerCaster->GetItemByGuid(artifactAura->GetCastItemGUID());
6555 if (!artifact)
6557
6558 if (spellEffectInfo.Effect == SPELL_EFFECT_GIVE_ARTIFACT_POWER)
6559 {
6560 ArtifactEntry const* artifactEntry = sArtifactStore.LookupEntry(artifact->GetTemplate()->GetArtifactID());
6561 if (!artifactEntry || artifactEntry->ArtifactCategoryID != spellEffectInfo.MiscValue)
6563 }
6564 break;
6565 }
6569 {
6570 Player* playerCaster = m_caster->ToPlayer();
6571 if (!playerCaster || !m_targets.GetUnitTarget() || !m_targets.GetUnitTarget()->IsCreature())
6573
6574 BattlePets::BattlePetMgr* battlePetMgr = playerCaster->GetSession()->GetBattlePetMgr();
6575 if (!battlePetMgr->HasJournalLock())
6577
6578 if (Creature* creature = m_targets.GetUnitTarget()->ToCreature())
6579 {
6580 if (playerCaster->GetSummonedBattlePetGUID().IsEmpty() || creature->GetBattlePetCompanionGUID().IsEmpty())
6581 return SPELL_FAILED_NO_PET;
6582
6583 if (playerCaster->GetSummonedBattlePetGUID() != creature->GetBattlePetCompanionGUID())
6585
6586 if (BattlePets::BattlePet* battlePet = battlePetMgr->GetPet(creature->GetBattlePetCompanionGUID()))
6587 {
6588 if (BattlePetSpeciesEntry const* battlePetSpecies = sBattlePetSpeciesStore.LookupEntry(battlePet->PacketInfo.Species))
6589 {
6590 if (uint32 battlePetType = spellEffectInfo.MiscValue)
6591 if (!(battlePetType & (1 << battlePetSpecies->PetTypeEnum)))
6593
6594 if (spellEffectInfo.Effect == SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY)
6595 {
6596 auto qualityItr = std::lower_bound(sBattlePetBreedQualityStore.begin(), sBattlePetBreedQualityStore.end(), spellEffectInfo.CalcBaseValue(m_caster, creature, m_castItemEntry, m_castItemLevel), [](BattlePetBreedQualityEntry const* a1, int32 selector)
6597 {
6598 return a1->MaxQualityRoll < selector;
6599 });
6600
6602 if (qualityItr != sBattlePetBreedQualityStore.end())
6603 quality = BattlePets::BattlePetBreedQuality(qualityItr->QualityEnum);
6604
6605 if (battlePet->PacketInfo.Quality >= AsUnderlyingType(quality))
6607 }
6608
6609 if (spellEffectInfo.Effect == SPELL_EFFECT_GRANT_BATTLEPET_LEVEL || spellEffectInfo.Effect == SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE)
6610 if (battlePet->PacketInfo.Level >= BattlePets::MAX_BATTLE_PET_LEVEL)
6611 return GRANT_PET_LEVEL_FAIL;
6612
6613 if (battlePetSpecies->GetFlags().HasFlag(BattlePetSpeciesFlags::CantBattle))
6615 }
6616 }
6617 }
6618 break;
6619 }
6620 default:
6621 break;
6622 }
6623
6624 if (spellEffectInfo.IsAura())
6625 approximateAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6626 else if (spellEffectInfo.IsEffect())
6627 nonAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6628 }
6629
6630 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6631 {
6632 switch (spellEffectInfo.ApplyAuraName)
6633 {
6635 {
6637 return SPELL_FAILED_NO_PET;
6638
6639 Pet* pet = m_caster->ToPlayer()->GetPet();
6640 if (!pet)
6641 return SPELL_FAILED_NO_PET;
6642
6643 if (!pet->GetCharmerGUID().IsEmpty())
6645 break;
6646 }
6650 {
6651 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6652 if (!unitCaster)
6654
6655 if (!unitCaster->GetCharmerGUID().IsEmpty())
6656 return SPELL_FAILED_CHARMED;
6657
6658 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_CHARM
6659 || spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_POSSESS)
6660 {
6663
6664 if (!unitCaster->GetCharmedGUID().IsEmpty())
6666 }
6667
6668 if (Unit* target = m_targets.GetUnitTarget())
6669 {
6670 if (target->GetTypeId() == TYPEID_UNIT && target->IsVehicle())
6672
6673 if (target->IsMounted())
6675
6676 if (!target->GetCharmerGUID().IsEmpty())
6678
6679 if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER)
6681
6682 int32 value = CalculateDamage(spellEffectInfo, target);
6683 if (value && int32(target->GetLevelForTarget(m_caster)) > value)
6685 }
6686
6687 break;
6688 }
6689 case SPELL_AURA_MOUNTED:
6690 {
6691 Unit* unitCaster = m_caster->ToUnit();
6692 if (!unitCaster)
6694
6697
6698 if (unitCaster->IsInDisallowedMountForm())
6699 {
6700 SendMountResult(MountResult::Shapeshifted); // mount result gets sent before the cast result
6702 }
6703 break;
6704 }
6706 {
6707 if (!m_targets.GetUnitTarget())
6709
6710 // can be cast at non-friendly unit or own pet/charm
6713 break;
6714 }
6715 case SPELL_AURA_FLY:
6717 {
6718 // not allow cast fly spells if not have req. skills (all spells is self target)
6719 // allow always ghost flight spells
6721 {
6722 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetMap(), m_originalCaster->GetZoneId());
6723 if (Bf && !Bf->CanFlyIn())
6724 return SPELL_FAILED_NOT_HERE;
6725 }
6726 break;
6727 }
6729 {
6730 if (spellEffectInfo.IsTargetingArea())
6731 break;
6732
6733 if (!m_targets.GetUnitTarget())
6735
6737 break;
6738
6741 break;
6742 }
6743 default:
6744 break;
6745 }
6746
6747 // check if target already has the same type, but more powerful aura
6750 && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex))
6752 if (Unit* target = m_targets.GetUnitTarget())
6753 if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, spellEffectInfo.ApplyAuraName,
6754 spellEffectInfo.CalcValue(m_caster, &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex], nullptr, nullptr, m_castItemEntry, m_castItemLevel),
6755 approximateAuraEffectMask, false))
6757 }
6758
6759 // check trade slot case (last, for allow catch any another cast problems)
6761 {
6762 if (m_CastItem)
6764
6767
6770
6771 TradeData* my_trade = m_caster->ToPlayer()->GetTradeData();
6772 if (!my_trade)
6774
6777
6778 if (!IsTriggered())
6779 if (my_trade->GetSpell())
6781 }
6782
6783 // all ok
6784 return SPELL_CAST_OK;
6785}
6786
6788{
6789 Unit* unitCaster = m_caster->ToUnit();
6790 if (unitCaster && unitCaster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
6792
6793 // dead owner (pets still alive when owners ressed?)
6794 if (Unit* owner = m_caster->GetCharmerOrOwner())
6795 if (!owner->IsAlive())
6797
6798 if (!target && m_targets.GetUnitTarget())
6799 target = m_targets.GetUnitTarget();
6800
6802 {
6803 if (!target)
6805 m_targets.SetUnitTarget(target);
6806 }
6807
6808 // check cooldown
6809 if (Creature* creatureCaster = m_caster->ToCreature())
6810 if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
6812
6813 // Check if spell is affected by GCD
6815 if (unitCaster && unitCaster->GetCharmInfo() && unitCaster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
6817
6818 return CheckCast(true);
6819}
6820
6822{
6823 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6824 if (!unitCaster)
6825 return SPELL_CAST_OK;
6826
6827 // these attributes only show the spell as usable on the client when it has related aura applied
6828 // still they need to be checked against certain mechanics
6829
6830 // SPELL_ATTR5_USABLE_WHILE_STUNNED by default only MECHANIC_STUN (ie no sleep, knockout, freeze, etc.)
6831 bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_STUNNED);
6832
6833 // SPELL_ATTR5_USABLE_WHILE_FEARED by default only fear (ie no horror)
6834 bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_FLEEING);
6835
6836 // SPELL_ATTR5_USABLE_WHILE_CONFUSED by default only disorient (ie no polymorph)
6837 bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_ALLOW_WHILE_CONFUSED);
6838
6839 // Check whether the cast should be prevented by any state you might have.
6841
6842 // Get unit state
6843 uint32 const unitflag = unitCaster->m_unitData->Flags;
6844
6845 // this check should only be done when player does cast directly
6846 // (ie not when it's called from a script) Breaks for example PlayerAI when charmed
6847 /*
6848 if (!unitCaster->GetCharmerGUID().IsEmpty())
6849 {
6850 if (Unit* charmer = unitCaster->GetCharmer())
6851 if (charmer->GetUnitBeingMoved() != unitCaster && !CheckSpellCancelsCharm(param1))
6852 result = SPELL_FAILED_CHARMED;
6853 }
6854 */
6855
6856 // spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell
6857 auto mechanicCheck = [&](AuraType type) -> SpellCastResult
6858 {
6859 bool foundNotMechanic = false;
6860 Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
6861 for (AuraEffect const* aurEff : auras)
6862 {
6863 uint64 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
6864 if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask()))
6865 {
6866 foundNotMechanic = true;
6867
6868 // fill up aura mechanic info to send client proper error message
6869 if (param1)
6870 {
6871 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6872 if (!*param1)
6873 *param1 = aurEff->GetSpellInfo()->Mechanic;
6874 }
6875
6876 break;
6877 }
6878 }
6879
6880 if (foundNotMechanic)
6881 {
6882 switch (type)
6883 {
6886 return SPELL_FAILED_STUNNED;
6888 return SPELL_FAILED_FLEEING;
6890 return SPELL_FAILED_CONFUSED;
6891 default:
6892 ABORT();
6894 }
6895 }
6896
6897 return SPELL_CAST_OK;
6898 };
6899
6900 if (unitflag & UNIT_FLAG_STUNNED)
6901 {
6902 if (usableWhileStunned)
6903 {
6904 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN);
6905 if (mechanicResult != SPELL_CAST_OK)
6906 result = mechanicResult;
6907 else
6908 {
6909 mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN_DISABLE_GRAVITY);
6910 if (mechanicResult != SPELL_CAST_OK)
6911 result = mechanicResult;
6912 }
6913 }
6914 else if (!CheckSpellCancelsStun(param1))
6915 result = SPELL_FAILED_STUNNED;
6917 result = SPELL_FAILED_STUNNED;
6918 }
6920 result = SPELL_FAILED_SILENCED;
6922 result = SPELL_FAILED_PACIFIED;
6923 else if (unitflag & UNIT_FLAG_FLEEING)
6924 {
6925 if (usableWhileFeared)
6926 {
6927 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_FEAR);
6928 if (mechanicResult != SPELL_CAST_OK)
6929 result = mechanicResult;
6930 }
6931 else if (!CheckSpellCancelsFear(param1))
6932 result = SPELL_FAILED_FLEEING;
6933 }
6934 else if (unitflag & UNIT_FLAG_CONFUSED)
6935 {
6936 if (usableWhileConfused)
6937 {
6938 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_CONFUSE);
6939 if (mechanicResult != SPELL_CAST_OK)
6940 result = mechanicResult;
6941 }
6942 else if (!CheckSpellCancelsConfuse(param1))
6943 result = SPELL_FAILED_CONFUSED;
6944 }
6946 result = SPELL_FAILED_NO_ACTIONS;
6947
6948 // Attr must make flag drop spell totally immune from all effects
6949 if (result != SPELL_CAST_OK)
6950 return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
6951
6952 return SPELL_CAST_OK;
6953}
6954
6956{
6957 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6958 if (!unitCaster)
6959 return false;
6960
6961 // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
6962 Unit::AuraEffectList const& auraEffects = unitCaster->GetAuraEffectsByType(auraType);
6963 if (auraEffects.empty())
6964 return true;
6965
6966 for (AuraEffect const* aurEff : auraEffects)
6967 {
6969 continue;
6970
6971 if (param1)
6972 {
6973 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6974 if (!*param1)
6975 *param1 = aurEff->GetSpellInfo()->Mechanic;
6976 }
6977
6978 return false;
6979 }
6980
6981 return true;
6982}
6983
6985{
6989}
6990
6992{
6995}
6996
6998{
7001}
7002
7004{
7007}
7008
7010{
7012}
7013
7015{
7017}
7018
7020{
7022}
7023
7025{
7026 bool isRatedBattleground = false; // NYI
7027 bool isArena = !isRatedBattleground;
7028
7029 // check USABLE attributes
7030 // USABLE takes precedence over NOT_USABLE
7032 return SPELL_CAST_OK;
7033
7035 return SPELL_CAST_OK;
7036
7037 // check NOT_USABLE attributes
7040
7043
7044 // check cooldowns
7045 uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
7046 if (isArena && spellCooldown > 10 * MINUTE * IN_MILLISECONDS) // not sure if still needed
7048
7049 if (isRatedBattleground && spellCooldown > 15 * MINUTE * IN_MILLISECONDS)
7051
7052 return SPELL_CAST_OK;
7053}
7054
7056{
7057 if (IsTriggered())
7058 return SPELL_CAST_OK;
7059
7060 // Creatures (not controlled) give priority to spell casting over movement.
7061 // We assume that the casting is always valid and the current movement
7062 // is stopped by Unit:IsmovementPreventedByCasting to prevent casting interruption.
7064 return SPELL_CAST_OK;
7065
7066 if (Unit* unitCaster = m_caster->ToUnit())
7067 {
7068 if (!unitCaster->CanCastSpellWhileMoving(m_spellInfo))
7069 {
7071 {
7072 if (m_casttime > 0)
7074 return SPELL_FAILED_MOVING;
7075 }
7076 else if (getState() == SPELL_STATE_CASTING)
7078 return SPELL_FAILED_MOVING;
7079 }
7080 }
7081
7082 return SPELL_CAST_OK;
7083}
7084
7085int32 Spell::CalculateDamage(SpellEffectInfo const& spellEffectInfo, Unit const* target, float* var /*= nullptr*/) const
7086{
7087 bool needRecalculateBasePoints = !(m_spellValue->CustomBasePointsMask & (1 << spellEffectInfo.EffectIndex));
7088 return m_caster->CalculateSpellDamage(target, spellEffectInfo, needRecalculateBasePoints ? nullptr : &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex], var, m_castItemEntry, m_castItemLevel);
7089}
7090
7092{
7093 if (!target)
7094 return (CheckPetCast(target) == SPELL_CAST_OK);
7095
7096 ObjectGuid targetguid = target->GetGUID();
7097
7098 // check if target already has the same or a more powerful aura
7099 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7100 {
7101 if (!spellEffectInfo.IsAura())
7102 continue;
7103
7104 AuraType const& auraType = spellEffectInfo.ApplyAuraName;
7105 Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
7106 for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
7107 {
7108 if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
7109 return false;
7110
7111 switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
7112 {
7114 return false;
7116 if (GetCaster() == (*auraIt)->GetCaster())
7117 return false;
7118 break;
7119 case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
7121 if (abs(spellEffectInfo.CalcBaseValue(m_caster, target, 0, -1)) <= abs((*auraIt)->GetAmount()))
7122 return false;
7123 break;
7125 default:
7126 break;
7127 }
7128 }
7129 }
7130
7131 SpellCastResult result = CheckPetCast(target);
7132 if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
7133 {
7134 // do not check targets for ground-targeted spells (we target them on top of the intended target anyway)
7135 if (GetSpellInfo()->ExplicitTargetMask & TARGET_FLAG_DEST_LOCATION)
7136 return true;
7138 //check if among target units, our WANTED target is as well (->only self cast spells return false)
7139 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
7140 if (ihit->TargetGUID == targetguid)
7141 return true;
7142 }
7143 // either the cast failed or the intended target wouldn't be hit
7144 return false;
7145}
7146
7148{
7149 if (!m_targets.HasSrc())
7151}
7152
7154{
7155 if (!m_targets.HasDst())
7157}
7158
7160{
7161 // Don't check for instant cast spells
7162 if (!strict && m_casttime == 0)
7163 return SPELL_CAST_OK;
7164
7165 auto [minRange, maxRange] = GetMinMaxRange(strict);
7166
7167 // dont check max_range to strictly after cast
7169 maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
7170
7171 // get square values for sqr distance checks
7172 minRange *= minRange;
7173 maxRange *= maxRange;
7174
7175 Unit* target = m_targets.GetUnitTarget();
7176 if (target && target != m_caster)
7177 {
7178 if (m_caster->GetExactDistSq(target) > maxRange)
7180
7181 if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange)
7183
7184 if (m_caster->GetTypeId() == TYPEID_PLAYER &&
7185 (((m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
7186 && !m_caster->ToPlayer()->IsWithinBoundaryRadius(target)))
7188 }
7189
7190 if (GameObject* goTarget = m_targets.GetGOTarget())
7191 {
7192 if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
7194 }
7195
7196 if (m_targets.HasDst() && !m_targets.HasTraj())
7197 {
7198 if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange)
7200 if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange)
7202 }
7203
7204 return SPELL_CAST_OK;
7205}
7206
7207std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
7208{
7209 float rangeMod = 0.0f;
7210 float minRange = 0.0f;
7211 float maxRange = 0.0f;
7212
7213 if (strict && m_spellInfo->IsNextMeleeSwingSpell())
7214 return { 0.0f, 100.0f };
7215
7216 Unit* unitCaster = m_caster->ToUnit();
7218 {
7219 Unit* target = m_targets.GetUnitTarget();
7221 {
7222 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
7223 if (unitCaster)
7224 rangeMod = unitCaster->GetMeleeRange(target ? target : unitCaster);
7225 }
7226 else
7227 {
7228 float meleeRange = 0.0f;
7230 {
7231 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
7232 if (unitCaster)
7233 meleeRange = unitCaster->GetMeleeRange(target ? target : unitCaster);
7234 }
7235
7236 minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
7237 maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
7238
7239 if (target || m_targets.GetCorpseTarget())
7240 {
7241 rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
7242
7243 if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
7244 minRange += rangeMod;
7245 }
7246 }
7247
7248 if (target && unitCaster && unitCaster->isMoving() && target->isMoving() && !unitCaster->IsWalking() && !target->IsWalking() &&
7250 rangeMod += 8.0f / 3.0f;
7251 }
7252
7254 if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
7255 maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
7256
7257 if (Player* modOwner = m_caster->GetSpellModOwner())
7258 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::Range, maxRange, const_cast<Spell*>(this));
7259
7260 maxRange += rangeMod;
7261
7262 return { minRange, maxRange };
7263}
7264
7266{
7267 Unit* unitCaster = m_caster->ToUnit();
7268 if (!unitCaster)
7269 return SPELL_CAST_OK;
7270
7271 // item cast not used power
7272 if (m_CastItem)
7273 return SPELL_CAST_OK;
7274
7275 for (SpellPowerCost const& cost : m_powerCost)
7276 {
7277 // health as power used - need check health amount
7278 if (cost.Power == POWER_HEALTH)
7279 {
7280 if (int64(unitCaster->GetHealth()) <= cost.Amount)
7282 continue;
7283 }
7284 // Check valid power type
7285 if (cost.Power >= MAX_POWERS)
7286 {
7287 TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '{}'", cost.Power);
7288 return SPELL_FAILED_UNKNOWN;
7289 }
7290
7291 //check rune cost only if a spell has PowerType == POWER_RUNES
7292 if (cost.Power == POWER_RUNES)
7293 {
7294 SpellCastResult failReason = CheckRuneCost();
7295 if (failReason != SPELL_CAST_OK)
7296 return failReason;
7297 }
7298
7299 // Check power amount
7300 if (int32(unitCaster->GetPower(cost.Power)) < cost.Amount)
7301 return SPELL_FAILED_NO_POWER;
7302 }
7303
7304 return SPELL_CAST_OK;
7305}
7306
7307SpellCastResult Spell::CheckItems(int32* param1 /*= nullptr*/, int32* param2 /*= nullptr*/) const
7308{
7309 Player* player = m_caster->ToPlayer();
7310 if (!player)
7311 return SPELL_CAST_OK;
7312
7313 if (!m_CastItem)
7314 {
7315 if (!m_castItemGUID.IsEmpty())
7317 }
7318 else
7319 {
7320 uint32 itemid = m_CastItem->GetEntry();
7321 if (!player->HasItemCount(itemid))
7323
7324 ItemTemplate const* proto = m_CastItem->GetTemplate();
7325 if (!proto)
7327
7328 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
7329 if (itemEffect->LegacySlotIndex < m_CastItem->m_itemData->SpellCharges.size() && itemEffect->Charges)
7330 if (m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex) == 0)
7332
7333 // consumable cast item checks
7335 {
7336 // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
7337 SpellCastResult failReason = SPELL_CAST_OK;
7338 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7339 {
7340 // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster
7341 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
7342 continue;
7343
7344 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
7345 {
7347 {
7349 continue;
7350 }
7351 else
7352 {
7353 failReason = SPELL_CAST_OK;
7354 break;
7355 }
7356 }
7357
7358 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
7359 if (spellEffectInfo.IsEffect(SPELL_EFFECT_ENERGIZE))
7360 {
7361 if (spellEffectInfo.MiscValue < 0 || spellEffectInfo.MiscValue >= int8(MAX_POWERS))
7362 {
7364 continue;
7365 }
7366
7367 Powers power = Powers(spellEffectInfo.MiscValue);
7369 {
7371 continue;
7372 }
7373 else
7374 {
7375 failReason = SPELL_CAST_OK;
7376 break;
7377 }
7378 }
7379 }
7380 if (failReason != SPELL_CAST_OK)
7381 return failReason;
7382 }
7383 }
7384
7385 // check target item
7387 {
7388 Item* item = m_targets.GetItemTarget();
7389 if (!item)
7391
7394 }
7395 // if not item target then required item must be equipped
7396 else
7397 {
7401 }
7402
7403 // do not take reagents for these item casts
7405 {
7407 // Not own traded item (in trader trade slot) requires reagents even if triggered spell
7408 if (!checkReagents)
7409 if (Item* targetItem = m_targets.GetItemTarget())
7410 if (targetItem->GetOwnerGUID() != player->GetGUID())
7411 checkReagents = true;
7412
7413 // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
7414 if (checkReagents)
7415 {
7416 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
7417 {
7418 if (m_spellInfo->Reagent[i] <= 0)
7419 continue;
7420
7421 uint32 itemid = m_spellInfo->Reagent[i];
7422 uint32 itemcount = m_spellInfo->ReagentCount[i];
7423
7424 // if CastItem is also spell reagent
7425 if (m_CastItem && m_CastItem->GetEntry() == itemid)
7426 {
7427 ItemTemplate const* proto = m_CastItem->GetTemplate();
7428 if (!proto)
7430
7431 for (ItemEffectEntry const* itemEffect : m_CastItem->GetEffects())
7432 {
7433 if (itemEffect->LegacySlotIndex >= m_CastItem->m_itemData->SpellCharges.size())
7434 continue;
7435
7436 // CastItem will be used up and does not count as reagent
7437 int32 charges = m_CastItem->GetSpellCharges(itemEffect->LegacySlotIndex);
7438 if (itemEffect->Charges < 0 && abs(charges) < 2)
7439 {
7440 ++itemcount;
7441 break;
7442 }
7443 }
7444 }
7445 if (!player->HasItemCount(itemid, itemcount))
7446 {
7447 if (param1)
7448 *param1 = itemid;
7449 return SPELL_FAILED_REAGENTS;
7450 }
7451 }
7452
7453 for (SpellReagentsCurrencyEntry const* reagentsCurrency : m_spellInfo->ReagentsCurrency)
7454 {
7455 if (!player->HasCurrency(reagentsCurrency->CurrencyTypesID, reagentsCurrency->CurrencyCount))
7456 {
7457 if (param1)
7458 *param1 = -1;
7459
7460 if (param2)
7461 *param2 = reagentsCurrency->CurrencyTypesID;
7462
7463 return SPELL_FAILED_REAGENTS;
7464 }
7465 }
7466 }
7467
7468 // check totem-item requirements (items presence in inventory)
7469 uint32 totems = 2;
7470 for (uint8 i = 0; i < 2; ++i)
7471 {
7472 if (m_spellInfo->Totem[i] != 0)
7473 {
7474 if (player->HasItemCount(m_spellInfo->Totem[i]))
7475 {
7476 totems -= 1;
7477 continue;
7478 }
7479 }
7480 else
7481 totems -= 1;
7482 }
7483
7484 if (totems != 0)
7485 return SPELL_FAILED_TOTEMS;
7486
7487 // Check items for TotemCategory (items presence in inventory)
7488 uint32 totemCategory = 2;
7489 for (uint8 i = 0; i < 2; ++i)
7490 {
7491 if (m_spellInfo->TotemCategory[i] != 0)
7492 {
7494 {
7495 totemCategory -= 1;
7496 continue;
7497 }
7498 }
7499 else
7500 totemCategory -= 1;
7501 }
7502
7503 if (totemCategory != 0)
7505 }
7506
7507 // special checks for spell effects
7508 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7509 {
7510 switch (spellEffectInfo.Effect)
7511 {
7514 {
7515 // m_targets.GetUnitTarget() means explicit cast, otherwise we dont check for possible equip error
7516 Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
7517 if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered())
7518 {
7519 // 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,
7520 // so we need to make sure there is at least one free space in the player's inventory
7521 if (spellEffectInfo.Effect == SPELL_EFFECT_CREATE_LOOT)
7522 if (target->ToPlayer()->GetFreeInventorySpace() == 0)
7523 {
7524 player->SendEquipError(EQUIP_ERR_INV_FULL, nullptr, nullptr, spellEffectInfo.ItemType);
7526 }
7527
7528 if (spellEffectInfo.ItemType)
7529 {
7530 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType);
7531 if (!itemTemplate)
7533
7534 uint32 createCount = std::clamp<uint32>(spellEffectInfo.CalcValue(), 1u, itemTemplate->GetMaxStackSize());
7535 ItemPosCountVec dest;
7536 InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, createCount);
7537 if (msg != EQUIP_ERR_OK)
7538 {
7540 if (!itemTemplate->GetItemLimitCategory())
7541 {
7542 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7544 }
7545 else
7546 {
7547 // Conjure Food/Water/Refreshment spells
7550 else if (!(target->ToPlayer()->HasItemCount(spellEffectInfo.ItemType)))
7551 {
7552 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7554 }
7555 else if (m_spellInfo->GetEffects().size() > EFFECT_1)
7557 .SetTriggeringSpell(this)); // move this to anywhere
7559 }
7560 }
7561 }
7562 }
7563 break;
7564 }
7566 if (spellEffectInfo.ItemType && m_targets.GetItemTarget()
7568 {
7569 // cannot enchant vellum for other player
7570 if (m_targets.GetItemTarget()->GetOwner() != player)
7572 // do not allow to enchant vellum from scroll made by vellum-prevent exploit
7575 ItemPosCountVec dest;
7576 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, 1);
7577 if (msg != EQUIP_ERR_OK)
7578 {
7579 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
7581 }
7582 }
7583 [[fallthrough]];
7585 {
7586 Item* targetItem = m_targets.GetItemTarget();
7587 if (!targetItem)
7589
7590 // required level has to be checked also! Exploit fix
7591 if (targetItem->GetItemLevel(targetItem->GetOwner()) < m_spellInfo->BaseLevel || (targetItem->GetRequiredLevel() && uint32(targetItem->GetRequiredLevel()) < m_spellInfo->BaseLevel))
7592 return SPELL_FAILED_LOWLEVEL;
7593
7594 bool isItemUsable = false;
7595 for (ItemEffectEntry const* itemEffect : targetItem->GetEffects())
7596 {
7597 if (itemEffect->SpellID && itemEffect->TriggerType == ITEM_SPELLTRIGGER_ON_USE)
7598 {
7599 isItemUsable = true;
7600 break;
7601 }
7602 }
7603
7604 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(spellEffectInfo.MiscValue);
7605 // do not allow adding usable enchantments to items that have use effect already
7606 if (enchantEntry)
7607 {
7608 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
7609 {
7610 switch (enchantEntry->Effect[s])
7611 {
7613 if (isItemUsable)
7615 break;
7617 {
7618 uint32 numSockets = 0;
7619 for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket)
7620 if (targetItem->GetSocketColor(socket))
7621 ++numSockets;
7622
7623 if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
7625 break;
7626 }
7627 }
7628 }
7629 }
7630
7631 // Not allow enchant in trade slot for some enchant type
7632 if (targetItem->GetOwner() != player)
7633 {
7634 if (!enchantEntry)
7635 return SPELL_FAILED_ERROR;
7636 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
7638 }
7639 break;
7640 }
7642 {
7643 Item* item = m_targets.GetItemTarget();
7644 if (!item)
7646 // Not allow enchant in trade slot for some enchant type
7647 if (item->GetOwner() != player)
7648 {
7649 uint32 enchant_id = spellEffectInfo.MiscValue;
7650 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
7651 if (!enchantEntry)
7652 return SPELL_FAILED_ERROR;
7653 if (enchantEntry->GetFlags().HasFlag(SpellItemEnchantmentFlags::Soulbound))
7655 }
7656
7657 // Apply item level restriction if the enchanting spell has max level restrition set
7658 if (m_CastItem && m_spellInfo->MaxLevel > 0)
7659 {
7661 return SPELL_FAILED_LOWLEVEL;
7664 }
7665 break;
7666 }
7668 // check item existence in effect code (not output errors at offhand hold item effect to main hand for example
7669 break;
7671 {
7672 Item const* item = m_targets.GetItemTarget();
7673 if (!item)
7675
7676 // prevent disenchanting in trade slot
7677 if (item->GetOwnerGUID() != player->GetGUID())
7679
7680 ItemTemplate const* itemProto = item->GetTemplate();
7681 if (!itemProto)
7683
7684 ItemDisenchantLootEntry const* itemDisenchantLoot = item->GetDisenchantLoot(m_caster->ToPlayer());
7685 if (!itemDisenchantLoot)
7687 if (itemDisenchantLoot->SkillRequired > player->GetSkillValue(SKILL_ENCHANTING))
7689 break;
7690 }
7692 {
7693 Item* item = m_targets.GetItemTarget();
7694 if (!item)
7696 //ensure item is a prospectable ore
7699 //prevent prospecting in trade slot
7700 if (item->GetOwnerGUID() != player->GetGUID())
7702 //Check for enough skill in jewelcrafting
7703 uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7704 if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
7706 //make sure the player has the required ores in inventory
7707 if (item->GetCount() < 5)
7708 {
7709 if (param1 && param2)
7710 {
7711 *param1 = item->GetEntry();
7712 *param2 = 5;
7713 }
7715 }
7716
7719
7720 break;
7721 }
7723 {
7724 Item* item = m_targets.GetItemTarget();
7725 if (!item)
7727 //ensure item is a millable herb
7730 //prevent milling in trade slot
7731 if (item->GetOwnerGUID() != player->GetGUID())
7733 //Check for enough skill in inscription
7734 uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7735 if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
7737 //make sure the player has the required herbs in inventory
7738 if (item->GetCount() < 5)
7739 {
7740 if (param1 && param2)
7741 {
7742 *param1 = item->GetEntry();
7743 *param2 = 5;
7744 }
7746 }
7747
7750
7751 break;
7752 }
7755 {
7757 break;
7758
7759 Item* item = player->GetWeaponForAttack(m_attackType);
7760 if (!item || item->IsBroken())
7762
7763 switch (item->GetTemplate()->GetSubClass())
7764 {
7766 {
7767 uint32 const ammo = item->GetEntry();
7768 if (!player->HasItemCount(ammo))
7769 return SPELL_FAILED_NO_AMMO;
7770 break;
7771 }
7776 break;
7777 default:
7778 break;
7779 }
7780 break;
7781 }
7783 {
7784 uint32 itemId = spellEffectInfo.ItemType;
7785
7786 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId);
7787 if (!proto)
7789
7790 if (Item* item = player->GetItemByEntry(itemId))
7791 for (ItemEffectEntry const* itemEffect : item->GetEffects())
7792 if (itemEffect->LegacySlotIndex <= item->m_itemData->SpellCharges.size()
7793 && itemEffect->Charges != 0
7794 && item->GetSpellCharges(itemEffect->LegacySlotIndex) == itemEffect->Charges)
7796 break;
7797 }
7799 {
7800 Item const* item = m_targets.GetItemTarget();
7801 if (!item)
7803
7804 if (item->GetOwnerGUID() != m_caster->GetGUID())
7806
7807 AzeriteEmpoweredItem const* azeriteEmpoweredItem = item->ToAzeriteEmpoweredItem();
7808 if (!azeriteEmpoweredItem)
7810
7811 bool hasSelections = false;
7812 for (int32 tier = 0; tier < MAX_AZERITE_EMPOWERED_TIER; ++tier)
7813 {
7814 if (azeriteEmpoweredItem->GetSelectedAzeritePower(tier))
7815 {
7816 hasSelections = true;
7817 break;
7818 }
7819 }
7820
7821 if (!hasSelections)
7823
7824 if (!m_caster->ToPlayer()->HasEnoughMoney(azeriteEmpoweredItem->GetRespecCost()))
7826
7827 break;
7828 }
7829 default:
7830 break;
7831 }
7832 }
7833
7834 // check weapon presence in slots for main/offhand weapons
7836 {
7837 auto weaponCheck = [&](WeaponAttackType attackType) -> SpellCastResult
7838 {
7839 Item const* item = player->GetWeaponForAttack(attackType);
7840
7841 // skip spell if no weapon in slot or broken
7842 if (!item || item->IsBroken())
7844
7845 // skip spell if weapon not fit to triggered spell
7848
7849 return SPELL_CAST_OK;
7850 };
7851
7853 {
7854 SpellCastResult mainHandResult = weaponCheck(BASE_ATTACK);
7855 if (mainHandResult != SPELL_CAST_OK)
7856 return mainHandResult;
7857 }
7858
7860 {
7861 SpellCastResult offHandResult = weaponCheck(OFF_ATTACK);
7862 if (offHandResult != SPELL_CAST_OK)
7863 return offHandResult;
7864 }
7865 }
7866
7867 return SPELL_CAST_OK;
7868}
7869
7870void Spell::Delayed() // only called in DealDamage()
7871{
7872 Unit* unitCaster = m_caster->ToUnit();
7873 if (!unitCaster)
7874 return;
7875
7876 if (IsDelayableNoMore()) // Spells may only be delayed twice
7877 return;
7878
7879 //check pushback reduce
7880 int32 delaytime = 500; // spellcasting delay is normally 500ms
7881
7882 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
7883 if (Player* player = unitCaster->GetSpellModOwner())
7884 player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
7885 delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
7886 if (delayReduce >= 100)
7887 return;
7888
7889 AddPct(delaytime, -delayReduce);
7890
7891 if (m_timer + delaytime > m_casttime)
7892 {
7893 delaytime = m_casttime - m_timer;
7895 }
7896 else
7897 m_timer += delaytime;
7898
7900 spellDelayed.Caster = unitCaster->GetGUID();
7901 spellDelayed.ActualDelay = delaytime;
7902
7903 unitCaster->SendMessageToSet(spellDelayed.Write(), true);
7904}
7905
7907{
7908 Unit* unitCaster = m_caster->ToUnit();
7909 if (!unitCaster)
7910 return;
7911
7913 return;
7914
7915 if (IsDelayableNoMore()) // Spells may only be delayed twice
7916 return;
7917
7918 //check pushback reduce
7919 // should be affected by modifiers, not take the dbc duration.
7921
7922 int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
7923
7924 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
7925 if (Player* player = unitCaster->GetSpellModOwner())
7926 player->ApplySpellMod(m_spellInfo, SpellModOp::ResistPushback, delayReduce, this);
7927 delayReduce += unitCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
7928 if (delayReduce >= 100)
7929 return;
7930
7931 AddPct(delaytime, -delayReduce);
7932
7933 if (m_timer <= delaytime)
7934 {
7935 delaytime = m_timer;
7936 m_timer = 0;
7937 }
7938 else
7939 m_timer -= delaytime;
7940
7941 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
7942 if (targetInfo.MissCondition == SPELL_MISS_NONE)
7943 if (Unit* unit = (unitCaster->GetGUID() == targetInfo.TargetGUID) ? unitCaster : ObjectAccessor::GetUnit(*unitCaster, targetInfo.TargetGUID))
7944 unit->DelayOwnedAuras(m_spellInfo->Id, m_originalCasterGUID, delaytime);
7945
7946 // partially interrupt persistent area auras
7947 if (DynamicObject* dynObj = unitCaster->GetDynObject(m_spellInfo->Id))
7948 dynObj->Delay(delaytime);
7949
7951}
7952
7954{
7955 return GetPowerTypeCostAmount(power).has_value();
7956}
7957
7959{
7960 auto itr = std::find_if(m_powerCost.cbegin(), m_powerCost.cend(), [power](SpellPowerCost const& cost)
7961 {
7962 return cost.Power == power;
7963 });
7964
7965 if (itr == m_powerCost.cend())
7966 return { };
7967
7968 return itr->Amount;
7969}
7970
7972{
7975 else
7976 {
7979 m_originalCaster = nullptr;
7980 }
7981
7983 {
7985 m_castItemLevel = -1;
7986 // cast item not found, somehow the item is no longer where we expected
7987 if (!m_CastItem)
7988 return false;
7989
7990 // check if the item is really the same, in case it has been wrapped for example
7992 return false;
7993
7995 }
7996
7998
7999 // further actions done only for dest targets
8000 if (!m_targets.HasDst())
8001 return true;
8002
8003 // cache last transport
8004 WorldObject* transport = nullptr;
8005
8006 // update effect destinations (in case of moved transport dest target)
8007 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8008 {
8009 SpellDestination& dest = m_destTargets[spellEffectInfo.EffectIndex];
8010 if (!dest._transportGUID)
8011 continue;
8012
8013 if (!transport || transport->GetGUID() != dest._transportGUID)
8015
8016 if (transport)
8017 {
8018 dest._position.Relocate(transport);
8020 }
8021 }
8022
8023 return true;
8024}
8025
8027{
8029 return CURRENT_MELEE_SPELL;
8030 else if (IsAutoRepeat())
8032 else if (m_spellInfo->IsChanneled())
8034
8035 return CURRENT_GENERIC_SPELL;
8036}
8037
8039{
8040 return m_caster->GetMap()->GetDifficultyID();
8041}
8042
8043bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEffectInfo, Position const* losPosition) const
8044{
8045 switch (spellEffectInfo.ApplyAuraName)
8046 {
8051 if (target->GetVehicleKit() && target->GetVehicleKit()->IsControllableVehicle())
8052 return false;
8053 if (target->IsMounted())
8054 return false;
8055 if (!target->GetCharmerGUID().IsEmpty())
8056 return false;
8057 if (int32 value = CalculateDamage(spellEffectInfo, target))
8058 if ((int32)target->GetLevelForTarget(m_caster) > value)
8059 return false;
8060 break;
8061 default:
8062 break;
8063 }
8064
8065 // check for ignore LOS on the effect itself
8067 return true;
8068
8069 // check if gameobject ignores LOS
8070 if (GameObject const* gobCaster = m_caster->ToGameObject())
8071 if (!gobCaster->GetGOInfo()->GetRequireLOS())
8072 return true;
8073
8074 // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
8076 return true;
8077
8079 //Check targets for LOS visibility
8080 switch (spellEffectInfo.Effect)
8081 {
8083 {
8085 {
8087 return true;
8088
8089 return false;
8090 }
8091
8093 if (!corpse)
8094 return false;
8095
8096 if (target->GetGUID() != corpse->GetOwnerGUID())
8097 return false;
8098
8100 return false;
8101
8102 if (!IsWithinLOS(m_caster, corpse, true, VMAP::ModelIgnoreFlags::M2))
8103 return false;
8104
8105 break;
8106 }
8107 default:
8108 {
8110 {
8111 // Get GO cast coordinates if original caster -> GO
8112 WorldObject* caster = nullptr;
8115 if (!caster)
8116 caster = m_caster;
8117
8118 if (target != m_caster && !IsWithinLOS(caster, target, true, VMAP::ModelIgnoreFlags::M2))
8119 return false;
8120 }
8121
8122 if (losPosition)
8123 if (!IsWithinLOS(target, *losPosition, VMAP::ModelIgnoreFlags::M2))
8124 return false;
8125 }
8126 }
8127
8128 return true;
8129}
8130
8131bool Spell::CheckEffectTarget(GameObject const* target, SpellEffectInfo const& spellEffectInfo) const
8132{
8133 switch (spellEffectInfo.Effect)
8134 {
8139 return false;
8140 break;
8141 default:
8142 break;
8143 }
8144
8145 return true;
8146}
8147
8148bool Spell::CheckEffectTarget(Item const* /*target*/, SpellEffectInfo const& /*spellEffectInfo*/) const
8149{
8150 return true;
8151}
8152
8154{
8156}
8157
8159{
8161}
8162
8164{
8166}
8167
8169{
8171}
8172
8174{
8175 return m_caster->IsUnit() && m_caster->ToUnit()->GetChannelSpellId() != 0;
8176}
8177
8179{
8181 return false;
8182
8184 return false;
8185
8186 return true;
8187}
8188
8190{
8192}
8193
8195{
8199}
8200
8202{
8204}
8205
8206SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell)
8207{
8208}
8209
8211{
8213 m_Spell->cancel();
8214
8215 if (!m_Spell->IsDeletable())
8216 {
8217 TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.",
8218 (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id);
8219 ABORT();
8220 }
8221}
8222
8224{
8225 // update spell if it is not finished
8227 m_Spell->update(p_time);
8228
8229 // check spell state to process
8230 switch (m_Spell->getState())
8231 {
8233 {
8234 // spell was finished, check deletable state
8235 if (m_Spell->IsDeletable())
8236 {
8237 // check, if we do have unfinished triggered spells
8238 return true; // spell is deletable, finish event
8239 }
8240 // event will be re-added automatically at the end of routine)
8241 break;
8242 }
8244 {
8245 // first, check, if we have just started
8246 if (m_Spell->GetDelayStart() != 0)
8247 {
8248 // no, we aren't, do the typical update
8249 // check, if we have channeled spell on our hands
8250 /*
8251 if (m_Spell->m_spellInfo->IsChanneled())
8252 {
8253 // evented channeled spell is processed separately, cast once after delay, and not destroyed till finish
8254 // check, if we have casting anything else except this channeled spell and autorepeat
8255 if (m_Spell->GetCaster()->IsNonMeleeSpellCast(false, true, true))
8256 {
8257 // another non-melee non-delayed spell is cast now, abort
8258 m_Spell->cancel();
8259 }
8260 else
8261 {
8262 // Set last not triggered spell for apply spellmods
8263 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, true);
8264 // do the action (pass spell to channeling state)
8265 m_Spell->handle_immediate();
8266
8267 // And remove after effect handling
8268 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, false);
8269 }
8270 // event will be re-added automatically at the end of routine)
8271 }
8272 else
8273 */
8274 {
8275 // run the spell handler and think about what we can do next
8276 uint64 t_offset = e_time - m_Spell->GetDelayStart();
8277 uint64 n_offset = m_Spell->handle_delayed(t_offset);
8278 if (n_offset)
8279 {
8280 // re-add us to the queue
8281 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(m_Spell->GetDelayStart() + n_offset), false);
8282 return false; // event not complete
8283 }
8284 // event complete
8285 // finish update event will be re-added automatically at the end of routine)
8286 }
8287 }
8288 else
8289 {
8290 // delaying had just started, record the moment
8291 m_Spell->SetDelayStart(e_time);
8292 // handle effects on caster if the spell has travel time but also affects the caster in some way
8293 uint64 n_offset = m_Spell->handle_delayed(0);
8295 ASSERT(n_offset == uint64(std::floor(m_Spell->m_spellInfo->LaunchDelay * 1000.0f)));
8296 else
8297 ASSERT(n_offset == m_Spell->GetDelayMoment(), UI64FMTD " == " UI64FMTD, n_offset, m_Spell->GetDelayMoment());
8298 // re-plan the event for the delay moment
8299 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + n_offset), false);
8300 return false; // event not complete
8301 }
8302 break;
8303 }
8304 default:
8305 {
8306 // all other states
8307 // event will be re-added automatically at the end of routine)
8308 break;
8309 }
8310 }
8311
8312 // spell processing not complete, plan event on the next update interval
8313 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + 1), false);
8314 return false; // event not complete
8315}
8316
8318{
8319 // oops, the spell we try to do is aborted
8321 m_Spell->cancel();
8322}
8323
8325{
8326 return m_Spell->IsDeletable();
8327}
8328
8329bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
8330{
8331 if (target->IsAlive())
8334 return true;
8335 return false;
8336}
8337
8339{
8340 // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode
8341 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8342 {
8343 // don't do anything for empty effect
8344 if (!spellEffectInfo.IsEffect())
8345 continue;
8346
8347 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
8348 }
8349
8351
8352 for (TargetInfo& target : m_UniqueTargetInfo)
8353 PreprocessSpellLaunch(target);
8354
8355 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8356 {
8357 float multiplier = 1.0f;
8358 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
8359 multiplier = spellEffectInfo.CalcDamageMultiplier(m_originalCaster, this);
8360
8361 for (TargetInfo& target : m_UniqueTargetInfo)
8362 {
8363 uint32 mask = target.EffectMask;
8364 if (!(mask & (1 << spellEffectInfo.EffectIndex)))
8365 continue;
8366
8367 DoEffectOnLaunchTarget(target, multiplier, spellEffectInfo);
8368 }
8369 }
8370
8372}
8373
8375{
8376 Unit* targetUnit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
8377 if (!targetUnit)
8378 return;
8379
8380 // This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
8382 m_originalCaster->SetInCombatWith(targetUnit, true);
8383
8384 Unit* unit = nullptr;
8385 // In case spell hit target, do all effect on that target
8386 if (targetInfo.MissCondition == SPELL_MISS_NONE)
8387 unit = targetUnit;
8388 // In case spell reflect from target, do all effect on caster (if hit)
8389 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
8390 unit = m_caster->ToUnit();
8391
8392 if (!unit)
8393 return;
8394
8395 float critChance = m_spellValue->CriticalChance;
8396 if (m_originalCaster)
8397 {
8398 if (!critChance)
8400 critChance = unit->SpellCritChanceTaken(m_originalCaster, this, nullptr, m_spellSchoolMask, critChance, m_attackType);
8401 }
8402
8403 targetInfo.IsCrit = roll_chance_f(critChance);
8404}
8405
8406void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, SpellEffectInfo const& spellEffectInfo)
8407{
8408 Unit* unit = nullptr;
8409 // In case spell hit target, do all effect on that target
8411 unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
8412 // In case spell reflect from target, do all effect on caster (if hit)
8413 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
8414 unit = m_caster->ToUnit();
8415
8416 if (!unit)
8417 return;
8418
8419 m_damage = 0;
8420 m_healing = 0;
8421
8422 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
8423
8424 if (m_originalCaster && m_damage > 0)
8425 {
8426 bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
8428 {
8430
8432 {
8435
8436 // sqrt target cap damage calculation
8440 m_damage = m_damage * std::sqrt(float(m_spellInfo->SqrtDamageAndHealingDiminishing.MaxTargets) / std::min(AOE_DAMAGE_TARGET_CAP, targetCount));
8441
8442 // cap damage of player AOE
8443 if (targetCount > AOE_DAMAGE_TARGET_CAP)
8444 m_damage = m_damage * AOE_DAMAGE_TARGET_CAP / targetCount;
8445 }
8446 }
8447 }
8448
8449 if (m_originalCaster && m_healing > 0)
8450 {
8451 bool isAoeTarget = spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA);
8453 {
8455 {
8458
8459 // sqrt target cap healing calculation
8464 }
8465 }
8466 }
8467
8468 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
8469 {
8472
8473 m_damageMultipliers[spellEffectInfo.EffectIndex] *= multiplier;
8474 }
8475
8476 targetInfo.Damage += m_damage;
8477 targetInfo.Healing += m_healing;
8478}
8479
8481{
8482 Unit* unitCaster = m_caster->ToUnit();
8483 if (!unitCaster)
8484 return;
8485
8486 unitCaster->resetAttackTimer(BASE_ATTACK);
8487 if (unitCaster->haveOffhandWeapon())
8488 unitCaster->resetAttackTimer(OFF_ATTACK);
8489 unitCaster->resetAttackTimer(RANGED_ATTACK);
8490}
8491
8492SpellCastResult Spell::CanOpenLock(SpellEffectInfo const& effect, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
8493{
8494 if (!lockId) // possible case for GO and maybe for items.
8495 return SPELL_CAST_OK;
8496
8497 Unit const* unitCaster = m_caster->ToUnit();
8498 if (!unitCaster)
8500
8501 // Get LockInfo
8502 LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
8503
8504 if (!lockInfo)
8506
8507 bool reqKey = false; // some locks not have reqs
8508
8509 for (int j = 0; j < MAX_LOCK_CASE; ++j)
8510 {
8511 switch (lockInfo->Type[j])
8512 {
8513 // check key item (many fit cases can be)
8514 case LOCK_KEY_ITEM:
8515 if (lockInfo->Index[j] && m_CastItem && int32(m_CastItem->GetEntry()) == lockInfo->Index[j])
8516 return SPELL_CAST_OK;
8517 reqKey = true;
8518 break;
8519 // check key skill (only single first fit case can be)
8520 case LOCK_KEY_SKILL:
8521 {
8522 reqKey = true;
8523
8524 // wrong locktype, skip
8525 if (effect.MiscValue != lockInfo->Index[j])
8526 continue;
8527
8528 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
8529
8530 if (skillId != SKILL_NONE || lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
8531 {
8532 reqSkillValue = lockInfo->Skill[j];
8533
8534 // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
8535 skillValue = 0;
8536 if (!m_CastItem && unitCaster->GetTypeId() == TYPEID_PLAYER)
8537 skillValue = unitCaster->ToPlayer()->GetSkillValue(skillId);
8538 else if (lockInfo->Index[j] == LOCKTYPE_LOCKPICKING)
8539 skillValue = unitCaster->GetLevel() * 5;
8540
8541 // skill bonus provided by casting spell (mostly item spells)
8542 // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.)
8544 skillValue += effect.CalcValue();
8545
8546 if (skillValue < reqSkillValue)
8548 }
8549
8550 return SPELL_CAST_OK;
8551 }
8552 case LOCK_KEY_SPELL:
8553 if (m_spellInfo->Id == uint32(lockInfo->Index[j]))
8554 return SPELL_CAST_OK;
8555 reqKey = true;
8556 break;
8557 }
8558 }
8559
8560 if (reqKey)
8562
8563 return SPELL_CAST_OK;
8564}
8565
8567{
8568 if (mod < SPELLVALUE_BASE_POINT_END)
8569 {
8570 m_spellValue->EffectBasePoints[mod] = value;
8572 return;
8573 }
8574
8575 switch (mod)
8576 {
8578 m_spellValue->RadiusMod = (float)value / 10000;
8579 break;
8582 break;
8585 break;
8587 m_spellValue->CriticalChance = value / 100.0f; // @todo ugly /100 remove when basepoints are double
8588 break;
8590 m_spellValue->DurationMul = float(value) / 100.0f;
8591 break;
8593 m_spellValue->Duration = value;
8594 break;
8597 break;
8600 break;
8601 default:
8602 break;
8603 }
8604}
8605
8607{
8608}
8609
8611{
8613}
8614
8616{
8617 sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this);
8618 for (SpellScript* script : m_loadedScripts)
8619 {
8620 TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `{}` for spell `{}` is loaded now", script->GetScriptName(), m_spellInfo->Id);
8621 script->Register();
8622 }
8623}
8624
8626{
8627 for (SpellScript* script : m_loadedScripts)
8628 {
8629 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_PRECAST);
8630 script->OnPrecast();
8631 script->_FinishScriptCall();
8632 }
8633}
8634
8636{
8637 for (SpellScript* script : m_loadedScripts)
8638 {
8639 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST);
8640 for (SpellScript::CastHandler const& beforeCast : script->BeforeCast)
8641 beforeCast.Call(script);
8642
8643 script->_FinishScriptCall();
8644 }
8645}
8646
8648{
8649 for (SpellScript* script : m_loadedScripts)
8650 {
8651 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST);
8652 for (SpellScript::CastHandler const& onCast : script->OnCast)
8653 onCast.Call(script);
8654
8655 script->_FinishScriptCall();
8656 }
8657}
8658
8660{
8661 for (SpellScript* script : m_loadedScripts)
8662 {
8663 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST);
8664 for (SpellScript::CastHandler const& afterCast : script->AfterCast)
8665 afterCast.Call(script);
8666
8667 script->_FinishScriptCall();
8668 }
8669}
8670
8672{
8674 for (SpellScript* script : m_loadedScripts)
8675 {
8676 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST);
8677 for (SpellScript::CheckCastHandler const& checkCast : script->OnCheckCast)
8678 {
8679 SpellCastResult tempResult = checkCast.Call(script);
8680 if (retVal == SPELL_CAST_OK)
8681 retVal = tempResult;
8682 }
8683
8684 script->_FinishScriptCall();
8685 }
8686 return retVal;
8687}
8688
8690{
8691 for (SpellScript* script : m_loadedScripts)
8692 {
8693 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_CAST_TIME);
8694 castTime = script->CalcCastTime(castTime);
8695 script->_FinishScriptCall();
8696 }
8697 return castTime;
8698}
8699
8701{
8702 // execute script effect handler hooks and check if effects was prevented
8703 bool preventDefault = false;
8704 for (SpellScript* script : m_loadedScripts)
8705 {
8706 script->_InitHit();
8707
8709 SpellScriptHookType hookType;
8710 switch (mode)
8711 {
8713 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectLaunch.begin(), script->OnEffectLaunch.end());
8715 break;
8717 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectLaunchTarget.begin(), script->OnEffectLaunchTarget.end());
8719 break;
8721 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectHit.begin(), script->OnEffectHit.end());
8723 break;
8725 effectHandlers = Trinity::Containers::MakeIteratorPair(script->OnEffectHitTarget.begin(), script->OnEffectHitTarget.end());
8727 break;
8728 default:
8729 ABORT();
8730 return false;
8731 }
8732 script->_PrepareScriptCall(hookType);
8733 for (SpellScript::EffectHandler const& effectHandler : effectHandlers)
8734 // effect execution can be prevented
8735 if (!script->_IsEffectPrevented(effIndex) && effectHandler.IsEffectAffected(m_spellInfo, effIndex))
8736 effectHandler.Call(script, effIndex);
8737
8738 if (!preventDefault)
8739 preventDefault = script->_IsDefaultEffectPrevented(effIndex);
8740
8741 script->_FinishScriptCall();
8742 }
8743 return preventDefault;
8744}
8745
8747{
8748 for (SpellScript* script : m_loadedScripts)
8749 {
8750 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
8751 for (SpellScript::EffectHandler const& onDispel : script->OnEffectSuccessfulDispel)
8752 onDispel.Call(script, effIndex);
8753
8754 script->_FinishScriptCall();
8755 }
8756}
8757
8759{
8760 for (SpellScript* script : m_loadedScripts)
8761 {
8762 script->_InitHit();
8763 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT);
8764 for (SpellScript::BeforeHitHandler const& beforeHit : script->BeforeHit)
8765 beforeHit.Call(script, missInfo);
8766
8767 script->_FinishScriptCall();
8768 }
8769}
8770
8772{
8773 for (SpellScript* script : m_loadedScripts)
8774 {
8775 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT);
8776 for (SpellScript::HitHandler const& onHit : script->OnHit)
8777 onHit.Call(script);
8778
8779 script->_FinishScriptCall();
8780 }
8781}
8782
8784{
8785 for (SpellScript* script : m_loadedScripts)
8786 {
8787 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT);
8788 for (SpellScript::HitHandler const& afterHit : script->AfterHit)
8789 afterHit.Call(script);
8790
8791 script->_FinishScriptCall();
8792 }
8793}
8794
8795void Spell::CallScriptCalcCritChanceHandlers(Unit const* victim, float& critChance)
8796{
8797 for (SpellScript* script : m_loadedScripts)
8798 {
8799 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_CRIT_CHANCE);
8800 for (SpellScript::OnCalcCritChanceHandler const& calcCritChance : script->OnCalcCritChance)
8801 calcCritChance.Call(script, victim, critChance);
8802
8803 script->_FinishScriptCall();
8804 }
8805}
8806
8807void Spell::CallScriptCalcDamageHandlers(Unit* victim, int32& damage, int32& flatMod, float& pctMod)
8808{
8809 for (SpellScript* script : m_loadedScripts)
8810 {
8811 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_DAMAGE);
8812 for (SpellScript::DamageAndHealingCalcHandler const& calcDamage : script->CalcDamage)
8813 calcDamage.Call(script, victim, damage, flatMod, pctMod);
8814
8815 script->_FinishScriptCall();
8816 }
8817}
8818
8819void Spell::CallScriptCalcHealingHandlers(Unit* victim, int32& healing, int32& flatMod, float& pctMod)
8820{
8821 for (SpellScript* script : m_loadedScripts)
8822 {
8823 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CALC_HEALING);
8824 for (SpellScript::DamageAndHealingCalcHandler const& calcHealing : script->CalcHealing)
8825 calcHealing.Call(script, victim, healing, flatMod, pctMod);
8826
8827 script->_FinishScriptCall();
8828 }
8829}
8830
8831void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
8832{
8833 for (SpellScript* script : m_loadedScripts)
8834 {
8835 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT);
8836 for (SpellScript::ObjectAreaTargetSelectHandler const& objectAreaTargetSelect : script->OnObjectAreaTargetSelect)
8837 if (objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == objectAreaTargetSelect.GetTarget())
8838 objectAreaTargetSelect.Call(script, targets);
8839
8840 script->_FinishScriptCall();
8841 }
8842}
8843
8845{
8846 for (SpellScript* script : m_loadedScripts)
8847 {
8848 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT);
8849 for (SpellScript::ObjectTargetSelectHandler const& objectTargetSelect : script->OnObjectTargetSelect)
8850 if (objectTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == objectTargetSelect.GetTarget())
8851 objectTargetSelect.Call(script, target);
8852
8853 script->_FinishScriptCall();
8854 }
8855}
8856
8858{
8859 for (SpellScript* script : m_loadedScripts)
8860 {
8861 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT);
8862 for (SpellScript::DestinationTargetSelectHandler const& destinationTargetSelect : script->OnDestinationTargetSelect)
8863 if (destinationTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == destinationTargetSelect.GetTarget())
8864 destinationTargetSelect.Call(script, target);
8865
8866 script->_FinishScriptCall();
8867 }
8868}
8869
8870void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)
8871{
8872 for (SpellScript* script : m_loadedScripts)
8873 {
8874 script->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION);
8875 for (SpellScript::OnCalculateResistAbsorbHandler const& calculateResistAbsorb : script->OnCalculateResistAbsorb)
8876 calculateResistAbsorb.Call(script, damageInfo, resistAmount, absorbAmount);
8877
8878 script->_FinishScriptCall();
8879 }
8880}
8881
8883{
8884 // Skip if there are not any script
8885 if (m_loadedScripts.empty())
8886 return true;
8887
8888 for (SpellScript* script : m_loadedScripts)
8889 {
8890 for (SpellScript::ObjectTargetSelectHandler const& objectTargetSelect : script->OnObjectTargetSelect)
8891 if ((objectTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && !objectTargetSelect.IsEffectAffected(m_spellInfo, effIndexToCheck)) ||
8892 (!objectTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && objectTargetSelect.IsEffectAffected(m_spellInfo, effIndexToCheck)))
8893 return false;
8894
8895 for (SpellScript::ObjectAreaTargetSelectHandler const& objectAreaTargetSelect : script->OnObjectAreaTargetSelect)
8896 if ((objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && !objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndexToCheck)) ||
8897 (!objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndex) && objectAreaTargetSelect.IsEffectAffected(m_spellInfo, effIndexToCheck)))
8898 return false;
8899 }
8900 return true;
8901}
8902
8903bool Spell::CanExecuteTriggersOnHit(Unit* unit, SpellInfo const* triggeredByAura /*= nullptr*/) const
8904{
8905 bool onlyOnTarget = (triggeredByAura && (triggeredByAura->HasAttribute(SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET)));
8906 if (!onlyOnTarget)
8907 return true;
8908
8909 // If triggeredByAura has SPELL_ATTR4_CLASS_TRIGGER_ONLY_ON_TARGET then it can only proc on either noncaster units...
8910 if (unit != m_caster)
8911 return true;
8912
8913 // ... or caster if it is the only target
8914 if (m_UniqueTargetInfo.size() == 1)
8915 return true;
8916
8917 return false;
8918}
8919
8921{
8922 Unit* unitCaster = m_caster->ToUnit();
8923 if (!unitCaster)
8924 return;
8925
8926 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
8927 // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
8928 // and to correctly calculate proc chance when combopoints are present
8929 Unit::AuraEffectList const& targetTriggers = unitCaster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
8930 for (AuraEffect const* aurEff : targetTriggers)
8931 {
8932 if (!aurEff->IsAffectingSpell(m_spellInfo))
8933 continue;
8934
8935 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo().TriggerSpell, GetCastDifficulty()))
8936 {
8937 // calculate the chance using spell base amount, because aura amount is not updated on combo-points change
8938 // this possibly needs fixing
8939 int32 auraBaseAmount = aurEff->GetBaseAmount();
8940 // proc chance is stored in effect amount
8941 int32 chance = unitCaster->CalculateSpellDamage(nullptr, aurEff->GetSpellEffectInfo(), &auraBaseAmount);
8942 chance *= aurEff->GetBase()->GetStackAmount();
8943
8944 // build trigger and add to the list
8945 m_hitTriggerSpells.emplace_back(spellInfo, aurEff->GetSpellInfo(), chance);
8946 }
8947 }
8948}
8949
8950// Global cooldowns management
8952{
8953 // Only players or controlled units have global cooldown
8954 if (caster->GetTypeId() != TYPEID_PLAYER && (caster->GetTypeId() != TYPEID_UNIT || !const_cast<WorldObject*>(caster)->ToCreature()->GetCharmInfo()))
8955 return false;
8956
8957 return true;
8958}
8959
8961{
8963 return false;
8964
8966}
8967
8969{
8971 return;
8972
8974 if (gcd == 0ms || !m_spellInfo->StartRecoveryCategory)
8975 return;
8976
8979 return;
8980
8981 constexpr Milliseconds MinGCD = 750ms;
8982 constexpr Milliseconds MaxGCD = 1500ms;
8983
8984 // Global cooldown can't leave range 1..1.5 secs
8985 // There are some spells (mostly not cast directly by player) that have < 1 sec and > 1.5 sec global cooldowns
8986 // but as tests show are not affected by any spell mods.
8987 if (gcd >= MinGCD && gcd <= MaxGCD)
8988 {
8989 // gcd modifier auras are applied only to own spells and only players have such mods
8990 if (Player* modOwner = m_caster->GetSpellModOwner())
8991 {
8992 int32 intGcd = gcd.count();
8993 modOwner->ApplySpellMod(m_spellInfo, SpellModOp::StartCooldown, intGcd, this);
8994 gcd = Milliseconds(intGcd);
8995 }
8996
8997 bool isMeleeOrRangedSpell = m_spellInfo->DmgClass == SPELL_DAMAGE_CLASS_MELEE ||
9001
9002 // Apply haste rating
9003 if (gcd > MinGCD && ((m_spellInfo->StartRecoveryCategory == 133 && !isMeleeOrRangedSpell)))
9004 {
9005 gcd = Milliseconds(int64(gcd.count() * m_caster->ToUnit()->m_unitData->ModSpellHaste));
9006 RoundToInterval(gcd, MinGCD, MaxGCD);
9007 }
9008
9010 {
9011 gcd = Milliseconds(int64(gcd.count() * m_caster->ToUnit()->m_unitData->ModHasteRegen));
9012 RoundToInterval(gcd, MinGCD, MaxGCD);
9013 }
9014 }
9015
9017}
9018
9020{
9022 return;
9023
9025 return;
9026
9027 // Cancel global cooldown when interrupting current cast
9029 return;
9030
9032}
9033
9034std::string Spell::GetDebugInfo() const
9035{
9036 std::stringstream sstr;
9037 sstr << std::boolalpha
9038 << "Id: " << GetSpellInfo()->Id << " Name: '" << (*GetSpellInfo()->SpellName)[sWorld->GetDefaultDbcLocale()] << "' OriginalCaster: " << m_originalCasterGUID.ToString()
9039 << " State: " << getState();
9040 return sstr.str();
9041}
9042
9044{
9045 return _spellEvent->GetSpellWeakPtr();
9046}
9047
9048bool Spell::IsWithinLOS(WorldObject const* source, WorldObject const* target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const
9049{
9051 return true;
9052
9054 return true;
9055
9056 if (target->IsCreature() && target->ToCreature()->CanIgnoreLineOfSightWhenCastingOnMe())
9057 return true;
9058
9059 WorldObject const* src = targetAsSourceLocation ? target : source;
9060 WorldObject const* dst = targetAsSourceLocation ? source : target;
9061 return src->IsWithinLOSInMap(dst, LINEOFSIGHT_ALL_CHECKS, ignoreFlags);
9062}
9063
9064bool Spell::IsWithinLOS(WorldObject const* source, Position const& target, VMAP::ModelIgnoreFlags ignoreFlags) const
9065{
9067 return true;
9068
9070 return true;
9071
9072 return source->IsWithinLOS(target.GetPositionX(), target.GetPositionY(), target.GetPositionZ(), LINEOFSIGHT_ALL_CHECKS, ignoreFlags);
9073}
9074
9075namespace Trinity
9076{
9077
9079 SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
9080 _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList), _objectType(objectType)
9081{
9082 if (condList)
9083 _condSrcInfo = std::make_unique<ConditionSourceInfo>(nullptr, caster);
9084}
9085
9087{
9088}
9089
9091{
9092 if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
9093 return false;
9094
9095 Unit* unitTarget = target->ToUnit();
9096 if (Corpse* corpseTarget = target->ToCorpse())
9097 {
9098 // use owner for party/assistance checks
9099 if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
9100 unitTarget = owner;
9101 else
9102 return false;
9103 }
9104
9105 Unit* refUnit = _referer->ToUnit();
9106 if (unitTarget)
9107 {
9108 // do only faction checks here
9109 switch (_targetSelectionType)
9110 {
9111 case TARGET_CHECK_ENEMY:
9112 if (unitTarget->IsTotem())
9113 return false;
9114 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9115 if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo))
9116 return false;
9117 break;
9118 case TARGET_CHECK_ALLY:
9119 if (unitTarget->IsTotem())
9120 return false;
9121 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9122 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9123 return false;
9124 break;
9125 case TARGET_CHECK_PARTY:
9126 if (!refUnit)
9127 return false;
9128 if (unitTarget->IsTotem())
9129 return false;
9130 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9131 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9132 return false;
9133 if (!refUnit->IsInPartyWith(unitTarget))
9134 return false;
9135 break;
9137 if (!refUnit)
9138 return false;
9139 if (refUnit->GetClass() != unitTarget->GetClass())
9140 return false;
9141 [[fallthrough]];
9142 case TARGET_CHECK_RAID:
9143 if (!refUnit)
9144 return false;
9145 if (unitTarget->IsTotem())
9146 return false;
9147 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
9148 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
9149 return false;
9150 if (!refUnit->IsInRaidWith(unitTarget))
9151 return false;
9152 break;
9154 if (!unitTarget->IsSummon())
9155 return false;
9156 if (unitTarget->ToTempSummon()->GetSummonerGUID() != _caster->GetGUID())
9157 return false;
9158 break;
9160 if (!_referer->IsUnit() || _referer->ToUnit()->GetThreatManager().GetThreat(unitTarget, true) <= 0.0f)
9161 return false;
9162 break;
9163 case TARGET_CHECK_TAP:
9164 if (_referer->GetTypeId() != TYPEID_UNIT || unitTarget->GetTypeId() != TYPEID_PLAYER)
9165 return false;
9166 if (!_referer->ToCreature()->isTappedBy(unitTarget->ToPlayer()))
9167 return false;
9168 break;
9169 default:
9170 break;
9171 }
9172
9173 switch (_objectType)
9174 {
9178 if (unitTarget->IsAlive())
9179 return false;
9180 break;
9181 default:
9182 break;
9183 }
9184 }
9185
9186 if (!_condSrcInfo)
9187 return true;
9188 _condSrcInfo->mConditionTargets[0] = target;
9189 return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
9190}
9191
9193 SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9194 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(caster) { }
9195
9197{
9198 float dist = target->GetDistance(*_position);
9199 if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target))
9200 {
9201 _range = dist;
9202 return true;
9203 }
9204 return false;
9205}
9206
9208 WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType,
9209 WorldObjectSpellAreaTargetSearchReason searchReason /*= Area*/)
9210 : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList, objectType), _range(range), _position(position), _searchReason(searchReason) { }
9211
9213{
9214 if (GameObject* gameObjectTarget = target->ToGameObject())
9215 {
9216 // isInRange including the dimension of the GO
9217 bool isInRange = gameObjectTarget->IsInRange(_position->GetPositionX(), _position->GetPositionY(), _position->GetPositionZ(), _range);
9218 if (!isInRange)
9219 return false;
9220 }
9221 else
9222 {
9223 bool isInsideCylinder = target->IsWithinDist2d(_position, _range) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range;
9224 if (!isInsideCylinder)
9225 return false;
9226
9227 if (Unit* unitTarget = target->ToUnit())
9228 {
9229 switch (_searchReason)
9230 {
9232 if (!_spellInfo->HasAttribute(SPELL_ATTR8_CAN_HIT_AOE_UNTARGETABLE) && unitTarget->GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity::AoETarget))
9233 return false;
9234 break;
9236 if (unitTarget->GetSpellOtherImmunityMask().HasFlag(SpellOtherImmunity::ChainTarget))
9237 return false;
9238 break;
9239 default:
9240 break;
9241 }
9242 }
9243 }
9244
9246}
9247
9248WorldObjectSpellConeTargetCheck::WorldObjectSpellConeTargetCheck(Position const& coneSrc, float coneAngle, float lineWidth, float range, WorldObject* caster,
9249 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9250 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _coneSrc(coneSrc), _coneAngle(coneAngle), _lineWidth(lineWidth) { }
9251
9253{
9255 {
9256 if (_coneSrc.HasInArc(-std::abs(_coneAngle), target))
9257 return false;
9258 }
9260 {
9261 if (!_coneSrc.HasInLine(target, target->GetCombatReach(), _lineWidth))
9262 return false;
9263 }
9264 else
9265 {
9266 if (!_caster->IsUnit() || !_caster->ToUnit()->IsWithinBoundaryRadius(target->ToUnit()))
9267 // ConeAngle > 0 -> select targets in front
9268 // ConeAngle < 0 -> select targets in back
9269 if (_coneSrc.HasInArc(_coneAngle, target) != G3D::fuzzyGe(_coneAngle, 0.f))
9270 return false;
9271 }
9273}
9274
9275WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9276 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList, objectType), _range(range), _position(position) { }
9277
9279{
9280 // return all targets on missile trajectory (0 - size of a missile)
9281 if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
9282 return false;
9283
9284 if (target->GetExactDist2d(_position) > _range)
9285 return false;
9286
9288}
9289
9290WorldObjectSpellLineTargetCheck::WorldObjectSpellLineTargetCheck(Position const* srcPosition, Position const* dstPosition, float lineWidth, float range, WorldObject* caster,
9291 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType)
9292 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList, objectType), _position(*srcPosition), _lineWidth(lineWidth)
9293{
9294 if (dstPosition && *srcPosition != *dstPosition)
9295 _position.SetOrientation(srcPosition->GetAbsoluteAngle(dstPosition));
9296}
9297
9299{
9300 if (!_position.HasInLine(target, target->GetCombatReach(), _lineWidth))
9301 return false;
9302
9304}
9305
9306void SelectRandomInjuredTargets(std::list<WorldObject*>& targets, size_t maxTargets, bool prioritizePlayers, Unit const* prioritizeGroupMembersOf /*= nullptr*/)
9307{
9308 if (targets.size() <= maxTargets)
9309 return;
9310
9311 // Target priority states (bit indices)
9312 // higher value means lower selection priority
9313 // current list:
9314 // * injured player group members
9315 // * injured other players
9316 // * injured pets of group members
9317 // * injured other pets
9318 // * full health player group members
9319 // * full health other players
9320 // * full health pets of group members
9321 // * full health other pets
9322 enum
9323 {
9324 NOT_GROUPED,
9325 NOT_PLAYER,
9326 NOT_INJURED,
9327 END
9328 };
9329
9330 std::array<std::ptrdiff_t, 1 << END> countsByPriority = {};
9331 std::vector<std::pair<WorldObject*, int32>> tempTargets;
9332 tempTargets.resize(targets.size());
9333
9334 // categorize each target
9335 std::transform(targets.begin(), targets.end(), tempTargets.begin(), [&](WorldObject* target)
9336 {
9337 int32 negativePoints = 0;
9338 if (prioritizeGroupMembersOf && (!target->IsUnit() || target->ToUnit()->IsInRaidWith(prioritizeGroupMembersOf)))
9339 negativePoints |= 1 << NOT_GROUPED;
9340
9341 if (prioritizePlayers && !target->IsPlayer() && (!target->IsCreature() || !target->ToCreature()->IsTreatedAsRaidUnit()))
9342 negativePoints |= 1 << NOT_PLAYER;
9343
9344 if (!target->IsUnit() || target->ToUnit()->IsFullHealth())
9345 negativePoints |= 1 << NOT_INJURED;
9346
9347 ++countsByPriority[negativePoints];
9348 return std::make_pair(target, negativePoints);
9349 });
9350
9351 std::sort(tempTargets.begin(), tempTargets.end(), [](std::pair<WorldObject*, int32> const& left, std::pair<WorldObject*, int32> const& right)
9352 {
9353 return left.second < right.second;
9354 });
9355
9356 std::size_t foundTargets = 0;
9357 for (std::ptrdiff_t countForPriority : countsByPriority)
9358 {
9359 if (foundTargets + countForPriority >= maxTargets)
9360 {
9361 // shuffle only the lower priority extras
9362 // example: our initial target list had 5 injured and 5 full health units and we want to select 7 targets
9363 // we always want to select 5 injured and 2 random full health ones
9364 Containers::RandomShuffle(tempTargets.begin() + foundTargets, tempTargets.begin() + foundTargets + countForPriority);
9365 break;
9366 }
9367
9368 foundTargets += countForPriority;
9369 }
9370
9371 targets.resize(maxTargets);
9372 std::transform(tempTargets.begin(), tempTargets.begin() + maxTargets, targets.begin(), std::mem_fn(&std::pair<WorldObject*, int32>::first));
9373}
9374} //namespace Trinity
9375
9377{
9378 if (target)
9379 {
9380 if (Unit* unitTarget = target->ToUnit())
9381 {
9382 Targets.emplace();
9383 Targets->SetUnitTarget(unitTarget);
9384 }
9385 else if (GameObject* goTarget = target->ToGameObject())
9386 {
9387 Targets.emplace();
9388 Targets->SetGOTarget(goTarget);
9389 }
9390 // error when targeting anything other than units and gameobjects
9391 }
9392 else
9393 Targets.emplace(); // nullptr is allowed
9394}
9395
9402
9404{
9405 TriggeringSpell = triggeringSpell;
9406 if (triggeringSpell)
9407 {
9408 OriginalCastItemLevel = triggeringSpell->m_castItemLevel;
9409 OriginalCastId = triggeringSpell->m_castId;
9410 }
9411 return *this;
9412}
9413
9415{
9416 TriggeringAura = triggeringAura;
9417 if (triggeringAura)
9418 OriginalCastId = triggeringAura->GetBase()->GetCastId();
9419
9420 return *this;
9421}
9422
9423SpellCastVisual::operator UF::SpellCastVisual() const
9424{
9425 UF::SpellCastVisual visual;
9426 visual.SpellXSpellVisualID = SpellXSpellVisualID;
9427 visual.ScriptVisualID = ScriptVisualID;
9428 return visual;
9429}
9430
9431SpellCastVisual::operator WorldPackets::Spells::SpellCastVisual() const
9432{
9433 return { int32(SpellXSpellVisualID), int32(ScriptVisualID) };
9434}
#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:290
#define sConditionMgr
Definition: ConditionMgr.h:365
@ CONDITION_SOURCE_TYPE_SPELL
Definition: ConditionMgr.h:171
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:538
#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:200
@ ITEM_ENCHANTMENT_TYPE_USE_SPELL
Definition: DBCEnums.h:1008
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
Definition: DBCEnums.h:1009
Difficulty
Definition: DBCEnums.h:873
@ DIFFICULTY_NONE
Definition: DBCEnums.h:874
#define MAX_EFFECT_MASK
Definition: DBCEnums.h:1954
#define MAX_ITEM_PROTO_SOCKETS
Definition: DBCEnums.h:989
#define MAX_SPELL_EFFECTS
Definition: DBCEnums.h:1953
@ LandTargetedSpellOnTarget
#define UI64FMTD
Definition: Define.h:126
#define TC_GAME_API
Definition: Define.h:123
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint32_t uint32
Definition: Define.h:142
@ SPELL_DISABLE_LOS
Definition: DisableMgr.h:48
@ DISABLE_TYPE_SPELL
Definition: DisableMgr.h:27
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition: Duration.h:29
#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:85
@ GRID_MAP_TYPE_MASK_CREATURE
Definition: GridDefines.h:82
@ GRID_MAP_TYPE_MASK_ALL
Definition: GridDefines.h:89
@ GRID_MAP_TYPE_MASK_GAMEOBJECT
Definition: GridDefines.h:84
@ GRID_MAP_TYPE_MASK_CORPSE
Definition: GridDefines.h:81
#define VMAP_INVALID_HEIGHT_VALUE
Definition: IVMapManager.h:44
#define sInstanceLockMgr
@ PRISMATIC_ENCHANTMENT_SLOT
Definition: ItemDefines.h:185
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:422
@ ITEM_CLASS_CONSUMABLE
Definition: ItemTemplate.h:420
@ ITEM_SUBCLASS_WEAPON_CROSSBOW
Definition: ItemTemplate.h:498
@ ITEM_SUBCLASS_WEAPON_GUN
Definition: ItemTemplate.h:483
@ ITEM_SUBCLASS_WEAPON_BOW
Definition: ItemTemplate.h:482
@ ITEM_SUBCLASS_WEAPON_WAND
Definition: ItemTemplate.h:499
@ ITEM_SUBCLASS_WEAPON_THROWN
Definition: ItemTemplate.h:496
@ ITEM_SPELLTRIGGER_ON_USE
Definition: ItemTemplate.h:104
@ ITEM_FLAG_IS_MILLABLE
Definition: ItemTemplate.h:205
@ ITEM_FLAG_NO_REAGENT_COST
Definition: ItemTemplate.h:204
@ ITEM_FLAG_IS_PROSPECTABLE
Definition: ItemTemplate.h:194
@ INVTYPE_THROWN
Definition: ItemTemplate.h:404
@ INVTYPE_AMMO
Definition: ItemTemplate.h:403
@ ITEM_CHANGED
Definition: Item.h:55
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
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:106
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:87
#define EXTRA_CELL_SEARCH_RADIUS
Definition: ObjectDefines.h:47
#define DEFAULT_PLAYER_BOUNDING_RADIUS
Definition: ObjectDefines.h:39
@ TYPEID_GAMEOBJECT
Definition: ObjectGuid.h:43
@ TYPEID_UNIT
Definition: ObjectGuid.h:40
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
#define sObjectMgr
Definition: ObjectMgr.h:1946
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:97
@ HUNTER_PET
Definition: PetDefines.h:32
constexpr uint32 PET_SUMMONING_DISORIENTATION
Definition: PetDefines.h:131
PetSaveMode
Definition: PetDefines.h:41
std::vector< ItemPosCount > ItemPosCountVec
Definition: Player.h:750
@ RUNE_MISS_COOLDOWN
Definition: Player.h:390
@ CHEAT_COOLDOWN
Definition: Player.h:951
@ CHEAT_POWER
Definition: Player.h:952
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:1418
SpellEffIndex
Definition: SharedDefines.h:29
@ EFFECT_1
Definition: SharedDefines.h:31
@ SPELL_ATTR10_USES_RANGED_SLOT_COSMETIC_ONLY
@ SPELL_ATTR9_USABLE_IN_RATED_BATTLEGROUNDS
@ SPELL_ATTR9_SPECIAL_DELAY_CALCULATION
@ SPELL_ATTR9_NOT_USABLE_IN_ARENA
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_CASTER_GROUND
@ TARGET_UNIT_SRC_AREA_FURTHEST_ENEMY
@ TARGET_UNIT_VEHICLE
@ TARGET_UNIT_CASTER_AND_SUMMONS
@ TARGET_DEST_NEARBY_ENTRY_OR_DB
@ 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_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
@ TARGET_DEST_CHANNEL_CASTER
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_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
@ MECHANIC_BANISH
@ MECHANIC_IMMUNE_SHIELD
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_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
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_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
@ TARGET_FLAG_TRADE_ITEM
Definition: SpellDefines.h:292
@ TARGET_FLAG_GAMEOBJECT
Definition: SpellDefines.h:291
@ TARGET_FLAG_STRING
Definition: SpellDefines.h:293
@ TARGET_FLAG_UNIT_RAID
Definition: SpellDefines.h:282
@ TARGET_FLAG_UNIT_ENEMY
Definition: SpellDefines.h:287
@ TARGET_FLAG_CORPSE_ALLY
Definition: SpellDefines.h:295
@ TARGET_FLAG_ITEM
Definition: SpellDefines.h:284
@ TARGET_FLAG_UNIT_MINIPET
Definition: SpellDefines.h:296
@ TARGET_FLAG_GAMEOBJECT_ITEM
Definition: SpellDefines.h:294
@ TARGET_FLAG_DEST_LOCATION
Definition: SpellDefines.h:286
@ TARGET_FLAG_UNIT_ALLY
Definition: SpellDefines.h:288
@ TARGET_FLAG_SOURCE_LOCATION
Definition: SpellDefines.h:285
@ TARGET_FLAG_ITEM_MASK
Definition: SpellDefines.h:311
@ TARGET_FLAG_UNIT
Definition: SpellDefines.h:281
@ TARGET_FLAG_UNIT_MASK
Definition: SpellDefines.h:307
@ TARGET_FLAG_CORPSE_ENEMY
Definition: SpellDefines.h:289
@ TARGET_FLAG_CORPSE_MASK
Definition: SpellDefines.h:310
@ TARGET_FLAG_GAMEOBJECT_MASK
Definition: SpellDefines.h:309
@ TARGET_FLAG_UNIT_PARTY
Definition: SpellDefines.h:283
TriggerCastFlags
Definition: SpellDefines.h:245
@ TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT
Will ignore equipped item requirements.
Definition: SpellDefines.h:269
@ TRIGGERED_FULL_MASK
Used when doing CastSpell with triggered == true.
Definition: SpellDefines.h:266
@ TRIGGERED_IGNORE_POWER_AND_REAGENT_COST
Will ignore power and reagent cost.
Definition: SpellDefines.h:249
@ TRIGGERED_DONT_RESET_PERIODIC_TIMER
Will allow periodic aura timers to keep ticking (instead of resetting)
Definition: SpellDefines.h:264
@ TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
Will ignore Spell and Category cooldowns.
Definition: SpellDefines.h:248
@ TRIGGERED_CAST_DIRECTLY
In Spell::prepare, will be cast directly without setting containers for executed spell.
Definition: SpellDefines.h:254
@ TRIGGERED_IGNORE_TARGET_CHECK
Will ignore most target checks (mostly DBC target checks)
Definition: SpellDefines.h:270
@ TRIGGERED_IGNORE_CASTER_AURASTATE
Will ignore caster aura states including combat requirements and death state.
Definition: SpellDefines.h:271
@ TRIGGERED_IGNORE_CAST_IN_PROGRESS
Will not check if a current cast is in progress.
Definition: SpellDefines.h:252
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Will ignore mounted/on vehicle restrictions.
Definition: SpellDefines.h:260
@ TRIGGERED_IGNORE_SHAPESHIFT
Will ignore shapeshift checks.
Definition: SpellDefines.h:257
@ TRIGGERED_IGNORE_CAST_ITEM
Will not take away cast item or update related achievement criteria.
Definition: SpellDefines.h:250
@ TRIGGERED_IGNORE_GCD
Will ignore GCD.
Definition: SpellDefines.h:247
@ TRIGGERED_DISALLOW_PROC_EVENTS
Disallows proc events from triggered spell (default)
Definition: SpellDefines.h:259
@ TRIGGERED_IGNORE_CASTER_AURAS
Will ignore caster aura restrictions or requirements.
Definition: SpellDefines.h:263
@ TRIGGERED_DONT_REPORT_CAST_ERROR
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
Definition: SpellDefines.h:265
@ TRIGGERED_IGNORE_SET_FACING
Will not adjust facing to target (if any)
Definition: SpellDefines.h:256
SpellValueMod
Definition: SpellDefines.h:195
@ SPELLVALUE_AURA_STACK
Definition: SpellDefines.h:231
@ SPELLVALUE_DURATION_PCT
Definition: SpellDefines.h:233
@ SPELLVALUE_BASE_POINT_END
Definition: SpellDefines.h:228
@ SPELLVALUE_PARENT_SPELL_TARGET_COUNT
Definition: SpellDefines.h:235
@ SPELLVALUE_RADIUS_MOD
Definition: SpellDefines.h:229
@ SPELLVALUE_PARENT_SPELL_TARGET_INDEX
Definition: SpellDefines.h:236
@ SPELLVALUE_MAX_TARGETS
Definition: SpellDefines.h:230
@ SPELLVALUE_DURATION
Definition: SpellDefines.h:234
@ SPELLVALUE_CRIT_CHANCE
Definition: SpellDefines.h:232
@ SPELL_FACING_FLAG_INFRONT
Definition: SpellDefines.h:241
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
Definition: SpellInfo.cpp:41
SpellTargetCheckTypes
Definition: SpellInfo.h:81
@ TARGET_CHECK_TAP
Definition: SpellInfo.h:92
@ TARGET_CHECK_PARTY
Definition: SpellInfo.h:86
@ TARGET_CHECK_ENEMY
Definition: SpellInfo.h:84
@ TARGET_CHECK_DEFAULT
Definition: SpellInfo.h:82
@ TARGET_CHECK_THREAT
Definition: SpellInfo.h:91
@ TARGET_CHECK_SUMMONED
Definition: SpellInfo.h:90
@ TARGET_CHECK_ENTRY
Definition: SpellInfo.h:83
@ TARGET_CHECK_RAID_CLASS
Definition: SpellInfo.h:88
@ TARGET_CHECK_ALLY
Definition: SpellInfo.h:85
@ TARGET_CHECK_RAID
Definition: SpellInfo.h:87
@ EFFECT_IMPLICIT_TARGET_CASTER
Definition: SpellInfo.h:114
@ EFFECT_IMPLICIT_TARGET_EXPLICIT
Definition: SpellInfo.h:113
@ TARGET_SELECT_CATEGORY_CONE
Definition: SpellInfo.h:48
@ TARGET_SELECT_CATEGORY_AREA
Definition: SpellInfo.h:49
@ TARGET_SELECT_CATEGORY_DEFAULT
Definition: SpellInfo.h:45
@ TARGET_SELECT_CATEGORY_NEARBY
Definition: SpellInfo.h:47
@ TARGET_SELECT_CATEGORY_NYI
Definition: SpellInfo.h:44
@ TARGET_SELECT_CATEGORY_LINE
Definition: SpellInfo.h:51
@ TARGET_SELECT_CATEGORY_TRAJ
Definition: SpellInfo.h:50
@ TARGET_SELECT_CATEGORY_CHANNEL
Definition: SpellInfo.h:46
SpellTargetObjectTypes
Definition: SpellInfo.h:65
@ TARGET_OBJECT_TYPE_UNIT
Definition: SpellInfo.h:69
@ TARGET_OBJECT_TYPE_CORPSE
Definition: SpellInfo.h:74
@ TARGET_OBJECT_TYPE_UNIT_AND_DEST
Definition: SpellInfo.h:70
@ TARGET_OBJECT_TYPE_NONE
Definition: SpellInfo.h:66
@ TARGET_OBJECT_TYPE_DEST
Definition: SpellInfo.h:68
@ TARGET_OBJECT_TYPE_GOBJ
Definition: SpellInfo.h:71
@ TARGET_OBJECT_TYPE_CORPSE_ALLY
Definition: SpellInfo.h:77
@ TARGET_OBJECT_TYPE_CORPSE_ENEMY
Definition: SpellInfo.h:76
@ TARGET_OBJECT_TYPE_GOBJ_ITEM
Definition: SpellInfo.h:72
@ TARGET_OBJECT_TYPE_SRC
Definition: SpellInfo.h:67
@ SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER
Definition: SpellInfo.h:164
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition: SpellInfo.h:165
@ SPELL_ATTR0_CU_CONE_BACK
Definition: SpellInfo.h:149
@ SPELL_ATTR0_CU_NEEDS_AMMO_DATA
Definition: SpellInfo.h:167
@ SPELL_ATTR0_CU_CONE_LINE
Definition: SpellInfo.h:150
@ SPELL_ATTR0_CU_NO_INITIAL_THREAT
Definition: SpellInfo.h:152
@ TARGET_REFERENCE_TYPE_SRC
Definition: SpellInfo.h:60
@ TARGET_REFERENCE_TYPE_TARGET
Definition: SpellInfo.h:58
@ TARGET_REFERENCE_TYPE_LAST
Definition: SpellInfo.h:59
@ TARGET_REFERENCE_TYPE_CASTER
Definition: SpellInfo.h:57
@ TARGET_REFERENCE_TYPE_DEST
Definition: SpellInfo.h:61
ProcFlagsSpellPhase
Definition: SpellMgr.h:261
@ PROC_SPELL_PHASE_FINISH
Definition: SpellMgr.h:265
@ PROC_SPELL_PHASE_NONE
Definition: SpellMgr.h:262
@ PROC_SPELL_PHASE_CAST
Definition: SpellMgr.h:263
@ PROC_SPELL_PHASE_HIT
Definition: SpellMgr.h:264
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER
Definition: SpellMgr.h:385
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE
Definition: SpellMgr.h:384
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition: SpellMgr.h:383
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition: SpellMgr.h:386
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition: SpellMgr.h:387
#define sSpellMgr
Definition: SpellMgr.h:849
ProcFlagsSpellType
Definition: SpellMgr.h:250
@ PROC_SPELL_TYPE_NONE
Definition: SpellMgr.h:251
@ PROC_SPELL_TYPE_HEAL
Definition: SpellMgr.h:253
@ PROC_SPELL_TYPE_MASK_ALL
Definition: SpellMgr.h:255
@ PROC_SPELL_TYPE_DAMAGE
Definition: SpellMgr.h:252
@ PROC_SPELL_TYPE_NO_DMG_HEAL
Definition: SpellMgr.h:254
@ SPELL_LINK_HIT
Definition: SpellMgr.h:127
@ SPELL_LINK_CAST
Definition: SpellMgr.h:126
ProcFlags
Definition: SpellMgr.h:134
@ PROC_FLAG_DEAL_MELEE_ABILITY
Definition: SpellMgr.h:143
@ PROC_FLAG_TAKE_HARMFUL_PERIODIC
Definition: SpellMgr.h:165
@ PROC_FLAG_MAIN_HAND_WEAPON_SWING
Definition: SpellMgr.h:171
@ PROC_FLAG_TAKE_ANY_DAMAGE
Definition: SpellMgr.h:167
@ PROC_FLAG_CAST_ENDED
Definition: SpellMgr.h:184
@ PROC_FLAG_TAKE_HELPFUL_ABILITY
Definition: SpellMgr.h:153
@ PROC_FLAG_DEAL_RANGED_ABILITY
Definition: SpellMgr.h:149
@ PROC_FLAG_TAKE_HELPFUL_SPELL
Definition: SpellMgr.h:159
@ PROC_FLAG_DEAL_HELPFUL_ABILITY
Definition: SpellMgr.h:152
@ PROC_FLAG_DEAL_RANGED_ATTACK
Definition: SpellMgr.h:146
@ PROC_FLAG_TAKE_HARMFUL_SPELL
Definition: SpellMgr.h:162
@ PROC_FLAG_TAKE_MELEE_ABILITY
Definition: SpellMgr.h:144
@ PROC_FLAG_DEAL_HARMFUL_ABILITY
Definition: SpellMgr.h:155
@ PROC_FLAG_DEAL_HARMFUL_PERIODIC
Definition: SpellMgr.h:164
@ PROC_FLAG_OFF_HAND_WEAPON_SWING
Definition: SpellMgr.h:172
@ PROC_FLAG_DEAL_HELPFUL_SPELL
Definition: SpellMgr.h:158
@ PROC_FLAG_DEAL_HELPFUL_PERIODIC
Definition: SpellMgr.h:169
@ PROC_FLAG_DEAL_HARMFUL_SPELL
Definition: SpellMgr.h:161
@ PROC_FLAG_TAKE_RANGED_ABILITY
Definition: SpellMgr.h:150
@ PROC_FLAG_TAKE_HELPFUL_PERIODIC
Definition: SpellMgr.h:188
@ PROC_FLAG_TAKE_RANGED_ATTACK
Definition: SpellMgr.h:147
@ PROC_FLAG_NONE
Definition: SpellMgr.h:135
@ PROC_FLAG_TAKE_HARMFUL_ABILITY
Definition: SpellMgr.h:156
@ PROC_FLAG_2_CAST_SUCCESSFUL
Definition: SpellMgr.h:235
ProcFlagsHit
Definition: SpellMgr.h:272
@ PROC_HIT_NONE
Definition: SpellMgr.h:273
@ PROC_HIT_IMMUNE
Definition: SpellMgr.h:282
@ PROC_HIT_CRITICAL
Definition: SpellMgr.h:275
@ PROC_HIT_NORMAL
Definition: SpellMgr.h:274
@ PROC_HIT_REFLECT
Definition: SpellMgr.h:285
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_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:8951
void FillSpellCastFailedArgs(T &packet, ObjectGuid castId, SpellInfo const *spellInfo, SpellCastResult result, SpellCustomErrors customError, int32 *param1, int32 *param2, Player *caster)
Definition: Spell.cpp:4388
float tangent(float x)
Definition: Spell.cpp:1854
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:4978
NonDefaultConstructible< SpellEffectHandlerFn > SpellEffectHandlers[TOTAL_SPELL_EFFECTS]
@ SPELL_CAST_SOURCE_NORMAL
Definition: Spell.h:146
@ SPELL_RANGE_MELEE
Definition: Spell.h:165
@ SPELL_RANGE_RANGED
Definition: Spell.h:166
#define MAX_SPELL_RANGE_TOLERANCE
Definition: Spell.h:77
@ CAST_FLAG_EX_IGNORE_COOLDOWN
Definition: Spell.h:130
SpellEffectHandleMode
Definition: Spell.h:243
@ SPELL_EFFECT_HANDLE_LAUNCH_TARGET
Definition: Spell.h:245
@ SPELL_EFFECT_HANDLE_LAUNCH
Definition: Spell.h:244
@ SPELL_EFFECT_HANDLE_HIT
Definition: Spell.h:246
@ SPELL_EFFECT_HANDLE_HIT_TARGET
Definition: Spell.h:247
#define AOE_DAMAGE_TARGET_CAP
Definition: Spell.h:79
@ SPELL_STATE_DELAYED
Definition: Spell.h:239
@ SPELL_STATE_NULL
Definition: Spell.h:234
@ SPELL_STATE_FINISHED
Definition: Spell.h:237
@ SPELL_STATE_PREPARING
Definition: Spell.h:235
@ SPELL_STATE_CASTING
Definition: Spell.h:236
@ SPELL_STATE_IDLE
Definition: Spell.h:238
static const uint32 SPELL_INTERRUPT_NONPLAYER
Definition: Spell.h:252
@ CAST_FLAG_ADJUST_MISSILE
Definition: Spell.h:101
@ CAST_FLAG_HEAL_PREDICTION
Definition: Spell.h:114
@ CAST_FLAG_UNKNOWN_9
Definition: Spell.h:92
@ CAST_FLAG_NO_GCD
Definition: Spell.h:102
@ CAST_FLAG_PROJECTILE
Definition: Spell.h:89
@ CAST_FLAG_POWER_LEFT_SELF
Definition: Spell.h:95
@ CAST_FLAG_HAS_TRAJECTORY
Definition: Spell.h:85
@ CAST_FLAG_RUNE_LIST
Definition: Spell.h:105
@ CAST_FLAG_PENDING
Definition: Spell.h:84
@ CAST_FLAG_IMMUNITY
Definition: Spell.h:110
#define TRAJECTORY_MISSILE_SIZE
Definition: Spell.h:78
SpellHealPredictionType
Definition: Spell.h:155
@ SPELL_HEAL_PREDICTION_TARGET_AND_BEACON
Definition: Spell.h:158
@ SPELL_HEAL_PREDICTION_TARGET
Definition: Spell.h:156
@ SPELL_HEAL_PREDICTION_TARGET_PARTY
Definition: Spell.h:159
@ SPELL_HEAL_PREDICTION_TARGET_AND_CASTER
Definition: Spell.h:157
uint32 getMSTime()
Definition: Timer.h:33
@ TRADE_SLOT_NONTRADED
Definition: TradeData.h:27
@ UNIT_FLAG2_ALLOW_CHEAT_SPELLS
Definition: UnitDefines.h:212
@ UNIT_FLAG2_NO_ACTIONS
Definition: UnitDefines.h:217
@ UNIT_STAND_STATE_STAND
Definition: UnitDefines.h:42
@ MOVEMENTFLAG_FORWARD
Definition: UnitDefines.h:358
@ MOVEMENTFLAG_NONE
Definition: UnitDefines.h:357
@ MOVEMENTFLAG_STRAFE_LEFT
Definition: UnitDefines.h:360
@ MOVEMENTFLAG_BACKWARD
Definition: UnitDefines.h:359
@ MOVEMENTFLAG_STRAFE_RIGHT
Definition: UnitDefines.h:361
@ DIRECT_DAMAGE
Definition: UnitDefines.h:132
@ NODAMAGE
Definition: UnitDefines.h:136
@ SPELL_DIRECT_DAMAGE
Definition: UnitDefines.h:133
@ UNIT_FLAG_STUNNED
Definition: UnitDefines.h:162
@ UNIT_FLAG_NON_ATTACKABLE
Definition: UnitDefines.h:145
@ UNIT_FLAG_POSSESSED
Definition: UnitDefines.h:168
@ UNIT_FLAG_IMMUNE
Definition: UnitDefines.h:175
@ UNIT_FLAG_PACIFIED
Definition: UnitDefines.h:161
@ UNIT_FLAG_CONFUSED
Definition: UnitDefines.h:166
@ UNIT_FLAG_FLEEING
Definition: UnitDefines.h:167
@ UNIT_FLAG_PLAYER_CONTROLLED
Definition: UnitDefines.h:147
@ UNIT_FLAG_SKINNABLE
Definition: UnitDefines.h:170
ProcFlagsHit createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition: Unit.cpp:9776
@ UNIT_MASK_PUPPET
Definition: Unit.h:356
@ JUST_DIED
Definition: Unit.h:247
CurrentSpellTypes
Definition: Unit.h:588
@ CURRENT_CHANNELED_SPELL
Definition: Unit.h:591
@ CURRENT_GENERIC_SPELL
Definition: Unit.h:590
@ CURRENT_MELEE_SPELL
Definition: Unit.h:589
@ CURRENT_AUTOREPEAT_SPELL
Definition: Unit.h:592
@ UNIT_STATE_ATTACK_PLAYER
Definition: Unit.h:269
@ UNIT_STATE_ROOT
Definition: Unit.h:265
@ UNIT_STATE_CASTING
Definition: Unit.h:270
@ NULL_BAG
Definition: Unit.h:62
@ NULL_SLOT
Definition: Unit.h:63
#define ARTIFACTS_ALL_WEAPONS_GENERAL_WEAPON_EQUIPPED_PASSIVE
Definition: Unit.h:37
float DegToRad(float degrees)
Definition: Util.cpp:912
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:491
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:294
ObjectGuid GetCastId() const
Definition: SpellAuras.h:138
int32 GetMaxDuration() const
Definition: SpellAuras.h:168
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
Definition: SpellAuras.cpp:337
void SetStackAmount(uint8 num)
int32 GetCastItemLevel() const
Definition: SpellAuras.h:142
AuraEffectVector const & GetAuraEffects() const
Definition: SpellAuras.h:308
int32 GetDuration() const
Definition: SpellAuras.h:173
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
int32 CalcMaxDuration() const
Definition: SpellAuras.h:170
void SetDuration(int32 duration, bool withMods=false)
Definition: SpellAuras.cpp:892
ObjectGuid GetCastItemGUID() const
Definition: SpellAuras.h:140
uint32 GetEffectMask() const
void SetMaxDuration(int32 duration)
Definition: SpellAuras.h:169
static uint32 BuildEffectMaskForOwner(SpellInfo const *spellProto, uint32 availableEffectMask, WorldObject *owner)
Definition: SpellAuras.cpp:307
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:277
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:220
Loot * GetLootForPlayer(Player const *player) const override
Definition: Creature.cpp:1386
bool isTappedBy(Player const *player) const
Definition: Creature.cpp:1381
void SetSpellFocus(Spell const *focusSpell, WorldObject const *target)
Definition: Creature.cpp:3427
CreatureAI * AI() const
Definition: Creature.h:214
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:378
GameobjectTypes GetGoType() const
Definition: GameObject.h:279
Definition: Guild.h:329
Definition: Item.h:170
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition: Item.cpp:1166
void SetSpellCharges(uint8 index, int32 value)
Definition: Item.h:315
Trinity::IteratorPair< ItemEffectEntry const *const * > GetEffects() const
Definition: Item.h:354
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition: Item.h:298
int32 GetSpellCharges(uint8 index=0) const
Definition: Item.h:314
bool IsVellum() const
Definition: Item.h:334
bool IsLocked() const
Definition: Item.h:251
ItemTemplate const * GetTemplate() const
Definition: Item.cpp:1141
bool IsPotion() const
Definition: Item.h:333
bool IsBroken() const
Definition: Item.h:257
SocketColor GetSocketColor(uint32 index) const
Definition: Item.h:344
Player * GetOwner() const
Definition: Item.cpp:1146
ObjectGuid GetOwnerGUID() const
Definition: Item.h:188
uint32 GetDisplayId(Player const *owner) const
Definition: Item.cpp:2405
ItemDisenchantLootEntry const * GetDisenchantLoot(Player const *owner) const
Definition: Item.cpp:2360
uint32 GetItemLevel(Player const *owner) const
Definition: Item.cpp:2279
uint32 GetCount() const
Definition: Item.h:273
AzeriteEmpoweredItem * ToAzeriteEmpoweredItem()
Definition: Item.h:245
UF::UpdateField< UF::ItemData, 0, TYPEID_ITEM > m_itemData
Definition: Item.h:449
int32 GetRequiredLevel() const
Definition: Item.cpp:2807
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition: Item.cpp:1387
bool HaveLootFor(uint32 loot_id) const
Definition: LootMgr.h:83
Definition: Map.h:189
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition: Map.cpp:2547
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:1726
bool IsBattleground() const
Definition: Map.cpp:3330
ObjectGuid::LowType GenerateLowGuid()
Definition: Map.h:519
GameObject * GetGameObject(ObjectGuid const &guid)
Definition: Map.cpp:3489
Difficulty GetDifficultyID() const
Definition: Map.h:324
InstanceMap * ToInstanceMap()
Definition: Map.h:454
static ObjectGuid const Empty
Definition: ObjectGuid.h:274
bool IsAnyTypeGameObject() const
Definition: ObjectGuid.h:334
bool IsCorpse() const
Definition: ObjectGuid.h:331
bool IsEmpty() const
Definition: ObjectGuid.h:319
bool IsUnit() const
Definition: ObjectGuid.h:327
std::string ToString() const
Definition: ObjectGuid.cpp:554
static char const * GetTypeName(HighGuid high)
Definition: ObjectGuid.cpp:546
bool IsGameObject() const
Definition: ObjectGuid.h:329
static ObjectGuid const TradeItem
Definition: ObjectGuid.h:276
bool IsCreature() const
Definition: ObjectGuid.h:320
void Clear()
Definition: ObjectGuid.h:286
Definition: Object.h:150
static Creature * ToCreature(Object *o)
Definition: Object.h:219
bool IsPlayer() const
Definition: Object.h:212
static Unit * ToUnit(Object *o)
Definition: Object.h:225
Player * ToPlayer()
Definition: Object.h:215
static GameObject * ToGameObject(Object *o)
Definition: Object.h:231
bool IsInWorld() const
Definition: Object.h:154
bool HasDynamicFlag(uint32 flag) const
Definition: Object.h:168
bool IsCorpse() const
Definition: Object.h:236
bool IsUnit() const
Definition: Object.h:224
TypeID GetTypeId() const
Definition: Object.h:173
uint32 GetEntry() const
Definition: Object.h:161
bool IsCreature() const
Definition: Object.h:218
static Corpse * ToCorpse(Object *o)
Definition: Object.h:237
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
static Player * ToPlayer(Object *o)
Definition: Object.h:213
std::array< Optional< PetInfo >, MAX_ACTIVE_PETS > ActivePets
Definition: PetDefines.h:158
Definition: Pet.h:40
Player * GetOwner() const
Definition: Pet.cpp:1794
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:1093
static PhaseShift const & GetAlwaysVisiblePhaseShift()
ChrSpecialization GetPrimarySpecialization() const
Definition: Player.h:1841
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition: Player.cpp:13254
void SetSpellModTakingSpell(Spell *spell, bool apply)
Definition: Player.cpp:22381
bool Satisfy(AccessRequirement const *ar, uint32 target_map, TransferAbortParams *params=nullptr, bool report=false)
Definition: Player.cpp:19715
bool IsInSameRaidWith(Player const *p) const
Definition: Player.cpp:2160
bool HasItemFitToSpellRequirements(SpellInfo const *spellInfo, Item const *ignoreItem=nullptr) const
Definition: Player.cpp:25444
uint32 GetFreeInventorySpace() const
Definition: Player.cpp:9621
ObjectGuid GetSummonedBattlePetGUID() const
Definition: Player.h:2820
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition: Player.cpp:1611
void SetRuneCooldown(uint8 index, uint32 cooldown)
Definition: Player.cpp:26335
void SendDirectMessage(WorldPacket const *data) const
Definition: Player.cpp:6324
uint16 GetSkillValue(uint32 skill) const
Definition: Player.cpp:6052
void UpdatePotionCooldown(Spell *spell=nullptr)
Definition: Player.cpp:23374
bool CanTameExoticPets() const
Definition: Player.h:2305
uint32 GetRuneBaseCooldown() const
Definition: Player.cpp:26313
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition: Player.cpp:9888
bool HasCurrency(uint32 id, uint32 amount) const
Definition: Player.cpp:7413
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition: Player.cpp:26192
bool InBattleground() const
Definition: Player.h:2394
Item * GetItemByEntry(uint32 entry, ItemSearchLocation where=ItemSearchLocation::Default) const
Definition: Player.cpp:12589
std::vector< uint32 > const & GetGlyphs(uint8 spec) const
Definition: Player.h:1877
PetStable * GetPetStable()
Definition: Player.h:1222
bool IsLoading() const override
Definition: Player.cpp:17613
Pet * GetPet() const
Definition: Player.cpp:21513
Guild * GetGuild()
Definition: Player.cpp:29432
bool HasItemTotemCategory(uint32 TotemCategory) const
Definition: Player.cpp:10045
uint8 GetRunesState() const
Definition: Player.cpp:26308
bool GetCommandStatus(uint32 command) const
Definition: Player.h:1206
bool HasSummonPending() const
Definition: Player.cpp:25301
WorldSession * GetSession() const
Definition: Player.h:2101
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition: Player.cpp:8622
bool CanNoReagentCast(SpellInfo const *spellInfo) const
Definition: Player.cpp:25509
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition: Player.cpp:12281
uint32 GetRuneCooldown(uint8 index) const
Definition: Player.h:2643
void SendTameFailure(PetTameResult result)
Definition: Player.cpp:21629
Battleground * GetBattleground() const
Definition: Player.cpp:24976
TradeData * GetTradeData() const
Definition: Player.h:1498
bool IsGameMaster() const
Definition: Player.h:1178
void RemoveCurrency(uint32 id, int32 amount, CurrencyDestroyReason destroyReason=CurrencyDestroyReason::Cheat)
Definition: Player.cpp:7253
uint8 GetActiveTalentGroup() const
Definition: Player.h:1843
Player * GetSelectedPlayer() const
Definition: Player.cpp:24150
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition: Player.cpp:9643
bool HasSpell(uint32 spell) const override
Definition: Player.cpp:3792
Item * GetItemByGuid(ObjectGuid guid) const
Definition: Player.cpp:9566
void UpdatePvP(bool state, bool override=false)
Definition: Player.cpp:23360
Spell * m_spellModTakingSpell
Definition: Player.h:2672
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition: Player.cpp:10032
bool HasEnoughMoney(uint64 amount) const
Definition: Player.h:1740
ProcReflectDelayed(Unit *owner, ObjectGuid casterGuid)
Definition: Spell.cpp:2382
bool Execute(uint64, uint32) override
Definition: Spell.cpp:2384
ObjectGuid _casterGuid
Definition: Spell.cpp:2402
void SetPitch(float pitch)
Definition: SpellDefines.h:390
SpellDestination const * GetSrc() const
Definition: Spell.cpp:324
void SetItemTarget(Item *item)
Definition: Spell.cpp:295
void RemoveObjectTarget()
Definition: Spell.cpp:288
ObjectGuid m_objectTargetGUID
Definition: SpellDefines.h:409
WorldObject * GetObjectTarget() const
Definition: Spell.cpp:278
ObjectGuid GetUnitTargetGUID() const
Definition: Spell.cpp:210
void ModDst(Position const &pos)
Definition: Spell.cpp:403
GameObject * GetGOTarget() const
Definition: Spell.cpp:244
void SetTradeItemTarget(Player *caster)
Definition: Spell.cpp:306
SpellDestination m_dst
Definition: SpellDefines.h:414
bool HasSrc() const
Definition: Spell.cpp:420
bool HasTraj() const
Definition: SpellDefines.h:387
Corpse * GetCorpseTarget() const
Definition: Spell.cpp:270
void SetDst(float x, float y, float z, float orientation, uint32 mapId=MAPID_INVALID)
Definition: Spell.cpp:373
void SetSpeed(float speed)
Definition: SpellDefines.h:392
void SetSrc(float x, float y, float z)
Definition: Spell.cpp:334
void SetTargetFlag(SpellCastTargetFlags flag)
Definition: SpellDefines.h:342
SpellDestination const * GetDst() const
Definition: Spell.cpp:363
void SetGOTarget(GameObject *target)
Definition: Spell.cpp:252
std::string m_strTarget
Definition: SpellDefines.h:417
void UpdateTradeSlotItem()
Definition: Spell.cpp:315
SpellDestination m_src
Definition: SpellDefines.h:413
ObjectGuid GetCorpseTargetGUID() const
Definition: Spell.cpp:262
ObjectGuid GetObjectTargetGUID() const
Definition: Spell.cpp:283
void SetUnitTarget(Unit *target)
Definition: Spell.cpp:226
bool HasDst() const
Definition: Spell.cpp:425
ObjectGuid GetItemTargetGUID() const
Definition: SpellDefines.h:359
WorldObject * m_objectTarget
Definition: SpellDefines.h:405
Item * GetItemTarget() const
Definition: SpellDefines.h:360
uint32 GetTargetMask() const
Definition: SpellDefines.h:339
uint32 GetItemTargetEntry() const
Definition: SpellDefines.h:361
Unit * GetUnitTarget() const
Definition: Spell.cpp:218
ObjectGuid m_itemTargetGUID
Definition: SpellDefines.h:410
float GetSpeedXY() const
Definition: SpellDefines.h:395
float GetDist2d() const
Definition: SpellDefines.h:394
uint32 m_itemTargetEntry
Definition: SpellDefines.h:411
void Update(WorldObject *caster)
Definition: Spell.cpp:430
void ModSrc(Position const &pos)
Definition: Spell.cpp:352
void RemoveDst()
Definition: Spell.cpp:415
void Write(WorldPackets::Spells::SpellTargetData &data)
Definition: Spell.cpp:176
void RemoveSrc()
Definition: Spell.cpp:358
float GetPitch() const
Definition: SpellDefines.h:389
Position const * GetSrcPos() const
Definition: Spell.cpp:329
ObjectGuid GetGOTargetGUID() const
Definition: Spell.cpp:236
WorldLocation const * GetDstPos() const
Definition: Spell.cpp:368
float PositionFacing
Definition: SpellInfo.h:230
bool HasRadius(SpellTargetIndex targetIndex) const
Definition: SpellInfo.cpp:660
AuraType ApplyAuraName
Definition: SpellInfo.h:219
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:495
uint32 TriggerSpell
Definition: SpellInfo.h:237
uint32 GetMissingTargetMask(bool srcSet=false, bool dstSet=false, uint32 mask=0) const
Definition: SpellInfo.cpp:719
bool IsAreaAuraEffect() const
Definition: SpellInfo.cpp:476
SpellEffectName Effect
Definition: SpellInfo.h:218
std::shared_ptr< std::vector< Condition > > ImplicitTargetConditions
Definition: SpellInfo.h:240
bool IsEffect() const
Definition: SpellInfo.cpp:451
bool IsTargetingArea() const
Definition: SpellInfo.cpp:471
int32 ChainTargets
Definition: SpellInfo.h:235
SpellEffectImplicitTargetTypes GetImplicitTargetType() const
Definition: SpellInfo.cpp:743
EnumFlag< SpellEffectAttributes > EffectAttributes
Definition: SpellInfo.h:241
SpellEffIndex EffectIndex
Definition: SpellInfo.h:217
SpellImplicitTargetInfo TargetA
Definition: SpellInfo.h:231
float CalcRadius(WorldObject *caster=nullptr, SpellTargetIndex targetIndex=SpellTargetIndex::TargetA, Spell *=nullptr) const
Definition: SpellInfo.cpp:673
SpellImplicitTargetInfo TargetB
Definition: SpellInfo.h:232
~SpellEvent()
Definition: Spell.cpp:8210
bool IsDeletable() const override
Definition: Spell.cpp:8324
Trinity::unique_trackable_ptr< Spell > m_Spell
Definition: Spell.cpp:500
std::string GetDebugInfo() const
Definition: Spell.cpp:497
void Abort(uint64 e_time) override
Definition: Spell.cpp:8317
Trinity::unique_weak_ptr< Spell > GetSpellWeakPtr() const
Definition: Spell.cpp:495
SpellEvent(Spell *spell)
Definition: Spell.cpp:8206
bool Execute(uint64 e_time, uint32 p_time) override
Definition: Spell.cpp:8223
Spell const * GetSpell() const
Definition: Spell.cpp:494
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:95
SpellTargetReferenceTypes GetReferenceType() const
Definition: SpellInfo.cpp:85
SpellTargetSelectionCategories GetSelectionCategory() const
Definition: SpellInfo.cpp:80
SpellTargetObjectTypes GetObjectType() const
Definition: SpellInfo.cpp:90
float CalcDirectionAngle() const
Definition: SpellInfo.cpp:105
Targets GetTarget() const
Definition: SpellInfo.cpp:132
uint32 RequiresSpellFocus
Definition: SpellInfo.h:351
uint32 BaseLevel
Definition: SpellInfo.h:383
uint32 MaxLevel
Definition: SpellInfo.h:382
uint32 SpellLevel
Definition: SpellInfo.h:384
struct SpellInfo::@337 SqrtDamageAndHealingDiminishing
std::array< int32, MAX_SPELL_TOTEMS > Totem
Definition: SpellInfo.h:391
uint32 GetMaxTicks() const
Definition: SpellInfo.cpp:3823
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition: SpellInfo.h:393
uint32 PreventionType
Definition: SpellInfo.h:411
uint32 CasterAuraSpell
Definition: SpellInfo.h:357
float Width
Definition: SpellInfo.h:405
Optional< SpellPowerCost > CalcPowerCost(Powers powerType, bool optionalCost, WorldObject const *caster, SpellSchoolMask schoolMask, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3870
float GetMaxRange(bool positive=false, WorldObject *caster=nullptr, Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3768
bool HasEffect(SpellEffectName effect) const
Definition: SpellInfo.cpp:1391
SpellCastResult CheckShapeshift(uint32 form) const
Definition: SpellInfo.cpp:1946
std::array< uint16, MAX_SPELL_TOTEMS > TotemCategory
Definition: SpellInfo.h:392
uint64 GetAllEffectsMechanicMask() const
Definition: SpellInfo.cpp:2470
bool IsRequiringDeadTarget() const
Definition: SpellInfo.cpp:1663
uint32 const Id
Definition: SpellInfo.h:325
int32 NumNonDiminishedTargets
Definition: SpellInfo.h:430
uint64 GetMechanicImmunityMask(Unit const *caster) const
Definition: SpellInfo.cpp:3744
std::array< int16, MAX_SPELL_REAGENTS > ReagentCount
Definition: SpellInfo.h:394
bool IsCooldownStartedOnEvent() const
Definition: SpellInfo.cpp:1649
EnumFlag< SpellAuraInterruptFlags > ChannelInterruptFlags
Definition: SpellInfo.h:374
bool IsPassive() const
Definition: SpellInfo.cpp:1592
uint32 StackAmount
Definition: SpellInfo.h:390
::Difficulty const Difficulty
Definition: SpellInfo.h:326
uint32 Mechanic
Definition: SpellInfo.h:329
SpellRangeEntry const * RangeEntry
Definition: SpellInfo.h:387
uint32 CalcCastTime(Spell *spell=nullptr) const
Definition: SpellInfo.cpp:3805
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const *player=nullptr) const
Definition: SpellInfo.cpp:1995
uint32 GetRecoveryTime() const
Definition: SpellInfo.cpp:3865
DiminishingReturnsType GetDiminishingReturnsGroupType() const
Definition: SpellInfo.cpp:3293
uint64 GetAllowedMechanicMask() const
Definition: SpellInfo.cpp:3739
bool HasHitDelay() const
Definition: SpellInfo.cpp:1751
uint32 ExcludeCasterAuraState
Definition: SpellInfo.h:355
float Speed
Definition: SpellInfo.h:388
float GetMinRange(bool positive=false) const
Definition: SpellInfo.cpp:3761
int32 GetMaxDuration() const
Definition: SpellInfo.cpp:3798
int32 EquippedItemClass
Definition: SpellInfo.h:396
bool HasInitialAggro() const
Definition: SpellInfo.cpp:1746
DiminishingGroup GetDiminishingReturnsGroupForSpell() const
Definition: SpellInfo.cpp:3288
uint32 SchoolMask
Definition: SpellInfo.h:413
uint32 CasterAuraState
Definition: SpellInfo.h:353
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
Definition: SpellInfo.cpp:2175
EnumFlag< SpellInterruptFlags > InterruptFlags
Definition: SpellInfo.h:371
flag128 SpellFamilyFlags
Definition: SpellInfo.h:409
bool IsAllowingDeadTarget() const
Definition: SpellInfo.cpp:1668
float LaunchDelay
Definition: SpellInfo.h:389
WeaponAttackType GetAttackType() const
Definition: SpellInfo.cpp:1756
SpellSchoolMask GetSchoolMask() const
Definition: SpellInfo.cpp:2465
std::vector< SpellReagentsCurrencyEntry const * > ReagentsCurrency
Definition: SpellInfo.h:395
bool IsChanneled() const
Definition: SpellInfo.cpp:1719
bool HasAttribute(SpellAttr0 attribute) const
Definition: SpellInfo.h:449
bool IsNextMeleeSwingSpell() const
Definition: SpellInfo.cpp:1729
uint32 ChargeCategoryId
Definition: SpellInfo.h:414
bool SpellCancelsAuraEffect(AuraEffect const *aurEff) const
Definition: SpellInfo.cpp:3693
uint32 IconFileDataId
Definition: SpellInfo.h:399
uint32 MaxAffectedTargets
Definition: SpellInfo.h:407
int32 GetDuration() const
Definition: SpellInfo.cpp:3791
SpellCastResult CheckVehicle(Unit const *caster) const
Definition: SpellInfo.cpp:2395
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition: SpellInfo.h:577
std::vector< SpellEffectInfo > const & GetEffects() const
Definition: SpellInfo.h:576
int32 EquippedItemSubClassMask
Definition: SpellInfo.h:397
uint32 GetExplicitTargetMask() const
Definition: SpellInfo.cpp:2533
uint32 FacingCasterFlags
Definition: SpellInfo.h:352
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
Definition: SpellInfo.cpp:2359
uint32 StartRecoveryTime
Definition: SpellInfo.h:369
LocalizedString const * SpellName
Definition: SpellInfo.h:403
bool NeedsExplicitUnitTarget() const
Definition: SpellInfo.cpp:1551
EnumFlag< SpellAuraInterruptFlags2 > ChannelInterruptFlags2
Definition: SpellInfo.h:375
AuraType ExcludeCasterAuraType
Definition: SpellInfo.h:363
bool IsPositive() const
Definition: SpellInfo.cpp:1709
bool IsAutoRepeatRangedSpell() const
Definition: SpellInfo.cpp:1741
bool IsMoveAllowedChannel() const
Definition: SpellInfo.cpp:1724
uint32 DmgClass
Definition: SpellInfo.h:410
AuraType CasterAuraType
Definition: SpellInfo.h:361
uint32 ExcludeCasterAuraSpell
Definition: SpellInfo.h:359
bool HasAura(AuraType aura) const
Definition: SpellInfo.cpp:1400
bool IsTargetingArea() const
Definition: SpellInfo.cpp:1542
uint32 StartRecoveryCategory
Definition: SpellInfo.h:368
int32 MaxTargets
Definition: SpellInfo.h:429
uint32 CategoryId
Definition: SpellInfo.h:327
float ConeAngle
Definition: SpellInfo.h:404
uint32 SpellFamilyName
Definition: SpellInfo.h:408
bool IsPositiveEffect(uint8 effIndex) const
Definition: SpellInfo.cpp:1714
bool CanBeUsedInCombat(Unit const *caster) const
Definition: SpellInfo.cpp:1703
bool IsEffectAffected(SpellInfo const *spellInfo, uint8 effIndex) const
void Call(SpellScript *spellScript, SpellMissInfo missInfo) const
Definition: SpellScript.h:412
void Call(SpellScript *spellScript) const
Definition: SpellScript.h:276
SpellCastResult Call(SpellScript *spellScript) const
Definition: SpellScript.h:328
void Call(SpellScript *spellScript, Unit *victim, int32 &damageOrHealing, int32 &flatMod, float &pctMod) const
Definition: SpellScript.h:727
void Call(SpellScript *spellScript, SpellDestination &target) const
Definition: SpellScript.h:675
void Call(SpellScript *spellScript, SpellEffIndex effIndex) const
Definition: SpellScript.h:378
void Call(SpellScript *spellScript) const
Definition: SpellScript.h:446
void Call(SpellScript *spellScript, std::list< WorldObject * > &targets) const
Definition: SpellScript.h:569
void Call(SpellScript *spellScript, WorldObject *&target) const
Definition: SpellScript.h:622
void Call(SpellScript *spellScript, Unit const *victim, float &critChance) const
Definition: SpellScript.h:498
void Call(SpellScript *spellScript, DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount) const
Definition: SpellScript.h:779
uint16 GetTarget() const
Definition: SpellScript.h:518
Definition: Spell.h:255
int32 CalculateDamage(SpellEffectInfo const &spellEffectInfo, Unit const *target, float *var=nullptr) const
Definition: Spell.cpp:7085
void CheckDst()
Definition: Spell.cpp:7153
void SelectImplicitTargetObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1796
SpellInfo const * GetSpellInfo() const
Definition: Spell.h:650
void ExecuteLogEffectTakeTargetPower(SpellEffectName effect, Unit *target, uint32 powerType, uint32 points, float amplitude)
Definition: Spell.cpp:5086
float m_damageMultipliers[MAX_SPELL_EFFECTS]
Definition: Spell.h:729
SpellCastResult CheckItems(int32 *param1, int32 *param2) const
Definition: Spell.cpp:7307
void ExecuteLogEffectSummonObject(SpellEffectName effect, WorldObject *obj)
Definition: Spell.cpp:5152
bool m_fromClient
Definition: Spell.h:570
void CallScriptAfterCastHandlers()
Definition: Spell.cpp:8659
std::vector< SpellPowerCost > m_powerCost
Definition: Spell.h:702
uint32 m_castFlagsEx
Definition: Spell.h:571
void AddCorpseTarget(Corpse *target, uint32 effectMask)
Definition: Spell.cpp:2593
uint64 CalculateDelayMomentForDst(float launchDelay) const
Definition: Spell.cpp:849
GameObject * SearchSpellFocus()
Definition: Spell.cpp:2317
bool CheckSpellCancelsStun(int32 *param1) const
Definition: Spell.cpp:6991
std::vector< SpellScript * > m_loadedScripts
Definition: Spell.h:886
GameObject * gameObjTarget
Definition: Spell.h:734
std::pair< float, float > GetMinMaxRange(bool strict) const
Definition: Spell.cpp:7207
void PrepareTriggersExecutedOnHit()
Definition: Spell.cpp:8920
SpellMissInfo targetMissInfo
Definition: Spell.h:738
bool m_referencedFromCurrentSpell
Definition: Spell.h:726
bool m_canReflect
Definition: Spell.h:705
void PreprocessSpellLaunch(TargetInfo &targetInfo)
Definition: Spell.cpp:8374
void UpdateDelayMomentForUnitTarget(Unit *unit, uint64 hitDelay)
Definition: Spell.cpp:887
bool CheckSpellCancelsNoActions(int32 *param1) const
Definition: Spell.cpp:7019
bool HasPowerTypeCost(Powers power) const
Definition: Spell.cpp:7953
Unit * m_originalCaster
Definition: Spell.h:696
void LoadScripts()
Definition: Spell.cpp:8615
void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction &healPrediction, bool withPeriodic)
Definition: Spell.cpp:5024
void SelectImplicitTrajTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1866
DynObjAura * _dynObjAura
Definition: Spell.h:745
void ExecuteLogEffectUnsummonObject(SpellEffectName effect, WorldObject *obj)
Definition: Spell.cpp:5160
uint32 m_channelTargetEffectMask
Definition: Spell.h:809
void ExecuteLogEffectResurrect(SpellEffectName effect, Unit *target)
Definition: Spell.cpp:5168
void cast(bool skipCheck=false)
Definition: Spell.cpp:3648
void ExecuteLogEffectDestroyItem(SpellEffectName effect, uint32 entry)
Definition: Spell.cpp:5144
void SendChannelStart(uint32 duration)
Definition: Spell.cpp:5215
void ExecuteLogEffectOpenLock(SpellEffectName effect, Object *obj)
Definition: Spell.cpp:5128
uint64 m_delayStart
Definition: Spell.h:720
int64 GetCorpseTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2691
SpellCastTargets m_targets
Definition: Spell.h:607
void SelectImplicitNearbyTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1105
std::unique_ptr< PathGenerator > m_preGeneratedPath
Definition: Spell.h:927
Difficulty GetCastDifficulty() const
Definition: Spell.cpp:8038
void CallScriptBeforeHitHandlers(SpellMissInfo missInfo)
Definition: Spell.cpp:8758
void SelectEffectImplicitTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 &processedEffectMask)
Definition: Spell.cpp:914
SpellCastResult CheckRuneCost() const
Definition: Spell.cpp:5454
void CallScriptCalcDamageHandlers(Unit *victim, int32 &damage, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:8807
void SelectExplicitTargets()
Definition: Spell.cpp:710
void handle_immediate()
Definition: Spell.cpp:3979
void SendSpellGo()
Definition: Spell.cpp:4778
int32 m_procChainLength
Definition: Spell.h:925
SpellCastResult CanOpenLock(SpellEffectInfo const &effect, uint32 lockid, SkillType &skillid, int32 &reqSkillValue, int32 &skillValue)
Definition: Spell.cpp:8492
void DoTriggersOnSpellHit(Unit *unit)
Definition: Spell.cpp:3304
TriggerCastFlags _triggeredCastFlags
Definition: Spell.h:919
bool IsAutoRepeat() const
Definition: Spell.h:614
int32 damage
Definition: Spell.h:737
void SetSpellValue(SpellValueMod mod, int32 value)
Definition: Spell.cpp:8566
void HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, Corpse *pCorpseTarget, SpellEffectInfo const &spellEffectInfo, SpellEffectHandleMode mode)
Definition: Spell.cpp:5615
void prepareDataForTriggerSystem()
Definition: Spell.cpp:2326
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:2193
SpellEffectHandleMode effectHandleMode
Definition: Spell.h:740
void TakeReagents()
Definition: Spell.cpp:5505
bool IsValidDeadOrAliveTarget(Unit const *target) const
Definition: Spell.cpp:8329
int32 m_channeledDuration
Definition: Spell.h:704
SpellCastResult CheckMovement() const
Definition: Spell.cpp:7055
void DoProcessTargetContainer(Container &targetContainer)
Definition: Spell.cpp:3965
bool IsNeedSendToClient() const
Definition: Spell.cpp:8194
WorldObject * SearchNearbyTarget(SpellEffectInfo const &spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const *condList=nullptr)
Definition: Spell.cpp:2179
bool IsIgnoringCooldowns() const
Definition: Spell.cpp:8158
void SelectImplicitDestDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition: Spell.cpp:1679
uint32 Id
Definition: Spell.h:590
std::vector< TargetInfo > m_UniqueTargetInfo
Definition: Spell.h:808
SpellDestination m_destTargets[MAX_SPELL_EFFECTS]
Definition: Spell.h:840
void _handle_finish_phase()
Definition: Spell.cpp:4171
void UpdateDelayMomentForDst(uint64 hitDelay)
Definition: Spell.cpp:879
bool CanExecuteTriggersOnHit(Unit *unit, SpellInfo const *triggeredByAura=nullptr) const
Definition: Spell.cpp:8903
void PrepareTargetProcessing()
Definition: Spell.cpp:8606
Trinity::unique_weak_ptr< Spell > GetWeakPtr() const
Definition: Spell.cpp:9043
void SetExecutedCurrently(bool yes)
Definition: Spell.h:632
void AddUnitTarget(Unit *target, uint32 effectMask, bool checkIfValid=true, bool implicit=true, Position const *losPosition=nullptr)
Definition: Spell.cpp:2405
void SendSpellStart()
Definition: Spell.cpp:4671
ObjectGuid m_originalCastId
Definition: Spell.h:569
uint8 m_delayAtDamageCount
Definition: Spell.h:709
void SendChannelUpdate(uint32 time)
Definition: Spell.cpp:5195
static Spell const * ExtractSpellFromEvent(BasicEvent *event)
Definition: Spell.cpp:5633
ProcFlagsSpellType m_procSpellType
Definition: Spell.h:760
uint64 m_delayMoment
Definition: Spell.h:721
void ExecuteLogEffectExtraAttacks(SpellEffectName effect, Unit *victim, uint32 numAttacks)
Definition: Spell.cpp:5098
WeaponAttackType m_attackType
Definition: Spell.h:700
void _cast(bool skipCheck=false)
Definition: Spell.cpp:3665
void SendInterrupted(uint8 result)
Definition: Spell.cpp:5176
bool IsProcDisabled() const
Definition: Spell.cpp:8168
bool m_immediateHandled
Definition: Spell.h:723
void SendSpellInterruptLog(Unit *victim, uint32 spellId)
Definition: Spell.cpp:5107
uint32 m_spellState
Definition: Spell.h:915
bool IsFocusDisabled() const
Definition: Spell.cpp:8163
std::any m_customArg
Definition: Spell.h:605
int32 GetSpellCastDataAmmo()
Definition: Spell.cpp:4908
ObjectGuid m_originalCasterGUID
Definition: Spell.h:694
WorldObject *const m_caster
Definition: Spell.h:690
int64 GetItemTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2683
std::string GetDebugInfo() const
Definition: Spell.cpp:9034
bool IsDeletable() const
Definition: Spell.h:629
bool UpdateChanneledTargetList()
Definition: Spell.cpp:3357
void CleanupTargetList()
Definition: Spell.cpp:2371
void TriggerGlobalCooldown()
Definition: Spell.cpp:8968
int32 m_timer
Definition: Spell.h:916
int32 m_casttime
Definition: Spell.h:703
void ExecuteLogEffectDurabilityDamage(SpellEffectName effect, Unit *victim, int32 itemId, int32 amount)
Definition: Spell.cpp:5118
void CallScriptCalcHealingHandlers(Unit *victim, int32 &healing, int32 &flatMod, float &pctMod)
Definition: Spell.cpp:8819
void SendMountResult(MountResult result)
Definition: Spell.cpp:4654
Item * itemTarget
Definition: Spell.h:733
void AddGOTarget(GameObject *target, uint32 effectMask)
Definition: Spell.cpp:2512
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:4643
void HandleThreatSpells()
Definition: Spell.cpp:5559
float variance
Definition: Spell.h:739
int32 m_damage
Definition: Spell.h:751
std::vector< CorpseTargetInfo > m_UniqueCorpseTargetInfo
Definition: Spell.h:835
void CancelGlobalCooldown()
Definition: Spell.cpp:9019
bool CheckSpellCancelsAuraEffect(AuraType auraType, int32 *param1) const
Definition: Spell.cpp:6955
void SearchChainTargets(std::list< WorldObject * > &targets, uint32 chainTargets, WorldObject *target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const &spellEffectInfo, bool isChainHeal)
Definition: Spell.cpp:2208
uint32 getState() const
Definition: Spell.h:514
bool m_executedCurrently
Definition: Spell.h:727
void SelectImplicitAreaTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1349
bool CheckSpellCancelsSilence(int32 *param1) const
Definition: Spell.cpp:6997
void CallScriptOnCastHandlers()
Definition: Spell.cpp:8647
void AddDestTarget(SpellDestination const &dest, uint32 effIndex)
Definition: Spell.cpp:2645
int64 GetGameObjectTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2675
void _handle_immediate_phase()
Definition: Spell.cpp:4151
void SendSpellCooldown()
Definition: Spell.cpp:4210
void CallScriptBeforeCastHandlers()
Definition: Spell.cpp:8635
bool CheckSpellCancelsCharm(int32 *param1) const
Definition: Spell.cpp:6984
void HandleLaunchPhase()
Definition: Spell.cpp:8338
bool UpdatePointers()
Definition: Spell.cpp:7971
SpellCustomErrors m_customError
Definition: Spell.h:608
void SelectImplicitLineTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1952
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode)
Definition: Spell.cpp:8700
std::vector< GOTargetInfo > m_UniqueGOTargetInfo
Definition: Spell.h:818
void DoSpellEffectHit(Unit *unit, SpellEffectInfo const &spellEffectInfo, TargetInfo &targetInfo)
Definition: Spell.cpp:3214
HitTriggerSpellList m_hitTriggerSpells
Definition: Spell.h:902
int32 m_healing
Definition: Spell.h:752
void SelectImplicitTargetDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition: Spell.cpp:1646
void SetDelayStart(uint64 m_time)
Definition: Spell.h:634
void ResetCombatTimers()
Definition: Spell.cpp:8480
void CallScriptOnPrecastHandler()
Definition: Spell.cpp:8625
void SelectImplicitCasterDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex)
Definition: Spell.cpp:1476
SpellEffectInfo const * effectInfo
Definition: Spell.h:741
Unit * GetUnitCasterForEffectHandlers() const
Definition: Spell.cpp:8201
SpellInfo const * m_triggeredByAuraSpell
Definition: Spell.h:924
uint64 handle_delayed(uint64 t_offset)
Definition: Spell.cpp:4046
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition: Spell.cpp:8870
bool CheckSpellCancelsPacify(int32 *param1) const
Definition: Spell.cpp:7003
int32 m_castItemLevel
Definition: Spell.h:567
CurrentSpellTypes GetCurrentContainer() const
Definition: Spell.cpp:8026
UnitAura * _spellAura
Definition: Spell.h:744
uint32 m_applyMultiplierMask
Definition: Spell.h:728
Unit * unitTarget
Definition: Spell.h:732
void Delayed()
Definition: Spell.cpp:7870
SpellSchoolMask m_spellSchoolMask
Definition: Spell.h:699
void SendSpellExecuteLog()
Definition: Spell.cpp:5056
Optional< int32 > GetPowerTypeCostAmount(Powers power) const
Definition: Spell.cpp:7958
void cancel()
Definition: Spell.cpp:3594
WorldObject * GetCaster() const
Definition: Spell.h:647
SpellEvent * _spellEvent
Definition: Spell.h:918
void SelectSpellTargets()
Definition: Spell.cpp:739
bool CheckSpellCancelsConfuse(int32 *param1) const
Definition: Spell.cpp:7014
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition: Spell.cpp:3426
SpellCastResult CheckCast(bool strict, int32 *param1=nullptr, int32 *param2=nullptr)
Definition: Spell.cpp:5641
bool IsChannelActive() const
Definition: Spell.cpp:8173
~Spell()
Definition: Spell.cpp:617
void TakePower()
Definition: Spell.cpp:5388
SpellCastResult CheckPetCast(Unit *target)
Definition: Spell.cpp:6787
void RecalculateDelayMomentForDst()
Definition: Spell.cpp:874
Corpse * m_corpseTarget
Definition: Spell.h:735
SpellLogEffect & GetExecuteLogEffect(SpellEffectName effect)
Definition: Spell.cpp:5072
void ReSetTimer()
Definition: Spell.h:616
void SelectImplicitChainTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, WorldObject *target, uint32 effMask)
Definition: Spell.cpp:1820
int32 CallScriptCalcCastTimeHandlers(int32 originalCastTime)
Definition: Spell.cpp:8689
SpellCastResult CallScriptCheckCastHandlers()
Definition: Spell.cpp:8671
void ExecuteLogEffectCreateItem(SpellEffectName effect, uint32 entry)
Definition: Spell.cpp:5136
bool IsPositive() const
Definition: Spell.cpp:8189
void InitExplicitTargets(SpellCastTargets const &targets)
Definition: Spell.cpp:640
bool IsWithinLOS(WorldObject const *source, WorldObject const *target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const
Definition: Spell.cpp:9048
void SendPetCastResult(SpellCastResult result, int32 *param1=nullptr, int32 *param2=nullptr) const
Definition: Spell.cpp:4626
union Spell::@333 m_misc
WorldLocation * destTarget
Definition: Spell.h:736
bool CheckSpellCancelsFear(int32 *param1) const
Definition: Spell.cpp:7009
Spell ** m_selfContainer
Definition: Spell.h:662
bool IsTriggered() const
Definition: Spell.cpp:8153
void SelectImplicitCasterObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1731
void SetReferencedFromCurrent(bool yes)
Definition: Spell.h:630
bool IsDelayableNoMore()
Definition: Spell.h:710
void SelectEffectTypeImplicitTargets(SpellEffectInfo const &spellEffectInfo)
Definition: Spell.cpp:2013
void update(uint32 difftime)
Definition: Spell.cpp:4224
void SelectImplicitConeTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, SpellTargetIndex targetIndex, uint32 effMask)
Definition: Spell.cpp:1289
uint64 GetDelayStart() const
Definition: Spell.h:633
bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
Definition: Spell.cpp:8882
ProcFlagsInit m_procVictim
Definition: Spell.h:758
Item * m_CastItem
Definition: Spell.h:564
std::vector< SpellLogEffect > _executeLogEffects
Definition: Spell.h:929
void CallScriptSuccessfulDispel(SpellEffIndex effIndex)
Definition: Spell.cpp:8746
void DoEffectOnLaunchTarget(TargetInfo &targetInfo, float multiplier, SpellEffectInfo const &spellEffectInfo)
Definition: Spell.cpp:8406
uint32 m_castItemEntry
Definition: Spell.h:566
uint64 GetDelayMoment() const
Definition: Spell.h:635
void AddItemTarget(Item *item, uint32 effectMask)
Definition: Spell.cpp:2565
int32 GetUnitTargetIndexForEffect(ObjectGuid const &target, SpellEffIndex effect) const
Definition: Spell.cpp:2650
UsedSpellMods m_appliedMods
Definition: Spell.h:610
void TakeCastItem()
Definition: Spell.cpp:5320
void CheckSrc()
Definition: Spell.cpp:7147
void CallScriptCalcCritChanceHandlers(Unit const *victim, float &chance)
Definition: Spell.cpp:8795
SpellValue *const m_spellValue
Definition: Spell.h:692
void SelectImplicitChannelTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:1034
void finish(SpellCastResult result=SPELL_CAST_OK)
Definition: Spell.cpp:4311
bool CheckEffectTarget(Unit const *target, SpellEffectInfo const &spellEffectInfo, Position const *losPosition) const
Definition: Spell.cpp:8043
void SendResurrectRequest(Player *target)
Definition: Spell.cpp:5298
SpellMissInfo PreprocessSpellHit(Unit *unit, TargetInfo &targetInfo)
Definition: Spell.cpp:3100
SpellCastResult CheckCasterAuras(int32 *param1) const
Definition: Spell.cpp:6821
static uint32 GetSearcherTypeMask(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const *condList)
Definition: Spell.cpp:2113
static void SearchTargets(SEARCHER &searcher, uint32 containerMask, WorldObject *referer, Position const *pos, float radius)
Definition: Spell.cpp:2151
std::vector< ItemTargetInfo > m_UniqueItemInfo
Definition: Spell.h:826
bool IsAutoActionResetSpell() const
Definition: Spell.cpp:8178
void DelayedChannel()
Definition: Spell.cpp:7906
ProcFlagsInit m_procAttacker
Definition: Spell.h:757
ObjectGuid m_castItemGUID
Definition: Spell.h:565
SpellCastVisual m_SpellVisual
Definition: Spell.h:606
Spell(WorldObject *caster, SpellInfo const *info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID=ObjectGuid::Empty, ObjectGuid originalCastId=ObjectGuid::Empty)
Definition: Spell.cpp:503
int64 GetUnitTargetCountForEffect(SpellEffIndex effect) const
Definition: Spell.cpp:2667
SpellCastResult CheckPower() const
Definition: Spell.cpp:7265
GameObject * focusObject
Definition: Spell.h:748
void CallScriptDestinationTargetSelectHandlers(SpellDestination &target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:8857
ProcFlagsHit m_hitMask
Definition: Spell.h:759
ObjectGuid m_castId
Definition: Spell.h:568
bool m_launchHandled
Definition: Spell.h:722
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData &data)
Writes miss and hit targets for a SMSG_SPELL_GO packet.
Definition: Spell.cpp:4873
SpellInfo const *const m_spellInfo
Definition: Spell.h:563
std::vector< T > & GetExecuteLogEffectTargets(SpellEffectName effect, Optional< std::vector< T > > SpellLogEffect::*member)
Definition: Spell.h:536
bool HasGlobalCooldown() const
Definition: Spell.cpp:8960
uint8 m_runesState
Definition: Spell.h:707
void FinishTargetProcessing()
Definition: Spell.cpp:8610
void CallScriptOnHitHandlers()
Definition: Spell.cpp:8771
SpellCastResult CheckRange(bool strict) const
Definition: Spell.cpp:7159
bool m_autoRepeat
Definition: Spell.h:706
void CallScriptObjectTargetSelectHandlers(WorldObject *&target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:8844
void TakeRunePower(bool didHit)
Definition: Spell.cpp:5482
void CallScriptObjectAreaTargetSelectHandlers(std::list< WorldObject * > &targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition: Spell.cpp:8831
SpellCastResult CheckArenaAndRatedBattlegroundCastRules()
Definition: Spell.cpp:7024
void CallScriptAfterHitHandlers()
Definition: Spell.cpp:8783
bool CanAutoCast(Unit *target)
Definition: Spell.cpp:7091
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 ==
float GetThreat(Unit const *who, bool includeOffline=false) const
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:381
void AddStaticApplication(Unit *target, uint32 effMask)
Definition: Unit.h:627
Unit * GetCharmed() const
Definition: Unit.h:1191
void ClearUnitState(uint32 f)
Definition: Unit.h:733
uint32 GetChannelSpellId() const
Definition: Unit.h:1402
void SetLastDamagedTargetGuid(ObjectGuid guid)
Definition: Unit.h:946
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition: Unit.cpp:8280
bool IsWithinBoundaryRadius(const Unit *obj) const
Definition: Unit.cpp:672
void RemoveGameObject(GameObject *gameObj, bool del)
Definition: Unit.cpp:5238
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition: Unit.h:1321
uint32 GetSchoolImmunityMask() const
Definition: Unit.cpp:7521
uint32 m_lastSanctuaryTime
Definition: Unit.h:1547
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition: Unit.cpp:7120
Pet * ToPet()
Definition: Unit.h:1750
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition: Unit.h:1015
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3685
int64 ModifyHealth(int64 val)
Definition: Unit.cpp:8182
void SetCurrentCastSpell(Spell *pSpell)
Definition: Unit.cpp:2941
void SetStandState(UnitStandStateType state, uint32 animKitID=0)
Definition: Unit.cpp:10100
ThreatManager & GetThreatManager()
Definition: Unit.h:1063
bool HasAuraTypeWithMiscvalue(AuraType auraType, int32 miscValue) const
Definition: Unit.cpp:4687
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition: Unit.h:1045
UF::UpdateField< UF::UnitData, 0, TYPEID_UNIT > m_unitData
Definition: Unit.h:1814
uint8 GetClass() const
Definition: Unit.h:752
static void DealDamageMods(Unit const *attacker, Unit const *victim, uint32 &damage, uint32 *absorb)
Definition: Unit.cpp:748
uint64 GetMechanicImmunityMask() const
Definition: Unit.cpp:7541
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:1142
std::forward_list< AuraEffect * > AuraEffectList
Definition: Unit.h:644
bool IsInDisallowedMountForm() const
Definition: Unit.cpp:8915
bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7431
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition: Unit.cpp:1248
bool IsPvP() const
Definition: Unit.h:873
bool haveOffhandWeapon() const
Definition: Unit.cpp:498
bool IsPet() const
Definition: Unit.h:740
Powers GetPowerType() const
Definition: Unit.h:799
bool HasUnitFlag(UnitFlags flags) const
Definition: Unit.h:832
bool CanProc() const
Definition: Unit.h:1701
ObjectGuid GetCharmedGUID() const
Definition: Unit.h:1190
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition: Unit.cpp:3059
void UpdateInterruptMask()
Definition: Unit.cpp:696
void IncrDiminishing(SpellInfo const *auraSpellInfo)
Definition: Unit.cpp:8765
void AddChannelObject(ObjectGuid guid)
Definition: Unit.h:1419
void SetChannelSpellId(uint32 channelSpellId)
Definition: Unit.h:1403
bool IsFullHealth() const
Definition: Unit.h:779
bool HasUnitFlag2(UnitFlags2 flags) const
Definition: Unit.h:837
bool IsAlive() const
Definition: Unit.h:1164
float GetCombatReach() const override
Definition: Unit.h:694
int32 GetMaxPower(Powers power) const
Definition: Unit.cpp:9410
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition: Unit.cpp:6591
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition: Unit.cpp:5378
bool IsStandState() const
Definition: Unit.cpp:10094
bool IsSilenced(SpellSchoolMask schoolMask) const
Definition: Unit.h:1453
TempSummon * ToTempSummon()
Definition: Unit.h:1756
CharmInfo * GetCharmInfo()
Definition: Unit.h:1221
ControlList m_Controlled
Definition: Unit.h:1211
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1195
float SpellCritChanceDone(Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:6931
void SetChannelVisual(SpellCastVisual channelVisual)
Definition: Unit.h:1412
virtual bool IsAffectedByDiminishingReturns() const
Definition: Unit.h:678
bool IsOnVehicle(Unit const *vehicle) const
Definition: Unit.cpp:11475
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition: Unit.h:1196
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition: Unit.cpp:7561
bool IsInFlight() const
Definition: Unit.h:1012
bool IsAIEnabled() const
Definition: Unit.h:658
float SpellCritChanceTaken(Unit const *caster, Spell *spell, AuraEffect const *aurEff, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK) const
Definition: Unit.cpp:6985
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, bool npcCaster) const
Definition: Unit.cpp:11786
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4560
uint64 GetHealth() const
Definition: Unit.h:776
bool IsSummon() const
Definition: Unit.h:738
bool IsInWater() const
Definition: Unit.cpp:3186
void RemoveDynObject(uint32 spellId)
Definition: Unit.cpp:5180
AttackerSet const & getAttackers() const
Definition: Unit.h:713
bool isMoving() const
Definition: Unit.h:1732
void EngageWithTarget(Unit *who)
Definition: Unit.cpp:8077
uint8 GetLevelForTarget(WorldObject const *) const override
Definition: Unit.h:747
int32 GetTotalAuraModifier(AuraType auraType) const
Definition: Unit.cpp:4929
void RemoveAurasWithInterruptFlags(InterruptFlags flag, SpellInfo const *source=nullptr)
Definition: Unit.cpp:4101
bool IsMounted() const
Definition: Unit.h:898
Unit * GetVictim() const
Definition: Unit.h:715
int32 GetPower(Powers power) const
Definition: Unit.cpp:9401
float GetTotalAttackPowerValue(WeaponAttackType attType, bool includeWeapon=true) const
Definition: Unit.cpp:9285
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition: Unit.cpp:7376
DeathState getDeathState() const
Definition: Unit.h:1167
bool HasUnitState(const uint32 f) const
Definition: Unit.h:732
bool IsInRaidWith(Unit const *unit) const
Definition: Unit.cpp:11546
DynamicObject * GetDynObject(uint32 spellId) const
Definition: Unit.cpp:5164
int32 GetProcChainLength() const
Definition: Unit.h:1703
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0) const
Definition: Unit.cpp:4664
float GetMeleeRange(Unit const *target) const
Definition: Unit.cpp:666
SpellHistory * GetSpellHistory()
Definition: Unit.h:1457
bool IsControlledByPlayer() const
Definition: Unit.h:1193
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition: Unit.cpp:8752
ObjectGuid GetCharmerGUID() const
Definition: Unit.h:1187
bool HasAuraWithMechanic(uint64 mechanicMask) const
Definition: Unit.cpp:4739
virtual void setDeathState(DeathState s)
Definition: Unit.cpp:8592
CombatManager & GetCombatManager()
Definition: Unit.h:1023
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition: Unit.cpp:4696
bool isAttackReady(WeaponAttackType type=BASE_ATTACK) const
Definition: Unit.h:690
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition: Unit.cpp:8776
bool IsSpiritHealer() const
Definition: Unit.h:1001
bool IsTotem() const
Definition: Unit.h:742
AuraList & GetSingleCastAuras()
Definition: Unit.h:1323
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraApplication *except=nullptr) const
Definition: Unit.cpp:4506
Vehicle * GetVehicleKit() const
Definition: Unit.h:1711
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition: Unit.cpp:630
static void ProcSkillsAndAuras(Unit *actor, Unit *actionTarget, ProcFlagsInit const &typeMaskActor, ProcFlagsInit const &typeMaskActionTarget, ProcFlagsSpellType spellTypeMask, ProcFlagsSpellPhase spellPhaseMask, ProcFlagsHit hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition: Unit.cpp:5407
virtual bool IsEngaged() const
Definition: Unit.h:1019
void ClearChannelObjects()
Definition: Unit.h:1427
bool AttackStop()
Definition: Unit.cpp:5781
bool IsInPartyWith(Unit const *unit) const
Definition: Unit.cpp:11527
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint32 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition: Unit.cpp:3831
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:7138
ObjectGuid GetTarget() const
Definition: Unit.h:1759
uint8 GetLevel() const
Definition: Unit.h:746
bool IsInCombat() const
Definition: Unit.h:1043
bool IsWalking() const
Definition: Unit.h:1136
ObjectGuid GetPetGUID() const
Definition: Unit.h:1176
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition: Unit.h:1442
bool isLineOfSightCalcEnabled() const
Definition: IVMapManager.h:113
static VMapManager2 * createOrGetVMapManager()
Definition: VMapFactory.cpp:27
bool IsControllableVehicle() const
Definition: Vehicle.cpp:600
constexpr void WorldRelocate(WorldLocation const &loc)
Definition: Position.h:187
constexpr uint32 GetMapId() const
Definition: Position.h:201
uint32 m_mapId
Definition: Position.h:203
Unit * GetMagicHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo)
Definition: Object.cpp:3249
bool IsWithinDist2d(float x, float y, float dist) const
Definition: Object.cpp:1132
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition: Object.cpp:1744
Map * GetMap() const
Definition: Object.h:624
virtual float GetCollisionHeight() const
Definition: Object.h:769
Unit * GetCharmerOrOwner() const
Definition: Object.cpp:2234
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition: Object.cpp:2670
bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1161
void SendCombatLogMessage(WorldPackets::CombatLog::CombatLogServerPacket *combatLog) const
Definition: Object.cpp:1783
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition: Object.cpp:3403
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition: Object.cpp:3777
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition: Object.cpp:2896
float GetMapWaterOrGroundLevel(float x, float y, float z, float *ground=nullptr) const
Definition: Object.cpp:3762
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:2991
float GetTransOffsetX() const
Definition: Object.h:751
void MovePositionToFirstCollision(Position &pos, float dist, float angle)
Definition: Object.cpp:3482
PhaseShift & GetPhaseShift()
Definition: Object.h:523
bool GetDistanceOrder(WorldObject const *obj1, WorldObject const *obj2, bool is3D=true) const
Definition: Object.cpp:1215
bool IsOutdoors() const
Definition: Object.h:549
int32 ModSpellDuration(SpellInfo const *spellInfo, WorldObject const *target, int32 duration, bool positive, uint32 effectMask) const
Definition: Object.cpp:2401
std::string GetNameForLocaleIdx(LocaleConstant) const override
Definition: Object.h:558
float GetTransOffsetY() const
Definition: Object.h:752
float GetTransOffsetZ() const
Definition: Object.h:753
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:2297
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition: Object.cpp:1181
virtual ObjectGuid GetTransGUID() const
Definition: Object.cpp:3748
Player * GetSpellModOwner() const
Definition: Object.cpp:2272
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition: Object.cpp:2252
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1147
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition: Object.cpp:3144
EventProcessor m_Events
Definition: Object.h:777
float GetVisibilityRange() const
Definition: Object.cpp:1447
virtual uint32 GetCastSpellXSpellVisualId(SpellInfo const *spellInfo) const
Definition: Object.cpp:3286
float GetSpellMinRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition: Object.cpp:2319
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition: Object.cpp:2621
float GetDistance(WorldObject const *obj) const
Definition: Object.cpp:1078
float GetTransOffsetO() const
Definition: Object.h:754
uint32 GetZoneId() const
Definition: Object.h:545
MovementInfo m_movementInfo
Definition: Object.h:761
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition: Object.h:547
float GetSpellMaxRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition: Object.cpp:2305
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition: Object.cpp:1142
bool IsFriendlyTo(WorldObject const *target) const
Definition: Object.cpp:2865
virtual float GetCombatReach() const
Definition: Object.h:514
void ModSpellDurationTime(SpellInfo const *spellInfo, int32 &durationTime, Spell *spell=nullptr) const
Definition: Object.cpp:2490
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:818
Optional< SpellChannelStartInterruptImmunities > InterruptImmunities
Definition: SpellPackets.h:816
WorldPacket const * Write() override
WorldPacket const * Write() override
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:931
uint32 GetVirtualRealmAddress()
Definition: World.cpp:3968
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:285
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 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:170
auto SelectRandomContainerElement(C const &container) -> typename std::add_const< decltype(*std::begin(container))>::type &
Definition: Containers.h:109
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:966
void SelectRandomInjuredTargets(std::list< WorldObject * > &targets, size_t maxTargets, bool prioritizePlayers, Unit const *prioritizeGroupMembersOf)
Definition: Spell.cpp:9306
CellCoord ComputeCellCoord(float x, float y)
Definition: GridDefines.h:206
constexpr std::size_t size()
Definition: UpdateField.h:796
uint8 ArtifactCategoryID
Definition: DB2Structure.h:202
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetCastItem(ObjectGuid const &guid, uint32 itemId, int32 itemLevel)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
AuraCreateInfo & SetOwnerEffectMask(uint32 effMask)
AuraCreateInfo & SetPeriodicReset(bool reset)
friend struct CastSpellExtraArgs
Definition: SpellDefines.h:488
CastSpellExtraArgs & SetTriggeringSpell(Spell const *triggeringSpell)
Definition: Spell.cpp:9403
ObjectGuid OriginalCastId
Definition: SpellDefines.h:484
AuraEffect const * TriggeringAura
Definition: SpellDefines.h:481
CastSpellExtraArgs & operator=(CastSpellExtraArgs const &other)
CastSpellExtraArgs & SetTriggeringAura(AuraEffect const *triggeringAura)
Definition: Spell.cpp:9414
Optional< int32 > OriginalCastItemLevel
Definition: SpellDefines.h:485
Spell const * TriggeringSpell
Definition: SpellDefines.h:480
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:875
Condition const * mLastFailedCondition
Definition: ConditionMgr.h:222
uint32 ErrorType
Definition: ConditionMgr.h:256
uint8 ConditionTarget
Definition: ConditionMgr.h:260
uint32 ErrorTextId
Definition: ConditionMgr.h:257
CreatureDifficulty const * GetDifficulty(Difficulty difficulty) const
Definition: Creature.cpp:238
bool IsTameable(bool canTameExotic, CreatureDifficulty const *creatureDifficulty) const
Definition: CreatureData.h:541
uint32 GetNoDamageImmune() const
uint32 GetRequiredSkillRank() const
Definition: ItemTemplate.h:792
uint32 GetBaseItemLevel() const
Definition: ItemTemplate.h:789
uint32 GetMaxStackSize() const
Definition: ItemTemplate.h:847
InventoryType GetInventoryType() const
Definition: ItemTemplate.h:786
uint8 GetArtifactID() const
Definition: ItemTemplate.h:824
uint32 GetItemLimitCategory() const
Definition: ItemTemplate.h:821
int32 GetBaseRequiredLevel() const
Definition: ItemTemplate.h:790
bool HasFlag(ItemFlags flag) const
Definition: ItemTemplate.h:871
uint32 GetSubClass() const
Definition: ItemTemplate.h:778
uint32 GetLockID() const
Definition: ItemTemplate.h:810
uint32 GetClass() const
Definition: ItemTemplate.h:777
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:281
bool isLooted() const
Definition: Loot.h:307
LootType loot_type
Definition: Loot.h:288
uint32 GetMovementFlags() const
Definition: MovementInfo.h:108
constexpr void SetOrientation(float orientation)
Definition: Position.h:71
constexpr float GetPositionX() const
Definition: Position.h:76
float m_positionZ
Definition: Position.h:55
constexpr float GetPositionY() const
Definition: Position.h:77
float GetExactDist2d(const float x, const float y) const
Definition: Position.h:106
float GetRelativeAngle(float x, float y) const
Definition: Position.h:136
float GetExactDist(float x, float y, float z) const
Definition: Position.h:118
float m_positionX
Definition: Position.h:53
float m_positionY
Definition: Position.h:54
bool HasInLine(Position const *pos, float objSize, float width) const
Definition: Position.cpp:118
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition: Position.cpp:99
float GetAbsoluteAngle(float x, float y) const
Definition: Position.h:125
constexpr void Relocate(float x, float y)
Definition: Position.h:63
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:110
constexpr bool IsInDist(float x, float y, float z, float dist) const
Definition: Position.h:143
void RelocateOffset(Position const &offset)
Definition: Position.cpp:34
constexpr float GetOrientation() const
Definition: Position.h:79
constexpr float GetPositionZ() const
Definition: Position.h:78
uint32 ScriptVisualID
Definition: SpellDefines.h:505
uint32 SpellXSpellVisualID
Definition: SpellDefines.h:504
void RelocateOffset(Position const &offset)
Definition: Spell.cpp:122
Position _transportOffset
Definition: SpellDefines.h:327
WorldLocation _position
Definition: SpellDefines.h:325
void Relocate(Position const &pos)
Definition: Spell.cpp:111
ObjectGuid _transportGUID
Definition: SpellDefines.h:326
std::array< uint8, MAX_ITEM_ENCHANTMENT_EFFECTS > Effect
EnumFlag< SpellItemEnchantmentFlags > GetFlags() const
Optional< std::vector< SpellLogEffectTradeSkillItemParams > > TradeSkillTargets
Definition: Spell.h:213
Optional< std::vector< SpellLogEffectFeedPetParams > > FeedPetTargets
Definition: Spell.h:214
Optional< std::vector< SpellLogEffectPowerDrainParams > > PowerDrainTargets
Definition: Spell.h:209
Optional< std::vector< SpellLogEffectDurabilityDamageParams > > DurabilityDamageTargets
Definition: Spell.h:211
Optional< std::vector< SpellLogEffectGenericVictimParams > > GenericVictimTargets
Definition: Spell.h:212
Optional< std::vector< SpellLogEffectExtraAttacksParams > > ExtraAttacksTargets
Definition: Spell.h:210
Unit * target
Definition: Unit.h:551
uint32 damage
Definition: Unit.h:556
uint32 absorb
Definition: Unit.h:559
Unit * attacker
Definition: Unit.h:552
Powers Power
Definition: SpellInfo.h:316
float RadiusMod
Definition: Spell.h:223
Optional< int32 > Duration
Definition: Spell.h:227
Optional< int32 > ParentSpellTargetIndex
Definition: Spell.h:229
int32 EffectBasePoints[MAX_SPELL_EFFECTS]
Definition: Spell.h:220
uint32 CustomBasePointsMask
Definition: Spell.h:221
uint32 MaxAffectedTargets
Definition: Spell.h:222
int32 AuraStackAmount
Definition: Spell.h:224
float CriticalChance
Definition: Spell.h:226
Optional< int32 > ParentSpellTargetCount
Definition: Spell.h:228
float DurationMul
Definition: Spell.h:225
SpellValue(SpellInfo const *proto, WorldObject const *caster)
Definition: Spell.cpp:471
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition: Spell.cpp:3086
ObjectGuid TargetGUID
Definition: Spell.h:832
uint64 TimeDelay
Definition: Spell.h:816
ObjectGuid TargetGUID
Definition: Spell.h:815
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:802
void PreprocessTarget(Spell *spell) override
Definition: Spell.cpp:2699
SpellMissInfo MissCondition
Definition: Spell.h:791
int32 AuraBasePoints[MAX_SPELL_EFFECTS]
Definition: Spell.h:800
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition: Spell.cpp:2746
void DoDamageAndTriggers(Spell *spell) override
Definition: Spell.cpp:2775
SpellMissInfo ReflectResult
Definition: Spell.h:792
bool _enablePVP
Definition: Spell.h:806
uint64 TimeDelay
Definition: Spell.h:787
ObjectGuid TargetGUID
Definition: Spell.h:786
Unit * _spellHitTarget
Definition: Spell.h:805
int32 Damage
Definition: Spell.h:788
int32 Healing
Definition: Spell.h:789
int32 AuraDuration
Definition: Spell.h:799
DiminishingGroup DRGroup
Definition: Spell.h:798
uint32 SpellID
WorldObjectSpellAreaTargetSearchReason _searchReason
Definition: Spell.h:975
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9212
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:9207
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:9248
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9252
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:9290
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9298
WorldObjectSpellNearbyTargetCheck(float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9192
bool operator()(WorldObject *target)
Definition: Spell.cpp:9196
SpellTargetCheckTypes _targetSelectionType
Definition: Spell.h:943
WorldObjectSpellTargetCheck(WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9078
std::unique_ptr< ConditionSourceInfo > _condSrcInfo
Definition: Spell.h:944
SpellInfo const * _spellInfo
Definition: Spell.h:942
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9090
ConditionContainer const * _condList
Definition: Spell.h:945
SpellTargetObjectTypes _objectType
Definition: Spell.h:946
WorldObjectSpellTrajTargetCheck(float range, Position const *position, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList, SpellTargetObjectTypes objectType)
Definition: Spell.cpp:9275
bool operator()(WorldObject *target) const
Definition: Spell.cpp:9278
std::vector< ObjectGuid > HitTargets
Definition: SpellPackets.h:363
Optional< RuneData > RemainingRunes
Definition: SpellPackets.h:369
std::vector< SpellMissStatus > MissStatus
Definition: SpellPackets.h:366
MissileTrajectoryResult MissileTrajectory
Definition: SpellPackets.h:370
std::vector< ObjectGuid > MissTargets
Definition: SpellPackets.h:364
std::vector< SpellHitStatus > HitStatus
Definition: SpellPackets.h:365
std::vector< SpellPowerData > RemainingPower
Definition: SpellPackets.h:368
MissileTrajectoryRequest MissileTrajectory
Definition: SpellPackets.h:247
Optional< TargetLocation > SrcLocation
Definition: SpellPackets.h:206
Optional< TargetLocation > DstLocation
Definition: SpellPackets.h:207