private float CalculateSpellCriticalChance(Unit victim, SpellInfo spellInfo, SpellSchoolMask schoolMask)
            {
                if (spellInfo.HasAttribute(SpellAttributes.CantCrit) || spellInfo.DamageClass == SpellDamageClass.None)
                {
                    return(0.0f);
                }

                if (spellInfo.HasAttribute(SpellAttributes.AlwaysCrit))
                {
                    return(100.0f);
                }

                float critChance = unit.CritPercentage;

                if (victim == null)
                {
                    return(Mathf.Max(critChance, 0.0f));
                }

                switch (spellInfo.DamageClass)
                {
                case SpellDamageClass.Magic:
                    if (!spellInfo.IsPositive)
                    {
                        critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerSpellCritChance);
                    }
                    goto default;

                case SpellDamageClass.Melee:
                    if (!spellInfo.IsPositive)
                    {
                        critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerMeleeCritChance);
                    }
                    goto default;

                case SpellDamageClass.Ranged:
                    if (!spellInfo.IsPositive)
                    {
                        critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerRangedCritChance);
                    }
                    goto default;

                default:
                    critChance += victim.Auras.TotalAuraModifierForCaster(AuraEffectType.ModAttackerSpellCritChanceForCaster, unit.Id);
                    critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerSpellAndWeaponCritChance);
                    break;
                }

                return(Mathf.Max(critChance, 0.0f));
            }
Example #2
0
            internal bool IsImmuneToSpell(SpellInfo spellInfo, Unit caster)
            {
                if (spellInfo.HasAttribute(SpellAttributes.UnaffectedByInvulnerability))
                {
                    return(false);
                }

                if (IsImmuneToSpellSchool(spellInfo.SchoolMask, spellInfo, caster))
                {
                    return(true);
                }

                bool isImmuneToAllEffects = true;

                foreach (SpellEffectInfo spellEffectInfo in spellInfo.Effects)
                {
                    if (!IsImmuneToSpellEffect(spellEffectInfo, caster))
                    {
                        isImmuneToAllEffects = false;
                        break;
                    }
                }

                if (isImmuneToAllEffects)
                {
                    return(true);
                }

                return(false);
            }
Example #3
0
        private SpellCastResult Cast()
        {
            ExecutionState = SpellExecutionState.Casting;

            CastTime     = Caster.Spells.ModifySpellCastTime(this, SpellInfo.CastTime);
            CastTimeLeft = CastTime;

            // cast if needed, if already casting launch instead, should only be possible with CanCastWhileCasting
            bool instantCast = CastTime <= 0.0f || Caster.SpellCast.IsCasting || spellValue.CastFlags.HasTargetFlag(SpellCastFlags.CastDirectly);

            if (casterMovementFlags.IsMoving() && !instantCast && !SpellInfo.HasAttribute(SpellAttributes.CastableWhileMoving))
            {
                return(SpellCastResult.Moving);
            }

            if (!spellValue.CastFlags.HasTargetFlag(SpellCastFlags.IgnoreShapeShift) && SpellInfo.CanCancelForm(this))
            {
                Caster.Auras.RemoveAurasWithEffect(AuraEffectType.ShapeShift);
            }

            Caster.SpellHistory.StartGlobalCooldown(SpellInfo);

            if (!spellValue.CastFlags.HasTargetFlag(SpellCastFlags.IgnoreAuraInterruptFlags) && !SpellInfo.HasAttribute(SpellCustomAttributes.DontBreakStealth))
            {
                Caster.Auras.RemoveAurasWithInterrupt(AuraInterruptFlags.Cast);
            }

            if (instantCast)
            {
                Launch();
            }

            return(SpellCastResult.Success);
        }
        internal void EffectSchoolDamage(EffectSchoolDamage effect, int effectIndex, Unit target, SpellEffectHandleMode mode)
        {
            if (mode != SpellEffectHandleMode.HitStart || target == null || !target.IsAlive)
            {
                return;
            }

            float spellDamage = effect.CalculateSpellDamage(SpellInfo, effectIndex, Caster, target);

            if (SpellInfo.HasAttribute(SpellCustomAttributes.ShareDamage))
            {
                spellDamage /= Mathf.Min(1, ImplicitTargets.TargetCountForEffect(effectIndex));
            }

            for (var i = 0; i < effect.ConditionalModifiers.Count; i++)
            {
                ConditionalModifier modifier = effect.ConditionalModifiers[i];
                if (modifier.Condition.With(Caster, target, this).IsApplicableAndValid)
                {
                    modifier.Modify(ref spellDamage);
                }
            }

            EffectDamage += (int)spellDamage;
        }
