/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef __SPELL_H #define __SPELL_H #include "Concepts.h" #include "ConditionMgr.h" #include "DBCEnums.h" #include "Duration.h" #include "ModelIgnoreFlags.h" #include "ObjectGuid.h" #include "Optional.h" #include "Position.h" #include "SharedDefines.h" #include "SpellDefines.h" #include "Types.h" #include "UniqueTrackablePtr.h" #include #include namespace WorldPackets::Spells { struct SpellCastData; struct SpellHealPrediction; } class Aura; class AuraEffect; class BasicEvent; class Corpse; class DamageInfo; class DynamicObject; class DynObjAura; class GameObject; class Item; class Object; class PathGenerator; class Player; class SpellEffectInfo; class SpellEvent; class SpellImplicitTargetInfo; class SpellInfo; class SpellScript; class Unit; class UnitAura; class WorldObject; struct SpellPowerCost; struct SummonPropertiesEntry; enum AuraType : uint32; enum CurrentSpellTypes : uint8; enum LootType : uint8; enum ProcFlagsHit : uint32; enum ProcFlagsSpellType : uint32; enum SpellTargetCheckTypes : uint8; enum SpellTargetObjectTypes : uint8; enum SpellValueMod : int32; enum SpellValueModFloat : int32; enum TriggerCastFlags : uint32; enum WeaponAttackType : uint8; namespace Trinity { enum class WorldObjectSpellAreaTargetSearchReason; template struct WorldObjectListSearcher; } #define SPELL_CHANNEL_UPDATE_INTERVAL (1 * IN_MILLISECONDS) #define MAX_SPELL_RANGE_TOLERANCE 3.0f #define TRAJECTORY_MISSILE_SIZE 3.0f #define AOE_DAMAGE_TARGET_CAP SI64LIT(20) #define SPELL_EMPOWER_HOLD_TIME_AT_MAX (1 * IN_MILLISECONDS) #define SPELL_EMPOWER_HARDCODED_GCD 359115u enum SpellCastFlags : uint32 { CAST_FLAG_NONE = 0x00000000, CAST_FLAG_PENDING = 0x00000001, // aoe combat log? CAST_FLAG_HAS_TRAJECTORY = 0x00000002, CAST_FLAG_UNKNOWN_3 = 0x00000004, CAST_FLAG_UNKNOWN_4 = 0x00000008, // ignore AOE visual CAST_FLAG_UNKNOWN_5 = 0x00000010, CAST_FLAG_PROJECTILE = 0x00000020, CAST_FLAG_UNKNOWN_7 = 0x00000040, CAST_FLAG_UNKNOWN_8 = 0x00000080, CAST_FLAG_UNKNOWN_9 = 0x00000100, CAST_FLAG_UNKNOWN_10 = 0x00000200, CAST_FLAG_UNKNOWN_11 = 0x00000400, // sorts missed targets before hit targets for chain visual CAST_FLAG_POWER_LEFT_SELF = 0x00000800, CAST_FLAG_UNKNOWN_13 = 0x00001000, CAST_FLAG_UNKNOWN_14 = 0x00002000, CAST_FLAG_UNKNOWN_15 = 0x00004000, CAST_FLAG_UNKNOWN_16 = 0x00008000, CAST_FLAG_UNKNOWN_17 = 0x00010000, CAST_FLAG_ADJUST_MISSILE = 0x00020000, CAST_FLAG_NO_GCD = 0x00040000, // no GCD for spell casts from charm/summon (vehicle spells is an example) CAST_FLAG_VISUAL_CHAIN = 0x00080000, CAST_FLAG_UNKNOWN_21 = 0x00100000, CAST_FLAG_RUNE_LIST = 0x00200000, CAST_FLAG_UNKNOWN_23 = 0x00400000, CAST_FLAG_UNKNOWN_24 = 0x00800000, CAST_FLAG_UNKNOWN_25 = 0x01000000, CAST_FLAG_UNKNOWN_26 = 0x02000000, CAST_FLAG_IMMUNITY = 0x04000000, CAST_FLAG_UNKNOWN_28 = 0x08000000, CAST_FLAG_UNKNOWN_29 = 0x10000000, CAST_FLAG_UNKNOWN_30 = 0x20000000, CAST_FLAG_HEAL_PREDICTION = 0x40000000, CAST_FLAG_TRIGGER_PET_COOLDOWN = 0x80000000 // causes the cooldown to be stored in pets SpellHistory on client }; enum SpellCastFlagsEx : uint32 { CAST_FLAG_EX_NONE = 0x00000, CAST_FLAG_EX_TRIGGER_COOLDOWN_ON_SPELL_START = 0x00001, CAST_FLAG_EX_UNKNOWN_2 = 0x00002, CAST_FLAG_EX_DONT_CONSUME_CHARGES = 0x00004, CAST_FLAG_EX_UNKNOWN_4 = 0x00008, CAST_FLAG_EX_DELAY_STARTING_COOLDOWNS = 0x00010, // makes client start cooldown after precalculated delay instead of immediately after SPELL_GO (used by empower spells) CAST_FLAG_EX_UNKNOWN_6 = 0x00020, CAST_FLAG_EX_UNKNOWN_7 = 0x00040, CAST_FLAG_EX_UNKNOWN_8 = 0x00080, CAST_FLAG_EX_IGNORE_PET_COOLDOWN = 0x00100, // makes client not automatically start cooldown for pets after SPELL_GO CAST_FLAG_EX_IGNORE_COOLDOWN = 0x00200, // makes client not automatically start cooldown after SPELL_GO CAST_FLAG_EX_UNKNOWN_11 = 0x00400, CAST_FLAG_EX_UNKNOWN_12 = 0x00800, CAST_FLAG_EX_UNKNOWN_13 = 0x01000, CAST_FLAG_EX_UNKNOWN_14 = 0x02000, CAST_FLAG_EX_UNKNOWN_15 = 0x04000, CAST_FLAG_EX_USE_TOY_SPELL = 0x08000, // Starts cooldown on toy CAST_FLAG_EX_UNKNOWN_17 = 0x10000, CAST_FLAG_EX_UNKNOWN_18 = 0x20000, CAST_FLAG_EX_UNKNOWN_19 = 0x40000, CAST_FLAG_EX_UNKNOWN_20 = 0x80000 }; enum SpellCastSource : uint8 { SPELL_CAST_SOURCE_PLAYER = 2, SPELL_CAST_SOURCE_NORMAL = 3, SPELL_CAST_SOURCE_ITEM = 4, SPELL_CAST_SOURCE_PASSIVE = 7, SPELL_CAST_SOURCE_PET = 9, SPELL_CAST_SOURCE_AURA = 13, SPELL_CAST_SOURCE_SPELL = 16, }; enum SpellHealPredictionType : uint8 { SPELL_HEAL_PREDICTION_TARGET = 0, SPELL_HEAL_PREDICTION_TARGET_AND_CASTER = 1, SPELL_HEAL_PREDICTION_TARGET_AND_BEACON = 2, SPELL_HEAL_PREDICTION_TARGET_PARTY = 3, }; enum SpellRangeFlag { SPELL_RANGE_DEFAULT = 0, SPELL_RANGE_MELEE = 1, //melee SPELL_RANGE_RANGED = 2 //hunter range and ranged weapon }; struct SpellLogEffectPowerDrainParams { ObjectGuid Victim; uint32 Points = 0; Powers PowerType = POWER_MANA; float Amplitude = 0; }; struct SpellLogEffectExtraAttacksParams { ObjectGuid Victim; uint32 NumAttacks = 0; }; struct SpellLogEffectDurabilityDamageParams { ObjectGuid Victim; int32 ItemID = 0; int32 Amount = 0; }; struct SpellLogEffectGenericVictimParams { ObjectGuid Victim; }; struct SpellLogEffectTradeSkillItemParams { int32 ItemID = 0; }; struct SpellLogEffectFeedPetParams { int32 ItemID = 0; }; struct SpellLogEffect { int32 Effect = 0; Optional> PowerDrainTargets; Optional> ExtraAttacksTargets; Optional> DurabilityDamageTargets; Optional> GenericVictimTargets; Optional> TradeSkillTargets; Optional> FeedPetTargets; }; struct SpellValue { explicit SpellValue(SpellInfo const* proto, WorldObject const* caster); int32 EffectBasePoints[MAX_SPELL_EFFECTS]; uint32 CustomBasePointsMask; uint32 MaxAffectedTargets; float RadiusMod; int32 AuraStackAmount; float DurationMul; float CriticalChance; Optional Duration; Optional ParentSpellTargetCount; Optional ParentSpellTargetIndex; }; enum SpellState { SPELL_STATE_NULL = 0, SPELL_STATE_PREPARING = 1, SPELL_STATE_LAUNCHED = 2, SPELL_STATE_CHANNELING = 3, SPELL_STATE_FINISHED = 4, SPELL_STATE_IDLE = 5, }; enum SpellEffectHandleMode { SPELL_EFFECT_HANDLE_LAUNCH, SPELL_EFFECT_HANDLE_LAUNCH_TARGET, SPELL_EFFECT_HANDLE_HIT, SPELL_EFFECT_HANDLE_HIT_TARGET }; typedef std::vector> DispelList; static const uint32 SPELL_INTERRUPT_NONPLAYER = 32747; class TC_GAME_API Spell { friend class SpellScript; public: void EffectNULL(); void EffectUnused(); void EffectDistract(); void EffectSchoolDMG(); void EffectEnvironmentalDMG(); void EffectInstaKill(); void EffectDummy(); void EffectTeleportUnits(); void EffectTeleportUnitsWithVisualLoadingScreen(); void EffectApplyAura(); void EffectSendEvent(); void EffectPowerBurn(); void EffectPowerDrain(); void EffectHeal(); void EffectBind(); void EffectTeleportToReturnPoint(); void EffectIncreaseCurrencyCap(); void EffectHealthLeech(); void EffectQuestComplete(); void EffectCreateItem(); void EffectCreateItem2(); void EffectCreateRandomItem(); void EffectPersistentAA(); void EffectEnergize(); void EffectOpenLock(); void EffectSummonChangeItem(); void EffectProficiency(); void EffectSummonType(); void EffectLearnSpell(); void EffectDispel(); void EffectDualWield(); void EffectPickPocket(); void EffectAddFarsight(); void EffectUntrainTalents(); void EffectHealMechanical(); void EffectJump(); void EffectJumpDest(); void EffectLeapBack(); void EffectQuestClear(); void EffectTeleUnitsFaceCaster(); void EffectLearnSkill(); void EffectPlayMovie(); void EffectTradeSkill(); void EffectEnchantItemPerm(); void EffectEnchantItemTmp(); void EffectTameCreature(); void EffectSummonPet(); void EffectLearnPetSpell(); void EffectWeaponDmg(); void EffectForceCast(); void EffectForceCast2(); void EffectTriggerSpell(); void EffectTriggerMissileSpell(); void EffectThreat(); void EffectHealMaxHealth(); void EffectInterruptCast(); void EffectSummonObjectWild(); void EffectScriptEffect(); void EffectSanctuary(); void EffectDuel(); void EffectStuck(); void EffectSummonPlayer(); void EffectActivateObject(); void EffectApplyGlyph(); void EffectEnchantHeldItem(); void EffectSummonObject(); void EffectChangeRaidMarker(); void EffectResurrect(); void EffectParry(); void EffectBlock(); void EffectLeap(); void EffectTransmitted(); void EffectDisEnchant(); void EffectInebriate(); void EffectFeedPet(); void EffectDismissPet(); void EffectReputation(); void EffectForceDeselect(); void EffectSelfResurrect(); void EffectSkinning(); void EffectCharge(); void EffectChargeDest(); void EffectProspecting(); void EffectMilling(); void EffectRenamePet(); void EffectSendTaxi(); void EffectKnockBack(); void EffectPullTowards(); void EffectPullTowardsDest(); void EffectDispelMechanic(); void EffectResurrectPet(); void EffectDestroyAllTotems(); void EffectDurabilityDamage(); void EffectSkill(); void EffectTaunt(); void EffectDurabilityDamagePCT(); void EffectModifyThreatPercent(); void EffectResurrectNew(); void EffectAddExtraAttacks(); void EffectSpiritHeal(); void EffectSkinPlayerCorpse(); void EffectStealBeneficialBuff(); void EffectUnlearnSpecialization(); void EffectHealPct(); void EffectEnergizePct(); void EffectTriggerRitualOfSummoning(); void EffectSummonRaFFriend(); void EffectUnlockGuildVaultTab(); void EffectKillCreditPersonal(); void EffectKillCredit(); void EffectKillCreditLabel(); void EffectQuestFail(); void EffectQuestStart(); void EffectRedirectThreat(); void EffectGameObjectDamage(); void EffectGameObjectRepair(); void EffectGameObjectSetDestructionState(); void EffectCreateTamedPet(); void EffectDiscoverTaxi(); void EffectTitanGrip(); void EffectEnchantItemPrismatic(); void EffectPlayMusic(); void EffectActivateSpec(); void EffectPlaySound(); void EffectRemoveAura(); void EffectDamageFromMaxHealthPCT(); void EffectCastButtons(); void EffectRechargeItem(); void EffectGiveCurrency(); void EffectSummonPersonalGameObject(); void EffectResurrectWithAura(); void EffectCreateAreaTrigger(); void EffectRemoveTalent(); void EffectDestroyItem(); void EffectLearnGarrisonBuilding(); void EffectRemoveAuraBySpellLabel(); void EffectCreateGarrison(); void EffectCreateConversation(); void EffectCancelConversation(); void EffectAddGarrisonFollower(); void EffectActivateGarrisonBuilding(); void EffectGrantBattlePetLevel(); void EffectGiveExperience(); void EffectGiveRestedExperience(); void EffectHealBattlePetPct(); void EffectEnableBattlePets(); void EffectChangeBattlePetQuality(); void EffectLaunchQuestChoice(); void EffectUncageBattlePet(); void EffectCreateHeirloomItem(); void EffectUpgradeHeirloom(); void EffectApplyEnchantIllusion(); void EffectUpdatePlayerPhase(); void EffectUpdateZoneAurasAndPhases(); void EffectGiveArtifactPower(); void EffectGiveArtifactPowerNoBonus(); void EffectPlaySceneScriptPackage(); void EffectCreateSceneObject(); void EffectCreatePrivateSceneObject(); void EffectPlayScene(); void EffectGiveHonor(); void EffectJumpCharge(); void EffectLearnTransmogSet(); void EffectRespecAzeriteEmpoweredItem(); void EffectLearnAzeriteEssencePower(); void EffectCreatePrivateConversation(); void EffectApplyMountEquipment(); void EffectSendChatMessage(); void EffectGrantBattlePetExperience(); void EffectLearnTransmogIllusion(); void EffectModifyAuraStacks(); void EffectModifyCooldown(); void EffectModifyCooldowns(); void EffectModifyCooldownsByCategory(); void EffectModifySpellCharges(); void EffectCreateTraitTreeConfig(); void EffectChangeActiveCombatTraitConfig(); void EffectTeleportGraveyard(); void EffectUpdateInteractions(); void EffectLearnWarbandScene(); void EffectSetPlayerDataElementAccount(); void EffectSetPlayerDataElementCharacter(); void EffectSetPlayerDataFlagAccount(); void EffectSetPlayerDataFlagCharacter(); typedef std::unordered_set UsedSpellMods; Spell(WorldObject* caster, SpellInfo const* info, TriggerCastFlags triggerFlags, ObjectGuid originalCasterGUID = ObjectGuid::Empty, ObjectGuid originalCastId = ObjectGuid::Empty); ~Spell(); void InitExplicitTargets(SpellCastTargets const& targets); void SelectExplicitTargets(); void SelectSpellTargets(); void SelectEffectImplicitTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32& processedEffectMask); void SelectImplicitChannelTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); void SelectImplicitNearbyTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask); void SelectImplicitConeTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask); void SelectImplicitAreaTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask); void SelectImplicitCasterDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex); void SelectImplicitTargetDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex); void SelectImplicitDestDestTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex); void SelectImplicitCasterObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); void SelectImplicitTargetObjectTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); void SelectImplicitChainTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, WorldObject* target, uint32 effMask); void SelectImplicitTrajTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType); void SelectImplicitLineTargets(SpellEffectInfo const& spellEffectInfo, SpellImplicitTargetInfo const& targetType, SpellTargetIndex targetIndex, uint32 effMask); void SelectEffectTypeImplicitTargets(SpellEffectInfo const& spellEffectInfo); static uint32 GetSearcherTypeMask(SpellInfo const* spellInfo, SpellEffectInfo const& spellEffectInfo, SpellTargetObjectTypes objType, ConditionContainer const* condList); template static void SearchTargets(SEARCHER& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius); WorldObject* SearchNearbyTarget(SpellEffectInfo const& spellEffectInfo, float range, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList = nullptr); void SearchAreaTargets(std::list& targets, SpellEffectInfo const& spellEffectInfo, float range, Position const* position, WorldObject* referer, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, Trinity::WorldObjectSpellAreaTargetSearchReason searchReason); void SearchChainTargets(std::list& targets, uint32 chainTargets, WorldObject* target, SpellTargetObjectTypes objectType, SpellTargetCheckTypes selectType, SpellEffectInfo const& spellEffectInfo, bool isChainHeal); GameObject* SearchSpellFocus(); SpellCastResult prepare(SpellCastTargets const& targets, AuraEffect const* triggeredByAura = nullptr); void cancel(); void update(uint32 difftime); void cast(bool skipCheck = false); void finish(SpellCastResult result = SPELL_CAST_OK); void TakePower(); void RefundPower(); void TakeRunePower(bool didHit); void RefundRunePower(); void TakeReagents(); void TakeCastItem(); SpellCastResult CheckCast(bool strict, int32* param1 = nullptr, int32* param2 = nullptr); SpellCastResult CheckPetCast(Unit* target); // handlers void handle_immediate(); uint64 handle_delayed(uint64 t_offset); // handler helpers void _handle_immediate_phase(); void _handle_finish_phase(); SpellCastResult CheckItems(int32* param1, int32* param2) const; SpellCastResult CheckRange(bool strict) const; SpellCastResult CheckPower() const; SpellCastResult CheckRuneCost() const; SpellCastResult CheckCasterAuras(int32* param1) const; SpellCastResult CheckArenaAndRatedBattlegroundCastRules(); SpellCastResult CheckMovement() const; bool CheckSpellCancelsAuraEffect(AuraType auraType, int32* param1) const; bool CheckSpellCancelsCharm(int32* param1) const; bool CheckSpellCancelsStun(int32* param1) const; bool CheckSpellCancelsSilence(int32* param1) const; bool CheckSpellCancelsPacify(int32* param1) const; bool CheckSpellCancelsFear(int32* param1) const; bool CheckSpellCancelsConfuse(int32* param1) const; bool CheckSpellCancelsNoActions(int32* param1) const; int32 CalculateDamage(SpellEffectInfo const& spellEffectInfo, Unit const* target, float* var = nullptr) const; void Delayed(); void DelayedChannel(); SpellState getState() const { return m_spellState; } void setState(SpellState state) { m_spellState = state; } void DoCreateItem(uint32 itemId, ItemContext context = ItemContext::NONE, std::vector const* bonusListIDs = nullptr); bool CheckEffectTarget(Unit const* target, SpellEffectInfo const& spellEffectInfo, Position const* losPosition) const; bool CheckEffectTarget(GameObject const* target, SpellEffectInfo const& spellEffectInfo) const; bool CheckEffectTarget(Item const* target, SpellEffectInfo const& spellEffectInfo) const; bool CanAutoCast(Unit* target); void CheckSrc(); void CheckDst(); static void SendCastResult(Player* caster, SpellInfo const* spellInfo, SpellCastVisual spellVisual, ObjectGuid cast_count, SpellCastResult result, SpellCustomErrors customError = SPELL_CUSTOM_ERROR_NONE, int32* param1 = nullptr, int32* param2 = nullptr); void SendCastResult(SpellCastResult result, int32* param1 = nullptr, int32* param2 = nullptr) const; void SendPetCastResult(SpellCastResult result, int32* param1 = nullptr, int32* param2 = nullptr) const; void SendMountResult(MountResult result); void SendSpellStart(); void SendSpellGo(); void SendSpellCooldown(); void SendSpellExecuteLog(); SpellLogEffect& GetExecuteLogEffect(SpellEffectName effect); template std::vector& GetExecuteLogEffectTargets(SpellEffectName effect, Optional> SpellLogEffect::* member) { Optional>& opt = GetExecuteLogEffect(effect).*member; if (!opt) opt.emplace(); return *opt; } void ExecuteLogEffectTakeTargetPower(SpellEffectName effect, Unit* target, Powers powerType, uint32 points, float amplitude); void ExecuteLogEffectExtraAttacks(SpellEffectName effect, Unit* victim, uint32 numAttacks); void ExecuteLogEffectDurabilityDamage(SpellEffectName effect, Unit* victim, int32 itemId, int32 amount); void ExecuteLogEffectOpenLock(SpellEffectName effect, Object* obj); void ExecuteLogEffectCreateItem(SpellEffectName effect, uint32 entry); void ExecuteLogEffectDestroyItem(SpellEffectName effect, uint32 entry); void ExecuteLogEffectSummonObject(SpellEffectName effect, WorldObject* obj); void ExecuteLogEffectUnsummonObject(SpellEffectName effect, WorldObject* obj); void ExecuteLogEffectResurrect(SpellEffectName effect, Unit* target); void SendSpellInterruptLog(Unit* victim, uint32 spellId); void SendInterrupted(uint8 result); void SendChannelUpdate(uint32 time, Optional result = {}); void SendChannelStart(uint32 duration); void SendResurrectRequest(Player* target); void HandleEffects(Unit* pUnitTarget, Item* pItemTarget, GameObject* pGoTarget, Corpse* pCorpseTarget, SpellEffectInfo const& spellEffectInfo, SpellEffectHandleMode mode); void HandleThreatSpells(); static Spell const* ExtractSpellFromEvent(BasicEvent* event); SpellInfo const* const m_spellInfo; Item* m_CastItem; ObjectGuid m_castItemGUID; uint32 m_castItemEntry; int32 m_castItemLevel; ObjectGuid m_castId; ObjectGuid m_originalCastId; bool m_fromClient; uint32 m_castFlagsEx; union { // Alternate names for this value uint32 TalentId; // SPELL_EFFECT_APPLY_GLYPH uint32 SpellId; // SPELL_EFFECT_TALENT_SPEC_SELECT uint32 SpecializationId; // SPELL_EFFECT_SET_FOLLOWER_QUALITY // SPELL_EFFECT_INCREASE_FOLLOWER_ITEM_LEVEL // SPELL_EFFECT_INCREASE_FOLLOWER_EXPERIENCE // SPELL_EFFECT_RANDOMIZE_FOLLOWER_ABILITIES // SPELL_EFFECT_LEARN_FOLLOWER_ABILITY struct { uint32 Id; uint32 AbilityId; // only SPELL_EFFECT_LEARN_FOLLOWER_ABILITY } GarrFollower; // SPELL_EFFECT_FINISH_GARRISON_MISSION uint32 GarrMissionId; // SPELL_EFFECT_UPGRADE_HEIRLOOM uint32 ItemId; struct { uint32 Data[2]; } Raw; } m_misc; std::any m_customArg; SpellCastVisual m_SpellVisual; SpellCastTargets m_targets; SpellCustomErrors m_customError; UsedSpellMods m_appliedMods; Optional> m_scriptResult; bool m_scriptWaitsForSpellHit = false; int32 GetCastTime() const { return m_casttime; } int32 GetRemainingCastTime() const { return m_timer; } int32 GetChannelDuration() const { return m_channelDuration; } bool IsAutoRepeat() const { return m_autoRepeat; } void SetAutoRepeat(bool rep) { m_autoRepeat = rep; } void ReSetTimer() { m_timer = m_casttime > 0 ? m_casttime : 0; } bool IsTriggered() const; bool IsIgnoringCooldowns() const; bool IsFocusDisabled() const; bool IsProcDisabled() const; bool IsChannelActive() const; bool IsAutoActionResetSpell() const; bool IsPositive() const; bool IsEmpowerSpell() const { return m_empower != nullptr; } void SetEmpowerReleasedByClient(bool release); bool CanReleaseEmpowerSpell() const; bool IsTriggeredByAura(SpellInfo const* auraSpellInfo) const { return (auraSpellInfo == m_triggeredByAuraSpell); } int32 GetProcChainLength() const { return m_procChainLength; } bool IsDeletable() const { return !m_referencedFromCurrentSpell && !m_executedCurrently; } void SetReferencedFromCurrent(bool yes) { m_referencedFromCurrentSpell = yes; } bool IsInterruptable() const { return !m_executedCurrently; } void SetExecutedCurrently(bool yes) {m_executedCurrently = yes;} uint64 GetDelayStart() const { return m_delayStart; } void SetDelayStart(uint64 m_time) { m_delayStart = m_time; } uint64 GetDelayMoment() const { return m_delayMoment; } uint64 CalculateDelayMomentForDst(float launchDelay) const; void RecalculateDelayMomentForDst(); void UpdateDelayMomentForDst(uint64 hitDelay); void UpdateDelayMomentForUnitTarget(Unit* unit, uint64 hitDelay); uint8 GetRuneState() const { return m_runesState; } void SetRuneState(uint8 value) { m_runesState = value; } bool IsNeedSendToClient() const; CurrentSpellTypes GetCurrentContainer() const; WorldObject* GetCaster() const { return m_caster; } ObjectGuid GetOriginalCasterGUID() const { return m_originalCasterGUID; } Unit* GetOriginalCaster() const { return m_originalCaster; } SpellInfo const* GetSpellInfo() const { return m_spellInfo; } Difficulty GetCastDifficulty() const; std::vector const& GetPowerCost() const { return m_powerCost; } bool HasPowerTypeCost(Powers power) const; Optional GetPowerTypeCostAmount(Powers power) const; bool UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) void CleanupTargetList(); void SetSpellValue(CastSpellExtraArgsInit::SpellValueOverride const& value); Spell** m_selfContainer; // pointer to our spell container (if applicable) SpellInfo const* GetTriggeredByAuraSpell() const { return m_triggeredByAuraSpell; } int32 GetTimer() const { return m_timer; } int64 GetUnitTargetCountForEffect(SpellEffIndex effect) const; int64 GetGameObjectTargetCountForEffect(SpellEffIndex effect) const; int64 GetItemTargetCountForEffect(SpellEffIndex effect) const; int64 GetCorpseTargetCountForEffect(SpellEffIndex effect) const; std::string GetDebugInfo() const; Trinity::unique_weak_ptr GetWeakPtr() const; void CallScriptOnResistAbsorbCalculateHandlers(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount); bool IsWithinLOS(WorldObject const* source, WorldObject const* target, bool targetAsSourceLocation, VMAP::ModelIgnoreFlags ignoreFlags) const; bool IsWithinLOS(WorldObject const* source, Position const& target, VMAP::ModelIgnoreFlags ignoreFlags) const; void MovePosition(Position& pos, WorldObject const* from, float dist, float angle) const; static bool CanIncreaseRangeByMovement(Unit const* unit); std::pair GetMinMaxRange(bool strict) const; protected: bool HasGlobalCooldown() const; void TriggerGlobalCooldown(); void CancelGlobalCooldown(); void _cast(bool skipCheck = false); WorldObject* const m_caster; SpellValue* const m_spellValue; ObjectGuid m_originalCasterGUID; // real source of cast (aura caster/etc), used for spell targets selection // e.g. damage around area spell trigered by victim aura and damage enemies of aura caster Unit* m_originalCaster; // cached pointer for m_originalCaster, updated at Spell::UpdatePointers() // Spell data SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) WeaponAttackType m_attackType; // For weapon based attack std::vector m_powerCost; // Calculated spell cost initialized only in Spell::prepare int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare int32 m_channelDuration; // Calculated channeled spell duration in order to calculate correct pushback. bool m_canReflect; // can reflect this spell? bool m_autoRepeat; uint8 m_runesState; uint8 m_delayAtDamageCount; bool IsDelayableNoMore() { if (m_delayAtDamageCount >= 2) return true; ++m_delayAtDamageCount; return false; } struct EmpowerData { Milliseconds MinHoldTime = 0ms; std::vector StageDurations; int32 CompletedStages = 0; bool IsReleasedByClient = false; bool IsReleased = false; }; std::unique_ptr m_empower; // Delayed spells system uint64 m_delayStart; // time of spell delay start, filled by event handler, zero = just started uint64 m_delayMoment; // moment of next delay call, used internally bool m_launchHandled; // were launch actions handled bool m_immediateHandled; // were immediate actions handled? (used by delayed spells only) // These vars are used in both delayed spell system and modified immediate spell system bool m_referencedFromCurrentSpell; // mark as references to prevent deleted and access by dead pointers bool m_executedCurrently; // mark as executed to prevent deleted and access by dead pointers uint32 m_applyMultiplierMask; float m_damageMultipliers[MAX_SPELL_EFFECTS]; // Current targets, to be used in SpellEffects (MUST BE USED ONLY IN SPELL EFFECTS) Unit* unitTarget; Item* itemTarget; GameObject* gameObjTarget; Corpse* m_corpseTarget; WorldLocation* destTarget; int32 damage; SpellMissInfo targetMissInfo; float variance; SpellEffectHandleMode effectHandleMode; SpellEffectInfo const* effectInfo; // used in effects handlers Unit* GetUnitCasterForEffectHandlers() const; UnitAura* _spellAura; DynObjAura* _dynObjAura; // ------------------------------------------- GameObject* focusObject; // Damage and healing in effects need just calculate int32 m_damage; // Damage in effects count here int32 m_healing; // Healing in effects count here // ****************************************** // Spell trigger system // ****************************************** ProcFlagsInit m_procAttacker; // Attacker trigger flags ProcFlagsInit m_procVictim; // Victim trigger flags ProcFlagsHit m_hitMask; ProcFlagsSpellType m_procSpellType; // for finish procs void prepareDataForTriggerSystem(); // ***************************************** // Spell target subsystem // ***************************************** // Targets store structures and data struct TargetInfoBase { virtual void PreprocessTarget(Spell* /*spell*/) { } virtual void DoTargetSpellHit(Spell* spell, SpellEffectInfo const& spellEffectInfo) = 0; virtual void DoDamageAndTriggers(Spell* /*spell*/) { } uint32 EffectMask = 0; protected: TargetInfoBase() { } virtual ~TargetInfoBase() { } }; struct TargetInfo : public TargetInfoBase { void PreprocessTarget(Spell* spell) override; void DoTargetSpellHit(Spell* spell, SpellEffectInfo const& spellEffectInfo) override; void DoDamageAndTriggers(Spell* spell) override; ObjectGuid TargetGUID; uint64 TimeDelay = 0ULL; int32 Damage = 0; int32 Healing = 0; SpellMissInfo MissCondition = SPELL_MISS_NONE; SpellMissInfo ReflectResult = SPELL_MISS_NONE; bool IsAlive = false; bool IsCrit = false; // info set at PreprocessTarget, used by DoTargetSpellHit DiminishingGroup DRGroup = DIMINISHING_NONE; int32 AuraDuration = 0; int32 AuraBasePoints[MAX_SPELL_EFFECTS] = { }; bool Positive = true; UnitAura* HitAura = nullptr; ProcFlagsHit ProcHitMask = { }; private: Unit* _spellHitTarget = nullptr; // changed for example by reflect bool _enablePVP = false; // need to enable PVP at DoDamageAndTriggers? }; std::vector m_UniqueTargetInfo; uint32 m_channelTargetEffectMask; // Mask req. alive targets struct GOTargetInfo : public TargetInfoBase { void DoTargetSpellHit(Spell* spell, SpellEffectInfo const& spellEffectInfo) override; ObjectGuid TargetGUID; uint64 TimeDelay = 0ULL; }; std::vector m_UniqueGOTargetInfo; struct ItemTargetInfo : public TargetInfoBase { void DoTargetSpellHit(Spell* spell, SpellEffectInfo const& spellEffectInfo) override; Item* TargetItem = nullptr; }; std::vector m_UniqueItemInfo; struct CorpseTargetInfo : public TargetInfoBase { void DoTargetSpellHit(Spell* spell, SpellEffectInfo const& spellEffectInfo) override; ObjectGuid TargetGUID; uint64 TimeDelay = 0ULL; }; std::vector m_UniqueCorpseTargetInfo; template void DoProcessTargetContainer(Container& targetContainer); SpellDestination m_destTargets[MAX_SPELL_EFFECTS]; int32 GetUnitTargetIndexForEffect(ObjectGuid const& target, SpellEffIndex effect) const; void AddUnitTarget(Unit* target, uint32 effectMask, bool checkIfValid = true, bool implicit = true, Position const* losPosition = nullptr); void AddGOTarget(GameObject* target, uint32 effectMask); void AddItemTarget(Item* item, uint32 effectMask); void AddCorpseTarget(Corpse* target, uint32 effectMask); void AddDestTarget(SpellDestination const& dest, uint32 effIndex); void PreprocessSpellLaunch(TargetInfo& targetInfo); SpellMissInfo PreprocessSpellHit(Unit* unit, TargetInfo& targetInfo); void DoSpellEffectHit(Unit* unit, SpellEffectInfo const& spellEffectInfo, TargetInfo& targetInfo); void DoTriggersOnSpellHit(Unit* unit); bool UpdateChanneledTargetList(); bool IsValidDeadOrAliveTarget(Unit const* target) const; void HandleLaunchPhase(); void DoEffectOnLaunchTarget(TargetInfo& targetInfo, float multiplier, SpellEffectInfo const& spellEffectInfo); void ResetCombatTimers(); void PrepareTargetProcessing(); void FinishTargetProcessing(); // Scripting system void LoadScripts(); void CallScriptOnPrecastHandler(); void CallScriptBeforeCastHandlers(); void CallScriptOnCastHandlers(); void CallScriptAfterCastHandlers(); SpellCastResult CallScriptCheckCastHandlers(); int32 CallScriptCalcCastTimeHandlers(int32 originalCastTime); bool CallScriptEffectHandlers(SpellEffIndex effIndex, SpellEffectHandleMode mode); void CallScriptSuccessfulDispel(SpellEffIndex effIndex); void CallScriptBeforeHitHandlers(SpellMissInfo missInfo); void CallScriptOnHitHandlers(); void CallScriptAfterHitHandlers(); public: void CallScriptCalcCritChanceHandlers(Unit const* victim, float& chance); void CallScriptCalcDamageHandlers(SpellEffectInfo const& spellEffectInfo, Unit* victim, int32& damage, int32& flatMod, float& pctMod); void CallScriptCalcHealingHandlers(SpellEffectInfo const& spellEffectInfo, Unit* victim, int32& healing, int32& flatMod, float& pctMod); template Script* GetScript() const { return static_cast(GetScriptByType(typeid(Script))); } protected: void CallScriptObjectAreaTargetSelectHandlers(std::list& targets, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void CallScriptObjectTargetSelectHandlers(WorldObject*& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void CallScriptDestinationTargetSelectHandlers(SpellDestination& target, SpellEffIndex effIndex, SpellImplicitTargetInfo const& targetType); void CallScriptEmpowerStageCompletedHandlers(int32 completedStagesCount); void CallScriptEmpowerCompletedHandlers(int32 completedStagesCount); bool CheckScriptEffectImplicitTargets(uint32 effIndex, uint32 effIndexToCheck); SpellScript* GetScriptByType(std::type_info const& type) const; std::vector m_loadedScripts; struct HitTriggerSpell { HitTriggerSpell(SpellInfo const* spellInfo, SpellInfo const* auraSpellInfo, int32 procChance) : triggeredSpell(spellInfo), triggeredByAura(auraSpellInfo), chance(procChance) { } SpellInfo const* triggeredSpell; SpellInfo const* triggeredByAura; // uint8 triggeredByEffIdx This might be needed at a later stage - No need known for now int32 chance; }; bool CanExecuteTriggersOnHit(Unit* unit, SpellInfo const* triggeredByAura = nullptr) const; void PrepareTriggersExecutedOnHit(); typedef std::vector HitTriggerSpellList; HitTriggerSpellList m_hitTriggerSpells; // effect helpers void SummonGuardian(SpellEffectInfo const* effect, uint32 entry, SummonPropertiesEntry const* properties, uint32 numSummons, ObjectGuid privateObjectOwner); void CalculateJumpSpeeds(SpellEffectInfo const* effInfo, float dist, float& speedXY, float& speedZ); void UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData& data); int32 GetSpellCastDataAmmo(); void UpdateSpellHealPrediction(WorldPackets::Spells::SpellHealPrediction& healPrediction, bool withPeriodic); SpellCastResult CanOpenLock(SpellEffectInfo const& effect, uint32 lockid, SkillType& skillid, int32& reqSkillValue, int32& skillValue); // ------------------------------------------- SpellState m_spellState; int32 m_timer; SpellEvent* _spellEvent; TriggerCastFlags _triggeredCastFlags; // if need this can be replaced by Aura copy // we can't store original aura link to prevent access to deleted auras // and in same time need aura data and after aura deleting. SpellInfo const* m_triggeredByAuraSpell; int32 m_procChainLength; std::unique_ptr m_preGeneratedPath; std::vector _executeLogEffects; Spell(Spell const& right) = delete; Spell& operator=(Spell const& right) = delete; }; namespace Trinity { struct TC_GAME_API WorldObjectSpellTargetCheck { protected: WorldObject* _caster; WorldObject* _referer; SpellInfo const* _spellInfo; SpellTargetCheckTypes _targetSelectionType; std::unique_ptr _condSrcInfo; ConditionContainer const* _condList; SpellTargetObjectTypes _objectType; WorldObjectSpellTargetCheck(WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType); ~WorldObjectSpellTargetCheck(); bool operator()(WorldObject* target) const; }; struct TC_GAME_API WorldObjectSpellNearbyTargetCheck : public WorldObjectSpellTargetCheck { float _range; Position const* _position; WorldObjectSpellNearbyTargetCheck(float range, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType); bool operator()(WorldObject* target); }; enum class WorldObjectSpellAreaTargetSearchReason { Area, Chain }; struct TC_GAME_API WorldObjectSpellAreaTargetCheck : public WorldObjectSpellTargetCheck { float _range; Position const* _position; WorldObjectSpellAreaTargetSearchReason _searchReason; WorldObjectSpellAreaTargetCheck(float range, Position const* position, WorldObject* caster, WorldObject* referer, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType, WorldObjectSpellAreaTargetSearchReason searchReason = WorldObjectSpellAreaTargetSearchReason::Area); bool operator()(WorldObject* target) const; }; struct TC_GAME_API WorldObjectSpellConeTargetCheck : public WorldObjectSpellAreaTargetCheck { Position _coneSrc; float _coneAngle; float _lineWidth; WorldObjectSpellConeTargetCheck(Position const& coneSrc, float coneAngle, float lineWidth, float range, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType); bool operator()(WorldObject* target) const; }; struct TC_GAME_API WorldObjectSpellTrajTargetCheck : public WorldObjectSpellTargetCheck { float _range; Position const* _position; WorldObjectSpellTrajTargetCheck(float range, Position const* position, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType); bool operator()(WorldObject* target) const; }; struct TC_GAME_API WorldObjectSpellLineTargetCheck : public WorldObjectSpellAreaTargetCheck { Position _position; float _lineWidth; WorldObjectSpellLineTargetCheck(Position const* srcPosition, Position const* dstPosition, float lineWidth, float range, WorldObject* caster, SpellInfo const* spellInfo, SpellTargetCheckTypes selectionType, ConditionContainer const* condList, SpellTargetObjectTypes objectType); bool operator()(WorldObject* target) const; }; TC_GAME_API void SelectRandomInjuredTargets(std::list& targets, size_t maxTargets, bool prioritizePlayers, Unit const* prioritizeGroupMembersOf = nullptr); struct TargetPriorityRule { template requires (!std::same_as) TargetPriorityRule(Func&& func) : Rule([func = std::forward(func)](T* target) { if constexpr (invocable_r) return std::invoke(func, target); else if constexpr (invocable_r) return target->IsUnit() && std::invoke(func, target->ToUnit()); else if constexpr (invocable_r) return target->IsPlayer() && std::invoke(func, target->ToPlayer()); else static_assert(dependant_false_v, "Unsupported object type, use WorldObject* as your rule argument"); }) { } std::function Rule; }; TC_GAME_API void SortTargetsWithPriorityRules(std::list& targets, size_t maxTargets, std::span rules); template inline void SortTargetsWithPriorityRules(std::list& targets, size_t maxTargets, std::array const& rules) { static_assert(N <= 31); SortTargetsWithPriorityRules(targets, maxTargets, std::span(rules)); } } extern template void Spell::SearchTargets>(Trinity::WorldObjectListSearcher& searcher, uint32 containerMask, WorldObject* referer, Position const* pos, float radius); using SpellEffectHandlerFn = void(Spell::*)(); #endif