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_pitch(0), m_speed(0), m_strTarget()
119{
120 m_objectTarget = nullptr;
121 m_itemTarget = nullptr;
122
124
125 m_targetMask = 0;
126}
127
129 m_targetMask(spellCastRequest.Target.Flags), m_objectTarget(nullptr), m_itemTarget(nullptr),
130 m_objectTargetGUID(spellCastRequest.Target.Unit.value_or(ObjectGuid::Empty)), m_itemTargetGUID(spellCastRequest.Target.Item.value_or(ObjectGuid::Empty)),
131 m_itemTargetEntry(0), m_pitch(0.0f), m_speed(0.0f)
132{
133 if (spellCastRequest.Target.SrcLocation)
134 {
135 m_src._transportGUID = spellCastRequest.Target.SrcLocation->Transport;
136 Position* pos;
138 pos = &m_src._transportOffset;
139 else
140 pos = &m_src._position;
141
142 pos->Relocate(spellCastRequest.Target.SrcLocation->Location.Pos);
143 }
144
145 if (spellCastRequest.Target.DstLocation)
146 {
147 m_dst._transportGUID = spellCastRequest.Target.DstLocation->Transport;
148 Position* pos;
150 pos = &m_dst._transportOffset;
151 else
152 pos = &m_dst._position;
153
154 pos->Relocate(spellCastRequest.Target.DstLocation->Location.Pos);
155 }
156
157 if (spellCastRequest.MissileTrajectory)
158 {
159 SetPitch(spellCastRequest.MissileTrajectory->Pitch);
160 SetSpeed(spellCastRequest.MissileTrajectory->Speed);
161 }
162
163 if (spellCastRequest.Target.Name)
164 m_strTarget.assign(spellCastRequest.Target.Name->begin(), std::ranges::find(*spellCastRequest.Target.Name, '\0'));
165
166 Update(caster);
167}
168
170
172{
173 data >> m_targetMask;
174
176 return;
177
180
183
185 {
189 else
191 }
192 else
193 {
197 else
198 m_src._position.Relocate(caster);
199 }
200
202 {
206 else
208 }
209 else
210 {
214 else
215 m_dst._position.Relocate(caster);
216 }
217
219 data >> m_strTarget;
220
221 Update(caster);
222}
223
225{
226 data.Flags = m_targetMask;
227
230
232 {
233 data.Item.emplace();
234 if (m_itemTarget)
235 data.Item = m_itemTarget->GetGUID();
236 }
237
239 {
240 data.SrcLocation.emplace();
241 data.SrcLocation->Transport = m_src._transportGUID;
243 data.SrcLocation->Location = m_src._transportOffset;
244 else
245 data.SrcLocation->Location = m_src._position;
246 }
247
249 {
250 data.DstLocation.emplace();
251 data.DstLocation->Transport = m_dst._transportGUID;
253 data.DstLocation->Location = m_dst._transportOffset;
254 else
255 data.DstLocation->Location = m_dst._position;
256 }
257
259 {
260 std::array<char, 128>& name = data.Name.emplace();
261 std::ranges::copy_n(m_strTarget.begin(), std::min(std::ssize(m_strTarget), std::ssize(name)), name.begin());
262 }
263}
264
272
274{
275 if (m_objectTarget)
276 return m_objectTarget->ToUnit();
277
278 return nullptr;
279}
280
282{
283 if (!target)
284 return;
285
286 m_objectTarget = target;
287 m_objectTargetGUID = target->GetGUID();
289}
290
298
300{
301 if (m_objectTarget)
303
304 return nullptr;
305}
306
308{
309 if (!target)
310 return;
311
312 m_objectTarget = target;
313 m_objectTargetGUID = target->GetGUID();
315}
316
324
326{
327 if (m_objectTarget)
328 return m_objectTarget->ToCorpse();
329
330 return nullptr;
331}
332
337
342
349
351{
352 if (!item)
353 return;
354
355 m_itemTarget = item;
356 m_itemTargetGUID = item->GetGUID();
357 m_itemTargetEntry = item->GetEntry();
359}
360
369
378
380{
381 return &m_src;
382}
383
385{
386 return &m_src._position;
387}
388
389void SpellCastTargets::SetSrc(float x, float y, float z)
390{
391 m_src = SpellDestination(x, y, z);
393}
394
400
406
412
417
419{
420 return &m_dst;
421}
422
424{
425 return &m_dst._position;
426}
427
428void SpellCastTargets::SetDst(float x, float y, float z, float orientation, uint32 mapId)
429{
430 m_dst = SpellDestination(x, y, z, orientation, mapId);
432}
433
439
445
447{
448 m_dst = spellDest;
450}
451
453{
454 m_dst = spellTargets.m_dst;
456}
457
463
465{
467 m_dst = spellDest;
468}
469
474
476{
478}
479
481{
483}
484
486{
488
489 m_itemTarget = nullptr;
490 if (caster->GetTypeId() == TYPEID_PLAYER)
491 {
492 Player* player = caster->ToPlayer();
496 if (m_itemTargetGUID.GetRawValue() == TRADE_SLOT_NONTRADED) // here it is not guid but slot. Also prevents hacking slots
497 if (TradeData* pTrade = player->GetTradeData())
498 m_itemTarget = pTrade->GetTraderData()->GetItem(TRADE_SLOT_NONTRADED);
499
500 if (m_itemTarget)
502 }
503
504 // update positions by transport move
506 {
508 {
509 m_src._position.Relocate(transport);
511 }
512 }
513
515 {
517 {
518 m_dst._position.Relocate(transport);
520 }
521 }
522}
523
525{
526 for (SpellEffectInfo const& spellEffectInfo : proto->GetEffects())
527 EffectBasePoints[spellEffectInfo.EffectIndex] = spellEffectInfo.BasePoints;
529 RadiusMod = 1.0f;
530 AuraStackAmount = 1;
531 CriticalChance = 0.0f;
532}
533
535{
536public:
537 explicit SpellEvent(Spell* spell);
538 ~SpellEvent();
539
540 bool Execute(uint64 e_time, uint32 p_time) override;
541 void Abort(uint64 e_time) override;
542 bool IsDeletable() const override;
543 Spell const* GetSpell() const { return m_Spell.get(); }
545
546 std::string GetDebugInfo() const { return m_Spell->GetDebugInfo(); }
547
548protected:
550};
551
552Spell::Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID) :
553m_spellInfo(sSpellMgr->GetSpellForDifficultyFromSpell(info, caster)),
554m_caster((info->HasAttribute(SPELL_ATTR6_CAST_BY_CHARMER) && caster->GetCharmerOrOwner()) ? caster->GetCharmerOrOwner() : caster)
555, m_spellValue(new SpellValue(m_spellInfo)), _spellEvent(nullptr)
556{
558 m_fromClient = false;
559 m_selfContainer = nullptr;
561 m_executedCurrently = false;
563 m_comboTarget = nullptr;
565 m_delayStart = 0;
567
569 m_auraScaleMask = 0;
570 memset(m_damageMultipliers, 0, sizeof(m_damageMultipliers));
571
572 // Get data for type of attack
573 m_attackType = info->GetAttackType();
574
575 m_spellSchoolMask = info->GetSchoolMask(); // Can be override for some spell (wand shoot for example)
576
577 if (Player const* playerCaster = m_caster->ToPlayer())
578 {
579 // wand case
581 if ((playerCaster->GetClassMask() & CLASSMASK_WAND_USERS) != 0)
582 if (Item* pItem = playerCaster->GetWeaponForAttack(RANGED_ATTACK))
583 m_spellSchoolMask = SpellSchoolMask(1 << pItem->GetTemplate()->GetDamageType(0));
584 }
585
586 if (!originalCasterGUID.IsEmpty())
587 m_originalCasterGUID = originalCasterGUID;
588 else
590
592
594 _triggeredCastFlags = triggerFlags;
597
598 m_CastItem = nullptr;
600 m_castItemEntry = 0;
601
602 unitTarget = nullptr;
603 itemTarget = nullptr;
604 gameObjTarget = nullptr;
605 m_corpseTarget = nullptr;
606 destTarget = nullptr;
607 damage = 0;
610 effectInfo = nullptr;
611 m_damage = 0;
612 m_healing = 0;
613 m_procAttacker = 0;
614 m_procVictim = 0;
615 m_hitMask = 0;
616 focusObject = nullptr;
617 m_cast_count = 0;
618 m_misc.Data = 0;
619 m_triggeredByAuraSpell = nullptr;
620 _spellAura = nullptr;
621 _dynObjAura = nullptr;
622
623 //Auto Shot & Shoot (wand)
625
626 m_runesState = 0;
627 m_powerCost = 0; // setup to correct value in Spell::prepare, must not be used before.
628 m_casttime = 0; // setup to correct value in Spell::prepare, must not be used before.
629 m_timer = 0; // will set to castime in prepare
630 m_channeledDuration = 0; // will be setup in Spell::handle_immediate
631 m_immediateHandled = false;
632
634
635 // Determine if spell can be reflected back to the caster
636 // Patch 1.2 notes: Spell Reflection no longer reflects abilities
637 m_canReflect = caster->IsUnit()
640 && !m_spellInfo->IsPassive();
641
643 memset(m_effectExecuteData, 0, MAX_SPELL_EFFECTS * sizeof(ByteBuffer*));
644
645 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
647}
648
650{
651 // unload scripts
652 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
653 {
654 (*itr)->_Unload();
655 delete (*itr);
656 }
657
659 {
660 // Clean the reference to avoid later crash.
661 // If this error is repeating, we may have to add an ASSERT to better track down how we get into this case.
662 TC_LOG_ERROR("spells", "SPELL: deleting spell for spell ID {}. However, spell still referenced.", m_spellInfo->Id);
663 *m_selfContainer = nullptr;
664 }
665
668
669 delete m_spellValue;
670
671 // missing cleanup somewhere, mem leaks so let's crash
673}
674
676{
677 m_targets = targets;
678
679 // this function tries to correct spell explicit targets for spell
680 // client doesn't send explicit targets correctly sometimes - we need to fix such spells serverside
681 // this also makes sure that we correctly send explicit targets to client (removes redundant data)
682 uint32 neededTargets = m_spellInfo->GetExplicitTargetMask();
683
684 if (WorldObject* target = m_targets.GetObjectTarget())
685 {
686 // check if object target is valid with needed target flags
687 // for unit case allow corpse target mask because player with not released corpse is a unit target
688 if ((target->ToUnit() && !(neededTargets & (TARGET_FLAG_UNIT_MASK | TARGET_FLAG_CORPSE_MASK)))
689 || (target->ToGameObject() && !(neededTargets & TARGET_FLAG_GAMEOBJECT_MASK))
690 || (target->ToCorpse() && !(neededTargets & TARGET_FLAG_CORPSE_MASK)))
692 }
693 else
694 {
695 // try to select correct unit target if not provided by client or by serverside cast
696 if (neededTargets & (TARGET_FLAG_UNIT_MASK))
697 {
698 Unit* unit = nullptr;
699 // try to use player selection as a target
700 if (Player* playerCaster = m_caster->ToPlayer())
701 {
702 // selection has to be found and to be valid target for the spell
703 if (Unit* selectedUnit = ObjectAccessor::GetUnit(*m_caster, playerCaster->GetTarget()))
705 unit = selectedUnit;
706 }
707 // try to use attacked unit as a target
708 else if ((m_caster->GetTypeId() == TYPEID_UNIT) && neededTargets & (TARGET_FLAG_UNIT_ENEMY | TARGET_FLAG_UNIT))
709 unit = m_caster->ToCreature()->GetVictim();
710
711 // didn't find anything - let's use self as target
713 unit = m_caster->ToUnit();
714
716 }
717 }
718
719 // check if spell needs dst target
720 if (neededTargets & TARGET_FLAG_DEST_LOCATION)
721 {
722 // and target isn't set
723 if (!m_targets.HasDst())
724 {
725 // try to use unit target if provided
726 if (WorldObject* target = targets.GetObjectTarget())
727 m_targets.SetDst(*target);
728 // or use self if not available
729 else
731 }
732 }
733 else
735
736 if (neededTargets & TARGET_FLAG_SOURCE_LOCATION)
737 {
738 if (!targets.HasSrc())
740 }
741 else
743}
744
746{
747 // here go all explicit target changes made to explicit targets after spell prepare phase is finished
748 if (Unit* target = m_targets.GetUnitTarget())
749 {
750 // check for explicit target redirection, for Grounding Totem for example
753 {
754 Unit* redirect = nullptr;
755 switch (m_spellInfo->DmgClass)
756 {
759 break;
762 // should gameobjects cast damagetype melee/ranged spells this needs to be changed
764 break;
765 default:
766 break;
767 }
768 if (redirect && (redirect != target))
769 m_targets.SetUnitTarget(redirect);
770 }
771 }
772}
773
775{
776 // select targets for cast phase
778
779 uint32 processedEffectsMaskForSpell = 0;
780 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
781 {
782 // not call for empty effect.
783 // Also some spells use not used effect targets for store targets for dummy effect in triggered spells
784 if (!spellEffectInfo.IsEffect())
785 continue;
786
787 // set expected type of implicit targets to be sent to client
788 uint32 implicitTargetMask = GetTargetFlagMask(spellEffectInfo.TargetA.GetObjectType()) | GetTargetFlagMask(spellEffectInfo.TargetB.GetObjectType());
789 if (implicitTargetMask & TARGET_FLAG_UNIT)
791 if (implicitTargetMask & (TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_GAMEOBJECT_ITEM))
793
794 uint32 implicitTargetEffectMaskToSelect = [&]
795 {
796 uint32 effectMask = 1u << spellEffectInfo.EffectIndex;
797 // set the same target list for all effects
798 // some spells appear to need this, however this requires more research
799 std::array<SpellEffectInfo, MAX_SPELL_EFFECTS> const& effects = GetSpellInfo()->GetEffects();
800 // choose which targets we can select at once
801 for (uint32 j = spellEffectInfo.EffectIndex + 1; j < effects.size(); ++j)
802 {
803 if (effects[j].IsEffect() &&
804 spellEffectInfo.TargetA.GetTarget() == effects[j].TargetA.GetTarget() &&
805 spellEffectInfo.TargetB.GetTarget() == effects[j].TargetB.GetTarget() &&
806 spellEffectInfo.ImplicitTargetConditions == effects[j].ImplicitTargetConditions &&
807 CheckScriptEffectImplicitTargets(spellEffectInfo.EffectIndex, j))
808 {
809 auto shouldCheckRadius = [](SpellImplicitTargetInfo const& targetInfo)
810 {
811 switch (targetInfo.GetSelectionCategory())
812 {
816 return true;
817 default:
818 break;
819 }
820 return false;
821 };
822
823 if (shouldCheckRadius(spellEffectInfo.TargetA) || shouldCheckRadius(spellEffectInfo.TargetB))
824 if (spellEffectInfo.CalcRadius(m_caster) != effects[j].CalcRadius(m_caster))
825 continue;
826
827 effectMask |= 1 << j;
828 }
829 }
830
831 return effectMask;
832 }();
833
834 implicitTargetEffectMaskToSelect &= ~processedEffectsMaskForSpell;
835 if (implicitTargetEffectMaskToSelect)
836 {
837 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetA, implicitTargetEffectMaskToSelect);
838 SelectEffectImplicitTargets(spellEffectInfo, spellEffectInfo.TargetB, implicitTargetEffectMaskToSelect);
839 processedEffectsMaskForSpell |= implicitTargetEffectMaskToSelect;
840 }
841
842 // Select targets of effect based on effect type
843 // those are used when no valid target could be added for spell effect based on spell target type
844 // some spell effects use explicit target as a default target added to target map (like SPELL_EFFECT_LEARN_SPELL)
845 // some spell effects add target to target map only when target type specified (like SPELL_EFFECT_WEAPON)
846 // some spell effects don't add anything to target map (confirmed with sniffs) (like SPELL_EFFECT_DESTROY_ALL_TOTEMS)
847 SelectEffectTypeImplicitTargets(spellEffectInfo);
848
849 if (m_targets.HasDst())
850 AddDestTarget(*m_targets.GetDst(), spellEffectInfo.EffectIndex);
851
852 if (implicitTargetEffectMaskToSelect
853 && (spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
854 || spellEffectInfo.TargetA.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST
855 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT
856 || spellEffectInfo.TargetB.GetObjectType() == TARGET_OBJECT_TYPE_UNIT_AND_DEST))
857 {
859 {
860 bool noTargetFound = std::ranges::none_of(m_UniqueTargetInfo, [implicitTargetEffectMaskToSelect](TargetInfo const& target)
861 {
862 return target.EffectMask & implicitTargetEffectMaskToSelect;
863 });
864
865 if (noTargetFound)
866 {
868 finish(false);
869 return;
870 }
871 }
873 {
874 bool anyNonImmuneTargetFound = std::ranges::any_of(m_UniqueTargetInfo, [implicitTargetEffectMaskToSelect](TargetInfo const& target)
875 {
876 return target.EffectMask & implicitTargetEffectMaskToSelect && target.MissCondition != SPELL_MISS_IMMUNE && target.MissCondition != SPELL_MISS_IMMUNE2;
877 });
878
879 if (!anyNonImmuneTargetFound)
880 {
882 finish(false);
883 return;
884 }
885 }
886 }
887
889 {
890 // maybe do this for all spells?
891 if (!focusObject && m_UniqueTargetInfo.empty() && m_UniqueGOTargetInfo.empty() && m_UniqueItemInfo.empty() && !m_targets.HasDst())
892 {
894 finish(false);
895 return;
896 }
897
898 uint8 mask = (1 << spellEffectInfo.EffectIndex);
899 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
900 {
901 if (ihit->EffectMask & mask)
902 {
904 break;
905 }
906 }
907 }
908 else if (m_auraScaleMask)
909 {
910 bool checkLvl = !m_UniqueTargetInfo.empty();
911 m_UniqueTargetInfo.erase(std::remove_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [&](TargetInfo const& targetInfo) -> bool
912 {
913 // remove targets which did not pass min level check
914 if (m_auraScaleMask && targetInfo.EffectMask == m_auraScaleMask)
915 {
916 // Do not check for selfcast
917 if (!targetInfo.ScaleAura && targetInfo.TargetGUID != m_caster->GetGUID())
918 return true;
919 }
920
921 return false;
922 }), std::end(m_UniqueTargetInfo));
923
924 if (checkLvl && m_UniqueTargetInfo.empty())
925 {
927 finish(false);
928 }
929 }
930 }
931
932 if (uint64 dstDelay = CalculateDelayMomentForDst())
933 m_delayMoment = dstDelay;
934}
935
937{
938 if (m_targets.HasDst())
939 {
940 if (m_targets.HasTraj())
941 {
942 float speed = m_targets.GetSpeedXY();
943 if (speed > 0.0f)
944 return uint64(std::floor(m_targets.GetDist2d() / speed * 1000.0f));
945 }
946 else if (m_spellInfo->Speed > 0.0f)
947 {
948 // We should not subtract caster size from dist calculation (fixes execution time desync with animation on client, eg. Malleable Goo cast by PP)
949 float dist = m_caster->GetExactDist(*m_targets.GetDstPos());
950 return uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
951 }
952 }
953
954 return 0;
955}
956
962
963void Spell::SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effectMask)
964{
965 if (!targetType.GetTarget())
966 return;
967
968 switch (targetType.GetSelectionCategory())
969 {
971 SelectImplicitChannelTargets(spellEffectInfo, targetType, effectMask);
972 break;
974 SelectImplicitNearbyTargets(spellEffectInfo, targetType, effectMask);
975 break;
977 SelectImplicitConeTargets(spellEffectInfo, targetType, effectMask);
978 break;
980 SelectImplicitAreaTargets(spellEffectInfo, targetType, effectMask);
981 break;
983 // just in case there is no dest, explanation in SelectImplicitDestDestTargets
984 CheckDst();
985
986 SelectImplicitTrajTargets(spellEffectInfo, targetType);
987 break;
989 switch (targetType.GetObjectType())
990 {
992 switch (targetType.GetReferenceType())
993 {
996 break;
997 default:
998 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_SRC");
999 break;
1000 }
1001 break;
1003 switch (targetType.GetReferenceType())
1004 {
1006 SelectImplicitCasterDestTargets(spellEffectInfo, targetType);
1007 break;
1009 SelectImplicitTargetDestTargets(spellEffectInfo, targetType);
1010 break;
1012 SelectImplicitDestDestTargets(spellEffectInfo, targetType);
1013 break;
1014 default:
1015 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT_DEST");
1016 break;
1017 }
1018 break;
1019 default:
1020 switch (targetType.GetReferenceType())
1021 {
1023 SelectImplicitCasterObjectTargets(spellEffectInfo, targetType, effectMask);
1024 break;
1026 SelectImplicitTargetObjectTargets(spellEffectInfo, targetType, effectMask);
1027 break;
1028 default:
1029 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target reference type for TARGET_TYPE_OBJECT");
1030 break;
1031 }
1032 break;
1033 }
1034 break;
1036 TC_LOG_DEBUG("spells", "SPELL: target type {}, found in spellID {}, effect {} is not implemented yet!", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex), targetType.GetTarget());
1037 break;
1038 default:
1039 ABORT_MSG("Spell::SelectEffectImplicitTargets: received not implemented select target category");
1040 break;
1041 }
1042}
1043
1044void Spell::SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1045{
1047 {
1048 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target reference type");
1049 return;
1050 }
1051
1053 if (!channeledSpell)
1054 {
1055 TC_LOG_DEBUG("spells", "Spell::SelectImplicitChannelTargets: cannot find channel spell for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1056 return;
1057 }
1058 switch (targetType.GetTarget())
1059 {
1061 {
1063 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1064 // unit target may be no longer avalible - teleported out of map for example
1065 if (target && target->ToUnit())
1066 AddUnitTarget(target->ToUnit(), effMask);
1067 else
1068 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1069 break;
1070 }
1072 if (channeledSpell->m_targets.HasDst())
1073 m_targets.SetDst(channeledSpell->m_targets);
1075 {
1076 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1077 if (target)
1078 {
1079 SpellDestination dest(*target);
1080 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1081 m_targets.SetDst(dest);
1082 }
1083 }
1084 else
1085 TC_LOG_DEBUG("spells", "SPELL: cannot find channel spell destination for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1086 break;
1088 {
1089 SpellDestination dest(*channeledSpell->GetCaster());
1090 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1091 m_targets.SetDst(dest);
1092 break;
1093 }
1094 default:
1095 ABORT_MSG("Spell::SelectImplicitChannelTargets: received not implemented target type");
1096 break;
1097 }
1098}
1099
1100void Spell::SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1101{
1103 {
1104 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target reference type");
1105 return;
1106 }
1107
1108 float range = 0.0f;
1109 switch (targetType.GetCheckType())
1110 {
1111 case TARGET_CHECK_ENEMY:
1112 range = m_spellInfo->GetMaxRange(false, m_caster, this);
1113 break;
1114 case TARGET_CHECK_ALLY:
1115 case TARGET_CHECK_PARTY:
1116 case TARGET_CHECK_RAID:
1118 range = m_spellInfo->GetMaxRange(true, m_caster, this);
1119 break;
1120 case TARGET_CHECK_ENTRY:
1122 range = m_spellInfo->GetMaxRange(IsPositive(), m_caster, this);
1123 break;
1124 default:
1125 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented selection check type");
1126 break;
1127 }
1128
1129 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
1130
1131 // handle emergency case - try to use other provided targets if no conditions provided
1132 if (targetType.GetCheckType() == TARGET_CHECK_ENTRY && (!condList || condList->empty()))
1133 {
1134 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));
1135 switch (targetType.GetObjectType())
1136 {
1139 {
1140 if (focusObject)
1141 AddGOTarget(focusObject, effMask);
1142 else
1143 {
1145 finish(false);
1146 }
1147 return;
1148 }
1149 break;
1152 {
1153 if (focusObject)
1154 {
1156 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1157 m_targets.SetDst(dest);
1158 }
1159 else
1160 {
1162 finish(false);
1163 }
1164 return;
1165 }
1166 break;
1167 default:
1168 break;
1169 }
1170 }
1171
1172 WorldObject* target = SearchNearbyTarget(range, targetType.GetObjectType(), targetType.GetCheckType(), condList);
1173 if (!target)
1174 {
1175 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: cannot find nearby target for spell ID {}, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1177 finish(false);
1178 return;
1179 }
1180
1181 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1182 if (!target)
1183 {
1184 TC_LOG_DEBUG("spells", "Spell::SelectImplicitNearbyTargets: OnObjectTargetSelect script hook for spell Id {} set NULL target, effect {}", m_spellInfo->Id, uint32(spellEffectInfo.EffectIndex));
1186 finish(false);
1187 return;
1188 }
1189
1190 switch (targetType.GetObjectType())
1191 {
1193 if (Unit* unit = target->ToUnit())
1194 AddUnitTarget(unit, effMask, true, false);
1195 else
1196 {
1197 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);
1199 finish(false);
1200 return;
1201 }
1202 break;
1204 if (GameObject* gobjTarget = target->ToGameObject())
1205 AddGOTarget(gobjTarget, effMask);
1206 else
1207 {
1208 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);
1210 finish(false);
1211 return;
1212 }
1213 break;
1215 if (Corpse* corpseTarget = target->ToCorpse())
1216 AddCorpseTarget(corpseTarget, effMask);
1217 else
1218 {
1219 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);
1221 finish(false);
1222 return;
1223 }
1224 break;
1226 {
1227 SpellDestination dest(*target);
1228 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1229 m_targets.SetDst(dest);
1230 break;
1231 }
1232 default:
1233 ABORT_MSG("Spell::SelectImplicitNearbyTargets: received not implemented target object type");
1234 break;
1235 }
1236
1237 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1238}
1239
1240void Spell::SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1241{
1243 {
1244 ABORT_MSG("Spell::SelectImplicitConeTargets: received not implemented target reference type");
1245 return;
1246 }
1247 std::list<WorldObject*> targets;
1248 SpellTargetObjectTypes objectType = targetType.GetObjectType();
1249 SpellTargetCheckTypes selectionType = targetType.GetCheckType();
1250 ConditionContainer* condList = spellEffectInfo.ImplicitTargetConditions;
1251 float coneAngle = float(M_PI) / 2.f;
1252
1253 float radius = spellEffectInfo.CalcRadius(m_caster);
1254 // Workaround for some spells that don't have RadiusEntry set in dbc (but SpellRange instead)
1255 if (G3D::fuzzyEq(radius, 0.f))
1256 radius = m_spellInfo->GetMaxRange(m_spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex), m_caster, this);
1257
1258 radius *= m_spellValue->RadiusMod;
1259
1260 if (uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList))
1261 {
1262 float extraSearchRadius = radius > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1263 Trinity::WorldObjectSpellConeTargetCheck check(coneAngle, radius, m_caster, m_spellInfo, selectionType, condList);
1265 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellConeTargetCheck> >(searcher, containerTypeMask, m_caster, m_caster, radius + extraSearchRadius);
1266
1267 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1268
1269 if (!targets.empty())
1270 {
1271 // Other special target selection goes here
1272 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1273 {
1274 if (Unit* unitCaster = m_caster->ToUnit())
1275 maxTargets += unitCaster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
1276 Trinity::Containers::RandomResize(targets, maxTargets);
1277 }
1278
1279 for (WorldObject* itr : targets)
1280 {
1281 if (Unit* unit = itr->ToUnit())
1282 AddUnitTarget(unit, effMask, false);
1283 else if (GameObject* gObjTarget = itr->ToGameObject())
1284 AddGOTarget(gObjTarget, effMask);
1285 else if (Corpse* corpse = itr->ToCorpse())
1286 AddCorpseTarget(corpse, effMask);
1287 }
1288 }
1289 }
1290}
1291
1292void Spell::SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1293{
1294 WorldObject* referer = nullptr;
1295 switch (targetType.GetReferenceType())
1296 {
1300 referer = m_caster;
1301 break;
1303 referer = m_targets.GetUnitTarget();
1304 break;
1306 {
1307 // find last added target for this effect
1308 for (auto ihit = m_UniqueTargetInfo.rbegin(); ihit != m_UniqueTargetInfo.rend(); ++ihit)
1309 {
1310 if (ihit->EffectMask & (1 << spellEffectInfo.EffectIndex))
1311 {
1312 referer = ObjectAccessor::GetUnit(*m_caster, ihit->TargetGUID);
1313 break;
1314 }
1315 }
1316 break;
1317 }
1318 default:
1319 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1320 return;
1321 }
1322 if (!referer)
1323 return;
1324
1325 Position const* center = nullptr;
1326 switch (targetType.GetReferenceType())
1327 {
1329 center = m_targets.GetSrcPos();
1330 break;
1332 center = m_targets.GetDstPos();
1333 break;
1337 center = referer;
1338 break;
1339 default:
1340 ABORT_MSG("Spell::SelectImplicitAreaTargets: received not implemented target reference type");
1341 return;
1342 }
1343 std::list<WorldObject*> targets;
1344 float radius = spellEffectInfo.CalcRadius(m_caster);
1345 // Workaround for some spells that don't have RadiusEntry set in dbc (but SpellRange instead)
1346 if (G3D::fuzzyEq(radius, 0.f))
1347 radius = m_spellInfo->GetMaxRange(m_spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex), m_caster, this);
1348
1349 radius *= m_spellValue->RadiusMod;
1350
1351 SearchAreaTargets(targets, radius, center, referer, targetType.GetObjectType(), targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
1352
1353 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1354
1355 if (!targets.empty())
1356 {
1357 // Other special target selection goes here
1358 if (uint32 maxTargets = m_spellValue->MaxAffectedTargets)
1359 {
1360 if (Unit* unitCaster = m_caster->ToUnit())
1361 maxTargets += unitCaster->GetTotalAuraModifierByAffectMask(SPELL_AURA_MOD_MAX_AFFECTED_TARGETS, m_spellInfo);
1362 Trinity::Containers::RandomResize(targets, maxTargets);
1363 }
1364
1365 for (WorldObject* itr : targets)
1366 {
1367 if (Unit* unit = itr->ToUnit())
1368 AddUnitTarget(unit, effMask, false, true, center);
1369 else if (GameObject* gObjTarget = itr->ToGameObject())
1370 AddGOTarget(gObjTarget, effMask);
1371 else if (Corpse* corpse = itr->ToCorpse())
1372 AddCorpseTarget(corpse, effMask);
1373 }
1374 }
1375}
1376
1378{
1380
1381 switch (targetType.GetTarget())
1382 {
1383 case TARGET_DEST_CASTER:
1384 break;
1385 case TARGET_DEST_HOME:
1386 if (Player* playerCaster = m_caster->ToPlayer())
1387 dest = SpellDestination(playerCaster->m_homebindX, playerCaster->m_homebindY, playerCaster->m_homebindZ, playerCaster->GetOrientation(), playerCaster->m_homebindMapId);
1388 break;
1389 case TARGET_DEST_DB:
1390 if (SpellTargetPosition const* st = sSpellMgr->GetSpellTargetPosition(m_spellInfo->Id, spellEffectInfo.EffectIndex))
1391 {
1394 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation, (int32)st->target_mapId);
1395 else if (st->target_mapId == m_caster->GetMapId())
1396 dest = SpellDestination(st->target_X, st->target_Y, st->target_Z, st->target_Orientation);
1397 }
1398 else
1399 {
1400 TC_LOG_DEBUG("spells", "SPELL: unknown target coordinates for spell ID {}", m_spellInfo->Id);
1401 if (WorldObject* target = m_targets.GetObjectTarget())
1402 dest = SpellDestination(*target);
1403 }
1404 break;
1406 {
1407 float minDist = m_spellInfo->GetMinRange(true);
1408 float maxDist = m_spellInfo->GetMaxRange(true);
1409 float dist = frand(minDist, maxDist);
1410 float x, y, z;
1411 float angle = float(rand_norm()) * static_cast<float>(M_PI * 35.0f / 180.0f) - static_cast<float>(M_PI * 17.5f / 180.0f);
1413
1414 float ground = m_caster->GetMapHeight(x, y, z);
1415 float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
1416 LiquidData liquidData;
1417 if (m_caster->GetMap()->GetLiquidStatus(m_caster->GetPhaseMask(), x, y, z, {}, &liquidData, m_caster->GetCollisionHeight()))
1418 liquidLevel = liquidData.level;
1419
1420 if (liquidLevel <= ground) // When there is no liquid Map::GetWaterOrGroundLevel returns ground level
1421 {
1424 finish(false);
1425 return;
1426 }
1427
1428 if (ground + 0.75 > liquidLevel)
1429 {
1432 finish(false);
1433 return;
1434 }
1435
1436 dest = SpellDestination(x, y, liquidLevel, m_caster->GetOrientation());
1437 break;
1438 }
1440 {
1441 Unit* unitCaster = m_caster->ToUnit();
1442 if (!unitCaster)
1443 break;
1444
1445 float dist = spellEffectInfo.CalcRadius(unitCaster);
1446 float angle = targetType.CalcDirectionAngle();
1447
1448 Position pos = dest._position;
1449
1450 unitCaster->MovePositionToFirstCollision(pos, dist, angle);
1451 dest.Relocate(pos);
1452 break;
1453 }
1454 default:
1455 {
1456 float dist = spellEffectInfo.CalcRadius(m_caster);
1457 float angle = targetType.CalcDirectionAngle();
1458 float objSize = m_caster->GetCombatReach();
1459
1460 switch (targetType.GetTarget())
1461 {
1463 dist = PET_FOLLOW_DIST;
1464 break;
1466 if (dist > objSize)
1467 dist = objSize + (dist - objSize) * float(rand_norm());
1468 break;
1473 {
1474 static float const DefaultTotemDistance = 3.0f;
1475 if (!spellEffectInfo.HasRadius())
1476 dist = DefaultTotemDistance;
1477 break;
1478 }
1479 default:
1480 break;
1481 }
1482
1483 if (dist < objSize)
1484 dist = objSize;
1485
1486 Position pos = dest._position;
1487 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1488
1489 dest.Relocate(pos);
1490 break;
1491 }
1492 }
1493
1494 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1495 m_targets.SetDst(dest);
1496}
1497
1499{
1500 ASSERT(m_targets.GetObjectTarget() && "Spell::SelectImplicitTargetDestTargets - no explicit object target available!");
1502
1503 SpellDestination dest(*target);
1504
1505 switch (targetType.GetTarget())
1506 {
1509 break;
1510 default:
1511 {
1512 float angle = targetType.CalcDirectionAngle();
1513 float dist = spellEffectInfo.CalcRadius(nullptr);
1514 if (targetType.GetTarget() == TARGET_DEST_TARGET_RANDOM)
1515 dist *= float(rand_norm());
1516
1517 Position pos = dest._position;
1518 target->MovePositionToFirstCollision(pos, dist, angle);
1519
1520 dest.Relocate(pos);
1521 break;
1522 }
1523 }
1524
1525 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1526 m_targets.SetDst(dest);
1527}
1528
1530{
1531 // set destination to caster if no dest provided
1532 // can only happen if previous destination target could not be set for some reason
1533 // (not found nearby target, or channel target for example
1534 // maybe we should abort the spell in such case?
1535 CheckDst();
1536
1538
1539 switch (targetType.GetTarget())
1540 {
1544 case TARGET_DEST_DEST:
1545 return;
1546 default:
1547 {
1548 float angle = targetType.CalcDirectionAngle();
1549 float dist = spellEffectInfo.CalcRadius(m_caster);
1550 if (targetType.GetTarget() == TARGET_DEST_DEST_RANDOM)
1551 dist *= float(rand_norm());
1552
1553 Position pos = dest._position;
1554 m_caster->MovePositionToFirstCollision(pos, dist, angle);
1555
1556 dest.Relocate(pos);
1557 break;
1558 }
1559 }
1560
1561 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1562 m_targets.ModDst(dest);
1563}
1564
1565void Spell::SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1566{
1567 WorldObject* target = nullptr;
1568 bool checkIfValid = true;
1569
1570 switch (targetType.GetTarget())
1571 {
1572 case TARGET_UNIT_CASTER:
1573 target = m_caster;
1574 checkIfValid = false;
1575 break;
1576 case TARGET_UNIT_MASTER:
1577 target = m_caster->GetCharmerOrOwner();
1578 break;
1579 case TARGET_UNIT_PET:
1580 if (Unit* unitCaster = m_caster->ToUnit())
1581 target = unitCaster->GetGuardianPet();
1582 break;
1584 if (Unit* unitCaster = m_caster->ToUnit())
1585 if (unitCaster->IsSummon())
1586 target = unitCaster->ToTempSummon()->GetSummonerUnit();
1587 break;
1589 if (Unit* unitCaster = m_caster->ToUnit())
1590 target = unitCaster->GetVehicleBase();
1591 break;
1600 if (Creature* vehicleBase = m_caster->ToCreature())
1601 if (vehicleBase->IsVehicle())
1602 target = vehicleBase->GetVehicleKit()->GetPassenger(targetType.GetTarget() - TARGET_UNIT_PASSENGER_0);
1603 break;
1604 default:
1605 break;
1606 }
1607
1608 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1609
1610 if (target)
1611 {
1612 if (Unit* unit = target->ToUnit())
1613 AddUnitTarget(unit, effMask, checkIfValid);
1614 else if (GameObject* go = target->ToGameObject())
1615 AddGOTarget(go, effMask);
1616 }
1617}
1618
1619void Spell::SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, uint32 effMask)
1620{
1621 ASSERT((m_targets.GetObjectTarget() || m_targets.GetItemTarget()) && "Spell::SelectImplicitTargetObjectTargets - no explicit object or item target available!");
1622
1624
1625 CallScriptObjectTargetSelectHandlers(target, spellEffectInfo.EffectIndex, targetType);
1626
1627 if (target)
1628 {
1629 if (Unit* unit = target->ToUnit())
1630 AddUnitTarget(unit, effMask, true, false);
1631 else if (GameObject* gobj = target->ToGameObject())
1632 AddGOTarget(gobj, effMask);
1633 else if (Corpse* corpse = target->ToCorpse())
1634 AddCorpseTarget(corpse, effMask);
1635
1636 SelectImplicitChainTargets(spellEffectInfo, targetType, target, effMask);
1637 }
1638 // Script hook can remove object target and we would wrongly land here
1639 else if (Item* item = m_targets.GetItemTarget())
1640 AddItemTarget(item, effMask);
1641}
1642
1643void Spell::SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask)
1644{
1645 uint32 maxTargets = spellEffectInfo.ChainTargets;
1646 if (Player* modOwner = m_caster->GetSpellModOwner())
1647 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_JUMP_TARGETS, maxTargets, this);
1648
1649 if (maxTargets > 1)
1650 {
1651 // mark damage multipliers as used
1652 for (size_t k = spellEffectInfo.EffectIndex; k < m_spellInfo->GetEffects().size(); ++k)
1653 if (effMask & (1 << k))
1654 m_damageMultipliers[k] = 1.0f;
1655 m_applyMultiplierMask |= effMask;
1656
1657 std::list<WorldObject*> targets;
1658 SearchChainTargets(targets, maxTargets - 1, target, targetType.GetObjectType(), targetType.GetCheckType()
1659 , spellEffectInfo.ImplicitTargetConditions, targetType.GetTarget() == TARGET_UNIT_TARGET_CHAINHEAL_ALLY);
1660
1661 // Chain primary target is added earlier
1662 CallScriptObjectAreaTargetSelectHandlers(targets, spellEffectInfo.EffectIndex, targetType);
1663
1664 for (std::list<WorldObject*>::iterator itr = targets.begin(); itr != targets.end(); ++itr)
1665 if (Unit* unit = (*itr)->ToUnit())
1666 AddUnitTarget(unit, effMask, false);
1667 }
1668}
1669
1670float tangent(float x)
1671{
1672 x = std::tan(x);
1673 //if (x < std::numeric_limits<float>::max() && x > -std::numeric_limits<float>::max()) return x;
1674 //if (x >= std::numeric_limits<float>::max()) return std::numeric_limits<float>::max();
1675 //if (x <= -std::numeric_limits<float>::max()) return -std::numeric_limits<float>::max();
1676 if (x < 100000.0f && x > -100000.0f) return x;
1677 if (x >= 100000.0f) return 100000.0f;
1678 if (x <= 100000.0f) return -100000.0f;
1679 return 0.0f;
1680}
1681
1682void Spell::SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType)
1683{
1684 if (!m_targets.HasTraj())
1685 return;
1686
1687 float dist2d = m_targets.GetDist2d();
1688 if (!dist2d)
1689 return;
1690
1691 Position srcPos = *m_targets.GetSrcPos();
1693 float srcToDestDelta = m_targets.GetDstPos()->m_positionZ - srcPos.m_positionZ;
1694
1695 std::list<WorldObject*> targets;
1696 Trinity::WorldObjectSpellTrajTargetCheck check(dist2d, &srcPos, m_caster, m_spellInfo, targetType.GetCheckType(), spellEffectInfo.ImplicitTargetConditions);
1698 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellTrajTargetCheck> > (searcher, GRID_MAP_TYPE_MASK_ALL, m_caster, &srcPos, dist2d);
1699 if (targets.empty())
1700 return;
1701
1703
1704 float b = tangent(m_targets.GetPitch());
1705 float a = (srcToDestDelta - dist2d * b) / (dist2d * dist2d);
1706 if (a > -0.0001f)
1707 a = 0.f;
1708
1709 // We should check if triggered spell has greater range (which is true in many cases, and initial spell has too short max range)
1710 // limit max range to 300 yards, sometimes triggered spells can have 50000yds
1711 float bestDist = m_spellInfo->GetMaxRange(false);
1712 if (SpellInfo const* triggerSpellInfo = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell))
1713 bestDist = std::min(std::max(bestDist, triggerSpellInfo->GetMaxRange(false)), std::min(dist2d, 300.0f));
1714
1715 // GameObjects don't cast traj
1716 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
1717 for (auto itr = targets.begin(); itr != targets.end(); ++itr)
1718 {
1719 if (m_spellInfo->CheckTarget(unitCaster, *itr, true) != SPELL_CAST_OK)
1720 continue;
1721
1722 if (Unit* unit = (*itr)->ToUnit())
1723 {
1724 if (unitCaster == *itr || unitCaster->IsOnVehicle(unit) || unit->GetVehicle())
1725 continue;
1726
1727 if (Creature* creatureTarget = unit->ToCreature())
1728 {
1729 if (!(creatureTarget->GetCreatureTemplate()->type_flags & CREATURE_TYPE_FLAG_COLLIDE_WITH_MISSILES))
1730 continue;
1731 }
1732 }
1733
1734 float const size = std::max((*itr)->GetCombatReach(), 1.0f);
1735 float const objDist2d = srcPos.GetExactDist2d(*itr);
1736 float const dz = (*itr)->GetPositionZ() - srcPos.m_positionZ;
1737
1738 float const horizontalDistToTraj = std::fabs(objDist2d * std::sin(srcPos.GetRelativeAngle(*itr)));
1739 float const sizeFactor = std::cos((horizontalDistToTraj / size) * (M_PI / 2.0f));
1740 float const distToHitPoint = std::max(objDist2d * std::cos(srcPos.GetRelativeAngle(*itr)) - size * sizeFactor, 0.0f);
1741 float const height = distToHitPoint * (a * distToHitPoint + b);
1742
1743 if (fabs(dz - height) > size + b / 2.0f + TRAJECTORY_MISSILE_SIZE)
1744 continue;
1745
1746 if (distToHitPoint < bestDist)
1747 {
1748 bestDist = distToHitPoint;
1749 break;
1750 }
1751 }
1752
1753 if (dist2d > bestDist)
1754 {
1755 float x = m_targets.GetSrcPos()->m_positionX + std::cos(unitCaster->GetOrientation()) * bestDist;
1756 float y = m_targets.GetSrcPos()->m_positionY + std::sin(unitCaster->GetOrientation()) * bestDist;
1757 float z = m_targets.GetSrcPos()->m_positionZ + bestDist * (a * bestDist + b);
1758
1759 SpellDestination dest(x, y, z, unitCaster->GetOrientation());
1760 CallScriptDestinationTargetSelectHandlers(dest, spellEffectInfo.EffectIndex, targetType);
1761 m_targets.ModDst(dest);
1762 }
1763}
1764
1766{
1767 // special case for SPELL_EFFECT_SUMMON_RAF_FRIEND and SPELL_EFFECT_SUMMON_PLAYER, queue them on map for later execution
1768 switch (spellEffectInfo.Effect)
1769 {
1773 {
1776
1777 // scripts may modify the target - recheck
1778 if (target && target->GetTypeId() == TYPEID_PLAYER)
1779 {
1780 // target is not stored in target map for those spells
1781 // since we're completely skipping AddUnitTarget logic, we need to check immunity manually
1782 // eg. aura 21546 makes target immune to summons
1783 Player* player = target->ToPlayer();
1784 if (player->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, nullptr))
1785 return;
1786
1787 target->GetMap()->AddFarSpellCallback([spell = this, &spellEffectInfo, targetGuid = target->GetGUID()](Map* map)
1788 {
1789 Player* player = ObjectAccessor::GetPlayer(map, targetGuid);
1790 if (!player)
1791 return;
1792
1793 // check immunity again in case it changed during update
1794 if (player->IsImmunedToSpellEffect(spell->GetSpellInfo(), spellEffectInfo, nullptr))
1795 return;
1796
1797 spell->HandleEffects(player, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
1798 });
1799 }
1800 }
1801 return;
1802 default:
1803 break;
1804 }
1805
1806 // select spell implicit targets based on effect type
1807 if (!spellEffectInfo.GetImplicitTargetType())
1808 return;
1809
1810 uint32 targetMask = spellEffectInfo.GetMissingTargetMask();
1811
1812 if (!targetMask)
1813 return;
1814
1815 WorldObject* target = nullptr;
1816
1817 switch (spellEffectInfo.GetImplicitTargetType())
1818 {
1819 // add explicit object target or self to the target map
1821 // player which not released his spirit is Unit, but target flag for it is TARGET_FLAG_CORPSE_MASK
1823 {
1824 if (Unit* unit = m_targets.GetUnitTarget())
1825 target = unit;
1826 else if (targetMask & TARGET_FLAG_CORPSE_MASK)
1827 {
1828 if (Corpse* corpseTarget = m_targets.GetCorpseTarget())
1829 target = corpseTarget;
1830 }
1831 else //if (targetMask & TARGET_FLAG_UNIT_MASK)
1832 target = m_caster;
1833 }
1834 if (targetMask & TARGET_FLAG_ITEM_MASK)
1835 {
1836 if (Item* item = m_targets.GetItemTarget())
1837 AddItemTarget(item, 1 << spellEffectInfo.EffectIndex);
1838 return;
1839 }
1840 if (targetMask & TARGET_FLAG_GAMEOBJECT_MASK)
1841 target = m_targets.GetGOTarget();
1842 break;
1843 // add self to the target map
1845 if (targetMask & TARGET_FLAG_UNIT_MASK)
1846 target = m_caster;
1847 break;
1848 default:
1849 break;
1850 }
1851
1853
1854 if (target)
1855 {
1856 if (target->ToUnit())
1857 AddUnitTarget(target->ToUnit(), 1 << spellEffectInfo.EffectIndex, false);
1858 else if (target->ToGameObject())
1859 AddGOTarget(target->ToGameObject(), 1 << spellEffectInfo.EffectIndex);
1860 else if (target->ToCorpse())
1861 AddCorpseTarget(target->ToCorpse(), 1 << spellEffectInfo.EffectIndex);
1862 }
1863}
1864
1866{
1867 // this function selects which containers need to be searched for spell target
1869
1870 // filter searchers based on searched object type
1871 switch (objType)
1872 {
1876 break;
1881 break;
1885 break;
1886 default:
1887 break;
1888 }
1889
1893 retMask &= GRID_MAP_TYPE_MASK_PLAYER;
1894
1895 if (condList)
1896 retMask &= sConditionMgr->GetSearcherTypeMaskForConditionList(*condList);
1897 return retMask;
1898}
1899
1900template<class SEARCHER>
1901void Spell::SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius)
1902{
1903 if (!containerMask)
1904 return;
1905
1906 // search world and grid for possible targets
1907 bool searchInGrid = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_GAMEOBJECT)) != 0;
1908 bool searchInWorld = (containerMask & (GRID_MAP_TYPE_MASK_CREATURE | GRID_MAP_TYPE_MASK_PLAYER | GRID_MAP_TYPE_MASK_CORPSE)) != 0;
1909 if (searchInGrid || searchInWorld)
1910 {
1911 float x, y;
1912 x = pos->GetPositionX();
1913 y = pos->GetPositionY();
1914
1915 Map* map = referer->GetMap();
1916
1917 if (searchInWorld)
1918 Cell::VisitWorldObjects(x, y, map, searcher, radius);
1919
1920 if (searchInGrid)
1921 Cell::VisitGridObjects(x, y, map, searcher, radius);
1922 }
1923}
1924
1926{
1927 WorldObject* target = nullptr;
1928 uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
1929 if (!containerTypeMask)
1930 return nullptr;
1931
1932 Trinity::WorldObjectSpellNearbyTargetCheck check(range, m_caster, m_spellInfo, selectionType, condList);
1935 SearchTargets<Trinity::WorldObjectLastSearcher<Trinity::WorldObjectSpellNearbyTargetCheck>>(searcher, containerTypeMask, m_caster, m_caster, range);
1936 return target;
1937}
1938
1939void Spell::SearchAreaTargets(std::list<WorldObject*>& targets, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer* condList)
1940{
1941 uint32 containerTypeMask = GetSearcherTypeMask(objectType, condList);
1942 if (!containerTypeMask)
1943 return;
1944
1945 float extraSearchRadius = range > 0.0f ? EXTRA_CELL_SEARCH_RADIUS : 0.0f;
1946 Trinity::WorldObjectSpellAreaTargetCheck check(range, position, m_caster, referer, m_spellInfo, selectionType, condList);
1949 SearchTargets<Trinity::WorldObjectListSearcher<Trinity::WorldObjectSpellAreaTargetCheck>>(searcher, containerTypeMask, m_caster, position, range + extraSearchRadius);
1950}
1951
1952void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer* condList, bool isChainHeal)
1953{
1954 // max dist for jump target selection
1955 float jumpRadius = 0.0f;
1956 switch (m_spellInfo->DmgClass)
1957 {
1959 // 7.5y for multi shot
1960 jumpRadius = 7.5f;
1961 break;
1963 // 5y for swipe, cleave and similar
1964 jumpRadius = 5.0f;
1965 break;
1968 // 12.5y for chain heal spell since 3.2 patch
1969 if (isChainHeal)
1970 jumpRadius = 12.5f;
1971 // 10y as default for magic chain spells
1972 else
1973 jumpRadius = 10.0f;
1974 break;
1975 }
1976
1977 // chain lightning/heal spells and similar - allow to jump at larger distance and go out of los
1981
1982 // max dist which spell can reach
1983 float searchRadius = jumpRadius;
1984 if (isBouncingFar)
1985 searchRadius *= chainTargets;
1986
1987 std::list<WorldObject*> tempTargets;
1988 SearchAreaTargets(tempTargets, searchRadius, target, m_caster, objectType, selectType, condList);
1989 tempTargets.remove(target);
1990
1991 // remove targets which are always invalid for chain spells
1992 // for some spells allow only chain targets in front of caster (swipe for example)
1993 if (!isBouncingFar)
1994 {
1995 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end();)
1996 {
1997 std::list<WorldObject*>::iterator checkItr = itr++;
1998 if (!m_caster->HasInArc(static_cast<float>(M_PI), *checkItr))
1999 tempTargets.erase(checkItr);
2000 }
2001 }
2002
2003 while (chainTargets)
2004 {
2005 // try to get unit for next chain jump
2006 std::list<WorldObject*>::iterator foundItr = tempTargets.end();
2007 // get unit with highest hp deficit in dist
2008 if (isChainHeal)
2009 {
2010 uint32 maxHPDeficit = 0;
2011 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2012 {
2013 if (Unit* unit = (*itr)->ToUnit())
2014 {
2015 uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
2016 if (deficit > maxHPDeficit && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
2017 {
2018 foundItr = itr;
2019 maxHPDeficit = deficit;
2020 }
2021 }
2022 }
2023 }
2024 // get closest object
2025 else
2026 {
2027 for (std::list<WorldObject*>::iterator itr = tempTargets.begin(); itr != tempTargets.end(); ++itr)
2028 {
2029 if (foundItr == tempTargets.end())
2030 {
2031 if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
2032 foundItr = itr;
2033 }
2034 else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2))
2035 foundItr = itr;
2036 }
2037 }
2038 // not found any valid target - chain ends
2039 if (foundItr == tempTargets.end())
2040 break;
2041 target = *foundItr;
2042 tempTargets.erase(foundItr);
2043 targets.push_back(target);
2044 --chainTargets;
2045 }
2046}
2047
2056
2058{
2059 //==========================================================================================
2060 // Now fill data for trigger system, need know:
2061 // Create base triggers flags for Attacker and Victim (m_procAttacker, m_procVictim and m_hitMask)
2062 //==========================================================================================
2063
2065 // Get data for type of attack and fill base info for trigger
2066 switch (m_spellInfo->DmgClass)
2067 {
2070 if (m_attackType == OFF_ATTACK)
2072 else
2075 break;
2077 // Auto attack
2079 {
2082 }
2083 else // Ranged spell attack
2084 {
2087 }
2088 break;
2089 default:
2092 && m_spellInfo->HasAttribute(SPELL_ATTR2_AUTOREPEAT_FLAG)) // Wands auto attack
2093 {
2096 }
2097 // For other spells trigger procflags are set in Spell::TargetInfo::DoDamageAndTriggers
2098 // Because spell positivity is dependant on target
2099 }
2100
2101 // Hunter trap spells - activation proc for Lock and Load, Entrapment and Misdirection
2103 (m_spellInfo->SpellFamilyFlags[0] & 0x18 || // Freezing and Frost Trap, Freezing Arrow
2104 m_spellInfo->Id == 57879 || // Snake Trap - done this way to avoid double proc
2105 m_spellInfo->SpellFamilyFlags[2] & 0x00024000)) // Explosive and Immolation Trap
2106 {
2108
2109 // also fill up other flags (TargetInfo::DoDamageAndTriggers only fills up flag if both are not set)
2112 }
2113
2114 // Hellfire Effect - trigger as DOT
2116 {
2119 }
2120}
2121
2123{
2124 m_UniqueTargetInfo.clear();
2125 m_UniqueGOTargetInfo.clear();
2126 m_UniqueItemInfo.clear();
2127 m_delayMoment = 0;
2128}
2129
2131{
2132 public:
2133 ProcReflectDelayed(Unit* owner, ObjectGuid casterGuid) : _victim(owner), _casterGuid(casterGuid) { }
2134
2135 bool Execute(uint64 /*e_time*/, uint32 /*p_time*/) override
2136 {
2138 if (!caster)
2139 return true;
2140
2141 uint32 const typeMaskActor = PROC_FLAG_NONE;
2144 uint32 const spellPhaseMask = PROC_SPELL_PHASE_NONE;
2145 uint32 const hitMask = PROC_HIT_REFLECT;
2146
2147 Unit::ProcSkillsAndAuras(caster, _victim, typeMaskActor, typeMaskActionTarget, spellTypeMask, spellPhaseMask, hitMask, nullptr, nullptr, nullptr);
2148 return true;
2149 }
2150
2151 private:
2154};
2155
2156void Spell::AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid /*= true*/, bool implicit /*= true*/, Position const* losPosition /*= nullptr*/)
2157{
2158 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2159 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(target, spellEffectInfo, losPosition))
2160 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2161
2162 // no effects left
2163 if (!effectMask)
2164 return;
2165
2166 if (checkIfValid)
2167 if (m_spellInfo->CheckTarget(m_caster, target, implicit) != SPELL_CAST_OK) // skip stealth checks for AOE
2168 return;
2169
2170 // Check for effect immune skip if immuned
2171 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2172 if (target->IsImmunedToSpellEffect(m_spellInfo, spellEffectInfo, m_caster))
2173 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2174
2175 ObjectGuid targetGUID = target->GetGUID();
2176
2177 // Lookup target in already in list
2178 auto ihit = std::find_if(std::begin(m_UniqueTargetInfo), std::end(m_UniqueTargetInfo), [targetGUID](TargetInfo const& target) { return target.TargetGUID == targetGUID; });
2179 if (ihit != std::end(m_UniqueTargetInfo)) // Found in list
2180 {
2181 // Immune effects removed from mask
2182 ihit->EffectMask |= effectMask;
2183 ihit->ScaleAura = false;
2184 if (m_auraScaleMask && ihit->EffectMask == m_auraScaleMask && m_caster != target)
2185 {
2186 SpellInfo const* auraSpell = m_spellInfo->GetFirstRankSpell();
2187 if (uint32(target->GetLevel() + 10) >= auraSpell->SpellLevel)
2188 ihit->ScaleAura = true;
2189 }
2190 return;
2191 }
2192
2193 // This is new target calculate data for him
2194
2195 // Get spell hit result on target
2196 TargetInfo targetInfo;
2197 targetInfo.TargetGUID = targetGUID; // Store target GUID
2198 targetInfo.EffectMask = effectMask; // Store all effects not immune
2199 targetInfo.IsAlive = target->IsAlive();
2200 targetInfo.Damage = 0;
2201 targetInfo.Healing = 0;
2202 targetInfo.IsCrit = false;
2203 targetInfo.ScaleAura = false;
2204 if (m_auraScaleMask && targetInfo.EffectMask == m_auraScaleMask && m_caster != target)
2205 {
2206 SpellInfo const* auraSpell = m_spellInfo->GetFirstRankSpell();
2207 if (uint32(target->GetLevel() + 10) >= auraSpell->SpellLevel)
2208 targetInfo.ScaleAura = true;
2209 }
2210
2211 // Calculate hit result
2213 targetInfo.MissCondition = caster->SpellHitResult(target, m_spellInfo, m_canReflect && !(IsPositive() && m_caster->IsFriendlyTo(target)));
2214
2215 // Spell have speed - need calculate incoming time
2216 // Incoming time is zero for self casts. At least I think so.
2217 if (m_spellInfo->Speed > 0.0f && m_caster != target)
2218 {
2219 // calculate spell incoming interval
2221 float dist = m_caster->GetDistance(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ());
2222
2223 if (dist < 5.0f)
2224 dist = 5.0f;
2225
2226 targetInfo.TimeDelay = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
2227
2228 // Calculate minimum incoming time
2229 if (!m_delayMoment || m_delayMoment > targetInfo.TimeDelay)
2230 m_delayMoment = targetInfo.TimeDelay;
2231 }
2232 else
2233 targetInfo.TimeDelay = 0ULL;
2234
2235 // If target reflect spell back to caster
2236 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
2237 {
2238 // Shouldn't be able to reflect gameobject spells
2239 Unit* unitCaster = ASSERT_NOTNULL(m_caster->ToUnit());
2240
2241 // Calculate reflected spell result on caster
2242 SpellCastResult castResult = m_spellInfo->CheckTarget(target, unitCaster, implicit);
2243 targetInfo.ReflectResult = castResult == SPELL_CAST_OK || castResult == SPELL_FAILED_TARGET_AURASTATE
2244 ? unitCaster->SpellHitResult(unitCaster, m_spellInfo,
2245 false /*can't reflect twice*/)
2247
2248 // Proc spell reflect aura when missile hits the original target
2250
2251 // Increase time interval for reflected spells by 1.5
2252 targetInfo.TimeDelay += targetInfo.TimeDelay >> 1;
2253 }
2254 else
2255 targetInfo.ReflectResult = SPELL_MISS_NONE;
2256
2257 // Add target to list
2258 m_UniqueTargetInfo.emplace_back(std::move(targetInfo));
2259}
2260
2262{
2263 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2264 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(go, spellEffectInfo))
2265 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2266
2267 if (!effectMask)
2268 return;
2269
2270 ObjectGuid targetGUID = go->GetGUID();
2271
2272 // Lookup target in already in list
2273 auto ihit = std::find_if(std::begin(m_UniqueGOTargetInfo), std::end(m_UniqueGOTargetInfo), [targetGUID](GOTargetInfo const& target) { return target.TargetGUID == targetGUID; });
2274 if (ihit != std::end(m_UniqueGOTargetInfo)) // Found in list
2275 {
2276 // Add only effect mask
2277 ihit->EffectMask |= effectMask;
2278 return;
2279 }
2280
2281 // This is new target calculate data for him
2282
2283 GOTargetInfo target;
2284 target.TargetGUID = targetGUID;
2285 target.EffectMask = effectMask;
2286
2287 // Spell have speed - need calculate incoming time
2288 if (m_spellInfo->Speed > 0.0f)
2289 {
2290 // calculate spell incoming interval
2291 float dist = m_caster->GetDistance(go->GetPositionX(), go->GetPositionY(), go->GetPositionZ());
2292 if (dist < 5.0f)
2293 dist = 5.0f;
2294
2295 target.TimeDelay = uint64(std::floor(dist / m_spellInfo->Speed * 1000.0f));
2296
2297 if (!m_delayMoment || m_delayMoment > target.TimeDelay)
2298 m_delayMoment = target.TimeDelay;
2299 }
2300 else
2301 target.TimeDelay = 0ULL;
2302
2303 // Add target to list
2304 m_UniqueGOTargetInfo.emplace_back(std::move(target));
2305}
2306
2307void Spell::AddItemTarget(Item* item, uint32 effectMask)
2308{
2309 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2310 if (!spellEffectInfo.IsEffect() || !CheckEffectTarget(item, spellEffectInfo))
2311 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2312
2313 // no effects left
2314 if (!effectMask)
2315 return;
2316
2317 // Lookup target in already in list
2318 auto ihit = std::find_if(std::begin(m_UniqueItemInfo), std::end(m_UniqueItemInfo), [item](ItemTargetInfo const& target) { return target.TargetItem == item; });
2319 if (ihit != std::end(m_UniqueItemInfo)) // Found in list
2320 {
2321 // Add only effect mask
2322 ihit->EffectMask |= effectMask;
2323 return;
2324 }
2325
2326 // This is new target add data
2327
2328 ItemTargetInfo target;
2329 target.TargetItem = item;
2330 target.EffectMask = effectMask;
2331
2332 m_UniqueItemInfo.emplace_back(std::move(target));
2333}
2334
2335void Spell::AddCorpseTarget(Corpse* corpse, uint32 effectMask)
2336{
2337 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
2338 if (!spellEffectInfo.IsEffect())
2339 effectMask &= ~(1 << spellEffectInfo.EffectIndex);
2340
2341 if (!effectMask)
2342 return;
2343
2344 ObjectGuid targetGUID = corpse->GetGUID();
2345
2346 // Lookup target in already in list
2348 {
2349 if (targetGUID == ihit.TargetGUID) // Found in list
2350 {
2351 ihit.EffectMask |= effectMask; // Add only effect mask
2352 return;
2353 }
2354 }
2355
2356 // This is new target calculate data for him
2357 CorpseTargetInfo target;
2358 target.TargetGUID = targetGUID;
2359 target.EffectMask = effectMask;
2360
2361 // Spell have speed - need calculate incoming time
2362 if (m_spellInfo->Speed > 0.0f)
2363 {
2364 // calculate spell incoming interval
2365 float dist = m_caster->GetDistance(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ());
2366 if (dist < 5.0f)
2367 dist = 5.0f;
2368
2369 target.TimeDelay = uint64(floor(dist / m_spellInfo->Speed * 1000.0f));
2370
2371 if (!m_delayMoment || m_delayMoment > target.TimeDelay)
2372 m_delayMoment = target.TimeDelay;
2373 }
2374 else
2375 target.TimeDelay = 0LL;
2376
2377 // Add target to list
2378 m_UniqueCorpseTargetInfo.push_back(target);
2379}
2380
2382{
2383 m_destTargets[effIndex] = dest;
2384}
2385
2387{
2388 return std::count_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [effect](TargetInfo const& targetInfo)
2389 {
2390 return targetInfo.EffectMask & (1 << effect);
2391 });
2392}
2393
2395{
2396 return std::count_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [effect](GOTargetInfo const& targetInfo)
2397 {
2398 return targetInfo.EffectMask & (1 << effect);
2399 });
2400}
2401
2403{
2404 return std::count_if(m_UniqueItemInfo.begin(), m_UniqueItemInfo.end(), [effect](ItemTargetInfo const& targetInfo)
2405 {
2406 return targetInfo.EffectMask & (1 << effect);
2407 });
2408}
2409
2411{
2412 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2413 if (!unit)
2414 return;
2415
2416 // Need init unitTarget by default unit (can changed in code on reflect)
2417 spell->unitTarget = unit;
2418
2419 // Reset damage/healing counter
2420 spell->m_damage = Damage;
2421 spell->m_healing = Healing;
2422
2423 _spellHitTarget = nullptr;
2425 _spellHitTarget = unit;
2427 _spellHitTarget = spell->m_caster->ToUnit();
2428
2430 unit->SetInCombatWith(spell->m_originalCaster);
2431
2433
2434 _enablePVP = false; // need to check PvP state before spell effects, but act on it afterwards
2435 if (_spellHitTarget)
2436 {
2437 // if target is flagged for pvp also flag caster if a player
2438 // but respect current pvp rules (buffing/healing npcs flagged for pvp only flags you if they are in combat)
2439 if (unit->IsPvP() && (unit->IsInCombat() || unit->IsCharmedOwnedByPlayerOrPlayer()) && spell->m_caster->GetTypeId() == TYPEID_PLAYER && spell->m_caster->GetGUID() != unit->GetGUID())
2440 _enablePVP = true; // Decide on PvP flagging now, but act on it later.
2441
2442 SpellMissInfo missInfo = spell->PreprocessSpellHit(_spellHitTarget, ScaleAura, *this);
2443 if (missInfo != SPELL_MISS_NONE)
2444 {
2445 if (missInfo != SPELL_MISS_MISS)
2446 spell->m_caster->SendSpellMiss(unit, spell->m_spellInfo->Id, missInfo);
2447 spell->m_damage = 0;
2448 spell->m_healing = 0;
2449 _spellHitTarget = nullptr;
2450 }
2451 }
2452
2453 spell->CallScriptOnHitHandlers();
2454
2455 // scripts can modify damage/healing for current target, save them
2456 Damage = spell->m_damage;
2457 Healing = spell->m_healing;
2458}
2459
2461{
2462 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2463 if (!unit)
2464 return;
2465
2466 // Need init unitTarget by default unit (can changed in code on reflect)
2467 // Or on missInfo != SPELL_MISS_NONE unitTarget undefined (but need in trigger subsystem)
2468 spell->unitTarget = unit;
2469 spell->targetMissInfo = MissCondition;
2470
2471 // Reset damage/healing counter
2472 spell->m_damage = Damage;
2473 spell->m_healing = Healing;
2474
2475 if (unit->IsAlive() != IsAlive)
2476 return;
2477
2478 if (spell->getState() == SPELL_STATE_DELAYED && !spell->IsPositive() && (GameTime::GetGameTimeMS() - TimeDelay) <= unit->m_lastSanctuaryTime)
2479 return; // No missinfo in that case
2480
2481 if (_spellHitTarget)
2482 spell->DoSpellEffectHit(_spellHitTarget, spellEffectInfo, *this);
2483
2484 // scripts can modify damage/healing for current target, save them
2485 Damage = spell->m_damage;
2486 Healing = spell->m_healing;
2487}
2488
2490{
2491 Unit* unit = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToUnit() : ObjectAccessor::GetUnit(*spell->m_caster, TargetGUID);
2492 if (!unit)
2493 return;
2494
2495 // other targets executed before this one changed pointer
2496 spell->unitTarget = unit;
2497 if (_spellHitTarget)
2498 spell->unitTarget = _spellHitTarget;
2499
2500 // Reset damage/healing counter
2501 spell->m_damage = Damage;
2502 spell->m_healing = Healing;
2503
2504 // Get original caster (if exist) and calculate damage/healing from him data
2505 // Skip if m_originalCaster not available
2506 Unit* caster = spell->m_originalCaster ? spell->m_originalCaster : spell->m_caster->ToUnit();
2507
2508 if (caster)
2509 {
2510 // Fill base trigger info
2511 uint32 procAttacker = spell->m_procAttacker;
2512 uint32 procVictim = spell->m_procVictim;
2513 uint32 procSpellType = PROC_SPELL_TYPE_NONE;
2514 uint32 hitMask = PROC_HIT_NONE;
2515
2516 // Spells with this flag cannot trigger if effect is cast on self
2517 bool const canEffectTrigger = !spell->m_spellInfo->HasAttribute(SPELL_ATTR3_CANT_TRIGGER_PROC) && spell->unitTarget->CanProc() &&
2518 (spell->CanExecuteTriggersOnHit(EffectMask) || MissCondition == SPELL_MISS_IMMUNE || MissCondition == SPELL_MISS_IMMUNE2);
2519
2520 // Trigger info was not filled in Spell::prepareDataForTriggerSystem - we do it now
2521 if (canEffectTrigger && !procAttacker && !procVictim)
2522 {
2523 bool positive = true;
2524 if (spell->m_damage > 0)
2525 positive = false;
2526 else if (!spell->m_healing)
2527 {
2528 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
2529 {
2530 // in case of immunity, check all effects to choose correct procFlags, as none has technically hit
2531 if (EffectMask && !(EffectMask & (1 << i)))
2532 continue;
2533
2534 if (!spell->m_spellInfo->IsPositiveEffect(i))
2535 {
2536 positive = false;
2537 break;
2538 }
2539 }
2540 }
2541
2542 switch (spell->m_spellInfo->DmgClass)
2543 {
2545 if (positive)
2546 {
2549 }
2550 else
2551 {
2554 }
2555 break;
2557 if (positive)
2558 {
2561 }
2562 else
2563 {
2566 }
2567 break;
2568 }
2569 }
2570
2571 // All calculated do it!
2572 // Do healing
2573 bool hasHealing = false;
2574 std::unique_ptr<DamageInfo> spellDamageInfo;
2575 std::unique_ptr<HealInfo> healInfo;
2576 if (spell->m_healing > 0)
2577 {
2578 hasHealing = true;
2579 uint32 addhealth = spell->m_healing;
2580 if (IsCrit)
2581 {
2582 hitMask |= PROC_HIT_CRITICAL;
2583 addhealth = Unit::SpellCriticalHealingBonus(caster, spell->m_spellInfo, addhealth, nullptr);
2584 }
2585 else
2586 hitMask |= PROC_HIT_NORMAL;
2587
2588 healInfo = std::make_unique<HealInfo>(caster, spell->unitTarget, addhealth, spell->m_spellInfo, spell->m_spellInfo->GetSchoolMask());
2589 caster->HealBySpell(*healInfo, IsCrit);
2590 spell->unitTarget->GetThreatManager().ForwardThreatForAssistingMe(caster, float(healInfo->GetEffectiveHeal()) * 0.5f, spell->m_spellInfo);
2591 spell->m_healing = healInfo->GetEffectiveHeal();
2592
2593 procSpellType |= PROC_SPELL_TYPE_HEAL;
2594 }
2595
2596 // Do damage
2597 bool hasDamage = false;
2598 if (spell->m_damage > 0)
2599 {
2600 hasDamage = true;
2601 // Fill base damage struct (unitTarget - is real spell target)
2602 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask);
2603 // Check damage immunity
2604 if (spell->unitTarget->IsImmunedToDamage(spell->m_spellInfo))
2605 {
2606 hitMask = PROC_HIT_IMMUNE;
2607 spell->m_damage = 0;
2608
2609 // no packet found in sniffs
2610 }
2611 else
2612 {
2613 caster->SetLastDamagedTargetGuid(spell->unitTarget->GetGUID());
2614
2615 // Add bonuses and fill damageInfo struct
2616 caster->CalculateSpellDamageTaken(&damageInfo, spell->m_damage, spell->m_spellInfo, spell->m_attackType, IsCrit, MissCondition == SPELL_MISS_BLOCK, spell);
2617 Unit::DealDamageMods(damageInfo.target, damageInfo.damage, &damageInfo.absorb);
2618
2619 // Send log damage message to client
2620 caster->SendSpellNonMeleeDamageLog(&damageInfo);
2621
2622 hitMask |= createProcHitMask(&damageInfo, MissCondition);
2623 procVictim |= PROC_FLAG_TAKEN_DAMAGE;
2624
2625 spell->m_damage = damageInfo.damage;
2626 caster->DealSpellDamage(&damageInfo, true);
2627 }
2628
2629 // Do triggers for unit
2630 if (canEffectTrigger)
2631 {
2632 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, SPELL_DIRECT_DAMAGE, spell->m_attackType, hitMask);
2633 procSpellType |= PROC_SPELL_TYPE_DAMAGE;
2634 }
2635 }
2636
2637 // Passive spell hits/misses or active spells only misses (only triggers)
2638 if (!hasHealing && !hasDamage)
2639 {
2640 // Fill base damage struct (unitTarget - is real spell target)
2641 SpellNonMeleeDamage damageInfo(caster, spell->unitTarget, spell->m_spellInfo->Id, spell->m_spellSchoolMask);
2642 hitMask |= createProcHitMask(&damageInfo, MissCondition);
2643 // Do triggers for unit
2644 if (canEffectTrigger)
2645 {
2646 spellDamageInfo = std::make_unique<DamageInfo>(damageInfo, NODAMAGE, spell->m_attackType, hitMask);
2647 procSpellType |= PROC_SPELL_TYPE_NO_DMG_HEAL;
2648 }
2649
2650 // Failed Pickpocket, reveal rogue
2652 {
2653 Unit* unitCaster = ASSERT_NOTNULL(spell->m_caster->ToUnit());
2655 spell->unitTarget->ToCreature()->EngageWithTarget(unitCaster);
2656 }
2657 }
2658
2659 // Do triggers for unit
2660 if (canEffectTrigger)
2661 {
2662 Unit::ProcSkillsAndAuras(caster, spell->unitTarget, procAttacker, procVictim, procSpellType, PROC_SPELL_PHASE_HIT, hitMask, spell, spellDamageInfo.get(), healInfo.get());
2663
2664 // item spells (spell hit of non-damage spell may also activate items, for example seal of corruption hidden hit)
2665 if (caster->GetTypeId() == TYPEID_PLAYER && (procSpellType & (PROC_SPELL_TYPE_DAMAGE | PROC_SPELL_TYPE_NO_DMG_HEAL)))
2666 {
2669 caster->ToPlayer()->CastItemCombatSpell(*spellDamageInfo);
2670 }
2671 }
2672
2673 // set hitmask for finish procs
2674 spell->m_hitMask |= hitMask;
2675
2676 // Do not take combo points on dodge and miss
2677 if (MissCondition != SPELL_MISS_NONE && spell->m_needComboPoints && spell->m_targets.GetUnitTargetGUID() == TargetGUID)
2678 spell->m_needComboPoints = false;
2679
2680 // _spellHitTarget can be null if spell is missed in DoSpellHitOnUnit
2681 if (MissCondition != SPELL_MISS_EVADE && _spellHitTarget && !spell->m_caster->IsFriendlyTo(unit) && (!spell->IsPositive() || spell->m_spellInfo->HasEffect(SPELL_EFFECT_DISPEL)))
2682 {
2683 if (Unit* unitCaster = spell->m_caster->ToUnit())
2684 unitCaster->AtTargetAttacked(unit, spell->m_spellInfo->HasInitialAggro());
2685
2686 if (!unit->IsStandState())
2688 }
2689
2690 // Check for SPELL_ATTR7_INTERRUPT_ONLY_NONPLAYER
2692 caster->CastSpell(unit, SPELL_INTERRUPT_NONPLAYER, true);
2693 }
2694
2695 if (_spellHitTarget)
2696 {
2697 //AI functions
2698 if (Creature* cHitTarget = _spellHitTarget->ToCreature())
2699 if (CreatureAI* hitTargetAI = cHitTarget->AI())
2700 hitTargetAI->SpellHit(spell->m_caster, spell->m_spellInfo);
2701
2702 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
2703 spell->m_caster->ToCreature()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
2704 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
2705 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(_spellHitTarget, spell->m_spellInfo);
2706
2707 if (HitAura)
2708 {
2709 if (AuraApplication* aurApp = HitAura->GetApplicationOfTarget(_spellHitTarget->GetGUID()))
2710 {
2711 // only apply unapplied effects (for reapply case)
2712 uint8 effMask = EffectMask & aurApp->GetEffectsToApply();
2713 for (uint8 i = 0; i < spell->m_spellInfo->GetEffects().size(); ++i)
2714 if ((effMask & (1 << i)) && aurApp->HasEffect(i))
2715 effMask &= ~(1 << i);
2716
2717 if (effMask)
2718 _spellHitTarget->_ApplyAura(aurApp, effMask);
2719 }
2720 }
2721
2722 // Needs to be called after dealing damage/healing to not remove breaking on damage auras
2723 spell->DoTriggersOnSpellHit(_spellHitTarget, EffectMask);
2724
2725 if (_enablePVP)
2726 spell->m_caster->ToPlayer()->UpdatePvP(true);
2727 }
2728
2729 spell->_spellAura = HitAura;
2731 spell->_spellAura = nullptr;
2732}
2733
2735{
2736 GameObject* go = spell->m_caster->GetGUID() == TargetGUID ? spell->m_caster->ToGameObject() : ObjectAccessor::GetGameObject(*spell->m_caster, TargetGUID);
2737 if (!go)
2738 return;
2739
2741
2742 spell->HandleEffects(nullptr, nullptr, go, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2743
2744 // AI functions
2745 if (go->AI())
2746 go->AI()->SpellHit(spell->m_caster, spell->m_spellInfo);
2747
2748 if (spell->m_caster->GetTypeId() == TYPEID_UNIT && spell->m_caster->ToCreature()->IsAIEnabled())
2749 spell->m_caster->ToCreature()->AI()->SpellHitTarget(go, spell->m_spellInfo);
2750 else if (spell->m_caster->GetTypeId() == TYPEID_GAMEOBJECT && spell->m_caster->ToGameObject()->AI())
2751 spell->m_caster->ToGameObject()->AI()->SpellHitTarget(go, spell->m_spellInfo);
2752
2753 spell->CallScriptOnHitHandlers();
2755}
2756
2758{
2760
2761 spell->HandleEffects(nullptr, TargetItem, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2762
2763 spell->CallScriptOnHitHandlers();
2765}
2766
2768{
2769 Corpse* corpse = ObjectAccessor::GetCorpse(*spell->m_caster, TargetGUID);
2770 if (!corpse)
2771 return;
2772
2774
2775 spell->HandleEffects(nullptr, nullptr, nullptr, corpse, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2776
2777 spell->CallScriptOnHitHandlers();
2779}
2780
2782{
2783 if (!unit)
2784 return SPELL_MISS_EVADE;
2785
2786 // Target may have begun evading between launch and hit phases - re-check now
2787 if (Creature* creatureTarget = unit->ToCreature())
2788 if (creatureTarget->IsEvadingAttacks())
2789 return SPELL_MISS_EVADE;
2790
2791 // For delayed spells immunity may be applied between missile launch and hit - check immunity for that case
2793 return SPELL_MISS_IMMUNE;
2794
2795 if (Player* player = unit->ToPlayer())
2796 {
2797 player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_TARGET, m_spellInfo->Id);
2798 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, m_spellInfo->Id, 0, m_caster);
2799 }
2800
2801 if (Player* player = m_caster->ToPlayer())
2802 {
2803 player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_SPELL_CASTER, m_spellInfo->Id);
2804 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2, m_spellInfo->Id, 0, unit);
2805 }
2806
2807 if (m_caster != unit)
2808 {
2809 // Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
2811 return SPELL_MISS_EVADE;
2812
2815 else if (m_caster->IsFriendlyTo(unit))
2816 {
2817 // for delayed spells ignore negative spells (after duel end) for friendly targets
2818 if (m_spellInfo->Speed > 0.0f && unit->GetTypeId() == TYPEID_PLAYER && !IsPositive() && !m_caster->IsValidAssistTarget(unit, m_spellInfo))
2819 return SPELL_MISS_EVADE;
2820
2821 // assisting case, healing and resurrection
2823 {
2825 {
2826 playerOwner->SetContestedPvP();
2827 playerOwner->UpdatePvP(true);
2828 }
2829 }
2830
2832 {
2833 if (m_originalCaster->HasUnitFlag(UNIT_FLAG_PLAYER_CONTROLLED)) // only do explicit combat forwarding for PvP enabled units
2834 m_originalCaster->GetCombatManager().InheritCombatStatesFrom(unit); // for creature v creature combat, the threat forward does it for us
2836 }
2837 }
2838 }
2839
2840 // original caster for auras
2841 WorldObject* origCaster = m_caster;
2842 if (m_originalCaster)
2843 origCaster = m_originalCaster;
2844
2845 // check immunity due to diminishing returns
2847 {
2848 // Select rank for aura with level requirements only in specific cases
2849 // 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
2850 hitInfo.AuraSpellInfo = m_spellInfo;
2851 if (scaleAura)
2852 {
2853 if (SpellInfo const* actualSpellInfo = m_spellInfo->GetAuraRankForLevel(unitTarget->GetLevel()))
2854 hitInfo.AuraSpellInfo = actualSpellInfo;
2855
2856 for (SpellEffectInfo const& auraEffectInfo : hitInfo.AuraSpellInfo->GetEffects())
2857 {
2858 hitInfo.AuraBasePoints[auraEffectInfo.EffectIndex] = auraEffectInfo.BasePoints;
2859 if (m_spellInfo->GetEffect(auraEffectInfo.EffectIndex).Effect != auraEffectInfo.Effect)
2860 {
2861 hitInfo.AuraSpellInfo = m_spellInfo;
2862 break;
2863 }
2864 }
2865 }
2866
2867 // Get Data Needed for Diminishing Returns, some effects may have multiple auras, so this must be done on spell hit, not aura add
2868 bool triggered = (m_triggeredByAuraSpell != nullptr);
2870
2871 DiminishingLevels diminishLevel = DIMINISHING_LEVEL_1;
2872 if (hitInfo.DRGroup)
2873 {
2874 diminishLevel = unit->GetDiminishing(hitInfo.DRGroup);
2876 // Increase Diminishing on unit, current informations for actually casts will use values above
2877 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && unit->IsAffectedByDiminishingReturns()))
2878 unit->IncrDiminishing(m_spellInfo, triggered);
2879 }
2880
2881 // Now Reduce spell duration using data received at spell hit
2882 // check whatever effects we're going to apply, diminishing returns only apply to negative aura effects
2883 hitInfo.Positive = true;
2884 if (origCaster == unit || !origCaster->IsFriendlyTo(unit))
2885 {
2886 for (SpellEffectInfo const& auraSpellEffect : hitInfo.AuraSpellInfo->GetEffects())
2887 {
2888 // mod duration only for effects applying aura!
2889 if (hitInfo.EffectMask & (1 << auraSpellEffect.EffectIndex) &&
2890 auraSpellEffect.IsUnitOwnedAuraEffect() &&
2891 !hitInfo.AuraSpellInfo->IsPositiveEffect(auraSpellEffect.EffectIndex))
2892 {
2893 hitInfo.Positive = false;
2894 break;
2895 }
2896 }
2897 }
2898
2899 hitInfo.AuraDuration = Aura::CalcMaxDuration(hitInfo.AuraSpellInfo, origCaster);
2900
2901 // unit is immune to aura if it was diminished to 0 duration
2902 if (!hitInfo.Positive && !unit->ApplyDiminishingToDuration(hitInfo.AuraSpellInfo, triggered, hitInfo.AuraDuration, origCaster, diminishLevel))
2903 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; }))
2904 return SPELL_MISS_IMMUNE;
2905 }
2906
2907 return SPELL_MISS_NONE;
2908}
2909
2910void Spell::DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo, TargetInfo& hitInfo)
2911{
2912 if (uint8 aura_effmask = Aura::BuildEffectMaskForOwner(m_spellInfo, 1 << spellEffectInfo.EffectIndex, unit))
2913 {
2914 WorldObject* caster = m_caster;
2915 if (m_originalCaster)
2916 caster = m_originalCaster;
2917
2918 if (caster)
2919 {
2920 bool refresh = false;
2921
2922 if (!hitInfo.HitAura)
2923 {
2924 bool const resetPeriodicTimer = (m_spellInfo->StackAmount < 2) && !(_triggeredCastFlags & TRIGGERED_DONT_RESET_PERIODIC_TIMER);
2925 uint8 const allAuraEffectMask = Aura::BuildEffectMaskForOwner(hitInfo.AuraSpellInfo, MAX_EFFECT_MASK, unit);
2926 int32 const* bp = hitInfo.AuraBasePoints;
2927 if (hitInfo.AuraSpellInfo == m_spellInfo)
2929
2930 AuraCreateInfo createInfo(hitInfo.AuraSpellInfo, allAuraEffectMask, unit);
2931 createInfo
2932 .SetCasterGUID(caster->GetGUID())
2933 .SetBaseAmount(bp)
2935 .SetPeriodicReset(resetPeriodicTimer)
2936 .SetOwnerEffectMask(aura_effmask)
2937 .IsRefresh = &refresh;
2938
2939 if (Aura* aura = Aura::TryRefreshStackOrCreate(createInfo, false))
2940 {
2941 hitInfo.HitAura = aura->ToUnitAura();
2942
2943 // Set aura stack amount to desired value
2945 {
2946 if (!refresh)
2948 else
2950 }
2951
2952 hitInfo.HitAura->SetDiminishGroup(hitInfo.DRGroup);
2953
2954 hitInfo.AuraDuration = caster->ModSpellDuration(hitInfo.AuraSpellInfo, unit, hitInfo.AuraDuration, hitInfo.Positive, hitInfo.HitAura->GetEffectMask());
2955
2956 // Haste modifies duration of channeled spells
2957 if (m_spellInfo->IsChanneled())
2958 caster->ModSpellDurationTime(hitInfo.AuraSpellInfo, hitInfo.AuraDuration, this);
2959 // and duration of auras affected by SPELL_AURA_PERIODIC_HASTE
2962
2963 if (hitInfo.AuraDuration != hitInfo.HitAura->GetMaxDuration())
2964 {
2965 hitInfo.HitAura->SetMaxDuration(hitInfo.AuraDuration);
2966 hitInfo.HitAura->SetDuration(hitInfo.AuraDuration);
2967 }
2968
2969 if (refresh)
2970 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
2971 }
2972 }
2973 else
2974 hitInfo.HitAura->AddStaticApplication(unit, aura_effmask);
2975 }
2976 }
2977
2978 _spellAura = hitInfo.HitAura;
2979 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT_TARGET);
2980 _spellAura = nullptr;
2981}
2982
2984{
2985 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras
2986 // this is executed after spell proc spells on target hit
2987 // spells are triggered for each hit spell target
2988 // info confirmed with retail sniffs of permafrost and shadow weaving
2989 if (!m_hitTriggerSpells.empty())
2990 {
2991 int32 _duration = 0;
2992 for (auto i = m_hitTriggerSpells.begin(); i != m_hitTriggerSpells.end(); ++i)
2993 {
2994 if (CanExecuteTriggersOnHit(effMask, i->triggeredByAura) && roll_chance_i(i->chance))
2995 {
2996 m_caster->CastSpell(unit, i->triggeredSpell->Id, true);
2997 TC_LOG_DEBUG("spells", "Spell {} triggered spell {} by SPELL_AURA_ADD_TARGET_TRIGGER aura", m_spellInfo->Id, i->triggeredSpell->Id);
2998
2999 // SPELL_AURA_ADD_TARGET_TRIGGER auras shouldn't trigger auras without duration
3000 // set duration of current aura to the triggered spell
3001 if (i->triggeredSpell->GetDuration() == -1)
3002 {
3003 if (Aura* triggeredAur = unit->GetAura(i->triggeredSpell->Id, m_caster->GetGUID()))
3004 {
3005 // get duration from aura-only once
3006 if (!_duration)
3007 {
3008 Aura* aur = unit->GetAura(m_spellInfo->Id, m_caster->GetGUID());
3009 _duration = aur ? aur->GetDuration() : -1;
3010 }
3011 triggeredAur->SetDuration(_duration);
3012 }
3013 }
3014 }
3015 }
3016 }
3017
3018 // trigger linked auras remove/apply
3020 if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT))
3021 {
3022 for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
3023 {
3024 if (*i < 0)
3025 unit->RemoveAurasDueToSpell(-(*i));
3026 else
3027 unit->CastSpell(unit, *i, m_caster->GetGUID());
3028 }
3029 }
3030}
3031
3033{
3034 // Not need check return true
3036 return true;
3037
3038 uint8 channelTargetEffectMask = m_channelTargetEffectMask;
3039 uint8 channelAuraMask = 0;
3040 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3041 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3042 channelAuraMask |= 1 << spellEffectInfo.EffectIndex;
3043
3044 channelAuraMask &= channelTargetEffectMask;
3045
3046 float range = 0;
3047 if (channelAuraMask)
3048 {
3050 if (Player* modOwner = m_caster->GetSpellModOwner())
3051 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, range, this);
3052
3053 // add little tolerance level
3054 range += std::min(MAX_SPELL_RANGE_TOLERANCE, range*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
3055 }
3056
3057 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
3058 {
3059 if (targetInfo.MissCondition == SPELL_MISS_NONE && (channelTargetEffectMask & targetInfo.EffectMask))
3060 {
3061 Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
3062 if (!unit)
3063 continue;
3064
3065 if (IsValidDeadOrAliveTarget(unit))
3066 {
3067 if (channelAuraMask & targetInfo.EffectMask)
3068 {
3070 {
3071 if (m_caster != unit && !m_caster->IsWithinDistInMap(unit, range))
3072 {
3073 targetInfo.EffectMask &= ~aurApp->GetEffectMask();
3074 unit->RemoveAura(aurApp);
3075 continue;
3076 }
3077 }
3078 else // aura is dispelled
3079 continue;
3080 }
3081
3082 channelTargetEffectMask &= ~targetInfo.EffectMask; // remove from need alive mask effect that have alive target
3083 }
3084 }
3085 }
3086
3087 // is all effects from m_needAliveTargetMask have alive targets
3088 return channelTargetEffectMask == 0;
3089}
3090
3091SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura)
3092{
3093 if (m_CastItem)
3094 {
3097 }
3098 else
3099 {
3101 m_castItemEntry = 0;
3102 }
3103
3104 InitExplicitTargets(targets);
3105
3106 // Fill aura scaling information
3107 if (Unit* unitCaster = m_caster->ToUnit())
3108 {
3109 if (unitCaster->IsControlledByPlayer() && !m_spellInfo->IsPassive() && m_spellInfo->SpellLevel && !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_SCALING))
3110 {
3111 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3112 {
3113 if (spellEffectInfo.IsEffect(SPELL_EFFECT_APPLY_AURA))
3114 {
3115 // Change aura with ranks only if basepoints are taken from spellInfo and aura is positive
3116 if (m_spellInfo->IsPositiveEffect(spellEffectInfo.EffectIndex))
3117 {
3118 m_auraScaleMask |= (1 << spellEffectInfo.EffectIndex);
3119 if (m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex] != spellEffectInfo.BasePoints)
3120 {
3121 m_auraScaleMask = 0;
3122 break;
3123 }
3124 }
3125 }
3126 }
3127 }
3128 }
3129
3131
3132 if (triggeredByAura)
3133 m_triggeredByAuraSpell = triggeredByAura->GetSpellInfo();
3134
3135 // create and add update event for this spell
3136 _spellEvent = new SpellEvent(this);
3138
3139 // check disables
3141 {
3143 finish(false);
3145 }
3146
3147 // Prevent casting at cast another spell (ServerSide check)
3149 {
3151 finish(false);
3153 }
3154
3155 LoadScripts();
3156
3157 // Fill cost data (do not use power for item casts)
3159
3160 // Set combo point requirement
3162 m_needComboPoints = false;
3163
3164 uint32 param1 = 0, param2 = 0;
3165 SpellCastResult result = CheckCast(true, &param1, &param2);
3166 // target is checked in too many locations and with different results to handle each of them
3167 // handle just the general SPELL_FAILED_BAD_TARGETS result which is the default result for most DBC target checks
3169 result = SPELL_CAST_OK;
3170 if (result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
3171 {
3172 // Periodic auras should be interrupted when aura triggers a spell which can't be cast
3173 // for example bladestorm aura should be removed on disarm as of patch 3.3.5
3174 // channeled periodic spells should be affected by this (arcane missiles, penance, etc)
3175 // a possible alternative sollution for those would be validating aura target on unit state change
3176 if (triggeredByAura && triggeredByAura->IsPeriodic() && !triggeredByAura->GetBase()->IsPassive())
3177 {
3179 triggeredByAura->GetBase()->SetDuration(0);
3180 }
3181
3182 if (param1 || param2)
3183 SendCastResult(result, &param1, &param2);
3184 else
3185 SendCastResult(result);
3186
3187 finish(false);
3188 return result;
3189 }
3190
3191 // Prepare data for triggers
3193
3194 if (Player* player = m_caster->ToPlayer())
3195 {
3196 if (!player->GetCommandStatus(CHEAT_CASTTIME))
3197 {
3198 // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail)
3200 }
3201 else
3202 m_casttime = 0; // Set cast time to 0 if .cheat casttime is enabled.
3203 }
3204 else
3206
3207 SpellCastResult movementResult = SPELL_CAST_OK;
3208 if (m_caster->IsUnit() && m_caster->ToUnit()->isMoving())
3209 movementResult = CheckMovement();
3210
3211 // Creatures focus their target when possible
3213 {
3214 // 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
3215 bool const focusTarget = !m_spellInfo->IsChanneled() && !(_triggeredCastFlags & TRIGGERED_IGNORE_SET_FACING);
3216 if (focusTarget && m_targets.GetObjectTarget() && m_caster != m_targets.GetObjectTarget())
3218 else
3219 m_caster->ToCreature()->SetSpellFocus(this, nullptr);
3220 }
3221
3222 if (movementResult != SPELL_CAST_OK)
3223 {
3225 {
3226 SendCastResult(movementResult);
3227 finish(movementResult);
3228 return movementResult;
3229 }
3230 else
3231 {
3232 // Creatures (not controlled) give priority to spell casting over movement.
3233 // We assume that the casting is always valid and the current movement
3234 // is stopped immediately (because spells are updated before movement, so next Unit::Update would cancel the spell before stopping movement)
3235 // and future attempts are stopped by by Unit::IsMovementPreventedByCasting in movement generators to prevent casting interruption.
3237 }
3238 }
3239
3240 // set timer base at cast time
3241 ReSetTimer();
3242
3243 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());
3244
3245 //Containers for channeled spells have to be set
3247 // Why check duration? 29350: channelled triggers channelled
3249 cast(true);
3250 else
3251 {
3252 if (Unit* unitCaster = m_caster->ToUnit())
3253 {
3254 // stealth must be removed at cast starting (at show channel bar)
3255 // skip triggered spell (item equip spell casting and other not explicit character casts/item uses)
3257 {
3258 unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CAST);
3259 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3260 {
3261 if (spellEffectInfo.GetUsedTargetObjectType() == TARGET_OBJECT_TYPE_UNIT)
3262 {
3263 unitCaster->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_SPELL_ATTACK);
3264 break;
3265 }
3266 }
3267 }
3268
3269 unitCaster->SetCurrentCastSpell(this);
3270 }
3272
3275
3276 // Call CreatureAI hook OnSpellStart
3277 if (Creature* caster = m_caster->ToCreature())
3278 if (caster->IsAIEnabled())
3279 caster->AI()->OnSpellStart(GetSpellInfo());
3280
3281 // commented out !m_spellInfo->StartRecoveryTime, it forces instant spells with global cooldown to be processed in spell::update
3282 // as a result a spell that passed CheckCast and should be processed instantly may suffer from this delayed process
3283 // 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
3284 // 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)
3286 cast(true);
3287 }
3288
3289 return SPELL_CAST_OK;
3290}
3291
3292void Spell::cancel(SpellCastResult result /*= SPELL_FAILED_INTERRUPTED*/, Optional<SpellCastResult> resultOther /*= {}*/)
3293{
3295 return;
3296
3297 uint32 oldState = m_spellState;
3299
3300 m_autoRepeat = false;
3301 switch (oldState)
3302 {
3305 SendCastResult(result);
3306 SendInterrupted(result, resultOther);
3307 break;
3309 SendInterrupted(result, resultOther);
3310 break;
3312 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
3313 if (targetInfo.MissCondition == SPELL_MISS_NONE)
3314 if (Unit* unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID))
3315 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3316
3318 SendInterrupted(result, resultOther);
3319
3320 m_appliedMods.clear();
3321 break;
3322 default:
3323 break;
3324 }
3325
3327 if (m_selfContainer && *m_selfContainer == this)
3328 *m_selfContainer = nullptr;
3329
3330 // update original caster pointer to prevent access to non-existed already object (grid unload)
3332
3333 // originalcaster handles gameobjects/dynobjects for gob caster
3334 if (m_originalCaster)
3335 {
3337 if (m_spellInfo->IsChanneled()) // if not channeled then the object for the current cast wasn't summoned yet
3338 {
3340 {
3341 m_originalCaster->RemoveGameObject(gameObject, true);
3342 if (gameObject->GetGoType() == GAMEOBJECT_TYPE_RITUAL)
3344 }
3345 }
3346 }
3347
3348 //set state back so finish will be processed
3349 m_spellState = oldState;
3350
3351 finish(false);
3352}
3353
3354void Spell::cast(bool skipCheck)
3355{
3356 Player* modOwner = m_caster->GetSpellModOwner();
3357 Spell* lastSpellMod = nullptr;
3358 if (modOwner)
3359 {
3360 lastSpellMod = modOwner->m_spellModTakingSpell;
3361 if (lastSpellMod)
3362 modOwner->SetSpellModTakingSpell(lastSpellMod, false);
3363 }
3364
3365 _cast(skipCheck);
3366
3367 if (lastSpellMod)
3368 modOwner->SetSpellModTakingSpell(lastSpellMod, true);
3369}
3370
3371void Spell::_cast(bool skipCheck)
3372{
3373 // update pointers base at GUIDs to prevent access to non-existed already object
3374 if (!UpdatePointers())
3375 {
3376 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3377 cancel();
3378 return;
3379 }
3380
3381 // cancel at lost explicit target during cast
3383 {
3384 cancel();
3385 return;
3386 }
3387
3388 if (Player* playerCaster = m_caster->ToPlayer())
3389 {
3390 // now that we've done the basic check, now run the scripts
3391 // should be done before the spell is actually executed
3392 sScriptMgr->OnPlayerSpellCast(playerCaster, this, skipCheck);
3393
3394 // As of 3.0.2 pets begin attacking their owner's target immediately
3395 // Let any pets know we've attacked something. Check DmgClass for harmful spells only
3396 // This prevents spells such as Hunter's Mark from triggering pet attack
3397 if (GetSpellInfo()->DmgClass != SPELL_DAMAGE_CLASS_NONE)
3398 if (Unit* target = m_targets.GetUnitTarget())
3399 for (Unit* controlled : playerCaster->m_Controlled)
3400 if (Creature* cControlled = controlled->ToCreature())
3401 if (CreatureAI* controlledAI = cControlled->AI())
3402 controlledAI->OwnerAttacked(target);
3403 }
3404
3406
3407 // Should this be done for original caster?
3408 Player* modOwner = m_caster->GetSpellModOwner();
3409 if (modOwner)
3410 {
3411 // Set spell which will drop charges for triggered cast spells
3412 // if not successfully cast, will be remove in finish(false)
3413 modOwner->SetSpellModTakingSpell(this, true);
3414 }
3415
3417
3418 // skip check if done already (for instant cast spells for example)
3419 if (!skipCheck)
3420 {
3421 auto cleanupSpell = [this, modOwner](SpellCastResult res, uint32* p1 = nullptr, uint32* p2 = nullptr)
3422 {
3423 SendCastResult(res, p1, p2);
3424 SendInterrupted(res);
3425
3426 if (modOwner)
3427 modOwner->SetSpellModTakingSpell(this, false);
3428
3429 finish(false);
3430 SetExecutedCurrently(false);
3431 };
3432
3433 uint32 param1 = 0, param2 = 0;
3434 SpellCastResult castResult = CheckCast(false, &param1, &param2);
3435 if (castResult != SPELL_CAST_OK)
3436 {
3437 cleanupSpell(castResult, &param1, &param2);
3438 return;
3439 }
3440
3441 // additional check after cast bar completes (must not be in CheckCast)
3442 // if trade not complete then remember it in trade data
3444 {
3445 if (modOwner)
3446 {
3447 if (TradeData* my_trade = modOwner->GetTradeData())
3448 {
3449 if (!my_trade->IsInAcceptProcess())
3450 {
3451 // Spell will be cast after completing the trade. Silently ignore at this place
3452 my_trade->SetSpell(m_spellInfo->Id, m_CastItem);
3453 cleanupSpell(SPELL_FAILED_DONT_REPORT);
3454 return;
3455 }
3456 }
3457 }
3458 }
3459
3460 // check diminishing returns (again, only after finish cast bar, tested on retail)
3461 if (Unit* target = m_targets.GetUnitTarget())
3462 {
3463 uint8 aura_effmask = 0;
3464 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3465 if (spellEffectInfo.IsUnitOwnedAuraEffect())
3466 aura_effmask |= 1 << spellEffectInfo.EffectIndex;
3467
3468 if (aura_effmask)
3469 {
3470 bool const triggered = m_triggeredByAuraSpell != nullptr;
3472 {
3474 if (type == DRTYPE_ALL || (type == DRTYPE_PLAYER && target->IsAffectedByDiminishingReturns()))
3475 {
3477 {
3478 if (target->HasStrongerAuraWithDR(m_spellInfo, caster, triggered))
3479 {
3480 cleanupSpell(SPELL_FAILED_AURA_BOUNCED);
3481 return;
3482 }
3483 }
3484 }
3485 }
3486 }
3487 }
3488 }
3489 // 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.
3490 if (Creature* creatureCaster = m_caster->ToCreature())
3491 if (!creatureCaster->GetTarget().IsEmpty() && !creatureCaster->HasUnitFlag(UNIT_FLAG_POSSESSED))
3492 if (WorldObject const* target = ObjectAccessor::GetUnit(*creatureCaster, creatureCaster->GetTarget()))
3493 creatureCaster->SetInFront(target);
3494
3496
3497 // Spell may be finished after target map check
3499 {
3501
3502 if (modOwner)
3503 modOwner->SetSpellModTakingSpell(this, false);
3504
3505 finish(false);
3506 SetExecutedCurrently(false);
3507 return;
3508 }
3509
3510 if (Unit* unitCaster = m_caster->ToUnit())
3512 if (Creature* pet = ObjectAccessor::GetCreatureOrPetOrVehicle(*m_caster, unitCaster->GetPetGUID()))
3513 pet->DespawnOrUnsummon();
3514
3516
3518
3519 // traded items have trade slot instead of guid in m_itemTargetGUID
3520 // set to real guid to be sent later to the client
3522
3523 if (Player* player = m_caster->ToPlayer())
3524 {
3526 {
3527 player->StartTimedAchievement(ACHIEVEMENT_TIMED_TYPE_ITEM, m_CastItem->GetEntry());
3528 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM, m_CastItem->GetEntry());
3529 }
3530
3531 player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, m_spellInfo->Id);
3532 }
3533
3535 {
3536 // Powers have to be taken before SendSpellGo
3537 TakePower();
3538 TakeReagents(); // we must remove reagents before HandleEffects to allow place crafted item in same slot
3539 }
3540 else if (Item* targetItem = m_targets.GetItemTarget())
3541 {
3543 if (targetItem->GetOwnerGUID() != m_caster->GetGUID())
3544 TakeReagents();
3545 }
3546
3547 // CAST SPELL
3549
3551
3552 // we must send smsg_spell_go packet before m_castItem delete in TakeCastItem()...
3553 SendSpellGo();
3554
3555 if (!m_spellInfo->IsChanneled())
3556 if (Creature* creatureCaster = m_caster->ToCreature())
3557 creatureCaster->ReleaseSpellFocus(this);
3558
3559 // Okay, everything is prepared. Now we need to distinguish between immediate and evented delayed spells
3560 if (m_spellInfo->Speed > 0.0f && !m_spellInfo->IsChanneled())
3561 {
3562 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3563 // in case delayed spell remove item at cast delay start
3564 TakeCastItem();
3565
3566 // Okay, maps created, now prepare flags
3567 m_immediateHandled = false;
3569 SetDelayStart(0);
3570
3571 if (Unit* unitCaster = m_caster->ToUnit())
3572 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
3573 unitCaster->ClearUnitState(UNIT_STATE_CASTING);
3574 }
3575 else
3576 {
3577 // Immediate spell, no big deal
3579 }
3580
3582
3583 if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id))
3584 {
3585 for (int32 id : *spell_triggered)
3586 {
3587 if (id < 0)
3588 {
3589 if (Unit* unitCaster = m_caster->ToUnit())
3590 unitCaster->RemoveAurasDueToSpell(-id);
3591 }
3592 else
3594 }
3595 }
3596
3597 if (modOwner)
3598 {
3599 modOwner->SetSpellModTakingSpell(this, false);
3600
3601 //Clear spell cooldowns after every spell is cast if .cheat cooldown is enabled.
3604 }
3605
3606 SetExecutedCurrently(false);
3607
3608 if (!m_originalCaster)
3609 return;
3610
3611 // Handle procs on cast
3612 uint32 procAttacker = m_procAttacker;
3613 if (!procAttacker)
3614 {
3617 else
3619 }
3620
3621 uint32 hitMask = m_hitMask;
3622 if (!(hitMask & PROC_HIT_CRITICAL))
3623 hitMask |= PROC_HIT_NORMAL;
3624
3625 Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr);
3626
3627 // Call CreatureAI hook OnSpellCast
3628 if (Creature* caster = m_originalCaster->ToCreature())
3629 if (caster->IsAIEnabled())
3630 caster->AI()->OnSpellCast(GetSpellInfo());
3631}
3632
3633template <class Container>
3635{
3636 for (TargetInfoBase& target : targetContainer)
3637 target.PreprocessTarget(this);
3638
3639 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3640 for (TargetInfoBase& target : targetContainer)
3641 if (target.EffectMask & (1 << spellEffectInfo.EffectIndex))
3642 target.DoTargetSpellHit(this, spellEffectInfo);
3643
3644 for (TargetInfoBase& target : targetContainer)
3645 target.DoDamageAndTriggers(this);
3646}
3647
3649{
3650 // start channeling if applicable
3651 if (m_spellInfo->IsChanneled())
3652 {
3653 int32 duration = m_spellInfo->GetDuration();
3654 if (duration > 0)
3655 {
3656 // First mod_duration then haste - see Missile Barrage
3657 // Apply duration mod
3658 if (Player* modOwner = m_caster->GetSpellModOwner())
3659 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_DURATION, duration);
3660
3661 // Apply haste mods
3662 m_caster->ModSpellDurationTime(m_spellInfo, duration, this);
3663
3664 m_channeledDuration = duration;
3665 SendChannelStart(duration);
3666 }
3667 else if (duration == -1)
3668 SendChannelStart(duration);
3669
3670 if (duration != 0)
3671 {
3673 // GameObjects shouldn't cast channeled spells
3675 }
3676 }
3677
3679
3680 // process immediate effects (items, ground, etc.) also initialize some variables
3682
3683 // consider spell hit for some spells without target, so they may proc on finish phase correctly
3684 if (m_UniqueTargetInfo.empty())
3686 else
3688
3690
3692
3694
3695 // spell is finished, perform some last features of the spell here
3697
3698 // Remove used for cast item if need (it can be already NULL after TakeReagents call
3699 TakeCastItem();
3700
3701 // handle ammo consumption for Hunter's volley spell
3703 TakeAmmo();
3704
3706 finish(true); // successfully finish spell cast (not last in case autorepeat or channel spell)
3707}
3708
3710{
3711 if (!UpdatePointers())
3712 {
3713 // finish the spell if UpdatePointers() returned false, something wrong happened there
3714 finish(false);
3715 return 0;
3716 }
3717
3718 Player* modOwner = m_caster->GetSpellModOwner();
3719 if (modOwner)
3720 modOwner->SetSpellModTakingSpell(this, true);
3721
3722 uint64 next_time = 0;
3723
3725
3726 if (!m_immediateHandled)
3727 {
3729 m_immediateHandled = true;
3730 }
3731
3732 bool single_missile = (m_targets.HasDst());
3733
3734 // 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)
3735 {
3736 std::vector<TargetInfo> delayedTargets;
3737 m_UniqueTargetInfo.erase(std::remove_if(m_UniqueTargetInfo.begin(), m_UniqueTargetInfo.end(), [&](TargetInfo& target) -> bool
3738 {
3739 if (single_missile || target.TimeDelay <= t_offset)
3740 {
3741 target.TimeDelay = t_offset;
3742 delayedTargets.emplace_back(std::move(target));
3743 return true;
3744 }
3745 else if (next_time == 0 || target.TimeDelay < next_time)
3746 next_time = target.TimeDelay;
3747
3748 return false;
3749 }), m_UniqueTargetInfo.end());
3750
3751 DoProcessTargetContainer(delayedTargets);
3752 }
3753
3754 // now recheck gameobject targeting correctness
3755 {
3756 std::vector<GOTargetInfo> delayedGOTargets;
3757 m_UniqueGOTargetInfo.erase(std::remove_if(m_UniqueGOTargetInfo.begin(), m_UniqueGOTargetInfo.end(), [&](GOTargetInfo& goTarget) -> bool
3758 {
3759 if (single_missile || goTarget.TimeDelay <= t_offset)
3760 {
3761 goTarget.TimeDelay = t_offset;
3762 delayedGOTargets.emplace_back(std::move(goTarget));
3763 return true;
3764 }
3765 else if (next_time == 0 || goTarget.TimeDelay < next_time)
3766 next_time = goTarget.TimeDelay;
3767
3768 return false;
3769 }), m_UniqueGOTargetInfo.end());
3770
3771 DoProcessTargetContainer(delayedGOTargets);
3772 }
3773
3775
3776 if (modOwner)
3777 modOwner->SetSpellModTakingSpell(this, false);
3778
3779 // All targets passed - need finish phase
3780 if (next_time == 0)
3781 {
3782 // spell is finished, perform some last features of the spell here
3784
3785 finish(true); // successfully finish spell cast
3786
3787 // return zero, spell is finished now
3788 return 0;
3789 }
3790 else
3791 {
3792 // spell is unfinished, return next execution time
3793 return next_time;
3794 }
3795}
3796
3798{
3799 // handle some immediate features of the spell here
3801
3802 // handle effects with SPELL_EFFECT_HANDLE_HIT mode
3803 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
3804 {
3805 // don't do anything for empty effect
3806 if (!spellEffectInfo.IsEffect())
3807 continue;
3808
3809 // call effect handlers to handle destination hit
3810 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_HIT);
3811 }
3812
3813 // process items
3815}
3816
3818{
3819 if (Unit* unitCaster = m_caster->ToUnit())
3820 {
3821 // Take for real after all targets are processed
3823 unitCaster->ClearComboPoints();
3824
3825 // Real add combo points from effects
3827 {
3828 // remove Premed-like effects unless they were caused by ourselves
3829 // (this Aura removes the already-added CP when it expires from duration - now that we've added CP, this shouldn't happen anymore!)
3831 unitCaster->RemoveAurasByType(SPELL_AURA_RETAIN_COMBO_POINTS);
3832 unitCaster->AddComboPoints(m_comboTarget, m_comboPointGain);
3833 }
3834
3836 unitCaster->SetLastExtraAttackSpell(m_spellInfo->Id);
3837 }
3838
3839 // Handle procs on finish
3840 if (!m_originalCaster)
3841 return;
3842
3843 uint32 procAttacker = m_procAttacker;
3844 if (!procAttacker)
3845 {
3848 else
3850 }
3851
3853}
3854
3862
3863void Spell::update(uint32 difftime)
3864{
3865 // update pointers based at it's GUIDs
3866 if (!UpdatePointers())
3867 {
3868 // cancel the spell if UpdatePointers() returned false, something wrong happened there
3869 cancel();
3870 return;
3871 }
3872
3874 {
3875 TC_LOG_DEBUG("spells", "Spell {} is cancelled due to removal of target.", m_spellInfo->Id);
3876 cancel();
3877 return;
3878 }
3879
3880 // check if the unit caster has moved before the spell finished
3881 if (m_timer != 0 && m_caster->IsUnit() && m_caster->ToUnit()->isMoving() && CheckMovement() != SPELL_CAST_OK)
3882 cancel();
3883
3884 switch (m_spellState)
3885 {
3887 {
3888 if (m_timer > 0)
3889 {
3890 if (difftime >= (uint32)m_timer)
3891 m_timer = 0;
3892 else
3893 m_timer -= difftime;
3894 }
3895
3897 // don't CheckCast for instant spells - done in spell::prepare, skip duplicate checks, needed for range checks for example
3898 cast(!m_casttime);
3899 break;
3900 }
3902 {
3903 if (m_timer)
3904 {
3905 // check if there are alive targets left
3907 {
3908 TC_LOG_DEBUG("spells", "Channeled spell {} is removed due to lack of targets", m_spellInfo->Id);
3909 m_timer = 0;
3910
3911 // Also remove applied auras
3912 for (TargetInfo const& target : m_UniqueTargetInfo)
3913 if (Unit* unit = m_caster->GetGUID() == target.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, target.TargetGUID))
3914 unit->RemoveOwnedAura(m_spellInfo->Id, m_originalCasterGUID, 0, AURA_REMOVE_BY_CANCEL);
3915 }
3916
3917 if (m_timer > 0)
3918 {
3919 if (difftime >= (uint32)m_timer)
3920 m_timer = 0;
3921 else
3922 m_timer -= difftime;
3923 }
3924 }
3925
3926 if (m_timer == 0)
3927 {
3929 finish();
3930
3931 // 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
3932 if (Creature* creatureCaster = m_caster->ToCreature())
3933 if (creatureCaster->IsAIEnabled())
3934 creatureCaster->AI()->OnChannelFinished(m_spellInfo);
3935 }
3936 break;
3937 }
3938 default:
3939 break;
3940 }
3941}
3942
3943void Spell::finish(bool ok)
3944{
3946 return;
3948
3949 if (!m_caster)
3950 return;
3951
3952 Unit* unitCaster = m_caster->ToUnit();
3953 if (!unitCaster)
3954 return;
3955
3956 if (m_spellInfo->IsChanneled())
3957 unitCaster->UpdateInterruptMask();
3958
3959 if (unitCaster->HasUnitState(UNIT_STATE_CASTING) && !unitCaster->IsNonMeleeSpellCast(false, false, true))
3961
3962 // Unsummon summon as possessed creatures on spell cancel
3963 if (m_spellInfo->IsChanneled() && unitCaster->GetTypeId() == TYPEID_PLAYER)
3964 {
3965 if (Unit* charm = unitCaster->GetCharmed())
3966 if (charm->GetTypeId() == TYPEID_UNIT
3967 && charm->ToCreature()->HasUnitTypeMask(UNIT_MASK_PUPPET)
3968 && charm->GetUInt32Value(UNIT_CREATED_BY_SPELL) == m_spellInfo->Id)
3969 ((Puppet*)charm)->UnSummon();
3970 }
3971
3972 if (Creature* creatureCaster = unitCaster->ToCreature())
3973 creatureCaster->ReleaseSpellFocus(this);
3974
3975 if (!ok)
3976 return;
3977
3978 if (unitCaster->GetTypeId() == TYPEID_UNIT && unitCaster->IsSummon())
3979 {
3980 // Unsummon statue
3981 uint32 spell = unitCaster->GetUInt32Value(UNIT_CREATED_BY_SPELL);
3982 SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(spell);
3983 if (spellInfo && spellInfo->SpellIconID == 2056)
3984 {
3985 TC_LOG_DEBUG("spells", "Statue {} is unsummoned in spell {} finish", unitCaster->GetGUID().ToString(), m_spellInfo->Id);
3986 // Avoid infinite loops with setDeathState(JUST_DIED) being called over and over
3987 // It might make sense to do this check in Unit::setDeathState() and all overloaded functions
3988 if (unitCaster->getDeathState() != JUST_DIED)
3989 unitCaster->setDeathState(JUST_DIED);
3990 return;
3991 }
3992 }
3993
3995 {
3996 bool found = false;
3998 for (Unit::AuraEffectList::const_iterator i = vIgnoreReset.begin(); i != vIgnoreReset.end(); ++i)
3999 {
4000 if ((*i)->IsAffectingSpell(m_spellInfo))
4001 {
4002 found = true;
4003 break;
4004 }
4005 }
4006
4008 {
4009 unitCaster->resetAttackTimer(BASE_ATTACK);
4010 if (unitCaster->haveOffhandWeapon())
4011 unitCaster->resetAttackTimer(OFF_ATTACK);
4012 unitCaster->resetAttackTimer(RANGED_ATTACK);
4013 }
4014 }
4015
4016 // potions disabled by client, send event "not in combat" if need
4017 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4018 {
4020 unitCaster->ToPlayer()->UpdatePotionCooldown(this);
4021 }
4022
4023 // Stop Attack for some spells
4025 unitCaster->AttackStop();
4026}
4027
4028template<class T>
4029inline void FillSpellCastFailedArgs(T& packet, uint8 castId, SpellInfo const* spellInfo, SpellCastResult result, SpellCustomErrors customError, uint32* param1, uint32* param2)
4030{
4031 packet.CastID = castId;
4032 packet.SpellID = spellInfo->Id;
4033 packet.Reason = result;
4034
4035 switch (result)
4036 {
4038 if (param1)
4039 packet.FailedArg1 = *param1;
4040 else
4041 packet.FailedArg1 = spellInfo->RequiresSpellFocus; // SpellFocusObject.dbc id
4042 break;
4043 case SPELL_FAILED_REQUIRES_AREA: // AreaTable.dbc id
4044 if (param1)
4045 packet.FailedArg1 = *param1;
4046 else
4047 {
4048 // hardcode areas limitation case
4049 switch (spellInfo->Id)
4050 {
4051 case 41617: // Cenarion Mana Salve
4052 case 41619: // Cenarion Healing Salve
4053 packet.FailedArg1 = 3905;
4054 break;
4055 case 41618: // Bottled Nethergon Energy
4056 case 41620: // Bottled Nethergon Vapor
4057 packet.FailedArg1 = 3842;
4058 break;
4059 case 45373: // Bloodberry Elixir
4060 packet.FailedArg1 = 4075;
4061 break;
4062 default: // default case (don't must be)
4063 packet.FailedArg1 = 0;
4064 break;
4065 }
4066 }
4067 break;
4069 if (param1)
4070 {
4071 packet.FailedArg1 = *param1;
4072 }
4073 else
4074 {
4075 if (spellInfo->Totem[0])
4076 packet.FailedArg1 = spellInfo->Totem[0];
4077 else if (spellInfo->Totem[1])
4078 packet.FailedArg1 = spellInfo->Totem[1];
4079 }
4080 break;
4082 if (param1)
4083 {
4084 packet.FailedArg1 = *param1;
4085 }
4086 else
4087 {
4088 if (spellInfo->TotemCategory[0])
4089 packet.FailedArg1 = spellInfo->TotemCategory[0];
4090 else if (spellInfo->TotemCategory[1])
4091 packet.FailedArg1 = spellInfo->TotemCategory[1];
4092 }
4093 break;
4097 if (param1 && param2)
4098 {
4099 packet.FailedArg1 = *param1;
4100 packet.FailedArg2 = *param2;
4101 }
4102 else
4103 {
4104 packet.FailedArg1 = spellInfo->EquippedItemClass;
4105 packet.FailedArg2 = spellInfo->EquippedItemSubClassMask;
4106 }
4107 break;
4109 if (param1)
4110 packet.FailedArg1 = *param1; // ItemLimitCategory id
4111 break;
4113 if (param1)
4114 packet.FailedArg1 = *param1;
4115 break;
4117 if (param1)
4118 packet.FailedArg1 = *param1; // weapon subclass id
4119 break;
4121 if (param1 && param2)
4122 {
4123 packet.FailedArg1 = *param1; // Item id
4124 packet.FailedArg2 = *param2; // Item count
4125 }
4126 break;
4128 if (param1 && param2)
4129 {
4130 packet.FailedArg1 = *param1; // SkillLine.dbc id
4131 packet.FailedArg2 = *param2; // required skill value
4132 }
4133 break;
4135 if (param1)
4136 packet.FailedArg1 = *param1; // required fishing skill
4137 break;
4139 packet.FailedArg1 = customError;
4140 break;
4142 if (param1)
4143 packet.FailedArg1 = *param1;
4144 break;
4145 default:
4146 break;
4147 }
4148}
4149
4150void Spell::SendCastResult(Player* caster, SpellInfo const* spellInfo, uint8 castCount, SpellCastResult result, SpellCustomErrors customError /*= SPELL_CUSTOM_ERROR_NONE*/, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
4151{
4152 if (result == SPELL_CAST_OK)
4153 return;
4154
4156 FillSpellCastFailedArgs(castFailed, castCount, spellInfo, result, customError, param1, param2);
4157 caster->SendDirectMessage(castFailed.Write());
4158}
4159
4160void Spell::SendCastResult(SpellCastResult result, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
4161{
4162 if (result == SPELL_CAST_OK)
4163 return;
4164
4166 return;
4167
4168 if (m_caster->ToPlayer()->IsLoading()) // don't send cast results at loading time
4169 return;
4170
4172 result = SPELL_FAILED_DONT_REPORT;
4173
4175}
4176
4178{
4179 if (result == SPELL_CAST_OK)
4180 return;
4181
4182 Unit* owner = m_caster->GetCharmerOrOwner();
4183 if (!owner)
4184 return;
4185
4186 Player* player = owner->ToPlayer();
4187 if (!player)
4188 return;
4189
4191 result = SPELL_FAILED_DONT_REPORT;
4192
4194 FillSpellCastFailedArgs(petCastFailed, m_cast_count, m_spellInfo, result, m_customError, nullptr, nullptr);
4195 player->SendDirectMessage(petCastFailed.Write());
4196}
4197
4199{
4200 if (result == MountResult::Ok)
4201 return;
4202
4204 return;
4205
4206 Player* caster = m_caster->ToPlayer();
4207 if (caster->IsLoading()) // don't send mount results at loading time
4208 return;
4209
4211 packet.Result = AsUnderlyingType(result);
4212 caster->SendDirectMessage(packet.Write());
4213}
4214
4216{
4217 if (!IsNeedSendToClient())
4218 return;
4219
4220 //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_START id={}", m_spellInfo->Id);
4221
4222 uint32 castFlags = CAST_FLAG_HAS_TRAJECTORY;
4223 uint32 schoolImmunityMask = 0;
4224 uint32 mechanicImmunityMask = 0;
4225 if (Unit* unitCaster = m_caster->ToUnit())
4226 {
4227 schoolImmunityMask = m_timer!= 0 ? unitCaster->GetSchoolImmunityMask() : 0;
4228 mechanicImmunityMask = m_timer != 0 ? m_spellInfo->GetMechanicImmunityMask(unitCaster) : 0;
4229 }
4230
4231 if (schoolImmunityMask || mechanicImmunityMask)
4232 castFlags |= CAST_FLAG_IMMUNITY;
4233
4235 castFlags |= CAST_FLAG_PENDING;
4236
4238 castFlags |= CAST_FLAG_AMMO;
4239 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4242 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4243
4245 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4246
4248 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4249
4250 if (m_CastItem)
4251 castData.CasterGUID = m_CastItem->GetGUID();
4252 else
4253 castData.CasterGUID = m_caster->GetGUID();
4254
4255 castData.CasterUnit = m_caster->GetGUID();
4256 castData.CastID = m_cast_count;
4257 castData.SpellID = m_spellInfo->Id;
4258 castData.CastFlags = castFlags;
4259 castData.CastTime = m_timer;
4260
4261 m_targets.Write(castData.Target);
4262
4263 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4265
4266 if (castFlags & CAST_FLAG_AMMO)
4267 {
4268 castData.Ammo.emplace();
4269 UpdateSpellCastDataAmmo(*castData.Ammo);
4270 }
4271
4272 if (castFlags & CAST_FLAG_IMMUNITY)
4273 {
4274 castData.Immunities.emplace();
4275 castData.Immunities->School = schoolImmunityMask;
4276 castData.Immunities->Value = mechanicImmunityMask;
4277 }
4278
4279 m_caster->SendMessageToSet(packet.Write(), true);
4280}
4281
4283{
4284 // not send invisible spell casting
4285 if (!IsNeedSendToClient())
4286 return;
4287
4288 uint32 castFlags = CAST_FLAG_UNKNOWN_9;
4289
4290 // triggered spells with spell visual != 0
4292 castFlags |= CAST_FLAG_PENDING;
4293
4295 castFlags |= CAST_FLAG_AMMO; // arrows/bullets visual
4296
4297 if ((m_caster->GetTypeId() == TYPEID_PLAYER ||
4300 castFlags |= CAST_FLAG_POWER_LEFT_SELF;
4301
4302 if ((m_caster->GetTypeId() == TYPEID_PLAYER)
4307 {
4308 castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it
4309 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4310 }
4311
4313 castFlags |= CAST_FLAG_RUNE_LIST; // rune cooldowns list
4314
4315 if (m_targets.HasTraj())
4316 castFlags |= CAST_FLAG_ADJUST_MISSILE;
4317
4319 castFlags |= CAST_FLAG_NO_GCD;
4320
4322 WorldPackets::Spells::SpellCastData& castData = packet.Cast;
4323
4324 if (m_CastItem)
4325 castData.CasterGUID = m_CastItem->GetGUID();
4326 else
4327 castData.CasterGUID = m_caster->GetGUID();
4328
4329 castData.CasterUnit = m_caster->GetGUID();
4330 castData.CastID = m_cast_count;
4331 castData.SpellID = m_spellInfo->Id;
4332 castData.CastFlags = castFlags;
4333 castData.CastTime = GameTime::GetGameTimeMS();
4334
4336
4337 m_targets.Write(castData.Target);
4338
4339 if (castFlags & CAST_FLAG_POWER_LEFT_SELF)
4341
4342 if (castFlags & CAST_FLAG_RUNE_LIST && !m_spellInfo->HasAura(SPELL_AURA_CONVERT_RUNE)) // rune cooldowns list
4343 {
4344 castData.RemainingRunes.emplace();
4345
4347 // The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster
4348 if (Player* player = m_caster->ToPlayer())
4349 {
4350 uint8 runeMaskInitial = m_runesState;
4351 uint8 runeMaskAfterCast = player->GetRunesState();
4352 castData.RemainingRunes->Start = runeMaskInitial; // runes state before
4353 castData.RemainingRunes->Count = runeMaskAfterCast; // runes state after
4354
4355 for (uint8 i = 0; i < MAX_RUNES; ++i)
4356 {
4357 uint8 mask = (1 << i);
4358 if ((mask & runeMaskInitial) && !(mask & runeMaskAfterCast)) // usable before and on cooldown now...
4359 {
4360 // float casts ensure the division is performed on floats as we need float result
4361 float baseCd = float(player->GetRuneBaseCooldown(i));
4362 castData.RemainingRunes->Cooldowns.push_back(uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255));
4363 }
4364 }
4365 }
4366 }
4367
4368 if (castFlags & CAST_FLAG_ADJUST_MISSILE)
4369 {
4370 castData.MissileTrajectory.emplace();
4371 castData.MissileTrajectory->Pitch = m_targets.GetPitch();
4372 castData.MissileTrajectory->TravelTime = m_delayMoment;
4373 }
4374
4375 if (castFlags & CAST_FLAG_AMMO)
4376 UpdateSpellCastDataAmmo(castData.Ammo.emplace());
4377
4379 castData.DestLocSpellCastIndex.emplace();
4380
4382 castData.TargetPoints.emplace();
4383
4384 // should be sent to self only
4385 if (castFlags & CAST_FLAG_POWER_LEFT_SELF && m_caster->IsPlayer())
4386 {
4388
4389 packet.Clear();
4390
4391 // update nearby players (remove flag)
4392 castData.CastFlags &= ~CAST_FLAG_POWER_LEFT_SELF;
4393 castData.RemainingPower = std::nullopt;
4394 m_caster->SendMessageToSet(packet.Write(), false);
4395 }
4396 else
4397 m_caster->SendMessageToSet(packet.Write(), true);
4398}
4399
4401{
4402 uint32 ammoInventoryType = 0;
4403 uint32 ammoDisplayID = 0;
4404
4406 {
4408 if (pItem)
4409 {
4410 ammoInventoryType = pItem->GetTemplate()->GetInventoryType();
4411 if (ammoInventoryType == INVTYPE_THROWN)
4412 ammoDisplayID = pItem->GetTemplate()->GetDisplayId();
4413 else
4414 {
4416 if (ammoID)
4417 {
4418 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(ammoID);
4419 if (pProto)
4420 {
4421 ammoDisplayID = pProto->GetDisplayId();
4422 ammoInventoryType = pProto->GetInventoryType();
4423 }
4424 }
4425 else if (m_caster->ToPlayer()->HasAura(46699)) // Requires No Ammo
4426 {
4427 ammoDisplayID = 5996; // normal arrow
4428 ammoInventoryType = INVTYPE_AMMO;
4429 }
4430 }
4431 }
4432 }
4433 else if (Unit const* unitCaster = m_caster->ToUnit())
4434 {
4435 uint32 nonRangedAmmoDisplayID = 0;
4436 uint32 nonRangedAmmoInventoryType = 0;
4437 for (uint8 i = BASE_ATTACK; i < MAX_ATTACK; ++i)
4438 {
4439 if (uint32 item_id = unitCaster->GetVirtualItemId(i))
4440 {
4441 if (ItemEntry const* itemEntry = sItemStore.LookupEntry(item_id))
4442 {
4443 if (itemEntry->ClassID == ITEM_CLASS_WEAPON)
4444 {
4445 switch (itemEntry->SubclassID)
4446 {
4448 ammoDisplayID = itemEntry->DisplayInfoID;
4449 ammoInventoryType = itemEntry->InventoryType;
4450 break;
4453 ammoDisplayID = 5996; // is this need fixing?
4454 ammoInventoryType = INVTYPE_AMMO;
4455 break;
4457 ammoDisplayID = 5998; // is this need fixing?
4458 ammoInventoryType = INVTYPE_AMMO;
4459 break;
4460 default:
4461 nonRangedAmmoDisplayID = itemEntry->DisplayInfoID;
4462 nonRangedAmmoInventoryType = itemEntry->InventoryType;
4463 break;
4464 }
4465
4466 if (ammoDisplayID)
4467 break;
4468 }
4469 }
4470 }
4471 }
4472
4473 if (!ammoDisplayID && !ammoInventoryType)
4474 {
4475 ammoDisplayID = nonRangedAmmoDisplayID;
4476 ammoInventoryType = nonRangedAmmoInventoryType;
4477 }
4478 }
4479
4480 ammo.DisplayID = ammoDisplayID;
4481 ammo.InventoryType = ammoInventoryType;
4482}
4483
4486{
4487 // This function also fill data for channeled spells:
4488 // m_needAliveTargetMask req for stop channelig if one target die
4489 for (TargetInfo& targetInfo : m_UniqueTargetInfo)
4490 {
4491 if (targetInfo.EffectMask == 0) // No effect apply - all immuned add state
4492 // possibly SPELL_MISS_IMMUNE2 for this??
4493 targetInfo.MissCondition = SPELL_MISS_IMMUNE2;
4494
4495 if (targetInfo.MissCondition == SPELL_MISS_NONE || (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))) // Add only hits and partial blocked
4496 {
4497 data.HitTargets->push_back(targetInfo.TargetGUID);
4498
4499 m_channelTargetEffectMask |= targetInfo.EffectMask;
4500 }
4501 else // misses
4502 {
4503 // Only send blocks in spell_go packets if we know that the spell is not going to do anything to the target.
4504 // Spells that are partially blocked will send their block result in their according combat log packet.
4505 if (targetInfo.MissCondition == SPELL_MISS_BLOCK && !m_spellInfo->HasAttribute(SPELL_ATTR3_COMPLETELY_BLOCKED))
4506 continue;
4507
4509 missStatus.TargetGUID = targetInfo.TargetGUID;
4510 missStatus.Reason = targetInfo.MissCondition;
4511 if (targetInfo.MissCondition == SPELL_MISS_REFLECT)
4512 missStatus.ReflectStatus = targetInfo.ReflectResult;
4513
4514 data.MissStatus->push_back(missStatus);
4515 }
4516 }
4517
4518 for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo)
4519 data.HitTargets->push_back(targetInfo.TargetGUID); // Always hits
4520
4521 for (CorpseTargetInfo const& targetInfo : m_UniqueCorpseTargetInfo)
4522 data.HitTargets->push_back(targetInfo.TargetGUID); // Always hits
4523
4524 // Reset m_needAliveTargetMask for non channeled spell
4525 if (!m_spellInfo->IsChanneled())
4527}
4528
4530{
4531 WorldPacket data(SMSG_SPELLLOGEXECUTE, (8+4+4+4+4+8));
4532
4533 data << m_caster->GetPackGUID();
4534
4535 data << uint32(m_spellInfo->Id);
4536
4537 uint8 effCount = 0;
4538 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
4539 {
4540 if (m_effectExecuteData[i])
4541 ++effCount;
4542 }
4543
4544 if (!effCount)
4545 return;
4546
4547 data << uint32(effCount);
4548 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
4549 {
4550 if (!m_effectExecuteData[spellEffectInfo.EffectIndex])
4551 continue;
4552
4553 data << uint32(spellEffectInfo.Effect); // spell effect
4554
4555 data.append(*m_effectExecuteData[spellEffectInfo.EffectIndex]);
4556
4557 delete m_effectExecuteData[spellEffectInfo.EffectIndex];
4558 m_effectExecuteData[spellEffectInfo.EffectIndex] = nullptr;
4559 }
4560 m_caster->SendMessageToSet(&data, true);
4561}
4562
4563void Spell::ExecuteLogEffectTakeTargetPower(uint8 effIndex, Unit* target, uint32 powerType, uint32 powerTaken, float gainMultiplier)
4564{
4565 InitEffectExecuteData(effIndex);
4566 *m_effectExecuteData[effIndex] << target->GetPackGUID();
4567 *m_effectExecuteData[effIndex] << uint32(powerTaken);
4568 *m_effectExecuteData[effIndex] << uint32(powerType);
4569 *m_effectExecuteData[effIndex] << float(gainMultiplier);
4570}
4571
4572void Spell::ExecuteLogEffectExtraAttacks(uint8 effIndex, Unit* victim, uint32 attCount)
4573{
4574 InitEffectExecuteData(effIndex);
4575 *m_effectExecuteData[effIndex] << victim->GetPackGUID();
4576 *m_effectExecuteData[effIndex] << uint32(attCount);
4577}
4578
4580{
4581 InitEffectExecuteData(effIndex);
4582 *m_effectExecuteData[effIndex] << victim->GetPackGUID();
4583 *m_effectExecuteData[effIndex] << uint32(spellId);
4584}
4585
4586void Spell::ExecuteLogEffectDurabilityDamage(uint8 effIndex, Unit* victim, int32 itemId, int32 slot)
4587{
4588 InitEffectExecuteData(effIndex);
4589 *m_effectExecuteData[effIndex] << victim->GetPackGUID();
4590 *m_effectExecuteData[effIndex] << int32(itemId);
4591 *m_effectExecuteData[effIndex] << int32(slot);
4592}
4593
4595{
4596 InitEffectExecuteData(effIndex);
4597 *m_effectExecuteData[effIndex] << obj->GetPackGUID();
4598}
4599
4601{
4602 InitEffectExecuteData(effIndex);
4603 *m_effectExecuteData[effIndex] << uint32(entry);
4604}
4605
4607{
4608 InitEffectExecuteData(effIndex);
4609 *m_effectExecuteData[effIndex] << uint32(entry);
4610}
4611
4613{
4614 InitEffectExecuteData(effIndex);
4615 *m_effectExecuteData[effIndex] << obj->GetPackGUID();
4616}
4617
4619{
4620 InitEffectExecuteData(effIndex);
4621 *m_effectExecuteData[effIndex] << obj->GetPackGUID();
4622}
4623
4625{
4626 InitEffectExecuteData(effIndex);
4627 *m_effectExecuteData[effIndex] << target->GetPackGUID();
4628}
4629
4631{
4633 failurePacket.CasterUnit = m_caster->GetGUID();
4634 failurePacket.CastID = m_cast_count;
4635 failurePacket.SpellID = m_spellInfo->Id;
4636 failurePacket.Reason = result;
4637 m_caster->SendMessageToSet(failurePacket.Write(), true);
4638
4640 failedPacket.CasterUnit = m_caster->GetGUID();
4641 failedPacket.SpellID = m_spellInfo->Id;
4642 failedPacket.Reason = resultOther.value_or(result);
4643 m_caster->SendMessageToSet(failedPacket.Write(), true);
4644}
4645
4647{
4648 // GameObjects don't channel
4649 Unit* unitCaster = m_caster->ToUnit();
4650 if (!unitCaster)
4651 return;
4652
4653 if (time == 0)
4654 {
4656 unitCaster->SetChannelSpellId(0);
4657 }
4658
4660 data << unitCaster->GetPackGUID();
4661 data << uint32(time);
4662
4663 unitCaster->SendMessageToSet(&data, true);
4664}
4665
4667{
4668 // GameObjects don't channel
4669 Unit* unitCaster = m_caster->ToUnit();
4670 if (!unitCaster)
4671 return;
4672
4673 ObjectGuid channelTarget = m_targets.HasDst() ? unitCaster->GetGUID() : m_targets.GetObjectTargetGUID();
4674 if (!channelTarget && !m_spellInfo->NeedsExplicitUnitTarget())
4675 if (m_UniqueTargetInfo.size() + m_UniqueGOTargetInfo.size() == 1) // this is for TARGET_SELECT_CATEGORY_NEARBY
4676 channelTarget = !m_UniqueTargetInfo.empty() ? m_UniqueTargetInfo.front().TargetGUID : m_UniqueGOTargetInfo.front().TargetGUID;
4677
4678 WorldPacket data(MSG_CHANNEL_START, (8+4+4));
4679 data << unitCaster->GetPackGUID();
4680 data << uint32(m_spellInfo->Id);
4681 data << uint32(duration);
4682
4683 unitCaster->SendMessageToSet(&data, true);
4684
4685 m_timer = duration;
4686 if (!channelTarget.IsEmpty())
4687 {
4688 unitCaster->SetChannelObjectGuid(channelTarget);
4689
4690 if (Creature* creatureCaster = m_caster->ToCreature())
4691 if (!creatureCaster->HasSpellFocus(this))
4692 creatureCaster->SetSpellFocus(this, ObjectAccessor::GetWorldObject(*creatureCaster, channelTarget));
4693 }
4694
4695 unitCaster->SetChannelSpellId(m_spellInfo->Id);
4696}
4697
4699{
4700 // get resurrector name for creature resurrections, otherwise packet will be not accepted
4701 // for player resurrections the name is looked up by guid
4702 std::string sentName;
4705
4706 WorldPacket data(SMSG_RESURRECT_REQUEST, 8 + 4 + sentName.size() + 1 + 1 + 1);
4707 data << m_caster->GetGUID();
4708 data << uint32(sentName.size() + 1);
4709 data << sentName;
4710 data << uint8(m_caster->GetTypeId() == TYPEID_UNIT && m_caster->ToCreature()->IsSpiritHealer()); // "you'll be afflicted with resurrection sickness"
4711 // override delay sent with SMSG_CORPSE_RECLAIM_DELAY, set instant resurrection for spells with this attribute
4713 target->SendDirectMessage(&data);
4714}
4715
4717{
4718 if (!m_CastItem)
4719 return;
4720
4721 Player* player = m_caster->ToPlayer();
4722 if (!player)
4723 return;
4724
4725 // not remove cast item at triggered spell (equipping, weapon damage, etc)
4727 return;
4728
4729 ItemTemplate const* proto = m_CastItem->GetTemplate();
4730
4731 if (!proto)
4732 {
4733 // This code is to avoid a crash
4734 // I'm not sure, if this is really an error, but I guess every item needs a prototype
4735 TC_LOG_ERROR("spells", "Cast item has no item prototype {}", m_CastItem->GetGUID().ToString());
4736 return;
4737 }
4738
4739 bool expendable = false;
4740 bool withoutCharges = false;
4741
4742 for (uint32 i = 0; i < proto->Effects.size(); ++i)
4743 {
4744 ItemEffect const& itemEffect = proto->Effects[i];
4745 if (itemEffect.TriggerType == ITEM_SPELLTRIGGER_ON_USE && itemEffect.SpellID > 0)
4746 {
4747 // item has limited charges
4748 if (itemEffect.Charges)
4749 {
4750 if (itemEffect.Charges < 0)
4751 expendable = true;
4752
4753 int32 charges = m_CastItem->GetSpellCharges(i);
4754
4755 // item has charges left for this slot
4756 if (charges && itemEffect.SpellID == int32(m_spellInfo->Id))
4757 {
4758 (charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
4759 if (proto->GetMaxStackSize() == 1)
4760 m_CastItem->SetSpellCharges(i, charges);
4762 }
4763
4764 // all charges used
4765 withoutCharges = (charges == 0);
4766 }
4767 }
4768 }
4769
4770 if (expendable && withoutCharges)
4771 {
4772 uint32 count = 1;
4773 m_caster->ToPlayer()->DestroyItemCount(m_CastItem, count, true);
4774
4775 // prevent crash at access to deleted m_targets.GetItemTarget
4777 m_targets.SetItemTarget(nullptr);
4778
4779 m_CastItem = nullptr;
4781 m_castItemEntry = 0;
4782 }
4783}
4784
4786{
4787 // GameObjects don't use power
4788 Unit* unitCaster = m_caster->ToUnit();
4789 if (!unitCaster)
4790 return;
4791
4793 return;
4794
4795 //Don't take power if the spell is cast while .cheat power is enabled.
4796 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4797 {
4798 if (unitCaster->ToPlayer()->GetCommandStatus(CHEAT_POWER))
4799 return;
4800 }
4801
4802 Powers powerType = Powers(m_spellInfo->PowerType);
4803 bool hit = true;
4804 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
4805 {
4806 if (powerType == POWER_RAGE || powerType == POWER_ENERGY || powerType == POWER_RUNE)
4807 {
4808 ObjectGuid targetGUID = m_targets.GetUnitTargetGUID();
4809 if (!targetGUID.IsEmpty())
4810 {
4811 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; });
4812 if (ihit != std::end(m_UniqueTargetInfo))
4813 {
4814 hit = false;
4815 //lower spell cost on fail (by talent aura)
4816 if (Player* modOwner = unitCaster->ToPlayer()->GetSpellModOwner())
4818 }
4819 }
4820 }
4821 }
4822
4823 if (powerType == POWER_RUNE)
4824 {
4825 TakeRunePower(hit);
4826 return;
4827 }
4828
4829 if (!m_powerCost)
4830 return;
4831
4832 // health as power used
4833 if (powerType == POWER_HEALTH)
4834 {
4835 unitCaster->ModifyHealth(-(int32)m_powerCost);
4836 return;
4837 }
4838
4839 if (powerType >= MAX_POWERS)
4840 {
4841 TC_LOG_ERROR("spells", "Spell::TakePower: Unknown power type '{}'", powerType);
4842 return;
4843 }
4844
4845 unitCaster->ModifyPower(powerType, -m_powerCost);
4846
4847 // Set the five second timer
4848 if (powerType == POWER_MANA && m_powerCost > 0)
4850}
4851
4853{
4854 // Only players use ammo
4855 Player* player = m_caster->ToPlayer();
4856 if (!player)
4857 return;
4858
4859 // only ranged
4861 return;
4862
4863 // wands don't have ammo
4864 Item* item = player->GetWeaponForAttack(RANGED_ATTACK);
4865 if (!item || item->IsBroken() || item->GetTemplate()->GetSubClass() == ITEM_SUBCLASS_WEAPON_WAND)
4866 return;
4867
4869 {
4870 if (item->GetMaxStackCount() == 1)
4871 {
4872 // decrease durability for non-stackable throw weapon
4874 }
4875 else
4876 {
4877 // decrease items amount for stackable throw weapon
4878 uint32 count = 1;
4879 player->DestroyItemCount(item, count, true);
4880 }
4881 }
4882 else if (uint32 ammo = player->GetUInt32Value(PLAYER_AMMO_ID))
4883 player->DestroyItemCount(ammo, 1, true);
4884}
4885
4887{
4888 if (m_spellInfo->PowerType != POWER_RUNE || !runeCostID)
4889 return SPELL_CAST_OK;
4890
4891 Player* player = m_caster->ToPlayer();
4892 if (!player)
4893 return SPELL_CAST_OK;
4894
4895 if (player->GetClass() != CLASS_DEATH_KNIGHT)
4896 return SPELL_CAST_OK;
4897
4898 SpellRuneCostEntry const* src = sSpellRuneCostStore.LookupEntry(runeCostID);
4899 if (!src)
4900 return SPELL_CAST_OK;
4901
4902 if (src->NoRuneCost())
4903 return SPELL_CAST_OK;
4904
4905 int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
4906
4907 for (uint32 i = 0; i < RUNE_DEATH; ++i)
4908 {
4909 runeCost[i] = src->RuneCost[i];
4910 if (Player* modOwner = m_caster->GetSpellModOwner())
4911 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], const_cast<Spell*>(this));
4912 }
4913
4914 runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later
4915
4916 for (uint32 i = 0; i < MAX_RUNES; ++i)
4917 {
4918 RuneType rune = player->GetCurrentRune(i);
4919 if ((player->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0))
4920 runeCost[rune]--;
4921 }
4922
4923 for (uint32 i = 0; i < RUNE_DEATH; ++i)
4924 if (runeCost[i] > 0)
4925 runeCost[RUNE_DEATH] += runeCost[i];
4926
4927 if (runeCost[RUNE_DEATH] > MAX_RUNES)
4928 return SPELL_FAILED_NO_POWER; // not sure if result code is correct
4929
4930 return SPELL_CAST_OK;
4931}
4932
4933void Spell::TakeRunePower(bool didHit)
4934{
4936 return;
4937
4938 SpellRuneCostEntry const* runeCostData = sSpellRuneCostStore.LookupEntry(m_spellInfo->RuneCostID);
4939 if (!runeCostData || (runeCostData->NoRuneCost() && runeCostData->NoRunicPowerGain()))
4940 return;
4941
4942 Player* player = m_caster->ToPlayer();
4943 m_runesState = player->GetRunesState(); // store previous state
4944
4945 int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death
4946
4947 for (uint32 i = 0; i < RUNE_DEATH; ++i)
4948 {
4949 runeCost[i] = runeCostData->RuneCost[i];
4950 if (Player* modOwner = m_caster->GetSpellModOwner())
4951 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, runeCost[i], this);
4952 }
4953
4954 // Let's say we use a skill that requires a Frost rune. This is the order:
4955 // - Frost rune
4956 // - Death rune, originally a Frost rune
4957 // - Death rune, any kind
4958 runeCost[RUNE_DEATH] = 0; // calculated later
4959 for (uint32 i = 0; i < MAX_RUNES; ++i)
4960 {
4961 RuneType rune = player->GetCurrentRune(i);
4962 if (!player->GetRuneCooldown(i) && runeCost[rune] > 0)
4963 {
4964 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown(i) : uint32(RUNE_MISS_COOLDOWN), true);
4965 player->SetLastUsedRune(rune);
4966 runeCost[rune]--;
4967 }
4968 }
4969
4970 // Find a Death rune where the base rune matches the one we need
4971 runeCost[RUNE_DEATH] = runeCost[RUNE_BLOOD] + runeCost[RUNE_UNHOLY] + runeCost[RUNE_FROST];
4972 if (runeCost[RUNE_DEATH] > 0)
4973 {
4974 for (uint32 i = 0; i < MAX_RUNES; ++i)
4975 {
4976 RuneType rune = player->GetCurrentRune(i);
4977 RuneType baseRune = player->GetBaseRune(i);
4978 if (!player->GetRuneCooldown(i) && rune == RUNE_DEATH && runeCost[baseRune] > 0)
4979 {
4980 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown(i) : uint32(RUNE_MISS_COOLDOWN), true);
4981 player->SetLastUsedRune(rune);
4982 runeCost[baseRune]--;
4983 runeCost[rune]--;
4984
4985 // keep Death Rune type if missed
4986 if (didHit)
4987 player->RestoreBaseRune(i);
4988
4989 if (runeCost[RUNE_DEATH] == 0)
4990 break;
4991 }
4992 }
4993 }
4994
4995 // Grab any Death rune
4996 if (runeCost[RUNE_DEATH] > 0)
4997 {
4998 for (uint32 i = 0; i < MAX_RUNES; ++i)
4999 {
5000 RuneType rune = player->GetCurrentRune(i);
5001 if (!player->GetRuneCooldown(i) && rune == RUNE_DEATH)
5002 {
5003 player->SetRuneCooldown(i, didHit ? player->GetRuneBaseCooldown(i) : uint32(RUNE_MISS_COOLDOWN), true);
5004 player->SetLastUsedRune(rune);
5005 runeCost[rune]--;
5006
5007 // keep Death Rune type if missed
5008 if (didHit)
5009 player->RestoreBaseRune(i);
5010
5011 if (runeCost[RUNE_DEATH] == 0)
5012 break;
5013 }
5014 }
5015 }
5016
5017 // you can gain some runic power when use runes
5018 if (didHit)
5019 if (int32 rp = int32(runeCostData->RunicPower * sWorld->getRate(RATE_POWER_RUNICPOWER_INCOME)))
5020 player->ModifyPower(POWER_RUNIC_POWER, int32(rp));
5021}
5022
5024{
5026 return;
5027
5028 ItemTemplate const* castItemTemplate = m_CastItem ? m_CastItem->GetTemplate() : nullptr;
5029
5030 // do not take reagents for these item casts
5031 if (castItemTemplate && castItemTemplate->HasFlag(ITEM_FLAG_NO_REAGENT_COST))
5032 return;
5033
5034 Player* p_caster = m_caster->ToPlayer();
5035 if (p_caster->CanNoReagentCast(m_spellInfo))
5036 return;
5037
5038 for (uint32 x = 0; x < MAX_SPELL_REAGENTS; ++x)
5039 {
5040 if (m_spellInfo->Reagent[x] <= 0)
5041 continue;
5042
5043 uint32 itemid = m_spellInfo->Reagent[x];
5044 uint32 itemcount = m_spellInfo->ReagentCount[x];
5045
5046 // if CastItem is also spell reagent
5047 if (castItemTemplate && castItemTemplate->GetId() == itemid)
5048 {
5049 for (uint32 s = 0; s < castItemTemplate->Effects.size(); ++s)
5050 {
5051 // CastItem will be used up and does not count as reagent
5052 int32 charges = ASSERT_NOTNULL(m_CastItem)->GetSpellCharges(s);
5053 if (castItemTemplate->Effects[s].Charges < 0 && abs(charges) < 2)
5054 {
5055 ++itemcount;
5056 break;
5057 }
5058 }
5059
5060 m_CastItem = nullptr;
5062 m_castItemEntry = 0;
5063 }
5064
5065 // if GetItemTarget is also spell reagent
5066 if (m_targets.GetItemTargetEntry() == itemid)
5067 m_targets.SetItemTarget(nullptr);
5068
5069 p_caster->DestroyItemCount(itemid, itemcount, true);
5070 }
5071}
5072
5074{
5075 // wild GameObject spells don't cause threat
5076 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
5077 if (!unitCaster)
5078 return;
5079
5080 if (m_UniqueTargetInfo.empty())
5081 return;
5082
5084 return;
5085
5086 float threat = 0.0f;
5087 if (SpellThreatEntry const* threatEntry = sSpellMgr->GetSpellThreatEntry(m_spellInfo->Id))
5088 {
5089 if (threatEntry->apPctMod != 0.0f)
5090 threat += threatEntry->apPctMod * unitCaster->GetTotalAttackPowerValue(BASE_ATTACK);
5091
5092 threat += threatEntry->flatMod;
5093 }
5095 threat += m_spellInfo->SpellLevel;
5096
5097 // past this point only multiplicative effects occur
5098 if (threat == 0.0f)
5099 return;
5100
5101 // 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
5102 threat /= m_UniqueTargetInfo.size();
5103
5104 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
5105 {
5106 float threatToAdd = threat;
5107 if (ihit->MissCondition != SPELL_MISS_NONE)
5108 threatToAdd = 0.0f;
5109
5110 Unit* target = ObjectAccessor::GetUnit(*unitCaster, ihit->TargetGUID);
5111 if (!target)
5112 continue;
5113
5114 // positive spells distribute threat among all units that are in combat with target, like healing
5115 if (IsPositive())
5116 target->GetThreatManager().ForwardThreatForAssistingMe(unitCaster, threatToAdd, m_spellInfo);
5117 // for negative spells threat gets distributed among affected targets
5118 else
5119 {
5120 if (!target->CanHaveThreatList())
5121 continue;
5122
5123 target->GetThreatManager().AddThreat(unitCaster, threatToAdd, m_spellInfo, true);
5124 }
5125 }
5126 TC_LOG_DEBUG("spells", "Spell {}, added an additional {} threat for {} {} target(s)", m_spellInfo->Id, threat, IsPositive() ? "assisting" : "harming", uint32(m_UniqueTargetInfo.size()));
5127}
5128
5129void Spell::HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode)
5130{
5131 effectHandleMode = mode;
5132 unitTarget = pUnitTarget;
5133 itemTarget = pItemTarget;
5134 gameObjTarget = pGoTarget;
5135 m_corpseTarget = pCorpseTarget;
5136 destTarget = &m_destTargets[spellEffectInfo.EffectIndex]._position;
5137 effectInfo = &spellEffectInfo;
5138
5139 // we do not need ChainAmplitude here.
5140 damage = CalculateDamage(spellEffectInfo);
5141
5142 bool preventDefault = CallScriptEffectHandlers(spellEffectInfo.EffectIndex, mode);
5143
5144 if (!preventDefault)
5145 (this->*SpellEffectHandlers[spellEffectInfo.Effect])();
5146}
5147
5148SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/)
5149{
5150 // check death state
5153
5154 // 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
5156 {
5159 }
5160
5161 // check cooldowns to prevent cheating
5162 if (!m_spellInfo->IsPassive())
5163 {
5165 {
5166 //can cast triggered (by aura only?) spells while have this flag
5169
5170 // check if we are using a potion in combat for the 2nd+ time. Cooldown is added only after caster gets out of combat
5173 }
5174
5176 {
5179
5181 }
5182 }
5183
5185 {
5188 }
5189
5190 // Check global cooldown
5193
5194 // only triggered spells can be processed an ended battleground
5197 if (bg->GetStatus() == STATUS_WAIT_LEAVE)
5199
5201 {
5203 !m_caster->IsOutdoors())
5205
5209 }
5210
5211 if (Unit* unitCaster = m_caster->ToUnit())
5212 {
5213 // only check at first call, Stealth auras are already removed at second call
5214 // for now, ignore triggered spells
5216 {
5217 bool checkForm = true;
5218 // Ignore form req aura
5219 Unit::AuraEffectList const& ignore = unitCaster->GetAuraEffectsByType(SPELL_AURA_MOD_IGNORE_SHAPESHIFT);
5220 for (AuraEffect const* aurEff : ignore)
5221 {
5222 if (!aurEff->IsAffectingSpell(m_spellInfo))
5223 continue;
5224
5225 checkForm = false;
5226 break;
5227 }
5228
5229 if (checkForm)
5230 {
5231 // Cannot be used in this stance/form
5232 SpellCastResult shapeError = m_spellInfo->CheckShapeshift(unitCaster->GetShapeshiftForm());
5233 if (shapeError != SPELL_CAST_OK)
5234 return shapeError;
5235
5236 if (m_spellInfo->HasAttribute(SPELL_ATTR0_ONLY_STEALTHED) && !(unitCaster->HasStealthAura()))
5238 }
5239 }
5240
5241 if (unitCaster->HasAuraTypeWithMiscvalue(SPELL_AURA_BLOCK_SPELL_FAMILY, m_spellInfo->SpellFamilyName))
5243
5244 bool reqCombat = true;
5245 Unit::AuraEffectList const& stateAuras = unitCaster->GetAuraEffectsByType(SPELL_AURA_ABILITY_IGNORE_AURASTATE);
5246 for (Unit::AuraEffectList::const_iterator j = stateAuras.begin(); j != stateAuras.end(); ++j)
5247 {
5248 if ((*j)->IsAffectingSpell(m_spellInfo))
5249 {
5250 m_needComboPoints = false;
5251 if ((*j)->GetMiscValue() == 1)
5252 {
5253 reqCombat = false;
5254 break;
5255 }
5256 }
5257 }
5258
5259 // caster state requirements
5260 // not for triggered spells (needed by execute)
5262 {
5263 if (m_spellInfo->CasterAuraState && !unitCaster->HasAuraState(AuraStateType(m_spellInfo->CasterAuraState), m_spellInfo, unitCaster))
5265 if (m_spellInfo->ExcludeCasterAuraState && unitCaster->HasAuraState(AuraStateType(m_spellInfo->ExcludeCasterAuraState), m_spellInfo, unitCaster))
5267
5268 // Note: spell 62473 requres casterAuraSpell = triggering spell
5269 if (m_spellInfo->CasterAuraSpell && !unitCaster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->CasterAuraSpell, unitCaster)))
5271 if (m_spellInfo->ExcludeCasterAuraSpell && unitCaster->HasAura(sSpellMgr->GetSpellIdForDifficulty(m_spellInfo->ExcludeCasterAuraSpell, unitCaster)))
5273
5274 if (reqCombat && unitCaster->IsInCombat() && !m_spellInfo->CanBeUsedInCombat())
5276 }
5277
5278 // cancel autorepeat spells if cast start when moving
5279 // (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
5280 if (unitCaster->GetTypeId() == TYPEID_PLAYER && unitCaster->ToPlayer()->isMoving() && (!unitCaster->IsCharmed() || !unitCaster->GetCharmerGUID().IsCreature()))
5281 {
5282 // skip stuck spell to allow use it in falling case and apply spell limitations at movement
5283 if ((!unitCaster->HasUnitMovementFlag(MOVEMENTFLAG_FALLING_FAR) || !m_spellInfo->HasEffect(SPELL_EFFECT_STUCK)) &&
5285 return SPELL_FAILED_MOVING;
5286 }
5287
5288 if (unitCaster->IsCharmed() && m_spellInfo->HasAttribute(SPELL_ATTR5_NOT_USABLE_WHILE_CHARMED))
5289 return SPELL_FAILED_CHARMED;
5290
5291 // Check vehicle flags
5293 {
5294 SpellCastResult vehicleCheck = m_spellInfo->CheckVehicle(unitCaster);
5295 if (vehicleCheck != SPELL_CAST_OK)
5296 return vehicleCheck;
5297 }
5298 }
5299
5300 // check spell cast conditions from database
5301 {
5303 if (!sConditionMgr->IsObjectMeetingNotGroupedConditions(CONDITION_SOURCE_TYPE_SPELL, m_spellInfo->Id, condInfo))
5304 {
5305 // mLastFailedCondition can be NULL if there was an error processing the condition in Condition::Meets (i.e. wrong data for ConditionTarget or others)
5306 if (condInfo.mLastFailedCondition && condInfo.mLastFailedCondition->ErrorType)
5307 {
5311 }
5312
5313 if (!condInfo.mLastFailedCondition || !condInfo.mLastFailedCondition->ConditionTarget)
5316 }
5317 }
5318
5319 // Don't check explicit target for passive spells (workaround) (check should be skipped only for learn case)
5320 // those spells may have incorrect target entries or not filled at all (for example 15332)
5321 // such spells when learned are not targeting anyone using targeting system, they should apply directly to caster instead
5322 // also, such casts shouldn't be sent to client
5324 {
5325 // Check explicit target for m_originalCaster - todo: get rid of such workarounds
5326 WorldObject* caster = m_caster;
5327 // in case of gameobjects like traps, we need the gameobject itself to check target validity
5328 // otherwise, if originalCaster is far away and cannot detect the target, the trap would not hit the target
5329 if (m_originalCaster && !caster->ToGameObject())
5330 caster = m_originalCaster;
5331
5333 if (castResult != SPELL_CAST_OK)
5334 return castResult;
5335 }
5336
5337 if (Unit* target = m_targets.GetUnitTarget())
5338 {
5339 SpellCastResult castResult = m_spellInfo->CheckTarget(m_caster, target, m_caster->GetTypeId() == TYPEID_GAMEOBJECT); // skip stealth checks for GO casts
5340 if (castResult != SPELL_CAST_OK)
5341 return castResult;
5342
5343 if (target != m_caster)
5344 {
5345 // Must be behind the target
5346 if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET) && target->HasInArc(static_cast<float>(M_PI), m_caster))
5348
5349 // Target must be facing you
5350 if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
5352
5353 // Ignore LOS for gameobjects casts
5355 {
5356 WorldObject* losTarget = m_caster;
5359 losTarget = dynObj;
5360
5363 }
5364 }
5365 }
5366
5367 // Check for line of sight for spells with dest
5368 if (m_targets.HasDst())
5369 {
5370 float x, y, z;
5371 m_targets.GetDstPos()->GetPosition(x, y, z);
5372
5375 }
5376
5377 // check pet presence
5378 if (Unit* unitCaster = m_caster->ToUnit())
5379 {
5380 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5381 {
5382 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
5383 {
5384 if (!unitCaster->GetGuardianPet())
5385 {
5386 if (m_triggeredByAuraSpell) // not report pet not existence for triggered spells
5388 else
5389 return SPELL_FAILED_NO_PET;
5390 }
5391 break;
5392 }
5393 }
5394 }
5395
5396 // Spell cast only in battleground
5398 if (!m_caster->ToPlayer()->InBattleground())
5400
5401 // do not allow spells to be cast in arenas
5402 if (Player* player = m_caster->ToPlayer())
5403 if (player->InArena())
5404 {
5405 SpellCastResult castResult = CheckArenaCastRules();
5406 if (castResult != SPELL_CAST_OK)
5407 return castResult;
5408 }
5409
5410 // zone check
5412 {
5413 uint32 zone, area;
5414 m_caster->GetZoneAndAreaId(zone, area);
5415
5417 if (locRes != SPELL_CAST_OK)
5418 return locRes;
5419 }
5420
5421 // not let players cast spells at mount (and let do it to creatures)
5423 {
5425 {
5426 if (m_caster->ToPlayer()->IsInFlight())
5428 else
5430 }
5431 }
5432
5433 // check spell focus object
5435 {
5437 if (focusObject)
5439 else
5441 }
5442
5443 SpellCastResult castResult = SPELL_CAST_OK;
5444
5445 // always (except passive spells) check items (only player related checks)
5446 if (!m_spellInfo->IsPassive())
5447 {
5448 castResult = CheckItems(param1, param2);
5449 if (castResult != SPELL_CAST_OK)
5450 return castResult;
5451 }
5452
5453 // Triggered spells also have range check
5455 castResult = CheckRange(strict);
5456 if (castResult != SPELL_CAST_OK)
5457 return castResult;
5458
5460 {
5461 castResult = CheckPower();
5462 if (castResult != SPELL_CAST_OK)
5463 return castResult;
5464 }
5465
5467 {
5468 castResult = CheckCasterAuras(param1);
5469 if (castResult != SPELL_CAST_OK)
5470 return castResult;
5471 }
5472
5473 // script hook
5474 castResult = CallScriptCheckCastHandlers();
5475 if (castResult != SPELL_CAST_OK)
5476 return castResult;
5477
5478 bool hasDispellableAura = false;
5479 bool hasNonDispelEffect = false;
5480 uint32 dispelMask = 0;
5481 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5482 {
5483 if (spellEffectInfo.Effect == SPELL_EFFECT_DISPEL)
5484 {
5485 if (spellEffectInfo.IsTargetingArea() || m_spellInfo->HasAttribute(SPELL_ATTR1_MELEE_COMBAT_START))
5486 {
5487 hasDispellableAura = true;
5488 break;
5489 }
5490
5491 dispelMask |= SpellInfo::GetDispelMask(DispelType(spellEffectInfo.MiscValue));
5492 }
5493 else if (spellEffectInfo.IsEffect())
5494 {
5495 hasNonDispelEffect = true;
5496 break;
5497 }
5498 }
5499
5500 if (!hasNonDispelEffect && !hasDispellableAura && dispelMask && !IsTriggered())
5501 {
5502 if (Unit* target = m_targets.GetUnitTarget())
5503 {
5504 if (Unit* unitCaster = m_caster->ToUnit())
5505 {
5506 // do not allow to cast on hostile targets in sanctuary
5507 if (!unitCaster->IsFriendlyTo(target))
5508 {
5509 if (unitCaster->IsInSanctuary() || target->IsInSanctuary())
5510 {
5511 // fix for duels
5512 Player* player = unitCaster->ToPlayer();
5513 if (!player || !player->duel || target != player->duel->Opponent)
5515 }
5516 }
5517
5518 DispelChargesList dispelList;
5519 target->GetDispellableAuraList(unitCaster, dispelMask, dispelList);
5520 if (dispelList.empty())
5522 }
5523 }
5524 }
5525
5526 uint8 approximateAuraEffectMask = 0;
5527 uint8 nonAuraEffectMask = 0;
5528 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5529 {
5530 // for effects of spells that have only one target
5531 switch (spellEffectInfo.Effect)
5532 {
5534 {
5537
5538 if (spellEffectInfo.TargetA.GetTarget() != TARGET_UNIT_PET)
5539 break;
5540
5541 Pet* pet = m_caster->ToPlayer()->GetPet();
5542 if (!pet)
5543 return SPELL_FAILED_NO_PET;
5544
5545 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell);
5546 if (!learn_spellproto)
5548
5549 if (m_spellInfo->SpellLevel > pet->GetLevel())
5550 return SPELL_FAILED_LOWLEVEL;
5551
5552 break;
5553 }
5555 {
5556 // check target only for unit target case
5557 if (Unit* unit = m_targets.GetUnitTarget())
5558 {
5561
5562 Pet* pet = unit->ToPet();
5563 if (!pet || pet->GetOwner() != m_caster)
5565
5566 SpellInfo const* learn_spellproto = sSpellMgr->GetSpellInfo(spellEffectInfo.TriggerSpell);
5567
5568 if (!learn_spellproto)
5570
5571 if (m_spellInfo->SpellLevel > pet->GetLevel())
5572 return SPELL_FAILED_LOWLEVEL;
5573 }
5574 break;
5575 }
5577 {
5580
5581 uint32 glyphId = spellEffectInfo.MiscValue;
5582 if (GlyphPropertiesEntry const* gp = sGlyphPropertiesStore.LookupEntry(glyphId))
5583 if (m_caster->ToPlayer()->HasAura(gp->SpellID))
5585 break;
5586 }
5588 {
5591
5592 Item* foodItem = m_targets.GetItemTarget();
5593 if (!foodItem)
5595
5596 Pet* pet = m_caster->ToPlayer()->GetPet();
5597 if (!pet)
5598 return SPELL_FAILED_NO_PET;
5599
5600 if (!pet->HaveInDiet(foodItem->GetTemplate()))
5602
5605
5606 if (m_caster->ToPlayer()->IsInCombat() || pet->IsInCombat())
5608
5609 break;
5610 }
5613 {
5614 // Can be area effect, Check only for players and not check if target - caster (spell can have multiply drain/burn effects)
5616 if (Unit* target = m_targets.GetUnitTarget())
5617 if (target != m_caster && target->GetPowerType() != Powers(spellEffectInfo.MiscValue))
5619 break;
5620 }
5622 {
5623 Unit* unitCaster = m_caster->ToUnit();
5624 if (!unitCaster)
5626
5628 {
5629 // Warbringer - can't be handled in proc system - should be done before checkcast root check and charge effect process
5630 if (strict && unitCaster->IsScriptOverriden(m_spellInfo, 6953))
5631 unitCaster->RemoveMovementImpairingAuras(true);
5632 }
5633
5635 return SPELL_FAILED_ROOTED;
5636
5638 {
5639 Unit* target = m_targets.GetUnitTarget();
5640 if (!target)
5642
5643 // first we must check to see if the target is in LoS. A path can usually be built but LoS matters for charge spells
5644 if (!target->IsWithinLOSInMap(unitCaster)) //Do full LoS/Path check. Don't exclude m2
5646
5647 float objSize = target->GetCombatReach();
5648 float range = m_spellInfo->GetMaxRange(true, unitCaster, this) * 1.5f + objSize; // can't be overly strict
5649
5650 m_preGeneratedPath = std::make_unique<PathGenerator>(unitCaster);
5651 m_preGeneratedPath->SetPathLengthLimit(range);
5652
5653 // first try with raycast, if it fails fall back to normal path
5654 bool result = m_preGeneratedPath->CalculatePath(target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), false);
5655 if (m_preGeneratedPath->GetPathType() & PATHFIND_SHORT)
5656 return SPELL_FAILED_NOPATH;
5657 else if (!result || m_preGeneratedPath->GetPathType() & (PATHFIND_NOPATH | PATHFIND_INCOMPLETE))
5658 return SPELL_FAILED_NOPATH;
5659 else if (m_preGeneratedPath->IsInvalidDestinationZ(target)) // Check position z, if not in a straight line
5660 return SPELL_FAILED_NOPATH;
5661
5662 m_preGeneratedPath->ShortenPathUntilDist(PositionToVector3(target), objSize); // move back
5663 }
5664 break;
5665 }
5667 {
5670
5673
5674 Creature* creature = m_targets.GetUnitTarget()->ToCreature();
5675 if (!creature->IsCritter() && !creature->loot.isLooted())
5677
5678 uint32 skill = creature->GetCreatureTemplate()->GetRequiredLootSkill();
5679
5680 int32 skillValue = m_caster->ToPlayer()->GetSkillValue(skill);
5681 int32 TargetLevel = m_targets.GetUnitTarget()->GetLevel();
5682 int32 ReqValue = (skillValue < 100 ? (TargetLevel-10) * 10 : TargetLevel * 5);
5683 if (ReqValue > skillValue)
5685
5686 break;
5687 }
5689 {
5690 if (spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_TARGET &&
5691 spellEffectInfo.TargetA.GetTarget() != TARGET_GAMEOBJECT_ITEM_TARGET)
5692 break;
5693
5694 if (m_caster->GetTypeId() != TYPEID_PLAYER // only players can open locks, gather etc.
5695 // we need a go target in case of TARGET_GAMEOBJECT_TARGET
5696 || (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_TARGET && !m_targets.GetGOTarget()))
5698
5699 Item* pTempItem = nullptr;
5701 {
5702 if (TradeData* pTrade = m_caster->ToPlayer()->GetTradeData())
5703 pTempItem = pTrade->GetTraderData()->GetItem(TradeSlots(m_targets.GetItemTargetGUID().GetRawValue())); // at this point item target guid contains the trade slot
5704 }
5707
5708 // we need a go target, or an openable item target in case of TARGET_GAMEOBJECT_ITEM_TARGET
5709 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET &&
5711 (!pTempItem || !pTempItem->GetTemplate()->GetLockID() || !pTempItem->IsLocked()))
5713
5714 if (m_spellInfo->Id != 1842 || (m_targets.GetGOTarget() &&
5716 if (m_caster->ToPlayer()->InBattleground() && // In Battleground players can use only flags and banners
5719
5720 // get the lock entry
5721 uint32 lockId = 0;
5722 if (GameObject* go = m_targets.GetGOTarget())
5723 {
5724 lockId = go->GetGOInfo()->GetLockId();
5725 if (!lockId)
5727 }
5728 else if (Item* itm = m_targets.GetItemTarget())
5729 lockId = itm->GetTemplate()->GetLockID();
5730
5731 SkillType skillId = SKILL_NONE;
5732 int32 reqSkillValue = 0;
5733 int32 skillValue = 0;
5734
5735 // check lock compatibility
5736 SpellCastResult res = CanOpenLock(spellEffectInfo, lockId, skillId, reqSkillValue, skillValue);
5737 if (res != SPELL_CAST_OK)
5738 return res;
5739
5740 // chance for fail at lockpicking attempt
5741 // second check prevent fail at rechecks
5742 // herbalism and mining cannot fail as of patch 3.1.0
5743 if (skillId != SKILL_NONE && skillId != SKILL_HERBALISM && skillId != SKILL_MINING && (!m_selfContainer || ((*m_selfContainer) != this)))
5744 {
5745 bool canFailAtMax = skillId == SKILL_LOCKPICKING;
5746
5747 // chance for failure in orange lockpick
5748 if ((canFailAtMax || skillValue < sWorld->GetConfigMaxSkillValue()) && reqSkillValue > irand(skillValue - 25, skillValue + 37))
5750 }
5751 break;
5752 }
5754 {
5755 Unit* unitCaster = m_caster->ToUnit();
5756 if (!unitCaster)
5758
5759 Creature* pet = unitCaster->GetGuardianPet();
5760 if (pet && pet->IsAlive())
5762 break;
5763 }
5764 // This is generic summon effect
5766 {
5767 Unit* unitCaster = m_caster->ToUnit();
5768 if (!unitCaster)
5769 break;
5770
5771 SummonPropertiesEntry const* SummonProperties = sSummonPropertiesStore.LookupEntry(spellEffectInfo.MiscValueB);
5772 if (!SummonProperties)
5773 break;
5774
5775 switch (SummonProperties->Control)
5776 {
5780 [[fallthrough]]; // check both GetPetGUID() and GetCharmGUID for SUMMON_CATEGORY_PET
5782 if (!unitCaster->GetCharmedGUID().IsEmpty())
5784 break;
5785 }
5786 break;
5787 }
5789 {
5791 {
5796 }
5797 break;
5798 }
5800 {
5801 Unit* unitCaster = m_caster->ToUnit();
5802 if (!unitCaster)
5804
5805 if (!unitCaster->GetPetGUID().IsEmpty()) //let warlock do a replacement summon
5806 {
5807 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5808 {
5809 if (strict) //starting cast, trigger pet stun (cast by pet so it doesn't attack player)
5810 if (Pet* pet = unitCaster->ToPlayer()->GetPet())
5811 pet->CastSpell(pet, 32752, pet->GetGUID());
5812 }
5815 }
5816
5817 if (!unitCaster->GetCharmedGUID().IsEmpty())
5819
5820 Player* playerCaster = unitCaster->ToPlayer();
5821 if (playerCaster && playerCaster->GetPetStable())
5822 {
5823 std::pair<PetStable::PetInfo const*, PetSaveMode> info = Pet::GetLoadPetInfo(*playerCaster->GetPetStable(), spellEffectInfo.MiscValue, 0, false);
5824 if (info.first)
5825 {
5826 if (info.first->Type == HUNTER_PET)
5827 {
5828 if (!info.first->Health)
5829 {
5830 playerCaster->SendTameFailure(PETTAME_DEAD);
5832 }
5833
5834 CreatureTemplate const* creatureInfo = sObjectMgr->GetCreatureTemplate(info.first->CreatureId);
5835 if (!creatureInfo || !creatureInfo->IsTameable(playerCaster->CanTameExoticPets()))
5836 {
5837 // if problem in exotic pet
5838 if (creatureInfo && creatureInfo->IsTameable(true))
5840 else
5842
5844 }
5845 }
5846 }
5847 else if (!spellEffectInfo.MiscValue) // when miscvalue is present it is allowed to create new pets
5848 {
5851 }
5852 }
5853
5854 break;
5855 }
5857 {
5860
5861 if (!m_caster->ToPlayer()->GetTarget())
5863
5865 if (!target || m_caster->ToPlayer() == target || (!target->IsInSameRaidWith(m_caster->ToPlayer()) && m_spellInfo->Id != 48955)) // refer-a-friend spell
5867
5868 if (target->HasSummonPending())
5870
5871 // check if our map is dungeon
5872 MapEntry const* map = sMapStore.LookupEntry(m_caster->GetMapId());
5873 if (map->IsDungeon())
5874 {
5875 uint32 mapId = m_caster->GetMap()->GetId();
5876 Difficulty difficulty = m_caster->GetMap()->GetDifficultyID();
5877 if (map->IsRaid())
5878 if (InstancePlayerBind* targetBind = target->GetBoundInstance(mapId, difficulty))
5879 if (InstancePlayerBind* casterBind = m_caster->ToPlayer()->GetBoundInstance(mapId, difficulty))
5880 if (targetBind->perm && targetBind->save != casterBind->save)
5882
5883 InstanceTemplate const* instance = sObjectMgr->GetInstanceTemplate(mapId);
5884 if (!instance)
5886 }
5887 break;
5888 }
5889 // RETURN HERE
5891 {
5894
5895 Player* playerCaster = m_caster->ToPlayer();
5896 if (!playerCaster->GetTarget())
5898
5899 Player* target = playerCaster->GetSelectedPlayer();
5900 if (!target ||
5901 !(target->GetSession()->GetRecruiterId() == playerCaster->GetSession()->GetAccountId() || target->GetSession()->GetAccountId() == playerCaster->GetSession()->GetRecruiterId()))
5903 break;
5904 }
5905 case SPELL_EFFECT_LEAP:
5907 {
5908 //Do not allow to cast it before BG starts.
5910 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
5911 if (bg->GetStatus() != STATUS_IN_PROGRESS)
5913 break;
5914 }
5916 {
5919
5920 dispelMask = SpellInfo::GetDispelMask(DispelType(spellEffectInfo.MiscValue));
5921 bool hasStealableAura = false;
5923 for (Unit::VisibleAuraMap::const_iterator itr = visibleAuras.begin(); itr != visibleAuras.end(); ++itr)
5924 {
5925 if (!itr->second->IsPositive())
5926 continue;
5927
5928 Aura const* aura = itr->second->GetBase();
5929 if (!(aura->GetSpellInfo()->GetDispelMask() & dispelMask))
5930 continue;
5931
5933 continue;
5934
5935 hasStealableAura = true;
5936 break;
5937 }
5938
5939 if (!hasStealableAura)
5941
5942 break;
5943 }
5945 {
5946 Unit* unitCaster = m_caster->ToUnit();
5947 if (!unitCaster)
5949
5950 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
5951 {
5952 if (unitCaster->GetTypeId() == TYPEID_PLAYER)
5953 return SPELL_FAILED_ROOTED;
5954 else
5956 }
5957 break;
5958 }
5959 case SPELL_EFFECT_JUMP:
5961 {
5962 Unit* unitCaster = m_caster->ToUnit();
5963 if (!unitCaster)
5965
5966 if (unitCaster->HasUnitState(UNIT_STATE_ROOT))
5967 return SPELL_FAILED_ROOTED;
5968 break;
5969 }
5971 // can't change during already started arena/battleground
5973 if (Battleground const* bg = m_caster->ToPlayer()->GetBattleground())
5974 if (bg->GetStatus() == STATUS_IN_PROGRESS)
5976 break;
5977 default:
5978 break;
5979 }
5980
5981 if (spellEffectInfo.IsAura())
5982 approximateAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
5983 else if (spellEffectInfo.IsEffect())
5984 nonAuraEffectMask |= 1 << spellEffectInfo.EffectIndex;
5985 }
5986
5987 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
5988 {
5989 switch (spellEffectInfo.ApplyAuraName)
5990 {
5992 {
5994 return SPELL_FAILED_NO_PET;
5995
5996 Pet* pet = m_caster->ToPlayer()->GetPet();
5997 if (!pet)
5998 return SPELL_FAILED_NO_PET;
5999
6000 if (!pet->GetCharmerGUID().IsEmpty())
6002 break;
6003 }
6007 {
6008 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6009 if (!unitCaster)
6011
6012 if (!unitCaster->GetCharmerGUID().IsEmpty())
6013 return SPELL_FAILED_CHARMED;
6014
6015 if (spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_CHARM
6016 || spellEffectInfo.ApplyAuraName == SPELL_AURA_MOD_POSSESS)
6017 {
6020
6021 if (!unitCaster->GetCharmedGUID().IsEmpty())
6023 }
6024
6025 if (Unit* target = m_targets.GetUnitTarget())
6026 {
6027 if (target->GetTypeId() == TYPEID_UNIT && target->IsVehicle())
6029
6030 if (target->IsMounted())
6032
6033 if (!target->GetCharmerGUID().IsEmpty())
6035
6036 if (target->GetOwner() && target->GetOwner()->GetTypeId() == TYPEID_PLAYER)
6038
6039 int32 value = CalculateDamage(spellEffectInfo);
6040 if (value && int32(target->GetLevel()) > value)
6042 }
6043
6044 break;
6045 }
6046 case SPELL_AURA_MOUNTED:
6047 {
6048 Unit* unitCaster = m_caster->ToUnit();
6049 if (!unitCaster)
6051
6054
6055 // Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
6056 bool allowMount = !unitCaster->GetMap()->IsDungeon() || unitCaster->GetMap()->IsBattlegroundOrArena();
6057 InstanceTemplate const* it = sObjectMgr->GetInstanceTemplate(unitCaster->GetMapId());
6058 if (it)
6059 allowMount = it->AllowMount;
6060 if (unitCaster->GetTypeId() == TYPEID_PLAYER && !allowMount && !m_spellInfo->RequiredAreasID)
6062
6063 if (unitCaster->IsInDisallowedMountForm())
6064 {
6065 SendMountResult(MountResult::Shapeshifted); // mount result gets sent before the cast result
6067 }
6068 break;
6069 }
6071 {
6072 if (!m_targets.GetUnitTarget())
6074
6075 // can be cast at non-friendly unit or own pet/charm
6078 break;
6079 }
6080 case SPELL_AURA_FLY:
6082 {
6083 // not allow cast fly spells if not have req. skills (all spells is self target)
6084 // allow always ghost flight spells
6086 {
6087 Battlefield* Bf = sBattlefieldMgr->GetBattlefieldToZoneId(m_originalCaster->GetZoneId());
6088 if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_originalCaster->GetAreaId()))
6089 if (area->Flags & AREA_FLAG_NO_FLY_ZONE || (Bf && !Bf->CanFlyIn()))
6090 return SPELL_FAILED_NOT_HERE;
6091 }
6092 break;
6093 }
6095 {
6096 if (spellEffectInfo.IsTargetingArea())
6097 break;
6098
6099 if (!m_targets.GetUnitTarget())
6101
6103 break;
6104
6107 break;
6108 }
6109 default:
6110 break;
6111 }
6112
6113 // check if target already has the same type, but more powerful aura
6114 if (!nonAuraEffectMask && (approximateAuraEffectMask & (1 << spellEffectInfo.EffectIndex)) && !m_spellInfo->IsTargetingArea())
6115 if (Unit* target = m_targets.GetUnitTarget())
6116 if (!target->IsHighestExclusiveAuraEffect(m_spellInfo, AuraType(spellEffectInfo.ApplyAuraName),
6117 spellEffectInfo.CalcValue(m_caster, &m_spellValue->EffectBasePoints[spellEffectInfo.EffectIndex]), approximateAuraEffectMask, false))
6119 }
6120
6121 // check trade slot case (last, for allow catch any another cast problems)
6123 {
6124 if (m_CastItem)
6126
6129
6130 TradeData* my_trade = m_caster->ToPlayer()->GetTradeData();
6131 if (!my_trade)
6133
6134 // Item target guid contains trade slot until m_targets.UpdateTradeSlotItem() is called
6136 if (slot != TRADE_SLOT_NONTRADED)
6138
6139 if (!IsTriggered())
6140 if (my_trade->GetSpell())
6142 }
6143
6144 // check if caster has at least 1 combo point on target for spells that require combo points
6146 {
6147 if (Unit* unitCaster = m_caster->ToUnit())
6148 {
6150 {
6151 if (!unitCaster->GetComboPoints(m_targets.GetUnitTarget()))
6153 }
6154 else
6155 {
6156 if (!unitCaster->GetComboPoints())
6158 }
6159 }
6160 }
6161
6162 // all ok
6163 return SPELL_CAST_OK;
6164}
6165
6167{
6168 Unit* unitCaster = m_caster->ToUnit();
6169 if (unitCaster && unitCaster->HasUnitState(UNIT_STATE_CASTING) && !(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS)) //prevent spellcast interruption by another spellcast
6171
6172 // dead owner (pets still alive when owners ressed?)
6173 if (Unit* owner = m_caster->GetCharmerOrOwner())
6174 if (!owner->IsAlive() && !owner->IsGhouled())
6176
6177 if (!target && m_targets.GetUnitTarget())
6178 target = m_targets.GetUnitTarget();
6179
6181 {
6182 if (!target)
6184 m_targets.SetUnitTarget(target);
6185 }
6186
6187 // check power requirement
6188 // this would be zero until ::prepare normally, we set it here (it gets reset in ::prepare)
6190 SpellCastResult failReason = CheckPower();
6191 if (failReason != SPELL_CAST_OK)
6192 return failReason;
6193
6194 // check cooldown
6195 if (Creature* creatureCaster = m_caster->ToCreature())
6196 if (!creatureCaster->GetSpellHistory()->IsReady(m_spellInfo))
6198
6199 // Check if spell is affected by GCD
6201 if (unitCaster && unitCaster->GetCharmInfo() && unitCaster->GetSpellHistory()->HasGlobalCooldown(m_spellInfo))
6203
6204 return CheckCast(true);
6205}
6206
6208{
6209 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6210 if (!unitCaster)
6211 return SPELL_CAST_OK;
6212
6213 // spells totally immuned to caster auras (wsg flag drop, give marks etc)
6215 return SPELL_CAST_OK;
6216
6217 // these attributes only show the spell as usable on the client when it has related aura applied
6218 // still they need to be checked against certain mechanics
6219
6220 // SPELL_ATTR5_USABLE_WHILE_STUNNED by default only MECHANIC_STUN (ie no sleep, knockout, freeze, etc.)
6221 bool usableWhileStunned = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_STUNNED);
6222
6223 // SPELL_ATTR5_USABLE_WHILE_FEARED by default only fear (ie no horror)
6224 bool usableWhileFeared = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_FEARED);
6225
6226 // SPELL_ATTR5_USABLE_WHILE_CONFUSED by default only disorient (ie no polymorph)
6227 bool usableWhileConfused = m_spellInfo->HasAttribute(SPELL_ATTR5_USABLE_WHILE_CONFUSED);
6228
6229 // Glyph of Pain Suppression
6230 // there is no other way to handle it
6231 if (m_spellInfo->Id == 33206 && !unitCaster->HasAura(63248))
6232 usableWhileStunned = false;
6233
6234 // Check whether the cast should be prevented by any state you might have.
6236
6237 // Get unit state
6238 uint32 const unitflag = unitCaster->GetUnitFlags();
6239
6240 if (m_fromClient && unitCaster->IsCharmed() && unitCaster->IsPlayer() && !CheckSpellCancelsCharm(param1))
6241 result = SPELL_FAILED_CHARMED;
6242
6243 // spell has attribute usable while having a cc state, check if caster has allowed mechanic auras, another mechanic types must prevent cast spell
6244 auto mechanicCheck = [&](AuraType type) -> SpellCastResult
6245 {
6246 bool foundNotMechanic = false;
6247 Unit::AuraEffectList const& auras = unitCaster->GetAuraEffectsByType(type);
6248 for (AuraEffect const* aurEff : auras)
6249 {
6250 uint32 const mechanicMask = aurEff->GetSpellInfo()->GetAllEffectsMechanicMask();
6251 if (mechanicMask && !(mechanicMask & GetSpellInfo()->GetAllowedMechanicMask()))
6252 {
6253 foundNotMechanic = true;
6254
6255 // fill up aura mechanic info to send client proper error message
6256 if (param1)
6257 {
6258 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6259 if (!*param1)
6260 *param1 = aurEff->GetSpellInfo()->Mechanic;
6261 }
6262
6263 break;
6264 }
6265 }
6266
6267 if (foundNotMechanic)
6268 {
6269 switch (type)
6270 {
6272 return SPELL_FAILED_STUNNED;
6274 return SPELL_FAILED_FLEEING;
6276 return SPELL_FAILED_CONFUSED;
6277 default:
6278 ABORT();
6280 }
6281 }
6282
6283 return SPELL_CAST_OK;
6284 };
6285
6286 if (unitflag & UNIT_FLAG_STUNNED)
6287 {
6288 if (usableWhileStunned)
6289 {
6290 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_STUN);
6291 if (mechanicResult != SPELL_CAST_OK)
6292 result = mechanicResult;
6293 }
6294 else if (!CheckSpellCancelsStun(param1))
6295 result = SPELL_FAILED_STUNNED;
6297 result = SPELL_FAILED_STUNNED;
6298 }
6300 result = SPELL_FAILED_SILENCED;
6302 result = SPELL_FAILED_PACIFIED;
6303 else if (unitflag & UNIT_FLAG_FLEEING)
6304 {
6305 if (usableWhileFeared)
6306 {
6307 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_FEAR);
6308 if (mechanicResult != SPELL_CAST_OK)
6309 result = mechanicResult;
6310 }
6311 else if (!CheckSpellCancelsFear(param1))
6312 result = SPELL_FAILED_FLEEING;
6313 }
6314 else if (unitflag & UNIT_FLAG_CONFUSED)
6315 {
6316 if (usableWhileConfused)
6317 {
6318 SpellCastResult mechanicResult = mechanicCheck(SPELL_AURA_MOD_CONFUSE);
6319 if (mechanicResult != SPELL_CAST_OK)
6320 result = mechanicResult;
6321 }
6322 else if (!CheckSpellCancelsConfuse(param1))
6323 result = SPELL_FAILED_CONFUSED;
6324 }
6325
6326 // Attr must make flag drop spell totally immune from all effects
6327 if (result != SPELL_CAST_OK)
6328 return (param1 && *param1) ? SPELL_FAILED_PREVENTED_BY_MECHANIC : result;
6329
6330 return SPELL_CAST_OK;
6331}
6332
6334{
6335 Unit* unitCaster = (m_originalCaster ? m_originalCaster : m_caster->ToUnit());
6336 if (!unitCaster)
6337 return false;
6338
6339 // Checking auras is needed now, because you are prevented by some state but the spell grants immunity.
6340 Unit::AuraEffectList const& auraEffects = unitCaster->GetAuraEffectsByType(auraType);
6341 if (auraEffects.empty())
6342 return true;
6343
6344 for (AuraEffect const* aurEff : auraEffects)
6345 {
6346 SpellInfo const* auraInfo = aurEff->GetSpellInfo();
6348 continue;
6349
6350 if (param1)
6351 {
6352 *param1 = aurEff->GetSpellEffectInfo().Mechanic;
6353 if (!*param1)
6354 *param1 = auraInfo->Mechanic;
6355 }
6356
6357 return false;
6358 }
6359
6360 return true;
6361}
6362
6369
6375
6381
6387
6389{
6391}
6392
6397
6398int32 Spell::CalculateDamage(SpellEffectInfo const& spellEffectInfo) const
6399{
6400 return m_caster->CalculateSpellDamage(spellEffectInfo, m_spellValue->EffectBasePoints + spellEffectInfo.EffectIndex);
6401}
6402
6404{
6405 // check USABLE attributes
6406 // USABLE takes precedence over NOT_USABLE
6408 return SPELL_CAST_OK;
6409
6410 // check NOT_USABLE attributes
6413
6414 // check cooldowns
6415 uint32 spellCooldown = m_spellInfo->GetRecoveryTime();
6416 if (spellCooldown > 10 * MINUTE * IN_MILLISECONDS) // not sure if still needed
6418
6419 return SPELL_CAST_OK;
6420}
6421
6423{
6424 if (IsTriggered())
6425 return SPELL_CAST_OK;
6426
6428 {
6429 if (m_casttime > 0)
6431 return SPELL_FAILED_MOVING;
6432 }
6433 else if (getState() == SPELL_STATE_CASTING)
6435 return SPELL_FAILED_MOVING;
6436
6437 return SPELL_CAST_OK;
6438}
6439
6441{
6442 if (!target)
6443 return (CheckPetCast(target) == SPELL_CAST_OK);
6444
6445 ObjectGuid targetguid = target->GetGUID();
6446
6447 // check if target already has the same or a more powerful aura
6448 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6449 {
6450 if (!spellEffectInfo.IsAura())
6451 continue;
6452
6453 AuraType const& auraType = spellEffectInfo.ApplyAuraName;
6454 Unit::AuraEffectList const& auras = target->GetAuraEffectsByType(auraType);
6455 for (Unit::AuraEffectList::const_iterator auraIt = auras.begin(); auraIt != auras.end(); ++auraIt)
6456 {
6457 if (GetSpellInfo()->Id == (*auraIt)->GetSpellInfo()->Id)
6458 return false;
6459
6460 switch (sSpellMgr->CheckSpellGroupStackRules(GetSpellInfo(), (*auraIt)->GetSpellInfo()))
6461 {
6463 return false;
6465 if (GetCaster() == (*auraIt)->GetCaster())
6466 return false;
6467 break;
6468 case SPELL_GROUP_STACK_RULE_EXCLUSIVE_SAME_EFFECT: // this one has further checks, but i don't think they're necessary for autocast logic
6470 if (abs(spellEffectInfo.BasePoints) <= abs((*auraIt)->GetAmount()))
6471 return false;
6472 break;
6474 default:
6475 break;
6476 }
6477 }
6478 }
6479
6480 SpellCastResult result = CheckPetCast(target);
6481 if (result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT)
6482 {
6483 // do not check targets for ground-targeted spells (we target them on top of the intended target anyway)
6484 if (GetSpellInfo()->ExplicitTargetMask & TARGET_FLAG_DEST_LOCATION)
6485 return true;
6487 //check if among target units, our WANTED target is as well (->only self cast spells return false)
6488 for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
6489 if (ihit->TargetGUID == targetguid)
6490 return true;
6491 }
6492 // either the cast failed or the intended target wouldn't be hit
6493 return false;
6494}
6495
6497{
6498 if (!m_targets.HasSrc())
6500}
6501
6503{
6504 if (!m_targets.HasDst())
6506}
6507
6509{
6510 // Don't check for instant cast spells
6511 if (!strict && m_casttime == 0)
6512 return SPELL_CAST_OK;
6513
6514 float minRange, maxRange;
6515 std::tie(minRange, maxRange) = GetMinMaxRange(strict);
6516
6517 // dont check max_range to strictly after cast
6519 maxRange += std::min(MAX_SPELL_RANGE_TOLERANCE, maxRange*0.1f); // 10% but no more than MAX_SPELL_RANGE_TOLERANCE
6520
6521 // get square values for sqr distance checks
6522 minRange *= minRange;
6523 maxRange *= maxRange;
6524
6525 Unit* target = m_targets.GetUnitTarget();
6526 if (target && target != m_caster)
6527 {
6528 if (m_caster->GetExactDistSq(target) > maxRange)
6530
6531 if (minRange > 0.0f && m_caster->GetExactDistSq(target) < minRange)
6533
6534 if (m_caster->GetTypeId() == TYPEID_PLAYER &&
6535 (m_spellInfo->FacingCasterFlags & SPELL_FACING_FLAG_INFRONT) && !m_caster->HasInArc(static_cast<float>(M_PI), target))
6537 }
6538
6539 if (GameObject* goTarget = m_targets.GetGOTarget())
6540 {
6541 if (!goTarget->IsAtInteractDistance(m_caster->ToPlayer(), m_spellInfo))
6543 }
6544
6545 if (m_targets.HasDst() && !m_targets.HasTraj())
6546 {
6547 if (m_caster->GetExactDistSq(m_targets.GetDstPos()) > maxRange)
6549 if (minRange > 0.0f && m_caster->GetExactDistSq(m_targets.GetDstPos()) < minRange)
6551 }
6552
6553 return SPELL_CAST_OK;
6554}
6555
6556std::pair<float, float> Spell::GetMinMaxRange(bool strict) const
6557{
6558 float rangeMod = 0.0f;
6559 float minRange = 0.0f;
6560 float maxRange = 0.0f;
6561
6562 if (strict && m_spellInfo->IsNextMeleeSwingSpell())
6563 return { 0.0f, 100.0f };
6564
6565 Unit* unitCaster = m_caster->ToUnit();
6567 {
6568 Unit* target = m_targets.GetUnitTarget();
6570 {
6571 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
6572 if (unitCaster)
6573 rangeMod = unitCaster->GetMeleeRange(target ? target : unitCaster);
6574 }
6575 else
6576 {
6577 float meleeRange = 0.0f;
6579 {
6580 // when the target is not a unit, take the caster's combat reach as the target's combat reach.
6581 if (unitCaster)
6582 meleeRange = unitCaster->GetMeleeRange(target ? target : unitCaster);
6583 }
6584
6585 minRange = m_caster->GetSpellMinRangeForTarget(target, m_spellInfo) + meleeRange;
6586 maxRange = m_caster->GetSpellMaxRangeForTarget(target, m_spellInfo);
6587
6588 if (target || m_targets.GetCorpseTarget())
6589 {
6590 rangeMod = m_caster->GetCombatReach() + (target ? target->GetCombatReach() : m_caster->GetCombatReach());
6591
6592 if (minRange > 0.0f && !(m_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED))
6593 minRange += rangeMod;
6594 }
6595 }
6596
6597 if (target && unitCaster && unitCaster->isMoving() && target->isMoving() && !unitCaster->IsWalking() && !target->IsWalking() &&
6599 rangeMod += 8.0f / 3.0f;
6600 }
6601
6603 if (Item* ranged = m_caster->ToPlayer()->GetWeaponForAttack(RANGED_ATTACK, true))
6604 maxRange *= ranged->GetTemplate()->GetRangedModRange() * 0.01f;
6605
6606 if (Player* modOwner = m_caster->GetSpellModOwner())
6607 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_RANGE, maxRange, const_cast<Spell*>(this));
6608
6609 maxRange += rangeMod;
6610
6611 return { minRange, maxRange };
6612}
6613
6615{
6616 Unit* unitCaster = m_caster->ToUnit();
6617 if (!unitCaster)
6618 return SPELL_CAST_OK;
6619
6620 // item cast not used power
6621 if (m_CastItem)
6622 return SPELL_CAST_OK;
6623
6624 // health as power used - need check health amount
6626 {
6627 if (int32(unitCaster->GetHealth()) <= m_powerCost)
6629 return SPELL_CAST_OK;
6630 }
6631 // Check valid power type
6633 {
6634 TC_LOG_ERROR("spells", "Spell::CheckPower: Unknown power type '{}'", m_spellInfo->PowerType);
6635 return SPELL_FAILED_UNKNOWN;
6636 }
6637
6638 //check rune cost only if a spell has PowerType == POWER_RUNE
6640 {
6642 if (failReason != SPELL_CAST_OK)
6643 return failReason;
6644 }
6645
6646 // Check power amount
6647 Powers powerType = m_spellInfo->PowerType;
6648 if (int32(unitCaster->GetPower(powerType)) < m_powerCost)
6649 return SPELL_FAILED_NO_POWER;
6650 else
6651 return SPELL_CAST_OK;
6652}
6653
6654SpellCastResult Spell::CheckItems(uint32* param1 /*= nullptr*/, uint32* param2 /*= nullptr*/) const
6655{
6656 Player* player = m_caster->ToPlayer();
6657 if (!player)
6658 return SPELL_CAST_OK;
6659
6660 if (!m_CastItem)
6661 {
6662 if (!m_castItemGUID.IsEmpty())
6664 }
6665 else
6666 {
6667 uint32 itemid = m_CastItem->GetEntry();
6668 if (!player->HasItemCount(itemid))
6670
6671 ItemTemplate const* proto = m_CastItem->GetTemplate();
6672 if (!proto)
6674
6675 for (uint8 i = 0; i < MAX_ITEM_PROTO_SPELLS; ++i)
6676 if (proto->Effects[i].Charges)
6677 if (m_CastItem->GetSpellCharges(i) == 0)
6679
6680 // consumable cast item checks
6682 {
6683 // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example
6684 SpellCastResult failReason = SPELL_CAST_OK;
6685 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6686 {
6687 // skip check, pet not required like checks, and for TARGET_UNIT_PET m_targets.GetUnitTarget() is not the real target but the caster
6688 if (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_PET)
6689 continue;
6690
6691 if (spellEffectInfo.IsEffect(SPELL_EFFECT_HEAL))
6692 {
6694 {
6696 continue;
6697 }
6698 else
6699 {
6700 failReason = SPELL_CAST_OK;
6701 break;
6702 }
6703 }
6704
6705 // Mana Potion, Rage Potion, Thistle Tea(Rogue), ...
6706 if (spellEffectInfo.IsEffect(SPELL_EFFECT_ENERGIZE))
6707 {
6708 if (spellEffectInfo.MiscValue < 0 || spellEffectInfo.MiscValue >= int8(MAX_POWERS))
6709 {
6711 continue;
6712 }
6713
6714 Powers power = Powers(spellEffectInfo.MiscValue);
6716 {
6718 continue;
6719 }
6720 else
6721 {
6722 failReason = SPELL_CAST_OK;
6723 break;
6724 }
6725 }
6726 }
6727 if (failReason != SPELL_CAST_OK)
6728 return failReason;
6729 }
6730 }
6731
6732 // check target item
6734 {
6735 Item* item = m_targets.GetItemTarget();
6736 if (!item)
6738
6741 }
6742 // if not item target then required item must be equipped
6743 else
6744 {
6748 }
6749
6750 // do not take reagents for these item casts
6752 {
6754 // Not own traded item (in trader trade slot) requires reagents even if triggered spell
6755 if (!checkReagents)
6756 if (Item* targetItem = m_targets.GetItemTarget())
6757 if (targetItem->GetOwnerGUID() != player->GetGUID())
6758 checkReagents = true;
6759
6760 // check reagents (ignore triggered spells with reagents processed by original spell) and special reagent ignore case.
6761 if (checkReagents)
6762 {
6763 for (uint32 i = 0; i < MAX_SPELL_REAGENTS; i++)
6764 {
6765 if (m_spellInfo->Reagent[i] <= 0)
6766 continue;
6767
6768 uint32 itemid = m_spellInfo->Reagent[i];
6769 uint32 itemcount = m_spellInfo->ReagentCount[i];
6770
6771 // if CastItem is also spell reagent
6772 if (m_CastItem && m_CastItem->GetEntry() == itemid)
6773 {
6774 ItemTemplate const* proto = m_CastItem->GetTemplate();
6775 if (!proto)
6777 for (uint8 s = 0; s < MAX_ITEM_PROTO_SPELLS; ++s)
6778 {
6779 // CastItem will be used up and does not count as reagent
6780 int32 charges = m_CastItem->GetSpellCharges(s);
6781 if (proto->Effects[s].Charges < 0 && abs(charges) < 2)
6782 {
6783 ++itemcount;
6784 break;
6785 }
6786 }
6787 }
6788 if (!player->HasItemCount(itemid, itemcount))
6789 {
6790 if (param1)
6791 *param1 = itemid;
6792 return SPELL_FAILED_REAGENTS;
6793 }
6794 }
6795 }
6796
6797 // check totem-item requirements (items presence in inventory)
6798 for (uint32 totem : m_spellInfo->Totem)
6799 {
6800 if (totem && !player->HasItemCount(totem))
6801 {
6802 if (param1)
6803 *param1 = totem;
6804 return SPELL_FAILED_TOTEMS;
6805 }
6806 }
6807
6808 // Check items for TotemCategory (items presence in inventory)
6809 for (uint32 totemCategory : m_spellInfo->TotemCategory)
6810 {
6811 if (totemCategory && !player->HasItemTotemCategory(totemCategory))
6812 {
6813 if (param1)
6814 *param1 = totemCategory;
6816 }
6817 }
6818 }
6819
6820 // special checks for spell effects
6821 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
6822 {
6823 switch (spellEffectInfo.Effect)
6824 {
6827 {
6828 // m_targets.GetUnitTarget() means explicit cast, otherwise we dont check for possible equip error
6829 Unit* target = m_targets.GetUnitTarget() ? m_targets.GetUnitTarget() : player;
6830 if (target->GetTypeId() == TYPEID_PLAYER && !IsTriggered())
6831 {
6832 // 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,
6833 // so we need to make sure there is at least one free space in the player's inventory
6834 if (spellEffectInfo.IsEffect(SPELL_EFFECT_CREATE_ITEM_2))
6835 if (target->ToPlayer()->GetFreeInventorySpace() == 0)
6836 {
6837 player->SendEquipError(EQUIP_ERR_INV_FULL, nullptr, nullptr, spellEffectInfo.ItemType);
6839 }
6840
6841 if (spellEffectInfo.ItemType)
6842 {
6843 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(spellEffectInfo.ItemType);
6844 if (!itemTemplate)
6846
6847 uint32 createCount = std::clamp<uint32>(spellEffectInfo.CalcValue(), 1u, itemTemplate->GetMaxStackSize());
6848 ItemPosCountVec dest;
6849 InventoryResult msg = target->ToPlayer()->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, createCount);
6850 if (msg != EQUIP_ERR_OK)
6851 {
6853 if (!itemTemplate->GetItemLimitCategory())
6854 {
6855 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
6857 }
6858 else
6859 {
6860 // Conjure Food/Water/Refreshment spells
6863 else if (!(target->ToPlayer()->HasItemCount(spellEffectInfo.ItemType)))
6864 {
6865 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
6867 }
6868 else
6869 player->CastSpell(player, m_spellInfo->GetEffect(EFFECT_1).CalcValue(), false); // move this to anywhere
6871 }
6872 }
6873 }
6874 }
6875 break;
6876 }
6878 if (spellEffectInfo.ItemType && m_targets.GetItemTarget()
6880 {
6881 // cannot enchant vellum for other player
6882 if (m_targets.GetItemTarget()->GetOwner() != player)
6884 // do not allow to enchant vellum from scroll made by vellum-prevent exploit
6887 ItemPosCountVec dest;
6888 InventoryResult msg = player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, spellEffectInfo.ItemType, 1);
6889 if (msg != EQUIP_ERR_OK)
6890 {
6891 player->SendEquipError(msg, nullptr, nullptr, spellEffectInfo.ItemType);
6893 }
6894 }
6895 [[fallthrough]];
6897 {
6898 Item* targetItem = m_targets.GetItemTarget();
6899 if (!targetItem)
6901
6902 // Apply item level restriction
6904 {
6905 uint32 requiredLevel = targetItem->GetTemplate()->GetRequiredLevel();
6906 if (!requiredLevel)
6907 requiredLevel = targetItem->GetTemplate()->GetBaseItemLevel();
6908
6909 if (requiredLevel < m_spellInfo->BaseLevel)
6910 return SPELL_FAILED_LOWLEVEL;
6911 }
6912 if (m_CastItem
6915
6916 bool isItemUsable = false;
6917 ItemTemplate const* proto = targetItem->GetTemplate();
6918 for (ItemEffect const& itemEffect : proto->Effects)
6919 {
6920 if (itemEffect.SpellID > 0 && itemEffect.TriggerType == ITEM_SPELLTRIGGER_ON_USE)
6921 {
6922 isItemUsable = true;
6923 break;
6924 }
6925 }
6926
6927 SpellItemEnchantmentEntry const* enchantEntry = sSpellItemEnchantmentStore.LookupEntry(spellEffectInfo.MiscValue);
6928 // do not allow adding usable enchantments to items that have use effect already
6929 if (enchantEntry)
6930 {
6931 for (uint8 s = 0; s < MAX_ITEM_ENCHANTMENT_EFFECTS; ++s)
6932 {
6933 switch (enchantEntry->Effect[s])
6934 {
6936 if (isItemUsable)
6938 break;
6940 {
6941 uint32 numSockets = 0;
6942 for (uint32 socket = 0; socket < MAX_ITEM_PROTO_SOCKETS; ++socket)
6943 if (targetItem->GetTemplate()->GetSocketColor(socket))
6944 ++numSockets;
6945
6946 if (numSockets == MAX_ITEM_PROTO_SOCKETS || targetItem->GetEnchantmentId(PRISMATIC_ENCHANTMENT_SLOT))
6948 break;
6949 }
6950 }
6951 }
6952 }
6953
6954 // Not allow enchant in trade slot for some enchant type
6955 if (targetItem->GetOwner() != player)
6956 {
6957 if (!enchantEntry)
6958 return SPELL_FAILED_ERROR;
6959 if (enchantEntry->Flags & ENCHANTMENT_CAN_SOULBOUND)
6961 }
6962 break;
6963 }
6965 {
6966 Item* item = m_targets.GetItemTarget();
6967 if (!item)
6969 // Not allow enchant in trade slot for some enchant type
6970 if (item->GetOwner() != player)
6971 {
6972 uint32 enchant_id = spellEffectInfo.MiscValue;
6973 SpellItemEnchantmentEntry const* pEnchant = sSpellItemEnchantmentStore.LookupEntry(enchant_id);
6974 if (!pEnchant)
6975 return SPELL_FAILED_ERROR;
6976 if (pEnchant->Flags & ENCHANTMENT_CAN_SOULBOUND)
6978 }
6979
6980 // Apply item level restriction
6982 {
6983 uint32 requiredLevel = item->GetTemplate()->GetRequiredLevel();
6984 if (!requiredLevel)
6985 requiredLevel = item->GetTemplate()->GetBaseItemLevel();
6986
6987 if (requiredLevel < m_spellInfo->BaseLevel)
6988 return SPELL_FAILED_LOWLEVEL;
6989 }
6992 break;
6993 }
6995 // check item existence in effect code (not output errors at offhand hold item effect to main hand for example
6996 break;
6998 {
6999 if (!m_targets.GetItemTarget())
7001
7002 // prevent disenchanting in trade slot
7003 if (m_targets.GetItemTarget()->GetOwnerGUID() != player->GetGUID())
7005
7006 ItemTemplate const* itemProto = m_targets.GetItemTarget()->GetTemplate();
7007 if (!itemProto)
7009
7010 uint32 item_quality = itemProto->GetQuality();
7011 // 2.0.x addon: Check player enchanting level against the item disenchanting requirements
7012 uint32 item_disenchantskilllevel = itemProto->GetRequiredDisenchantSkill();
7013 if (item_disenchantskilllevel == uint32(-1))
7015 if (item_disenchantskilllevel > player->GetSkillValue(SKILL_ENCHANTING))
7017 if (item_quality > 4 || item_quality < 2)
7019 if (itemProto->GetClass() != ITEM_CLASS_WEAPON && itemProto->GetClass() != ITEM_CLASS_ARMOR)
7021 if (!itemProto->DisenchantID)
7023 break;
7024 }
7026 {
7027 Item* item = m_targets.GetItemTarget();
7028 if (!item)
7030 //ensure item is a prospectable ore
7033 //prevent prospecting in trade slot
7034 if (item->GetOwnerGUID() != player->GetGUID())
7036 //Check for enough skill in jewelcrafting
7037 uint32 item_prospectingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7038 if (item_prospectingskilllevel > player->GetSkillValue(SKILL_JEWELCRAFTING))
7040 //make sure the player has the required ores in inventory
7041 if (item->GetCount() < 5)
7042 {
7043 if (param1 && param2)
7044 {
7045 *param1 = item->GetEntry();
7046 *param2 = 5;
7047 }
7049 }
7050
7053
7054 break;
7055 }
7057 {
7058 Item* item = m_targets.GetItemTarget();
7059 if (!item)
7061 //ensure item is a millable herb
7064 //prevent milling in trade slot
7065 if (item->GetOwnerGUID() != player->GetGUID())
7067 //Check for enough skill in inscription
7068 uint32 item_millingskilllevel = item->GetTemplate()->GetRequiredSkillRank();
7069 if (item_millingskilllevel > player->GetSkillValue(SKILL_INSCRIPTION))
7071 //make sure the player has the required herbs in inventory
7072 if (item->GetCount() < 5)
7073 {
7074 if (param1 && param2)
7075 {
7076 *param1 = item->GetEntry();
7077 *param2 = 5;
7078 }
7080 }
7081
7084
7085 break;
7086 }
7089 {
7091 break;
7092
7093 Item* item = player->GetWeaponForAttack(m_attackType);
7094 if (!item || item->IsBroken())
7096
7097 switch (item->GetTemplate()->GetSubClass())
7098 {
7100 {
7101 uint32 const ammo = item->GetEntry();
7102 if (!player->HasItemCount(ammo))
7103 return SPELL_FAILED_NO_AMMO;
7104 break;
7105 }
7109 {
7110 uint32 const ammo = player->GetUInt32Value(PLAYER_AMMO_ID);
7111 if (!ammo)
7112 {
7113 // Requires No Ammo
7114 if (player->HasAura(46699))
7115 break; // skip other checks
7116
7117 return SPELL_FAILED_NO_AMMO;
7118 }
7119
7120 ItemTemplate const* ammoProto = sObjectMgr->GetItemTemplate(ammo);
7121 if (!ammoProto)
7122 return SPELL_FAILED_NO_AMMO;
7123
7124 if (ammoProto->GetClass() != ITEM_CLASS_PROJECTILE)
7125 return SPELL_FAILED_NO_AMMO;
7126
7127 // check ammo ws. weapon compatibility
7128 switch (item->GetTemplate()->GetSubClass())
7129 {
7132 if (ammoProto->GetSubClass() != ITEM_SUBCLASS_ARROW)
7133 return SPELL_FAILED_NO_AMMO;
7134 break;
7136 if (ammoProto->GetSubClass() != ITEM_SUBCLASS_BULLET)
7137 return SPELL_FAILED_NO_AMMO;
7138 break;
7139 default:
7140 return SPELL_FAILED_NO_AMMO;
7141 }
7142
7143 if (!player->HasItemCount(ammo))
7144 {
7145 player->SetUInt32Value(PLAYER_AMMO_ID, 0);
7146 return SPELL_FAILED_NO_AMMO;
7147 }
7148 break;
7149 }
7151 break;
7152 default:
7153 break;
7154 }
7155 break;
7156 }
7158 {
7159 uint32 item_id = spellEffectInfo.ItemType;
7160 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(item_id);
7161
7162 if (!proto)
7164
7165 if (Item* item = player->GetItemByEntry(item_id))
7166 {
7167 for (uint32 x = 0; x < proto->Effects.size(); ++x)
7168 if (proto->Effects[x].Charges != 0 && item->GetSpellCharges(x) == proto->Effects[x].Charges)
7170 }
7171 break;
7172 }
7173 default:
7174 break;
7175 }
7176 }
7177
7178 // check weapon presence in slots for main/offhand weapons
7180 {
7181 auto weaponCheck = [&](WeaponAttackType attackType) -> SpellCastResult
7182 {
7183 Item const* item = player->GetWeaponForAttack(attackType);
7184
7185 // skip spell if no weapon in slot or broken
7186 if (!item || item->IsBroken())
7188
7189 // skip spell if weapon not fit to triggered spell
7192
7193 return SPELL_CAST_OK;
7194 };
7195
7197 {
7198 SpellCastResult mainHandResult = weaponCheck(BASE_ATTACK);
7199 if (mainHandResult != SPELL_CAST_OK)
7200 return mainHandResult;
7201 }
7202
7204 {
7205 SpellCastResult offHandResult = weaponCheck(OFF_ATTACK);
7206 if (offHandResult != SPELL_CAST_OK)
7207 return offHandResult;
7208 }
7209 }
7210
7211 return SPELL_CAST_OK;
7212}
7213
7214void Spell::Delayed() // only called in DealDamage()
7215{
7216 Player* playerCaster = m_caster->ToPlayer();
7217 if (!playerCaster)
7218 return;
7219
7220 // spells not losing casting time
7222 return;
7223
7224 if (IsDelayableNoMore()) // Spells may only be delayed twice
7225 return;
7226
7227 //check pushback reduce
7228 int32 delaytime = 500; // spellcasting delay is normally 500ms
7229
7230 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
7231 playerCaster->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
7232 delayReduce += playerCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
7233 if (delayReduce >= 100)
7234 return;
7235
7236 AddPct(delaytime, -delayReduce);
7237
7238 if (m_timer + delaytime > m_casttime)
7239 {
7240 delaytime = m_casttime - m_timer;
7242 }
7243 else
7244 m_timer += delaytime;
7245
7247 data << playerCaster->GetPackGUID();
7248 data << uint32(delaytime);
7249
7250 playerCaster->SendMessageToSet(&data, true);
7251}
7252
7254{
7255 Player* playerCaster = m_caster->ToPlayer();
7256 if (!playerCaster)
7257 return;
7258
7260 return;
7261
7262 // spells not losing channeling time
7264 return;
7265
7266 if (IsDelayableNoMore()) // Spells may only be delayed twice
7267 return;
7268
7269 //check pushback reduce
7270 // should be affected by modifiers, not take the dbc duration.
7272
7273 int32 delaytime = CalculatePct(duration, 25); // channeling delay is normally 25% of its time per hit
7274
7275 int32 delayReduce = 100; // must be initialized to 100 for percent modifiers
7276 playerCaster->ApplySpellMod(m_spellInfo->Id, SPELLMOD_NOT_LOSE_CASTING_TIME, delayReduce, this);
7277 delayReduce += playerCaster->GetTotalAuraModifier(SPELL_AURA_REDUCE_PUSHBACK) - 100;
7278 if (delayReduce >= 100)
7279 return;
7280
7281 AddPct(delaytime, -delayReduce);
7282
7283 if (m_timer <= delaytime)
7284 {
7285 delaytime = m_timer;
7286 m_timer = 0;
7287 }
7288 else
7289 m_timer -= delaytime;
7290
7291 for (TargetInfo const& targetInfo : m_UniqueTargetInfo)
7292 if (targetInfo.MissCondition == SPELL_MISS_NONE)
7293 if (Unit* unit = (playerCaster->GetGUID() == targetInfo.TargetGUID) ? playerCaster : ObjectAccessor::GetUnit(*playerCaster, targetInfo.TargetGUID))
7294 unit->DelayOwnedAuras(m_spellInfo->Id, m_originalCasterGUID, delaytime);
7295
7296 // partially interrupt persistent area auras
7297 if (DynamicObject* dynObj = playerCaster->GetDynObject(m_spellInfo->Id))
7298 dynObj->Delay(delaytime);
7299
7301}
7302
7314
7316{
7318
7321
7323 {
7325 // cast item not found, somehow the item is no longer where we expected
7326 if (!m_CastItem)
7327 return false;
7328
7329 // check if the item is really the same, in case it has been wrapped for example
7331 return false;
7332 }
7333
7335
7336 // further actions done only for dest targets
7337 if (!m_targets.HasDst())
7338 return true;
7339
7340 // cache last transport
7341 WorldObject* transport = nullptr;
7342
7343 // update effect destinations (in case of moved transport dest target)
7344 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7345 {
7346 SpellDestination& dest = m_destTargets[spellEffectInfo.EffectIndex];
7347 if (!dest._transportGUID)
7348 continue;
7349
7350 if (!transport || transport->GetGUID() != dest._transportGUID)
7352
7353 if (transport)
7354 {
7355 dest._position.Relocate(transport);
7357 }
7358 }
7359
7360 return true;
7361}
7362
7364{
7366 return CURRENT_MELEE_SPELL;
7367 else if (IsAutoRepeat())
7369 else if (m_spellInfo->IsChanneled())
7371
7372 return CURRENT_GENERIC_SPELL;
7373}
7374
7375bool Spell::CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEffectInfo, Position const* losPosition) const
7376{
7377 switch (spellEffectInfo.ApplyAuraName)
7378 {
7383 if (target->GetVehicleKit() && target->GetVehicleKit()->IsControllableVehicle())
7384 return false;
7385 if (target->IsMounted())
7386 return false;
7387 if (!target->GetCharmerGUID().IsEmpty())
7388 return false;
7389 if (int32 value = CalculateDamage(spellEffectInfo))
7390 if ((int32)target->GetLevel() > value)
7391 return false;
7392 break;
7393 default:
7394 break;
7395 }
7396
7397 // check for ignore LOS on the effect itself
7399 return true;
7400
7401 // check if gameobject ignores LOS
7402 if (GameObject const* gobCaster = m_caster->ToGameObject())
7403 if (gobCaster->GetGOInfo()->IsIgnoringLOSChecks())
7404 return true;
7405
7406 // if spell is triggered, need to check for LOS disable on the aura triggering it and inherit that behaviour
7408 return true;
7409
7411 //Check targets for LOS visibility (except spells without range limitations)
7412 switch (spellEffectInfo.Effect)
7413 {
7415 // player far away, maybe his corpse near?
7416 if (target != m_caster && !target->IsWithinLOSInMap(m_caster))
7417 {
7419 return false;
7420
7422 if (!corpse)
7423 return false;
7424
7425 if (target->GetGUID() != corpse->GetOwnerGUID())
7426 return false;
7427
7428 if (!corpse->IsWithinLOSInMap(m_caster))
7429 return false;
7430 }
7431
7432 // all ok by some way or another, skip normal check
7433 break;
7435 {
7437 {
7439 return true;
7440
7441 return false;
7442 }
7443
7445 if (!corpse)
7446 return false;
7447
7448 if (target->GetGUID() != corpse->GetOwnerGUID())
7449 return false;
7450
7451 if (!corpse->HasCorpseFlag(CORPSE_FLAG_LOOTABLE))
7452 return false;
7453
7455 return false;
7456
7457 break;
7458 }
7459 default: // normal case
7460 {
7461 if (losPosition)
7462 return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2);
7463 else
7464 {
7465 // Get GO cast coordinates if original caster -> GO
7466 WorldObject* caster = nullptr;
7469 if (!caster)
7470 caster = m_caster;
7472 return false;
7473 }
7474 break;
7475 }
7476 }
7477
7478 return true;
7479}
7480
7481bool Spell::CheckEffectTarget(GameObject const* target, SpellEffectInfo const& spellEffectInfo) const
7482{
7483 switch (spellEffectInfo.Effect)
7484 {
7489 return false;
7490 break;
7491 default:
7492 break;
7493 }
7494
7495 return true;
7496}
7497
7498bool Spell::CheckEffectTarget(Item const* /*target*/, SpellEffectInfo const& /*spellEffectInfo*/) const
7499{
7500 return true;
7501}
7502
7504{
7506}
7507
7512
7517
7519{
7521}
7522
7524{
7525 return m_caster->IsUnit() && m_caster->ToUnit()->GetChannelSpellId() != 0;
7526}
7527
7529{
7532 return false;
7533
7535 return false;
7536
7537 return true;
7538}
7539
7544
7550
7555
7556SpellEvent::SpellEvent(Spell* spell) : BasicEvent(), m_Spell(spell)
7557{
7558}
7559
7561{
7563 m_Spell->cancel();
7564
7565 if (!m_Spell->IsDeletable())
7566 {
7567 TC_LOG_ERROR("spells", "~SpellEvent: {} {} tried to delete non-deletable spell {}. Was not deleted, causes memory leak.",
7568 (m_Spell->GetCaster()->GetTypeId() == TYPEID_PLAYER ? "Player" : "Creature"), m_Spell->GetCaster()->GetGUID().ToString(), m_Spell->m_spellInfo->Id);
7569 ABORT();
7570 }
7571}
7572
7574{
7575 // update spell if it is not finished
7577 m_Spell->update(p_time);
7578
7579 // check spell state to process
7580 switch (m_Spell->getState())
7581 {
7583 {
7584 // spell was finished, check deletable state
7585 if (m_Spell->IsDeletable())
7586 {
7587 // check, if we do have unfinished triggered spells
7588 return true; // spell is deletable, finish event
7589 }
7590 // event will be re-added automatically at the end of routine)
7591 break;
7592 }
7594 {
7595 // first, check, if we have just started
7596 if (m_Spell->GetDelayStart() != 0)
7597 {
7598 // no, we aren't, do the typical update
7599 // check, if we have channeled spell on our hands
7600 /*
7601 if (m_Spell->m_spellInfo->IsChanneled())
7602 {
7603 // evented channeled spell is processed separately, cast once after delay, and not destroyed till finish
7604 // check, if we have casting anything else except this channeled spell and autorepeat
7605 if (m_Spell->GetCaster()->IsNonMeleeSpellCast(false, true, true))
7606 {
7607 // another non-melee non-delayed spell is cast now, abort
7608 m_Spell->cancel();
7609 }
7610 else
7611 {
7612 // Set last not triggered spell for apply spellmods
7613 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, true);
7614 // do the action (pass spell to channeling state)
7615 m_Spell->handle_immediate();
7616
7617 // And remove after effect handling
7618 ((Player*)m_Spell->GetCaster())->SetSpellModTakingSpell(m_Spell, false);
7619 }
7620 // event will be re-added automatically at the end of routine)
7621 }
7622 else
7623 */
7624 {
7625 // run the spell handler and think about what we can do next
7626 uint64 t_offset = e_time - m_Spell->GetDelayStart();
7627 uint64 n_offset = m_Spell->handle_delayed(t_offset);
7628 if (n_offset)
7629 {
7630 // re-add us to the queue
7631 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(m_Spell->GetDelayStart() + n_offset), false);
7632 return false; // event not complete
7633 }
7634 // event complete
7635 // finish update event will be re-added automatically at the end of routine)
7636 }
7637 }
7638 else
7639 {
7640 // delaying had just started, record the moment
7641 m_Spell->SetDelayStart(e_time);
7642 // re-plan the event for the delay moment
7643 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + m_Spell->GetDelayMoment()), false);
7644 return false; // event not complete
7645 }
7646 break;
7647 }
7648 default:
7649 {
7650 // all other states
7651 // event will be re-added automatically at the end of routine)
7652 break;
7653 }
7654 }
7655
7656 // spell processing not complete, plan event on the next update interval
7657 m_Spell->GetCaster()->m_Events.AddEvent(this, Milliseconds(e_time + 1), false);
7658 return false; // event not complete
7659}
7660
7662{
7663 // oops, the spell we try to do is aborted
7665 m_Spell->cancel();
7666}
7667
7669{
7670 return m_Spell->IsDeletable();
7671}
7672
7673bool Spell::IsValidDeadOrAliveTarget(Unit const* target) const
7674{
7675 if (target->IsAlive())
7678 return true;
7679 return false;
7680}
7681
7683{
7684 // handle effects with SPELL_EFFECT_HANDLE_LAUNCH mode
7685 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7686 {
7687 // don't do anything for empty effect
7688 if (!spellEffectInfo.IsEffect())
7689 continue;
7690
7691 HandleEffects(nullptr, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH);
7692 }
7693
7695
7696 // Take ammunition if the ranged attack requires ammunition
7697 if (Player* player = m_caster->ToPlayer())
7698 {
7700 if (player->HasAuraTypeWithAffectMask(SPELL_AURA_ABILITY_CONSUME_NO_AMMO, m_spellInfo))
7701 usesAmmo = false;
7702
7703 // Do not consume ammo for the triggered AoE ticks of Volley (Hunter spell)
7705 usesAmmo = false;
7706
7707 if (usesAmmo)
7708 TakeAmmo();
7709 }
7710
7711 for (TargetInfo& target : m_UniqueTargetInfo)
7712 PreprocessSpellLaunch(target);
7713
7714 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
7715 {
7716 float multiplier = 1.0f;
7717 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
7718 multiplier = spellEffectInfo.CalcDamageMultiplier(m_originalCaster, this);
7719
7720 for (TargetInfo& target : m_UniqueTargetInfo)
7721 {
7722 uint32 mask = target.EffectMask;
7723 if (!(mask & (1 << spellEffectInfo.EffectIndex)))
7724 continue;
7725
7726 DoEffectOnLaunchTarget(target, multiplier, spellEffectInfo);
7727 }
7728 }
7729
7731}
7732
7734{
7735 Unit* targetUnit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
7736 if (!targetUnit)
7737 return;
7738
7739 // This will only cause combat - the target will engage once the projectile hits (in Spell::TargetInfo::PreprocessTarget)
7741 m_originalCaster->SetInCombatWith(targetUnit, true);
7742
7743 Unit* unit = nullptr;
7744 // In case spell hit target, do all effect on that target
7745 if (targetInfo.MissCondition == SPELL_MISS_NONE)
7746 unit = targetUnit;
7747 // In case spell reflect from target, do all effect on caster (if hit)
7748 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
7749 unit = m_caster->ToUnit();
7750
7751 if (!unit)
7752 return;
7753
7754 float critChance = m_spellValue->CriticalChance;
7755 if (m_originalCaster)
7756 {
7757 if (!critChance)
7760 }
7761
7762 targetInfo.IsCrit = roll_chance_f(critChance);
7763}
7764
7765void Spell::DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, SpellEffectInfo const& spellEffectInfo)
7766{
7767 Unit* unit = nullptr;
7768 // In case spell hit target, do all effect on that target
7770 unit = m_caster->GetGUID() == targetInfo.TargetGUID ? m_caster->ToUnit() : ObjectAccessor::GetUnit(*m_caster, targetInfo.TargetGUID);
7771 // In case spell reflect from target, do all effect on caster (if hit)
7772 else if (targetInfo.MissCondition == SPELL_MISS_REFLECT && targetInfo.ReflectResult == SPELL_MISS_NONE)
7773 unit = m_caster->ToUnit();
7774
7775 if (!unit)
7776 return;
7777
7778 m_damage = 0;
7779 m_healing = 0;
7780
7781 HandleEffects(unit, nullptr, nullptr, nullptr, spellEffectInfo, SPELL_EFFECT_HANDLE_LAUNCH_TARGET);
7782
7783 if (m_originalCaster && m_damage > 0)
7784 {
7785 if (spellEffectInfo.IsTargetingArea() || spellEffectInfo.IsAreaAuraEffect() || spellEffectInfo.IsEffect(SPELL_EFFECT_PERSISTENT_AREA_AURA))
7786 {
7788
7790 {
7791 // cap damage of player AOE
7792 int64 targetAmount = GetUnitTargetCountForEffect(spellEffectInfo.EffectIndex);
7793 if (targetAmount > 10)
7794 m_damage = m_damage * 10 / targetAmount;
7795 }
7796 }
7797 }
7798
7799 if (m_applyMultiplierMask & (1 << spellEffectInfo.EffectIndex))
7800 {
7803
7804 m_damageMultipliers[spellEffectInfo.EffectIndex] *= multiplier;
7805 }
7806
7807 targetInfo.Damage += m_damage;
7808 targetInfo.Healing += m_healing;
7809}
7810
7811SpellCastResult Spell::CanOpenLock(SpellEffectInfo const& spellEffectInfo, uint32 lockId, SkillType& skillId, int32& reqSkillValue, int32& skillValue)
7812{
7813 if (!lockId) // possible case for GO and maybe for items.
7814 return SPELL_CAST_OK;
7815
7816 // Get LockInfo
7817 LockEntry const* lockInfo = sLockStore.LookupEntry(lockId);
7818
7819 if (!lockInfo)
7821
7822 bool reqKey = false; // some locks not have reqs
7823
7824 for (int j = 0; j < MAX_LOCK_CASE; ++j)
7825 {
7826 switch (lockInfo->Type[j])
7827 {
7828 // check key item (many fit cases can be)
7829 case LOCK_KEY_ITEM:
7830 if (lockInfo->Index[j] && m_CastItem && m_CastItem->GetEntry() == lockInfo->Index[j])
7831 return SPELL_CAST_OK;
7832 reqKey = true;
7833 break;
7834 // check key skill (only single first fit case can be)
7835 case LOCK_KEY_SKILL:
7836 {
7837 reqKey = true;
7838
7839 // wrong locktype, skip
7840 if (uint32(spellEffectInfo.MiscValue) != lockInfo->Index[j])
7841 continue;
7842
7843 skillId = SkillByLockType(LockType(lockInfo->Index[j]));
7844
7845 if (skillId != SKILL_NONE)
7846 {
7847 reqSkillValue = lockInfo->Skill[j];
7848
7849 // castitem check: rogue using skeleton keys. the skill values should not be added in this case.
7850 skillValue = m_CastItem || m_caster->GetTypeId() != TYPEID_PLAYER ?
7851 0 : m_caster->ToPlayer()->GetSkillValue(skillId);
7852
7853 // skill bonus provided by casting spell (mostly item spells)
7854 // add the effect base points modifier from the spell cast (cheat lock / skeleton key etc.)
7855 if (spellEffectInfo.TargetA.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET || spellEffectInfo.TargetB.GetTarget() == TARGET_GAMEOBJECT_ITEM_TARGET)
7856 skillValue += spellEffectInfo.CalcValue();
7857
7858 if (skillValue < reqSkillValue)
7860 }
7861
7862 return SPELL_CAST_OK;
7863 }
7864 case LOCK_KEY_SPELL:
7865 if (m_spellInfo->Id == lockInfo->Index[j])
7866 return SPELL_CAST_OK;
7867 reqKey = true;
7868 break;
7869 }
7870 }
7871
7872 if (reqKey)
7874
7875 return SPELL_CAST_OK;
7876}
7877
7879{
7880 switch (mod)
7881 {
7884 break;
7887 break;
7890 break;
7892 m_spellValue->RadiusMod = (float)value / 10000;
7893 break;
7896 break;
7899 break;
7902 break;
7903 default:
7904 break;
7905 }
7906}
7907
7912
7917
7919{
7920 ASSERT(effIndex < MAX_SPELL_EFFECTS);
7921 if (!m_effectExecuteData[effIndex])
7922 {
7923 m_effectExecuteData[effIndex] = new ByteBuffer(0x20);
7924 // first dword - target counter
7925 *m_effectExecuteData[effIndex] << uint32(1);
7926 }
7927 else
7928 {
7929 // increase target counter by one
7930 uint32 count = (*m_effectExecuteData[effIndex]).read<uint32>(0);
7931 (*m_effectExecuteData[effIndex]).put<uint32>(0, ++count);
7932 }
7933}
7934
7936{
7937 for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
7939}
7940
7942{
7943 sScriptMgr->CreateSpellScripts(m_spellInfo->Id, m_loadedScripts, this);
7944 for (auto itr = m_loadedScripts.begin(); itr != m_loadedScripts.end(); ++itr)
7945 {
7946 TC_LOG_DEBUG("spells", "Spell::LoadScripts: Script `{}` for spell `{}` is loaded now", (*itr)->_GetScriptName()->c_str(), m_spellInfo->Id);
7947 (*itr)->Register();
7948 }
7949}
7950
7952{
7953 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7954 {
7955 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_CAST);
7956 auto hookItrEnd = (*scritr)->BeforeCast.end(), hookItr = (*scritr)->BeforeCast.begin();
7957 for (; hookItr != hookItrEnd; ++hookItr)
7958 (*hookItr).Call(*scritr);
7959
7960 (*scritr)->_FinishScriptCall();
7961 }
7962}
7963
7965{
7966 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7967 {
7968 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_CAST);
7969 auto hookItrEnd = (*scritr)->OnCast.end(), hookItr = (*scritr)->OnCast.begin();
7970 for (; hookItr != hookItrEnd; ++hookItr)
7971 (*hookItr).Call(*scritr);
7972
7973 (*scritr)->_FinishScriptCall();
7974 }
7975}
7976
7978{
7979 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7980 {
7981 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_CAST);
7982 auto hookItrEnd = (*scritr)->AfterCast.end(), hookItr = (*scritr)->AfterCast.begin();
7983 for (; hookItr != hookItrEnd; ++hookItr)
7984 (*hookItr).Call(*scritr);
7985
7986 (*scritr)->_FinishScriptCall();
7987 }
7988}
7989
7991{
7993 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
7994 {
7995 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_CHECK_CAST);
7996 auto hookItrEnd = (*scritr)->OnCheckCast.end(), hookItr = (*scritr)->OnCheckCast.begin();
7997 for (; hookItr != hookItrEnd; ++hookItr)
7998 {
7999 SpellCastResult tempResult = (*hookItr).Call(*scritr);
8000 if (retVal == SPELL_CAST_OK)
8001 retVal = tempResult;
8002 }
8003
8004 (*scritr)->_FinishScriptCall();
8005 }
8006 return retVal;
8007}
8008
8010{
8011 // execute script effect handler hooks and check if effects was prevented
8012 bool preventDefault = false;
8013 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8014 {
8015 (*scritr)->_InitHit();
8016
8018 SpellScriptHookType hookType;
8019 switch (mode)
8020 {
8022 effItr = (*scritr)->OnEffectLaunch.begin();
8023 effEndItr = (*scritr)->OnEffectLaunch.end();
8025 break;
8027 effItr = (*scritr)->OnEffectLaunchTarget.begin();
8028 effEndItr = (*scritr)->OnEffectLaunchTarget.end();
8030 break;
8032 effItr = (*scritr)->OnEffectHit.begin();
8033 effEndItr = (*scritr)->OnEffectHit.end();
8035 break;
8037 effItr = (*scritr)->OnEffectHitTarget.begin();
8038 effEndItr = (*scritr)->OnEffectHitTarget.end();
8040 break;
8041 default:
8042 ABORT();
8043 return false;
8044 }
8045 (*scritr)->_PrepareScriptCall(hookType);
8046 for (; effItr != effEndItr; ++effItr)
8047 // effect execution can be prevented
8048 if (!(*scritr)->_IsEffectPrevented(effIndex) && (*effItr).IsEffectAffected(m_spellInfo, effIndex))
8049 (*effItr).Call(*scritr, effIndex);
8050
8051 if (!preventDefault)
8052 preventDefault = (*scritr)->_IsDefaultEffectPrevented(effIndex);
8053
8054 (*scritr)->_FinishScriptCall();
8055 }
8056 return preventDefault;
8057}
8058
8060{
8061 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8062 {
8063 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_EFFECT_SUCCESSFUL_DISPEL);
8064 auto hookItrEnd = (*scritr)->OnEffectSuccessfulDispel.end(), hookItr = (*scritr)->OnEffectSuccessfulDispel.begin();
8065 for (; hookItr != hookItrEnd; ++hookItr)
8066 hookItr->Call(*scritr, effIndex);
8067
8068 (*scritr)->_FinishScriptCall();
8069 }
8070}
8071
8073{
8074 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8075 {
8076 (*scritr)->_InitHit();
8077 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_BEFORE_HIT);
8078 auto hookItrEnd = (*scritr)->BeforeHit.end(), hookItr = (*scritr)->BeforeHit.begin();
8079 for (; hookItr != hookItrEnd; ++hookItr)
8080 (*hookItr).Call(*scritr, missInfo);
8081
8082 (*scritr)->_FinishScriptCall();
8083 }
8084}
8085
8087{
8088 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8089 {
8090 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_HIT);
8091 auto hookItrEnd = (*scritr)->OnHit.end(), hookItr = (*scritr)->OnHit.begin();
8092 for (; hookItr != hookItrEnd; ++hookItr)
8093 (*hookItr).Call(*scritr);
8094
8095 (*scritr)->_FinishScriptCall();
8096 }
8097}
8098
8100{
8101 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8102 {
8103 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_AFTER_HIT);
8104 auto hookItrEnd = (*scritr)->AfterHit.end(), hookItr = (*scritr)->AfterHit.begin();
8105 for (; hookItr != hookItrEnd; ++hookItr)
8106 (*hookItr).Call(*scritr);
8107
8108 (*scritr)->_FinishScriptCall();
8109 }
8110}
8111
8112void Spell::CallScriptObjectAreaTargetSelectHandlers(std::list<WorldObject*>& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType)
8113{
8114 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8115 {
8116 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_AREA_TARGET_SELECT);
8117 auto hookItrEnd = (*scritr)->OnObjectAreaTargetSelect.end(), hookItr = (*scritr)->OnObjectAreaTargetSelect.begin();
8118 for (; hookItr != hookItrEnd; ++hookItr)
8119 if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
8120 hookItr->Call(*scritr, targets);
8121
8122 (*scritr)->_FinishScriptCall();
8123 }
8124}
8125
8127{
8128 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8129 {
8130 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_OBJECT_TARGET_SELECT);
8131 auto hookItrEnd = (*scritr)->OnObjectTargetSelect.end(), hookItr = (*scritr)->OnObjectTargetSelect.begin();
8132 for (; hookItr != hookItrEnd; ++hookItr)
8133 if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
8134 hookItr->Call(*scritr, target);
8135
8136 (*scritr)->_FinishScriptCall();
8137 }
8138}
8139
8141{
8142 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8143 {
8144 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_DESTINATION_TARGET_SELECT);
8145 auto hookItrEnd = (*scritr)->OnDestinationTargetSelect.end(), hookItr = (*scritr)->OnDestinationTargetSelect.begin();
8146 for (; hookItr != hookItrEnd; ++hookItr)
8147 if (hookItr->IsEffectAffected(m_spellInfo, effIndex) && targetType.GetTarget() == hookItr->GetTarget())
8148 hookItr->Call(*scritr, target);
8149
8150 (*scritr)->_FinishScriptCall();
8151 }
8152}
8153
8155{
8156 auto allEffectTargetScriptsAreShared = []<typename HookType>(HookList<HookType>& hooks, SpellInfo const* spellInfo, uint32 effIndex, uint32 effIndexToCheck)
8157 {
8158 for (HookType& hook : hooks)
8159 {
8160 if (!hook.IsEffectAffected(spellInfo, effIndex))
8161 continue;
8162
8163 bool otherEffectHasSameTargetFunction = std::ranges::any_of(hooks, [&](HookType& other)
8164 {
8165 return other.IsEffectAffected(spellInfo, effIndexToCheck) && hook.HasSameTargetFunctionAs(other);
8166 });
8167 if (!otherEffectHasSameTargetFunction)
8168 return false;
8169 }
8170
8171 return true;
8172 };
8173
8174 for (SpellScript* script : m_loadedScripts)
8175 {
8176 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
8177 return false;
8178
8179 if (!allEffectTargetScriptsAreShared(script->OnObjectTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
8180 return false;
8181
8182 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndex, effIndexToCheck))
8183 return false;
8184
8185 if (!allEffectTargetScriptsAreShared(script->OnObjectAreaTargetSelect, m_spellInfo, effIndexToCheck, effIndex))
8186 return false;
8187 }
8188 return true;
8189}
8190
8191bool Spell::CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const* triggeredByAura) const
8192{
8193 bool only_on_caster = (triggeredByAura && triggeredByAura->HasAttribute(SPELL_ATTR4_PROC_ONLY_ON_CASTER));
8194 // If triggeredByAura has SPELL_ATTR4_PROC_ONLY_ON_CASTER then it can only proc on a cast spell with TARGET_UNIT_CASTER
8195 for (SpellEffectInfo const& spellEffectInfo : m_spellInfo->GetEffects())
8196 {
8197 if ((effMask & (1 << spellEffectInfo.EffectIndex)) && (!only_on_caster || (spellEffectInfo.TargetA.GetTarget() == TARGET_UNIT_CASTER)))
8198 return true;
8199 }
8200 return false;
8201}
8202
8204{
8205 Unit* unitCaster = m_caster->ToUnit();
8206 if (!unitCaster)
8207 return;
8208
8209 // handle SPELL_AURA_ADD_TARGET_TRIGGER auras:
8210 // save auras which were present on spell caster on cast, to prevent triggered auras from affecting caster
8211 // and to correctly calculate proc chance when combopoints are present
8212 Unit::AuraEffectList const& targetTriggers = unitCaster->GetAuraEffectsByType(SPELL_AURA_ADD_TARGET_TRIGGER);
8213 for (AuraEffect const* aurEff : targetTriggers)
8214 {
8215 if (!aurEff->IsAffectingSpell(m_spellInfo))
8216 continue;
8217
8218 SpellInfo const* auraSpellInfo = aurEff->GetSpellInfo();
8219 if (SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(aurEff->GetSpellEffectInfo().TriggerSpell))
8220 {
8221 // calculate the chance using spell base amount, because aura amount is not updated on combo-points change
8222 // this possibly needs fixing
8223 int32 auraBaseAmount = aurEff->GetBaseAmount();
8224 // proc chance is stored in effect amount
8225 int32 chance = unitCaster->CalculateSpellDamage(aurEff->GetSpellEffectInfo(), &auraBaseAmount);
8226 chance *= aurEff->GetBase()->GetStackAmount();
8227
8228 // build trigger and add to the list
8229 m_hitTriggerSpells.emplace_back(spellInfo, auraSpellInfo, chance);
8230 }
8231 }
8232}
8233
8234// Global cooldowns management
8236{
8237 MIN_GCD = 1000,
8238 MAX_GCD = 1500
8240
8242{
8243 // Only players or controlled units have global cooldown
8244 if (caster->GetTypeId() != TYPEID_PLAYER && (caster->GetTypeId() != TYPEID_UNIT || !const_cast<WorldObject*>(caster)->ToCreature()->GetCharmInfo()))
8245 return false;
8246
8247 return true;
8248}
8249
8251{
8253 return false;
8254
8256}
8257
8259{
8261 return;
8262
8264 return;
8265
8268 return;
8269
8270 // Global cooldown can't leave range 1..1.5 secs
8272
8273 // gcd modifier auras are applied only to own spells and only players have such mods
8274 if (Player* modOwner = m_caster->GetSpellModOwner())
8275 modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_GLOBAL_COOLDOWN, gcd, this);
8276
8277 // Apply haste rating
8281 {
8282 gcd = int32(float(gcd) * m_caster->GetFloatValue(UNIT_MOD_CAST_SPEED));
8283 RoundToInterval<int32>(gcd, MIN_GCD, MAX_GCD);
8284 }
8285
8286 if (gcd)
8288}
8289
8291{
8293 return;
8294
8296 return;
8297
8298 // Cancel global cooldown when interrupting current cast
8300 return;
8301
8303}
8304
8305std::string Spell::GetDebugInfo() const
8306{
8307 std::stringstream sstr;
8308 sstr << std::boolalpha
8309 << "Id: " << GetSpellInfo()->Id << " Name: '" << GetSpellInfo()->SpellName[sWorld->GetDefaultDbcLocale()] << "' OriginalCaster: " << m_originalCasterGUID.ToString()
8310 << " State: " << getState();
8311 return sstr.str();
8312}
8313
8318
8319void Spell::CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)
8320{
8321 for (auto scritr = m_loadedScripts.begin(); scritr != m_loadedScripts.end(); ++scritr)
8322 {
8323 (*scritr)->_PrepareScriptCall(SPELL_SCRIPT_HOOK_ON_RESIST_ABSORB_CALCULATION);
8324 auto hookItrEnd = (*scritr)->OnCalculateResistAbsorb.end(), hookItr = (*scritr)->OnCalculateResistAbsorb.begin();
8325 for (; hookItr != hookItrEnd; ++hookItr)
8326 hookItr->Call(*scritr, damageInfo, resistAmount, absorbAmount);
8327
8328 (*scritr)->_FinishScriptCall();
8329 }
8330}
8331
8332namespace Trinity
8333{
8334
8336 SpellTargetCheckTypes selectionType, ConditionContainer const* condList) : _caster(caster), _referer(referer), _spellInfo(spellInfo),
8337 _targetSelectionType(selectionType), _condSrcInfo(nullptr), _condList(condList)
8338{
8339 if (condList)
8340 _condSrcInfo = std::make_unique<ConditionSourceInfo>(nullptr, caster);
8341}
8342
8346
8348{
8349 if (_spellInfo->CheckTarget(_caster, target, true) != SPELL_CAST_OK)
8350 return false;
8351
8352 Unit* unitTarget = target->ToUnit();
8353 if (Corpse* corpseTarget = target->ToCorpse())
8354 {
8355 // use owner for party/assistance checks
8356 if (Player* owner = ObjectAccessor::FindPlayer(corpseTarget->GetOwnerGUID()))
8357 unitTarget = owner;
8358 else
8359 return false;
8360 }
8361
8362 Unit* refUnit = _referer->ToUnit();
8363 if (unitTarget)
8364 {
8365 // do only faction checks here
8366 switch (_targetSelectionType)
8367 {
8368 case TARGET_CHECK_ENEMY:
8369 if (unitTarget->IsTotem())
8370 return false;
8371 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8372 if (!target->IsCorpse() && !_caster->IsValidAttackTarget(unitTarget, _spellInfo))
8373 return false;
8374 break;
8375 case TARGET_CHECK_ALLY:
8376 if (unitTarget->IsTotem())
8377 return false;
8378 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8379 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
8380 return false;
8381 break;
8382 case TARGET_CHECK_PARTY:
8383 if (!refUnit)
8384 return false;
8385 if (unitTarget->IsTotem())
8386 return false;
8387 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8388 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
8389 return false;
8390 if (!refUnit->IsInPartyWith(unitTarget))
8391 return false;
8392 break;
8394 if (!refUnit)
8395 return false;
8396 if (refUnit->GetClass() != unitTarget->GetClass())
8397 return false;
8398 [[fallthrough]];
8399 case TARGET_CHECK_RAID:
8400 if (!refUnit)
8401 return false;
8402 if (unitTarget->IsTotem())
8403 return false;
8404 // TODO: restore IsValidAttackTarget for corpses using corpse owner (faction, etc)
8405 if (!target->IsCorpse() && !_caster->IsValidAssistTarget(unitTarget, _spellInfo))
8406 return false;
8407 if (!refUnit->IsInRaidWith(unitTarget))
8408 return false;
8409 break;
8410 default:
8411 break;
8412 }
8413 }
8414
8415 if (!_condSrcInfo)
8416 return true;
8417 _condSrcInfo->mConditionTargets[0] = target;
8418 return sConditionMgr->IsObjectMeetToConditions(*_condSrcInfo, *_condList);
8419}
8420
8422 SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8423 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(caster) { }
8424
8426{
8427 float dist = target->GetDistance(*_position);
8428 if (dist < _range && WorldObjectSpellTargetCheck::operator ()(target))
8429 {
8430 _range = dist;
8431 return true;
8432 }
8433 return false;
8434}
8435
8437 WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8438 : WorldObjectSpellTargetCheck(caster, referer, spellInfo, selectionType, condList), _range(range), _position(position) { }
8439
8441{
8442 if (target->ToGameObject())
8443 {
8444 // isInRange including the dimension of the GO
8446 if (!isInRange)
8447 return false;
8448 }
8449 else
8450 {
8451 bool isInsideCylinder = target->IsWithinDist2d(_position, _range) && std::abs(target->GetPositionZ() - _position->GetPositionZ()) <= _range;
8452 if (!isInsideCylinder)
8453 return false;
8454 }
8455
8457}
8458
8460 SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8461 : WorldObjectSpellAreaTargetCheck(range, caster, caster, caster, spellInfo, selectionType, condList), _coneAngle(coneAngle) { }
8462
8464{
8466 {
8467 if (!_caster->isInBack(target, _coneAngle))
8468 return false;
8469 }
8471 {
8472 if (!_caster->HasInLine(target, target->GetCombatReach(), _caster->GetCombatReach()))
8473 return false;
8474 }
8475 else
8476 {
8477 if (!_caster->isInFront(target, _coneAngle))
8478 return false;
8479 }
8481}
8482
8483WorldObjectSpellTrajTargetCheck::WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList)
8484 : WorldObjectSpellTargetCheck(caster, caster, spellInfo, selectionType, condList), _range(range), _position(position) { }
8485
8487{
8488 // return all targets on missile trajectory (0 - size of a missile)
8489 if (!_caster->HasInLine(target, target->GetCombatReach(), TRAJECTORY_MISSILE_SIZE))
8490 return false;
8491
8492 if (target->GetExactDist2d(_position) > _range)
8493 return false;
8494
8496}
8497
8498} //namespace Trinity
8499
8501{
8502 if (target)
8503 {
8504 if (Unit* unitTarget = target->ToUnit())
8505 {
8506 Targets.emplace();
8507 Targets->SetUnitTarget(unitTarget);
8508 }
8509 else if (GameObject* goTarget = target->ToGameObject())
8510 {
8511 Targets.emplace();
8512 Targets->SetGOTarget(goTarget);
8513 }
8514 // error when targeting anything other than units and gameobjects
8515 }
8516 else
8517 Targets.emplace(); // nullptr is allowed
8518}
#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:71
#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:360
@ ITEM_ENCHANTMENT_TYPE_PRISMATIC_SOCKET
Definition DBCEnums.h:361
Difficulty
Definition DBCEnums.h:279
#define MAX_EFFECT_MASK
Definition DBCEnums.h:387
@ 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:392
#define MAX_SPELL_REAGENTS
Definition DBCEnums.h:388
@ AREA_FLAG_NO_FLY_ZONE
Definition DBCEnums.h:275
#define MAX_SPELL_EFFECTS
Definition DBCEnums.h:386
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:577
std::vector< ItemPosCount > ItemPosCountVec
Definition Player.h:632
@ PLAYER_ALLOW_ONLY_ABILITY
Definition Player.h:369
@ RUNE_MISS_COOLDOWN
Definition Player.h:285
@ CHEAT_COOLDOWN
Definition Player.h:817
@ CHEAT_POWER
Definition Player.h:818
@ CHEAT_CASTTIME
Definition Player.h:816
RuneType
Definition Player.h:289
@ RUNE_UNHOLY
Definition Player.h:291
@ RUNE_DEATH
Definition Player.h:293
@ NUM_RUNE_TYPES
Definition Player.h:294
@ RUNE_FROST
Definition Player.h:292
@ RUNE_BLOOD
Definition Player.h:290
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_RITUAL
@ 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
@ 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:8241
float tangent(float x)
Definition Spell.cpp:1670
void FillSpellCastFailedArgs(T &packet, uint8 castId, SpellInfo const *spellInfo, SpellCastResult result, SpellCustomErrors customError, uint32 *param1, uint32 *param2)
Definition Spell.cpp:4029
SpellEffectHandlerFn SpellEffectHandlers[TOTAL_SPELL_EFFECTS]
GCDLimits
Definition Spell.cpp:8236
@ MIN_GCD
Definition Spell.cpp:8237
@ MAX_GCD
Definition Spell.cpp:8238
@ 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:784
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:9978
@ UNIT_MASK_PUPPET
Definition Unit.h:384
@ JUST_DIED
Definition Unit.h:226
CurrentSpellTypes
Definition Unit.h:619
@ CURRENT_CHANNELED_SPELL
Definition Unit.h:622
@ CURRENT_GENERIC_SPELL
Definition Unit.h:621
@ CURRENT_MELEE_SPELL
Definition Unit.h:620
@ CURRENT_AUTOREPEAT_SPELL
Definition Unit.h:623
@ UNIT_STATE_ATTACK_PLAYER
Definition Unit.h:248
@ UNIT_STATE_ROOT
Definition Unit.h:244
@ UNIT_STATE_CASTING
Definition Unit.h:249
std::vector< DispelableAura > DispelChargesList
Definition Unit.h:133
@ NULL_BAG
Definition Unit.h:60
@ NULL_SLOT
Definition Unit.h:61
@ NODAMAGE
Definition Unit.h:371
@ SPELL_DIRECT_DAMAGE
Definition Unit.h:368
@ 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:282
int32 GetMaxDuration() const
Definition SpellAuras.h:168
static Aura * TryRefreshStackOrCreate(AuraCreateInfo &createInfo, bool updateEffectMask=true)
void SetStackAmount(uint8 num)
int32 GetDuration() const
Definition SpellAuras.h:173
bool ModStackAmount(int32 num, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT, bool resetPeriodicTimer=true)
int32 CalcMaxDuration() const
Definition SpellAuras.h:170
uint8 GetEffectMask() const
Definition SpellAuras.h:227
void SetDuration(int32 duration, bool withMods=false)
SpellInfo const * GetSpellInfo() const
Definition SpellAuras.h:140
void SetMaxDuration(int32 duration)
Definition SpellAuras.h:169
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:133
void InheritCombatStatesFrom(Unit const *who)
bool HasCorpseFlag(CorpseFlags flags) const
Definition Corpse.h:70
ObjectGuid GetOwnerGUID() const override
Definition Corpse.h:81
virtual void SpellHitTarget(WorldObject *, SpellInfo const *)
Definition CreatureAI.h:146
Loot loot
Definition Creature.h:218
CreatureTemplate const * GetCreatureTemplate() const
Definition Creature.h:195
void SetSpellFocus(Spell const *focusSpell, WorldObject const *target)
CreatureAI * AI() const
Definition Creature.h:163
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:644
void SetSpellCharges(uint8 index, int32 value)
Definition Item.h:180
uint32 GetEnchantmentId(EnchantmentSlot slot) const
Definition Item.h:165
int32 GetSpellCharges(uint8 index=0) const
Definition Item.h:179
bool IsLocked() const
Definition Item.h:116
ItemTemplate const * GetTemplate() const
Definition Item.cpp:541
bool IsPotion() const
Definition Item.h:197
bool IsBroken() const
Definition Item.h:120
bool IsWeaponVellum() const
Definition Item.h:198
bool IsArmorVellum() const
Definition Item.h:199
Player * GetOwner() const
Definition Item.cpp:546
ObjectGuid GetOwnerGUID() const
Definition Item.h:78
uint32 GetCount() const
Definition Item.h:136
uint32 GetMaxStackCount() const
Definition Item.h:138
bool IsFitToSpellRequirements(SpellInfo const *spellInfo) const
Definition Item.cpp:853
bool HaveLootFor(uint32 loot_id) const
Definition LootMgr.h:78
Definition Map.h:302
void AddFarSpellCallback(FarSpellCallback &&callback)
Definition Map.cpp:3518
bool IsDungeon() const
Definition Map.cpp:4231
bool IsBattlegroundOrArena() const
Definition Map.cpp:4272
GameObject * GetGameObject(ObjectGuid const &guid)
Definition Map.cpp:4425
Difficulty GetDifficultyID() const
Definition Map.h:433
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
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:189
bool IsPlayer() const
Definition Object.h:182
PackedGuid const & GetPackGUID() const
Definition Object.h:80
static Unit * ToUnit(Object *o)
Definition Object.h:195
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:241
static GameObject * ToGameObject(Object *o)
Definition Object.h:201
bool IsInWorld() const
Definition Object.h:73
bool IsCorpse() const
Definition Object.h:206
bool IsUnit() const
Definition Object.h:194
TypeID GetTypeId() const
Definition Object.h:93
float GetFloatValue(uint16 index) const
Definition Object.cpp:253
uint32 GetEntry() const
Definition Object.h:81
bool IsCreature() const
Definition Object.h:188
static Corpse * ToCorpse(Object *o)
Definition Object.h:207
bool HasFlag(uint16 index, uint32 flag) const
Definition Object.cpp:800
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
void SetUInt32Value(uint16 index, uint32 value)
Definition Object.cpp:577
static Player * ToPlayer(Object *o)
Definition Object.h:183
Definition Pet.h:40
Player * GetOwner() const
Definition Pet.cpp:1997
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:24329
void SendEquipError(InventoryResult msg, Item const *item1=nullptr, Item const *item2=nullptr, uint32 itemId=0) const
Definition Player.cpp:13070
void SetSpellModTakingSpell(Spell *spell, bool apply)
Definition Player.cpp:20930
bool IsInSameRaidWith(Player const *p) const
Definition Player.cpp:2329
bool HasItemFitToSpellRequirements(SpellInfo const *spellInfo, Item const *ignoreItem=nullptr) const
Definition Player.cpp:23402
uint32 GetFreeInventorySpace() const
Definition Player.cpp:9583
void SetLastUsedRune(RuneType type)
Definition Player.h:2199
bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const override
Definition Player.cpp:1894
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
uint16 GetSkillValue(uint32 skill) const
Definition Player.cpp:5906
Item * GetItemByEntry(uint32 entry) const
Definition Player.cpp:12459
void UpdatePotionCooldown(Spell *spell=nullptr)
Definition Player.cpp:21698
bool CanTameExoticPets() const
Definition Player.h:1889
bool HasItemCount(uint32 item, uint32 count=1, bool inBankAlso=false) const
Definition Player.cpp:9761
bool CanUseBattlegroundObject(GameObject *gameobject) const
Definition Player.cpp:24168
bool InBattleground() const
Definition Player.h:1969
void DurabilityPointLossForEquipSlot(EquipmentSlots slot)
Definition Player.cpp:4673
PetStable * GetPetStable()
Definition Player.h:1045
bool IsLoading() const override
Definition Player.cpp:16881
Pet * GetPet() const
Definition Player.cpp:20284
bool HasItemTotemCategory(uint32 TotemCategory) const
Definition Player.cpp:10000
uint8 GetRunesState() const
Definition Player.h:2191
bool GetCommandStatus(uint32 command) const
Definition Player.h:1006
void RestoreBaseRune(uint8 index)
Definition Player.cpp:24378
bool HasSummonPending() const
Definition Player.cpp:23277
WorldSession * GetSession() const
Definition Player.h:1705
void CastItemCombatSpell(DamageInfo const &damageInfo)
Definition Player.cpp:7661
bool CanNoReagentCast(SpellInfo const *spellInfo) const
Definition Player.cpp:23455
uint32 DestroyItemCount(uint32 item, uint32 count, bool update, bool unequip_check=false)
Definition Player.cpp:12207
uint32 GetRuneCooldown(uint8 index) const
Definition Player.h:2194
Battleground * GetBattleground() const
Definition Player.cpp:23024
TradeData * GetTradeData() const
Definition Player.h:1193
RuneType GetCurrentRune(uint8 index) const
Definition Player.h:2193
bool IsGameMaster() const
Definition Player.h:976
void ApplySpellMod(uint32 spellId, SpellModOp op, T &basevalue, Spell *spell=nullptr) const
Definition Player.cpp:20805
void SendTameFailure(uint8 result)
Definition Player.cpp:2809
uint32 GetRuneBaseCooldown(uint8 index) const
Definition Player.h:2195
Player * GetSelectedPlayer() const
Definition Player.cpp:22382
Item * GetWeaponForAttack(WeaponAttackType attackType, bool useable=false) const
Definition Player.cpp:9605
std::unique_ptr< DuelInfo > duel
Definition Player.h:1587
void SendMessageToSet(WorldPacket const *data, bool self) const override
Definition Player.h:1733
Item * GetItemByGuid(ObjectGuid guid) const
Definition Player.cpp:9516
void UpdatePvP(bool state, bool override=false)
Definition Player.cpp:21684
Spell * m_spellModTakingSpell
Definition Player.h:2231
InventoryResult CanStoreNewItem(uint8 bag, uint8 slot, ItemPosCountVec &dest, uint32 item, uint32 count, uint32 *no_space_count=nullptr) const
Definition Player.cpp:9987
uint32 GetLastPotionId() const
Definition Player.h:1530
RuneType GetBaseRune(uint8 index) const
Definition Player.h:2192
InstancePlayerBind * GetBoundInstance(uint32 mapid, Difficulty difficulty, bool withExpired=false)
Definition Player.cpp:18567
ProcReflectDelayed(Unit *owner, ObjectGuid casterGuid)
Definition Spell.cpp:2133
bool Execute(uint64, uint32) override
Definition Spell.cpp:2135
ObjectGuid _casterGuid
Definition Spell.cpp:2153
void SetPitch(float pitch)
SpellDestination const * GetSrc() const
Definition Spell.cpp:379
void SetItemTarget(Item *item)
Definition Spell.cpp:350
void RemoveObjectTarget()
Definition Spell.cpp:343
ObjectGuid m_objectTargetGUID
WorldObject * GetObjectTarget() const
Definition Spell.cpp:333
ObjectGuid GetUnitTargetGUID() const
Definition Spell.cpp:265
void ModDst(Position const &pos)
Definition Spell.cpp:458
GameObject * GetGOTarget() const
Definition Spell.cpp:299
void SetTradeItemTarget(Player *caster)
Definition Spell.cpp:361
SpellDestination m_dst
bool HasSrc() const
Definition Spell.cpp:475
bool HasTraj() const
Corpse * GetCorpseTarget() const
Definition Spell.cpp:325
void SetDst(float x, float y, float z, float orientation, uint32 mapId=MAPID_INVALID)
Definition Spell.cpp:428
void SetSpeed(float speed)
void SetSrc(float x, float y, float z)
Definition Spell.cpp:389
void SetTargetFlag(SpellCastTargetFlags flag)
SpellDestination const * GetDst() const
Definition Spell.cpp:418
void SetGOTarget(GameObject *target)
Definition Spell.cpp:307
std::string m_strTarget
void UpdateTradeSlotItem()
Definition Spell.cpp:370
SpellDestination m_src
ObjectGuid GetCorpseTargetGUID() const
Definition Spell.cpp:317
ObjectGuid GetObjectTargetGUID() const
Definition Spell.cpp:338
void SetUnitTarget(Unit *target)
Definition Spell.cpp:281
void Read(ByteBuffer &data, Unit *caster)
Definition Spell.cpp:171
bool HasDst() const
Definition Spell.cpp:480
ObjectGuid GetItemTargetGUID() const
WorldObject * m_objectTarget
Item * GetItemTarget() const
uint32 GetTargetMask() const
uint32 GetItemTargetEntry() const
Unit * GetUnitTarget() const
Definition Spell.cpp:273
ObjectGuid m_itemTargetGUID
float GetSpeedXY() const
float GetDist2d() const
void Update(WorldObject *caster)
Definition Spell.cpp:485
void ModSrc(Position const &pos)
Definition Spell.cpp:407
void RemoveDst()
Definition Spell.cpp:470
void Write(WorldPackets::Spells::SpellTargetData &data)
Definition Spell.cpp:224
void RemoveSrc()
Definition Spell.cpp:413
float GetPitch() const
Position const * GetSrcPos() const
Definition Spell.cpp:384
ObjectGuid GetGOTargetGUID() const
Definition Spell.cpp:291
WorldLocation const * GetDstPos() const
Definition Spell.cpp:423
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:7668
Trinity::unique_trackable_ptr< Spell > m_Spell
Definition Spell.cpp:549
std::string GetDebugInfo() const
Definition Spell.cpp:546
void Abort(uint64 e_time) override
Definition Spell.cpp:7661
Trinity::unique_weak_ptr< Spell > GetSpellWeakPtr() const
Definition Spell.cpp:544
SpellEvent(Spell *spell)
Definition Spell.cpp:7556
bool Execute(uint64 e_time, uint32 p_time) override
Definition Spell.cpp:7573
Spell const * GetSpell() const
Definition Spell.cpp:543
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)
bool HasCooldownOnHold(uint32 spellId) const
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 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:6502
SpellInfo const * GetSpellInfo() const
Definition Spell.h:459
float m_damageMultipliers[MAX_SPELL_EFFECTS]
Definition Spell.h:528
bool CanExecuteTriggersOnHit(uint8 effMask, SpellInfo const *triggeredByAura=nullptr) const
Definition Spell.cpp:8191
Unit * m_comboTarget
Definition Spell.h:421
void AssertEffectExecuteData() const
Definition Spell.cpp:7935
bool m_fromClient
Definition Spell.h:401
int8 m_comboPointGain
Definition Spell.h:422
void CallScriptAfterCastHandlers()
Definition Spell.cpp:7977
void AddCorpseTarget(Corpse *target, uint32 effectMask)
Definition Spell.cpp:2335
GameObject * SearchSpellFocus()
Definition Spell.cpp:2048
std::vector< SpellScript * > m_loadedScripts
Definition Spell.h:680
GameObject * gameObjTarget
Definition Spell.h:533
std::pair< float, float > GetMinMaxRange(bool strict) const
Definition Spell.cpp:6556
void PrepareTriggersExecutedOnHit()
Definition Spell.cpp:8203
SpellMissInfo targetMissInfo
Definition Spell.h:537
bool m_referencedFromCurrentSpell
Definition Spell.h:524
bool m_canReflect
Definition Spell.h:504
void PreprocessSpellLaunch(TargetInfo &targetInfo)
Definition Spell.cpp:7733
uint32 m_procVictim
Definition Spell.h:557
uint32 m_hitMask
Definition Spell.h:558
Unit * m_originalCaster
Definition Spell.h:496
SpellCastResult CheckArenaCastRules() const
Definition Spell.cpp:6403
void LoadScripts()
Definition Spell.cpp:7941
uint64 CalculateDelayMomentForDst() const
Definition Spell.cpp:936
void SelectImplicitTrajTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1682
DynObjAura * _dynObjAura
Definition Spell.h:543
void cast(bool skipCheck=false)
Definition Spell.cpp:3354
void SendChannelStart(uint32 duration)
Definition Spell.cpp:4666
bool m_needComboPoints
Definition Spell.h:526
uint64 m_delayStart
Definition Spell.h:519
SpellCastTargets m_targets
Definition Spell.h:409
bool CheckSpellCancelsAuraEffect(AuraType auraType, uint32 *param1) const
Definition Spell.cpp:6333
std::unique_ptr< PathGenerator > m_preGeneratedPath
Definition Spell.h:717
void SendPetCastResult(SpellCastResult result)
Definition Spell.cpp:4177
void CallScriptBeforeHitHandlers(SpellMissInfo missInfo)
Definition Spell.cpp:8072
SpellCastResult CheckRuneCost(uint32 runeCostID) const
Definition Spell.cpp:4886
void InitEffectExecuteData(uint8 effIndex)
Definition Spell.cpp:7918
void SelectExplicitTargets()
Definition Spell.cpp:745
void handle_immediate()
Definition Spell.cpp:3648
void SendSpellGo()
Definition Spell.cpp:4282
TriggerCastFlags _triggeredCastFlags
Definition Spell.h:709
bool IsAutoRepeat() const
Definition Spell.h:428
int32 damage
Definition Spell.h:536
void SetSpellValue(SpellValueMod mod, int32 value)
Definition Spell.cpp:7878
void HandleEffects(Unit *pUnitTarget, Item *pItemTarget, GameObject *pGoTarget, Corpse *pCorpseTarget, SpellEffectInfo const &spellEffectInfo, SpellEffectHandleMode mode)
Definition Spell.cpp:5129
void ExecuteLogEffectSummonObject(uint8 effIndex, WorldObject *obj)
Definition Spell.cpp:4612
void prepareDataForTriggerSystem()
Definition Spell.cpp:2057
SpellEffectHandleMode effectHandleMode
Definition Spell.h:538
void TakeReagents()
Definition Spell.cpp:5023
bool IsValidDeadOrAliveTarget(Unit const *target) const
Definition Spell.cpp:7673
int32 m_channeledDuration
Definition Spell.h:503
SpellCastResult CheckMovement() const
Definition Spell.cpp:6422
bool CheckSpellCancelsPacify(uint32 *param1) const
Definition Spell.cpp:6382
void DoProcessTargetContainer(Container &targetContainer)
Definition Spell.cpp:3634
WorldObject * SearchNearbyTarget(float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer *condList=nullptr)
Definition Spell.cpp:1925
bool IsNeedSendToClient() const
Definition Spell.cpp:7545
bool IsIgnoringCooldowns() const
Definition Spell.cpp:7508
std::vector< TargetInfo > m_UniqueTargetInfo
Definition Spell.h:608
SpellDestination m_destTargets[MAX_SPELL_EFFECTS]
Definition Spell.h:640
void UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo &data)
Definition Spell.cpp:4400
void _handle_finish_phase()
Definition Spell.cpp:3817
void PrepareTargetProcessing()
Definition Spell.cpp:7908
Trinity::unique_weak_ptr< Spell > GetWeakPtr() const
Definition Spell.cpp:8314
void SetExecutedCurrently(bool yes)
Definition Spell.h:444
void AddUnitTarget(Unit *target, uint32 effectMask, bool checkIfValid=true, bool implicit=true, Position const *losPosition=nullptr)
Definition Spell.cpp:2156
void SendSpellStart()
Definition Spell.cpp:4215
uint8 m_delayAtDamageCount
Definition Spell.h:508
void SendChannelUpdate(uint32 time)
Definition Spell.cpp:4646
uint64 m_delayMoment
Definition Spell.h:520
void SendLogExecute()
Definition Spell.cpp:4529
WeaponAttackType m_attackType
Definition Spell.h:500
void _cast(bool skipCheck=false)
Definition Spell.cpp:3371
void SelectImplicitNearbyTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1100
bool IsProcDisabled() const
Definition Spell.cpp:7518
bool m_immediateHandled
Definition Spell.h:521
uint32 m_spellState
Definition Spell.h:705
bool IsFocusDisabled() const
Definition Spell.cpp:7513
union Spell::@266 m_misc
ObjectGuid m_originalCasterGUID
Definition Spell.h:494
WorldObject *const m_caster
Definition Spell.h:490
void TakeAmmo()
Definition Spell.cpp:4852
int64 GetItemTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2402
std::string GetDebugInfo() const
Definition Spell.cpp:8305
bool IsDeletable() const
Definition Spell.h:441
bool UpdateChanneledTargetList()
Definition Spell.cpp:3032
void CleanupTargetList()
Definition Spell.cpp:2122
void TriggerGlobalCooldown()
Definition Spell.cpp:8258
int32 m_timer
Definition Spell.h:706
int32 m_casttime
Definition Spell.h:502
void ExecuteLogEffectOpenLock(uint8 effIndex, Object *obj)
Definition Spell.cpp:4594
void SendMountResult(MountResult result)
Definition Spell.cpp:4198
Item * itemTarget
Definition Spell.h:532
void AddGOTarget(GameObject *target, uint32 effectMask)
Definition Spell.cpp:2261
void HandleThreatSpells()
Definition Spell.cpp:5073
uint8 m_cast_count
Definition Spell.h:400
int32 m_damage
Definition Spell.h:550
std::vector< CorpseTargetInfo > m_UniqueCorpseTargetInfo
Definition Spell.h:635
void ExecuteLogEffectTakeTargetPower(uint8 effIndex, Unit *target, uint32 powerType, uint32 powerTaken, float gainMultiplier)
Definition Spell.cpp:4563
void CancelGlobalCooldown()
Definition Spell.cpp:8290
bool CheckSpellCancelsCharm(uint32 *param1) const
Definition Spell.cpp:6363
void SendInterrupted(SpellCastResult result, Optional< SpellCastResult > resultOther={})
Definition Spell.cpp:4630
uint32 getState() const
Definition Spell.h:356
void SelectImplicitCasterDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1377
bool m_executedCurrently
Definition Spell.h:525
uint32 GetSearcherTypeMask(SpellTargetObjectTypes objType, ConditionContainer *condList)
Definition Spell.cpp:1865
void CallScriptOnCastHandlers()
Definition Spell.cpp:7964
void AddDestTarget(SpellDestination const &dest, uint32 effIndex)
Definition Spell.cpp:2381
void SelectImplicitAreaTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1292
int64 GetGameObjectTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2394
SpellCastResult CheckItems(uint32 *param1, uint32 *param2) const
Definition Spell.cpp:6654
void SelectImplicitCasterObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1565
void SelectImplicitTargetDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1498
void SelectEffectImplicitTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effectMask)
Definition Spell.cpp:963
ByteBuffer * m_effectExecuteData[MAX_SPELL_EFFECTS]
Definition Spell.h:719
void _handle_immediate_phase()
Definition Spell.cpp:3797
void SendSpellCooldown()
Definition Spell.cpp:3855
void CallScriptBeforeCastHandlers()
Definition Spell.cpp:7951
uint8 m_auraScaleMask
Definition Spell.h:716
void HandleLaunchPhase()
Definition Spell.cpp:7682
SpellMissInfo PreprocessSpellHit(Unit *unit, bool scaleAura, TargetInfo &targetInfo)
Definition Spell.cpp:2781
bool UpdatePointers()
Definition Spell.cpp:7315
SpellCustomErrors m_customError
Definition Spell.h:423
bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode)
Definition Spell.cpp:8009
std::vector< GOTargetInfo > m_UniqueGOTargetInfo
Definition Spell.h:618
void DoSpellEffectHit(Unit *unit, SpellEffectInfo const &spellEffectInfo, TargetInfo &targetInfo)
Definition Spell.cpp:2910
void SearchAreaTargets(std::list< WorldObject * > &targets, float range, Position const *position, WorldObject *referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer *condList)
Definition Spell.cpp:1939
HitTriggerSpellList m_hitTriggerSpells
Definition Spell.h:696
int32 m_healing
Definition Spell.h:551
void SetDelayStart(uint64 m_time)
Definition Spell.h:446
SpellEffectInfo const * effectInfo
Definition Spell.h:539
Unit * GetUnitCasterForEffectHandlers() const
Definition Spell.cpp:7551
SpellInfo const * m_triggeredByAuraSpell
Definition Spell.h:714
uint64 handle_delayed(uint64 t_offset)
Definition Spell.cpp:3709
void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const &damageInfo, uint32 &resistAmount, int32 &absorbAmount)
Definition Spell.cpp:8319
uint8 m_channelTargetEffectMask
Definition Spell.h:609
CurrentSpellTypes GetCurrentContainer() const
Definition Spell.cpp:7363
UnitAura * _spellAura
Definition Spell.h:542
Unit * unitTarget
Definition Spell.h:531
void Delayed()
Definition Spell.cpp:7214
SpellSchoolMask m_spellSchoolMask
Definition Spell.h:499
void cancel(SpellCastResult result=SPELL_FAILED_INTERRUPTED, Optional< SpellCastResult > resultOther={})
Definition Spell.cpp:3292
WorldObject * GetCaster() const
Definition Spell.h:457
void ExecuteLogEffectUnsummonObject(uint8 effIndex, WorldObject *obj)
Definition Spell.cpp:4618
SpellEvent * _spellEvent
Definition Spell.h:708
void SelectImplicitChannelTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1044
void SelectSpellTargets()
Definition Spell.cpp:774
void ExecuteLogEffectInterruptCast(uint8 effIndex, Unit *victim, uint32 spellId)
Definition Spell.cpp:4579
SpellCastResult prepare(SpellCastTargets const &targets, AuraEffect const *triggeredByAura=nullptr)
Definition Spell.cpp:3091
void ExecuteLogEffectResurrect(uint8 effIndex, Unit *target)
Definition Spell.cpp:4624
bool IsChannelActive() const
Definition Spell.cpp:7523
~Spell()
Definition Spell.cpp:649
SpellCastResult CheckCasterAuras(uint32 *param1) const
Definition Spell.cpp:6207
void TakePower()
Definition Spell.cpp:4785
SpellCastResult CheckPetCast(Unit *target)
Definition Spell.cpp:6166
void RecalculateDelayMomentForDst()
Definition Spell.cpp:957
Corpse * m_corpseTarget
Definition Spell.h:534
Spell(WorldObject *caster, SpellInfo const *info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID=ObjectGuid::Empty)
Definition Spell.cpp:552
void ReSetTimer()
Definition Spell.h:430
void SelectImplicitChainTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, WorldObject *target, uint32 effMask)
Definition Spell.cpp:1643
SpellCastResult CallScriptCheckCastHandlers()
Definition Spell.cpp:7990
void ExecuteLogEffectCreateItem(uint8 effIndex, uint32 entry)
Definition Spell.cpp:4600
bool IsPositive() const
Definition Spell.cpp:7540
void InitExplicitTargets(SpellCastTargets const &targets)
Definition Spell.cpp:675
WorldLocation * destTarget
Definition Spell.h:535
Spell ** m_selfContainer
Definition Spell.h:469
bool IsTriggered() const
Definition Spell.cpp:7503
SpellCastResult CanOpenLock(SpellEffectInfo const &spellEffectInfo, uint32 lockid, SkillType &skillid, int32 &reqSkillValue, int32 &skillValue)
Definition Spell.cpp:7811
uint8 m_applyMultiplierMask
Definition Spell.h:527
void SetReferencedFromCurrent(bool yes)
Definition Spell.h:442
bool IsDelayableNoMore()
Definition Spell.h:509
void ExecuteLogEffectDestroyItem(uint8 effIndex, uint32 entry)
Definition Spell.cpp:4606
void SelectEffectTypeImplicitTargets(SpellEffectInfo const &spellEffectInfo)
Definition Spell.cpp:1765
bool CheckSpellCancelsStun(uint32 *param1) const
Definition Spell.cpp:6370
void update(uint32 difftime)
Definition Spell.cpp:3863
uint64 GetDelayStart() const
Definition Spell.h:445
bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck)
Definition Spell.cpp:8154
bool CheckSpellCancelsConfuse(uint32 *param1) const
Definition Spell.cpp:6393
Item * m_CastItem
Definition Spell.h:397
void CallScriptSuccessfulDispel(SpellEffIndex effIndex)
Definition Spell.cpp:8059
void DoEffectOnLaunchTarget(TargetInfo &targetInfo, float multiplier, SpellEffectInfo const &spellEffectInfo)
Definition Spell.cpp:7765
uint32 m_castItemEntry
Definition Spell.h:399
uint64 GetDelayMoment() const
Definition Spell.h:447
void AddItemTarget(Item *item, uint32 effectMask)
Definition Spell.cpp:2307
void SelectImplicitDestDestTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:1529
UsedSpellMods m_appliedMods
Definition Spell.h:425
void TakeCastItem()
Definition Spell.cpp:4716
SpellCastResult CheckCast(bool strict, uint32 *param1=nullptr, uint32 *param2=nullptr)
Definition Spell.cpp:5148
void CheckSrc()
Definition Spell.cpp:6496
bool CheckSpellCancelsFear(uint32 *param1) const
Definition Spell.cpp:6388
void SelectImplicitConeTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1240
ObjectGuid m_focusObjectGUID
Definition Spell.h:546
SpellValue *const m_spellValue
Definition Spell.h:492
int32 m_powerCost
Definition Spell.h:501
void SearchChainTargets(std::list< WorldObject * > &targets, uint32 chainTargets, WorldObject *target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, ConditionContainer *condList, bool isChainHeal)
Definition Spell.cpp:1952
bool CheckEffectTarget(Unit const *target, SpellEffectInfo const &spellEffectInfo, Position const *losPosition) const
Definition Spell.cpp:7375
void SendResurrectRequest(Player *target)
Definition Spell.cpp:4698
void SearchTargets(SEARCHER &searcher, uint32 containerMask, WorldObject *referer, Position const *pos, float radius)
Definition Spell.cpp:1901
std::vector< ItemTargetInfo > m_UniqueItemInfo
Definition Spell.h:626
bool IsAutoActionResetSpell() const
Definition Spell.cpp:7528
bool CheckSpellCancelsSilence(uint32 *param1) const
Definition Spell.cpp:6376
void ExecuteLogEffectDurabilityDamage(uint8 effIndex, Unit *victim, int32 itemId, int32 slot)
Definition Spell.cpp:4586
void DelayedChannel()
Definition Spell.cpp:7253
ObjectGuid m_castItemGUID
Definition Spell.h:398
uint32 m_procAttacker
Definition Spell.h:556
int64 GetUnitTargetCountForEffect(SpellEffIndex effect) const
Definition Spell.cpp:2386
SpellCastResult CheckPower() const
Definition Spell.cpp:6614
GameObject * focusObject
Definition Spell.h:547
void CallScriptDestinationTargetSelectHandlers(SpellDestination &target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8140
void ExecuteLogEffectExtraAttacks(uint8 effIndex, Unit *victim, uint32 attCount)
Definition Spell.cpp:4572
void finish(bool ok=true)
Definition Spell.cpp:3943
void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData &data)
Writes miss and hit targets for a SMSG_SPELL_GO packet.
Definition Spell.cpp:4485
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:4150
void UpdateOriginalCasterPointer()
Definition Spell.cpp:7303
SpellInfo const *const m_spellInfo
Definition Spell.h:396
bool HasGlobalCooldown() const
Definition Spell.cpp:8250
uint8 m_runesState
Definition Spell.h:506
void FinishTargetProcessing()
Definition Spell.cpp:7913
void DoTriggersOnSpellHit(Unit *unit, uint8 effMask)
Definition Spell.cpp:2983
void CallScriptOnHitHandlers()
Definition Spell.cpp:8086
SpellCastResult CheckRange(bool strict) const
Definition Spell.cpp:6508
bool m_autoRepeat
Definition Spell.h:505
void CallScriptObjectTargetSelectHandlers(WorldObject *&target, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8126
int32 CalculateDamage(SpellEffectInfo const &spellEffectInfo) const
Definition Spell.cpp:6398
void TakeRunePower(bool didHit)
Definition Spell.cpp:4933
void CallScriptObjectAreaTargetSelectHandlers(std::list< WorldObject * > &targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const &targetType)
Definition Spell.cpp:8112
void SelectImplicitTargetObjectTargets(SpellEffectInfo const &spellEffectInfo, SpellImplicitTargetInfo const &targetType, uint32 effMask)
Definition Spell.cpp:1619
void CallScriptAfterHitHandlers()
Definition Spell.cpp:8099
bool CanAutoCast(Unit *target)
Definition Spell.cpp:6440
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:358
Definition Unit.h:783
int32 ModifyHealth(int32 val)
Definition Unit.cpp:8321
Unit * GetCharmed() const
Definition Unit.h:1269
void ClearUnitState(uint32 f)
Definition Unit.h:891
uint32 GetChannelSpellId() const
Definition Unit.h:1471
void SetLastDamagedTargetGuid(ObjectGuid guid)
Definition Unit.h:1060
int32 ModifyPower(Powers power, int32 val, bool withPowerUpdate=true)
Definition Unit.cpp:8379
bool IsCharmed() const
Definition Unit.h:1293
void RemoveGameObject(GameObject *gameObj, bool del)
Definition Unit.cpp:5161
AuraEffectList const & GetAuraEffectsByType(AuraType type) const
Definition Unit.h:1397
uint32 m_lastSanctuaryTime
Definition Unit.h:1585
void SetChannelObjectGuid(ObjectGuid guid)
Definition Unit.h:1474
Aura * GetAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4462
static uint32 SpellCriticalHealingBonus(Unit const *caster, SpellInfo const *spellProto, uint32 damage, Unit *victim)
Definition Unit.cpp:7240
Pet * ToPet()
Definition Unit.h:1804
bool CanHaveThreatList() const
====================== THREAT & COMBAT ====================
Definition Unit.h:1136
void RemoveAura(AuraApplicationMap::iterator &i, AuraRemoveMode mode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3661
ThreatManager & GetThreatManager()
Definition Unit.h:1169
void SetInCombatWith(Unit *enemy, bool addSecondUnitSuppressed=false)
Definition Unit.h:1160
uint8 GetClass() const
Definition Unit.h:909
void RemoveAurasWithInterruptFlags(uint32 flag, uint32 except=0)
Definition Unit.cpp:4045
AuraApplication * GetAuraApplication(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraApplication *except=nullptr) const
Definition Unit.cpp:4443
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:1006
void StopMoving(bool force=false)
Definition Unit.cpp:10289
bool IsInDisallowedMountForm() const
Definition Unit.cpp:8915
virtual bool IsImmunedToSpell(SpellInfo const *spellInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7631
void DealSpellDamage(SpellNonMeleeDamage const *damageInfo, bool durabilityLoss)
Definition Unit.cpp:1120
bool IsPvP() const
Definition Unit.h:1002
bool haveOffhandWeapon() const
Definition Unit.cpp:518
MotionMaster * GetMotionMaster()
Definition Unit.h:1683
bool IsPet() const
Definition Unit.h:898
Powers GetPowerType() const
Definition Unit.h:945
bool HasUnitFlag(UnitFlags flags) const
Definition Unit.h:967
bool CanProc() const
Definition Unit.h:1742
ObjectGuid GetCharmedGUID() const
Definition Unit.h:1268
bool IsNonMeleeSpellCast(bool withDelayed, bool skipChanneled=false, bool skipAutorepeat=false, bool isAutoshoot=false, bool skipInstant=true) const
Definition Unit.cpp:3086
void UpdateInterruptMask()
Definition Unit.cpp:668
void SetChannelSpellId(uint32 channelSpellId)
Definition Unit.h:1472
bool IsFullHealth() const
Definition Unit.h:930
bool HasUnitFlag2(UnitFlags2 flags) const
Definition Unit.h:973
bool HasAuraWithMechanic(uint32 mechanicMask) const
Definition Unit.cpp:4625
bool IsAlive() const
Definition Unit.h:1247
AuraEffect * IsScriptOverriden(SpellInfo const *spell, int32 script) const
Definition Unit.cpp:4662
float GetCombatReach() const override
Definition Unit.h:853
int32 HealBySpell(HealInfo &healInfo, bool critical=false)
Definition Unit.cpp:6360
GameObject * GetGameObject(uint32 spellId) const
Definition Unit.cpp:5100
float SpellCritChanceTaken(Unit const *caster, SpellInfo const *spellInfo, SpellSchoolMask schoolMask, float doneChance, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:7009
void SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const *log)
Definition Unit.cpp:5199
UnitFlags GetUnitFlags() const
Definition Unit.h:966
bool IsStandState() const
Definition Unit.cpp:10334
CharmInfo * GetCharmInfo()
Definition Unit.h:1300
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1273
bool HasAura(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, ObjectGuid itemCasterGUID=ObjectGuid::Empty, uint8 reqEffMask=0) const
Definition Unit.cpp:4558
Unit * GetMeleeHitRedirectTarget(Unit *victim, SpellInfo const *spellInfo=nullptr)
Definition Unit.cpp:6161
std::map< uint8, AuraApplication * > VisibleAuraMap
Definition Unit.h:808
virtual bool IsAffectedByDiminishingReturns() const
Definition Unit.h:835
float SpellCritChanceDone(SpellInfo const *spellInfo, SpellSchoolMask schoolMask, WeaponAttackType attackType=BASE_ATTACK, bool isPeriodic=false) const
Definition Unit.cpp:6955
bool IsOnVehicle(Unit const *vehicle) const
Definition Unit.cpp:11792
bool IsCharmedOwnedByPlayerOrPlayer() const
Definition Unit.h:1274
void SetLastManaUse(uint32 spellCastTime)
Definition Unit.h:1646
virtual bool IsImmunedToSpellEffect(SpellInfo const *spellInfo, SpellEffectInfo const &spellEffectInfo, WorldObject const *caster, bool requireImmunityPurgesEffectAttribute=false) const
Definition Unit.cpp:7751
bool IsInFlight() const
Definition Unit.h:1133
bool IsAIEnabled() const
Definition Unit.h:812
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:5218
uint32 GetMaxPower(Powers power) const
Definition Unit.h:950
bool IsSummon() const
Definition Unit.h:896
bool IsInWater() const
Definition Unit.cpp:3185
uint32 GetHealth() const
Definition Unit.h:927
void RemoveDynObject(uint32 spellId)
Definition Unit.cpp:5077
void GetDispellableAuraList(WorldObject const *caster, uint32 dispelMask, DispelChargesList &dispelList, bool isReflect=false) const
Definition Unit.cpp:4486
bool isMoving() const
Definition Unit.h:1775
VisibleAuraMap const & GetVisibleAuras() const
Definition Unit.h:1587
void EngageWithTarget(Unit *who)
Definition Unit.cpp:8232
int32 GetTotalAuraModifier(AuraType auraType) const
Definition Unit.cpp:4815
bool IsMounted() const
Definition Unit.h:1027
bool ApplyDiminishingToDuration(SpellInfo const *auraSpellInfo, bool triggered, int32 &duration, WorldObject *caster, DiminishingLevels previousLevel) const
Definition Unit.cpp:8798
void RemoveAurasDueToSpell(uint32 spellId, ObjectGuid casterGUID=ObjectGuid::Empty, uint8 reqEffMask=0, AuraRemoveMode removeMode=AURA_REMOVE_BY_DEFAULT)
Definition Unit.cpp:3807
Unit * GetVictim() const
Definition Unit.h:873
bool IsImmunedToDamage(SpellSchoolMask meleeSchoolMask) const
Definition Unit.cpp:7579
DeathState getDeathState() const
Definition Unit.h:1251
ObjectGuid GetChannelObjectGuid() const
Definition Unit.h:1473
ObjectGuid GetTransGUID() const override
Definition Unit.cpp:11827
bool IsCritter() const
Definition Unit.h:1131
int32 CalculateAOEAvoidance(int32 damage, uint32 schoolMask, ObjectGuid const &casterGuid) const
Definition Unit.cpp:12062
bool HasUnitState(const uint32 f) const
Definition Unit.h:890
bool IsInRaidWith(Unit const *unit) const
Definition Unit.cpp:11863
DynamicObject * GetDynObject(uint32 spellId) const
Definition Unit.cpp:5061
float GetMeleeRange(Unit const *target) const
Definition Unit.cpp:642
void SetStandState(UnitStandStateType state)
Definition Unit.cpp:10340
SpellHistory * GetSpellHistory()
Definition Unit.h:1497
void IncrDiminishing(SpellInfo const *auraSpellInfo, bool triggered)
Definition Unit.cpp:8787
bool IsControlledByPlayer() const
Definition Unit.h:1271
DiminishingLevels GetDiminishing(DiminishingGroup group) const
Definition Unit.cpp:8774
ObjectGuid GetCharmerGUID() const
Definition Unit.h:1265
virtual void setDeathState(DeathState s)
Definition Unit.cpp:8668
uint32 GetPower(Powers power) const
Definition Unit.h:948
CombatManager & GetCombatManager()
Definition Unit.h:1144
bool HasAuraTypeWithAffectMask(AuraType auraType, SpellInfo const *affectedSpell) const
Definition Unit.cpp:4587
std::list< AuraEffect * > AuraEffectList
Definition Unit.h:801
void RemoveMovementImpairingAuras(bool withRoot)
Definition Unit.cpp:4092
bool IsSpiritHealer() const
Definition Unit.h:1124
bool IsTotem() const
Definition Unit.h:900
Vehicle * GetVehicleKit() const
Definition Unit.h:1751
Guardian * GetGuardianPet() const
Definition Unit.cpp:5836
void resetAttackTimer(WeaponAttackType type=BASE_ATTACK)
Definition Unit.cpp:606
virtual bool IsEngaged() const
Definition Unit.h:1140
bool AttackStop()
Definition Unit.cpp:5587
bool IsInPartyWith(Unit const *unit) const
Definition Unit.cpp:11844
static void DealDamageMods(Unit const *victim, uint32 &damage, uint32 *absorb)
Definition Unit.cpp:714
ObjectGuid GetTarget() const
Definition Unit.h:1813
uint8 GetLevel() const
Definition Unit.h:903
bool IsInCombat() const
Definition Unit.h:1158
bool IsWalking() const
Definition Unit.h:1232
float GetTotalAttackPowerValue(WeaponAttackType attType) const
Definition Unit.cpp:9289
ObjectGuid GetPetGUID() const
Definition Unit.h:1260
Spell * GetCurrentSpell(CurrentSpellTypes spellType) const
Definition Unit.h:1489
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:3102
uint32 GetPhaseMask() const
Definition Object.h:370
bool IsWithinDist2d(float x, float y, float dist) const
Definition Object.cpp:1178
virtual void SendMessageToSet(WorldPacket const *data, bool self) const
Definition Object.cpp:1784
Map * GetMap() const
Definition Object.h:451
std::string const & GetNameForLocaleIdx(LocaleConstant) const override
Definition Object.h:387
virtual float GetCollisionHeight() const
Definition Object.h:585
Unit * GetCharmerOrOwner() const
Definition Object.cpp:2186
void SendSpellMiss(Unit *target, uint32 spellID, SpellMissInfo missInfo)
Definition Object.cpp:2621
bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1207
void GetClosePoint(float &x, float &y, float &z, float size, float distance2d=0, float relAngle=0) const
Definition Object.cpp:3245
float GetMapHeight(float x, float y, float z, bool vmap=true, float distanceToSearch=50.0f) const
Definition Object.cpp:3605
SpellCastResult CastSpell(CastSpellTargetArg const &targets, uint32 spellId, CastSpellExtraArgs const &args={ })
Definition Object.cpp:2833
bool IsValidAttackTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:2857
float GetTransOffsetX() const
Definition Object.h:567
void MovePositionToFirstCollision(Position &pos, float dist, float angle)
Definition Object.cpp:3324
bool GetDistanceOrder(WorldObject const *obj1, WorldObject const *obj2, bool is3D=true) const
Definition Object.cpp:1261
bool isInFront(WorldObject const *target, float arc=float(M_PI)) const
Definition Object.cpp:1367
bool IsOutdoors() const
Definition Object.h:379
int32 ModSpellDuration(SpellInfo const *spellInfo, WorldObject const *target, int32 duration, bool positive, uint32 effectMask) const
Definition Object.cpp:2321
float GetTransOffsetY() const
Definition Object.h:568
float GetTransOffsetZ() const
Definition Object.h:569
bool IsWithinLOSInMap(WorldObject const *obj, LineOfSightChecks checks=LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags=VMAP::ModelIgnoreFlags::Nothing) const
Definition Object.cpp:1227
virtual ObjectGuid GetTransGUID() const
Definition Object.cpp:3578
bool isInBack(WorldObject const *target, float arc=float(M_PI)) const
Definition Object.cpp:1372
Player * GetSpellModOwner() const
Definition Object.cpp:2224
Player * GetCharmerOrOwnerPlayerOrPlayerItself() const
Definition Object.cpp:2204
bool IsWithinDistInMap(WorldObject const *obj, float dist2compare, bool is3D=true, bool incOwnRadius=true, bool incTargetRadius=true) const
Definition Object.cpp:1193
bool IsValidAssistTarget(WorldObject const *target, SpellInfo const *bySpell=nullptr) const
Definition Object.cpp:3001
EventProcessor m_Events
Definition Object.h:593
float GetVisibilityRange() const
Definition Object.cpp:1493
float GetSpellMinRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition Object.cpp:2268
SpellMissInfo SpellHitResult(Unit *victim, SpellInfo const *spellInfo, bool canReflect=false) const
Definition Object.cpp:2572
float GetDistance(WorldObject const *obj) const
Definition Object.cpp:1124
uint32 GetAreaId() const
Definition Object.h:376
float GetTransOffsetO() const
Definition Object.h:570
bool IsWithinDist(WorldObject const *obj, float dist2compare, bool is3D=true) const
Definition Object.cpp:1188
uint32 GetZoneId() const
Definition Object.h:375
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition Object.h:377
float GetSpellMaxRangeForTarget(Unit const *target, SpellInfo const *spellInfo) const
Definition Object.cpp:2254
bool IsFriendlyTo(WorldObject const *target) const
Definition Object.cpp:2802
virtual float GetCombatReach() const
Definition Object.h:360
int32 CalculateSpellDamage(SpellEffectInfo const &spellEffectInfo, int32 const *basePoints=nullptr) const
Definition Object.cpp:2249
void ModSpellDurationTime(SpellInfo const *spellInfo, int32 &durationTime, Spell *spell=nullptr) const
Definition Object.cpp:2437
void push_back(value_type const &value)
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
WorldPacket const * Write() override
LocaleConstant GetSessionDbLocaleIndex() const
uint32 GetRecruiterId() const
uint32 GetAccountId() const
@ SMSG_SPELLLOGEXECUTE
Definition Opcodes.h:617
@ SMSG_SPELL_DELAYED
Definition Opcodes.h:511
@ MSG_CHANNEL_START
Definition Opcodes.h:342
@ MSG_CHANNEL_UPDATE
Definition Opcodes.h:343
@ SMSG_RESURRECT_REQUEST
Definition Opcodes.h:376
#define sWorld
Definition World.h:901
@ RATE_POWER_RUNICPOWER_INCOME
Definition World.h:415
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
uint32 TriggerType
uint32 GetRequiredSkillRank() const
std::array< ItemEffect, MAX_ITEM_PROTO_SPELLS > Effects
uint32 GetBaseItemLevel() const
uint32 DisenchantID
uint32 GetQuality() const
uint32 GetId() const
uint32 GetMaxStackSize() const
SocketColor GetSocketColor(uint32 index) const
uint32 GetDisplayId() const
int32 GetRequiredLevel() const
uint32 GetItemLimitCategory() const
uint32 GetRequiredDisenchantSkill() const
bool HasFlag(ItemFlags flag) const
uint32 GetSubClass() const
::InventoryType GetInventoryType() const
uint32 GetLockID() const
uint32 GetClass() const
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:256
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:524
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:2767
ObjectGuid TargetGUID
Definition Spell.h:632
ObjectGuid TargetGUID
Definition Spell.h:615
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2734
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2757
UnitAura * HitAura
Definition Spell.h:602
SpellInfo const * AuraSpellInfo
Definition Spell.h:599
void PreprocessTarget(Spell *spell) override
Definition Spell.cpp:2410
SpellMissInfo MissCondition
Definition Spell.h:589
int32 AuraBasePoints[MAX_SPELL_EFFECTS]
Definition Spell.h:600
void DoTargetSpellHit(Spell *spell, SpellEffectInfo const &spellEffectInfo) override
Definition Spell.cpp:2460
void DoDamageAndTriggers(Spell *spell) override
Definition Spell.cpp:2489
SpellMissInfo ReflectResult
Definition Spell.h:590
uint64 TimeDelay
Definition Spell.h:585
ObjectGuid TargetGUID
Definition Spell.h:584
Unit * _spellHitTarget
Definition Spell.h:605
int32 AuraDuration
Definition Spell.h:598
DiminishingGroup DRGroup
Definition Spell.h:597
WorldObjectSpellAreaTargetCheck(float range, Position const *position, WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8436
bool operator()(WorldObject *target) const
Definition Spell.cpp:8440
WorldObjectSpellConeTargetCheck(float coneAngle, float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8459
bool operator()(WorldObject *target) const
Definition Spell.cpp:8463
bool operator()(WorldObject *target)
Definition Spell.cpp:8425
WorldObjectSpellNearbyTargetCheck(float range, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8421
WorldObjectSpellTargetCheck(WorldObject *caster, WorldObject *referer, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8335
SpellTargetCheckTypes _targetSelectionType
Definition Spell.h:733
std::unique_ptr< ConditionSourceInfo > _condSrcInfo
Definition Spell.h:734
bool operator()(WorldObject *target) const
Definition Spell.cpp:8347
ConditionContainer const * _condList
Definition Spell.h:735
WorldObjectSpellTrajTargetCheck(float range, Position const *position, WorldObject *caster, SpellInfo const *spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const *condList)
Definition Spell.cpp:8483
bool operator()(WorldObject *target) const
Definition Spell.cpp:8486
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< MissileTrajectoryRequest > MissileTrajectory
Optional< TargetLocation > SrcLocation
Optional< std::array< char, 128 > > Name
Optional< TargetLocation > DstLocation