Example #5
0
        private void ConsumePowers()
        {
            if (SpellInfo.HasAttribute(SpellAttributes.RequiresComboPoints))
            {
                if (spellValue.CastFlags.HasTargetFlag(SpellCastFlags.IgnoreComboPoints))
                {
                    ConsumedComboPoints = Caster.MaxComboPoints;
                }
                else
                {
                    ConsumedComboPoints = Caster.ComboPoints;
                    Caster.Attributes.SetComboPoints(0);
                }
            }

            if (spellValue.CastFlags.HasTargetFlag(SpellCastFlags.IgnorePowerAndReagentCost))
            {
                return;
            }

            foreach ((SpellPowerType, int)powerCost in powerCosts)
            {
                if (powerCost.Item1 == SpellPowerType.Health)
                {
                    if (Caster.IsAlive)
                    {
                        Caster.ModifyHealth(-Mathf.Min(Caster.Health - 1, powerCost.Item2));
                    }

                    continue;
                }

                Caster.Attributes.ModifyPower(powerCost.Item1, -powerCost.Item2);
            }
        }
Example #6
0
            internal bool IsImmunedToDamage(SpellInfo spellInfo, SpellSchoolMask?schoolMaskOverride = null, Unit caster = null)
            {
                SpellSchoolMask schoolMask = schoolMaskOverride ?? spellInfo.SchoolMask;

                if (spellInfo.HasAttribute(SpellAttributes.UnaffectedByInvulnerability) && spellInfo.HasAttribute(SpellAttributes.IgnoreHitResult))
                {
                    return(false);
                }

                if (spellInfo.HasAttribute(SpellAttributes.UnaffectedBySchoolImmune))
                {
                    return(false);
                }

                return(IsImmuneToSpellSchool(schoolMask, spellInfo, caster));
            }
Example #7
0
        internal void DoUpdate(int deltaTime)
        {
            switch (ExecutionState)
            {
            case SpellExecutionState.Casting:
                CastTimeLeft -= deltaTime;
                if (CastTimeLeft <= 0)
                {
                    Caster.SpellCast.HandleSpellCast(this, SpellCast.HandleMode.Finished);
                    Launch();
                    break;
                }

                bool mayBeInterruptedByMove = CastTime - CastTimeLeft > MovementUtils.SpellMovementInterruptThreshold;
                if (mayBeInterruptedByMove && !SpellInfo.HasAttribute(SpellAttributes.CastableWhileMoving) && Caster.MovementInfo.IsMoving)
                {
                    Caster.SpellCast.HandleSpellCast(this, SpellCast.HandleMode.Finished);
                    Cancel();
                }
                break;

            case SpellExecutionState.Processing:
                bool hasUnprocessed = false;
                foreach (SpellTargetEntry targetInfo in ImplicitTargets.Entries)
                {
                    if (targetInfo.Processed)
                    {
                        continue;
                    }

                    targetInfo.Delay -= deltaTime;

                    if (targetInfo.Delay <= 0)
                    {
                        ProcessTarget(targetInfo);
                    }
                    else
                    {
                        hasUnprocessed = true;
                    }
                }

                if (!hasUnprocessed)
                {
                    Finish();
                }
                break;

            case SpellExecutionState.Completed:
                goto default;

            case SpellExecutionState.Preparing:
                goto default;

            default:
                Assert.IsTrue(SpellState == SpellState.Removing, $"Spell {SpellInfo.SpellName} updated in invalid state: {ExecutionState} while not being removed!");
                break;
            }
        }
