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"
19#include "Battlefield.h"
20#include "BattlefieldMgr.h"
21#include "Battleground.h"
22#include "CellImpl.h"
23#include "Common.h"
24#include "ConditionMgr.h"
25#include "Containers.h"
26#include "DatabaseEnv.h"
27#include "DBCStores.h"
28#include "DisableMgr.h"
29#include "DynamicObject.h"
30#include "G3DPosition.hpp"
31#include "GameObjectAI.h"
32#include "GridNotifiers.h"
33#include "GridNotifiersImpl.h"
34#include "GameTime.h"
35#include "InstanceScript.h"
36#include "Item.h"
37#include "Log.h"
38#include "LootMgr.h"
39#include "MotionMaster.h"
40#include "ObjectAccessor.h"
41#include "ObjectMgr.h"
42#include "Opcodes.h"
43#include "PathGenerator.h"
44#include "Pet.h"
45#include "Player.h"
46#include "ScriptMgr.h"
47#include "SharedDefines.h"
48#include "SpellAuraEffects.h"
49#include "SpellHistory.h"
50#include "SpellInfo.h"
51#include "SpellMgr.h"
52#include "SpellPackets.h"
53#include "SpellScript.h"
54#include "TemporarySummon.h"
55#include "TradeData.h"
56#include "Unit.h"
57#include "UpdateData.h"
58#include "UpdateMask.h"
59#include "UniqueTrackablePtr.h"
60#include "Util.h"
61#include "Vehicle.h"
62#include "VMapFactory.h"
63#include "VMapManager2.h"
64#include "World.h"
65#include "WorldPacket.h"
66#include "WorldSession.h"
67
69
76
77SpellDestination::SpellDestination(float x, float y, float z, float orientation, uint32 mapId)
78{
79 _position.Relocate(x, y, z, orientation);
81 _position.m_mapId = mapId;
82 _transportOffset.Relocate(0, 0, 0, 0);
83}
84
91
98
100{
101 if (!_transportGUID.IsEmpty())
102 {
103 Position offset;
104 _position.GetPositionOffsetTo(pos, offset);
106 }
107 _position.Relocate(pos);
108}
109
111{
112 if (!_transportGUID.IsEmpty())
114
116}
117
118SpellCastTargets::SpellCastTargets() : m_elevation(0), m_speed(0), m_strTarget()
119{
120 m_objectTarget = nullptr;
121 m_itemTarget = nullptr;
122
124
125 m_targetMask = 0;
126}
127
129
131{
132 data >> m_targetMask;
133
135 return;
136
139
142
144 {
148 else
150 }
151 else
152 {
156 else
157 m_src._position.Relocate(caster);
158 }
159
161 {
165 else
167 }
168 else
169 {
173 else
174 m_dst._position.Relocate(caster);
175 }
176
178 data >> m_strTarget;
179
180 Update(caster);
181}
182
184{
185 data.Flags = m_targetMask;
186
189
191 {
192 data.Item.emplace();
193 if (m_itemTarget)
194 data.Item = m_itemTarget->GetGUID();
195 }
196
198 {
199 data.SrcLocation.emplace();
200 data.SrcLocation->Transport = m_src._transportGUID;
202 data.SrcLocation->Location = m_src._transportOffset;
203 else
204 data.SrcLocation->Location = m_src._position;
205 }
206
208 {
209 data.DstLocation.emplace();
210 data.DstLocation->Transport = m_dst._transportGUID;
212 data.DstLocation->Location = m_dst._transportOffset;
213 else
214 data.DstLocation->Location = m_dst._position;
215 }
216
218 data.Name = m_strTarget;
219}
220
228
230{
231 if (m_objectTarget)
232 return m_objectTarget->ToUnit();
233
234 return nullptr;
235}
236
238{
239 if (!target)
240 return;
241
242 m_objectTarget = target;
243 m_objectTargetGUID = target->GetGUID();
245}
246
254
256{
257 if (m_objectTarget)
259
260 return nullptr;
261}
262
264{
265 if (!target)
266 return;
267
268 m_objectTarget = target;
269 m_objectTargetGUID = target->GetGUID();
271}
272
280
282{
283 if (m_objectTarget)
284 return m_objectTarget->ToCorpse();
285
286 return nullptr;
287}
288
293
298
305
307{
308 if (!item)
309 return;
310
311 m_itemTarget = item;
312 m_itemTargetGUID = item->GetGUID();
313 m_itemTargetEntry = item->GetEntry();
315}
316
325
334
336{
337 return &m_src;
338}
339
341{
342 return &m_src._position;
343}
344
345void SpellCastTargets::SetSrc(float x, float y, float z)
346{
347 m_src = SpellDestination(x, y, z);
349}
350
356
362
368
373
375{
376 return &m_dst;
377}
378
380{
381 return &m_dst._position;
382}
383
384void SpellCastTargets::SetDst(float x, float y, float z, float orientation, uint32 mapId)
385{
386 m_dst = SpellDestination(x, y, z, orientation, mapId);
388}
389
395
401
403{
404 m_dst = spellDest;
406}
407
409{
410 m_dst = spellTargets.m_dst;
412}
413
419
421{
423 m_dst = spellDest;
424}
425
430
432{
434}
435
437{
439}
440
442{
444
445 m_itemTarget = nullptr;
446 if (caster->GetTypeId() == TYPEID_PLAYER)
447 {
448 Player* player = caster->ToPlayer();
452 if (m_itemTargetGUID.GetRawValue() == TRADE_SLOT_NONTRADED) // here it is not guid but slot. Also prevents hacking slots
453 if (TradeData* pTrade = player->GetTradeData())
454 m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
455
456 if (m_itemTarget)
458 }
459
460 // update positions by transport move
462 {
464 {
465 m_src._position.Relocate(transport);
467 }
468 }
469
471 {
473 {
474 m_dst._position.Relocate(transport);
476 }
477 }
478}
479
481{
482 for (SpellEffectInfo const& spellEffectInfo : proto->GetEffects())
483 EffectBasePoints[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
485 RadiusMod = 1.0f;
486 AuraStackAmount = 1;
487 CriticalChance = 0.0f;
488}
489
491{
492public:
493 explicit SpellEvent(Spell* spell);
494 ~SpellEvent();
495
496 bool Execute(uint64 e_time, uint32 p_time) override;
497 void Abort(uint64 e_time) override;
498 bool IsDeletable() const override;
499 Spell const* GetSpell() const { return m_Spell.get(); }
501
502 std::string GetDebugInfo() const { return m_Spell->GetDebugInfo(); }
503
504protected:
506};
507
508Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID) :
509m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
510m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
511, m_spellValue(new SpellValue(m_spellInfo)), _spellEvent(nullptr)
512{
514 m_fromClient = false;
515 m_selfContainer = nullptr;
517 m_executedCurrently = false;
519 m_comboTarget = nullptr;
521 m_delayStart = 0;
523
525 m_auraScaleMask = 0;
526 memset(m_damageMultipliers, 0, sizeof(m_damageMultipliers));
527
528 // Get data for type of attack
529 m_attackType = info->GetAttackType();
530
531 m_spellSchoolMask = info->GetSchoolMask(); // Can be override for some spell (wand shoot for example)
532
533 if (Player const* playerCaster = m_caster->ToPlayer())
534 {
535 // wand case
537 if ((playerCaster->GetClassMask() & CLASSMASK_WAND_USERS) != 0)
538 if (Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK))
539 m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->Damage[0].DamageType);
540 }
541
542 if (!originalCasterGUID.IsEmpty())
543 m_originalCasterGUID = originalCasterGUID;
544 else
546
549 else
550 {
553 m_originalCaster = nullptr;
554 }
555
557 _triggeredCastFlags = triggerFlags;
560
561 m_CastItem = nullptr;
563 m_castItemEntry = 0;
564
565 unitTarget = nullptr;
566 itemTarget = nullptr;
567 gameObjTarget = nullptr;
568 m_corpseTarget = nullptr;
569 destTarget = nullptr;
570 damage = 0;
573 effectInfo = nullptr;
574 m_damage = 0;
575 m_healing = 0;
576 m_procAttacker = 0;
577 m_procVictim = 0;
578 m_hitMask = 0;
579 focusObject = nullptr;
580 m_cast_count = 0;
581 m_glyphIndex = 0;
582 m_triggeredByAuraSpell = nullptr;
583 _spellAura = nullptr;
584 _dynObjAura = nullptr;
585
586 //Auto Shot & Shoot (wand)
588
589 m_runesState = 0;
590 m_powerCost = 0; // setup to correct value in Spell::prepare, must not be used before.
591 m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before.
592 m_timer = 0; // will set to castime in prepare
593 m_channeledDuration = 0; // will be setup in Spell::handle_immediate
594 m_immediateHandled = false;
595
597
598 // Determine if spell can be reflected back to the caster
599 // Patch 1.2 notes: Spell Reflection no longer reflects abilities
600 m_canReflect = caster->IsUnit()
603 && !m_spellInfo->IsPassive();
604
606 memset(m_effectExecuteData, 0, MAX_SPELL_EFFECTS * sizeof(ByteBuffer*));
607
608 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
610}
611
613{
614 // unload scripts
615 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
616 {
617 (*itr)->_Unload();
618 delete (*itr);
619 }
620
622 {
623 // Clean the reference to avoid later crash.
624 // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
625 TC_LOG_ERROR("spells", "SPELL: deleting spell for spell ID {}. However, spell still referenced.", m_spellInfo->Id);
626 *m_selfContainer = nullptr;
627 }
628
631
632 delete m_spellValue;
633
634 // missing cleanup somewhere, mem leaks so let's crash
636}
637
639{
640 m_targets = targets;
641
642 // this function tries to correct spell explicit targets for spell
643 // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
644 // this also makes sure that we correctly send explicit targets to client (removes redundant data)
645 uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
646
647 if (WorldObject* target = m_targets.GetObjectTarget())
648 {
649 // check if object target is valid with needed target flags
650 // for unit case allow corpse target mask because player with not released corpse is a unit target
651 if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)))
652 || (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
653 || (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK)))
655 }
656 else
657 {
658 // try to select correct unit target if not provided by client or by serverside cast
659 if (neededTargets & (TARGET_FLAG_UNIT_MASK))
660 {
661 Unit* unit = nullptr;
662 // try to use player selection as a target
663 if (Player* playerCaster = m_caster->ToPlayer())
664 {
665 // selection has to be found and to be valid target for the spell
666 if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget()))
668 unit = selectedUnit;
669 }
670 // try to use attacked unit as a target
671 else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
672 unit = m_caster->ToCreature()->GetVictim();
673
674 // didn't find anything - let's use self as target
676 unit = m_caster->ToUnit();
677
679 }
680 }
681
682 // check if spell needs dst target
683 if (neededTargets & TARGET_FLAG_DEST_LOCATION)
684 {
685 // and target isn't set
686 if (!m_targets.HasDst())
687 {
688 // try to use unit target if provided
689 if (WorldObject* target = targets.GetObjectTarget())
690 m_targets.SetDst(*target);
691 // or use self if not available
692 else
694 }
695 }
696 else
698
699 if (neededTargets & TARGET_FLAG_SOURCE_LOCATION)
700 {
701 if (!targets.HasSrc())
703 }
704 else
706}
707
709{
710 // here go all explicit target changes made to explicit targets after spell prepare phase is finished
711 if (Unit* target = m_targets.GetUnitTarget())
712 {
713 // check for explicit target redirection, for Grounding Totem for example
716 {
717 Unit* redirect = nullptr;
718 switch (m_spellInfo->DmgClass)
719 {
722 break;
725 // should gameobjects cast damagetype melee/ranged spells this needs to be changed
727 break;
728 default:
729 break;
730 }
731 if (redirect && (redirect != target))
732 m_targets.SetUnitTarget(redirect);
733 }
734 }
735}
736
738{
739 // select targets for cast phase
741
742 uint32 processedEffectsMaskForSpell = 0;
743 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
744 {
745 // not call for empty effect.
746 // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
747 if (!spellEffectInfo.IsEffect())
748 continue;
749
750 // set expected type of implicit targets to be sent to client
751 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
752 if (implicitTargetMask & TARGET_FLAG_UNIT)
754 if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
756
757 uint32 implicitTargetEffectMaskToSelect = [&]
758 {
759 uint32 effectMask = 1u << spellEffectInfo.EffectIndex;
760 // set the same target list for all effects
761 // some spells appear to need this, however this requires more research
762 std::array<SpellEffectInfo, MAX_SPELL_EFFECTS> const& effects = GetSpellInfo()->GetEffects();
763 // choose which targets we can select at once
764 for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j)
765 {
766 if (effects[j].IsEffect() &&
767 spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
768 spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
769 spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
770 CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, j))
771 {
772 auto shouldCheckRadius = [](SpellImplicitTargetInfo const& targetInfo)
773 {
774 switch (targetInfo.GetSelectionCategory())
775 {
779 return true;
780 default:
781 break;
782 }
783 return false;
784 };
785
786 if (shouldCheckRadius(spellEffectInfo.TargetA) || shouldCheckRadius(spellEffectInfo.TargetB))
787 if (spellEffectInfo.CalcRadius(m_caster) != effects[j].CalcRadius(m_caster))
788 continue;
789
790 effectMask |= 1 << j;
791 }
792 }
793
794 return effectMask;
795 }();
796
797 implicitTargetEffectMaskToSelect &= ~processedEffectsMaskForSpell;
798 if (implicitTargetEffectMaskToSelect)
799 {
800 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, implicitTargetEffectMaskToSelect);
801 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, implicitTargetEffectMaskToSelect);
802 processedEffectsMaskForSpell |= implicitTargetEffectMaskToSelect;
803 }
804
805 // Select targets of effect based on effect type
806 // those are used when no valid target could be added for spell effect based on spell target type
807 // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
808 // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
809 // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
810 SelectEffectTypeImplicitTargets(spellEffectInfo);
811
812 if (m_targets.HasDst())
813 AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex);
814
815 if (implicitTargetEffectMaskToSelect
816 && (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
817 || spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST
818 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
819 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST))
820 {
822 {
823 bool noTargetFound = std::ranges::none_of(m_UniqueTargetInfo, [implicitTargetEffectMaskToSelect](TargetInfo const& target)
824 {
825 return target.EffectMask & implicitTargetEffectMaskToSelect;
826 });
827
828 if (noTargetFound)
829 {
831 finish(false);
832 return;
833 }
834 }
836 {
837 bool anyNonImmuneTargetFound = std::ranges::any_of(m_UniqueTargetInfo, [implicitTargetEffectMaskToSelect](TargetInfo const& target)
838 {
839 return target.EffectMask & implicitTargetEffectMaskToSelect && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2;
840 });
841
842 if (!anyNonImmuneTargetFound)
843 {
845 finish(false);
846 return;
847 }
848 }
849 }
850
852 {
853 // maybe do this for all spells?
854 if (!focusObject && m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst())
855 {
857 finish(false);
858 return;
859 }
860
861 uint8 mask = (1 << spellEffectInfo.EffectIndex);
862 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
863 {
864 if (ihit->EffectMask & mask)
865 {
867 break;
868 }
869 }
870 }
871 else if (m_auraScaleMask)
872 {
873 bool checkLvl = !m_UniqueTargetInfo.empty();
874 m_UniqueTargetInfo.erase(std::remove_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [&](TargetInfo const& targetInfo) -> bool
875 {
876 // remove targets which did not pass min level check
877 if (m_auraScaleMask && targetInfo.EffectMask == m_auraScaleMask)
878 {
879 // Do not check for selfcast
880 if (!targetInfo.ScaleAura && targetInfo.TargetGUID != m_caster->GetGUID())
881 return true;
882 }
883
884 return false;
885 }), std::end(m_UniqueTargetInfo));
886
887 if (checkLvl && m_UniqueTargetInfo.empty())
888 {
890 finish(false);
891 }
892 }
893 }
894
895 if (uint64 dstDelay = CalculateDelayMomentForDst())
896 m_delayMoment = dstDelay;
897}
898
900{
901 if (m_targets.HasDst())
902 {
903 if (m_targets.HasTraj())
904 {
905 float speed = m_targets.GetSpeedXY();
906 if (speed > 0.0f)
907 return uint64(std::floor(m_targets.GetDist2d() / speed * 1000.0f));
908 }
909 else if (m_spellInfo->Speed > 0.0f)
910 {
911 // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP)
912 float dist = m_caster->GetExactDist(*m_targets.GetDstPos());
913 return uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
914 }
915 }
916
917 return 0;
918}
919
925
926void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effectMask)
927{
928 if (!targetType.GetTarget())
929 return;
930
931 switch (targetType.GetSelectionCategory())
932 {
934 SelectImplicitChannelTargets(spellEffectInfo, targetType, effectMask);
935 break;
937 SelectImplicitNearbyTargets(spellEffectInfo, targetType, effectMask);
938 break;
940 SelectImplicitConeTargets(spellEffectInfo, targetType, effectMask);
941 break;
943 SelectImplicitAreaTargets(spellEffectInfo, targetType, effectMask);
944 break;
946 // just in case there is no dest, explanation in SelectImplicitDestDestTargets
947 CheckDst();
948
949 SelectImplicitTrajTargets(spellEffectInfo, targetType);
950 break;
952 switch (targetType.GetObjectType())
953 {
955 switch (targetType.GetReferenceType())
956 {
959 break;
960 default:
961 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
962 break;
963 }
964 break;
966 switch (targetType.GetReferenceType())
967 {
969 SelectImplicitCasterDestTargets(spellEffectInfo, targetType);
970 break;
972 SelectImplicitTargetDestTargets(spellEffectInfo, targetType);
973 break;
975 SelectImplicitDestDestTargets(spellEffectInfo, targetType);
976 break;
977 default:
978 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
979 break;
980 }
981 break;
982 default:
983 switch (targetType.GetReferenceType())
984 {
986 SelectImplicitCasterObjectTargets(spellEffectInfo, targetType, effectMask);
987 break;
989 SelectImplicitTargetObjectTargets(spellEffectInfo, targetType, effectMask);
990 break;
991 default:
992 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
993 break;
994 }
995 break;
996 }
997 break;
999 TC_LOG_DEBUG("spells", "SPELL: target type {}, found in spellID {}, effect {} is not implemented yet!", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex), targetType.GetTarget());
1000 break;
1001 default:
1002 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target category");
1003 break;
1004 }
1005}
1006
1007void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1008{
1010 {
1011 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target reference type");
1012 return;
1013 }
1014
1016 if (!channeledSpell)
1017 {
1018 TC_LOG_DEBUG("spells", "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1019 return;
1020 }
1021 switch (targetType.GetTarget())
1022 {
1024 {
1026 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1027 // unit target may be no longer avalible - teleported out of map for example
1028 if (target && target->ToUnit())
1029 AddUnitTarget(target->ToUnit(), effMask);
1030 else
1031 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1032 break;
1033 }
1035 if (channeledSpell->m_targets.HasDst())
1036 m_targets.SetDst(channeledSpell->m_targets);
1038 {
1039 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1040 if (target)
1041 {
1042 SpellDestination dest(*target);
1043 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1044 m_targets.SetDst(dest);
1045 }
1046 }
1047 else
1048 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1049 break;
1051 {
1052 SpellDestination dest(*channeledSpell->GetCaster());
1053 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1054 m_targets.SetDst(dest);
1055 break;
1056 }
1057 default:
1058 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
1059 break;
1060 }
1061}
1062
1063void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1064{
1066 {
1067 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
1068 return;
1069 }
1070
1071 float range = 0.0f;
1072 switch (targetType.GetCheckType())
1073 {
1074 case TARGET_CHECK_ENEMY:
1075 range = m_spellInfo->GetMaxRange(false, m_caster, this);
1076 break;
1077 case TARGET_CHECK_ALLY:
1078 case TARGET_CHECK_PARTY:
1079 case TARGET_CHECK_RAID:
1081 range = m_spellInfo->GetMaxRange(true, m_caster, this);
1082 break;
1083 case TARGET_CHECK_ENTRY:
1085 range = m_spellInfo->GetMaxRange(IsPositive(), m_caster, this);
1086 break;
1087 default:
1088 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
1089 break;
1090 }
1091
1092 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
1093
1094 // handle emergency case - try to use other provided targets if no conditions provided
1095 if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
1096 {
1097 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));
1098 switch (targetType.GetObjectType())
1099 {
1102 {
1103 if (focusObject)
1104 AddGOTarget(focusObject, effMask);
1105 else
1106 {
1108 finish(false);
1109 }
1110 return;
1111 }
1112 break;
1115 {
1116 if (focusObject)
1117 {
1119 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1120 m_targets.SetDst(dest);
1121 }
1122 else
1123 {
1125 finish(false);
1126 }
1127 return;
1128 }
1129 break;
1130 default:
1131 break;
1132 }
1133 }
1134
1135 WorldObject* target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
1136 if (!target)
1137 {
1138 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1140 finish(false);
1141 return;
1142 }
1143
1144 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1145 if (!target)
1146 {
1147 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set NULL target, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1149 finish(false);
1150 return;
1151 }
1152
1153 switch (targetType.GetObjectType())
1154 {
1156 if (Unit* unit = target->ToUnit())
1157 AddUnitTarget(unit, effMask, true, false);
1158 else
1159 {
1160 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);
1162 finish(false);
1163 return;
1164 }
1165 break;
1167 if (GameObject* gobjTarget = target->ToGameObject())
1168 AddGOTarget(gobjTarget, effMask);
1169 else
1170 {
1171 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);
1173 finish(false);
1174 return;
1175 }
1176 break;
1178 if (Corpse* corpseTarget = target->ToCorpse())
1179 AddCorpseTarget(corpseTarget, effMask);
1180 else
1181 {
1182 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);
1184 finish(false);
1185 return;
1186 }
1187 break;
1189 {
1190 SpellDestination dest(*target);
1191 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1192 m_targets.SetDst(dest);
1193 break;
1194 }
1195 default:
1196 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target object type");
1197 break;
1198 }
1199
1200 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1201}
1202
1203void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1204{
1206 {
1207 ABORT_MSG("Spell::SelectImplicitConeTargets: received not implemented target reference type");
1208 return;
1209 }
1210 std::list<WorldObject*> targets;
1211 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1212 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1213 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
1214 float coneAngle = float(M_PI) / 2.f;
1215
1216 float radius = spellEffectInfo.CalcRadius(m_caster);
1217 // Workaround for some spells that don't have RadiusEntry set in dbc (but SpellRange instead)
1218 if (G3D::fuzzyEq(radius, 0.f))
1219 radius = m_spellInfo->GetMaxRange(m_spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex), m_caster, this);
1220
1221 radius *= m_spellValue->RadiusMod;
1222
1223 if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
1224 {
1225 float extraSearchRadius = radius > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1226 Trinity::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList);
1228 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius + extraSearchRadius);
1229
1230 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1231
1232 if (!targets.empty())
1233 {
1234 // Other special target selection goes here
1235 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1236 {
1237 if (Unit* unitCaster = m_caster->ToUnit())
1238 maxTargets += unitCaster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
1239 Trinity::Containers::RandomResize(targets, maxTargets);
1240 }
1241
1242 for (WorldObject* itr : targets)
1243 {
1244 if (Unit* unit = itr->ToUnit())
1245 AddUnitTarget(unit, effMask, false);
1246 else if (GameObject* gObjTarget = itr->ToGameObject())
1247 AddGOTarget(gObjTarget, effMask);
1248 else if (Corpse* corpse = itr->ToCorpse())
1249 AddCorpseTarget(corpse, effMask);
1250 }
1251 }
1252 }
1253}
1254
1255void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1256{
1257 WorldObject* referer = nullptr;
1258 switch (targetType.GetReferenceType())
1259 {
1263 referer = m_caster;
1264 break;
1266 referer = m_targets.GetUnitTarget();
1267 break;
1269 {
1270 // find last added target for this effect
1271 for (auto ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
1272 {
1273 if (ihit->EffectMask & (1 << spellEffectInfo.EffectIndex))
1274 {
1275 referer = ObjectAccessor::GetUnit(*m_caster, ihit->TargetGUID);
1276 break;
1277 }
1278 }
1279 break;
1280 }
1281 default:
1282 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1283 return;
1284 }
1285 if (!referer)
1286 return;
1287
1288 Position const* center = nullptr;
1289 switch (targetType.GetReferenceType())
1290 {
1292 center = m_targets.GetSrcPos();
1293 break;
1295 center = m_targets.GetDstPos();
1296 break;
1300 center = referer;
1301 break;
1302 default:
1303 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1304 return;
1305 }
1306 std::list<WorldObject*> targets;
1307 float radius = spellEffectInfo.CalcRadius(m_caster);
1308 // Workaround for some spells that don't have RadiusEntry set in dbc (but SpellRange instead)
1309 if (G3D::fuzzyEq(radius, 0.f))
1310 radius = m_spellInfo->GetMaxRange(m_spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex), m_caster, this);
1311
1312 radius *= m_spellValue->RadiusMod;
1313
1314 SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
1315
1316 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1317
1318 if (!targets.empty())
1319 {
1320 // Other special target selection goes here
1321 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1322 {
1323 if (Unit* unitCaster = m_caster->ToUnit())
1324 maxTargets += unitCaster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
1325 Trinity::Containers::RandomResize(targets, maxTargets);
1326 }
1327
1328 for (WorldObject* itr : targets)
1329 {
1330 if (Unit* unit = itr->ToUnit())
1331 AddUnitTarget(unit, effMask, false, true, center);
1332 else if (GameObject* gObjTarget = itr->ToGameObject())
1333 AddGOTarget(gObjTarget, effMask);
1334 else if (Corpse* corpse = itr->ToCorpse())
1335 AddCorpseTarget(corpse, effMask);
1336 }
1337 }
1338}
1339
1341{
1343
1344 switch (targetType.GetTarget())
1345 {
1346 case TARGET_DEST_CASTER:
1347 break;
1348 case TARGET_DEST_HOME:
1349 if (Player* playerCaster = m_caster->ToPlayer())
1350 dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId);
1351 break;
1352 case TARGET_DEST_DB:
1353 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1354 {
1357 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
1358 else if (st->target_mapId == m_caster->GetMapId())
1359 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
1360 }
1361 else
1362 {
1363 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1364 if (WorldObject* target = m_targets.GetObjectTarget())
1365 dest = SpellDestination(*target);
1366 }
1367 break;
1369 {
1370 float minDist = m_spellInfo->GetMinRange(true);
1371 float maxDist = m_spellInfo->GetMaxRange(true);
1372 float dist = frand(minDist, maxDist);
1373 float x, y, z;
1374 float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
1376
1377 float ground = m_caster->GetMapHeight(x, y, z);
1378 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
1379 LiquidData liquidData;
1380 if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseMask(), x, y, z, {}, &liquidData, m_caster->GetCollisionHeight()))
1381 liquidLevel = liquidData.level;
1382
1383 if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
1384 {
1387 finish(false);
1388 return;
1389 }
1390
1391 if (ground + 0.75 > liquidLevel)
1392 {
1395 finish(false);
1396 return;
1397 }
1398
1399 dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation());
1400 break;
1401 }
1403 {
1404 Unit* unitCaster = m_caster->ToUnit();
1405 if (!unitCaster)
1406 break;
1407
1408 float dist = spellEffectInfo.CalcRadius(unitCaster);
1409 float angle = targetType.CalcDirectionAngle();
1410
1411 Position pos = dest._position;
1412
1413 unitCaster->MovePositionToFirstCollision(pos, dist, angle);
1414 dest.Relocate(pos);
1415 break;
1416 }
1417 default:
1418 {
1419 float dist = spellEffectInfo.CalcRadius(m_caster);
1420 float angle = targetType.CalcDirectionAngle();
1421 float objSize = m_caster->GetCombatReach();
1422
1423 switch (targetType.GetTarget())
1424 {
1426 dist = PET_FOLLOW_DIST;
1427 break;
1429 if (dist > objSize)
1430 dist = objSize + (dist - objSize) * float(rand_norm());
1431 break;
1436 {
1437 static float const DefaultTotemDistance = 3.0f;
1438 if (!spellEffectInfo.HasRadius())
1439 dist = DefaultTotemDistance;
1440 break;
1441 }
1442 default:
1443 break;
1444 }
1445
1446 if (dist < objSize)
1447 dist = objSize;
1448
1449 Position pos = dest._position;
1450 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1451
1452 dest.Relocate(pos);
1453 break;
1454 }
1455 }
1456
1457 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1458 m_targets.SetDst(dest);
1459}
1460
1462{
1463 ASSERT(m_targets.GetObjectTarget() && "Spell::SelectImplicitTargetDestTargets - no explicit object target available!");
1465
1466 SpellDestination dest(*target);
1467
1468 switch (targetType.GetTarget())
1469 {
1472 break;
1473 default:
1474 {
1475 float angle = targetType.CalcDirectionAngle();
1476 float dist = spellEffectInfo.CalcRadius(nullptr);
1477 if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM)
1478 dist *= float(rand_norm());
1479
1480 Position pos = dest._position;
1481 target->MovePositionToFirstCollision(pos, dist, angle);
1482
1483 dest.Relocate(pos);
1484 break;
1485 }
1486 }
1487
1488 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1489 m_targets.SetDst(dest);
1490}
1491
1493{
1494 // set destination to caster if no dest provided
1495 // can only happen if previous destination target could not be set for some reason
1496 // (not found nearby target, or channel target for example
1497 // maybe we should abort the spell in such case?
1498 CheckDst();
1499
1501
1502 switch (targetType.GetTarget())
1503 {
1507 case TARGET_DEST_DEST:
1508 return;
1509 default:
1510 {
1511 float angle = targetType.CalcDirectionAngle();
1512 float dist = spellEffectInfo.CalcRadius(m_caster);
1513 if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM)
1514 dist *= float(rand_norm());
1515
1516 Position pos = dest._position;
1517 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1518
1519 dest.Relocate(pos);
1520 break;
1521 }
1522 }
1523
1524 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1525 m_targets.ModDst(dest);
1526}
1527
1528void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1529{
1530 WorldObject* target = nullptr;
1531 bool checkIfValid = true;
1532
1533 switch (targetType.GetTarget())
1534 {
1535 case TARGET_UNIT_CASTER:
1536 target = m_caster;
1537 checkIfValid = false;
1538 break;
1539 case TARGET_UNIT_MASTER:
1540 target = m_caster->GetCharmerOrOwner();
1541 break;
1542 case TARGET_UNIT_PET:
1543 if (Unit* unitCaster = m_caster->ToUnit())
1544 target = unitCaster->GetGuardianPet();
1545 break;
1547 if (Unit* unitCaster = m_caster->ToUnit())
1548 if (unitCaster->IsSummon())
1549 target = unitCaster->ToTempSummon()->GetSummonerUnit();
1550 break;
1552 if (Unit* unitCaster = m_caster->ToUnit())
1553 target = unitCaster->GetVehicleBase();
1554 break;
1563 if (Creature* vehicleBase = m_caster->ToCreature())
1564 if (vehicleBase->IsVehicle())
1565 target = vehicleBase->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
1566 break;
1567 default:
1568 break;
1569 }
1570
1571 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1572
1573 if (target)
1574 {
1575 if (Unit* unit = target->ToUnit())
1576 AddUnitTarget(unit, effMask, checkIfValid);
1577 else if (GameObject* go = target->ToGameObject())
1578 AddGOTarget(go, effMask);
1579 }
1580}
1581
1582void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1583{
1584 ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!");
1585
1587
1588 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1589
1590 if (target)
1591 {
1592 if (Unit* unit = target->ToUnit())
1593 AddUnitTarget(unit, effMask, true, false);
1594 else if (GameObject* gobj = target->ToGameObject())
1595 AddGOTarget(gobj, effMask);
1596 else if (Corpse* corpse = target->ToCorpse())
1597 AddCorpseTarget(corpse, effMask);
1598
1599 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1600 }
1601 // Script hook can remove object target and we would wrongly land here
1602 else if (Item* item = m_targets.GetItemTarget())
1603 AddItemTarget(item, effMask);
1604}
1605
1606void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask)
1607{
1608 uint32 maxTargets = spellEffectInfo.ChainTargets;
1609 if (Player* modOwner = m_caster->GetSpellModOwner())
1610 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
1611
1612 if (maxTargets > 1)
1613 {
1614 // mark damage multipliers as used
1615 for (size_t k = spellEffectInfo.EffectIndex; k < m_spellInfo->GetEffects().size(); ++k)
1616 if (effMask & (1 << k))
1617 m_damageMultipliers[k] = 1.0f;
1618 m_applyMultiplierMask |= effMask;
1619
1620 std::list<WorldObject*> targets;
1621 SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
1622 , spellEffectInfo.ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
1623
1624 // Chain primary target is added earlier
1625 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1626
1627 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
1628 if (Unit* unit = (*itr)->ToUnit())
1629 AddUnitTarget(unit, effMask, false);
1630 }
1631}
1632
1633float tangent(float x)
1634{
1635 x = std::tan(x);
1636 //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
1637 //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
1638 //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
1639 if (x < 100000.0f && x > -100000.0f) return x;
1640 if (x >= 100000.0f) return 100000.0f;
1641 if (x <= 100000.0f) return -100000.0f;
1642 return 0.0f;
1643}
1644
1645void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType)
1646{
1647 if (!m_targets.HasTraj())
1648 return;
1649
1650 float dist2d = m_targets.GetDist2d();
1651 if (!dist2d)
1652 return;
1653
1654 Position srcPos = *m_targets.GetSrcPos();
1656 float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
1657
1658 std::list<WorldObject*> targets;
1659 Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
1661 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
1662 if (targets.empty())
1663 return;
1664
1666
1667 float b = tangent(m_targets.GetElevation());
1668 float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
1669 if (a > -0.0001f)
1670 a = 0.f;
1671
1672 // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
1673 // limit max range to 300 yards, sometimes triggered spells can have 50000yds
1674 float bestDist = m_spellInfo->GetMaxRange(false);
1675 if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell))
1676 bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
1677
1678 // GameObjects don't cast traj
1679 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
1680 for (auto itr = targets.begin(); itr != targets.end(); ++itr)
1681 {
1682 if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
1683 continue;
1684
1685 if (Unit* unit = (*itr)->ToUnit())
1686 {
1687 if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
1688 continue;
1689
1690 if (Creature* creatureTarget = unit->ToCreature())
1691 {
1692 if (!(creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES))
1693 continue;
1694 }
1695 }
1696
1697 float const size = std::max((*itr)->GetCombatReach(), 1.0f);
1698 float const objDist2d = srcPos.GetExactDist2d(*itr);
1699 float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
1700
1701 float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
1702 float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
1703 float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
1704 float const height = distToHitPoint * (a * distToHitPoint + b);
1705
1706 if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
1707 continue;
1708
1709 if (distToHitPoint < bestDist)
1710 {
1711 bestDist = distToHitPoint;
1712 break;
1713 }
1714 }
1715
1716 if (dist2d > bestDist)
1717 {
1718 float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
1719 float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
1720 float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
1721
1722 SpellDestination dest(x, y, z, unitCaster->GetOrientation());
1723 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1724 m_targets.ModDst(dest);
1725 }
1726}
1727
1729{
1730 // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER, queue them on map for later execution
1731 switch (spellEffectInfo.Effect)
1732 {
1736 {
1739
1740 // scripts may modify the target - recheck
1741 if (target && target->GetTypeId() == TYPEID_PLAYER)
1742 {
1743 // target is not stored in target map for those spells
1744 // since we're completely skipping AddUnitTarget logic, we need to check immunity manually
1745 // eg. aura 21546 makes target immune to summons
1746 Player* player = target->ToPlayer();
1747 if (player->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, nullptr))
1748 return;
1749
1750 target->GetMap()->AddFarSpellCallback([spell = this, &spellEffectInfo, targetGuid = target->GetGUID()](Map* map)
1751 {
1752 Player* player = ObjectAccessor::GetPlayer(map, targetGuid);
1753 if (!player)
1754 return;
1755
1756 // check immunity again in case it changed during update
1757 if (player->IsImmunedToSpellEffect(spell->GetSpellInfo(), spellEffectInfo, nullptr))
1758 return;
1759
1760 spell->HandleEffects(player, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
1761 });
1762 }
1763 }
1764 return;
1765 default:
1766 break;
1767 }
1768
1769 // select spell implicit targets based on effect type
1770 if (!spellEffectInfo.GetImplicitTargetType())
1771 return;
1772
1773 uint32 targetMask = spellEffectInfo.GetMissingTargetMask();
1774
1775 if (!targetMask)
1776 return;
1777
1778 WorldObject* target = nullptr;
1779
1780 switch (spellEffectInfo.GetImplicitTargetType())
1781 {
1782 // add explicit object target or self to the target map
1784 // player which not released his spirit is Unit, but target flag for it is TARGET_FLAG_CORPSE_MASK
1786 {
1787 if (Unit* unit = m_targets.GetUnitTarget())
1788 target = unit;
1789 else if (targetMask & TARGET_FLAG_CORPSE_MASK)
1790 {
1791 if (Corpse* corpseTarget = m_targets.GetCorpseTarget())
1792 target = corpseTarget;
1793 }
1794 else //if (targetMask & TARGET_FLAG_UNIT_MASK)
1795 target = m_caster;
1796 }
1797 if (targetMask & TARGET_FLAG_ITEM_MASK)
1798 {
1799 if (Item* item = m_targets.GetItemTarget())
1800 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
1801 return;
1802 }
1803 if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK)
1804 target = m_targets.GetGOTarget();
1805 break;
1806 // add self to the target map
1808 if (targetMask & TARGET_FLAG_UNIT_MASK)
1809 target = m_caster;
1810 break;
1811 default:
1812 break;
1813 }
1814
1816
1817 if (target)
1818 {
1819 if (target->ToUnit())
1820 AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex, false);
1821 else if (target->ToGameObject())
1822 AddGOTarget(target->ToGameObject(), 1 << spellEffectInfo.EffectIndex);
1823 else if (target->ToCorpse())
1824 AddCorpseTarget(target->ToCorpse(), 1 << spellEffectInfo.EffectIndex);
1825 }
1826}
1827
1829{
1830 // this function selects which containers need to be searched for spell target
1832
1833 // filter searchers based on searched object type
1834 switch (objType)
1835 {
1839 break;
1844 break;
1848 break;
1849 default:
1850 break;
1851 }
1852
1856 retMask &= GRID_MAP_TYPE_MASK_PLAYER;
1857
1858 if (condList)
1859 retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
1860 return retMask;
1861}
1862
1863template<class SEARCHER>
1864void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius)
1865{
1866 if (!containerMask)
1867 return;
1868
1869 // search world and grid for possible targets
1870 bool searchInGrid = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT)) != 0;
1871 bool searchInWorld = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE)) != 0;
1872 if (searchInGrid || searchInWorld)
1873 {
1874 float x, y;
1875 x = pos->GetPositionX();
1876 y = pos->GetPositionY();
1877
1878 Map* map = referer->GetMap();
1879
1880 if (searchInWorld)
1881 Cell::VisitWorldObjects(x, y, map, searcher, radius);
1882
1883 if (searchInGrid)
1884 Cell::VisitGridObjects(x, y, map, searcher, radius);
1885 }
1886}
1887
1889{
1890 WorldObject* target = nullptr;
1891 uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
1892 if (!containerTypeMask)
1893 return nullptr;
1894
1895 Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList);
1898 SearchTargets<Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, range);
1899 return target;
1900}
1901
1902void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
1903{
1904 uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
1905 if (!containerTypeMask)
1906 return;
1907
1908 float extraSearchRadius = range > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1909 Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList);
1912 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(searcher, containerTypeMask, m_caster, position, range + extraSearchRadius);
1913}
1914
1915void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer* condList, bool isChainHeal)
1916{
1917 // max dist for jump target selection
1918 float jumpRadius = 0.0f;
1919 switch (m_spellInfo->DmgClass)
1920 {
1922 // 7.5y for multi shot
1923 jumpRadius = 7.5f;
1924 break;
1926 // 5y for swipe, cleave and similar
1927 jumpRadius = 5.0f;
1928 break;
1931 // 12.5y for chain heal spell since 3.2 patch
1932 if (isChainHeal)
1933 jumpRadius = 12.5f;
1934 // 10y as default for magic chain spells
1935 else
1936 jumpRadius = 10.0f;
1937 break;
1938 }
1939
1940 // chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
1944
1945 // max dist which spell can reach
1946 float searchRadius = jumpRadius;
1947 if (isBouncingFar)
1948 searchRadius *= chainTargets;
1949
1950 std::list<WorldObject*> tempTargets;
1951 SearchAreaTargets(tempTargets, searchRadius, target, m_caster, objectType, selectType, condList);
1952 tempTargets.remove(target);
1953
1954 // remove targets which are always invalid for chain spells
1955 // for some spells allow only chain targets in front of caster (swipe for example)
1956 if (!isBouncingFar)
1957 {
1958 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end();)
1959 {
1960 std::list<WorldObject*>::iterator checkItr = itr++;
1961 if (!m_caster->HasInArc(static_cast<float>(M_PI), *checkItr))
1962 tempTargets.erase(checkItr);
1963 }
1964 }
1965
1966 while (chainTargets)
1967 {
1968 // try to get unit for next chain jump
1969 std::list<WorldObject*>::iterator foundItr = tempTargets.end();
1970 // get unit with highest hp deficit in dist
1971 if (isChainHeal)
1972 {
1973 uint32 maxHPDeficit = 0;
1974 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
1975 {
1976 if (Unit* unit = (*itr)->ToUnit())
1977 {
1978 uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
1979 if (deficit > maxHPDeficit && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
1980 {
1981 foundItr = itr;
1982 maxHPDeficit = deficit;
1983 }
1984 }
1985 }
1986 }
1987 // get closest object
1988 else
1989 {
1990 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
1991 {
1992 if (foundItr == tempTargets.end())
1993 {
1994 if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
1995 foundItr = itr;
1996 }
1997 else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
1998 foundItr = itr;
1999 }
2000 }
2001 // not found any valid target - chain ends
2002 if (foundItr == tempTargets.end())
2003 break;
2004 target = *foundItr;
2005 tempTargets.erase(foundItr);
2006 targets.push_back(target);
2007 --chainTargets;
2008 }
2009}
2010
2019
2021{
2022 //==========================================================================================
2023 // Now fill data for trigger system, need know:
2024 // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
2025 //==========================================================================================
2026
2028 // Get data for type of attack and fill base info for trigger
2029 switch (m_spellInfo->DmgClass)
2030 {
2033 if (m_attackType == OFF_ATTACK)
2035 else
2038 break;
2040 // Auto attack
2042 {
2045 }
2046 else // Ranged spell attack
2047 {
2050 }
2051 break;
2052 default:
2055 && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
2056 {
2059 }
2060 // For other spells trigger procflags are set in Spell::TargetInfo::DoDamageAndTriggers
2061 // Because spell positivity is dependant on target
2062 }
2063
2064 // Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
2066 (m_spellInfo->SpellFamilyFlags[0] & 0x18 || // Freezing and Frost Trap, Freezing Arrow
2067 m_spellInfo->Id == 57879 || // Snake Trap - done this way to avoid double proc
2068 m_spellInfo->SpellFamilyFlags[2] & 0x00024000)) // Explosive and Immolation Trap
2069 {
2071
2072 // also fill up other flags (TargetInfo::DoDamageAndTriggers only fills up flag if both are not set)
2075 }
2076
2077 // Hellfire Effect - trigger as DOT
2079 {
2082 }
2083}
2084
2086{
2087 m_UniqueTargetInfo.clear();
2088 m_UniqueGOTargetInfo.clear();
2089 m_UniqueItemInfo.clear();
2090 m_delayMoment = 0;
2091}
2092
2094{
2095 public:
2096 ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
2097
2098 bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
2099 {
2101 if (!caster)
2102 return true;
2103
2104 uint32 const typeMaskActor = PROC_FLAG_NONE;
2107 uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
2108 uint32 const hitMask = PROC_HIT_REFLECT;
2109
2110 Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
2111 return true;
2112 }
2113
2114 private:
2117};
2118
2119void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
2120{
2121 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2122 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(target, spellEffectInfo, losPosition))
2123 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2124
2125 // no effects left
2126 if (!effectMask)
2127 return;
2128
2129 if (checkIfValid)
2130 if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
2131 return;
2132
2133 // Check for effect immune skip if immuned
2134 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2135 if (target->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, m_caster))
2136 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2137
2138 ObjectGuid targetGUID = target->GetGUID();
2139
2140 // Lookup target in already in list
2141 auto ihit = std::find_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [targetGUID](TargetInfo const& target) { return target.TargetGUID == targetGUID; });
2142 if (ihit != std::end(m_UniqueTargetInfo)) // Found in list
2143 {
2144 // Immune effects removed from mask
2145 ihit->EffectMask |= effectMask;
2146 ihit->ScaleAura = false;
2147 if (m_auraScaleMask && ihit->EffectMask == m_auraScaleMask && m_caster != target)
2148 {
2149 SpellInfo const* auraSpell = m_spellInfo->GetFirstRankSpell();
2150 if (uint32(target->GetLevel() + 10) >= auraSpell->SpellLevel)
2151 ihit->ScaleAura = true;
2152 }
2153 return;
2154 }
2155
2156 // This is new target calculate data for him
2157
2158 // Get spell hit result on target
2159 TargetInfo targetInfo;
2160 targetInfo.TargetGUID = targetGUID; // Store target GUID
2161 targetInfo.EffectMask = effectMask; // Store all effects not immune
2162 targetInfo.IsAlive = target->IsAlive();
2163 targetInfo.Damage = 0;
2164 targetInfo.Healing = 0;
2165 targetInfo.IsCrit = false;
2166 targetInfo.ScaleAura = false;
2167 if (m_auraScaleMask && targetInfo.EffectMask == m_auraScaleMask && m_caster != target)
2168 {
2169 SpellInfo const* auraSpell = m_spellInfo->GetFirstRankSpell();
2170 if (uint32(target->GetLevel() + 10) >= auraSpell->SpellLevel)
2171 targetInfo.ScaleAura = true;
2172 }
2173
2174 // Calculate hit result
2176 targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
2177
2178 // Spell have speed - need calculate incoming time
2179 // Incoming time is zero for self casts. At least I think so.
2180 if (m_spellInfo->Speed > 0.0f && m_caster != target)
2181 {
2182 // calculate spell incoming interval
2184 float dist = m_caster->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
2185
2186 if (dist < 5.0f)
2187 dist = 5.0f;
2188
2189 targetInfo.TimeDelay = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
2190
2191 // Calculate minimum incoming time
2192 if (!m_delayMoment || m_delayMoment > targetInfo.TimeDelay)
2193 m_delayMoment = targetInfo.TimeDelay;
2194 }
2195 else
2196 targetInfo.TimeDelay = 0ULL;
2197
2198 // If target reflect spell back to caster
2199 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
2200 {
2201 // Shouldn't be able to reflect gameobject spells
2202 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
2203
2204 // Calculate reflected spell result on caster
2205 SpellCastResult castResult = m_spellInfo->CheckTarget(target, unitCaster, implicit);
2206 if (castResult == SPELL_CAST_OK || castResult == SPELL_FAILED_TARGET_AURASTATE)
2207 targetInfo.ReflectResult = unitCaster->SpellHitResult(unitCaster, m_spellInfo, false); // can't reflect twice
2208 else
2209 targetInfo.ReflectResult = SPELL_MISS_IMMUNE;
2210
2211 // Proc spell reflect aura when missile hits the original target
2213
2214 // Increase time interval for reflected spells by 1.5
2215 targetInfo.TimeDelay += targetInfo.TimeDelay >> 1;
2216 }
2217 else
2218 targetInfo.ReflectResult = SPELL_MISS_NONE;
2219
2220 // Add target to list
2221 m_UniqueTargetInfo.emplace_back(std::move(targetInfo));
2222}
2223
2225{
2226 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2227 {
2228 if (!spellEffectInfo.IsEffect())
2229 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2230 else
2231 {
2232 switch (spellEffectInfo.Effect)
2233 {
2238 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2239 break;
2240 default:
2241 break;
2242 }
2243 }
2244 }
2245
2246 if (!effectMask)
2247 return;
2248
2249 ObjectGuid targetGUID = go->GetGUID();
2250
2251 // Lookup target in already in list
2252 auto ihit = std::find_if(std::begin(m_UniqueGOTargetInfo), std::end(m_UniqueGOTargetInfo), [targetGUID](GOTargetInfo const& target) { return target.TargetGUID == targetGUID; });
2253 if (ihit != std::end(m_UniqueGOTargetInfo)) // Found in list
2254 {
2255 // Add only effect mask
2256 ihit->EffectMask |= effectMask;
2257 return;
2258 }
2259
2260 // This is new target calculate data for him
2261
2262 GOTargetInfo target;
2263 target.TargetGUID = targetGUID;
2264 target.EffectMask = effectMask;
2265
2266 // Spell have speed - need calculate incoming time
2267 if (m_spellInfo->Speed > 0.0f)
2268 {
2269 // calculate spell incoming interval
2270 float dist = m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
2271 if (dist < 5.0f)
2272 dist = 5.0f;
2273
2274 target.TimeDelay = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
2275
2276 if (!m_delayMoment || m_delayMoment > target.TimeDelay)
2277 m_delayMoment = target.TimeDelay;
2278 }
2279 else
2280 target.TimeDelay = 0ULL;
2281
2282 // Add target to list
2283 m_UniqueGOTargetInfo.emplace_back(std::move(target));
2284}
2285
2286void Spell::AddItemTarget(Item* item, uint32 effectMask)
2287{
2288 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2289 if (!spellEffectInfo.IsEffect())
2290 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2291
2292 // no effects left
2293 if (!effectMask)
2294 return;
2295
2296 // Lookup target in already in list
2297 auto ihit = std::find_if(std::begin(m_UniqueItemInfo), std::end(m_UniqueItemInfo), [item](ItemTargetInfo const& target) { return target.TargetItem == item; });
2298 if (ihit != std::end(m_UniqueItemInfo)) // Found in list
2299 {
2300 // Add only effect mask
2301 ihit->EffectMask |= effectMask;
2302 return;
2303 }
2304
2305 // This is new target add data
2306
2307 ItemTargetInfo target;
2308 target.TargetItem = item;
2309 target.EffectMask = effectMask;
2310
2311 m_UniqueItemInfo.emplace_back(std::move(target));
2312}
2313
2314void Spell::AddCorpseTarget(Corpse* corpse, uint32 effectMask)
2315{
2316 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2317 if (!spellEffectInfo.IsEffect())
2318 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2319
2320 if (!effectMask)
2321 return;
2322
2323 ObjectGuid targetGUID = corpse->GetGUID();
2324
2325 // Lookup target in already in list
2327 {
2328 if (targetGUID == ihit.TargetGUID) // Found in list
2329 {
2330 ihit.EffectMask |= effectMask; // Add only effect mask
2331 return;
2332 }
2333 }
2334
2335 // This is new target calculate data for him
2336 CorpseTargetInfo target;
2337 target.TargetGUID = targetGUID;
2338 target.EffectMask = effectMask;
2339
2340 // Spell have speed - need calculate incoming time
2341 if (m_spellInfo->Speed > 0.0f)
2342 {
2343 // calculate spell incoming interval
2344 float dist = m_caster->GetDistance(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ());
2345 if (dist < 5.0f)
2346 dist = 5.0f;
2347
2348 target.TimeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f));
2349
2350 if (!m_delayMoment || m_delayMoment > target.TimeDelay)
2351 m_delayMoment = target.TimeDelay;
2352 }
2353 else
2354 target.TimeDelay = 0LL;
2355
2356 // Add target to list
2357 m_UniqueCorpseTargetInfo.push_back(target);
2358}
2359
2361{
2362 m_destTargets[effIndex] = dest;
2363}
2364
2366{
2367 return std::count_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effect](TargetInfo const& targetInfo)
2368 {
2369 return targetInfo.EffectMask & (1 << effect);
2370 });
2371}
2372
2374{
2375 return std::count_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [effect](GOTargetInfo const& targetInfo)
2376 {
2377 return targetInfo.EffectMask & (1 << effect);
2378 });
2379}
2380
2382{
2383 return std::count_if(m_UniqueItemInfo.begin(), m_UniqueItemInfo.end(), [effect](ItemTargetInfo const& targetInfo)
2384 {
2385 return targetInfo.EffectMask & (1 << effect);
2386 });
2387}
2388
2390{
2391 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2392 if (!unit)
2393 return;
2394
2395 // Need init unitTarget by default unit (can changed in code on reflect)
2396 spell->unitTarget = unit;
2397
2398 // Reset damage/healing counter
2399 spell->m_damage = Damage;
2400 spell->m_healing = Healing;
2401
2402 _spellHitTarget = nullptr;
2404 _spellHitTarget = unit;
2406 _spellHitTarget = spell->m_caster->ToUnit();
2407
2409 unit->SetInCombatWith(spell->m_originalCaster);
2410
2412
2413 _enablePVP = false; // need to check PvP state before spell effects, but act on it afterwards
2414 if (_spellHitTarget)
2415 {
2416 // if target is flagged for pvp also flag caster if a player
2417 // but respect current pvp rules (buffing/healing npcs flagged for pvp only flags you if they are in combat)
2418 if (unit->IsPvP() && (unit->IsInCombat() || unit->IsCharmedOwnedByPlayerOrPlayer()) && spell->m_caster->GetTypeId() == TYPEID_PLAYER)
2419 _enablePVP = true; // Decide on PvP flagging now, but act on it later.
2420
2421 SpellMissInfo missInfo = spell->PreprocessSpellHit(_spellHitTarget, ScaleAura, *this);
2422 if (missInfo != SPELL_MISS_NONE)
2423 {
2424 if (missInfo != SPELL_MISS_MISS)
2425 spell->m_caster->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
2426 spell->m_damage = 0;
2427 spell->m_healing = 0;
2428 _spellHitTarget = nullptr;
2429 }
2430 }
2431
2432 spell->CallScriptOnHitHandlers();
2433
2434 // scripts can modify damage/healing for current target, save them
2435 Damage = spell->m_damage;
2436 Healing = spell->m_healing;
2437}
2438
2440{
2441 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2442 if (!unit)
2443 return;
2444
2445 // Need init unitTarget by default unit (can changed in code on reflect)
2446 // Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
2447 spell->unitTarget = unit;
2448 spell->targetMissInfo = MissCondition;
2449
2450 // Reset damage/healing counter
2451 spell->m_damage = Damage;
2452 spell->m_healing = Healing;
2453
2454 if (unit->IsAlive() != IsAlive)
2455 return;
2456
2457 if (spell->getState() == SPELL_STATE_DELAYED && !spell->IsPositive() && (GameTime::GetGameTimeMS() - TimeDelay) <= unit->m_lastSanctuaryTime)
2458 return; // No missinfo in that case
2459
2460 if (_spellHitTarget)
2461 spell->DoSpellEffectHit(_spellHitTarget, spellEffectInfo, *this);
2462
2463 // scripts can modify damage/healing for current target, save them
2464 Damage = spell->m_damage;
2465 Healing = spell->m_healing;
2466}
2467
2469{
2470 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2471 if (!unit)
2472 return;
2473
2474 // other targets executed before this one changed pointer
2475 spell->unitTarget = unit;
2476 if (_spellHitTarget)
2477 spell->unitTarget = _spellHitTarget;
2478
2479 // Reset damage/healing counter
2480 spell->m_damage = Damage;
2481 spell->m_healing = Healing;
2482
2483 // Get original caster (if exist) and calculate damage/healing from him data
2484 // Skip if m_originalCaster not available
2485 Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit();
2486
2487 if (caster)
2488 {
2489 // Fill base trigger info
2490 uint32 procAttacker = spell->m_procAttacker;
2491 uint32 procVictim = spell->m_procVictim;
2492 uint32 procSpellType = PROC_SPELL_TYPE_NONE;
2493 uint32 hitMask = PROC_HIT_NONE;
2494
2495 // Spells with this flag cannot trigger if effect is cast on self
2496 bool const canEffectTrigger = !spell->m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && spell->unitTarget->CanProc() &&
2497 (spell->CanExecuteTriggersOnHit(EffectMask) || MissCondition == SPELL_MISS_IMMUNE || MissCondition == SPELL_MISS_IMMUNE2);
2498
2499 // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
2500 if (canEffectTrigger && !procAttacker && !procVictim)
2501 {
2502 bool positive = true;
2503 if (spell->m_damage > 0)
2504 positive = false;
2505 else if (!spell->m_healing)
2506 {
2507 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
2508 {
2509 // in case of immunity, check all effects to choose correct procFlags, as none has technically hit
2510 if (EffectMask && !(EffectMask & (1 << i)))
2511 continue;
2512
2513 if (!spell->m_spellInfo->IsPositiveEffect(i))
2514 {
2515 positive = false;
2516 break;
2517 }
2518 }
2519 }
2520
2521 switch (spell->m_spellInfo->DmgClass)
2522 {
2524 if (positive)
2525 {
2528 }
2529 else
2530 {
2533 }
2534 break;
2536 if (positive)
2537 {
2540 }
2541 else
2542 {
2545 }
2546 break;
2547 }
2548 }
2549
2550 // All calculated do it!
2551 // Do healing
2552 bool hasHealing = false;
2553 std::unique_ptr<DamageInfo> spellDamageInfo;
2554 std::unique_ptr<HealInfo> healInfo;
2555 if (spell->m_healing > 0)
2556 {
2557 hasHealing = true;
2558 uint32 addhealth = spell->m_healing;
2559 if (IsCrit)
2560 {
2561 hitMask |= PROC_HIT_CRITICAL;
2562 addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr);
2563 }
2564 else
2565 hitMask |= PROC_HIT_NORMAL;
2566
2567 healInfo = std::make_unique<HealInfo>(caster, spell->unitTarget, addhealth, spell->m_spellInfo, spell->m_spellInfo->GetSchoolMask());
2568 caster->HealBySpell(*healInfo, IsCrit);
2569 spell->unitTarget->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo->GetEffectiveHeal()) * 0.5f, spell->m_spellInfo);
2570 spell->m_healing = healInfo->GetEffectiveHeal();
2571
2572 procSpellType |= PROC_SPELL_TYPE_HEAL;
2573 }
2574
2575 // Do damage
2576 bool hasDamage = false;
2577 if (spell->m_damage > 0)
2578 {
2579 hasDamage = true;
2580 // Fill base damage struct (unitTarget - is real spell target)
2581 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask);
2582 // Check damage immunity
2583 if (spell->unitTarget->IsImmunedToDamage(spell->m_spellInfo))
2584 {
2585 hitMask = PROC_HIT_IMMUNE;
2586 spell->m_damage = 0;
2587
2588 // no packet found in sniffs
2589 }
2590 else
2591 {
2592 caster->SetLastDamagedTargetGuid(spell->unitTarget->GetGUID());
2593
2594 // Add bonuses and fill damageInfo struct
2595 caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit, MissCondition == SPELL_MISS_BLOCK, spell);
2596 Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
2597
2598 // Send log damage message to client
2599 caster->SendSpellNonMeleeDamageLog(&damageInfo);
2600
2601 hitMask |= createProcHitMask(&damageInfo, MissCondition);
2602 procVictim |= PROC_FLAG_TAKEN_DAMAGE;
2603
2604 spell->m_damage = damageInfo.damage;
2605 caster->DealSpellDamage(&damageInfo, true);
2606 }
2607
2608 // Do triggers for unit
2609 if (canEffectTrigger)
2610 {
2611 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, SPELL_DIRECT_DAMAGE, spell->m_attackType, hitMask);
2612 procSpellType |= PROC_SPELL_TYPE_DAMAGE;
2613 }
2614 }
2615
2616 // Passive spell hits/misses or active spells only misses (only triggers)
2617 if (!hasHealing && !hasDamage)
2618 {
2619 // Fill base damage struct (unitTarget - is real spell target)
2620 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask);
2621 hitMask |= createProcHitMask(&damageInfo, MissCondition);
2622 // Do triggers for unit
2623 if (canEffectTrigger)
2624 {
2625 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, hitMask);
2626 procSpellType |= PROC_SPELL_TYPE_NO_DMG_HEAL;
2627 }
2628
2629 // Failed Pickpocket, reveal rogue
2631 {
2632 Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit());
2634 spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster);
2635 }
2636 }
2637
2638 // Do triggers for unit
2639 if (canEffectTrigger)
2640 {
2641 Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, hitMask, spell, spellDamageInfo.get(), healInfo.get());
2642
2643 // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
2644 if (caster->GetTypeId() == TYPEID_PLAYER && (procSpellType & (PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL)))
2645 {
2648 caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo);
2649 }
2650 }
2651
2652 // set hitmask for finish procs
2653 spell->m_hitMask |= hitMask;
2654
2655 // Do not take combo points on dodge and miss
2656 if (MissCondition != SPELL_MISS_NONE && spell->m_needComboPoints && spell->m_targets.GetUnitTargetGUID() == TargetGUID)
2657 spell->m_needComboPoints = false;
2658
2659 // _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit
2660 if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
2661 {
2662 if (Unit* unitCaster = spell->m_caster->ToUnit())
2663 unitCaster->AtTargetAttacked(unit, spell->m_spellInfo->HasInitialAggro());
2664
2665 if (!unit->IsStandState())
2667 }
2668
2669 // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
2671 caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, true);
2672 }
2673
2674 if (_spellHitTarget)
2675 {
2676 //AI functions
2677 if (Creature* cHitTarget = _spellHitTarget->ToCreature())
2678 if (CreatureAI* hitTargetAI = cHitTarget->AI())
2679 hitTargetAI->SpellHit(spell->m_caster, spell->m_spellInfo);
2680
2681 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
2682 spell->m_caster->ToCreature()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
2683 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
2684 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
2685
2686 if (HitAura)
2687 {
2688 if (AuraApplication* aurApp = HitAura->GetApplicationOfTarget(_spellHitTarget->GetGUID()))
2689 {
2690 // only apply unapplied effects (for reapply case)
2691 uint8 effMask = EffectMask & aurApp->GetEffectsToApply();
2692 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
2693 if ((effMask & (1 << i)) && aurApp->HasEffect(i))
2694 effMask &= ~(1 << i);
2695
2696 if (effMask)
2697 _spellHitTarget->_ApplyAura(aurApp, effMask);
2698 }
2699 }
2700
2701 // Needs to be called after dealing damage/healing to not remove breaking on damage auras
2702 spell->DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
2703
2704 if (_enablePVP)
2705 spell->m_caster->ToPlayer()->UpdatePvP(true);
2706 }
2707
2708 spell->_spellAura = HitAura;
2710 spell->_spellAura = nullptr;
2711}
2712
2714{
2715 GameObject* go = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToGameObject() : ObjectAccessor::GetGameObject(*spell->m_caster, TargetGUID);
2716 if (!go)
2717 return;
2718
2720
2721 spell->HandleEffects(nullptr, nullptr, go, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2722
2723 // AI functions
2724 if (go->AI())
2725 go->AI()->SpellHit(spell->m_caster, spell->m_spellInfo);
2726
2727 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
2728 spell->m_caster->ToCreature()->AI()->SpellHitTarget(go, spell->m_spellInfo);
2729 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
2730 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(go, spell->m_spellInfo);
2731
2732 spell->CallScriptOnHitHandlers();
2734}
2735
2737{
2739
2740 spell->HandleEffects(nullptr, TargetItem, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2741
2742 spell->CallScriptOnHitHandlers();
2744}
2745
2747{
2748 Corpse* corpse = ObjectAccessor::GetCorpse(*spell->m_caster, TargetGUID);
2749 if (!corpse)
2750 return;
2751
2753
2754 spell->HandleEffects(nullptr, nullptr, nullptr, corpse, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2755
2756 spell->CallScriptOnHitHandlers();
2758}
2759
2761{
2762 if (!unit)
2763 return SPELL_MISS_EVADE;
2764
2765 // Target may have begun evading between launch and hit phases - re-check now
2766 if (Creature* creatureTarget = unit->ToCreature())
2767 if (creatureTarget->IsEvadingAttacks())
2768 return SPELL_MISS_EVADE;
2769
2770 // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
2772 return SPELL_MISS_IMMUNE;
2773
2774 if (Player* player = unit->ToPlayer())
2775 {
2776 player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id);
2777 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, m_caster);
2778 }
2779
2780 if (Player* player = m_caster->ToPlayer())
2781 {
2782 player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER, m_spellInfo->Id);
2783 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit);
2784 }
2785
2786 if (m_caster != unit)
2787 {
2788 // Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
2790 return SPELL_MISS_EVADE;
2791
2794 else if (m_caster->IsFriendlyTo(unit))
2795 {
2796 // for delayed spells ignore negative spells (after duel end) for friendly targets
2797 if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidAssistTarget(unit, m_spellInfo))
2798 return SPELL_MISS_EVADE;
2799
2800 // assisting case, healing and resurrection
2802 {
2804 {
2805 playerOwner->SetContestedPvP();
2806 playerOwner->UpdatePvP(true);
2807 }
2808 }
2809
2811 {
2812 if (m_originalCaster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // only do explicit combat forwarding for PvP enabled units
2813 m_originalCaster->GetCombatManager().InheritCombatStatesFrom(unit); // for creature v creature combat, the threat forward does it for us
2815 }
2816 }
2817 }
2818
2819 // original caster for auras
2820 WorldObject* origCaster = m_caster;
2821 if (m_originalCaster)
2822 origCaster = m_originalCaster;
2823
2824 // check immunity due to diminishing returns
2826 {
2827 // Select rank for aura with level requirements only in specific cases
2828 // Unit has to be target only of aura effect, both caster and target have to be players, target has to be other than unit target
2829 hitInfo.AuraSpellInfo = m_spellInfo;
2830 if (scaleAura)
2831 {
2832 if (SpellInfo const* actualSpellInfo = m_spellInfo->GetAuraRankForLevel(unitTarget->GetLevel()))
2833 hitInfo.AuraSpellInfo = actualSpellInfo;
2834
2835 for (SpellEffectInfo const& auraEffectInfo : hitInfo.AuraSpellInfo->GetEffects())
2836 {
2837 hitInfo.AuraBasePoints[auraEffectInfo.EffectIndex] = auraEffectInfo.BasePoints;
2838 if (m_spellInfo->GetEffect(auraEffectInfo.EffectIndex).Effect != auraEffectInfo.Effect)
2839 {
2840 hitInfo.AuraSpellInfo = m_spellInfo;
2841 break;
2842 }
2843 }
2844 }
2845
2846 // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
2847 bool triggered = (m_triggeredByAuraSpell != nullptr);
2849
2850 DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1;
2851 if (hitInfo.DRGroup)
2852 {
2853 diminishLevel = unit->GetDiminishing(hitInfo.DRGroup);
2855 // Increase Diminishing on unit, current informations for actually casts will use values above
2856 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && unit->IsAffectedByDiminishingReturns()))
2857 unit->IncrDiminishing(m_spellInfo, triggered);
2858 }
2859
2860 // Now Reduce spell duration using data received at spell hit
2861 // check whatever effects we're going to apply, diminishing returns only apply to negative aura effects
2862 hitInfo.Positive = true;
2863 if (origCaster == unit || !origCaster->IsFriendlyTo(unit))
2864 {
2865 for (SpellEffectInfo const& auraSpellEffect : hitInfo.AuraSpellInfo->GetEffects())
2866 {
2867 // mod duration only for effects applying aura!
2868 if (hitInfo.EffectMask & (1 << auraSpellEffect.EffectIndex) &&
2869 auraSpellEffect.IsUnitOwnedAuraEffect() &&
2870 !hitInfo.AuraSpellInfo->IsPositiveEffect(auraSpellEffect.EffectIndex))
2871 {
2872 hitInfo.Positive = false;
2873 break;
2874 }
2875 }
2876 }
2877
2878 hitInfo.AuraDuration = Aura::CalcMaxDuration(hitInfo.AuraSpellInfo, origCaster);
2879
2880 // unit is immune to aura if it was diminished to 0 duration
2881 if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(hitInfo.AuraSpellInfo, triggered, hitInfo.AuraDuration, origCaster, diminishLevel))
2882 if (std::all_of(std::begin(hitInfo.AuraSpellInfo->GetEffects()), std::end(hitInfo.AuraSpellInfo->GetEffects()), [](SpellEffectInfo const& effInfo) { return !effInfo.IsEffect() || effInfo.Effect == SPELL_EFFECT_APPLY_AURA; }))
2883 return SPELL_MISS_IMMUNE;
2884 }
2885
2886 return SPELL_MISS_NONE;
2887}
2888
2889void Spell::DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo, TargetInfo& hitInfo)
2890{
2891 if (uint8 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << spellEffectInfo.EffectIndex, unit))
2892 {
2893 WorldObject* caster = m_caster;
2894 if (m_originalCaster)
2895 caster = m_originalCaster;
2896
2897 if (caster)
2898 {
2899 bool refresh = false;
2900
2901 if (!hitInfo.HitAura)
2902 {
2903 bool const resetPeriodicTimer = (m_spellInfo->StackAmount < 2) && !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER);
2904 uint8 const allAuraEffectMask = Aura::BuildEffectMaskForOwner(hitInfo.AuraSpellInfo, MAX_EFFECT_MASK, unit);
2905 int32 const* bp = hitInfo.AuraBasePoints;
2906 if (hitInfo.AuraSpellInfo == m_spellInfo)
2908
2909 AuraCreateInfo createInfo(hitInfo.AuraSpellInfo, allAuraEffectMask, unit);
2910 createInfo
2911 .SetCasterGUID(caster->GetGUID())
2912 .SetBaseAmount(bp)
2914 .SetPeriodicReset(resetPeriodicTimer)
2915 .SetOwnerEffectMask(aura_effmask)
2916 .IsRefresh = &refresh;
2917
2918 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo, false))
2919 {
2920 hitInfo.HitAura = aura->ToUnitAura();
2921
2922 // Set aura stack amount to desired value
2924 {
2925 if (!refresh)
2927 else
2929 }
2930
2931 hitInfo.HitAura->SetDiminishGroup(hitInfo.DRGroup);
2932
2933 hitInfo.AuraDuration = caster->ModSpellDuration(hitInfo.AuraSpellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask());
2934
2935 // Haste modifies duration of channeled spells
2936 if (m_spellInfo->IsChanneled())
2937 caster->ModSpellDurationTime(hitInfo.AuraSpellInfo, hitInfo.AuraDuration, this);
2938 // and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
2941
2942 if (hitInfo.AuraDuration != hitInfo.HitAura->GetMaxDuration())
2943 {
2944 hitInfo.HitAura->SetMaxDuration(hitInfo.AuraDuration);
2945 hitInfo.HitAura->SetDuration(hitInfo.AuraDuration);
2946 }
2947
2948 if (refresh)
2949 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
2950 }
2951 }
2952 else
2953 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
2954 }
2955 }
2956
2957 _spellAura = hitInfo.HitAura;
2958 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2959 _spellAura = nullptr;
2960}
2961
2963{
2964 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras
2965 // this is executed after spell proc spells on target hit
2966 // spells are triggered for each hit spell target
2967 // info confirmed with retail sniffs of permafrost and shadow weaving
2968 if (!m_hitTriggerSpells.empty())
2969 {
2970 int32 _duration = 0;
2971 for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
2972 {
2973 if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance))
2974 {
2975 m_caster->CastSpell(unit, i->triggeredSpell->Id, true);
2976 TC_LOG_DEBUG("spells", "Spell {} triggered spell {} by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id);
2977
2978 // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
2979 // set duration of current aura to the triggered spell
2980 if (i->triggeredSpell->GetDuration() == -1)
2981 {
2982 if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID()))
2983 {
2984 // get duration from aura-only once
2985 if (!_duration)
2986 {
2987 Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
2988 _duration = aur ? aur->GetDuration() : -1;
2989 }
2990 triggeredAur->SetDuration(_duration);
2991 }
2992 }
2993 }
2994 }
2995 }
2996
2997 // trigger linked auras remove/apply
2999 if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT))
3000 {
3001 for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
3002 {
3003 if (*i < 0)
3004 unit->RemoveAurasDueToSpell(-(*i));
3005 else
3006 unit->CastSpell(unit, *i, m_caster->GetGUID());
3007 }
3008 }
3009}
3010
3012{
3013 // Not need check return true
3015 return true;
3016
3017 uint8 channelTargetEffectMask = m_channelTargetEffectMask;
3018 uint8 channelAuraMask = 0;
3019 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3020 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3021 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
3022
3023 channelAuraMask &= channelTargetEffectMask;
3024
3025 float range = 0;
3026 if (channelAuraMask)
3027 {
3029 if (Player* modOwner = m_caster->GetSpellModOwner())
3030 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
3031
3032 // add little tolerance level
3033 range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
3034 }
3035
3036 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
3037 {
3038 if (targetInfo.MissCondition == SPELL_MISS_NONE && (channelTargetEffectMask & targetInfo.EffectMask))
3039 {
3040 Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
3041 if (!unit)
3042 continue;
3043
3044 if (IsValidDeadOrAliveTarget(unit))
3045 {
3046 if (channelAuraMask & targetInfo.EffectMask)
3047 {
3049 {
3050 if (m_caster != unit && !m_caster->IsWithinDistInMap(unit, range))
3051 {
3052 targetInfo.EffectMask &= ~aurApp->GetEffectMask();
3053 unit->RemoveAura(aurApp);
3054 continue;
3055 }
3056 }
3057 else // aura is dispelled
3058 continue;
3059 }
3060
3061 channelTargetEffectMask &= ~targetInfo.EffectMask; // remove from need alive mask effect that have alive target
3062 }
3063 }
3064 }
3065
3066 // is all effects from m_needAliveTargetMask have alive targets
3067 return channelTargetEffectMask == 0;
3068}
3069
3070SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura)
3071{
3072 if (m_CastItem)
3073 {
3076 }
3077 else
3078 {
3080 m_castItemEntry = 0;
3081 }
3082
3083 InitExplicitTargets(targets);
3084
3085 // Fill aura scaling information
3086 if (Unit* unitCaster = m_caster->ToUnit())
3087 {
3088 if (unitCaster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING))
3089 {
3090 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3091 {
3092 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3093 {
3094 // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive
3095 if (m_spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex))
3096 {
3097 m_auraScaleMask |= (1 << spellEffectInfo.EffectIndex);
3098 if (m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex] != spellEffectInfo.BasePoints)
3099 {
3100 m_auraScaleMask = 0;
3101 break;
3102 }
3103 }
3104 }
3105 }
3106 }
3107 }
3108
3110
3111 if (triggeredByAura)
3112 m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
3113
3114 // create and add update event for this spell
3115 _spellEvent = new SpellEvent(this);
3117
3118 // check disables
3120 {
3122 finish(false);
3124 }
3125
3126 // Prevent casting at cast another spell (ServerSide check)
3128 {
3130 finish(false);
3132 }
3133
3134 LoadScripts();
3135
3136 // Fill cost data (do not use power for item casts)
3138
3139 // Set combo point requirement
3141 m_needComboPoints = false;
3142
3143 uint32 param1 = 0, param2 = 0;
3144 SpellCastResult result = CheckCast(true, &param1, &param2);
3145 // target is checked in too many locations and with different results to handle each of them
3146 // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
3148 result = SPELL_CAST_OK;
3149 if (result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
3150 {
3151 // Periodic auras should be interrupted when aura triggers a spell which can't be cast
3152 // for example bladestorm aura should be removed on disarm as of patch 3.3.5
3153 // channeled periodic spells should be affected by this (arcane missiles, penance, etc)
3154 // a possible alternative sollution for those would be validating aura target on unit state change
3155 if (triggeredByAura && triggeredByAura->IsPeriodic() && !triggeredByAura->GetBase()->IsPassive())
3156 {
3158 triggeredByAura->GetBase()->SetDuration(0);
3159 }
3160
3161 if (param1 || param2)
3162 SendCastResult(result, &param1, &param2);
3163 else
3164 SendCastResult(result);
3165
3166 finish(false);
3167 return result;
3168 }
3169
3170 // Prepare data for triggers
3172
3173 if (Player* player = m_caster->ToPlayer())
3174 {
3175 if (!player->GetCommandStatus(CHEAT_CASTTIME))
3176 {
3177 // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
3179 }
3180 else
3181 m_casttime = 0; // Set cast time to 0 if .cheat casttime is enabled.
3182 }
3183 else
3185
3186 SpellCastResult movementResult = SPELL_CAST_OK;
3187 if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving())
3188 movementResult = CheckMovement();
3189
3190 // Creatures focus their target when possible
3192 {
3193 // 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
3194 bool const focusTarget = !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING);
3195 if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
3197 else
3198 m_caster->ToCreature()->SetSpellFocus(this, nullptr);
3199 }
3200
3201 if (movementResult != SPELL_CAST_OK)
3202 {
3204 {
3205 SendCastResult(movementResult);
3206 finish(movementResult);
3207 return movementResult;
3208 }
3209 else
3210 {
3211 // Creatures (not controlled) give priority to spell casting over movement.
3212 // We assume that the casting is always valid and the current movement
3213 // is stopped immediately (because spells are updated before movement, so next Unit::Update would cancel the spell before stopping movement)
3214 // and future attempts are stopped by by Unit::IsMovementPreventedByCasting in movement generators to prevent casting interruption.
3216 }
3217 }
3218
3219 // set timer base at cast time
3220 ReSetTimer();
3221
3222 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());
3223
3224 //Containers for channeled spells have to be set
3226 // Why check duration? 29350: channelled triggers channelled
3228 cast(true);
3229 else
3230 {
3231 if (Unit* unitCaster = m_caster->ToUnit())
3232 {
3233 // stealth must be removed at cast starting (at show channel bar)
3234 // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
3236 {
3237 unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
3238 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3239 {
3240 if (spellEffectInfo.GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT)
3241 {
3242 unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK);
3243 break;
3244 }
3245 }
3246 }
3247
3248 unitCaster->SetCurrentCastSpell(this);
3249 }
3251
3254
3255 // Call CreatureAI hook OnSpellStart
3256 if (Creature* caster = m_caster->ToCreature())
3257 if (caster->IsAIEnabled())
3258 caster->AI()->OnSpellStart(GetSpellInfo());
3259
3260 // commented out !m_spellInfo->StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
3261 // as a result a spell that passed CheckCast and should be processed instantly may suffer from this delayed process
3262 // 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
3263 // 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)
3265 cast(true);
3266 }
3267
3268 return SPELL_CAST_OK;
3269}
3270
3271void Spell::cancel(SpellCastResult result /*= SPELL_FAILED_INTERRUPTED*/, Optional<SpellCastResult> resultOther /*= {}*/)
3272{
3274 return;
3275
3276 uint32 oldState = m_spellState;
3278
3279 m_autoRepeat = false;
3280 switch (oldState)
3281 {
3284 SendCastResult(result);
3285 SendInterrupted(result, resultOther);
3286 break;
3288 SendInterrupted(result, resultOther);
3289 break;
3291 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
3292 if (targetInfo.MissCondition == SPELL_MISS_NONE)
3293 if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
3294 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3295
3297 SendInterrupted(result, resultOther);
3298
3299 m_appliedMods.clear();
3300 break;
3301 default:
3302 break;
3303 }
3304
3306 if (m_selfContainer && *m_selfContainer == this)
3307 *m_selfContainer = nullptr;
3308
3309 // originalcaster handles gameobjects/dynobjects for gob caster
3310 if (m_originalCaster)
3311 {
3313 if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
3315 }
3316
3317 //set state back so finish will be processed
3318 m_spellState = oldState;
3319
3320 finish(false);
3321}
3322
3323void Spell::cast(bool skipCheck)
3324{
3325 Player* modOwner = m_caster->GetSpellModOwner();
3326 Spell* lastSpellMod = nullptr;
3327 if (modOwner)
3328 {
3329 lastSpellMod = modOwner->m_spellModTakingSpell;
3330 if (lastSpellMod)
3331 modOwner->SetSpellModTakingSpell(lastSpellMod, false);
3332 }
3333
3334 _cast(skipCheck);
3335
3336 if (lastSpellMod)
3337 modOwner->SetSpellModTakingSpell(lastSpellMod, true);
3338}
3339
3340void Spell::_cast(bool skipCheck)
3341{
3342 // update pointers base at GUIDs to prevent access to non-existed already object
3343 if (!UpdatePointers())
3344 {
3345 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3346 cancel();
3347 return;
3348 }
3349
3350 // cancel at lost explicit target during cast
3352 {
3353 cancel();
3354 return;
3355 }
3356
3357 if (Player* playerCaster = m_caster->ToPlayer())
3358 {
3359 // now that we've done the basic check, now run the scripts
3360 // should be done before the spell is actually executed
3361 sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
3362
3363 // As of 3.0.2 pets begin attacking their owner's target immediately
3364 // Let any pets know we've attacked something. Check DmgClass for harmful spells only
3365 // This prevents spells such as Hunter's Mark from triggering pet attack
3366 if (GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE)
3367 if (Unit* target = m_targets.GetUnitTarget())
3368 for (Unit* controlled : playerCaster->m_Controlled)
3369 if (Creature* cControlled = controlled->ToCreature())
3370 if (CreatureAI* controlledAI = cControlled->AI())
3371 controlledAI->OwnerAttacked(target);
3372 }
3373
3375
3376 // Should this be done for original caster?
3377 Player* modOwner = m_caster->GetSpellModOwner();
3378 if (modOwner)
3379 {
3380 // Set spell which will drop charges for triggered cast spells
3381 // if not successfully cast, will be remove in finish(false)
3382 modOwner->SetSpellModTakingSpell(this, true);
3383 }
3384
3386
3387 // skip check if done already (for instant cast spells for example)
3388 if (!skipCheck)
3389 {
3390 auto cleanupSpell = [this, modOwner](SpellCastResult res, uint32* p1 = nullptr, uint32* p2 = nullptr)
3391 {
3392 SendCastResult(res, p1, p2);
3393 SendInterrupted(res);
3394
3395 if (modOwner)
3396 modOwner->SetSpellModTakingSpell(this, false);
3397
3398 finish(false);
3399 SetExecutedCurrently(false);
3400 };
3401
3402 uint32 param1 = 0, param2 = 0;
3403 SpellCastResult castResult = CheckCast(false, &param1, &param2);
3404 if (castResult != SPELL_CAST_OK)
3405 {
3406 cleanupSpell(castResult, &param1, &param2);
3407 return;
3408 }
3409
3410 // additional check after cast bar completes (must not be in CheckCast)
3411 // if trade not complete then remember it in trade data
3413 {
3414 if (modOwner)
3415 {
3416 if (TradeData* my_trade = modOwner->GetTradeData())
3417 {
3418 if (!my_trade->IsInAcceptProcess())
3419 {
3420 // Spell will be cast after completing the trade. Silently ignore at this place
3421 my_trade->SetSpell(m_spellInfo->Id, m_CastItem);
3422 cleanupSpell(SPELL_FAILED_DONT_REPORT);
3423 return;
3424 }
3425 }
3426 }
3427 }
3428
3429 // check diminishing returns (again, only after finish cast bar, tested on retail)
3430 if (Unit* target = m_targets.GetUnitTarget())
3431 {
3432 uint8 aura_effmask = 0;
3433 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3434 if (spellEffectInfo.IsUnitOwnedAuraEffect())
3435 aura_effmask |= 1 << spellEffectInfo.EffectIndex;
3436
3437 if (aura_effmask)
3438 {
3439 bool const triggered = m_triggeredByAuraSpell != nullptr;
3441 {
3443 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
3444 {
3446 {
3447 if (target->HasStrongerAuraWithDR(m_spellInfo, caster, triggered))
3448 {
3449 cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
3450 return;
3451 }
3452 }
3453 }
3454 }
3455 }
3456 }
3457 }
3458 // 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.
3459 if (Creature* creatureCaster = m_caster->ToCreature())
3460 if (!creatureCaster->GetTarget().IsEmpty() && !creatureCaster->HasUnitFlag(UNIT_FLAG_POSSESSED))
3461 if (WorldObject const* target = ObjectAccessor::GetUnit(*creatureCaster, creatureCaster->GetTarget()))
3462 creatureCaster->SetInFront(target);
3463
3465
3466 // Spell may be finished after target map check
3468 {
3470
3471 if (modOwner)
3472 modOwner->SetSpellModTakingSpell(this, false);
3473
3474 finish(false);
3475 SetExecutedCurrently(false);
3476 return;
3477 }
3478
3479 if (Unit* unitCaster = m_caster->ToUnit())
3481 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetPetGUID()))
3482 pet->DespawnOrUnsummon();
3483
3485
3487
3488 // traded items have trade slot instead of guid in m_itemTargetGUID
3489 // set to real guid to be sent later to the client
3491
3492 if (Player* player = m_caster->ToPlayer())
3493 {
3495 {
3496 player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_ITEM, m_CastItem->GetEntry());
3497 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry());
3498 }
3499
3500 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id);
3501 }
3502
3504 {
3505 // Powers have to be taken before SendSpellGo
3506 TakePower();
3507 TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
3508 }
3509 else if (Item* targetItem = m_targets.GetItemTarget())
3510 {
3512 if (targetItem->GetOwnerGUID() != m_caster->GetGUID())
3513 TakeReagents();
3514 }
3515
3516 // CAST SPELL
3518
3520
3521 // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
3522 SendSpellGo();
3523
3524 if (!m_spellInfo->IsChanneled())
3525 if (Creature* creatureCaster = m_caster->ToCreature())
3526 creatureCaster->ReleaseSpellFocus(this);
3527
3528 // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
3529 if (m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled())
3530 {
3531 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3532 // in case delayed spell remove item at cast delay start
3533 TakeCastItem();
3534
3535 // Okay, maps created, now prepare flags
3536 m_immediateHandled = false;
3538 SetDelayStart(0);
3539
3540 if (Unit* unitCaster = m_caster->ToUnit())
3541 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
3542 unitCaster->ClearUnitState(UNIT_STATE_CASTING);
3543 }
3544 else
3545 {
3546 // Immediate spell, no big deal
3548 }
3549
3551
3552 if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id))
3553 {
3554 for (int32 id : *spell_triggered)
3555 {
3556 if (id < 0)
3557 {
3558 if (Unit* unitCaster = m_caster->ToUnit())
3559 unitCaster->RemoveAurasDueToSpell(-id);
3560 }
3561 else
3563 }
3564 }
3565
3566 if (modOwner)
3567 {
3568 modOwner->SetSpellModTakingSpell(this, false);
3569
3570 //Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
3573 }
3574
3575 SetExecutedCurrently(false);
3576
3577 if (!m_originalCaster)
3578 return;
3579
3580 // Handle procs on cast
3581 uint32 procAttacker = m_procAttacker;
3582 if (!procAttacker)
3583 {
3586 else
3588 }
3589
3590 uint32 hitMask = m_hitMask;
3591 if (!(hitMask & PROC_HIT_CRITICAL))
3592 hitMask |= PROC_HIT_NORMAL;
3593
3594 Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
3595
3596 // Call CreatureAI hook OnSpellCast
3597 if (Creature* caster = m_originalCaster->ToCreature())
3598 if (caster->IsAIEnabled())
3599 caster->AI()->OnSpellCast(GetSpellInfo());
3600}
3601
3602template <class Container>
3604{
3605 for (TargetInfoBase& target : targetContainer)
3606 target.PreprocessTarget(this);
3607
3608 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3609 for (TargetInfoBase& target : targetContainer)
3610 if (target.EffectMask & (1 << spellEffectInfo.EffectIndex))
3611 target.DoTargetSpellHit(this, spellEffectInfo);
3612
3613 for (TargetInfoBase& target : targetContainer)
3614 target.DoDamageAndTriggers(this);
3615}
3616
3618{
3619 // start channeling if applicable
3620 if (m_spellInfo->IsChanneled())
3621 {
3622 int32 duration = m_spellInfo->GetDuration();
3623 if (duration > 0)
3624 {
3625 // First mod_duration then haste - see Missile Barrage
3626 // Apply duration mod
3627 if (Player* modOwner = m_caster->GetSpellModOwner())
3628 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
3629
3630 // Apply haste mods
3631 m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
3632
3633 m_channeledDuration = duration;
3634 SendChannelStart(duration);
3635 }
3636 else if (duration == -1)
3637 SendChannelStart(duration);
3638
3639 if (duration != 0)
3640 {
3642 // GameObjects shouldn't cast channeled spells
3644 }
3645 }
3646
3648
3649 // process immediate effects (items, ground, etc.) also initialize some variables
3651
3652 // consider spell hit for some spells without target, so they may proc on finish phase correctly
3653 if (m_UniqueTargetInfo.empty())
3655 else
3657
3659
3661
3663
3664 // spell is finished, perform some last features of the spell here
3666
3667 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3668 TakeCastItem();
3669
3670 // handle ammo consumption for Hunter's volley spell
3672 TakeAmmo();
3673
3675 finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell)
3676}
3677
3679{
3680 if (!UpdatePointers())
3681 {
3682 // finish the spell if UpdatePointers() returned false, something wrong happened there
3683 finish(false);
3684 return 0;
3685 }
3686
3687 Player* modOwner = m_caster->GetSpellModOwner();
3688 if (modOwner)
3689 modOwner->SetSpellModTakingSpell(this, true);
3690
3691 uint64 next_time = 0;
3692
3694
3695 if (!m_immediateHandled)
3696 {
3698 m_immediateHandled = true;
3699 }
3700
3701 bool single_missile = (m_targets.HasDst());
3702
3703 // 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)
3704 {
3705 std::vector<TargetInfo> delayedTargets;
3706 m_UniqueTargetInfo.erase(std::remove_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo& target) -> bool
3707 {
3708 if (single_missile || target.TimeDelay <= t_offset)
3709 {
3710 target.TimeDelay = t_offset;
3711 delayedTargets.emplace_back(std::move(target));
3712 return true;
3713 }
3714 else if (next_time == 0 || target.TimeDelay < next_time)
3715 next_time = target.TimeDelay;
3716
3717 return false;
3718 }), m_UniqueTargetInfo.end());
3719
3720 DoProcessTargetContainer(delayedTargets);
3721 }
3722
3723 // now recheck gameobject targeting correctness
3724 {
3725 std::vector<GOTargetInfo> delayedGOTargets;
3726 m_UniqueGOTargetInfo.erase(std::remove_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [&](GOTargetInfo& goTarget) -> bool
3727 {
3728 if (single_missile || goTarget.TimeDelay <= t_offset)
3729 {
3730 goTarget.TimeDelay = t_offset;
3731 delayedGOTargets.emplace_back(std::move(goTarget));
3732 return true;
3733 }
3734 else if (next_time == 0 || goTarget.TimeDelay < next_time)
3735 next_time = goTarget.TimeDelay;
3736
3737 return false;
3738 }), m_UniqueGOTargetInfo.end());
3739
3740 DoProcessTargetContainer(delayedGOTargets);
3741 }
3742
3744
3745 if (modOwner)
3746 modOwner->SetSpellModTakingSpell(this, false);
3747
3748 // All targets passed - need finish phase
3749 if (next_time == 0)
3750 {
3751 // spell is finished, perform some last features of the spell here
3753
3754 finish(true); // successfully finish spell cast
3755
3756 // return zero, spell is finished now
3757 return 0;
3758 }
3759 else
3760 {
3761 // spell is unfinished, return next execution time
3762 return next_time;
3763 }
3764}
3765
3767{
3768 // handle some immediate features of the spell here
3770
3771 // handle effects with SPELL_EFFECT_HANDLE_HIT mode
3772 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3773 {
3774 // don't do anything for empty effect
3775 if (!spellEffectInfo.IsEffect())
3776 continue;
3777
3778 // call effect handlers to handle destination hit
3779 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
3780 }
3781
3782 // process items
3784}
3785
3787{
3788 if (Unit* unitCaster = m_caster->ToUnit())
3789 {
3790 // Take for real after all targets are processed
3792 unitCaster->ClearComboPoints();
3793
3794 // Real add combo points from effects
3796 {
3797 // remove Premed-like effects unless they were caused by ourselves
3798 // (this Aura removes the already-added CP when it expires from duration - now that we've added CP, this shouldn't happen anymore!)
3800 unitCaster->RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
3801 unitCaster->AddComboPoints(m_comboTarget, m_comboPointGain);
3802 }
3803
3805 unitCaster->SetLastExtraAttackSpell(m_spellInfo->Id);
3806 }
3807
3808 // Handle procs on finish
3809 if (!m_originalCaster)
3810 return;
3811
3812 uint32 procAttacker = m_procAttacker;
3813 if (!procAttacker)
3814 {
3817 else
3819 }
3820
3822}
3823
3831
3832void Spell::update(uint32 difftime)
3833{
3834 // update pointers based at it's GUIDs
3835 if (!UpdatePointers())
3836 {
3837 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3838 cancel();
3839 return;
3840 }
3841
3843 {
3844 TC_LOG_DEBUG("spells", "Spell {} is cancelled due to removal of target.", m_spellInfo->Id);
3845 cancel();
3846 return;
3847 }
3848
3849 // check if the unit caster has moved before the spell finished
3850 if (m_timer != 0 && m_caster->IsUnit() && m_caster->ToUnit()->isMoving() && CheckMovement() != SPELL_CAST_OK)
3851 cancel();
3852
3853 switch (m_spellState)
3854 {
3856 {
3857 if (m_timer > 0)
3858 {
3859 if (difftime >= (uint32)m_timer)
3860 m_timer = 0;
3861 else
3862 m_timer -= difftime;
3863 }
3864
3866 // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
3867 cast(!m_casttime);
3868 break;
3869 }
3871 {
3872 if (m_timer)
3873 {
3874 // check if there are alive targets left
3876 {
3877 TC_LOG_DEBUG("spells", "Channeled spell {} is removed due to lack of targets", m_spellInfo->Id);
3878 m_timer = 0;
3879
3880 // Also remove applied auras
3881 for (TargetInfo const& target : m_UniqueTargetInfo)
3882 if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
3883 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3884 }
3885
3886 if (m_timer > 0)
3887 {
3888 if (difftime >= (uint32)m_timer)
3889 m_timer = 0;
3890 else
3891 m_timer -= difftime;
3892 }
3893 }
3894
3895 if (m_timer == 0)
3896 {
3898 finish();
3899
3900 // 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
3901 if (Creature* creatureCaster = m_caster->ToCreature())
3902 if (creatureCaster->IsAIEnabled())
3903 creatureCaster->AI()->OnChannelFinished(m_spellInfo);
3904 }
3905 break;
3906 }
3907 default:
3908 break;
3909 }
3910}
3911
3912void Spell::finish(bool ok)
3913{
3915 return;
3917
3918 if (!m_caster)
3919 return;
3920
3921 Unit* unitCaster = m_caster->ToUnit();
3922 if (!unitCaster)
3923 return;
3924
3925 if (m_spellInfo->IsChanneled())
3926 unitCaster->UpdateInterruptMask();
3927
3928 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
3930
3931 // Unsummon summon as possessed creatures on spell cancel
3932 if (m_spellInfo->IsChanneled() && unitCaster->GetTypeId() == TYPEID_PLAYER)
3933 {
3934 if (Unit* charm = unitCaster->GetCharmed())
3935 if (charm->GetTypeId() == TYPEID_UNIT
3936 && charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
3937 && charm->GetUInt32Value(UNIT_CREATED_BY_SPELL) == m_spellInfo->Id)
3938 ((Puppet*)charm)->UnSummon();
3939 }
3940
3941 if (Creature* creatureCaster = unitCaster->ToCreature())
3942 creatureCaster->ReleaseSpellFocus(this);
3943
3944 if (!ok)
3945 return;
3946
3947 if (unitCaster->GetTypeId() == TYPEID_UNIT && unitCaster->IsSummon())
3948 {
3949 // Unsummon statue
3950 uint32 spell = unitCaster->GetUInt32Value(UNIT_CREATED_BY_SPELL);
3951 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell);
3952 if (spellInfo && spellInfo->SpellIconID == 2056)
3953 {
3954 TC_LOG_DEBUG("spells", "Statue {} is unsummoned in spell {} finish", unitCaster->GetGUID().ToString(), m_spellInfo->Id);
3955 // Avoid infinite loops with setDeathState(JUST_DIED) being called over and over
3956 // It might make sense to do this check in Unit::setDeathState() and all overloaded functions
3957 if (unitCaster->getDeathState() != JUST_DIED)
3958 unitCaster->setDeathState(JUST_DIED);
3959 return;
3960 }
3961 }
3962
3964 {
3965 bool found = false;
3967 for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i)
3968 {
3969 if ((*i)->IsAffectingSpell(m_spellInfo))
3970 {
3971 found = true;
3972 break;
3973 }
3974 }
3975
3977 {
3978 unitCaster->resetAttackTimer(BASE_ATTACK);
3979 if (unitCaster->haveOffhandWeapon())
3980 unitCaster->resetAttackTimer(OFF_ATTACK);
3981 unitCaster->resetAttackTimer(RANGED_ATTACK);
3982 }
3983 }
3984
3985 // potions disabled by client, send event "not in combat" if need
3986 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
3987 {
3989 unitCaster->ToPlayer()->UpdatePotionCooldown(this);
3990 }
3991
3992 // Stop Attack for some spells
3994 unitCaster->AttackStop();
3995}
3996
3997void Spell::WriteCastResultInfo(WorldPacket& data, Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
3998{
3999 data << uint8(castCount); // single cast or multi 2.3 (0/1)
4000 data << uint32(spellInfo->Id);
4001 data << uint8(result); // problem
4002 switch (result)
4003 {
4005 if (param1)
4006 data << uint32(*param1);
4007 else
4008 data << uint32(spellInfo->RequiresSpellFocus); // SpellFocusObject.dbc id
4009 break;
4010 case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
4011 if (param1)
4012 data << uint32(*param1);
4013 else
4014 {
4015 // hardcode areas limitation case
4016 switch (spellInfo->Id)
4017 {
4018 case 41617: // Cenarion Mana Salve
4019 case 41619: // Cenarion Healing Salve
4020 data << uint32(3905);
4021 break;
4022 case 41618: // Bottled Nethergon Energy
4023 case 41620: // Bottled Nethergon Vapor
4024 data << uint32(3842);
4025 break;
4026 case 45373: // Bloodberry Elixir
4027 data << uint32(4075);
4028 break;
4029 default: // default case (don't must be)
4030 data << uint32(0);
4031 break;
4032 }
4033 }
4034 break;
4036 if (param1)
4037 {
4038 data << uint32(*param1);
4039 if (param2)
4040 data << uint32(*param2);
4041 }
4042 else
4043 {
4044 if (spellInfo->Totem[0])
4045 data << uint32(spellInfo->Totem[0]);
4046 if (spellInfo->Totem[1])
4047 data << uint32(spellInfo->Totem[1]);
4048 }
4049 break;
4051 if (param1)
4052 {
4053 data << uint32(*param1);
4054 if (param2)
4055 data << uint32(*param2);
4056 }
4057 else
4058 {
4059 if (spellInfo->TotemCategory[0])
4060 data << uint32(spellInfo->TotemCategory[0]);
4061 if (spellInfo->TotemCategory[1])
4062 data << uint32(spellInfo->TotemCategory[1]);
4063 }
4064 break;
4068 if (param1 && param2)
4069 {
4070 data << uint32(*param1);
4071 data << uint32(*param2);
4072 }
4073 else
4074 {
4075 data << uint32(spellInfo->EquippedItemClass);
4076 data << uint32(spellInfo->EquippedItemSubClassMask);
4077 }
4078 break;
4080 {
4081 if (param1)
4082 data << uint32(*param1);
4083 else
4084 {
4085 uint32 item = 0;
4086 for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
4087 {
4088 if (uint32 itemType = spellEffectInfo.ItemType)
4089 {
4090 item = itemType;
4091 break;
4092 }
4093 }
4094
4095 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item);
4096 if (proto && proto->ItemLimitCategory)
4097 data << uint32(proto->ItemLimitCategory);
4098 }
4099 break;
4100 }
4102 data << uint32(customError);
4103 break;
4105 {
4106 if (param1)
4107 data << uint32(*param1);
4108 else
4109 {
4110 uint32 missingItem = 0;
4111 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
4112 {
4113 if (spellInfo->Reagent[i] <= 0)
4114 continue;
4115
4116 uint32 itemid = spellInfo->Reagent[i];
4117 uint32 itemcount = spellInfo->ReagentCount[i];
4118
4119 if (!caster->HasItemCount(itemid, itemcount))
4120 {
4121 missingItem = itemid;
4122 break;
4123 }
4124 }
4125
4126 data << uint32(missingItem); // first missing item
4127 }
4128 break;
4129 }
4131 if (param1)
4132 data << uint32(*param1);
4133 else
4134 data << uint32(spellInfo->Mechanic);
4135 break;
4137 if (param1)
4138 data << uint32(*param1);
4139 else
4140 data << uint32(spellInfo->EquippedItemSubClassMask);
4141 break;
4143 if (param1 && param2)
4144 {
4145 data << uint32(*param1);
4146 data << uint32(*param2);
4147 }
4148 else
4149 {
4150 data << uint32(0); // Item entry
4151 data << uint32(0); // Count
4152 }
4153 break;
4155 if (param1 && param2)
4156 {
4157 data << uint32(*param1);
4158 data << uint32(*param2);
4159 }
4160 else
4161 {
4162 data << uint32(0); // SkillLine.dbc Id
4163 data << uint32(0); // Amount
4164 }
4165 break;
4167 if (param1)
4168 data << uint32(*param1);
4169 else
4170 data << uint32(0); // Skill level
4171 break;
4172 default:
4173 break;
4174 }
4175}
4176
4177void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
4178{
4179 if (result == SPELL_CAST_OK)
4180 return;
4181
4182 WorldPacket data(SMSG_CAST_FAILED, 1 + 4 + 1);
4183 WriteCastResultInfo(data, caster, spellInfo, castCount, result, customError, param1, param2);
4184
4185 caster->SendDirectMessage(&data);
4186}
4187
4188void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
4189{
4190 if (result == SPELL_CAST_OK)
4191 return;
4192
4194 return;
4195
4196 if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time
4197 return;
4198
4200 result = SPELL_FAILED_DONT_REPORT;
4201
4203}
4204
4206{
4207 if (result == SPELL_CAST_OK)
4208 return;
4209
4210 Unit* owner = m_caster->GetCharmerOrOwner();
4211 if (!owner)
4212 return;
4213
4214 Player* player = owner->ToPlayer();
4215 if (!player)
4216 return;
4217
4219 result = SPELL_FAILED_DONT_REPORT;
4220
4221 WorldPacket data(SMSG_PET_CAST_FAILED, 1 + 4 + 1);
4223
4224 player->SendDirectMessage(&data);
4225}
4226
4228{
4229 if (result == MountResult::Ok)
4230 return;
4231
4233 return;
4234
4235 Player* caster = m_caster->ToPlayer();
4236 if (caster->IsLoading()) // don't send mount results at loading time
4237 return;
4238
4240 packet.Result = AsUnderlyingType(result);
4241 caster->SendDirectMessage(packet.Write());
4242}
4243
4245{
4246 if (!IsNeedSendToClient())
4247 return;
4248
4249 //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id={}", m_spellInfo->Id);
4250
4251 uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
4252 uint32 schoolImmunityMask = 0;
4253 uint32 mechanicImmunityMask = 0;
4254 if (Unit* unitCaster = m_caster->ToUnit())
4255 {
4256 schoolImmunityMask = m_timer!= 0 ? unitCaster->GetSchoolImmunityMask() : 0;
4257 mechanicImmunityMask = m_timer != 0 ? m_spellInfo->GetMechanicImmunityMask(unitCaster) : 0;
4258 }
4259
4260 if (schoolImmunityMask || mechanicImmunityMask)
4261 castFlags |= CAST_FLAG_IMMUNITY;
4262
4264 castFlags |= CAST_FLAG_PENDING;
4265
4267 castFlags |= CAST_FLAG_AMMO;
4268 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4271 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4272
4274 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4275
4277 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4278
4279 if (m_CastItem)
4280 castData.CasterGUID = m_CastItem->GetGUID();
4281 else
4282 castData.CasterGUID = m_caster->GetGUID();
4283
4284 castData.CasterUnit = m_caster->GetGUID();
4285 castData.CastID = m_cast_count;
4286 castData.SpellID = m_spellInfo->Id;
4287 castData.CastFlags = castFlags;
4288 castData.CastTime = m_timer;
4289
4290 m_targets.Write(castData.Target);
4291
4292 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4294
4295 if (castFlags & CAST_FLAG_AMMO)
4296 {
4297 castData.Ammo.emplace();
4298 UpdateSpellCastDataAmmo(*castData.Ammo);
4299 }
4300
4301 if (castFlags & CAST_FLAG_IMMUNITY)
4302 {
4303 castData.Immunities.emplace();
4304 castData.Immunities->School = schoolImmunityMask;
4305 castData.Immunities->Value = mechanicImmunityMask;
4306 }
4307
4308 m_caster->SendMessageToSet(packet.Write(), true);
4309}
4310
4312{
4313 // not send invisible spell casting
4314 if (!IsNeedSendToClient())
4315 return;
4316
4317 uint32 castFlags = CAST_FLAG_UNKNOWN_9;
4318
4319 // triggered spells with spell visual != 0
4321 castFlags |= CAST_FLAG_PENDING;
4322
4324 castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
4325
4326 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4329 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4330
4331 if ((m_caster->GetTypeId() == TYPEID_PLAYER)
4336 {
4337 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4338 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4339 }
4340
4342 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4343
4344 if (m_targets.HasTraj())
4345 castFlags |= CAST_FLAG_ADJUST_MISSILE;
4346
4348 castFlags |= CAST_FLAG_NO_GCD;
4349
4351 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4352
4353 if (m_CastItem)
4354 castData.CasterGUID = m_CastItem->GetGUID();
4355 else
4356 castData.CasterGUID = m_caster->GetGUID();
4357
4358 castData.CasterUnit = m_caster->GetGUID();
4359 castData.CastID = m_cast_count;
4360 castData.SpellID = m_spellInfo->Id;
4361 castData.CastFlags = castFlags;
4362 castData.CastTime = GameTime::GetGameTimeMS();
4363
4365
4366 m_targets.Write(castData.Target);
4367
4368 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4370
4371 if (castFlags & CAST_FLAG_RUNE_LIST && !m_spellInfo->HasAura(SPELL_AURA_CONVERT_RUNE)) // rune cooldowns list
4372 {
4373 castData.RemainingRunes.emplace();
4374
4376 // The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
4377 if (Player* player = m_caster->ToPlayer())
4378 {
4379 uint8 runeMaskInitial = m_runesState;
4380 uint8 runeMaskAfterCast = player->GetRunesState();
4381 castData.RemainingRunes->Start = runeMaskInitial; // runes state before
4382 castData.RemainingRunes->Count = runeMaskAfterCast; // runes state after
4383
4384 for (uint8 i = 0; i < MAX_RUNES; ++i)
4385 {
4386 uint8 mask = (1 << i);
4387 if ((mask & runeMaskInitial) && !(mask & runeMaskAfterCast)) // usable before and on cooldown now...
4388 {
4389 // float casts ensure the division is performed on floats as we need float result
4390 float baseCd = float(player->GetRuneBaseCooldown(i));
4391 castData.RemainingRunes->Cooldowns.push_back(uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255));
4392 }
4393 }
4394 }
4395 }
4396
4397 if (castFlags & CAST_FLAG_ADJUST_MISSILE)
4398 {
4399 castData.MissileTrajectory.emplace();
4400 castData.MissileTrajectory->Pitch = m_targets.GetElevation();
4401 castData.MissileTrajectory->TravelTime = m_delayMoment;
4402 }
4403
4404 if (castFlags & CAST_FLAG_AMMO)
4405 UpdateSpellCastDataAmmo(castData.Ammo.emplace());
4406
4408 castData.DestLocSpellCastIndex.emplace();
4409
4411 castData.TargetPoints.emplace();
4412
4413 // should be sent to self only
4414 if (castFlags & CAST_FLAG_POWER_LEFT_SELF && m_caster->IsPlayer())
4415 {
4417
4418 packet.Clear();
4419
4420 // update nearby players (remove flag)
4421 castData.CastFlags &= ~CAST_FLAG_POWER_LEFT_SELF;
4422 castData.RemainingPower = std::nullopt;
4423 m_caster->SendMessageToSet(packet.Write(), false);
4424 }
4425 else
4426 m_caster->SendMessageToSet(packet.Write(), true);
4427}
4428
4430{
4431 uint32 ammoInventoryType = 0;
4432 uint32 ammoDisplayID = 0;
4433
4435 {
4437 if (pItem)
4438 {
4439 ammoInventoryType = pItem->GetTemplate()->InventoryType;
4440 if (ammoInventoryType == INVTYPE_THROWN)
4441 ammoDisplayID = pItem->GetTemplate()->DisplayInfoID;
4442 else
4443 {
4445 if (ammoID)
4446 {
4447 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(ammoID);
4448 if (pProto)
4449 {
4450 ammoDisplayID = pProto->DisplayInfoID;
4451 ammoInventoryType = pProto->InventoryType;
4452 }
4453 }
4454 else if (m_caster->ToPlayer()->HasAura(46699)) // Requires No Ammo
4455 {
4456 ammoDisplayID = 5996; // normal arrow
4457 ammoInventoryType = INVTYPE_AMMO;
4458 }
4459 }
4460 }
4461 }
4462 else if (Unit const* unitCaster = m_caster->ToUnit())
4463 {
4464 uint32 nonRangedAmmoDisplayID = 0;
4465 uint32 nonRangedAmmoInventoryType = 0;
4466 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
4467 {
4468 if (uint32 item_id = unitCaster->GetVirtualItemId(i))
4469 {
4470 if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
4471 {
4472 if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
4473 {
4474 switch (itemEntry->SubclassID)
4475 {
4477 ammoDisplayID = itemEntry->DisplayInfoID;
4478 ammoInventoryType = itemEntry->InventoryType;
4479 break;
4482 ammoDisplayID = 5996; // is this need fixing?
4483 ammoInventoryType = INVTYPE_AMMO;
4484 break;
4486 ammoDisplayID = 5998; // is this need fixing?
4487 ammoInventoryType = INVTYPE_AMMO;
4488 break;
4489 default:
4490 nonRangedAmmoDisplayID = itemEntry->DisplayInfoID;
4491 nonRangedAmmoInventoryType = itemEntry->InventoryType;
4492 break;
4493 }
4494
4495 if (ammoDisplayID)
4496 break;
4497 }
4498 }
4499 }
4500 }
4501
4502 if (!ammoDisplayID && !ammoInventoryType)
4503 {
4504 ammoDisplayID = nonRangedAmmoDisplayID;
4505 ammoInventoryType = nonRangedAmmoInventoryType;
4506 }
4507 }
4508
4509 ammo.DisplayID = ammoDisplayID;
4510 ammo.InventoryType = ammoInventoryType;
4511}
4512
4515{
4516 // This function also fill data for channeled spells:
4517 // m_needAliveTargetMask req for stop channelig if one target die
4518 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
4519 {
4520 if (targetInfo.EffectMask == 0) // No effect apply - all immuned add state
4521 // possibly SPELL_MISS_IMMUNE2 for this??
4522 targetInfo.MissCondition = SPELL_MISS_IMMUNE2;
4523
4524 if (targetInfo.MissCondition == SPELL_MISS_NONE || (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))) // Add only hits and partial blocked
4525 {
4526 data.HitTargets->push_back(targetInfo.TargetGUID);
4527
4528 m_channelTargetEffectMask |= targetInfo.EffectMask;
4529 }
4530 else // misses
4531 {
4532 // Only send blocks in spell_go packets if we know that the spell is not going to do anything to the target.
4533 // Spells that are partially blocked will send their block result in their according combat log packet.
4534 if (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))
4535 continue;
4536
4538 missStatus.TargetGUID = targetInfo.TargetGUID;
4539 missStatus.Reason = targetInfo.MissCondition;
4540 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
4541 missStatus.ReflectStatus = targetInfo.ReflectResult;
4542
4543 data.MissStatus->push_back(missStatus);
4544 }
4545 }
4546
4547 for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo)
4548 data.HitTargets->push_back(targetInfo.TargetGUID); // Always hits
4549
4550 for (CorpseTargetInfo const& targetInfo : m_UniqueCorpseTargetInfo)
4551 data.HitTargets->push_back(targetInfo.TargetGUID); // Always hits
4552
4553 // Reset m_needAliveTargetMask for non channeled spell
4554 if (!m_spellInfo->IsChanneled())
4556}
4557
4559{
4560 WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8));
4561
4562 data << m_caster->GetPackGUID();
4563
4564 data << uint32(m_spellInfo->Id);
4565
4566 uint8 effCount = 0;
4567 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
4568 {
4569 if (m_effectExecuteData[i])
4570 ++effCount;
4571 }
4572
4573 if (!effCount)
4574 return;
4575
4576 data << uint32(effCount);
4577 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
4578 {
4579 if (!m_effectExecuteData[spellEffectInfo.EffectIndex])
4580 continue;
4581
4582 data << uint32(spellEffectInfo.Effect); // spell effect
4583
4584 data.append(*m_effectExecuteData[spellEffectInfo.EffectIndex]);
4585
4586 delete m_effectExecuteData[spellEffectInfo.EffectIndex];
4587 m_effectExecuteData[spellEffectInfo.EffectIndex] = nullptr;
4588 }
4589 m_caster->SendMessageToSet(&data, true);
4590}
4591
4592void Spell::ExecuteLogEffectTakeTargetPower(uint8 effIndex, Unit* target, uint32 powerType, uint32 powerTaken, float gainMultiplier)
4593{
4594 InitEffectExecuteData(effIndex);
4595 *m_effectExecuteData[effIndex] << target->GetPackGUID();
4596 *m_effectExecuteData[effIndex] << uint32(powerTaken);
4597 *m_effectExecuteData[effIndex] << uint32(powerType);
4598 *m_effectExecuteData[effIndex] << float(gainMultiplier);
4599}
4600
4601void Spell::ExecuteLogEffectExtraAttacks(uint8 effIndex, Unit* victim, uint32 attCount)
4602{
4603 InitEffectExecuteData(effIndex);
4604 *m_effectExecuteData[effIndex] << victim->GetPackGUID();
4605 *m_effectExecuteData[effIndex] << uint32(attCount);
4606}
4607
4609{
4610 InitEffectExecuteData(effIndex);
4611 *m_effectExecuteData[effIndex] << victim->GetPackGUID();
4612 *m_effectExecuteData[effIndex] << uint32(spellId);
4613}
4614
4615void Spell::ExecuteLogEffectDurabilityDamage(uint8 effIndex, Unit* victim, int32 itemId, int32 slot)
4616{
4617 InitEffectExecuteData(effIndex);
4618 *m_effectExecuteData[effIndex] << victim->GetPackGUID();
4619 *m_effectExecuteData[effIndex] << int32(itemId);
4620 *m_effectExecuteData[effIndex] << int32(slot);
4621}
4622
4624{
4625 InitEffectExecuteData(effIndex);
4626 *m_effectExecuteData[effIndex] << obj->GetPackGUID();
4627}
4628
4630{
4631 InitEffectExecuteData(effIndex);
4632 *m_effectExecuteData[effIndex] << uint32(entry);
4633}
4634
4636{
4637 InitEffectExecuteData(effIndex);
4638 *m_effectExecuteData[effIndex] << uint32(entry);
4639}
4640
4642{
4643 InitEffectExecuteData(effIndex);
4644 *m_effectExecuteData[effIndex] << obj->GetPackGUID();
4645}
4646
4648{
4649 InitEffectExecuteData(effIndex);
4650 *m_effectExecuteData[effIndex] << obj->GetPackGUID();
4651}
4652
4654{
4655 InitEffectExecuteData(effIndex);
4656 *m_effectExecuteData[effIndex] << target->GetPackGUID();
4657}
4658
4660{
4661 WorldPacket data(SMSG_SPELL_FAILURE, 8 + 1 + 4 + 1);
4662 data << m_caster->GetPackGUID();
4663 data << uint8(m_cast_count);
4664 data << uint32(m_spellInfo->Id);
4665 data << uint8(result);
4666 m_caster->SendMessageToSet(&data, true);
4667
4668 data.Initialize(SMSG_SPELL_FAILED_OTHER, 8 + 1 + 4 + 1);
4669 data << m_caster->GetPackGUID();
4670 data << uint8(m_cast_count);
4671 data << uint32(m_spellInfo->Id);
4672 data << uint8(resultOther.value_or(result));
4673 m_caster->SendMessageToSet(&data, true);
4674}
4675
4677{
4678 // GameObjects don't channel
4679 Unit* unitCaster = m_caster->ToUnit();
4680 if (!unitCaster)
4681 return;
4682
4683 if (time == 0)
4684 {
4686 unitCaster->SetChannelSpellId(0);
4687 }
4688
4690 data << unitCaster->GetPackGUID();
4691 data << uint32(time);
4692
4693 unitCaster->SendMessageToSet(&data, true);
4694}
4695
4697{
4698 // GameObjects don't channel
4699 Unit* unitCaster = m_caster->ToUnit();
4700 if (!unitCaster)
4701 return;
4702
4703 ObjectGuid channelTarget = m_targets.HasDst() ? unitCaster->GetGUID() : m_targets.GetObjectTargetGUID();
4704 if (!channelTarget && !m_spellInfo->NeedsExplicitUnitTarget())
4705 if (m_UniqueTargetInfo.size() + m_UniqueGOTargetInfo.size() == 1) // this is for TARGET_SELECT_CATEGORY_NEARBY
4706 channelTarget = !m_UniqueTargetInfo.empty() ? m_UniqueTargetInfo.front().TargetGUID : m_UniqueGOTargetInfo.front().TargetGUID;
4707
4708 WorldPacket data(MSG_CHANNEL_START, (8+4+4));
4709 data << unitCaster->GetPackGUID();
4710 data << uint32(m_spellInfo->Id);
4711 data << uint32(duration);
4712
4713 unitCaster->SendMessageToSet(&data, true);
4714
4715 m_timer = duration;
4716 if (!channelTarget.IsEmpty())
4717 {
4718 unitCaster->SetChannelObjectGuid(channelTarget);
4719
4720 if (Creature* creatureCaster = m_caster->ToCreature())
4721 if (!creatureCaster->HasSpellFocus(this))
4722 creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, channelTarget));
4723 }
4724
4725 unitCaster->SetChannelSpellId(m_spellInfo->Id);
4726}
4727
4729{
4730 // get resurrector name for creature resurrections, otherwise packet will be not accepted
4731 // for player resurrections the name is looked up by guid
4732 std::string sentName;
4735
4736 WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + sentName.size() + 1 + 1 + 1);
4737 data << m_caster->GetGUID();
4738 data << uint32(sentName.size() + 1);
4739 data << sentName;
4740 data << uint8(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsSpiritHealer()); // "you'll be afflicted with resurrection sickness"
4741 // override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
4743 target->SendDirectMessage(&data);
4744}
4745
4747{
4748 if (!m_CastItem)
4749 return;
4750
4751 Player* player = m_caster->ToPlayer();
4752 if (!player)
4753 return;
4754
4755 // not remove cast item at triggered spell (equipping, weapon damage, etc)
4757 return;
4758
4759 ItemTemplate const* proto = m_CastItem->GetTemplate();
4760
4761 if (!proto)
4762 {
4763 // This code is to avoid a crash
4764 // I'm not sure, if this is really an error, but I guess every item needs a prototype
4765 TC_LOG_ERROR("spells", "Cast item has no item prototype {}", m_CastItem->GetGUID().ToString());
4766 return;
4767 }
4768
4769 bool expendable = false;
4770 bool withoutCharges = false;
4771
4772 for (int i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
4773 {
4774 ItemEffect const& itemEffect = proto->Effects[i];
4775 if (itemEffect.SpellID > 0)
4776 {
4777 // item has limited charges
4778 if (itemEffect.Charges)
4779 {
4780 if (itemEffect.Charges < 0)
4781 expendable = true;
4782
4783 int32 charges = m_CastItem->GetSpellCharges(i);
4784
4785 // item has charges left for this slot
4786 if (charges && itemEffect.SpellID == int32(m_spellInfo->Id))
4787 {
4788 (charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
4789 if (proto->Stackable == 1)
4790 m_CastItem->SetSpellCharges(i, charges);
4792 }
4793
4794 // all charges used
4795 withoutCharges = (charges == 0);
4796 }
4797 }
4798 }
4799
4800 if (expendable && withoutCharges)
4801 {
4802 uint32 count = 1;
4803 m_caster->ToPlayer()->DestroyItemCount(m_CastItem, count, true);
4804
4805 // prevent crash at access to deleted m_targets.GetItemTarget
4807 m_targets.SetItemTarget(nullptr);
4808
4809 m_CastItem = nullptr;
4811 m_castItemEntry = 0;
4812 }
4813}
4814
4816{
4817 // GameObjects don't use power
4818 Unit* unitCaster = m_caster->ToUnit();
4819 if (!unitCaster)
4820 return;
4821
4823 return;
4824
4825 //Don't take power if the spell is cast while .cheat power is enabled.
4826 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4827 {
4828 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
4829 return;
4830 }
4831
4832 Powers powerType = Powers(m_spellInfo->PowerType);
4833 bool hit = true;
4834 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4835 {
4836 if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNE)
4837 {
4838 ObjectGuid targetGUID = m_targets.GetUnitTargetGUID();
4839 if (!targetGUID.IsEmpty())
4840 {
4841 auto ihit = std::find_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [&](TargetInfo const& targetInfo) { return targetInfo.TargetGUID == targetGUID && targetInfo.MissCondition != SPELL_MISS_NONE; });
4842 if (ihit != std::end(m_UniqueTargetInfo))
4843 {
4844 hit = false;
4845 //lower spell cost on fail (by talent aura)
4846 if (Player* modOwner = unitCaster->ToPlayer()->GetSpellModOwner())
4848 }
4849 }
4850 }
4851 }
4852
4853 if (powerType == POWER_RUNE)
4854 {
4855 TakeRunePower(hit);
4856 return;
4857 }
4858
4859 if (!m_powerCost)
4860 return;
4861
4862 // health as power used
4863 if (powerType == POWER_HEALTH)
4864 {
4865 unitCaster->ModifyHealth(-(int32)m_powerCost);
4866 return;
4867 }
4868
4869 if (powerType >= MAX_POWERS)
4870 {
4871 TC_LOG_ERROR("spells", "Spell::TakePower: Unknown power type '{}'", powerType);
4872 return;
4873 }
4874
4875 unitCaster->ModifyPower(powerType, -m_powerCost);
4876
4877 // Set the five second timer
4878 if (powerType == POWER_MANA && m_powerCost > 0)
4880}
4881
4883{
4884 // Only players use ammo
4885 Player* player = m_caster->ToPlayer();
4886 if (!player)
4887 return;
4888
4889 // only ranged
4891 return;
4892
4893 // wands don't have ammo
4894 Item* item = player->GetWeaponForAttack(RANGED_ATTACK);
4895 if (!item || item->IsBroken() || item->GetTemplate()->SubClass == ITEM_SUBCLASS_WEAPON_WAND)
4896 return;
4897
4899 {
4900 if (item->GetMaxStackCount() == 1)
4901 {
4902 // decrease durability for non-stackable throw weapon
4904 }
4905 else
4906 {
4907 // decrease items amount for stackable throw weapon
4908 uint32 count = 1;
4909 player->DestroyItemCount(item, count, true);
4910 }
4911 }
4912 else if (uint32 ammo = player->GetUInt32Value(PLAYER_AMMO_ID))
4913 player->DestroyItemCount(ammo, 1, true);
4914}
4915
4917{
4918 if (m_spellInfo->PowerType != POWER_RUNE || !runeCostID)
4919 return SPELL_CAST_OK;
4920
4921 Player* player = m_caster->ToPlayer();
4922 if (!player)
4923 return SPELL_CAST_OK;
4924
4925 if (player->GetClass() != CLASS_DEATH_KNIGHT)
4926 return SPELL_CAST_OK;
4927
4928 SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(runeCostID);
4929 if (!src)
4930 return SPELL_CAST_OK;
4931
4932 if (src->NoRuneCost())
4933 return SPELL_CAST_OK;
4934
4935 int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
4936
4937 for (uint32 i = 0; i < RUNE_DEATH; ++i)
4938 {
4939 runeCost[i] = src->RuneCost[i];
4940 if (Player* modOwner = m_caster->GetSpellModOwner())
4941 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], const_cast<Spell*>(this));
4942 }
4943
4944 runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
4945
4946 for (uint32 i = 0; i < MAX_RUNES; ++i)
4947 {
4948 RuneType rune = player->GetCurrentRune(i);
4949 if ((player->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0))
4950 runeCost[rune]--;
4951 }
4952
4953 for (uint32 i = 0; i < RUNE_DEATH; ++i)
4954 if (runeCost[i] > 0)
4955 runeCost[RUNE_DEATH] += runeCost[i];
4956
4957 if (runeCost[RUNE_DEATH] > MAX_RUNES)
4958 return SPELL_FAILED_NO_POWER; // not sure if result code is correct
4959
4960 return SPELL_CAST_OK;
4961}
4962
4963void Spell::TakeRunePower(bool didHit)
4964{
4966 return;
4967
4968 SpellRuneCostEntry const* runeCostData = sSpellRuneCostStore.LookupEntry(m_spellInfo->RuneCostID);
4969 if (!runeCostData || (runeCostData->NoRuneCost() && runeCostData->NoRunicPowerGain()))
4970 return;
4971
4972 Player* player = m_caster->ToPlayer();
4973 m_runesState = player->GetRunesState(); // store previous state
4974
4975 int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
4976
4977 for (uint32 i = 0; i < RUNE_DEATH; ++i)
4978 {
4979 runeCost[i] = runeCostData->RuneCost[i];
4980 if (Player* modOwner = m_caster->GetSpellModOwner())
4981 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
4982 }
4983
4984 // Let's say we use a skill that requires a Frost rune. This is the order:
4985 // - Frost rune
4986 // - Death rune, originally a Frost rune
4987 // - Death rune, any kind
4988 runeCost[RUNE_DEATH] = 0; // calculated later
4989 for (uint32 i = 0; i < MAX_RUNES; ++i)
4990 {
4991 RuneType rune = player->GetCurrentRune(i);
4992 if (!player->GetRuneCooldown(i) && runeCost[rune] > 0)
4993 {
4994 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown(i) : uint32(RUNE_MISS_COOLDOWN), true);
4995 player->SetLastUsedRune(rune);
4996 runeCost[rune]--;
4997 }
4998 }
4999
5000 // Find a Death rune where the base rune matches the one we need
5001 runeCost[RUNE_DEATH] = runeCost[RUNE_BLOOD] + runeCost[RUNE_UNHOLY] + runeCost[RUNE_FROST];
5002 if (runeCost[RUNE_DEATH] > 0)
5003 {
5004 for (uint32 i = 0; i < MAX_RUNES; ++i)
5005 {
5006 RuneType rune = player->GetCurrentRune(i);
5007 RuneType baseRune = player->GetBaseRune(i);
5008 if (!player->GetRuneCooldown(i) && rune == RUNE_DEATH && runeCost[baseRune] > 0)
5009 {
5010 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown(i) : uint32(RUNE_MISS_COOLDOWN), true);
5011 player->SetLastUsedRune(rune);
5012 runeCost[baseRune]--;
5013 runeCost[rune]--;
5014
5015 // keep Death Rune type if missed
5016 if (didHit)
5017 player->RestoreBaseRune(i);
5018
5019 if (runeCost[RUNE_DEATH] == 0)
5020 break;
5021 }
5022 }
5023 }
5024
5025 // Grab any Death rune
5026 if (runeCost[RUNE_DEATH] > 0)
5027 {
5028 for (uint32 i = 0; i < MAX_RUNES; ++i)
5029 {
5030 RuneType rune = player->GetCurrentRune(i);
5031 if (!player->GetRuneCooldown(i) && rune == RUNE_DEATH)
5032 {
5033 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown(i) : uint32(RUNE_MISS_COOLDOWN), true);
5034 player->SetLastUsedRune(rune);
5035 runeCost[rune]--;
5036
5037 // keep Death Rune type if missed
5038 if (didHit)
5039 player->RestoreBaseRune(i);
5040
5041 if (runeCost[RUNE_DEATH] == 0)
5042 break;
5043 }
5044 }
5045 }
5046
5047 // you can gain some runic power when use runes
5048 if (didHit)
5049 if (int32 rp = int32(runeCostData->RunicPower * sWorld->getRate(RATE_POWER_RUNICPOWER_INCOME)))
5050 player->ModifyPower(POWER_RUNIC_POWER, int32(rp));
5051}
5052
5054{
5056 return;
5057
5058 ItemTemplate const* castItemTemplate = m_CastItem ? m_CastItem->GetTemplate() : nullptr;
5059
5060 // do not take reagents for these item casts
5061 if (castItemTemplate && castItemTemplate->HasFlag(ITEM_FLAG_NO_REAGENT_COST))
5062 return;
5063
5064 Player* p_caster = m_caster->ToPlayer();
5065 if (p_caster->CanNoReagentCast(m_spellInfo))
5066 return;
5067
5068 for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
5069 {
5070 if (m_spellInfo->Reagent[x] <= 0)
5071 continue;
5072
5073 uint32 itemid = m_spellInfo->Reagent[x];
5074 uint32 itemcount = m_spellInfo->ReagentCount[x];
5075
5076 // if CastItem is also spell reagent
5077 if (castItemTemplate && castItemTemplate->ItemId == itemid)
5078 {
5079 for (int s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
5080 {
5081 // CastItem will be used up and does not count as reagent
5082 int32 charges = ASSERT_NOTNULL(m_CastItem)->GetSpellCharges(s);
5083 if (castItemTemplate->Effects[s].Charges < 0 && abs(charges) < 2)
5084 {
5085 ++itemcount;
5086 break;
5087 }
5088 }
5089
5090 m_CastItem = nullptr;
5092 m_castItemEntry = 0;
5093 }
5094
5095 // if GetItemTarget is also spell reagent
5096 if (m_targets.GetItemTargetEntry() == itemid)
5097 m_targets.SetItemTarget(nullptr);
5098
5099 p_caster->DestroyItemCount(itemid, itemcount, true);
5100 }
5101}
5102
5104{
5105 // wild GameObject spells don't cause threat
5106 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
5107 if (!unitCaster)
5108 return;
5109
5110 if (m_UniqueTargetInfo.empty())
5111 return;
5112
5114 return;
5115
5116 float threat = 0.0f;
5117 if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
5118 {
5119 if (threatEntry->apPctMod != 0.0f)
5120 threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
5121
5122 threat += threatEntry->flatMod;
5123 }
5125 threat += m_spellInfo->SpellLevel;
5126
5127 // past this point only multiplicative effects occur
5128 if (threat == 0.0f)
5129 return;
5130
5131 // 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
5132 threat /= m_UniqueTargetInfo.size();
5133
5134 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
5135 {
5136 float threatToAdd = threat;
5137 if (ihit->MissCondition != SPELL_MISS_NONE)
5138 threatToAdd = 0.0f;
5139
5140 Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit->TargetGUID);
5141 if (!target)
5142 continue;
5143
5144 // positive spells distribute threat among all units that are in combat with target, like healing
5145 if (IsPositive())
5146 target->GetThreatManager().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
5147 // for negative spells threat gets distributed among affected targets
5148 else
5149 {
5150 if (!target->CanHaveThreatList())
5151 continue;
5152
5153 target->GetThreatManager().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
5154 }
5155 }
5156 TC_LOG_DEBUG("spells", "Spell {}, added an additional {} threat for {} {} target(s)", m_spellInfo->Id, threat, IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
5157}
5158
5159void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
5160{
5161 effectHandleMode = mode;
5162 unitTarget = pUnitTarget;
5163 itemTarget = pItemTarget;
5164 gameObjTarget = pGoTarget;
5165 m_corpseTarget = pCorpseTarget;
5166 destTarget = &m_destTargets[spellEffectInfo.EffectIndex]._position;
5167 effectInfo = &spellEffectInfo;
5168
5169 // we do not need ChainAmplitude here.
5170 damage = CalculateDamage(spellEffectInfo);
5171
5172 bool preventDefault = CallScriptEffectHandlers(spellEffectInfo.EffectIndex, mode);
5173
5174 if (!preventDefault)
5175 (this->*SpellEffectHandlers[spellEffectInfo.Effect])();
5176}
5177
5178SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
5179{
5180 // check death state
5183
5184 // 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
5186 {
5189 }
5190
5191 // check cooldowns to prevent cheating
5192 if (!m_spellInfo->IsPassive())
5193 {
5195 {
5196 //can cast triggered (by aura only?) spells while have this flag
5199
5200 // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
5203 }
5204
5206 {
5209 else
5211 }
5212 }
5213
5215 {
5218 }
5219
5220 // Check global cooldown
5223
5224 // only triggered spells can be processed an ended battleground
5227 if (bg->GetStatus() == STATUS_WAIT_LEAVE)
5229
5231 {
5233 !m_caster->IsOutdoors())
5235
5239 }
5240
5241 if (Unit* unitCaster = m_caster->ToUnit())
5242 {
5243 // only check at first call, Stealth auras are already removed at second call
5244 // for now, ignore triggered spells
5246 {
5247 bool checkForm = true;
5248 // Ignore form req aura
5249 Unit::AuraEffectList const& ignore = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
5250 for (AuraEffect const* aurEff : ignore)
5251 {
5252 if (!aurEff->IsAffectingSpell(m_spellInfo))
5253 continue;
5254
5255 checkForm = false;
5256 break;
5257 }
5258
5259 if (checkForm)
5260 {
5261 // Cannot be used in this stance/form
5262 SpellCastResult shapeError = m_spellInfo->CheckShapeshift(unitCaster->GetShapeshiftForm());
5263 if (shapeError != SPELL_CAST_OK)
5264 return shapeError;
5265
5266 if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(unitCaster->HasStealthAura()))
5268 }
5269 }
5270
5271 if (unitCaster->HasAuraTypeWithMiscvalue(SPELL_AURA_BLOCK_SPELL_FAMILY, m_spellInfo->SpellFamilyName))
5273
5274 bool reqCombat = true;
5275 Unit::AuraEffectList const& stateAuras = unitCaster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
5276 for (Unit::AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
5277 {
5278 if ((*j)->IsAffectingSpell(m_spellInfo))
5279 {
5280 m_needComboPoints = false;
5281 if ((*j)->GetMiscValue() == 1)
5282 {
5283 reqCombat = false;
5284 break;
5285 }
5286 }
5287 }
5288
5289 // caster state requirements
5290 // not for triggered spells (needed by execute)
5292 {
5293 if (m_spellInfo->CasterAuraState && !unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, unitCaster))
5295 if (m_spellInfo->ExcludeCasterAuraState && unitCaster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, unitCaster))
5297
5298 // Note: spell 62473 requres casterAuraSpell = triggering spell
5299 if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->CasterAuraSpell, unitCaster)))
5301 if (m_spellInfo->ExcludeCasterAuraSpell && unitCaster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeCasterAuraSpell, unitCaster)))
5303
5304 if (reqCombat && unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat())
5306 }
5307
5308 // cancel autorepeat spells if cast start when moving
5309 // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
5310 if (unitCaster->GetTypeId() == TYPEID_PLAYER && unitCaster->ToPlayer()->isMoving() && (!unitCaster->IsCharmed() || !unitCaster->GetCharmerGUID().IsCreature()))
5311 {
5312 // skip stuck spell to allow use it in falling case and apply spell limitations at movement
5313 if ((!unitCaster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || !m_spellInfo->HasEffect(SPELL_EFFECT_STUCK)) &&
5315 return SPELL_FAILED_MOVING;
5316 }
5317
5318 if (unitCaster->IsCharmed() && m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED))
5319 return SPELL_FAILED_CHARMED;
5320
5321 // Check vehicle flags
5323 {
5324 SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(unitCaster);
5325 if (vehicleCheck != SPELL_CAST_OK)
5326 return vehicleCheck;
5327 }
5328 }
5329
5330 // check spell cast conditions from database
5331 {
5333 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL, m_spellInfo->Id, condInfo))
5334 {
5335 // mLastFailedCondition can be NULL if there was an error processing the condition in Condition::Meets (i.e. wrong data for ConditionTarget or others)
5336 if (condInfo.mLastFailedCondition && condInfo.mLastFailedCondition->ErrorType)
5337 {
5341 }
5342
5343 if (!condInfo.mLastFailedCondition || !condInfo.mLastFailedCondition->ConditionTarget)
5346 }
5347 }
5348
5349 // Don't check explicit target for passive spells (workaround) (check should be skipped only for learn case)
5350 // those spells may have incorrect target entries or not filled at all (for example 15332)
5351 // such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
5352 // also, such casts shouldn't be sent to client
5354 {
5355 // Check explicit target for m_originalCaster - todo: get rid of such workarounds
5356 WorldObject* caster = m_caster;
5357 // in case of gameobjects like traps, we need the gameobject itself to check target validity
5358 // otherwise, if originalCaster is far away and cannot detect the target, the trap would not hit the target
5359 if (m_originalCaster && !caster->ToGameObject())
5360 caster = m_originalCaster;
5361
5363 if (castResult != SPELL_CAST_OK)
5364 return castResult;
5365 }
5366
5367 if (Unit* target = m_targets.GetUnitTarget())
5368 {
5369 SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetTypeId() == TYPEID_GAMEOBJECT); // skip stealth checks for GO casts
5370 if (castResult != SPELL_CAST_OK)
5371 return castResult;
5372
5373 if (target != m_caster)
5374 {
5375 // Must be behind the target
5376 if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
5378
5379 // Target must be facing you
5380 if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
5382
5383 // Ignore LOS for gameobjects casts
5385 {
5386 WorldObject* losTarget = m_caster;
5389 losTarget = dynObj;
5390
5393 }
5394 }
5395 }
5396
5397 // Check for line of sight for spells with dest
5398 if (m_targets.HasDst())
5399 {
5400 float x, y, z;
5401 m_targets.GetDstPos()->GetPosition(x, y, z);
5402
5405 }
5406
5407 // check pet presence
5408 if (Unit* unitCaster = m_caster->ToUnit())
5409 {
5410 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5411 {
5412 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
5413 {
5414 if (!unitCaster->GetGuardianPet())
5415 {
5416 if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
5418 else
5419 return SPELL_FAILED_NO_PET;
5420 }
5421 break;
5422 }
5423 }
5424 }
5425
5426 // Spell cast only in battleground
5428 if (!m_caster->ToPlayer()->InBattleground())
5430
5431 // do not allow spells to be cast in arenas
5432 if (Player* player = m_caster->ToPlayer())
5433 if (player->InArena())
5434 {
5435 SpellCastResult castResult = CheckArenaCastRules();
5436 if (castResult != SPELL_CAST_OK)
5437 return castResult;
5438 }
5439
5440 // zone check
5442 {
5443 uint32 zone, area;
5444 m_caster->GetZoneAndAreaId(zone, area);
5445
5447 if (locRes != SPELL_CAST_OK)
5448 return locRes;
5449 }
5450
5451 // not let players cast spells at mount (and let do it to creatures)
5453 {
5455 {
5456 if (m_caster->ToPlayer()->IsInFlight())
5458 else
5460 }
5461 }
5462
5463 // check spell focus object
5465 {
5467 if (focusObject)
5469 else
5471 }
5472
5473 SpellCastResult castResult = SPELL_CAST_OK;
5474
5475 // always (except passive spells) check items (only player related checks)
5476 if (!m_spellInfo->IsPassive())
5477 {
5478 castResult = CheckItems(param1, param2);
5479 if (castResult != SPELL_CAST_OK)
5480 return castResult;
5481 }
5482
5483 // Triggered spells also have range check
5485 castResult = CheckRange(strict);
5486 if (castResult != SPELL_CAST_OK)
5487 return castResult;
5488
5490 {
5491 castResult = CheckPower();
5492 if (castResult != SPELL_CAST_OK)
5493 return castResult;
5494 }
5495
5497 {
5498 castResult = CheckCasterAuras(param1);
5499 if (castResult != SPELL_CAST_OK)
5500 return castResult;
5501 }
5502
5503 // script hook
5504 castResult = CallScriptCheckCastHandlers();
5505 if (castResult != SPELL_CAST_OK)
5506 return castResult;
5507
5508 bool hasDispellableAura = false;
5509 bool hasNonDispelEffect = false;
5510 uint32 dispelMask = 0;
5511 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5512 {
5513 if (spellEffectInfo.Effect == SPELL_EFFECT_DISPEL)
5514 {
5515 if (spellEffectInfo.IsTargetingArea() || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START))
5516 {
5517 hasDispellableAura = true;
5518 break;
5519 }
5520
5521 dispelMask |= SpellInfo::GetDispelMask(DispelType(spellEffectInfo.MiscValue));
5522 }
5523 else if (spellEffectInfo.IsEffect())
5524 {
5525 hasNonDispelEffect = true;
5526 break;
5527 }
5528 }
5529
5530 if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered())
5531 {
5532 if (Unit* target = m_targets.GetUnitTarget())
5533 {
5534 if (Unit* unitCaster = m_caster->ToUnit())
5535 {
5536 // do not allow to cast on hostile targets in sanctuary
5537 if (!unitCaster->IsFriendlyTo(target))
5538 {
5539 if (unitCaster->IsInSanctuary() || target->IsInSanctuary())
5540 {
5541 // fix for duels
5542 Player* player = unitCaster->ToPlayer();
5543 if (!player || !player->duel || target != player->duel->Opponent)
5545 }
5546 }
5547
5548 DispelChargesList dispelList;
5549 target->GetDispellableAuraList(unitCaster, dispelMask, dispelList);
5550 if (dispelList.empty())
5552 }
5553 }
5554 }
5555
5556 uint8 approximateAuraEffectMask = 0;
5557 uint8 nonAuraEffectMask = 0;
5558 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5559 {
5560 // for effects of spells that have only one target
5561 switch (spellEffectInfo.Effect)
5562 {
5564 {
5567
5568 if (spellEffectInfo.TargetA.GetTarget() != TARGET_UNIT_PET)
5569 break;
5570
5571 Pet* pet = m_caster->ToPlayer()->GetPet();
5572 if (!pet)
5573 return SPELL_FAILED_NO_PET;
5574
5575 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell);
5576 if (!learn_spellproto)
5578
5579 if (m_spellInfo->SpellLevel > pet->GetLevel())
5580 return SPELL_FAILED_LOWLEVEL;
5581
5582 break;
5583 }
5585 {
5586 // check target only for unit target case
5587 if (Unit* unit = m_targets.GetUnitTarget())
5588 {
5591
5592 Pet* pet = unit->ToPet();
5593 if (!pet || pet->GetOwner() != m_caster)
5595
5596 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell);
5597
5598 if (!learn_spellproto)
5600
5601 if (m_spellInfo->SpellLevel > pet->GetLevel())
5602 return SPELL_FAILED_LOWLEVEL;
5603 }
5604 break;
5605 }
5607 {
5610
5611 uint32 glyphId = spellEffectInfo.MiscValue;
5612 if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId))
5613 if (m_caster->ToPlayer()->HasAura(gp->SpellID))
5615 break;
5616 }
5618 {
5621
5622 Item* foodItem = m_targets.GetItemTarget();
5623 if (!foodItem)
5625
5626 Pet* pet = m_caster->ToPlayer()->GetPet();
5627 if (!pet)
5628 return SPELL_FAILED_NO_PET;
5629
5630 if (!pet->HaveInDiet(foodItem->GetTemplate()))
5632
5633 if (!pet->GetCurrentFoodBenefitLevel(foodItem->GetTemplate()->ItemLevel))
5635
5636 if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
5638
5639 break;
5640 }
5643 {
5644 // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects)
5646 if (Unit* target = m_targets.GetUnitTarget())
5647 if (target != m_caster && target->GetPowerType() != Powers(spellEffectInfo.MiscValue))
5649 break;
5650 }
5652 {
5653 Unit* unitCaster = m_caster->ToUnit();
5654 if (!unitCaster)
5656
5658 {
5659 // Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process
5660 if (strict && unitCaster->IsScriptOverriden(m_spellInfo, 6953))
5661 unitCaster->RemoveMovementImpairingAuras(true);
5662 }
5663
5665 return SPELL_FAILED_ROOTED;
5666
5668 {
5669 Unit* target = m_targets.GetUnitTarget();
5670 if (!target)
5672
5673 // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
5674 if (!target->IsWithinLOSInMap(unitCaster)) //Do full LoS/Path check. Don't exclude m2
5676
5677 float objSize = target->GetCombatReach();
5678 float range = m_spellInfo->GetMaxRange(true, unitCaster, this) * 1.5f + objSize; // can't be overly strict
5679
5680 m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
5681 m_preGeneratedPath->SetPathLengthLimit(range);
5682
5683 // first try with raycast, if it fails fall back to normal path
5684 bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
5685 if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
5686 return SPELL_FAILED_NOPATH;
5687 else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
5688 return SPELL_FAILED_NOPATH;
5689 else if (m_preGeneratedPath->IsInvalidDestinationZ(target)) // Check position z, if not in a straight line
5690 return SPELL_FAILED_NOPATH;
5691
5692 m_preGeneratedPath->ShortenPathUntilDist(PositionToVector3(target), objSize); // move back
5693 }
5694 break;
5695 }
5697 {
5700
5703
5704 Creature* creature = m_targets.GetUnitTarget()->ToCreature();
5705 if (!creature->IsCritter() && !creature->loot.isLooted())
5707
5708 uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
5709
5710 int32 skillValue = m_caster->ToPlayer()->GetSkillValue(skill);
5711 int32 TargetLevel = m_targets.GetUnitTarget()->GetLevel();
5712 int32 ReqValue = (skillValue < 100 ? (TargetLevel-10) * 10 : TargetLevel * 5);
5713 if (ReqValue > skillValue)
5715
5716 break;
5717 }
5719 {
5720 if (spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET &&
5721 spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET)
5722 break;
5723
5724 if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc.
5725 // we need a go target in case of TARGET_GAMEOBJECT_TARGET
5726 || (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget()))
5728
5729 Item* pTempItem = nullptr;
5731 {
5732 if (TradeData* pTrade = m_caster->ToPlayer()->GetTradeData())
5733 pTempItem = pTrade->GetTraderData()->GetItem(TradeSlots(m_targets.GetItemTargetGUID().GetRawValue())); // at this point item target guid contains the trade slot
5734 }
5737
5738 // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
5739 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET &&
5741 (!pTempItem || !pTempItem->GetTemplate()->LockID || !pTempItem->IsLocked()))
5743
5744 if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
5746 if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners
5749
5750 // get the lock entry
5751 uint32 lockId = 0;
5752 if (GameObject* go = m_targets.GetGOTarget())
5753 {
5754 lockId = go->GetGOInfo()->GetLockId();
5755 if (!lockId)
5757 }
5758 else if (Item* itm = m_targets.GetItemTarget())
5759 lockId = itm->GetTemplate()->LockID;
5760
5761 SkillType skillId = SKILL_NONE;
5762 int32 reqSkillValue = 0;
5763 int32 skillValue = 0;
5764
5765 // check lock compatibility
5766 SpellCastResult res = CanOpenLock(spellEffectInfo, lockId, skillId, reqSkillValue, skillValue);
5767 if (res != SPELL_CAST_OK)
5768 return res;
5769
5770 // chance for fail at lockpicking attempt
5771 // second check prevent fail at rechecks
5772 // herbalism and mining cannot fail as of patch 3.1.0
5773 if (skillId != SKILL_NONE && skillId != SKILL_HERBALISM && skillId != SKILL_MINING && (!m_selfContainer || ((*m_selfContainer) != this)))
5774 {
5775 bool canFailAtMax = skillId == SKILL_LOCKPICKING;
5776
5777 // chance for failure in orange lockpick
5778 if ((canFailAtMax || skillValue < sWorld->GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37))
5780 }
5781 break;
5782 }
5784 {
5785 Unit* unitCaster = m_caster->ToUnit();
5786 if (!unitCaster)
5788
5789 Creature* pet = unitCaster->GetGuardianPet();
5790 if (pet && pet->IsAlive())
5792 break;
5793 }
5794 // This is generic summon effect
5796 {
5797 Unit* unitCaster = m_caster->ToUnit();
5798 if (!unitCaster)
5799 break;
5800
5801 SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(spellEffectInfo.MiscValueB);
5802 if (!SummonProperties)
5803 break;
5804
5805 switch (SummonProperties->Control)
5806 {
5810 [[fallthrough]]; // check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
5812 if (!unitCaster->GetCharmedGUID().IsEmpty())
5814 break;
5815 }
5816 break;
5817 }
5819 {
5821 {
5826 }
5827 break;
5828 }
5830 {
5831 Unit* unitCaster = m_caster->ToUnit();
5832 if (!unitCaster)
5834
5835 if (!unitCaster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
5836 {
5837 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5838 {
5839 if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
5840 if (Pet* pet = unitCaster->ToPlayer()->GetPet())
5841 pet->CastSpell(pet, 32752, pet->GetGUID());
5842 }
5845 }
5846
5847 if (!unitCaster->GetCharmedGUID().IsEmpty())
5849
5850 Player* playerCaster = unitCaster->ToPlayer();
5851 if (playerCaster && playerCaster->GetPetStable())
5852 {
5853 std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, false);
5854 if (info.first)
5855 {
5856 if (info.first->Type == HUNTER_PET)
5857 {
5858 if (!info.first->Health)
5859 {
5860 playerCaster->SendTameFailure(PETTAME_DEAD);
5862 }
5863
5864 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(info.first->CreatureId);
5865 if (!creatureInfo || !creatureInfo->IsTameable(playerCaster->CanTameExoticPets()))
5866 {
5867 // if problem in exotic pet
5868 if (creatureInfo && creatureInfo->IsTameable(true))
5870 else
5872
5874 }
5875 }
5876 }
5877 else if (!spellEffectInfo.MiscValue) // when miscvalue is present it is allowed to create new pets
5878 {
5881 }
5882 }
5883
5884 break;
5885 }
5887 {
5890
5891 if (!m_caster->ToPlayer()->GetTarget())
5893
5895 if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell
5897
5898 if (target->HasSummonPending())
5900
5901 // check if our map is dungeon
5902 MapEntry const* map = sMapStore.LookupEntry(m_caster->GetMapId());
5903 if (map->IsDungeon())
5904 {
5905 uint32 mapId = m_caster->GetMap()->GetId();
5906 Difficulty difficulty = m_caster->GetMap()->GetDifficulty();
5907 if (map->IsRaid())
5908 if (InstancePlayerBind* targetBind = target->GetBoundInstance(mapId, difficulty))
5909 if (InstancePlayerBind* casterBind = m_caster->ToPlayer()->GetBoundInstance(mapId, difficulty))
5910 if (targetBind->perm && targetBind->save != casterBind->save)
5912
5913 InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(mapId);
5914 if (!instance)
5916 }
5917 break;
5918 }
5919 // RETURN HERE
5921 {
5924
5925 Player* playerCaster = m_caster->ToPlayer();
5926 if (!playerCaster->GetTarget())
5928
5929 Player* target = playerCaster->GetSelectedPlayer();
5930 if (!target ||
5931 !(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
5933 break;
5934 }
5935 case SPELL_EFFECT_LEAP:
5937 {
5938 //Do not allow to cast it before BG starts.
5940 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
5941 if (bg->GetStatus() != STATUS_IN_PROGRESS)
5943 break;
5944 }
5946 {
5949
5950 dispelMask = SpellInfo::GetDispelMask(DispelType(spellEffectInfo.MiscValue));
5951 bool hasStealableAura = false;
5953 for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras.begin(); itr != visibleAuras.end(); ++itr)
5954 {
5955 if (!itr->second->IsPositive())
5956 continue;
5957
5958 Aura const* aura = itr->second->GetBase();
5959 if (!(aura->GetSpellInfo()->GetDispelMask() & dispelMask))
5960 continue;
5961
5963 continue;
5964
5965 hasStealableAura = true;
5966 break;
5967 }
5968
5969 if (!hasStealableAura)
5971
5972 break;
5973 }
5975 {
5976 Unit* unitCaster = m_caster->ToUnit();
5977 if (!unitCaster)
5979
5980 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
5981 {
5982 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5983 return SPELL_FAILED_ROOTED;
5984 else
5986 }
5987 break;
5988 }
5989 case SPELL_EFFECT_JUMP:
5991 {
5992 Unit* unitCaster = m_caster->ToUnit();
5993 if (!unitCaster)
5995
5996 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
5997 return SPELL_FAILED_ROOTED;
5998 break;
5999 }
6001 // can't change during already started arena/battleground
6003 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
6004 if (bg->GetStatus() == STATUS_IN_PROGRESS)
6006 break;
6007 default:
6008 break;
6009 }
6010
6011 if (spellEffectInfo.IsAura())
6012 approximateAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6013 else if (spellEffectInfo.IsEffect())
6014 nonAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
6015 }
6016
6017 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6018 {
6019 switch (spellEffectInfo.ApplyAuraName)
6020 {
6022 {
6024 return SPELL_FAILED_NO_PET;
6025
6026 Pet* pet = m_caster->ToPlayer()->GetPet();
6027 if (!pet)
6028 return SPELL_FAILED_NO_PET;
6029
6030 if (!pet->GetCharmerGUID().IsEmpty())
6032 break;
6033 }
6037 {
6038 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6039 if (!unitCaster)
6041
6042 if (!unitCaster->GetCharmerGUID().IsEmpty())
6043 return SPELL_FAILED_CHARMED;
6044
6045 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_CHARM
6046 || spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_POSSESS)
6047 {
6050
6051 if (!unitCaster->GetCharmedGUID().IsEmpty())
6053 }
6054
6055 if (Unit* target = m_targets.GetUnitTarget())
6056 {
6057 if (target->GetTypeId() == TYPEID_UNIT && target->IsVehicle())
6059
6060 if (target->IsMounted())
6062
6063 if (!target->GetCharmerGUID().IsEmpty())
6065
6066 if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER)
6068
6069 int32 value = CalculateDamage(spellEffectInfo);
6070 if (value && int32(target->GetLevel()) > value)
6072 }
6073
6074 break;
6075 }
6076 case SPELL_AURA_MOUNTED:
6077 {
6078 Unit* unitCaster = m_caster->ToUnit();
6079 if (!unitCaster)
6081
6084
6085 // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
6086 bool allowMount = !unitCaster->GetMap()->IsDungeon() || unitCaster->GetMap()->IsBattlegroundOrArena();
6087 InstanceTemplate const* it = sObjectMgr->GetInstanceTemplate(unitCaster->GetMapId());
6088 if (it)
6089 allowMount = it->AllowMount;
6090 if (unitCaster->GetTypeId() == TYPEID_PLAYER && !allowMount && !m_spellInfo->RequiredAreasID)
6092
6093 if (unitCaster->IsInDisallowedMountForm())
6094 {
6095 SendMountResult(MountResult::Shapeshifted); // mount result gets sent before the cast result
6097 }
6098 break;
6099 }
6101 {
6102 if (!m_targets.GetUnitTarget())
6104
6105 // can be cast at non-friendly unit or own pet/charm
6108 break;
6109 }
6110 case SPELL_AURA_FLY:
6112 {
6113 // not allow cast fly spells if not have req. skills (all spells is self target)
6114 // allow always ghost flight spells
6116 {
6117 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId());
6118 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId()))
6119 if (area->Flags & AREA_FLAG_NO_FLY_ZONE || (Bf && !Bf->CanFlyIn()))
6120 return SPELL_FAILED_NOT_HERE;
6121 }
6122 break;
6123 }
6125 {
6126 if (spellEffectInfo.IsTargetingArea())
6127 break;
6128
6129 if (!m_targets.GetUnitTarget())
6131
6133 break;
6134
6137 break;
6138 }
6139 default:
6140 break;
6141 }
6142
6143 // check if target already has the same type, but more powerful aura
6144 if (!nonAuraEffectMask && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex)) && !m_spellInfo->IsTargetingArea())
6145 if (Unit* target = m_targets.GetUnitTarget())
6146 if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, AuraType(spellEffectInfo.ApplyAuraName),
6147 spellEffectInfo.CalcValue(m_caster, &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex]), approximateAuraEffectMask, false))
6149 }
6150
6151 // check trade slot case (last, for allow catch any another cast problems)
6153 {
6154 if (m_CastItem)
6156
6159
6160 TradeData* my_trade = m_caster->ToPlayer()->GetTradeData();
6161 if (!my_trade)
6163
6164 // Item target guid contains trade slot until m_targets.UpdateTradeSlotItem() is called
6166 if (slot != TRADE_SLOT_NONTRADED)
6168
6169 if (!IsTriggered())
6170 if (my_trade->GetSpell())
6172 }
6173
6174 // check if caster has at least 1 combo point on target for spells that require combo points
6176 {
6177 if (Unit* unitCaster = m_caster->ToUnit())
6178 {
6180 {
6181 if (!unitCaster->GetComboPoints(m_targets.GetUnitTarget()))
6183 }
6184 else
6185 {
6186 if (!unitCaster->GetComboPoints())
6188 }
6189 }
6190 }
6191
6192 // all ok
6193 return SPELL_CAST_OK;
6194}
6195
6197{
6198 Unit* unitCaster = m_caster->ToUnit();
6199 if (unitCaster && unitCaster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
6201
6202 // dead owner (pets still alive when owners ressed?)
6203 if (Unit* owner = m_caster->GetCharmerOrOwner())
6204 if (!owner->IsAlive() && !owner->IsGhouled())
6206
6207 if (!target && m_targets.GetUnitTarget())
6208 target = m_targets.GetUnitTarget();
6209
6211 {
6212 if (!target)
6214 m_targets.SetUnitTarget(target);
6215 }
6216
6217 // check power requirement
6218 // this would be zero until ::prepare normally, we set it here (it gets reset in ::prepare)
6220 SpellCastResult failReason = CheckPower();
6221 if (failReason != SPELL_CAST_OK)
6222 return failReason;
6223
6224 // check cooldown
6225 if (Creature* creatureCaster = m_caster->ToCreature())
6226 if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
6228
6229 // Check if spell is affected by GCD
6231 if (unitCaster && unitCaster->GetCharmInfo() && unitCaster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
6233
6234 return CheckCast(true);
6235}
6236
6238{
6239 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6240 if (!unitCaster)
6241 return SPELL_CAST_OK;
6242
6243 // spells totally immuned to caster auras (wsg flag drop, give marks etc)
6245 return SPELL_CAST_OK;
6246
6247 // these attributes only show the spell as usable on the client when it has related aura applied
6248 // still they need to be checked against certain mechanics
6249
6250 // SPELL_ATTR5_USABLE_WHILE_STUNNED by default only MECHANIC_STUN (ie no sleep, knockout, freeze, etc.)
6251 bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
6252
6253 // SPELL_ATTR5_USABLE_WHILE_FEARED by default only fear (ie no horror)
6254 bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED);
6255
6256 // SPELL_ATTR5_USABLE_WHILE_CONFUSED by default only disorient (ie no polymorph)
6257 bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED);
6258
6259 // Glyph of Pain Suppression
6260 // there is no other way to handle it
6261 if (m_spellInfo->Id == 33206 && !unitCaster->HasAura(63248))
6262 usableWhileStunned = false;
6263
6264 // Check whether the cast should be prevented by any state you might have.
6266
6267 // Get unit state
6268 uint32 const unitflag = unitCaster->GetUnitFlags();
6269
6270 if (m_fromClient && unitCaster->IsCharmed() && unitCaster->IsPlayer() && !CheckSpellCancelsCharm(param1))
6271 result = SPELL_FAILED_CHARMED;
6272
6273 // spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell
6274 auto mechanicCheck = [&](AuraType type) -> SpellCastResult
6275 {
6276 bool foundNotMechanic = false;
6277 Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
6278 for (AuraEffect const* aurEff : auras)
6279 {
6280 uint32 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
6281 if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask()))
6282 {
6283 foundNotMechanic = true;
6284
6285 // fill up aura mechanic info to send client proper error message
6286 if (param1)
6287 {
6288 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6289 if (!*param1)
6290 *param1 = aurEff->GetSpellInfo()->Mechanic;
6291 }
6292
6293 break;
6294 }
6295 }
6296
6297 if (foundNotMechanic)
6298 {
6299 switch (type)
6300 {
6302 return SPELL_FAILED_STUNNED;
6304 return SPELL_FAILED_FLEEING;
6306 return SPELL_FAILED_CONFUSED;
6307 default:
6308 ABORT();
6310 }
6311 }
6312
6313 return SPELL_CAST_OK;
6314 };
6315
6316 if (unitflag & UNIT_FLAG_STUNNED)
6317 {
6318 if (usableWhileStunned)
6319 {
6320 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN);
6321 if (mechanicResult != SPELL_CAST_OK)
6322 result = mechanicResult;
6323 }
6324 else if (!CheckSpellCancelsStun(param1))
6325 result = SPELL_FAILED_STUNNED;
6327 result = SPELL_FAILED_STUNNED;
6328 }
6330 result = SPELL_FAILED_SILENCED;
6332 result = SPELL_FAILED_PACIFIED;
6333 else if (unitflag & UNIT_FLAG_FLEEING)
6334 {
6335 if (usableWhileFeared)
6336 {
6337 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_FEAR);
6338 if (mechanicResult != SPELL_CAST_OK)
6339 result = mechanicResult;
6340 }
6341 else if (!CheckSpellCancelsFear(param1))
6342 result = SPELL_FAILED_FLEEING;
6343 }
6344 else if (unitflag & UNIT_FLAG_CONFUSED)
6345 {
6346 if (usableWhileConfused)
6347 {
6348 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_CONFUSE);
6349 if (mechanicResult != SPELL_CAST_OK)
6350 result = mechanicResult;
6351 }
6352 else if (!CheckSpellCancelsConfuse(param1))
6353 result = SPELL_FAILED_CONFUSED;
6354 }
6355
6356 // Attr must make flag drop spell totally immune from all effects
6357 if (result != SPELL_CAST_OK)
6358 return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
6359
6360 return SPELL_CAST_OK;
6361}
6362
6364{
6365 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6366 if (!unitCaster)
6367 return false;
6368
6369 // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
6370 Unit::AuraEffectList const& auraEffects = unitCaster->GetAuraEffectsByType(auraType);
6371 if (auraEffects.empty())
6372 return true;
6373
6374 for (AuraEffect const* aurEff : auraEffects)
6375 {
6376 SpellInfo const* auraInfo = aurEff->GetSpellInfo();
6378 continue;
6379
6380 if (param1)
6381 {
6382 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6383 if (!*param1)
6384 *param1 = auraInfo->Mechanic;
6385 }
6386
6387 return false;
6388 }
6389
6390 return true;
6391}
6392
6399
6405
6411
6417
6419{
6421}
6422
6427
6428int32 Spell::CalculateDamage(SpellEffectInfo const& spellEffectInfo) const
6429{
6430 return m_caster->CalculateSpellDamage(spellEffectInfo, m_spellValue->EffectBasePoints + spellEffectInfo.EffectIndex);
6431}
6432
6434{
6435 // check USABLE attributes
6436 // USABLE takes precedence over NOT_USABLE
6438 return SPELL_CAST_OK;
6439
6440 // check NOT_USABLE attributes
6443
6444 // check cooldowns
6445 uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
6446 if (spellCooldown > 10 * MINUTE * IN_MILLISECONDS) // not sure if still needed
6448
6449 return SPELL_CAST_OK;
6450}
6451
6453{
6454 if (IsTriggered())
6455 return SPELL_CAST_OK;
6456
6458 {
6459 if (m_casttime > 0)
6461 return SPELL_FAILED_MOVING;
6462 }
6463 else if (getState() == SPELL_STATE_CASTING)
6465 return SPELL_FAILED_MOVING;
6466
6467 return SPELL_CAST_OK;
6468}
6469
6471{
6472 if (!target)
6473 return (CheckPetCast(target) == SPELL_CAST_OK);
6474
6475 ObjectGuid targetguid = target->GetGUID();
6476
6477 // check if target already has the same or a more powerful aura
6478 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6479 {
6480 if (!spellEffectInfo.IsAura())
6481 continue;
6482
6483 AuraType const& auraType = spellEffectInfo.ApplyAuraName;
6484 Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
6485 for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
6486 {
6487 if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
6488 return false;
6489
6490 switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
6491 {
6493 return false;
6495 if (GetCaster() == (*auraIt)->GetCaster())
6496 return false;
6497 break;
6498 case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
6500 if (abs(spellEffectInfo.BasePoints) <= abs((*auraIt)->GetAmount()))
6501 return false;
6502 break;
6504 default:
6505 break;
6506 }
6507 }
6508 }
6509
6510 SpellCastResult result = CheckPetCast(target);
6511 if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
6512 {
6513 // do not check targets for ground-targeted spells (we target them on top of the intended target anyway)
6514 if (GetSpellInfo()->ExplicitTargetMask & TARGET_FLAG_DEST_LOCATION)
6515 return true;
6517 //check if among target units, our WANTED target is as well (->only self cast spells return false)
6518 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
6519 if (ihit->TargetGUID == targetguid)
6520 return true;
6521 }
6522 // either the cast failed or the intended target wouldn't be hit
6523 return false;
6524}
6525
6527{
6528 if (!m_targets.HasSrc())
6530}
6531
6533{
6534 if (!m_targets.HasDst())
6536}
6537
6539{
6540 // Don't check for instant cast spells
6541 if (!strict && m_casttime == 0)
6542 return SPELL_CAST_OK;
6543
6544 float minRange, maxRange;
6545 std::tie(minRange, maxRange) = GetMinMaxRange(strict);
6546
6547 // dont check max_range to strictly after cast
6549 maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
6550
6551 // get square values for sqr distance checks
6552 minRange *= minRange;
6553 maxRange *= maxRange;
6554
6555 Unit* target = m_targets.GetUnitTarget();
6556 if (target && target != m_caster)
6557 {
6558 if (m_caster->GetExactDistSq(target) > maxRange)
6560
6561 if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange)
6563
6564 if (m_caster->GetTypeId() == TYPEID_PLAYER &&
6565 (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
6567 }
6568
6569 if (GameObject* goTarget = m_targets.GetGOTarget())
6570 {
6571 if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
6573 }
6574
6575 if (m_targets.HasDst() && !m_targets.HasTraj())
6576 {
6577 if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange)
6579 if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange)
6581 }
6582
6583 return SPELL_CAST_OK;
6584}
6585
6586std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
6587{
6588 float rangeMod = 0.0f;
6589 float minRange = 0.0f;
6590 float maxRange = 0.0f;
6591
6592 if (strict && m_spellInfo->IsNextMeleeSwingSpell())
6593 return { 0.0f, 100.0f };
6594
6595 Unit* unitCaster = m_caster->ToUnit();
6597 {
6598 Unit* target = m_targets.GetUnitTarget();
6600 {
6601 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
6602 if (unitCaster)
6603 rangeMod = unitCaster->GetMeleeRange(target ? target : unitCaster);
6604 }
6605 else
6606 {
6607 float meleeRange = 0.0f;
6609 {
6610 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
6611 if (unitCaster)
6612 meleeRange = unitCaster->GetMeleeRange(target ? target : unitCaster);
6613 }
6614
6615 minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
6616 maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
6617
6618 if (target || m_targets.GetCorpseTarget())
6619 {
6620 rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
6621
6622 if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
6623 minRange += rangeMod;
6624 }
6625 }
6626
6627 if (target && unitCaster && unitCaster->isMoving() && target->isMoving() && !unitCaster->IsWalking() && !target->IsWalking() &&
6629 rangeMod += 8.0f / 3.0f;
6630 }
6631
6633 if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
6634 maxRange *= ranged->GetTemplate()->RangedModRange * 0.01f;
6635
6636 if (Player* modOwner = m_caster->GetSpellModOwner())
6637 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, const_cast<Spell*>(this));
6638
6639 maxRange += rangeMod;
6640
6641 return { minRange, maxRange };
6642}
6643
6645{
6646 Unit* unitCaster = m_caster->ToUnit();
6647 if (!unitCaster)
6648 return SPELL_CAST_OK;
6649
6650 // item cast not used power
6651 if (m_CastItem)
6652 return SPELL_CAST_OK;
6653
6654 // health as power used - need check health amount
6656 {
6657 if (int32(unitCaster->GetHealth()) <= m_powerCost)
6659 return SPELL_CAST_OK;
6660 }
6661 // Check valid power type
6663 {
6664 TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '{}'", m_spellInfo->PowerType);
6665 return SPELL_FAILED_UNKNOWN;
6666 }
6667
6668 //check rune cost only if a spell has PowerType == POWER_RUNE
6670 {
6672 if (failReason != SPELL_CAST_OK)
6673 return failReason;
6674 }
6675
6676 // Check power amount
6677 Powers powerType = m_spellInfo->PowerType;
6678 if (int32(unitCaster->GetPower(powerType)) < m_powerCost)
6679 return SPELL_FAILED_NO_POWER;
6680 else
6681 return SPELL_CAST_OK;
6682}
6683
6684SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
6685{
6686 Player* player = m_caster->ToPlayer();
6687 if (!player)
6688 return SPELL_CAST_OK;
6689
6690 if (!m_CastItem)
6691 {
6692 if (!m_castItemGUID.IsEmpty())
6694 }
6695 else
6696 {
6697 uint32 itemid = m_CastItem->GetEntry();
6698 if (!player->HasItemCount(itemid))
6700
6701 ItemTemplate const* proto = m_CastItem->GetTemplate();
6702 if (!proto)
6704
6705 for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
6706 if (proto->Effects[i].Charges)
6707 if (m_CastItem->GetSpellCharges(i) == 0)
6709
6710 // consumable cast item checks
6712 {
6713 // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
6714 SpellCastResult failReason = SPELL_CAST_OK;
6715 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6716 {
6717 // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster
6718 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
6719 continue;
6720
6721 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
6722 {
6724 {
6726 continue;
6727 }
6728 else
6729 {
6730 failReason = SPELL_CAST_OK;
6731 break;
6732 }
6733 }
6734
6735 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
6736 if (spellEffectInfo.IsEffect(SPELL_EFFECT_ENERGIZE))
6737 {
6738 if (spellEffectInfo.MiscValue < 0 || spellEffectInfo.MiscValue >= int8(MAX_POWERS))
6739 {
6741 continue;
6742 }
6743
6744 Powers power = Powers(spellEffectInfo.MiscValue);
6746 {
6748 continue;
6749 }
6750 else
6751 {
6752 failReason = SPELL_CAST_OK;
6753 break;
6754 }
6755 }
6756 }
6757 if (failReason != SPELL_CAST_OK)
6758 return failReason;
6759 }
6760 }
6761
6762 // check target item
6764 {
6765 Item* item = m_targets.GetItemTarget();
6766 if (!item)
6768
6771 }
6772 // if not item target then required item must be equipped
6773 else
6774 {
6778 }
6779
6780 // do not take reagents for these item casts
6782 {
6784 // Not own traded item (in trader trade slot) requires reagents even if triggered spell
6785 if (!checkReagents)
6786 if (Item* targetItem = m_targets.GetItemTarget())
6787 if (targetItem->GetOwnerGUID() != player->GetGUID())
6788 checkReagents = true;
6789
6790 // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
6791 if (checkReagents)
6792 {
6793 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
6794 {
6795 if (m_spellInfo->Reagent[i] <= 0)
6796 continue;
6797
6798 uint32 itemid = m_spellInfo->Reagent[i];
6799 uint32 itemcount = m_spellInfo->ReagentCount[i];
6800
6801 // if CastItem is also spell reagent
6802 if (m_CastItem && m_CastItem->GetEntry() == itemid)
6803 {
6804 ItemTemplate const* proto = m_CastItem->GetTemplate();
6805 if (!proto)
6807 for (uint8 s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
6808 {
6809 // CastItem will be used up and does not count as reagent
6810 int32 charges = m_CastItem->GetSpellCharges(s);
6811 if (proto->Effects[s].Charges < 0 && abs(charges) < 2)
6812 {
6813 ++itemcount;
6814 break;
6815 }
6816 }
6817 }
6818 if (!player->HasItemCount(itemid, itemcount))
6819 {
6820 if (param1)
6821 *param1 = itemid;
6822 return SPELL_FAILED_REAGENTS;
6823 }
6824 }
6825 }
6826
6827 // check totem-item requirements (items presence in inventory)
6828 uint32 totems = 2;
6829 for (uint8 i = 0; i < 2; ++i)
6830 {
6831 if (m_spellInfo->Totem[i] != 0)
6832 {
6833 if (player->HasItemCount(m_spellInfo->Totem[i]))
6834 {
6835 totems -= 1;
6836 continue;
6837 }
6838 }
6839 else
6840 totems -= 1;
6841 }
6842 if (totems != 0)
6843 return SPELL_FAILED_TOTEMS; //0x7C
6844
6845 // Check items for TotemCategory (items presence in inventory)
6847 for (uint8 i = 0; i < 2; ++i)
6848 {
6849 if (m_spellInfo->TotemCategory[i] != 0)
6850 {
6852 {
6853 TotemCategory -= 1;
6854 continue;
6855 }
6856 }
6857 else
6858 TotemCategory -= 1;
6859 }
6860 if (TotemCategory != 0)
6861 return SPELL_FAILED_TOTEM_CATEGORY; //0x7B
6862 }
6863
6864 // special checks for spell effects
6865 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6866 {
6867 switch (spellEffectInfo.Effect)
6868 {
6871 {
6872 // m_targets.GetUnitTarget() means explicit cast, otherwise we dont check for possible equip error
6873 Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
6874 if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered())
6875 {
6876 // 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,
6877 // so we need to make sure there is at least one free space in the player's inventory
6878 if (spellEffectInfo.IsEffect(SPELL_EFFECT_CREATE_ITEM_2))
6879 if (target->ToPlayer()->GetFreeInventorySpace() == 0)
6880 {
6881 player->SendEquipError(EQUIP_ERR_INV_FULL, nullptr, nullptr, spellEffectInfo.ItemType);
6883 }
6884
6885 if (spellEffectInfo.ItemType)
6886 {
6887 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType);
6888 if (!itemTemplate)
6890
6891 uint32 createCount = std::clamp<uint32>(spellEffectInfo.CalcValue(), 1u, itemTemplate->GetMaxStackSize());
6892 ItemPosCountVec dest;
6893 InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, createCount);
6894 if (msg != EQUIP_ERR_OK)
6895 {
6897 if (!itemTemplate->ItemLimitCategory)
6898 {
6899 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
6901 }
6902 else
6903 {
6904 // Conjure Food/Water/Refreshment spells
6907 else if (!(target->ToPlayer()->HasItemCount(spellEffectInfo.ItemType)))
6908 {
6909 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
6911 }
6912 else
6913 player->CastSpell(player, m_spellInfo->GetEffect(EFFECT_1).CalcValue(), false); // move this to anywhere
6915 }
6916 }
6917 }
6918 }
6919 break;
6920 }
6922 if (spellEffectInfo.ItemType && m_targets.GetItemTarget()
6924 {
6925 // cannot enchant vellum for other player
6926 if (m_targets.GetItemTarget()->GetOwner() != player)
6928 // do not allow to enchant vellum from scroll made by vellum-prevent exploit
6931 ItemPosCountVec dest;
6932 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, 1);
6933 if (msg != EQUIP_ERR_OK)
6934 {
6935 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
6937 }
6938 }
6939 [[fallthrough]];
6941 {
6942 Item* targetItem = m_targets.GetItemTarget();
6943 if (!targetItem)
6945
6946 // Apply item level restriction
6948 {
6949 uint32 requiredLevel = targetItem->GetTemplate()->RequiredLevel;
6950 if (!requiredLevel)
6951 requiredLevel = targetItem->GetTemplate()->ItemLevel;
6952
6953 if (requiredLevel < m_spellInfo->BaseLevel)
6954 return SPELL_FAILED_LOWLEVEL;
6955 }
6956 if (m_CastItem
6957 && m_spellInfo->MaxLevel > 0 && targetItem->GetTemplate()->ItemLevel > m_spellInfo->MaxLevel)
6959
6960 bool isItemUsable = false;
6961 ItemTemplate const* proto = targetItem->GetTemplate();
6962 for (ItemEffect const& itemEffect : proto->Effects)
6963 {
6964 if (itemEffect.SpellID > 0 && itemEffect.TriggerType == ITEM_SPELLTRIGGER_ON_USE)
6965 {
6966 isItemUsable = true;
6967 break;
6968 }
6969 }
6970
6971 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(spellEffectInfo.MiscValue);
6972 // do not allow adding usable enchantments to items that have use effect already
6973 if (enchantEntry)
6974 {
6975 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
6976 {
6977 switch (enchantEntry->Effect[s])
6978 {
6980 if (isItemUsable)
6982 break;
6984 {
6985 uint32 numSockets = 0;
6986 for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket)
6987 if (targetItem->GetTemplate()->Socket[socket].Color)
6988 ++numSockets;
6989
6990 if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
6992 break;
6993 }
6994 }
6995 }
6996 }
6997
6998 // Not allow enchant in trade slot for some enchant type
6999 if (targetItem->GetOwner() != player)
7000 {
7001 if (!enchantEntry)
7002 return SPELL_FAILED_ERROR;
7003 if (enchantEntry->Flags & ENCHANTMENT_CAN_SOULBOUND)
7005 }
7006 break;
7007 }
7009 {
7010 Item* item = m_targets.GetItemTarget();
7011 if (!item)
7013 // Not allow enchant in trade slot for some enchant type
7014 if (item->GetOwner() != player)
7015 {
7016 uint32 enchant_id = spellEffectInfo.MiscValue;
7017 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
7018 if (!pEnchant)
7019 return SPELL_FAILED_ERROR;
7020 if (pEnchant->Flags & ENCHANTMENT_CAN_SOULBOUND)
7022 }
7023
7024 // Apply item level restriction
7026 {
7027 uint32 requiredLevel = item->GetTemplate()->RequiredLevel;
7028 if (!requiredLevel)
7029 requiredLevel = item->GetTemplate()->ItemLevel;
7030
7031 if (requiredLevel < m_spellInfo->BaseLevel)
7032 return SPELL_FAILED_LOWLEVEL;
7033 }
7036 break;
7037 }
7039 // check item existence in effect code (not output errors at offhand hold item effect to main hand for example
7040 break;
7042 {
7043 if (!m_targets.GetItemTarget())
7045
7046 // prevent disenchanting in trade slot
7047 if (m_targets.GetItemTarget()->GetOwnerGUID() != player->GetGUID())
7049
7050 ItemTemplate const* itemProto = m_targets.GetItemTarget()->GetTemplate();
7051 if (!itemProto)
7053
7054 uint32 item_quality = itemProto->Quality;
7055 // 2.0.x addon: Check player enchanting level against the item disenchanting requirements
7056 uint32 item_disenchantskilllevel = itemProto->RequiredDisenchantSkill;
7057 if (item_disenchantskilllevel == uint32(-1))
7059 if (item_disenchantskilllevel > player->GetSkillValue(SKILL_ENCHANTING))
7061 if (item_quality > 4 || item_quality < 2)
7063 if (itemProto->Class != ITEM_CLASS_WEAPON && itemProto->Class != ITEM_CLASS_ARMOR)
7065 if (!itemProto->DisenchantID)
7067 break;
7068 }
7070 {
7071 Item* item = m_targets.GetItemTarget();
7072 if (!item)
7074 //ensure item is a prospectable ore
7077 //prevent prospecting in trade slot
7078 if (item->GetOwnerGUID() != player->GetGUID())
7080 //Check for enough skill in jewelcrafting
7081 uint32 item_prospectingskilllevel = item->GetTemplate()->RequiredSkillRank;
7082 if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
7084 //make sure the player has the required ores in inventory
7085 if (item->GetCount() < 5)
7086 {
7087 if (param1 && param2)
7088 {
7089 *param1 = item->GetEntry();
7090 *param2 = 5;
7091 }
7093 }
7094
7097
7098 break;
7099 }
7101 {
7102 Item* item = m_targets.GetItemTarget();
7103 if (!item)
7105 //ensure item is a millable herb
7108 //prevent milling in trade slot
7109 if (item->GetOwnerGUID() != player->GetGUID())
7111 //Check for enough skill in inscription
7112 uint32 item_millingskilllevel = item->GetTemplate()->RequiredSkillRank;
7113 if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
7115 //make sure the player has the required herbs in inventory
7116 if (item->GetCount() < 5)
7117 {
7118 if (param1 && param2)
7119 {
7120 *param1 = item->GetEntry();
7121 *param2 = 5;
7122 }
7124 }
7125
7128
7129 break;
7130 }
7133 {
7135 break;
7136
7137 Item* item = player->GetWeaponForAttack(m_attackType);
7138 if (!item || item->IsBroken())
7140
7141 switch (item->GetTemplate()->SubClass)
7142 {
7144 {
7145 uint32 const ammo = item->GetEntry();
7146 if (!player->HasItemCount(ammo))
7147 return SPELL_FAILED_NO_AMMO;
7148 break;
7149 }
7153 {
7154 uint32 const ammo = player->GetUInt32Value(PLAYER_AMMO_ID);
7155 if (!ammo)
7156 {
7157 // Requires No Ammo
7158 if (player->HasAura(46699))
7159 break; // skip other checks
7160
7161 return SPELL_FAILED_NO_AMMO;
7162 }
7163
7164 ItemTemplate const* ammoProto = sObjectMgr->GetItemTemplate(ammo);
7165 if (!ammoProto)
7166 return SPELL_FAILED_NO_AMMO;
7167
7168 if (ammoProto->Class != ITEM_CLASS_PROJECTILE)
7169 return SPELL_FAILED_NO_AMMO;
7170
7171 // check ammo ws. weapon compatibility
7172 switch (item->GetTemplate()->SubClass)
7173 {
7176 if (ammoProto->SubClass != ITEM_SUBCLASS_ARROW)
7177 return SPELL_FAILED_NO_AMMO;
7178 break;
7180 if (ammoProto->SubClass != ITEM_SUBCLASS_BULLET)
7181 return SPELL_FAILED_NO_AMMO;
7182 break;
7183 default:
7184 return SPELL_FAILED_NO_AMMO;
7185 }
7186
7187 if (!player->HasItemCount(ammo))
7188 {
7189 player->SetUInt32Value(PLAYER_AMMO_ID, 0);
7190 return SPELL_FAILED_NO_AMMO;
7191 }
7192 break;
7193 }
7195 break;
7196 default:
7197 break;
7198 }
7199 break;
7200 }
7202 {
7203 uint32 item_id = spellEffectInfo.ItemType;
7204 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item_id);
7205
7206 if (!pProto)
7208
7209 if (Item* pitem = player->GetItemByEntry(item_id))
7210 {
7211 for (int x = 0; x < MAX_ITEM_PROTO_SPELLS; ++x)
7212 if (pProto->Effects[x].Charges != 0 && pitem->GetSpellCharges(x) == pProto->Effects[x].Charges)
7214 }
7215 break;
7216 }
7217 default:
7218 break;
7219 }
7220 }
7221
7222 // check weapon presence in slots for main/offhand weapons
7224 {
7225 auto weaponCheck = [&](WeaponAttackType attackType) -> SpellCastResult
7226 {
7227 Item const* item = player->GetWeaponForAttack(attackType);
7228
7229 // skip spell if no weapon in slot or broken
7230 if (!item || item->IsBroken())
7232
7233 // skip spell if weapon not fit to triggered spell
7236
7237 return SPELL_CAST_OK;
7238 };
7239
7241 {
7242 SpellCastResult mainHandResult = weaponCheck(BASE_ATTACK);
7243 if (mainHandResult != SPELL_CAST_OK)
7244 return mainHandResult;
7245 }
7246
7248 {
7249 SpellCastResult offHandResult = weaponCheck(OFF_ATTACK);
7250 if (offHandResult != SPELL_CAST_OK)
7251 return offHandResult;
7252 }
7253 }
7254
7255 return SPELL_CAST_OK;
7256}
7257
7258void Spell::Delayed() // only called in DealDamage()
7259{
7260 Player* playerCaster = m_caster->ToPlayer();
7261 if (!playerCaster)
7262 return;
7263
7264 // spells not losing casting time
7266 return;
7267
7268 if (IsDelayableNoMore()) // Spells may only be delayed twice
7269 return;
7270
7271 //check pushback reduce
7272 int32 delaytime = 500; // spellcasting delay is normally 500ms
7273
7274 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
7275 playerCaster->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
7276 delayReduce += playerCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
7277 if (delayReduce >= 100)
7278 return;
7279
7280 AddPct(delaytime, -delayReduce);
7281
7282 if (m_timer + delaytime > m_casttime)
7283 {
7284 delaytime = m_casttime - m_timer;
7286 }
7287 else
7288 m_timer += delaytime;
7289
7291 data << playerCaster->GetPackGUID();
7292 data << uint32(delaytime);
7293
7294 playerCaster->SendMessageToSet(&data, true);
7295}
7296
7298{
7299 Player* playerCaster = m_caster->ToPlayer();
7300 if (!playerCaster)
7301 return;
7302
7304 return;
7305
7306 // spells not losing channeling time
7308 return;
7309
7310 if (IsDelayableNoMore()) // Spells may only be delayed twice
7311 return;
7312
7313 //check pushback reduce
7314 // should be affected by modifiers, not take the dbc duration.
7316
7317 int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
7318
7319 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
7320 playerCaster->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
7321 delayReduce += playerCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
7322 if (delayReduce >= 100)
7323 return;
7324
7325 AddPct(delaytime, -delayReduce);
7326
7327 if (m_timer <= delaytime)
7328 {
7329 delaytime = m_timer;
7330 m_timer = 0;
7331 }
7332 else
7333 m_timer -= delaytime;
7334
7335 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
7336 if (targetInfo.MissCondition == SPELL_MISS_NONE)
7337 if (Unit* unit = (playerCaster->GetGUID() == targetInfo.TargetGUID) ? playerCaster : ObjectAccessor::GetUnit(*playerCaster, targetInfo.TargetGUID))
7338 unit->DelayOwnedAuras(m_spellInfo->Id, m_originalCasterGUID, delaytime);
7339
7340 // partially interrupt persistent area auras
7341 if (DynamicObject* dynObj = playerCaster->GetDynObject(m_spellInfo->Id))
7342 dynObj->Delay(delaytime);
7343
7345}
7346
7348{
7351 else
7352 {
7355 m_originalCaster = nullptr;
7356 }
7357
7360
7362 {
7364 // cast item not found, somehow the item is no longer where we expected
7365 if (!m_CastItem)
7366 return false;
7367
7368 // check if the item is really the same, in case it has been wrapped for example
7370 return false;
7371 }
7372
7374
7375 // further actions done only for dest targets
7376 if (!m_targets.HasDst())
7377 return true;
7378
7379 // cache last transport
7380 WorldObject* transport = nullptr;
7381
7382 // update effect destinations (in case of moved transport dest target)
7383 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7384 {
7385 SpellDestination& dest = m_destTargets[spellEffectInfo.EffectIndex];
7386 if (!dest._transportGUID)
7387 continue;
7388
7389 if (!transport || transport->GetGUID() != dest._transportGUID)
7391
7392 if (transport)
7393 {
7394 dest._position.Relocate(transport);
7396 }
7397 }
7398
7399 return true;
7400}
7401
7403{
7405 return CURRENT_MELEE_SPELL;
7406 else if (IsAutoRepeat())
7408 else if (m_spellInfo->IsChanneled())
7410
7411 return CURRENT_GENERIC_SPELL;
7412}
7413
7414bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEffectInfo, Position const* losPosition) const
7415{
7416 switch (spellEffectInfo.ApplyAuraName)
7417 {
7422 if (target->GetVehicleKit() && target->GetVehicleKit()->IsControllableVehicle())
7423 return false;
7424 if (target->IsMounted())
7425 return false;
7426 if (!target->GetCharmerGUID().IsEmpty())
7427 return false;
7428 if (int32 value = CalculateDamage(spellEffectInfo))
7429 if ((int32)target->GetLevel() > value)
7430 return false;
7431 break;
7432 default:
7433 break;
7434 }
7435
7436 // check for ignore LOS on the effect itself
7438 return true;
7439
7440 // check if gameobject ignores LOS
7441 if (GameObject const* gobCaster = m_caster->ToGameObject())
7442 if (gobCaster->GetGOInfo()->IsIgnoringLOSChecks())
7443 return true;
7444
7445 // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
7447 return true;
7448
7450 //Check targets for LOS visibility (except spells without range limitations)
7451 switch (spellEffectInfo.Effect)
7452 {
7454 // player far away, maybe his corpse near?
7455 if (target != m_caster && !target->IsWithinLOSInMap(m_caster))
7456 {
7458 return false;
7459
7461 if (!corpse)
7462 return false;
7463
7464 if (target->GetGUID() != corpse->GetOwnerGUID())
7465 return false;
7466
7467 if (!corpse->IsWithinLOSInMap(m_caster))
7468 return false;
7469 }
7470
7471 // all ok by some way or another, skip normal check
7472 break;
7474 {
7476 {
7478 return true;
7479
7480 return false;
7481 }
7482
7484 if (!corpse)
7485 return false;
7486
7487 if (target->GetGUID() != corpse->GetOwnerGUID())
7488 return false;
7489
7491 return false;
7492
7494 return false;
7495
7496 break;
7497 }
7498 default: // normal case
7499 {
7500 if (losPosition)
7501 return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2);
7502 else
7503 {
7504 // Get GO cast coordinates if original caster -> GO
7505 WorldObject* caster = nullptr;
7508 if (!caster)
7509 caster = m_caster;
7511 return false;
7512 }
7513 break;
7514 }
7515 }
7516
7517 return true;
7518}
7519
7521{
7523}
7524
7529
7534
7536{
7538}
7539
7541{
7542 return m_caster->IsUnit() && m_caster->ToUnit()->GetChannelSpellId() != 0;
7543}
7544
7546{
7549 return false;
7550
7552 return false;
7553
7554 return true;
7555}
7556
7561
7567
7572
7573SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell)
7574{
7575}
7576
7578{
7580 m_Spell->cancel();
7581
7582 if (!m_Spell->IsDeletable())
7583 {
7584 TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.",
7585 (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id);
7586 ABORT();
7587 }
7588}
7589
7591{
7592 // update spell if it is not finished
7594 m_Spell->update(p_time);
7595
7596 // check spell state to process
7597 switch (m_Spell->getState())
7598 {
7600 {
7601 // spell was finished, check deletable state
7602 if (m_Spell->IsDeletable())
7603 {
7604 // check, if we do have unfinished triggered spells
7605 return true; // spell is deletable, finish event
7606 }
7607 // event will be re-added automatically at the end of routine)
7608 break;
7609 }
7611 {
7612 // first, check, if we have just started
7613 if (m_Spell->GetDelayStart() != 0)
7614 {
7615 // no, we aren't, do the typical update
7616 // check, if we have channeled spell on our hands
7617 /*
7618 if (m_Spell->m_spellInfo->IsChanneled())
7619 {
7620 // evented channeled spell is processed separately, cast once after delay, and not destroyed till finish
7621 // check, if we have casting anything else except this channeled spell and autorepeat
7622 if (m_Spell->GetCaster()->IsNonMeleeSpellCast(false, true, true))
7623 {
7624 // another non-melee non-delayed spell is cast now, abort
7625 m_Spell->cancel();
7626 }
7627 else
7628 {
7629 // Set last not triggered spell for apply spellmods
7630 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, true);
7631 // do the action (pass spell to channeling state)
7632 m_Spell->handle_immediate();
7633
7634 // And remove after effect handling
7635 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, false);
7636 }
7637 // event will be re-added automatically at the end of routine)
7638 }
7639 else
7640 */
7641 {
7642 // run the spell handler and think about what we can do next
7643 uint64 t_offset = e_time - m_Spell->GetDelayStart();
7644 uint64 n_offset = m_Spell->handle_delayed(t_offset);
7645 if (n_offset)
7646 {
7647 // re-add us to the queue
7648 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(m_Spell->GetDelayStart() + n_offset), false);
7649 return false; // event not complete
7650 }
7651 // event complete
7652 // finish update event will be re-added automatically at the end of routine)
7653 }
7654 }
7655 else
7656 {
7657 // delaying had just started, record the moment
7658 m_Spell->SetDelayStart(e_time);
7659 // re-plan the event for the delay moment
7660 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + m_Spell->GetDelayMoment()), false);
7661 return false; // event not complete
7662 }
7663 break;
7664 }
7665 default:
7666 {
7667 // all other states
7668 // event will be re-added automatically at the end of routine)
7669 break;
7670 }
7671 }
7672
7673 // spell processing not complete, plan event on the next update interval
7674 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + 1), false);
7675 return false; // event not complete
7676}
7677
7679{
7680 // oops, the spell we try to do is aborted
7682 m_Spell->cancel();
7683}
7684
7686{
7687 return m_Spell->IsDeletable();
7688}
7689
7690bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
7691{
7692 if (target->IsAlive())
7695 return true;
7696 return false;
7697}
7698
7700{
7701 // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode
7702 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7703 {
7704 // don't do anything for empty effect
7705 if (!spellEffectInfo.IsEffect())
7706 continue;
7707
7708 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
7709 }
7710
7712
7713 // Take ammunition if the ranged attack requires ammunition
7714 if (Player* player = m_caster->ToPlayer())
7715 {
7717 if (player->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_CONSUME_NO_AMMO, m_spellInfo))
7718 usesAmmo = false;
7719
7720 // Do not consume ammo for the triggered AoE ticks of Volley (Hunter spell)
7722 usesAmmo = false;
7723
7724 if (usesAmmo)
7725 TakeAmmo();
7726 }
7727
7728 for (TargetInfo& target : m_UniqueTargetInfo)
7729 PreprocessSpellLaunch(target);
7730
7731 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7732 {
7733 float multiplier = 1.0f;
7734 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
7735 multiplier = spellEffectInfo.CalcDamageMultiplier(m_originalCaster, this);
7736
7737 for (TargetInfo& target : m_UniqueTargetInfo)
7738 {
7739 uint32 mask = target.EffectMask;
7740 if (!(mask & (1 << spellEffectInfo.EffectIndex)))
7741 continue;
7742
7743 DoEffectOnLaunchTarget(target, multiplier, spellEffectInfo);
7744 }
7745 }
7746
7748}
7749
7751{
7752 Unit* targetUnit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
7753 if (!targetUnit)
7754 return;
7755
7756 // This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
7758 m_originalCaster->SetInCombatWith(targetUnit, true);
7759
7760 Unit* unit = nullptr;
7761 // In case spell hit target, do all effect on that target
7762 if (targetInfo.MissCondition == SPELL_MISS_NONE)
7763 unit = targetUnit;
7764 // In case spell reflect from target, do all effect on caster (if hit)
7765 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
7766 unit = m_caster->ToUnit();
7767
7768 if (!unit)
7769 return;
7770
7771 float critChance = m_spellValue->CriticalChance;
7772 if (m_originalCaster)
7773 {
7774 if (!critChance)
7777 }
7778
7779 targetInfo.IsCrit = roll_chance_f(critChance);
7780}
7781
7782void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, SpellEffectInfo const& spellEffectInfo)
7783{
7784 Unit* unit = nullptr;
7785 // In case spell hit target, do all effect on that target
7787 unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
7788 // In case spell reflect from target, do all effect on caster (if hit)
7789 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
7790 unit = m_caster->ToUnit();
7791
7792 if (!unit)
7793 return;
7794
7795 m_damage = 0;
7796 m_healing = 0;
7797
7798 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
7799
7800 if (m_originalCaster && m_damage > 0)
7801 {
7802 if (spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
7803 {
7805
7807 {
7808 // cap damage of player AOE
7809 int64 targetAmount = GetUnitTargetCountForEffect(spellEffectInfo.EffectIndex);
7810 if (targetAmount > 10)
7811 m_damage = m_damage * 10 / targetAmount;
7812 }
7813 }
7814 }
7815
7816 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
7817 {
7820
7821 m_damageMultipliers[spellEffectInfo.EffectIndex] *= multiplier;
7822 }
7823
7824 targetInfo.Damage += m_damage;
7825 targetInfo.Healing += m_healing;
7826}
7827
7828SpellCastResult Spell::CanOpenLock(SpellEffectInfo const& spellEffectInfo, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
7829{
7830 if (!lockId) // possible case for GO and maybe for items.
7831 return SPELL_CAST_OK;
7832
7833 // Get LockInfo
7834 LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
7835
7836 if (!lockInfo)
7838
7839 bool reqKey = false; // some locks not have reqs
7840
7841 for (int j = 0; j < MAX_LOCK_CASE; ++j)
7842 {
7843 switch (lockInfo->Type[j])
7844 {
7845 // check key item (many fit cases can be)
7846 case LOCK_KEY_ITEM:
7847 if (lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry() == lockInfo->Index[j])
7848 return SPELL_CAST_OK;
7849 reqKey = true;
7850 break;
7851 // check key skill (only single first fit case can be)
7852 case LOCK_KEY_SKILL:
7853 {
7854 reqKey = true;
7855
7856 // wrong locktype, skip
7857 if (uint32(spellEffectInfo.MiscValue) != lockInfo->Index[j])
7858 continue;
7859
7860 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
7861
7862 if (skillId != SKILL_NONE)
7863 {
7864 reqSkillValue = lockInfo->Skill[j];
7865
7866 // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
7867 skillValue = m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER ?
7868 0 : m_caster->ToPlayer()->GetSkillValue(skillId);
7869
7870 // skill bonus provided by casting spell (mostly item spells)
7871 // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.)
7872 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET || spellEffectInfo.TargetB.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET)
7873 skillValue += spellEffectInfo.CalcValue();
7874
7875 if (skillValue < reqSkillValue)
7877 }
7878
7879 return SPELL_CAST_OK;
7880 }
7881 case LOCK_KEY_SPELL:
7882 if (m_spellInfo->Id == lockInfo->Index[j])
7883 return SPELL_CAST_OK;
7884 reqKey = true;
7885 break;
7886 }
7887 }
7888
7889 if (reqKey)
7891
7892 return SPELL_CAST_OK;
7893}
7894
7896{
7897 switch (mod)
7898 {
7901 break;
7904 break;
7907 break;
7909 m_spellValue->RadiusMod = (float)value / 10000;
7910 break;
7913 break;
7916 break;
7919 break;
7920 }
7921}
7922
7927
7932
7934{
7935 ASSERT(effIndex < MAX_SPELL_EFFECTS);
7936 if (!m_effectExecuteData[effIndex])
7937 {
7938 m_effectExecuteData[effIndex] = new ByteBuffer(0x20);
7939 // first dword - target counter
7940 *m_effectExecuteData[effIndex] << uint32(1);
7941 }
7942 else
7943 {
7944 // increase target counter by one
7945 uint32 count = (*m_effectExecuteData[effIndex]).read<uint32>(0);
7946 (*m_effectExecuteData[effIndex]).put<uint32>(0, ++count);
7947 }
7948}
7949
7951{
7952 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
7954}
7955
7957{
7958 sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this);
7959 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
7960 {
7961 TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `{}` for spell `{}` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id);
7962 (*itr)->Register();
7963 }
7964}
7965
7967{
7968 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7969 {
7970 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST);
7971 auto hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin();
7972 for (; hookItr != hookItrEnd; ++hookItr)
7973 (*hookItr).Call(*scritr);
7974
7975 (*scritr)->_FinishScriptCall();
7976 }
7977}
7978
7980{
7981 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7982 {
7983 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST);
7984 auto hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin();
7985 for (; hookItr != hookItrEnd; ++hookItr)
7986 (*hookItr).Call(*scritr);
7987
7988 (*scritr)->_FinishScriptCall();
7989 }
7990}
7991
7993{
7994 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7995 {
7996 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST);
7997 auto hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin();
7998 for (; hookItr != hookItrEnd; ++hookItr)
7999 (*hookItr).Call(*scritr);
8000
8001 (*scritr)->_FinishScriptCall();
8002 }
8003}
8004
8006{
8008 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8009 {
8010 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST);
8011 auto hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin();
8012 for (; hookItr != hookItrEnd; ++hookItr)
8013 {
8014 SpellCastResult tempResult = (*hookItr).Call(*scritr);
8015 if (retVal == SPELL_CAST_OK)
8016 retVal = tempResult;
8017 }
8018
8019 (*scritr)->_FinishScriptCall();
8020 }
8021 return retVal;
8022}
8023
8025{
8026 // execute script effect handler hooks and check if effects was prevented
8027 bool preventDefault = false;
8028 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8029 {
8030 (*scritr)->_InitHit();
8031
8033 SpellScriptHookType hookType;
8034 switch (mode)
8035 {
8037 effItr = (*scritr)->OnEffectLaunch.begin();
8038 effEndItr = (*scritr)->OnEffectLaunch.end();
8040 break;
8042 effItr = (*scritr)->OnEffectLaunchTarget.begin();
8043 effEndItr = (*scritr)->OnEffectLaunchTarget.end();
8045 break;
8047 effItr = (*scritr)->OnEffectHit.begin();
8048 effEndItr = (*scritr)->OnEffectHit.end();
8050 break;
8052 effItr = (*scritr)->OnEffectHitTarget.begin();
8053 effEndItr = (*scritr)->OnEffectHitTarget.end();
8055 break;
8056 default:
8057 ABORT();
8058 return false;
8059 }
8060 (*scritr)->_PrepareScriptCall(hookType);
8061 for (; effItr != effEndItr; ++effItr)
8062 // effect execution can be prevented
8063 if (!(*scritr)->_IsEffectPrevented(effIndex) && (*effItr).IsEffectAffected(m_spellInfo, effIndex))
8064 (*effItr).Call(*scritr, effIndex);
8065
8066 if (!preventDefault)
8067 preventDefault = (*scritr)->_IsDefaultEffectPrevented(effIndex);
8068
8069 (*scritr)->_FinishScriptCall();
8070 }
8071 return preventDefault;
8072}
8073
8075{
8076 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8077 {
8078 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
8079 auto hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin();
8080 for (; hookItr != hookItrEnd; ++hookItr)
8081 hookItr->Call(*scritr, effIndex);
8082
8083 (*scritr)->_FinishScriptCall();
8084 }
8085}
8086
8088{
8089 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8090 {
8091 (*scritr)->_InitHit();
8092 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT);
8093 auto hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin();
8094 for (; hookItr != hookItrEnd; ++hookItr)
8095 (*hookItr).Call(*scritr, missInfo);
8096
8097 (*scritr)->_FinishScriptCall();
8098 }
8099}
8100
8102{
8103 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8104 {
8105 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT);
8106 auto hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin();
8107 for (; hookItr != hookItrEnd; ++hookItr)
8108 (*hookItr).Call(*scritr);
8109
8110 (*scritr)->_FinishScriptCall();
8111 }
8112}
8113
8115{
8116 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8117 {
8118 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT);
8119 auto hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin();
8120 for (; hookItr != hookItrEnd; ++hookItr)
8121 (*hookItr).Call(*scritr);
8122
8123 (*scritr)->_FinishScriptCall();
8124 }
8125}
8126
8127void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
8128{
8129 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8130 {
8131 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT);
8132 auto hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin();
8133 for (; hookItr != hookItrEnd; ++hookItr)
8134 if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
8135 hookItr->Call(*scritr, targets);
8136
8137 (*scritr)->_FinishScriptCall();
8138 }
8139}
8140
8142{
8143 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8144 {
8145 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT);
8146 auto hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin();
8147 for (; hookItr != hookItrEnd; ++hookItr)
8148 if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
8149 hookItr->Call(*scritr, target);
8150
8151 (*scritr)->_FinishScriptCall();
8152 }
8153}
8154
8156{
8157 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8158 {
8159 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT);
8160 auto hookItrEnd = (*scritr)->OnDestinationTargetSelect.end(), hookItr = (*scritr)->OnDestinationTargetSelect.begin();
8161 for (; hookItr != hookItrEnd; ++hookItr)
8162 if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
8163 hookItr->Call(*scritr, target);
8164
8165 (*scritr)->_FinishScriptCall();
8166 }
8167}
8168
8170{
8171 auto allEffectTargetScriptsAreShared = []<typename HookType>(HookList<HookType>& hooks, SpellInfo const* spellInfo, uint32 effIndex, uint32 effIndexToCheck)
8172 {
8173 for (HookType& hook : hooks)
8174 {
8175 if (!hook.IsEffectAffected(spellInfo, effIndex))
8176 continue;
8177
8178 bool otherEffectHasSameTargetFunction = std::ranges::any_of(hooks, [&](HookType& other)
8179 {
8180 return other.IsEffectAffected(spellInfo, effIndexToCheck) && hook.HasSameTargetFunctionAs(other);
8181 });
8182 if (!otherEffectHasSameTargetFunction)
8183 return false;
8184 }
8185
8186 return true;
8187 };
8188
8189 for (SpellScript* script : m_loadedScripts)
8190 {
8191 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
8192 return false;
8193
8194 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
8195 return false;
8196
8197 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
8198 return false;
8199
8200 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
8201 return false;
8202 }
8203 return true;
8204}
8205
8206bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const
8207{
8208 bool only_on_caster = (triggeredByAura && triggeredByAura->HasAttribute(SPELL_ATTR4_PROC_ONLY_ON_CASTER));
8209 // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER
8210 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8211 {
8212 if ((effMask & (1 << spellEffectInfo.EffectIndex)) && (!only_on_caster || (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER)))
8213 return true;
8214 }
8215 return false;
8216}
8217
8219{
8220 Unit* unitCaster = m_caster->ToUnit();
8221 if (!unitCaster)
8222 return;
8223
8224 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
8225 // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
8226 // and to correctly calculate proc chance when combopoints are present
8227 Unit::AuraEffectList const& targetTriggers = unitCaster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
8228 for (AuraEffect const* aurEff : targetTriggers)
8229 {
8230 if (!aurEff->IsAffectingSpell(m_spellInfo))
8231 continue;
8232
8233 SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo();
8234 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo().TriggerSpell))
8235 {
8236 // calculate the chance using spell base amount, because aura amount is not updated on combo-points change
8237 // this possibly needs fixing
8238 int32 auraBaseAmount = aurEff->GetBaseAmount();
8239 // proc chance is stored in effect amount
8240 int32 chance = unitCaster->CalculateSpellDamage(aurEff->GetSpellEffectInfo(), &auraBaseAmount);
8241 chance *= aurEff->GetBase()->GetStackAmount();
8242
8243 // build trigger and add to the list
8244 m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance);
8245 }
8246 }
8247}
8248
8249// Global cooldowns management
8251{
8252 MIN_GCD = 1000,
8253 MAX_GCD = 1500
8255
8257{
8258 // Only players or controlled units have global cooldown
8259 if (caster->GetTypeId() != TYPEID_PLAYER && (caster->GetTypeId() != TYPEID_UNIT || !const_cast<WorldObject*>(caster)->ToCreature()->GetCharmInfo()))
8260 return false;
8261
8262 return true;
8263}
8264
8266{
8268 return false;
8269
8271}
8272
8274{
8276 return;
8277
8279 return;
8280
8283 return;
8284
8285 // Global cooldown can't leave range 1..1.5 secs
8287
8288 // gcd modifier auras are applied only to own spells and only players have such mods
8289 if (Player* modOwner = m_caster->GetSpellModOwner())
8290 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
8291
8292 // Apply haste rating
8296 {
8297 gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
8298 RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
8299 }
8300
8301 if (gcd)
8303}
8304
8306{
8308 return;
8309
8311 return;
8312
8313 // Cancel global cooldown when interrupting current cast
8315 return;
8316
8318}
8319
8320std::string Spell::GetDebugInfo() const
8321{
8322 std::stringstream sstr;
8323 sstr << std::boolalpha
8324 << "Id: " << GetSpellInfo()->Id << " Name: '" << GetSpellInfo()->SpellName[sWorld->GetDefaultDbcLocale()] << "' OriginalCaster: " << m_originalCasterGUID.ToString()
8325 << " State: " << getState();
8326 return sstr.str();
8327}
8328
8333
8334void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)
8335{
8336 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8337 {
8338 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION);
8339 auto hookItrEnd = (*scritr)->OnCalculateResistAbsorb.end(), hookItr = (*scritr)->OnCalculateResistAbsorb.begin();
8340 for (; hookItr != hookItrEnd; ++hookItr)
8341 hookItr->Call(*scritr, damageInfo, resistAmount, absorbAmount);
8342
8343 (*scritr)->_FinishScriptCall();
8344 }
8345}
8346
8347namespace Trinity
8348{
8349
8351 SpellTargetCheckTypes selectionType, ConditionContainer const* condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
8352 _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList)
8353{
8354 if (condList)
8355 _condSrcInfo = std::make_unique<ConditionSourceInfo>(nullptr, caster);
8356}
8357
8361
8363{
8364 if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
8365 return false;
8366
8367 Unit* unitTarget = target->ToUnit();
8368 if (Corpse* corpseTarget = target->ToCorpse())
8369 {
8370 // use owner for party/assistance checks
8371 if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
8372 unitTarget = owner;
8373 else
8374 return false;
8375 }
8376
8377 Unit* refUnit = _referer->ToUnit();
8378 if (unitTarget)
8379 {
8380 // do only faction checks here
8381 switch (_targetSelectionType)
8382 {
8383 case TARGET_CHECK_ENEMY:
8384 if (unitTarget->IsTotem())
8385 return false;
8386 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8387 if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo))
8388 return false;
8389 break;
8390 case TARGET_CHECK_ALLY:
8391 if (unitTarget->IsTotem())
8392 return false;
8393 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8394 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
8395 return false;
8396 break;
8397 case TARGET_CHECK_PARTY:
8398 if (!refUnit)
8399 return false;
8400 if (unitTarget->IsTotem())
8401 return false;
8402 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8403 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
8404 return false;
8405 if (!refUnit->IsInPartyWith(unitTarget))
8406 return false;
8407 break;
8409 if (!refUnit)
8410 return false;
8411 if (refUnit->GetClass() != unitTarget->GetClass())
8412 return false;
8413 [[fallthrough]];
8414 case TARGET_CHECK_RAID:
8415 if (!refUnit)
8416 return false;
8417 if (unitTarget->IsTotem())
8418 return false;
8419 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8420 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
8421 return false;
8422 if (!refUnit->IsInRaidWith(unitTarget))
8423 return false;
8424 break;
8425 default:
8426 break;
8427 }
8428 }
8429
8430 if (!_condSrcInfo)
8431 return true;
8432 _condSrcInfo->mConditionTargets[0] = target;
8433 return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
8434}
8435
8437 SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8438 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(caster) { }
8439
8441{
8442 float dist = target->GetDistance(*_position);
8443 if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target))
8444 {
8445 _range = dist;
8446 return true;
8447 }
8448 return false;
8449}
8450
8452 WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8453 : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList), _range(range), _position(position) { }
8454
8456{
8457 if (target->ToGameObject())
8458 {
8459 // isInRange including the dimension of the GO
8461 if (!isInRange)
8462 return false;
8463 }
8464 else
8465 {
8466 bool isInsideCylinder = target->IsWithinDist2d(_position, _range) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range;
8467 if (!isInsideCylinder)
8468 return false;
8469 }
8470
8472}
8473
8475 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8476 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList), _coneAngle(coneAngle) { }
8477
8479{
8481 {
8482 if (!_caster->isInBack(target, _coneAngle))
8483 return false;
8484 }
8486 {
8487 if (!_caster->HasInLine(target, target->GetCombatReach(), _caster->GetCombatReach()))
8488 return false;
8489 }
8490 else
8491 {
8492 if (!_caster->isInFront(target, _coneAngle))
8493 return false;
8494 }
8496}
8497
8498WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8499 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(position) { }
8500
8502{
8503 // return all targets on missile trajectory (0 - size of a missile)
8504 if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
8505 return false;
8506
8507 if (target->GetExactDist2d(_position) > _range)
8508 return false;
8509
8511}
8512
8513} //namespace Trinity
8514
8516{
8517 if (target)
8518 {
8519 if (Unit* unitTarget = target->ToUnit())
8520 {
8521 Targets.emplace();
8522 Targets->SetUnitTarget(unitTarget);
8523 }
8524 else if (GameObject* goTarget = target->ToGameObject())
8525 {
8526 Targets.emplace();
8527 Targets->SetGOTarget(goTarget);
8528 }
8529 // error when targeting anything other than units and gameobjects
8530 }
8531 else
8532 Targets.emplace(); // nullptr is allowed
8533}
#define sBattlefieldMgr
@ STATUS_WAIT_LEAVE
@ STATUS_IN_PROGRESS
@ IN_MILLISECONDS
Definition Common.h:35
@ MINUTE
Definition Common.h:29
#define M_PI
Definition Common.h:72
#define sConditionMgr
@ CONDITION_SOURCE_TYPE_SPELL
std::vector< Condition * > ConditionContainer
@ CORPSE_FLAG_LOOTABLE
Definition Corpse.h:46
@ ITEM_ENCHANTMENT_TYPE_USE_SPELL
Definition DBCEnums.h:362
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
Definition DBCEnums.h:363
Difficulty
Definition DBCEnums.h:279
#define MAX_EFFECT_MASK
Definition DBCEnums.h:389
@ ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER
Definition DBCEnums.h:124
@ ACHIEVEMENT_TIMED_TYPE_ITEM
Definition DBCEnums.h:127
@ ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET
Definition DBCEnums.h:125
@ ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM
Definition DBCEnums.h:167
@ ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET
Definition DBCEnums.h:154
@ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL
Definition DBCEnums.h:155
@ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2
Definition DBCEnums.h:230
@ ENCHANTMENT_CAN_SOULBOUND
Definition DBCEnums.h:394
#define MAX_SPELL_REAGENTS
Definition DBCEnums.h:390
@ AREA_FLAG_NO_FLY_ZONE
Definition DBCEnums.h:275
#define MAX_SPELL_EFFECTS
Definition DBCEnums.h:388
DBCStorage< SpellItemEnchantmentEntry > sSpellItemEnchantmentStore(SpellItemEnchantmentfmt)
DBCStorage< SummonPropertiesEntry > sSummonPropertiesStore(SummonPropertiesfmt)
DBCStorage< LockEntry > sLockStore(LockEntryfmt)
DBCStorage< ItemEntry > sItemStore(Itemfmt)
DBCStorage< SpellRuneCostEntry > sSpellRuneCostStore(SpellRuneCostfmt)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
DBCStorage< GlyphPropertiesEntry > sGlyphPropertiesStore(GlyphPropertiesfmt)
DBCStorage< AreaTableEntry > sAreaTableStore(AreaTableEntryfmt)
#define MAX_LOCK_CASE
#define MAX_ITEM_ENCHANTMENT_EFFECTS
#define TC_GAME_API
Definition Define.h:114
uint8_t uint8
Definition Define.h:135
int64_t int64
Definition Define.h:128
int8_t int8
Definition Define.h:131
int32_t int32
Definition Define.h:129
uint64_t uint64
Definition Define.h:132
uint32_t uint32
Definition Define.h:133
@ SPELL_DISABLE_LOS
Definition DisableMgr.h:46
@ DISABLE_TYPE_SPELL
Definition DisableMgr.h:27
std::chrono::milliseconds Milliseconds
Milliseconds shorthand typedef.
Definition Duration.h:24
#define ABORT_MSG
Definition Errors.h:75
#define ABORT
Definition Errors.h:74
#define ASSERT_NOTNULL(pointer)
Definition Errors.h:84
#define ASSERT
Definition Errors.h:68
@ GRID_MAP_TYPE_MASK_PLAYER
Definition GridDefines.h:75
@ GRID_MAP_TYPE_MASK_CREATURE
Definition GridDefines.h:72
@ GRID_MAP_TYPE_MASK_ALL
Definition GridDefines.h:76
@ GRID_MAP_TYPE_MASK_GAMEOBJECT
Definition GridDefines.h:74
@ GRID_MAP_TYPE_MASK_CORPSE
Definition GridDefines.h:71
#define VMAP_INVALID_HEIGHT_VALUE
@ PRISMATIC_ENCHANTMENT_SLOT
InventoryResult
Definition ItemDefines.h:25
@ EQUIP_ERR_OK
Definition ItemDefines.h:26
@ EQUIP_ERR_INV_FULL
Definition ItemDefines.h:76
@ ITEM_CLASS_PROJECTILE
@ ITEM_CLASS_ARMOR
@ 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
@ ITEM_SUBCLASS_ARROW
@ ITEM_SUBCLASS_BULLET
#define MAX_ITEM_PROTO_SOCKETS
#define MAX_ITEM_PROTO_SPELLS
@ INVTYPE_THROWN
@ INVTYPE_AMMO
@ ITEM_CHANGED
Definition Item.h:54
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
LootStore LootTemplates_Milling("milling_loot_template", "item entry (herb)", true)
LootStore LootTemplates_Prospecting("prospecting_loot_template", "item entry (ore)", true)
constexpr bool CanStopMovementForSpellCasting(MovementGeneratorType type)
#define EXTRA_CELL_SEARCH_RADIUS
@ PHASEMASK_ANYWHERE
#define DEFAULT_PLAYER_BOUNDING_RADIUS
@ TYPEID_GAMEOBJECT
Definition ObjectGuid.h:40
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
#define sObjectMgr
Definition ObjectMgr.h:1721
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:85
@ HUNTER_PET
Definition PetDefines.h:32
@ EQUIPMENT_SLOT_RANGED
Definition Player.h:569
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:624
@ PLAYER_ALLOW_ONLY_ABILITY
Definition Player.h:367
@ RUNE_MISS_COOLDOWN
Definition Player.h:283
@ CHEAT_COOLDOWN
Definition Player.h:839
@ CHEAT_POWER
Definition Player.h:840
@ CHEAT_CASTTIME
Definition Player.h:838
RuneType
Definition Player.h:287
@ RUNE_UNHOLY
Definition Player.h:289
@ RUNE_DEATH
Definition Player.h:291
@ NUM_RUNE_TYPES
Definition Player.h:292
@ RUNE_FROST
Definition Player.h:290
@ RUNE_BLOOD
Definition Player.h:288
float frand(float min, float max)
Definition Random.cpp:55
int32 irand(int32 min, int32 max)
Definition Random.cpp:35
double rand_norm()
Definition Random.cpp:75
bool roll_chance_f(float chance)
Definition Random.h:53
bool roll_chance_i(int chance)
Definition Random.h:59
if(posix_memalign(&__mallocedMemory, __align, __size)) return NULL
#define sScriptMgr
Definition ScriptMgr.h:1168
@ GAMEOBJECT_TYPE_TRAP
@ GAMEOBJECT_TYPE_DESTRUCTIBLE_BUILDING
SpellEffIndex
@ EFFECT_1
@ EFFECT_0
@ EFFECT_2
MountResult
@ SPELL_ATTR7_IS_CHEAT_SPELL
@ SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
@ SPELL_EFFECT_LEAP
@ SPELL_EFFECT_POWER_BURN
@ SPELL_EFFECT_SUMMON_PET
@ SPELL_EFFECT_DISENCHANT
@ SPELL_EFFECT_PROSPECTING
@ SPELL_EFFECT_ENCHANT_HELD_ITEM
@ SPELL_EFFECT_ENCHANT_ITEM
@ SPELL_EFFECT_STUCK
@ SPELL_EFFECT_GAMEOBJECT_REPAIR
@ SPELL_EFFECT_SUMMON_RAF_FRIEND
@ SPELL_EFFECT_WEAPON_DAMAGE
@ SPELL_EFFECT_APPLY_GLYPH
@ SPELL_EFFECT_HEAL
@ SPELL_EFFECT_FEED_PET
@ SPELL_EFFECT_SUMMON_PLAYER
@ SPELL_EFFECT_DISPEL
@ SPELL_EFFECT_MILLING
@ SPELL_EFFECT_JUMP_DEST
@ SPELL_EFFECT_TELEPORT_UNITS_FACE_CASTER
@ SPELL_EFFECT_RESURRECT_PET
@ SPELL_EFFECT_CREATE_MANA_GEM
@ SPELL_EFFECT_SKIN_PLAYER_CORPSE
@ SPELL_EFFECT_ADD_EXTRA_ATTACKS
@ SPELL_EFFECT_ACTIVATE_RUNE
@ SPELL_EFFECT_CREATE_ITEM_2
@ SPELL_EFFECT_WEAPON_DAMAGE_NOSCHOOL
@ SPELL_EFFECT_PERSISTENT_AREA_AURA
@ SPELL_EFFECT_LEAP_BACK
@ SPELL_EFFECT_SUMMON
@ SPELL_EFFECT_ENERGIZE
@ SPELL_EFFECT_BIND
@ SPELL_EFFECT_POWER_DRAIN
@ SPELL_EFFECT_CHARGE
@ SPELL_EFFECT_RESURRECT_NEW
@ SPELL_EFFECT_TALENT_SPEC_SELECT
@ TOTAL_SPELL_EFFECTS
@ SPELL_EFFECT_GAMEOBJECT_SET_DESTRUCTION_STATE
@ SPELL_EFFECT_GAMEOBJECT_DAMAGE
@ SPELL_EFFECT_LEARN_SPELL
@ SPELL_EFFECT_JUMP
@ SPELL_EFFECT_SKINNING
@ 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
#define MAX_RUNES
#define CLASSMASK_WAND_USERS
@ SPELL_PREVENTION_TYPE_SILENCE
@ SPELL_PREVENTION_TYPE_PACIFY
@ SPELL_ATTR5_USABLE_WHILE_CONFUSED
@ SPELL_ATTR5_USABLE_WHILE_FEARED
@ SPELL_ATTR5_SKIP_CHECKCAST_LOS_CHECK
@ SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED
@ SPELL_ATTR5_HASTE_AFFECT_DURATION
@ SPELL_ATTR5_USABLE_WHILE_STUNNED
Targets
@ TARGET_UNIT_PASSENGER_1
@ TARGET_DEST_TARGET_ANY
@ TARGET_UNIT_TARGET_CHAINHEAL_ALLY
@ TARGET_DEST_CASTER_RANDOM
@ TARGET_DEST_DB
@ TARGET_DEST_DYNOBJ_ENEMY
@ TARGET_UNIT_PASSENGER_6
@ TARGET_DEST_CASTER_FRONT_LEAP
@ TARGET_DEST_CHANNEL_TARGET
@ TARGET_DEST_CASTER_FRONT_LEFT
@ TARGET_DEST_CASTER_BACK_RIGHT
@ TARGET_DEST_DEST_RANDOM
@ TARGET_UNIT_VEHICLE
@ TARGET_UNIT_PASSENGER_2
@ TARGET_UNIT_CHANNEL_TARGET
@ TARGET_DEST_CASTER_FISHING
@ TARGET_DEST_TARGET_RANDOM
@ 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_MASTER
@ TARGET_UNIT_PASSENGER_5
@ TARGET_UNIT_PASSENGER_3
@ TARGET_DEST_CASTER_BACK_LEFT
@ TARGET_DEST_CASTER_SUMMON
@ TARGET_DEST_CASTER
@ TARGET_UNIT_CASTER
@ TARGET_GAMEOBJECT_TARGET
@ TARGET_GAMEOBJECT_ITEM_TARGET
@ TARGET_DEST_CASTER_FRONT_RIGHT
@ TARGET_UNIT_SUMMONER
@ TARGET_UNIT_PASSENGER_0
@ TARGET_DEST_HOME
@ TARGET_DEST_CHANNEL_CASTER
SpellSchoolMask
@ SPELL_ATTR2_AUTOREPEAT_FLAG
@ SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS
@ SPELL_ATTR2_NOT_RESET_AUTO_ACTIONS
@ SPELL_ATTR2_ALLOW_LOW_LEVEL_BUFF
@ SPELL_ATTR2_FAIL_ON_ALL_TARGETS_IMMUNE
LockType
@ SPELL_ATTR1_REQUIRE_ALL_TARGETS
@ SPELL_ATTR1_CANT_BE_REFLECTED
@ SPELL_ATTR1_CHANNEL_TRACK_TARGET
@ SPELL_ATTR1_DISMISS_PET
@ SPELL_ATTR1_MELEE_COMBAT_START
@ SPELL_ATTR3_MAIN_HAND
@ SPELL_ATTR3_ONLY_TARGET_PLAYERS
@ SPELL_ATTR3_ONLY_TARGET_GHOSTS
@ SPELL_ATTR3_IGNORE_RESURRECTION_TIMER
@ SPELL_ATTR3_BATTLEGROUND
@ SPELL_ATTR3_CANT_TRIGGER_PROC
@ SPELL_ATTR3_REQ_OFFHAND
@ SPELL_ATTR3_COMPLETELY_BLOCKED
@ SPELL_DAMAGE_CLASS_RANGED
@ SPELL_DAMAGE_CLASS_MAGIC
@ SPELL_DAMAGE_CLASS_NONE
@ SPELL_DAMAGE_CLASS_MELEE
@ LOCK_KEY_ITEM
@ LOCK_KEY_SKILL
@ LOCK_KEY_SPELL
WeaponAttackType
@ OFF_ATTACK
@ MAX_ATTACK
@ BASE_ATTACK
@ RANGED_ATTACK
@ PETTAME_DEAD
@ PETTAME_CANTCONTROLEXOTIC
@ PETTAME_NOPETAVAILABLE
@ CLASS_DEATH_KNIGHT
@ MECHANIC_BANISH
@ MECHANIC_IMMUNE_SHIELD
@ SPELLFAMILY_WARLOCK
@ SPELLFAMILY_MAGE
@ SPELLFAMILY_WARRIOR
@ SPELLFAMILY_HUNTER
SpellCustomErrors
@ SPELL_CUSTOM_ERROR_NONE
@ SPELL_CUSTOM_ERROR_GM_ONLY
Powers
@ MAX_POWERS
@ POWER_RAGE
@ POWER_HEALTH
@ POWER_RUNIC_POWER
@ POWER_ENERGY
@ POWER_MANA
@ POWER_RUNE
@ SPELL_ATTR0_STOP_ATTACK_TARGET
@ SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY
@ SPELL_ATTR0_DISABLED_WHILE_ACTIVE
@ SPELL_ATTR0_CASTABLE_WHILE_DEAD
@ SPELL_ATTR0_ABILITY
@ SPELL_ATTR0_REQ_AMMO
@ SPELL_ATTR0_OUTDOORS_ONLY
@ SPELL_ATTR0_ONLY_STEALTHED
@ SPELL_ATTR0_INDOORS_ONLY
@ SPELL_ATTR0_CASTABLE_WHILE_MOUNTED
DiminishingLevels
@ DIMINISHING_LEVEL_1
TotemCategory
@ LINEOFSIGHT_ALL_CHECKS
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
AuraStateType
DiminishingReturnsType
@ DRTYPE_PLAYER
@ DRTYPE_ALL
constexpr SkillType SkillByLockType(LockType locktype)
DispelType
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
@ 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_ITEM_AT_MAX_CHARGES
@ SPELL_FAILED_MIN_SKILL
@ SPELL_FAILED_NOTHING_TO_DISPEL
@ SPELL_FAILED_NO_POWER
@ SPELL_FAILED_NOT_KNOWN
@ SPELL_FAILED_FOOD_LOWLEVEL
@ SPELL_FAILED_NOT_HERE
@ SPELL_FAILED_ROOTED
@ 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_NO_COMBO_POINTS
@ 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_NOTHING_TO_STEAL
@ SPELL_FAILED_NO_AMMO
@ SPELL_FAILED_NO_MOUNTS_ALLOWED
@ 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_TARGET_NOT_IN_INSTANCE
@ SPELL_FAILED_HIGHLEVEL
@ SPELL_FAILED_DONT_REPORT
@ SPELL_FAILED_ON_USE_ENCHANT
@ SPELL_FAILED_TARGET_AURASTATE
@ SPELL_FAILED_TOTEMS
@ SPELL_FAILED_ERROR
@ SPELL_FAILED_LOWLEVEL
@ SPELL_FAILED_NOT_READY
@ SPELL_FAILED_ONLY_BATTLEGROUNDS
@ SPELL_FAILED_NOT_IN_ARENA
@ SPELL_FAILED_ITEM_ALREADY_ENCHANTED
@ SPELL_FAILED_ONLY_STEALTHED
@ SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED
@ SPELL_FAILED_REAGENTS
@ SPELL_FAILED_ONLY_ABOVEWATER
@ SPELL_FAILED_AURA_BOUNCED
@ SPELL_FAILED_CANT_BE_CHARMED
@ SPELL_FAILED_MAX_SOCKETS
@ SPELL_FAILED_CASTER_DEAD
@ SPELL_FAILED_BAD_TARGETS
@ SPELL_FAILED_CANT_BE_DISENCHANTED
@ SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW
@ SPELL_FAILED_TOO_MANY_OF_ITEM
@ SPELL_FAILED_CONFUSED
@ SPELL_FAILED_TARGET_UNSKINNABLE
@ SPELL_FAILED_SILENCED
@ SPELL_FAILED_UNIQUE_GLYPH
@ SPELL_FAILED_NEED_MORE_ITEMS
@ SPELL_FAILED_ONLY_OUTDOORS
@ SPELL_CAST_OK
@ SPELL_FAILED_CHARMED
@ SPELL_FAILED_LOW_CASTLEVEL
@ SPELL_FAILED_CANT_BE_PROSPECTED
@ SPELL_FAILED_LINE_OF_SIGHT
@ SPELL_FAILED_FLEEING
@ SPELL_FAILED_PACIFIED
@ 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_ONLY_INDOORS
@ SPELL_FAILED_NOT_ON_TAXI
@ SPELL_FAILED_TARGET_FRIENDLY
@ SPELL_ATTR4_CAN_CAST_WHILE_CASTING
@ SPELL_ATTR4_AREA_TARGET_CHAIN
@ SPELL_ATTR4_USABLE_IN_ARENA
@ SPELL_ATTR4_PROC_ONLY_ON_CASTER
@ SPELL_ATTR4_NOT_USABLE_IN_ARENA
@ SPELL_ATTR4_CANT_TRIGGER_ITEM_SPELLS
@ SPELL_ATTR4_NOT_STEALABLE
@ SUMMON_CATEGORY_PET
@ SUMMON_CATEGORY_PUPPET
@ CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES
SkillType
@ SKILL_INSCRIPTION
@ SKILL_MINING
@ SKILL_NONE
@ SKILL_LOCKPICKING
@ SKILL_ENCHANTING
@ SKILL_JEWELCRAFTING
@ SKILL_HERBALISM
@ SPELL_ATTR6_NOT_RESET_SWING_IF_INSTANT
@ SPELL_ATTR6_IGNORE_CASTER_AURAS
@ SPELL_ATTR6_CAST_BY_CHARMER
@ AURA_REMOVE_BY_CANCEL
@ SPELL_AURA_RETAIN_COMBO_POINTS
@ SPELL_AURA_PERIODIC_HASTE
@ SPELL_AURA_ABILITY_IGNORE_AURASTATE
@ SPELL_AURA_MOD_IGNORE_SHAPESHIFT
@ SPELL_AURA_PERIODIC_MANA_LEECH
@ SPELL_AURA_MOD_POSSESS_PET
@ SPELL_AURA_RANGED_ATTACK_POWER_ATTACKER_BONUS
@ SPELL_AURA_ABILITY_CONSUME_NO_AMMO
@ SPELL_AURA_CONVERT_RUNE
@ SPELL_AURA_MOD_FEAR
@ SPELL_AURA_FLY
@ SPELL_AURA_MOD_PACIFY
@ SPELL_AURA_MOD_SILENCE
@ SPELL_AURA_ADD_TARGET_TRIGGER
@ SPELL_AURA_MOD_CHARM
@ SPELL_AURA_MOUNTED
@ SPELL_AURA_MOD_PACIFY_SILENCE
@ SPELL_AURA_AOE_CHARM
@ SPELL_AURA_STRANGULATE
@ SPELL_AURA_REDUCE_PUSHBACK
@ SPELL_AURA_IGNORE_MELEE_RESET
@ SPELL_AURA_MOD_CONFUSE
@ SPELL_AURA_MOD_POSSESS
@ SPELL_AURA_MOD_MAX_AFFECTED_TARGETS
@ SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED
@ SPELL_AURA_BLOCK_SPELL_FAMILY
@ SPELL_AURA_MOD_STUN
@ SPELL_INTERRUPT_FLAG_PUSH_BACK
@ SPELL_INTERRUPT_FLAG_INTERRUPT
@ SPELL_INTERRUPT_FLAG_MOVEMENT
@ CHANNEL_FLAG_DELAY
@ SPELLMOD_RANGE
@ SPELLMOD_NOT_LOSE_CASTING_TIME
@ SPELLMOD_SPELL_COST_REFUND_ON_FAIL
@ SPELLMOD_GLOBAL_COOLDOWN
@ SPELLMOD_DURATION
@ SPELLMOD_JUMP_TARGETS
@ SPELLMOD_COST
@ TARGET_FLAG_TRADE_ITEM
@ TARGET_FLAG_GAMEOBJECT
@ TARGET_FLAG_STRING
@ TARGET_FLAG_NONE
@ TARGET_FLAG_UNIT_ENEMY
@ TARGET_FLAG_CORPSE_ALLY
@ TARGET_FLAG_ITEM
@ TARGET_FLAG_UNIT_MINIPET
@ TARGET_FLAG_UNIT_PASSENGER
@ TARGET_FLAG_GAMEOBJECT_ITEM
@ TARGET_FLAG_DEST_LOCATION
@ TARGET_FLAG_UNUSED20
@ TARGET_FLAG_SOURCE_LOCATION
@ TARGET_FLAG_ITEM_MASK
@ TARGET_FLAG_UNIT
@ TARGET_FLAG_UNIT_MASK
@ TARGET_FLAG_UNIT_DEAD
@ TARGET_FLAG_CORPSE_ENEMY
@ TARGET_FLAG_CORPSE_MASK
@ TARGET_FLAG_GAMEOBJECT_MASK
TriggerCastFlags
@ TRIGGERED_IGNORE_EQUIPPED_ITEM_REQUIREMENT
Used when doing CastSpell with triggered == true.
@ TRIGGERED_FULL_MASK
Will return SPELL_FAILED_DONT_REPORT in CheckCast functions.
@ TRIGGERED_IGNORE_POWER_AND_REAGENT_COST
Will ignore Spell and Category cooldowns.
@ TRIGGERED_DONT_RESET_PERIODIC_TIMER
Will ignore caster aura restrictions or requirements.
@ TRIGGERED_IGNORE_SPELL_AND_CATEGORY_CD
Will ignore GCD.
@ TRIGGERED_CAST_DIRECTLY
Will ignore combo point requirement.
@ TRIGGERED_IGNORE_TARGET_CHECK
Will ignore equipped item requirements.
@ TRIGGERED_IGNORE_CASTER_AURASTATE
Will ignore shapeshift checks.
@ TRIGGERED_IGNORE_AURA_SCALING
Will not take away cast item or update related achievement criteria.
@ TRIGGERED_IGNORE_CAST_IN_PROGRESS
Will ignore aura scaling.
@ TRIGGERED_IGNORE_CASTER_MOUNTED_OR_ON_VEHICLE
Disallows proc events from triggered spell (default)
@ TRIGGERED_IGNORE_SHAPESHIFT
Will not adjust facing to target (if any)
@ TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS
In Spell::prepare, will be cast directly without setting containers for executed spell.
@ TRIGGERED_IGNORE_CAST_ITEM
Will ignore power and reagent cost.
@ TRIGGERED_IGNORE_COMBO_POINTS
Will not check if a current cast is in progress.
@ TRIGGERED_IGNORE_GCD
Not triggered.
@ TRIGGERED_DISALLOW_PROC_EVENTS
Will ignore caster aura states including combat requirements and death state.
@ TRIGGERED_IGNORE_CASTER_AURAS
Will ignore mounted/on vehicle restrictions.
@ TRIGGERED_DONT_REPORT_CAST_ERROR
Will allow periodic aura timers to keep ticking (instead of resetting)
@ TRIGGERED_IGNORE_SET_FACING
Will ignore interruptible aura's at cast.
SpellValueMod
@ SPELLVALUE_AURA_STACK
@ SPELLVALUE_BASE_POINT1
@ SPELLVALUE_RADIUS_MOD
@ SPELLVALUE_MAX_TARGETS
@ SPELLVALUE_BASE_POINT2
@ SPELLVALUE_BASE_POINT0
@ SPELLVALUE_CRIT_CHANCE
@ SPELL_FACING_FLAG_INFRONT
@ AURA_INTERRUPT_FLAG_SPELL_ATTACK
@ AURA_INTERRUPT_FLAG_CAST
@ AURA_INTERRUPT_FLAG_TALK
@ AURA_INTERRUPT_FLAG_HITBYSPELL
@ AURA_INTERRUPT_FLAG_NOT_SEATED
uint32 GetTargetFlagMask(SpellTargetObjectTypes objType)
Definition SpellInfo.cpp:35
SpellTargetCheckTypes
Definition SpellInfo.h:78
@ TARGET_CHECK_PARTY
Definition SpellInfo.h:83
@ TARGET_CHECK_ENEMY
Definition SpellInfo.h:81
@ TARGET_CHECK_DEFAULT
Definition SpellInfo.h:79
@ TARGET_CHECK_ENTRY
Definition SpellInfo.h:80
@ TARGET_CHECK_RAID_CLASS
Definition SpellInfo.h:85
@ TARGET_CHECK_ALLY
Definition SpellInfo.h:82
@ TARGET_CHECK_RAID
Definition SpellInfo.h:84
@ EFFECT_IMPLICIT_TARGET_CASTER
Definition SpellInfo.h:108
@ EFFECT_IMPLICIT_TARGET_EXPLICIT
Definition SpellInfo.h:107
@ TARGET_SELECT_CATEGORY_CONE
Definition SpellInfo.h:46
@ TARGET_SELECT_CATEGORY_AREA
Definition SpellInfo.h:47
@ TARGET_SELECT_CATEGORY_DEFAULT
Definition SpellInfo.h:43
@ TARGET_SELECT_CATEGORY_NEARBY
Definition SpellInfo.h:45
@ TARGET_SELECT_CATEGORY_NYI
Definition SpellInfo.h:42
@ TARGET_SELECT_CATEGORY_TRAJ
Definition SpellInfo.h:48
@ TARGET_SELECT_CATEGORY_CHANNEL
Definition SpellInfo.h:44
SpellTargetObjectTypes
Definition SpellInfo.h:62
@ TARGET_OBJECT_TYPE_UNIT
Definition SpellInfo.h:66
@ TARGET_OBJECT_TYPE_CORPSE
Definition SpellInfo.h:71
@ TARGET_OBJECT_TYPE_UNIT_AND_DEST
Definition SpellInfo.h:67
@ TARGET_OBJECT_TYPE_DEST
Definition SpellInfo.h:65
@ TARGET_OBJECT_TYPE_GOBJ
Definition SpellInfo.h:68
@ TARGET_OBJECT_TYPE_CORPSE_ALLY
Definition SpellInfo.h:74
@ TARGET_OBJECT_TYPE_CORPSE_ENEMY
Definition SpellInfo.h:73
@ TARGET_OBJECT_TYPE_GOBJ_ITEM
Definition SpellInfo.h:69
@ TARGET_OBJECT_TYPE_SRC
Definition SpellInfo.h:64
@ SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER
Definition SpellInfo.h:157
@ SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET
Definition SpellInfo.h:158
@ SPELL_ATTR0_CU_CONE_BACK
Definition SpellInfo.h:142
@ SPELL_ATTR0_CU_NEEDS_AMMO_DATA
Definition SpellInfo.h:160
@ SPELL_ATTR0_CU_PICKPOCKET
Definition SpellInfo.h:151
@ SPELL_ATTR0_CU_CONE_LINE
Definition SpellInfo.h:143
@ SPELL_ATTR0_CU_NO_INITIAL_THREAT
Definition SpellInfo.h:145
@ TARGET_REFERENCE_TYPE_SRC
Definition SpellInfo.h:57
@ TARGET_REFERENCE_TYPE_TARGET
Definition SpellInfo.h:55
@ TARGET_REFERENCE_TYPE_LAST
Definition SpellInfo.h:56
@ TARGET_REFERENCE_TYPE_CASTER
Definition SpellInfo.h:54
@ TARGET_REFERENCE_TYPE_DEST
Definition SpellInfo.h:58
@ PROC_HIT_NONE
Definition SpellMgr.h:219
@ PROC_HIT_IMMUNE
Definition SpellMgr.h:228
@ PROC_HIT_CRITICAL
Definition SpellMgr.h:221
@ PROC_HIT_NORMAL
Definition SpellMgr.h:220
@ PROC_HIT_REFLECT
Definition SpellMgr.h:231
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_FROM_SAME_CASTER
Definition SpellMgr.h:328
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE
Definition SpellMgr.h:327
@ SPELL_GROUP_STACK_RULE_DEFAULT
Definition SpellMgr.h:326
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT
Definition SpellMgr.h:329
@ SPELL_GROUP_STACK_RULE_EXCLUSIVE_HIGHEST
Definition SpellMgr.h:330
#define sSpellMgr
Definition SpellMgr.h:738
@ SPELL_LINK_HIT
Definition SpellMgr.h:105
@ PROC_SPELL_TYPE_NONE
Definition SpellMgr.h:201
@ PROC_SPELL_TYPE_HEAL
Definition SpellMgr.h:203
@ PROC_SPELL_TYPE_MASK_ALL
Definition SpellMgr.h:205
@ PROC_SPELL_TYPE_DAMAGE
Definition SpellMgr.h:202
@ PROC_SPELL_TYPE_NO_DMG_HEAL
Definition SpellMgr.h:204
@ PROC_SPELL_PHASE_FINISH
Definition SpellMgr.h:213
@ PROC_SPELL_PHASE_NONE
Definition SpellMgr.h:210
@ PROC_SPELL_PHASE_CAST
Definition SpellMgr.h:211
@ PROC_SPELL_PHASE_HIT
Definition SpellMgr.h:212
@ PROC_FLAG_DONE_SPELL_RANGED_DMG_CLASS
Definition SpellMgr.h:127
@ PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_POS
Definition SpellMgr.h:136
@ PROC_FLAG_TAKEN_RANGED_AUTO_ATTACK
Definition SpellMgr.h:125
@ PROC_FLAG_DONE_PERIODIC
Definition SpellMgr.h:142
@ PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_POS
Definition SpellMgr.h:130
@ PROC_FLAG_DONE_SPELL_MELEE_DMG_CLASS
Definition SpellMgr.h:121
@ PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_NEG
Definition SpellMgr.h:140
@ PROC_FLAG_TAKEN_SPELL_RANGED_DMG_CLASS
Definition SpellMgr.h:128
@ PROC_FLAG_TAKEN_PERIODIC
Definition SpellMgr.h:143
@ PROC_FLAG_DONE_MAINHAND_ATTACK
Definition SpellMgr.h:148
@ PROC_FLAG_DONE_RANGED_AUTO_ATTACK
Definition SpellMgr.h:124
@ PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_NEG
Definition SpellMgr.h:134
@ PROC_FLAG_DONE_SPELL_NONE_DMG_CLASS_NEG
Definition SpellMgr.h:133
@ PROC_FLAG_TAKEN_SPELL_MAGIC_DMG_CLASS_POS
Definition SpellMgr.h:137
@ PROC_FLAG_TAKEN_DAMAGE
Definition SpellMgr.h:145
@ PROC_FLAG_TAKEN_SPELL_NONE_DMG_CLASS_POS
Definition SpellMgr.h:131
@ PROC_FLAG_TAKEN_SPELL_MELEE_DMG_CLASS
Definition SpellMgr.h:122
@ PROC_FLAG_DONE_TRAP_ACTIVATION
Definition SpellMgr.h:146
@ PROC_FLAG_DONE_OFFHAND_ATTACK
Definition SpellMgr.h:149
@ PROC_FLAG_NONE
Definition SpellMgr.h:113
@ PROC_FLAG_DONE_SPELL_MAGIC_DMG_CLASS_NEG
Definition SpellMgr.h:139
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_EFFECT_LAUNCH
@ SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT
@ SPELL_SCRIPT_HOOK_BEFORE_HIT
@ SPELL_SCRIPT_HOOK_CHECK_CAST
@ SPELL_SCRIPT_HOOK_EFFECT_LAUNCH_TARGET
@ 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_ON_CAST
bool CanHaveGlobalCooldown(WorldObject const *caster)
Definition Spell.cpp:8256
float tangent(float x)
Definition Spell.cpp:1633
SpellEffectHandlerFn SpellEffectHandlers[TOTAL_SPELL_EFFECTS]
GCDLimits
Definition Spell.cpp:8251
@ MIN_GCD
Definition Spell.cpp:8252
@ MAX_GCD
Definition Spell.cpp:8253
@ SPELL_RANGE_MELEE
Definition Spell.h:115
@ SPELL_RANGE_RANGED
Definition Spell.h:116
#define MAX_SPELL_RANGE_TOLERANCE
Definition Spell.h:72
void(Spell::*)() SpellEffectHandlerFn
Definition Spell.h:776
SpellEffectHandleMode
Definition Spell.h:140
@ SPELL_EFFECT_HANDLE_LAUNCH_TARGET
Definition Spell.h:142
@ SPELL_EFFECT_HANDLE_LAUNCH
Definition Spell.h:141
@ SPELL_EFFECT_HANDLE_HIT
Definition Spell.h:143
@ SPELL_EFFECT_HANDLE_HIT_TARGET
Definition Spell.h:144
@ SPELL_STATE_DELAYED
Definition Spell.h:136
@ SPELL_STATE_NULL
Definition Spell.h:131
@ SPELL_STATE_FINISHED
Definition Spell.h:134
@ SPELL_STATE_PREPARING
Definition Spell.h:132
@ SPELL_STATE_CASTING
Definition Spell.h:133
static const uint32 SPELL_INTERRUPT_NONPLAYER
Definition Spell.h:149
#define TRAJECTORY_MISSILE_SIZE
Definition Spell.h:73
@ CAST_FLAG_AMMO
Definition Spell.h:83
@ CAST_FLAG_ADJUST_MISSILE
Definition Spell.h:95
@ CAST_FLAG_UNKNOWN_9
Definition Spell.h:86
@ CAST_FLAG_NO_GCD
Definition Spell.h:96
@ CAST_FLAG_POWER_LEFT_SELF
Definition Spell.h:89
@ CAST_FLAG_HAS_TRAJECTORY
Definition Spell.h:79
@ CAST_FLAG_RUNE_LIST
Definition Spell.h:99
@ CAST_FLAG_PENDING
Definition Spell.h:78
@ CAST_FLAG_IMMUNITY
Definition Spell.h:104
TradeSlots
Definition TradeData.h:24
@ TRADE_SLOT_NONTRADED
Definition TradeData.h:27
@ UNIT_FLAG2_ALLOW_CHEAT_SPELLS
@ UNIT_STAND_STATE_STAND
Definition UnitDefines.h:34
@ MOVEMENTFLAG_FALLING_FAR
@ UNIT_FLAG_STUNNED
@ UNIT_FLAG_NON_ATTACKABLE
@ UNIT_FLAG_POSSESSED
@ UNIT_FLAG_IMMUNE
@ UNIT_FLAG_PACIFIED
@ UNIT_FLAG_CONFUSED
@ UNIT_FLAG_FLEEING
@ UNIT_FLAG_SILENCED
@ UNIT_FLAG_PLAYER_CONTROLLED
@ UNIT_FLAG_SKINNABLE
uint32 createProcHitMask(SpellNonMeleeDamage *damageInfo, SpellMissInfo missCondition)
Definition Unit.cpp:10001
@ UNIT_MASK_PUPPET
Definition Unit.h:370
@ JUST_DIED
Definition Unit.h:212
CurrentSpellTypes
Definition Unit.h:605
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:608
@ CURRENT_GENERIC_SPELL
Definition Unit.h:607
@ CURRENT_MELEE_SPELL
Definition Unit.h:606
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:609
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:234
@ UNIT_STATE_ROOT
Definition Unit.h:230
@ UNIT_STATE_CASTING
Definition Unit.h:235
std::vector< DispelableAura > DispelChargesList
Definition Unit.h:132
@ NULL_BAG
Definition Unit.h:61
@ NULL_SLOT
Definition Unit.h:62
@ NODAMAGE
Definition Unit.h:357
@ SPELL_DIRECT_DAMAGE
Definition Unit.h:354
@ CORPSE_FIELD_FLAGS
@ UNIT_MOD_CAST_SPEED
@ PLAYER_FLAGS
@ PLAYER_AMMO_ID
@ UNIT_CREATED_BY_SPELL
T AddPct(T &base, U pct)
Definition Util.h:77
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
Definition Util.h:554
T CalculatePct(T base, U pct)
Definition Util.h:71
SpellInfo const * GetSpellInfo() const
bool IsPeriodic() const
Aura * GetBase() const
UnitAura * ToUnitAura()
Definition SpellAuras.h:257
int32 GetMaxDuration() const
Definition SpellAuras.h:143
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
void SetStackAmount(uint8 num)
int32 GetDuration() const
Definition SpellAuras.h:148
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
int32 CalcMaxDuration() const
Definition SpellAuras.h:145
uint8 GetEffectMask() const
Definition SpellAuras.h:202
void SetDuration(int32 duration, bool withMods=false)
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:115
void SetMaxDuration(int32 duration)
Definition SpellAuras.h:144
bool IsPassive() const
static uint8 BuildEffectMaskForOwner(SpellInfo const *spellProto, uint8 availableEffectMask, WorldObject *owner)
virtual void Abort(uint64)
virtual bool IsDeletable() const
virtual bool Execute(uint64, uint32)
bool CanFlyIn()
Return if we can use mount in battlefield.
void append(T value)
Definition ByteBuffer.h:129
void InheritCombatStatesFrom(Unit const *who)
ObjectGuid GetOwnerGUID() const override
Definition Corpse.h:67
virtual void SpellHitTarget(WorldObject *, SpellInfo const *)
Definition CreatureAI.h:146
Loot loot
Definition Creature.h:209
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:186
void SetSpellFocus(Spell const *focusSpell, WorldObject const *target)
CreatureAI * AI() const
Definition Creature.h:154
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:102
GameObjectAI * AI() const
Definition GameObject.h:275
bool IsInRange(float x, float y, float z, float radius) const
GameobjectTypes GetGoType() const
Definition GameObject.h:176
iterator end()
Definition Util.h:405
ContainerType::iterator iterator
Definition Util.h:387
iterator begin()
Definition Util.h:400
Definition Item.h:62
void SetState(ItemUpdateState state, Player *forplayer=nullptr)
Definition Item.cpp:638
void SetSpellCharges(uint8 index, int32 value)
Definition Item.h:162
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:148
int32 GetSpellCharges(uint8 index=0) const
Definition Item.h:161
bool IsLocked() const
Definition Item.h:101
ItemTemplate const * GetTemplate() const
Definition Item.cpp:535
bool IsPotion() const
Definition Item.h:179
bool IsBroken() const
Definition Item.h:105
bool IsWeaponVellum() const
Definition Item.h:180
bool IsArmorVellum() const
Definition Item.h:181
Player * GetOwner() const
Definition Item.cpp:540
ObjectGuid GetOwnerGUID() const
Definition Item.h:76
uint32 GetCount() const
Definition Item.h:119
uint32 GetMaxStackCount() const
Definition Item.h:121
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition Item.cpp:847
bool HaveLootFor(uint32 loot_id) const
Definition LootMgr.h:78
Definition Map.h:281
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition Map.cpp:3518
bool IsDungeon() const
Definition Map.cpp:4236
bool IsBattlegroundOrArena() const
Definition Map.cpp:4277
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:4430
ZLiquidStatus GetLiquidStatus(uint32 phaseMask, float x, float y, float z, Optional< uint8 > ReqLiquidType, LiquidData *data=nullptr, float collisionHeight=2.03128f) const
Definition Map.cpp:2635
uint32 GetId() const
Definition Map.cpp:4216
Difficulty GetDifficulty() const
Definition Map.h:412
MovementGeneratorType GetCurrentMovementGeneratorType() const
static ObjectGuid const Empty
Definition ObjectGuid.h:140
static std::string_view GetTypeName(HighGuid high)
bool IsAnyTypeGameObject() const
Definition ObjectGuid.h:187
bool IsCorpse() const
Definition ObjectGuid.h:184
bool IsEmpty() const
Definition ObjectGuid.h:172
void SetRawValue(uint64 guid)
Definition ObjectGuid.h:149
uint64 GetRawValue() const
Definition ObjectGuid.h:148
bool IsUnit() const
Definition ObjectGuid.h:180
std::string ToString() const
bool IsGameObject() const
Definition ObjectGuid.h:182
PackedGuidReader ReadAsPacked()
Definition ObjectGuid.h:146
void Clear()
Definition ObjectGuid.h:150
static Creature * ToCreature(Object *o)
Definition Object.h:186
bool IsPlayer() const
Definition Object.h:179
PackedGuid const & GetPackGUID() const
Definition Object.h:80
static Unit * ToUnit(Object *o)
Definition Object.h:192
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:249
static GameObject * ToGameObject(Object *o)
Definition Object.h:198
bool IsInWorld() const
Definition Object.h:73
bool IsCorpse() const
Definition Object.h:203
bool IsUnit() const
Definition Object.h:191
TypeID GetTypeId() const
Definition Object.h:93
float GetFloatValue(uint16 index) const
Definition Object.cpp:261
uint32 GetEntry() const
Definition Object.h:81
bool IsCreature() const
Definition Object.h:185
static Corpse * ToCorpse(Object *o)
Definition Object.h:204
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:799
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:585
static Player * ToPlayer(Object *o)
Definition Object.h:180
Definition Pet.h:40
Player * GetOwner() const
Definition Pet.cpp:2000
bool HaveInDiet(ItemTemplate const *item) const
Definition Pet.cpp:1132
uint32 GetCurrentFoodBenefitLevel(uint32 itemlevel) const
Definition Pet.cpp:1150
static std::pair< PetStable::PetInfo const *, PetSaveMode > GetLoadPetInfo(PetStable const &stable, uint32 petEntry, uint32 petnumber, bool current)
Definition Pet.cpp:102
void SetRuneCooldown(uint8 index, uint32 cooldown, bool casted=false)
Definition Player.cpp:24354
void SetSpellModTakingSpell(Spell *spell, bool apply)
Definition Player.cpp:20934
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2297
bool HasItemFitToSpellRequirements(SpellInfo const *spellInfo, Item const *ignoreItem=nullptr) const
Definition Player.cpp:23427
uint32 GetFreeInventorySpace() const
Definition Player.cpp:9585
void SetLastUsedRune(RuneType type)
Definition Player.h:2211
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition Player.cpp:1878
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5892
Item * GetItemByEntry(uint32 entry) const
Definition Player.cpp:12461
void UpdatePotionCooldown(Spell *spell=nullptr)
Definition Player.cpp:21701
bool CanTameExoticPets() const
Definition Player.h:1902
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition Player.cpp:9763
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition Player.cpp:24193
bool InBattleground() const
Definition Player.h:1982
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:4654
PetStable * GetPetStable()
Definition Player.h:1067
bool IsLoading() const override
Definition Player.cpp:16870
Pet * GetPet() const
Definition Player.cpp:20286
bool HasItemTotemCategory(uint32 TotemCategory) const
Definition Player.cpp:10002
uint8 GetRunesState() const
Definition Player.h:2203
bool GetCommandStatus(uint32 command) const
Definition Player.h:1028
void RestoreBaseRune(uint8 index)
Definition Player.cpp:24403
bool HasSummonPending() const
Definition Player.cpp:23302
WorldSession * GetSession() const
Definition Player.h:1719
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:7660
bool CanNoReagentCast(SpellInfo const *spellInfo) const
Definition Player.cpp:23480
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition Player.cpp:12209
uint32 GetRuneCooldown(uint8 index) const
Definition Player.h:2206
Battleground * GetBattleground() const
Definition Player.cpp:23049
TradeData * GetTradeData() const
Definition Player.h:1210
RuneType GetCurrentRune(uint8 index) const
Definition Player.h:2205
bool IsGameMaster() const
Definition Player.h:998
void ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell *spell=nullptr) const
Definition Player.cpp:20807
void SendEquipError(InventoryResult msg, Item *pItem, Item *pItem2=nullptr, uint32 itemid=0) const
Definition Player.cpp:13075
void SendTameFailure(uint8 result)
Definition Player.cpp:2781
uint32 GetRuneBaseCooldown(uint8 index) const
Definition Player.h:2207
Player * GetSelectedPlayer() const
Definition Player.cpp:22385
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9607
std::unique_ptr< DuelInfo > duel
Definition Player.h:1602
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:1747
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9518
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:21687
Spell * m_spellModTakingSpell
Definition Player.h:2243
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition Player.cpp:9989
uint32 GetLastPotionId() const
Definition Player.h:1546
RuneType GetBaseRune(uint8 index) const
Definition Player.h:2204
InstancePlayerBind * GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired=false)
Definition Player.cpp:18564
ProcReflectDelayed(Unit *owner, ObjectGuid casterGuid)
Definition Spell.cpp:2096
bool Execute(uint64, uint32) override
Definition Spell.cpp:2098
ObjectGuid _casterGuid
Definition Spell.cpp:2116
SpellDestination const * GetSrc() const
Definition Spell.cpp:335
void SetItemTarget(Item *item)
Definition Spell.cpp:306
void RemoveObjectTarget()
Definition Spell.cpp:299
ObjectGuid m_objectTargetGUID
WorldObject * GetObjectTarget() const
Definition Spell.cpp:289
ObjectGuid GetUnitTargetGUID() const
Definition Spell.cpp:221
void ModDst(Position const &pos)
Definition Spell.cpp:414
GameObject * GetGOTarget() const
Definition Spell.cpp:255
void SetTradeItemTarget(Player *caster)
Definition Spell.cpp:317
SpellDestination m_dst
bool HasSrc() const
Definition Spell.cpp:431
bool HasTraj() const
Corpse * GetCorpseTarget() const
Definition Spell.cpp:281
void SetDst(float x, float y, float z, float orientation, uint32 mapId=MAPID_INVALID)
Definition Spell.cpp:384
void SetSrc(float x, float y, float z)
Definition Spell.cpp:345
void SetTargetFlag(SpellCastTargetFlags flag)
SpellDestination const * GetDst() const
Definition Spell.cpp:374
float GetElevation() const
void SetGOTarget(GameObject *target)
Definition Spell.cpp:263
std::string m_strTarget
void UpdateTradeSlotItem()
Definition Spell.cpp:326
SpellDestination m_src
ObjectGuid GetCorpseTargetGUID() const
Definition Spell.cpp:273
ObjectGuid GetObjectTargetGUID() const
Definition Spell.cpp:294
void SetUnitTarget(Unit *target)
Definition Spell.cpp:237
void Read(ByteBuffer &data, Unit *caster)
Definition Spell.cpp:130
bool HasDst() const
Definition Spell.cpp:436
ObjectGuid GetItemTargetGUID() const
WorldObject * m_objectTarget
Item * GetItemTarget() const
uint32 GetTargetMask() const
uint32 GetItemTargetEntry() const
Unit * GetUnitTarget() const
Definition Spell.cpp:229
ObjectGuid m_itemTargetGUID
float GetSpeedXY() const
float GetDist2d() const
void Update(WorldObject *caster)
Definition Spell.cpp:441
void ModSrc(Position const &pos)
Definition Spell.cpp:363
void RemoveDst()
Definition Spell.cpp:426
void Write(WorldPackets::Spells::SpellTargetData &data)
Definition Spell.cpp:183
void RemoveSrc()
Definition Spell.cpp:369
Position const * GetSrcPos() const
Definition Spell.cpp:340
ObjectGuid GetGOTargetGUID() const
Definition Spell.cpp:247
WorldLocation const * GetDstPos() const
Definition Spell.cpp:379
AuraType ApplyAuraName
Definition SpellInfo.h:211
float CalcRadius(WorldObject *caster=nullptr, Spell *=nullptr) const
uint32 TriggerSpell
Definition SpellInfo.h:228
SpellEffects Effect
Definition SpellInfo.h:210
bool IsAreaAuraEffect() const
uint32 GetMissingTargetMask(bool srcSet=false, bool destSet=false, uint32 mask=0) const
uint32 ChainTargets
Definition SpellInfo.h:226
bool HasRadius() const
bool IsEffect() const
int32 CalcValue(WorldObject const *caster=nullptr, int32 const *basePoints=nullptr) const
bool IsTargetingArea() const
SpellEffectImplicitTargetTypes GetImplicitTargetType() const
std::vector< Condition * > * ImplicitTargetConditions
Definition SpellInfo.h:230
SpellEffIndex EffectIndex
Definition SpellInfo.h:209
SpellImplicitTargetInfo TargetA
Definition SpellInfo.h:223
int32 CalcBaseValue(int32 value) const
SpellImplicitTargetInfo TargetB
Definition SpellInfo.h:224
bool IsDeletable() const override
Definition Spell.cpp:7685
Trinity::unique_trackable_ptr< Spell > m_Spell
Definition Spell.cpp:505
std::string GetDebugInfo() const
Definition Spell.cpp:502
void Abort(uint64 e_time) override
Definition Spell.cpp:7678
Trinity::unique_weak_ptr< Spell > GetSpellWeakPtr() const
Definition Spell.cpp:500
SpellEvent(Spell *spell)
Definition Spell.cpp:7573
bool Execute(uint64 e_time, uint32 p_time) override
Definition Spell.cpp:7590
Spell const * GetSpell() const
Definition Spell.cpp:499
bool IsReady(SpellInfo const *spellInfo, uint32 itemId=0, bool ignoreCategoryCooldown=false) const
bool HasGlobalCooldown(SpellInfo const *spellInfo) const
void ResetCooldown(uint32 spellId, bool update=false)
void AddGlobalCooldown(SpellInfo const *spellInfo, uint32 duration)
void CancelGlobalCooldown(SpellInfo const *spellInfo)
void HandleCooldowns(SpellInfo const *spellInfo, Item const *item, Spell *spell=nullptr)
SpellTargetCheckTypes GetCheckType() const
Definition SpellInfo.cpp:89
SpellTargetReferenceTypes GetReferenceType() const
Definition SpellInfo.cpp:79
SpellTargetSelectionCategories GetSelectionCategory() const
Definition SpellInfo.cpp:74
SpellTargetObjectTypes GetObjectType() const
Definition SpellInfo.cpp:84
float CalcDirectionAngle() const
Definition SpellInfo.cpp:99
Targets GetTarget() const
uint32 ChannelInterruptFlags
Definition SpellInfo.h:323
uint32 RequiresSpellFocus
Definition SpellInfo.h:306
uint32 MaxLevel
Definition SpellInfo.h:327
uint32 SpellLevel
Definition SpellInfo.h:329
std::array< int32, MAX_SPELL_REAGENTS > Reagent
Definition SpellInfo.h:342
uint32 PreventionType
Definition SpellInfo.h:359
uint32 CasterAuraSpell
Definition SpellInfo.h:312
uint32 RuneCostID
Definition SpellInfo.h:337
SpellInfo const * GetFirstRankSpell() const
float GetMaxRange(bool positive=false, WorldObject *caster=nullptr, Spell *spell=nullptr) const
SpellCastResult CheckShapeshift(uint32 form) const
bool IsRequiringDeadTarget() const
flag96 SpellFamilyFlags
Definition SpellInfo.h:357
std::array< uint32, 2 > TotemCategory
Definition SpellInfo.h:347
bool IsCooldownStartedOnEvent() const
bool IsPassive() const
uint32 StackAmount
Definition SpellInfo.h:340
uint32 Mechanic
Definition SpellInfo.h:292
uint32 Id
Definition SpellInfo.h:289
SpellRangeEntry const * RangeEntry
Definition SpellInfo.h:338
int32 RequiredAreasID
Definition SpellInfo.h:360
uint32 GetDispelMask() const
uint32 CalcCastTime(Spell *spell=nullptr) const
SpellInfo const * GetAuraRankForLevel(uint8 level) const
uint32 GetRecoveryTime() const
Powers PowerType
Definition SpellInfo.h:331
uint32 ExcludeCasterAuraState
Definition SpellInfo.h:310
float Speed
Definition SpellInfo.h:339
float GetMinRange(bool positive=false) const
int32 GetMaxDuration() const
int32 EquippedItemClass
Definition SpellInfo.h:344
bool HasInitialAggro() const
uint32 SchoolMask
Definition SpellInfo.h:361
std::array< uint32, 2 > Totem
Definition SpellInfo.h:341
uint32 CasterAuraState
Definition SpellInfo.h:308
SpellCastResult CheckTarget(WorldObject const *caster, WorldObject const *target, bool implicit=true) const
std::array< uint32, 2 > SpellVisual
Definition SpellInfo.h:348
DiminishingGroup GetDiminishingReturnsGroupForSpell(bool triggered) const
bool CanBeUsedInCombat() const
bool IsAllowingDeadTarget() const
WeaponAttackType GetAttackType() const
SpellSchoolMask GetSchoolMask() const
std::array< uint32, MAX_SPELL_REAGENTS > ReagentCount
Definition SpellInfo.h:343
bool NeedsComboPoints() const
bool IsChanneled() const
bool HasAttribute(SpellAttr0 attribute) const
Definition SpellInfo.h:375
uint32 InterruptFlags
Definition SpellInfo.h:321
bool IsNextMeleeSwingSpell() const
int32 CalcPowerCost(WorldObject const *caster, SpellSchoolMask schoolMask, Spell *spell=nullptr) const
bool SpellCancelsAuraEffect(AuraEffect const *aurEff) const
uint32 MaxAffectedTargets
Definition SpellInfo.h:355
int32 GetDuration() const
SpellCastResult CheckVehicle(Unit const *caster) const
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:483
int32 EquippedItemSubClassMask
Definition SpellInfo.h:345
uint32 GetExplicitTargetMask() const
uint32 FacingCasterFlags
Definition SpellInfo.h:307
SpellCastResult CheckExplicitTarget(WorldObject const *caster, WorldObject const *target, Item const *itemTarget=nullptr) const
uint32 StartRecoveryTime
Definition SpellInfo.h:320
uint32 SpellIconID
Definition SpellInfo.h:349
uint32 GetMechanicImmunityMask(Unit *caster) const
bool NeedsExplicitUnitTarget() const
DiminishingReturnsType GetDiminishingReturnsGroupType(bool triggered) const
bool HasEffect(SpellEffects effect) const
bool IsPositive() const
bool IsAutoRepeatRangedSpell() const
SpellCastResult CheckLocation(uint32 map_id, uint32 zone_id, uint32 area_id, Player const *player=nullptr, bool strict=true) const
bool IsMoveAllowedChannel() const
uint32 DmgClass
Definition SpellInfo.h:358
bool IsRangedWeaponSpell() const
uint32 AttributesEx4
Definition SpellInfo.h:297
uint32 ExcludeCasterAuraSpell
Definition SpellInfo.h:314
bool HasAura(AuraType aura) const
bool IsTargetingArea() const
std::array< SpellEffectInfo, MAX_SPELL_EFFECTS > const & GetEffects() const
Definition SpellInfo.h:482
uint32 StartRecoveryCategory
Definition SpellInfo.h:319
uint32 SpellFamilyName
Definition SpellInfo.h:356
std::array< char const *, 16 > SpellName
Definition SpellInfo.h:352
uint32 AuraInterruptFlags
Definition SpellInfo.h:322
bool IsBreakingStealth() const
bool IsPositiveEffect(uint8 effIndex) const
Definition Spell.h:152
void CheckDst()
Definition Spell.cpp:6532
SpellInfo const * GetSpellInfo() const
Definition Spell.h:452
float m_damageMultipliers[MAX_SPELL_EFFECTS]
Definition Spell.h:520
bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const *triggeredByAura=nullptr) const
Definition Spell.cpp:8206
Unit * m_comboTarget
Definition Spell.h:414
void AssertEffectExecuteData() const
Definition Spell.cpp:7950
bool m_fromClient
Definition Spell.h:400
int8 m_comboPointGain
Definition Spell.h:415
void CallScriptAfterCastHandlers()
Definition Spell.cpp:7992
void AddCorpseTarget(Corpse *target, uint32 effectMask)
Definition Spell.cpp:2314
GameObject * SearchSpellFocus()
Definition Spell.cpp:2011
std::vector< SpellScript * > m_loadedScripts
Definition Spell.h:672
GameObject * gameObjTarget
Definition Spell.h:525
std::pair< float, float > GetMinMaxRange(bool strict) const
Definition Spell.cpp:6586
void PrepareTriggersExecutedOnHit()
Definition Spell.cpp:8218
SpellMissInfo targetMissInfo
Definition Spell.h:529
bool m_referencedFromCurrentSpell
Definition Spell.h:516
bool m_canReflect
Definition Spell.h:496
void PreprocessSpellLaunch(TargetInfo &targetInfo)
Definition Spell.cpp:7750
uint32 m_procVictim
Definition Spell.h:549
uint32 m_hitMask
Definition Spell.h:550
Unit * m_originalCaster
Definition Spell.h:488
SpellCastResult CheckArenaCastRules() const
Definition Spell.cpp:6433
void LoadScripts()
Definition Spell.cpp:7956
uint64 CalculateDelayMomentForDst() const
Definition Spell.cpp:899
void SelectImplicitTrajTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1645
DynObjAura * _dynObjAura
Definition Spell.h:535
void cast(bool skipCheck=false)
Definition Spell.cpp:3323
void SendChannelStart(uint32 duration)
Definition Spell.cpp:4696
bool m_needComboPoints
Definition Spell.h:518
uint64 m_delayStart
Definition Spell.h:511
SpellCastTargets m_targets
Definition Spell.h:402
bool CheckSpellCancelsAuraEffect(AuraType auraType, uint32 *param1) const
Definition Spell.cpp:6363
std::unique_ptr< PathGenerator > m_preGeneratedPath
Definition Spell.h:709
void SendPetCastResult(SpellCastResult result)
Definition Spell.cpp:4205
void CallScriptBeforeHitHandlers(SpellMissInfo missInfo)
Definition Spell.cpp:8087
SpellCastResult CheckRuneCost(uint32 runeCostID) const
Definition Spell.cpp:4916
void InitEffectExecuteData(uint8 effIndex)
Definition Spell.cpp:7933
void SelectExplicitTargets()
Definition Spell.cpp:708
void handle_immediate()
Definition Spell.cpp:3617
void SendSpellGo()
Definition Spell.cpp:4311
TriggerCastFlags _triggeredCastFlags
Definition Spell.h:701
bool IsAutoRepeat() const
Definition Spell.h:421
int32 damage
Definition Spell.h:528
void SetSpellValue(SpellValueMod mod, int32 value)
Definition Spell.cpp:7895
void HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, Corpse *pCorpseTarget, SpellEffectInfo const &spellEffectInfo, SpellEffectHandleMode mode)
Definition Spell.cpp:5159
void ExecuteLogEffectSummonObject(uint8 effIndex, WorldObject *obj)
Definition Spell.cpp:4641
void prepareDataForTriggerSystem()
Definition Spell.cpp:2020
SpellEffectHandleMode effectHandleMode
Definition Spell.h:530
void TakeReagents()
Definition Spell.cpp:5053
bool IsValidDeadOrAliveTarget(Unit const *target) const
Definition Spell.cpp:7690
int32 m_channeledDuration
Definition Spell.h:495
SpellCastResult CheckMovement() const
Definition Spell.cpp:6452
bool CheckSpellCancelsPacify(uint32 *param1) const
Definition Spell.cpp:6412
void DoProcessTargetContainer(Container &targetContainer)
Definition Spell.cpp:3603
WorldObject * SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer *condList=nullptr)
Definition Spell.cpp:1888
bool IsNeedSendToClient() const
Definition Spell.cpp:7562
bool IsIgnoringCooldowns() const
Definition Spell.cpp:7525
static void WriteCastResultInfo(WorldPacket &data, Player *caster, SpellInfo const *spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:3997
std::vector< TargetInfo > m_UniqueTargetInfo
Definition Spell.h:600
SpellDestination m_destTargets[MAX_SPELL_EFFECTS]
Definition Spell.h:632
void UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo &data)
Definition Spell.cpp:4429
void _handle_finish_phase()
Definition Spell.cpp:3786
void PrepareTargetProcessing()
Definition Spell.cpp:7923
Trinity::unique_weak_ptr< Spell > GetWeakPtr() const
Definition Spell.cpp:8329
void SetExecutedCurrently(bool yes)
Definition Spell.h:437
void AddUnitTarget(Unit *target, uint32 effectMask, bool checkIfValid=true, bool implicit=true, Position const *losPosition=nullptr)
Definition Spell.cpp:2119
void SendSpellStart()
Definition Spell.cpp:4244
uint8 m_delayAtDamageCount
Definition Spell.h:500
void SendChannelUpdate(uint32 time)
Definition Spell.cpp:4676
uint64 m_delayMoment
Definition Spell.h:512
void SendLogExecute()
Definition Spell.cpp:4558
WeaponAttackType m_attackType
Definition Spell.h:492
void _cast(bool skipCheck=false)
Definition Spell.cpp:3340
void SelectImplicitNearbyTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1063
bool IsProcDisabled() const
Definition Spell.cpp:7535
bool m_immediateHandled
Definition Spell.h:513
uint32 m_spellState
Definition Spell.h:697
bool IsFocusDisabled() const
Definition Spell.cpp:7530
ObjectGuid m_originalCasterGUID
Definition Spell.h:486
WorldObject *const m_caster
Definition Spell.h:482
void TakeAmmo()
Definition Spell.cpp:4882
int64 GetItemTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2381
std::string GetDebugInfo() const
Definition Spell.cpp:8320
bool IsDeletable() const
Definition Spell.h:434
bool UpdateChanneledTargetList()
Definition Spell.cpp:3011
void CleanupTargetList()
Definition Spell.cpp:2085
void TriggerGlobalCooldown()
Definition Spell.cpp:8273
int32 m_timer
Definition Spell.h:698
int32 m_casttime
Definition Spell.h:494
void ExecuteLogEffectOpenLock(uint8 effIndex, Object *obj)
Definition Spell.cpp:4623
void SendMountResult(MountResult result)
Definition Spell.cpp:4227
Item * itemTarget
Definition Spell.h:524
void AddGOTarget(GameObject *target, uint32 effectMask)
Definition Spell.cpp:2224
void HandleThreatSpells()
Definition Spell.cpp:5103
uint8 m_cast_count
Definition Spell.h:399
int32 m_damage
Definition Spell.h:542
std::vector< CorpseTargetInfo > m_UniqueCorpseTargetInfo
Definition Spell.h:627
void ExecuteLogEffectTakeTargetPower(uint8 effIndex, Unit *target, uint32 powerType, uint32 powerTaken, float gainMultiplier)
Definition Spell.cpp:4592
void CancelGlobalCooldown()
Definition Spell.cpp:8305
bool CheckSpellCancelsCharm(uint32 *param1) const
Definition Spell.cpp:6393
void SendInterrupted(SpellCastResult result, Optional< SpellCastResult > resultOther={})
Definition Spell.cpp:4659
uint32 getState() const
Definition Spell.h:356
void SelectImplicitCasterDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1340
bool m_executedCurrently
Definition Spell.h:517
uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionContainer *condList)
Definition Spell.cpp:1828
void CallScriptOnCastHandlers()
Definition Spell.cpp:7979
void AddDestTarget(SpellDestination const &dest, uint32 effIndex)
Definition Spell.cpp:2360
void SelectImplicitAreaTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1255
int64 GetGameObjectTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2373
SpellCastResult CheckItems(uint32 *param1, uint32 *param2) const
Definition Spell.cpp:6684
void SelectImplicitCasterObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1528
void SelectImplicitTargetDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1461
void SelectEffectImplicitTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effectMask)
Definition Spell.cpp:926
ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS]
Definition Spell.h:711
void _handle_immediate_phase()
Definition Spell.cpp:3766
void SendSpellCooldown()
Definition Spell.cpp:3824
void CallScriptBeforeCastHandlers()
Definition Spell.cpp:7966
uint8 m_auraScaleMask
Definition Spell.h:708
void HandleLaunchPhase()
Definition Spell.cpp:7699
SpellMissInfo PreprocessSpellHit(Unit *unit, bool scaleAura, TargetInfo &targetInfo)
Definition Spell.cpp:2760
bool UpdatePointers()
Definition Spell.cpp:7347
SpellCustomErrors m_customError
Definition Spell.h:416
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode)
Definition Spell.cpp:8024
std::vector< GOTargetInfo > m_UniqueGOTargetInfo
Definition Spell.h:610
void DoSpellEffectHit(Unit *unit, SpellEffectInfo const &spellEffectInfo, TargetInfo &targetInfo)
Definition Spell.cpp:2889
void SearchAreaTargets(std::list< WorldObject * > &targets, float range, Position const *position, WorldObject *referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer *condList)
Definition Spell.cpp:1902
HitTriggerSpellList m_hitTriggerSpells
Definition Spell.h:688
int32 m_healing
Definition Spell.h:543
void SetDelayStart(uint64 m_time)
Definition Spell.h:439
SpellEffectInfo const * effectInfo
Definition Spell.h:531
uint32 m_glyphIndex
Definition Spell.h:401
Unit * GetUnitCasterForEffectHandlers() const
Definition Spell.cpp:7568
SpellInfo const * m_triggeredByAuraSpell
Definition Spell.h:706
uint64 handle_delayed(uint64 t_offset)
Definition Spell.cpp:3678
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:8334
uint8 m_channelTargetEffectMask
Definition Spell.h:601
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:7402
UnitAura * _spellAura
Definition Spell.h:534
Unit * unitTarget
Definition Spell.h:523
void Delayed()
Definition Spell.cpp:7258
SpellSchoolMask m_spellSchoolMask
Definition Spell.h:491
void cancel(SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={})
Definition Spell.cpp:3271
WorldObject * GetCaster() const
Definition Spell.h:450
void ExecuteLogEffectUnsummonObject(uint8 effIndex, WorldObject *obj)
Definition Spell.cpp:4647
SpellEvent * _spellEvent
Definition Spell.h:700
void SelectImplicitChannelTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1007
void SelectSpellTargets()
Definition Spell.cpp:737
void ExecuteLogEffectInterruptCast(uint8 effIndex, Unit *victim, uint32 spellId)
Definition Spell.cpp:4608
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3070
void ExecuteLogEffectResurrect(uint8 effIndex, Unit *target)
Definition Spell.cpp:4653
bool IsChannelActive() const
Definition Spell.cpp:7540
~Spell()
Definition Spell.cpp:612
SpellCastResult CheckCasterAuras(uint32 *param1) const
Definition Spell.cpp:6237
void TakePower()
Definition Spell.cpp:4815
SpellCastResult CheckPetCast(Unit *target)
Definition Spell.cpp:6196
void RecalculateDelayMomentForDst()
Definition Spell.cpp:920
Corpse * m_corpseTarget
Definition Spell.h:526
Spell(WorldObject *caster, SpellInfo const *info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID=ObjectGuid::Empty)
Definition Spell.cpp:508
void ReSetTimer()
Definition Spell.h:423
void SelectImplicitChainTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, WorldObject *target, uint32 effMask)
Definition Spell.cpp:1606
SpellCastResult CallScriptCheckCastHandlers()
Definition Spell.cpp:8005
void ExecuteLogEffectCreateItem(uint8 effIndex, uint32 entry)
Definition Spell.cpp:4629
bool IsPositive() const
Definition Spell.cpp:7557
void InitExplicitTargets(SpellCastTargets const &targets)
Definition Spell.cpp:638
WorldLocation * destTarget
Definition Spell.h:527
Spell ** m_selfContainer
Definition Spell.h:461
bool IsTriggered() const
Definition Spell.cpp:7520
SpellCastResult CanOpenLock(SpellEffectInfo const &spellEffectInfo, uint32 lockid, SkillType &skillid, int32 &reqSkillValue, int32 &skillValue)
Definition Spell.cpp:7828
uint8 m_applyMultiplierMask
Definition Spell.h:519
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:435
bool IsDelayableNoMore()
Definition Spell.h:501
void ExecuteLogEffectDestroyItem(uint8 effIndex, uint32 entry)
Definition Spell.cpp:4635
void SelectEffectTypeImplicitTargets(SpellEffectInfo const &spellEffectInfo)
Definition Spell.cpp:1728
bool CheckSpellCancelsStun(uint32 *param1) const
Definition Spell.cpp:6400
void update(uint32 difftime)
Definition Spell.cpp:3832
uint64 GetDelayStart() const
Definition Spell.h:438
bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
Definition Spell.cpp:8169
bool CheckSpellCancelsConfuse(uint32 *param1) const
Definition Spell.cpp:6423
Item * m_CastItem
Definition Spell.h:396
void CallScriptSuccessfulDispel(SpellEffIndex effIndex)
Definition Spell.cpp:8074
void DoEffectOnLaunchTarget(TargetInfo &targetInfo, float multiplier, SpellEffectInfo const &spellEffectInfo)
Definition Spell.cpp:7782
uint32 m_castItemEntry
Definition Spell.h:398
uint64 GetDelayMoment() const
Definition Spell.h:440
void AddItemTarget(Item *item, uint32 effectMask)
Definition Spell.cpp:2286
void SelectImplicitDestDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1492
UsedSpellMods m_appliedMods
Definition Spell.h:418
void TakeCastItem()
Definition Spell.cpp:4746
SpellCastResult CheckCast(bool strict, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:5178
void CheckSrc()
Definition Spell.cpp:6526
bool CheckSpellCancelsFear(uint32 *param1) const
Definition Spell.cpp:6418
void SelectImplicitConeTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1203
ObjectGuid m_focusObjectGUID
Definition Spell.h:538
SpellValue *const m_spellValue
Definition Spell.h:484
int32 m_powerCost
Definition Spell.h:493
void SearchChainTargets(std::list< WorldObject * > &targets, uint32 chainTargets, WorldObject *target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer *condList, bool isChainHeal)
Definition Spell.cpp:1915
bool CheckEffectTarget(Unit const *target, SpellEffectInfo const &spellEffectInfo, Position const *losPosition) const
Definition Spell.cpp:7414
void SendResurrectRequest(Player *target)
Definition Spell.cpp:4728
void SearchTargets(SEARCHER &searcher, uint32 containerMask, WorldObject *referer, Position const *pos, float radius)
Definition Spell.cpp:1864
std::vector< ItemTargetInfo > m_UniqueItemInfo
Definition Spell.h:618
bool IsAutoActionResetSpell() const
Definition Spell.cpp:7545
bool CheckSpellCancelsSilence(uint32 *param1) const
Definition Spell.cpp:6406
void ExecuteLogEffectDurabilityDamage(uint8 effIndex, Unit *victim, int32 itemId, int32 slot)
Definition Spell.cpp:4615
void DelayedChannel()
Definition Spell.cpp:7297
ObjectGuid m_castItemGUID
Definition Spell.h:397
uint32 m_procAttacker
Definition Spell.h:548
int64 GetUnitTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2365
SpellCastResult CheckPower() const
Definition Spell.cpp:6644
GameObject * focusObject
Definition Spell.h:539
void CallScriptDestinationTargetSelectHandlers(SpellDestination &target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8155
void ExecuteLogEffectExtraAttacks(uint8 effIndex, Unit *victim, uint32 attCount)
Definition Spell.cpp:4601
void finish(bool ok=true)
Definition Spell.cpp:3912
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData &data)
Writes miss and hit targets for a SMSG_SPELL_GO packet.
Definition Spell.cpp:4514
static void SendCastResult(Player *caster, SpellInfo const *spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError=SPELL_CUSTOM_ERROR_NONE, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:4177
SpellInfo const *const m_spellInfo
Definition Spell.h:395
bool HasGlobalCooldown() const
Definition Spell.cpp:8265
uint8 m_runesState
Definition Spell.h:498
void FinishTargetProcessing()
Definition Spell.cpp:7928
void DoTriggersOnSpellHit(Unit *unit, uint8 effMask)
Definition Spell.cpp:2962
void CallScriptOnHitHandlers()
Definition Spell.cpp:8101
SpellCastResult CheckRange(bool strict) const
Definition Spell.cpp:6538
bool m_autoRepeat
Definition Spell.h:497
void CallScriptObjectTargetSelectHandlers(WorldObject *&target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8141
int32 CalculateDamage(SpellEffectInfo const &spellEffectInfo) const
Definition Spell.cpp:6428
void TakeRunePower(bool didHit)
Definition Spell.cpp:4963
void CallScriptObjectAreaTargetSelectHandlers(std::list< WorldObject * > &targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8127
void SelectImplicitTargetObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1582
void CallScriptAfterHitHandlers()
Definition Spell.cpp:8114
bool CanAutoCast(Unit *target)
Definition Spell.cpp:6470
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
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 AddStaticApplication(Unit *target, uint8 effMask)
void SetDiminishGroup(DiminishingGroup group)
Definition SpellAuras.h:333
Definition Unit.h:769
int32 ModifyHealth(int32 val)
Definition Unit.cpp:8381
Unit * GetCharmed() const
Definition Unit.h:1256
void ClearUnitState(uint32 f)
Definition Unit.h:877
uint32 GetChannelSpellId() const
Definition Unit.h:1458
void SetLastDamagedTargetGuid(ObjectGuid guid)
Definition Unit.h:1046
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8439
bool IsCharmed() const
Definition Unit.h:1280
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5111
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1384
uint32 m_lastSanctuaryTime
Definition Unit.h:1569
void SetChannelObjectGuid(ObjectGuid guid)
Definition Unit.h:1461
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4439
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7300
Pet * ToPet()
Definition Unit.h:1788
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1122
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3638
ThreatManager & GetThreatManager()
Definition Unit.h:1155
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1146
uint8 GetClass() const
Definition Unit.h:895
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except=0)
Definition Unit.cpp:4022
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4420
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:995
void StopMoving(bool force=false)
Definition Unit.cpp:10312
bool IsInDisallowedMountForm() const
Definition Unit.cpp:8975
virtual bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7691
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1109
bool IsPvP() const
Definition Unit.h:988
bool haveOffhandWeapon() const
Definition Unit.cpp:510
MotionMaster * GetMotionMaster()
Definition Unit.h:1667
bool IsPet() const
Definition Unit.h:884
Powers GetPowerType() const
Definition Unit.h:931
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:953
bool CanProc() const
Definition Unit.h:1726
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1255
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3063
void UpdateInterruptMask()
Definition Unit.cpp:660
void SetChannelSpellId(uint32 channelSpellId)
Definition Unit.h:1459
bool IsFullHealth() const
Definition Unit.h:916
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:959
bool HasAuraWithMechanic(uint32 mechanicMask) const
Definition Unit.cpp:4602
bool IsAlive() const
Definition Unit.h:1234
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition Unit.cpp:4639
float GetCombatReach() const override
Definition Unit.h:839
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6420
float SpellCritChanceTaken(Unit const *caster, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:7069
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5185
UnitFlags GetUnitFlags() const
Definition Unit.h:952
bool IsStandState() const
Definition Unit.cpp:10357
CharmInfo * GetCharmInfo()
Definition Unit.h:1287
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1260
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4535
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6221
std::map< uint8, AuraApplication * > VisibleAuraMap
Definition Unit.h:794
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:821
float SpellCritChanceDone(SpellInfo const *spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:7015
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:11821
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1261
void SetLastManaUse(uint32 spellCastTime)
Definition Unit.h:1630
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7811
bool IsInFlight() const
Definition Unit.h:1119
bool IsAIEnabled() const
Definition Unit.h:798
static void ProcSkillsAndAuras(Unit *actor, Unit *actionTarget, uint32 typeMaskActor, uint32 typeMaskActionTarget, uint32 spellTypeMask, uint32 spellPhaseMask, uint32 hitMask, Spell *spell, DamageInfo *damageInfo, HealInfo *healInfo)
Definition Unit.cpp:5240
uint32 GetMaxPower(Powers power) const
Definition Unit.h:936
bool IsSummon() const
Definition Unit.h:882
bool IsInWater() const
Definition Unit.cpp:3162
uint32 GetHealth() const
Definition Unit.h:913
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5054
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition Unit.cpp:4463
bool isMoving() const
Definition Unit.h:1759
VisibleAuraMap const & GetVisibleAuras() const
Definition Unit.h:1571
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8292
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4792
bool IsMounted() const
Definition Unit.h:1013
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, bool triggered, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:8858
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3784
Unit * GetVictim() const
Definition Unit.h:859
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7639
DeathState getDeathState() const
Definition Unit.h:1238
ObjectGuid GetChannelObjectGuid() const
Definition Unit.h:1460
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:11856
bool IsCritter() const
Definition Unit.h:1117
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const &casterGuid) const
Definition Unit.cpp:12091
bool HasUnitState(const uint32 f) const
Definition Unit.h:876
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:11892
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5038
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:634
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10363
SpellHistory * GetSpellHistory()
Definition Unit.h:1484
void IncrDiminishing(SpellInfo const *auraSpellInfo, bool triggered)
Definition Unit.cpp:8847
bool IsControlledByPlayer() const
Definition Unit.h:1258
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:8834
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1252
virtual void setDeathState(DeathState s)
Definition Unit.cpp:8728
uint32 GetPower(Powers power) const
Definition Unit.h:934
CombatManager & GetCombatManager()
Definition Unit.h:1130
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4564
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:787
void RemoveMovementImpairingAuras(bool withRoot)
Definition Unit.cpp:4069
bool IsSpiritHealer() const
Definition Unit.h:1110
bool IsTotem() const
Definition Unit.h:886
Vehicle * GetVehicleKit() const
Definition Unit.h:1735
Guardian * GetGuardianPet() const
Definition Unit.cpp:5894
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:598
virtual bool IsEngaged() const
Definition Unit.h:1126
bool AttackStop()
Definition Unit.cpp:5645
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:11873
static void DealDamageMods(Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:706
ObjectGuid GetTarget() const
Definition Unit.h:1797
uint8 GetLevel() const
Definition Unit.h:889
bool IsInCombat() const
Definition Unit.h:1144
bool IsWalking() const
Definition Unit.h:1219
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9312
ObjectGuid GetPetGUID() const
Definition Unit.h:1247
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1476
bool isLineOfSightCalcEnabled() const
static VMapManager2 * createOrGetVMapManager()
bool IsControllableVehicle() const
Definition Vehicle.cpp:599
uint32 GetMapId() const
Definition Position.h:193
uint32 m_mapId
Definition Position.h:195
Unit * GetMagicHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo)
Definition Object.cpp:3101
uint32 GetPhaseMask() const
Definition Object.h:368
bool IsWithinDist2d(float x, float y, float dist) const
Definition Object.cpp:1177
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1783
Map * GetMap() const
Definition Object.h:449
virtual float GetCollisionHeight() const
Definition Object.h:583
Unit * GetCharmerOrOwner() const
Definition Object.cpp:2185
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:2620
bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1206
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition Object.cpp:3244
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition Object.cpp:3606
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2832
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2856
float GetTransOffsetX() const
Definition Object.h:565
void MovePositionToFirstCollision(Position &pos, float dist, float angle)
Definition Object.cpp:3323
bool GetDistanceOrder(WorldObject const *obj1, WorldObject const *obj2, bool is3D=true) const
Definition Object.cpp:1260
bool isInFront(WorldObject const *target, float arc=float(M_PI)) const
Definition Object.cpp:1366
bool IsOutdoors() const
Definition Object.h:377
int32 ModSpellDuration(SpellInfo const *spellInfo, WorldObject const *target, int32 duration, bool positive, uint32 effectMask) const
Definition Object.cpp:2320
float GetTransOffsetY() const
Definition Object.h:566
float GetTransOffsetZ() const
Definition Object.h:567
virtual std::string const & GetNameForLocaleIdx(LocaleConstant) const
Definition Object.h:385
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1226
virtual ObjectGuid GetTransGUID() const
Definition Object.cpp:3579
bool isInBack(WorldObject const *target, float arc=float(M_PI)) const
Definition Object.cpp:1371
Player * GetSpellModOwner() const
Definition Object.cpp:2223
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:2203
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1192
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:3000
EventProcessor m_Events
Definition Object.h:591
float GetVisibilityRange() const
Definition Object.cpp:1492
float GetSpellMinRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition Object.cpp:2267
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition Object.cpp:2571
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:1123
uint32 GetAreaId() const
Definition Object.h:374
float GetTransOffsetO() const
Definition Object.h:568
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition Object.cpp:1187
uint32 GetZoneId() const
Definition Object.h:373
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition Object.h:375
float GetSpellMaxRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition Object.cpp:2253
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2801
virtual float GetCombatReach() const
Definition Object.h:358
int32 CalculateSpellDamage(SpellEffectInfo const &spellEffectInfo, int32 const *basePoints=nullptr) const
Definition Object.cpp:2248
void ModSpellDurationTime(SpellInfo const *spellInfo, int32 &durationTime, Spell *spell=nullptr) const
Definition Object.cpp:2436
void Initialize(uint16 opcode, size_t newres=200)
Definition WorldPacket.h:73
void push_back(value_type const &value)
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
LocaleConstant GetSessionDbLocaleIndex() const
uint32 GetRecruiterId() const
uint32 GetAccountId() const
@ SMSG_SPELL_FAILURE
Definition Opcodes.h:336
@ SMSG_SPELLLOGEXECUTE
Definition Opcodes.h:617
@ SMSG_SPELL_DELAYED
Definition Opcodes.h:511
@ MSG_CHANNEL_START
Definition Opcodes.h:342
@ SMSG_CAST_FAILED
Definition Opcodes.h:333
@ MSG_CHANNEL_UPDATE
Definition Opcodes.h:343
@ SMSG_SPELL_FAILED_OTHER
Definition Opcodes.h:707
@ SMSG_RESURRECT_REQUEST
Definition Opcodes.h:376
@ SMSG_PET_CAST_FAILED
Definition Opcodes.h:341
#define sWorld
Definition World.h:900
@ RATE_POWER_RUNICPOWER_INCOME
Definition World.h:414
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
uint32 GetGameTimeMS()
Definition GameTime.cpp:47
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 Corpse * GetCorpse(WorldObject const &u, ObjectGuid const &guid)
TC_GAME_API Creature * GetCreatureOrPetOrVehicle(WorldObject const &, ObjectGuid const &)
void RandomResize(C &container, std::size_t requestedSize)
Definition Containers.h:66
AuraCreateInfo & SetCastItemGUID(ObjectGuid const &guid)
AuraCreateInfo & SetBaseAmount(int32 const *bp)
AuraCreateInfo & SetOwnerEffectMask(uint8 effMask)
AuraCreateInfo & SetCasterGUID(ObjectGuid const &guid)
static void VisitGridObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:168
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:180
Condition const * mLastFailedCondition
uint32 ErrorType
uint8 ConditionTarget
uint32 ErrorTextId
SkillType GetRequiredLootSkill() const
bool IsTameable(bool canTameExotic) const
bool CannotBeUsedUnderImmunity() const
std::array< ItemEffect, MAX_ITEM_PROTO_SPELLS > Effects
uint32 DisenchantID
uint32 RequiredSkillRank
uint32 GetMaxStackSize() const
std::array< _Socket, MAX_ITEM_PROTO_SOCKETS > Socket
uint32 RequiredDisenchantSkill
uint32 RequiredLevel
uint32 DisplayInfoID
bool HasFlag(ItemFlags flag) const
uint32 ItemLimitCategory
uint32 InventoryType
float level
Definition MapDefines.h:89
uint32 Type[MAX_LOCK_CASE]
uint32 Index[MAX_LOCK_CASE]
uint32 Skill[MAX_LOCK_CASE]
bool isLooted() const
Definition Loot.h:239
bool IsDungeon() const
bool IsRaid() const
float m_positionZ
Definition Position.h:58
float GetExactDist2d(const float x, const float y) const
Definition Position.h:109
float GetRelativeAngle(float x, float y) const
Definition Position.h:139
float GetExactDist(float x, float y, float z) const
Definition Position.h:121
float m_positionX
Definition Position.h:56
float GetPositionZ() const
Definition Position.h:81
float m_positionY
Definition Position.h:57
bool HasInLine(Position const *pos, float objSize, float width) const
Definition Position.cpp:139
float GetOrientation() const
Definition Position.h:82
bool HasInArc(float arcangle, Position const *pos, float border=2.0f) const
Definition Position.cpp:120
Streamer< XYZ > PositionXYZStream()
Definition Position.h:91
void SetOrientation(float orientation)
Definition Position.h:74
float GetPositionX() const
Definition Position.h:79
void GetPosition(float &x, float &y) const
Definition Position.h:84
void GetPositionOffsetTo(Position const &endPos, Position &retOffset) const
Definition Position.cpp:49
float GetPositionY() const
Definition Position.h:80
float GetExactDistSq(float x, float y, float z) const
Definition Position.h:113
void RelocateOffset(Position const &offset)
Definition Position.cpp:36
void Relocate(float x, float y)
Definition Position.h:66
void RelocateOffset(Position const &offset)
Definition Spell.cpp:110
Position _transportOffset
WorldLocation _position
void Relocate(Position const &pos)
Definition Spell.cpp:99
ObjectGuid _transportGUID
uint32 Effect[MAX_ITEM_ENCHANTMENT_EFFECTS]
bool NoRuneCost() const
bool NoRunicPowerGain() const
float RadiusMod
Definition Spell.h:124
SpellValue(SpellInfo const *proto)
Definition Spell.cpp:480
int32 EffectBasePoints[MAX_SPELL_EFFECTS]
Definition Spell.h:122
uint32 MaxAffectedTargets
Definition Spell.h:123
float CriticalChance
Definition Spell.h:126
uint8 AuraStackAmount
Definition Spell.h:125
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2746
ObjectGuid TargetGUID
Definition Spell.h:624
ObjectGuid TargetGUID
Definition Spell.h:607
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2713
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2736
UnitAura * HitAura
Definition Spell.h:594
SpellInfo const * AuraSpellInfo
Definition Spell.h:591
void PreprocessTarget(Spell *spell) override
Definition Spell.cpp:2389
SpellMissInfo MissCondition
Definition Spell.h:581
int32 AuraBasePoints[MAX_SPELL_EFFECTS]
Definition Spell.h:592
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2439
void DoDamageAndTriggers(Spell *spell) override
Definition Spell.cpp:2468
SpellMissInfo ReflectResult
Definition Spell.h:582
uint64 TimeDelay
Definition Spell.h:577
ObjectGuid TargetGUID
Definition Spell.h:576
Unit * _spellHitTarget
Definition Spell.h:597
int32 AuraDuration
Definition Spell.h:590
DiminishingGroup DRGroup
Definition Spell.h:589
WorldObjectSpellAreaTargetCheck(float range, Position const *position, WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8451
bool operator()(WorldObject *target) const
Definition Spell.cpp:8455
WorldObjectSpellConeTargetCheck(float coneAngle, float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8474
bool operator()(WorldObject *target) const
Definition Spell.cpp:8478
bool operator()(WorldObject *target)
Definition Spell.cpp:8440
WorldObjectSpellNearbyTargetCheck(float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8436
WorldObjectSpellTargetCheck(WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8350
SpellTargetCheckTypes _targetSelectionType
Definition Spell.h:725
std::unique_ptr< ConditionSourceInfo > _condSrcInfo
Definition Spell.h:726
bool operator()(WorldObject *target) const
Definition Spell.cpp:8362
ConditionContainer const * _condList
Definition Spell.h:727
WorldObjectSpellTrajTargetCheck(float range, Position const *position, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8498
bool operator()(WorldObject *target) const
Definition Spell.cpp:8501
Optional< std::vector< SpellMissStatus > > MissStatus
Optional< RuneData > RemainingRunes
Optional< std::vector< ObjectGuid > > HitTargets
Optional< CreatureImmunities > Immunities
Optional< MissileTrajectoryResult > MissileTrajectory
Optional< std::vector< TargetLocation > > TargetPoints
Optional< TargetLocation > SrcLocation
Optional< TargetLocation > DstLocation