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