Example #8
0
        internal Spell(Unit caster, SpellInfo info, SpellCastingOptions options)
        {
            Logging.LogSpell($"Created new spell, current count: {++SpellAliveCount}");

            spellManager         = caster.World.SpellManager;
            spellValue.CastFlags = options.SpellFlags;
            casterMovementFlags  = options.MovementFlags ?? caster.MovementInfo.Flags;
            SchoolMask           = info.SchoolMask;

            CastTime  = CastTimeLeft = EffectDamage = EffectHealing = 0;
            Caster    = OriginalCaster = caster;
            SpellInfo = info;

            IsTriggered = spellValue.CastFlags.HasTargetFlag(SpellCastFlags.TriggeredByAura);

            if (IsTriggered)
            {
                spellValue.CastFlags |= SpellCastFlags.IgnoreTargetCheck | SpellCastFlags.IgnoreRangeCheck |
                                        SpellCastFlags.IgnoreShapeShift | SpellCastFlags.IgnoreAuraInterruptFlags | SpellCastFlags.IgnoreCasterState;
            }

            if (info.HasAttribute(SpellExtraAttributes.CanCastWhileCasting))
            {
                spellValue.CastFlags |= SpellCastFlags.IgnoreCastInProgress | SpellCastFlags.CastDirectly;
            }

            if (info.HasAttribute(SpellExtraAttributes.IgnoreGcd))
            {
                spellValue.CastFlags |= SpellCastFlags.IgnoreGcd;
            }

            if (info.HasAttribute(SpellExtraAttributes.IgnoreCasterAuras))
            {
                spellValue.CastFlags |= SpellCastFlags.IgnoreCasterAuras;
            }

            CanReflect = SpellInfo.DamageClass == SpellDamageClass.Magic && !SpellInfo.HasAttribute(SpellAttributes.CantBeReflected) &&
                         !SpellInfo.HasAttribute(SpellAttributes.UnaffectedByInvulnerability) && !SpellInfo.IsPassive && !SpellInfo.IsPositive;

            ExplicitTargets = options.Targets ?? new SpellExplicitTargets();
            ImplicitTargets = new SpellImplicitTargets(this);

            spellManager.Add(this);
        }
Example #9
0
            internal bool IsImmuneToSpell(SpellInfo spellInfo, Unit caster)
            {
                if (spellInfo.HasAttribute(SpellAttributes.UnaffectedByInvulnerability))
                {
                    return(false);
                }

                if (spellInfo.SchoolMask != 0)
                {
                    SpellSchoolMask immunedSchools = 0;
                    foreach (var schoolImmunityEntry in schoolImmunities)
                    {
                        if (!schoolImmunityEntry.Key.HasAnyFlag(spellInfo.SchoolMask))
                        {
                            continue;
                        }

                        foreach (SpellInfo immunitySpells in schoolImmunityEntry.Value)
                        {
                            if (!immunitySpells.IsPositive || !spellInfo.IsPositive || !unit.IsFriendlyTo(caster))
                            {
                                if (!spellInfo.CanPierceImmuneAura(immunitySpells))
                                {
                                    immunedSchools |= schoolImmunityEntry.Key;
                                }
                            }
                        }
                    }

                    if (immunedSchools.HasTargetFlag(spellInfo.SchoolMask))
                    {
                        return(true);
                    }
                }

                bool isImmuneToAllEffects = true;

                foreach (SpellEffectInfo spellEffectInfo in spellInfo.Effects)
                {
                    if (!IsImmuneToSpellEffect(spellEffectInfo, caster))
                    {
                        isImmuneToAllEffects = false;
                        break;
                    }
                }

                if (isImmuneToAllEffects)
                {
                    return(true);
                }

                return(false);
            }
