From 1509cdfdeddfcceb68a9657d4feeb5ebf2383606 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Thu, 13 May 2021 20:35:45 -0400 Subject: [PATCH] Core/Spells: Expose number of targets selected for each spell effect to scripts to allow implementing spells that do something depending on number of targets hit Port From (https://github.com/TrinityCore/TrinityCore/commit/1a7779a6e6464d9bc5b367e02820213edd60f704) --- Source/Game/Scripting/SpellScript.cs | 45 ++++++++++++++++++++++++++-- Source/Game/Spells/Spell.cs | 19 ++++++++++-- Source/Game/Spells/SpellEffects.cs | 4 +-- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/Source/Game/Scripting/SpellScript.cs b/Source/Game/Scripting/SpellScript.cs index 828dfe99c..f4fb3f43b 100644 --- a/Source/Game/Scripting/SpellScript.cs +++ b/Source/Game/Scripting/SpellScript.cs @@ -257,7 +257,7 @@ namespace Game.Scripting SpellOnCalcCritChanceFnType _onCalcCritChanceHandlerScript; } - + public class TargetHook : EffectHook { public TargetHook(uint effectIndex, Targets targetType, bool area, bool dest = false) : base(effectIndex) @@ -430,6 +430,15 @@ namespace Game.Scripting { return m_currentScriptState == (byte)SpellScriptHookType.CheckCast; } + + bool IsAfterTargetSelectionPhase() + { + return IsInHitPhase() + || m_currentScriptState == (byte)SpellScriptHookType.OnCast + || m_currentScriptState == (byte)SpellScriptHookType.AfterCast + || m_currentScriptState == (byte)SpellScriptHookType.CalcCritChance; + } + public bool IsInTargetHook() { switch ((SpellScriptHookType)m_currentScriptState) @@ -551,10 +560,40 @@ namespace Game.Scripting public Unit GetExplTargetUnit() { return m_spell.m_targets.GetUnitTarget(); } // returns: GameObject which was selected as an explicit spell target or null if there's no target - GameObject GetExplTargetGObj() { return m_spell.m_targets.GetGOTarget(); } + public GameObject GetExplTargetGObj() { return m_spell.m_targets.GetGOTarget(); } // returns: Item which was selected as an explicit spell target or null if there's no target - Item GetExplTargetItem() { return m_spell.m_targets.GetItemTarget(); } + public Item GetExplTargetItem() { return m_spell.m_targets.GetItemTarget(); } + + public long GetUnitTargetCountForEffect(uint effect) + { + if (!IsAfterTargetSelectionPhase()) + { + Log.outError(LogFilter.Scripts, $"Script: `{m_scriptName}` Spell: `{m_scriptSpellId}`: function SpellScript.GetUnitTargetCountForEffect was called, but function has no effect in current hook! (spell has not selected targets yet)"); + return 0; + } + return m_spell.GetUnitTargetCountForEffect(effect); + } + + public long GetGameObjectTargetCountForEffect(uint effect) + { + if (!IsAfterTargetSelectionPhase()) + { + Log.outError(LogFilter.Scripts, $"Script: `{m_scriptName}` Spell: `{m_scriptSpellId}`: function SpellScript.GetGameObjectTargetCountForEffect was called, but function has no effect in current hook! (spell has not selected targets yet)"); + return 0; + } + return m_spell.GetGameObjectTargetCountForEffect(effect); + } + + public long GetItemTargetCountForEffect(uint effect) + { + if (!IsAfterTargetSelectionPhase()) + { + Log.outError(LogFilter.Scripts, $"Script: `{m_scriptName}` Spell: `{m_scriptSpellId}`: function SpellScript.GetItemTargetCountForEffect was called, but function has no effect in current hook! (spell has not selected targets yet)"); + return 0; + } + return m_spell.GetItemTargetCountForEffect(effect); + } // methods useable only during spell hit on target, or during spell launch on target: // returns: target of current effect if it was Unit otherwise null diff --git a/Source/Game/Spells/Spell.cs b/Source/Game/Spells/Spell.cs index 4faa19f38..e4c55c2ec 100644 --- a/Source/Game/Spells/Spell.cs +++ b/Source/Game/Spells/Spell.cs @@ -1758,6 +1758,21 @@ namespace Game.Spells m_destTargets[effIndex] = dest; } + public long GetUnitTargetCountForEffect(uint effect) + { + return m_UniqueTargetInfo.Count(targetInfo => (targetInfo.effectMask & (1 << (int)effect)) != 0); + } + + public long GetGameObjectTargetCountForEffect(uint effect) + { + return m_UniqueGOTargetInfo.Count(targetInfo => (targetInfo.effectMask & (1 << (int)effect)) != 0); + } + + public long GetItemTargetCountForEffect(uint effect) + { + return m_UniqueItemInfo.Count(targetInfo => (targetInfo.effectMask & (1 << (int)effect)) != 0); + } + void DoAllEffectOnTarget(TargetInfo target) { if (target == null || target.processed) @@ -6853,9 +6868,9 @@ namespace Game.Spells if (m_caster.IsTypeId(TypeId.Player)) { - int targetAmount = m_UniqueTargetInfo.Count; + long targetAmount = GetUnitTargetCountForEffect(effect.EffectIndex); if (targetAmount > 20) - m_damage = m_damage * 20 / targetAmount; + m_damage = (int)(m_damage * 20 / targetAmount); } } } diff --git a/Source/Game/Spells/SpellEffects.cs b/Source/Game/Spells/SpellEffects.cs index 6987afe9a..66cff1ff7 100644 --- a/Source/Game/Spells/SpellEffects.cs +++ b/Source/Game/Spells/SpellEffects.cs @@ -153,11 +153,11 @@ namespace Game.Spells // Meteor like spells (divided damage to targets) if (m_spellInfo.HasAttribute(SpellCustomAttributes.ShareDamage)) { - int count = m_UniqueTargetInfo.Count(targetInfo => Convert.ToBoolean(targetInfo.effectMask & (1 << (int)effIndex))); + long count = GetUnitTargetCountForEffect(effIndex); // divide to all targets if (count != 0) - damage /= count; + damage /= (int)count; } switch (m_spellInfo.SpellFamilyName)