Example #10
0
        private SpellCastResult ValidateCasterState()
        {
            if (spellValue.CastFlags.HasTargetFlag(SpellCastFlags.IgnoreCasterState))
            {
                return(SpellCastResult.Success);
            }

            if (SpellInfo.HasAttribute(SpellAttributes.CantBeUsedInCombat) && Caster.Combat.InCombat)
            {
                return(SpellCastResult.AffectingCombat);
            }

            return(SpellCastResult.Success);
        }
        internal void StartGlobalCooldown(SpellInfo spellInfo)
        {
            if (spellInfo.HasAttribute(SpellExtraAttributes.DoesNotTriggerGcd))
            {
                return;
            }

            if (GlobalCooldownLeft > spellInfo.GlobalCooldownTime)
            {
                return;
            }

            GlobalCooldown     = spellInfo.GlobalCooldownTime;
            GlobalCooldownLeft = GlobalCooldown;

            casterState.GlobalCooldown.CooldownTime = GlobalCooldown;
            casterState.GlobalCooldown.ServerFrame  = BoltNetwork.ServerFrame;
        }
Example #12
0
        private void PrepareExplicitTarget()
        {
            ExplicitTargets.Source = Caster.Position;

            // initializes client-provided targets, corrects and automatically attempts to set required target.
            bool targetsUnits = SpellInfo.ExplicitCastTargets.HasAnyFlag(SpellCastTargetFlags.UnitMask);

            if (ExplicitTargets.Target != null && !targetsUnits)
            {
                ExplicitTargets.Target = null;
            }

            if (SpellInfo.ExplicitTargetType == SpellExplicitTargetType.Caster)
            {
                ExplicitTargets.Target = Caster;
            }

            // try to select correct unit target if not provided by client
            if (ExplicitTargets.Target == null && targetsUnits)
            {
                // try to use player selection as target, it has to be valid target for the spell
                if (Caster is Player playerCaster && playerCaster.Target is Unit playerTarget)
                {
                    if (SpellInfo.CheckExplicitTarget(Caster, playerTarget) == SpellCastResult.Success)
                    {
                        ExplicitTargets.Target = playerTarget;
                    }
                }

                // didn't find anything, try to use self as target
                if (ExplicitTargets.Target == null && SpellInfo.ExplicitCastTargets.HasAnyFlag(SpellCastTargetFlags.UnitAlly))
                {
                    ExplicitTargets.Target = Caster;
                }
            }

            if (ExplicitTargets.Target != null && SpellInfo.HasAttribute(SpellCustomAttributes.LaunchSourceIsExplicit))
            {
                ExplicitTargets.Source = ExplicitTargets.Target.Position;
            }
        }
            internal void CalculateSpellDamageTaken(ref SpellDamageInfo damageInfo)
            {
                if (damageInfo.Damage == 0 || !damageInfo.Target.IsAlive)
                {
                    return;
                }

                Unit      caster    = damageInfo.Caster;
                Unit      target    = damageInfo.Target;
                SpellInfo spellInfo = damageInfo.SpellInfo;

                damageInfo.UpdateDamage(caster.Spells.SpellDamageBonusDone(target, spellInfo, damageInfo.Damage, damageInfo.SpellDamageType));
                damageInfo.UpdateDamage(target.Spells.SpellDamageBonusTaken(caster, spellInfo, damageInfo.Damage, damageInfo.SpellDamageType));

                if (!spellInfo.HasAttribute(SpellExtraAttributes.FixedDamage) && damageInfo.HasCrit)
                {
                    uint criticalDamage = CalculateSpellCriticalDamage(spellInfo, damageInfo.Damage);
                    damageInfo.UpdateOriginalDamage(criticalDamage);
                }

                HandleAbsorb(ref damageInfo);
            }
Example #14
0
        private void ConsumePowers()
        {
            if (SpellInfo.HasAttribute(SpellAttributes.RequiresComboPoints))
            {
                ConsumedComboPoints = Caster.ComboPoints;
                Caster.Attributes.SetComboPoints(0);
            }

            foreach ((SpellPowerType, int)powerCost in powerCosts)
            {
                if (powerCost.Item1 == SpellPowerType.Health)
                {
                    if (Caster.IsAlive)
                    {
                        Caster.ModifyHealth(-Mathf.Min(Caster.Health - 1, powerCost.Item2));
                    }

                    continue;
                }

                Caster.Attributes.ModifyPower(powerCost.Item1, -powerCost.Item2);
            }
        }
Example #15
0
        private SpellCastResult Cast()
        {
            ExecutionState = SpellExecutionState.Casting;

            CastTime     = Caster.Spells.ModifySpellCastTime(this, SpellInfo.CastTime);
            CastTimeLeft = CastTime;

            // cast if needed, if already casting launch instead, should only be possible with CanCastWhileCasting
            bool instantCast = CastTime <= 0.0f || Caster.SpellCast.IsCasting || spellCastFlags.HasTargetFlag(SpellCastFlags.CastDirectly);

            if (casterMovementFlags.IsMoving() && !instantCast && !SpellInfo.HasAttribute(SpellAttributes.CastableWhileMoving))
            {
                return(SpellCastResult.Moving);
            }

            Caster.SpellHistory.StartGlobalCooldown(SpellInfo);

            if (instantCast)
            {
                Launch();
            }

            return(SpellCastResult.Success);
        }
Example #16
0
        private SpellCastResult ValidateCast()
        {
            if (spellCastFlags.HasTargetFlag(SpellCastFlags.TriggeredByAura))
            {
                return(SpellCastResult.Success);
            }

            if (Caster.HasState(UnitControlState.Stunned) && !SpellInfo.HasAttribute(SpellExtraAttributes.UsableWhileStunned))
            {
                return(SpellCastResult.Stunned);
            }

            if (Caster.HasState(UnitControlState.Confused) && !SpellInfo.HasAttribute(SpellExtraAttributes.UsableWhileConfused))
            {
                return(SpellCastResult.Confused);
            }

            if (Caster.HasState(UnitControlState.Fleeing) && !SpellInfo.HasAttribute(SpellExtraAttributes.UsableWhileFeared))
            {
                return(SpellCastResult.Fleeing);
            }

            if (SpellInfo.PreventionType != 0)
            {
                if (SpellInfo.PreventionType.HasTargetFlag(SpellPreventionType.Pacify) && Caster.HasFlag(UnitFlags.Pacified))
                {
                    return(SpellCastResult.Silenced);
                }

                if (SpellInfo.PreventionType.HasTargetFlag(SpellPreventionType.Silence) && Caster.HasFlag(UnitFlags.Silenced))
                {
                    return(SpellCastResult.Pacified);
                }
            }

            // check death state
            if (!Caster.IsAlive && !SpellInfo.IsPassive() && !SpellInfo.HasAttribute(SpellAttributes.CastableWhileDead))
            {
                return(SpellCastResult.CasterDead);
            }

            // check cooldowns to prevent cheating
            if (!SpellInfo.IsPassive() && !Caster.SpellHistory.IsReady(SpellInfo))
            {
                return(SpellCastResult.NotReady);
            }

            // check global cooldown
            if (!spellCastFlags.HasTargetFlag(SpellCastFlags.IgnoreGcd) && Caster.SpellHistory.HasGlobalCooldown)
            {
                return(SpellCastResult.NotReady);
            }

            // check if already casting
            if (Caster.SpellCast.IsCasting && !SpellInfo.HasAttribute(SpellExtraAttributes.CanCastWhileCasting))
            {
                return(SpellCastResult.NotReady);
            }

            SpellCastResult castResult = ValidateRange();

            if (castResult != SpellCastResult.Success)
            {
                return(castResult);
            }

            if (!spellCastFlags.HasTargetFlag(SpellCastFlags.IgnoreTargetCheck))
            {
                castResult = SpellInfo.CheckExplicitTarget(Caster, ExplicitTargets.Target);
                if (castResult != SpellCastResult.Success)
                {
                    return(castResult);
                }

                if (ExplicitTargets.Target != null)
                {
                    castResult = SpellInfo.CheckTarget(Caster, ExplicitTargets.Target, this, false);
                    if (castResult != SpellCastResult.Success)
                    {
                        return(castResult);
                    }
                }
            }

            return(SpellCastResult.Success);
        }
Example #17
0
        private SpellCastResult ValidateAuras()
        {
            if (spellCastFlags.HasTargetFlag(SpellCastFlags.IgnoreCasterAuras))
            {
                return(SpellCastResult.Success);
            }

            bool usableWhileStunned  = SpellInfo.HasAttribute(SpellExtraAttributes.UsableWhileStunned);
            bool usableWhileConfused = SpellInfo.HasAttribute(SpellExtraAttributes.UsableWhileConfused);
            bool usableWhileFeared   = SpellInfo.HasAttribute(SpellExtraAttributes.UsableWhileFeared);

            if (Caster.HasFlag(UnitFlags.Stunned))
            {
                if (usableWhileStunned)
                {
                    SpellCastResult result = ValidateMechanics(AuraEffectType.StunState);
                    if (result != SpellCastResult.Success)
                    {
                        return(result);
                    }
                }
                else if (!WillCancelStun())
                {
                    return(SpellCastResult.Stunned);
                }
            }

            if (SpellInfo.PreventionType != 0)
            {
                if (SpellInfo.PreventionType.HasTargetFlag(SpellPreventionType.Pacify) && Caster.HasFlag(UnitFlags.Pacified) && !WillCancelPacify())
                {
                    return(SpellCastResult.Pacified);
                }

                if (SpellInfo.PreventionType.HasTargetFlag(SpellPreventionType.Silence) && Caster.HasFlag(UnitFlags.Silenced) && !WillCancelSilence())
                {
                    return(SpellCastResult.Silenced);
                }
            }

            if (Caster.HasFlag(UnitFlags.Fleeing))
            {
                if (usableWhileFeared)
                {
                    SpellCastResult result = ValidateMechanics(AuraEffectType.ModFear);
                    if (result != SpellCastResult.Success)
                    {
                        return(result);
                    }
                }
                else if (!WillCancelFear())
                {
                    return(SpellCastResult.Fleeing);
                }
            }

            if (Caster.HasFlag(UnitFlags.Confused))
            {
                if (usableWhileConfused)
                {
                    SpellCastResult result = ValidateMechanics(AuraEffectType.ConfusionState);
                    if (result != SpellCastResult.Success)
                    {
                        return(result);
                    }
                }
                else if (!WillCancelConfuse())
                {
                    return(SpellCastResult.Confused);
                }
            }

            return(SpellCastResult.Success);

            bool WillCancelStun()
            {
                return(SpellInfo.CanCancelAuraType(AuraEffectType.StunState, Caster) && SpellInfo.CanCancelAuraType(AuraEffectType.Strangulate, Caster));
            }

            bool WillCancelSilence()
            {
                return(SpellInfo.CanCancelAuraType(AuraEffectType.Silence, Caster) && SpellInfo.CanCancelAuraType(AuraEffectType.SilencePacify, Caster));
            }

            bool WillCancelPacify()
            {
                return(SpellInfo.CanCancelAuraType(AuraEffectType.Pacify, Caster) && SpellInfo.CanCancelAuraType(AuraEffectType.SilencePacify, Caster));
            }

            bool WillCancelFear()
            {
                return(SpellInfo.CanCancelAuraType(AuraEffectType.ModFear, Caster));
            }

            bool WillCancelConfuse()
            {
                return(SpellInfo.CanCancelAuraType(AuraEffectType.ConfusionState, Caster));
            }
        }
Example #18
0
            private float CalculateSpellCriticalChance(Unit victim, SpellInfo spellInfo, SpellSchoolMask schoolMask, Spell spell = null)
            {
                if (spellInfo.HasAttribute(SpellAttributes.CantCrit) || spellInfo.DamageClass == SpellDamageClass.None)
                {
                    return(0.0f);
                }

                if (spellInfo.HasAttribute(SpellAttributes.AlwaysCrit))
                {
                    return(100.0f);
                }

                float critChance = unit.CritPercentage;

                if (victim == null)
                {
                    return(Mathf.Max(critChance, 0.0f));
                }

                switch (spellInfo.DamageClass)
                {
                case SpellDamageClass.Magic:
                    if (!spellInfo.IsPositive)
                    {
                        critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerSpellCritChance);
                    }

                    IReadOnlyList <AuraEffect> spellCritAuras = unit.GetAuraEffects(AuraEffectType.OverrideSpellCritCalculation);
                    if (spellCritAuras != null)
                    {
                        for (int i = 0; i < spellCritAuras.Count; i++)
                        {
                            if (spellCritAuras[i].EffectInfo is AuraEffectInfoOverrideSpellCritCalculation effectInfo)
                            {
                                effectInfo.ModifySpellCrit(unit, victim, spell, ref critChance);
                            }
                        }
                    }

                    goto default;

                case SpellDamageClass.Melee:
                    if (!spellInfo.IsPositive)
                    {
                        critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerMeleeCritChance);
                    }
                    goto default;

                case SpellDamageClass.Ranged:
                    if (!spellInfo.IsPositive)
                    {
                        critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerRangedCritChance);
                    }
                    goto default;

                default:
                    critChance += victim.Auras.TotalAuraModifierForCaster(AuraEffectType.ModAttackerSpellCritChanceForCaster, unit.Id);
                    critChance += victim.Auras.TotalAuraModifier(AuraEffectType.ModAttackerSpellAndWeaponCritChance);
                    break;
                }

                return(Mathf.Max(critChance, 0.0f));
            }
Example #19
0
        private SpellCastResult ValidateCast()
        {
            if (spellCastFlags.HasTargetFlag(SpellCastFlags.TriggeredByAura))
            {
                return(SpellCastResult.Success);
            }

            if (Caster is Player player && !player.PlayerSpells.HasKnownSpell(SpellInfo))
            {
                return(SpellCastResult.NotKnown);
            }

            // check death state
            if (!Caster.IsAlive && !SpellInfo.IsPassive && !SpellInfo.HasAttribute(SpellAttributes.CastableWhileDead))
            {
                return(SpellCastResult.CasterDead);
            }

            // check cooldowns to prevent cheating
            if (!SpellInfo.IsPassive && !Caster.SpellHistory.IsReady(SpellInfo))
            {
                return(SpellCastResult.NotReady);
            }

            // check global cooldown
            if (!spellCastFlags.HasTargetFlag(SpellCastFlags.IgnoreGcd) && Caster.SpellHistory.HasGlobalCooldown)
            {
                return(SpellCastResult.NotReady);
            }

            // check if already casting
            if (Caster.SpellCast.IsCasting && !SpellInfo.HasAttribute(SpellExtraAttributes.CanCastWhileCasting))
            {
                return(SpellCastResult.NotReady);
            }

            SpellCastResult castResult;

            if (!spellCastFlags.HasTargetFlag(SpellCastFlags.IgnoreTargetCheck))
            {
                castResult = SpellInfo.CheckExplicitTarget(Caster, ExplicitTargets.Target);
                if (castResult != SpellCastResult.Success)
                {
                    return(castResult);
                }

                if (ExplicitTargets.Target != null)
                {
                    castResult = SpellInfo.CheckTarget(Caster, ExplicitTargets.Target, this, false);
                    if (castResult != SpellCastResult.Success)
                    {
                        return(castResult);
                    }
                }
            }

            castResult = ValidateRange();
            if (castResult != SpellCastResult.Success)
            {
                return(castResult);
            }

            castResult = ValidateAuras();
            if (castResult != SpellCastResult.Success)
            {
                return(castResult);
            }

            return(SpellCastResult.Success);
        }