public void OnEndSubSpell(ISubSpellHandler handler)
        {
            // If SubSpell has ended - remove and destroy all instances that are assigned to that SubSpell
            for (var i = _instances.Count - 1; i >= 0; i--)
            {
                var instance = _instances[i];
                // If instance was destroyed
                if (instance.InstanceObject == null)
                {
                    _instances.RemoveAt(i);
                    continue;
                }

                if (!instance.Handler.Equals(handler))
                {
                    continue;
                }

                if (DestroyAfterSpell)
                {
                    Destroy(instance.InstanceObject);
                }

                _instances.RemoveAt(i);
            }
        }
Beispiel #2
0
 public SubSpellEventArgs(ISubSpellHandler handler, SubSpellEvent e, Query q, IEnumerable <Target> targets)
 {
     Handler        = handler;
     Event          = e;
     Query          = q;
     QueriedTargets = targets;
 }
        private SubSpellEffectInstance Create(ISubSpellHandler handler, Target source, Target target)
        {
            Transform attachTo;
            Target    relativeTo;

            switch (SpawnOrigin)
            {
            case EffectSpawnOrigin.Target:
                attachTo   = GetTransform(target);
                relativeTo = source;
                break;

            default:
            case EffectSpawnOrigin.Source:
                attachTo   = GetTransform(source);
                relativeTo = target;
                break;
            }

            CalculateTransform(attachTo, relativeTo, out var position, out var rotation);
            return(new SubSpellEffectInstance
            {
                AttachedTo = attachTo,
                Relative = relativeTo,
                Handler = handler,
                InstanceObject = SpawnInstance(position, rotation, null, handler.Stacks)
            });
        }
Beispiel #4
0
        public Change ApplyModifier(
            ModificationParameter parameter,
            float amount,
            CharacterState sourceCharacter,
            ISubSpellHandler subSpell = null,
            bool applyChange          = true)
        {
            // First - calculate an actual change of modifier
            // using all spell amplification things, evasions and other stuff
            var change = CalcChange(parameter, amount, sourceCharacter, subSpell);

#if DEBUG_COMBAT
            _combatLog.Log(
                $"<b>{gameObject.name}</b> received modifier <b>{parameter}</b> with amount <b>{amount}</b>. Actual change: <b>{change.Amount}</b>");
#endif

            if (applyChange)
            {
#if DEBUG
                ModifierApplied?.Invoke(parameter, subSpell, change.Amount);
#endif
                // Apply an actual change
                ApplyChange(change);
            }

            return(change);
        }
Beispiel #5
0
        private void HandlerOnStateChanged(ISpellHandler handler, SpellEvent e, ISubSpellHandler subHandler)
        {
            // Even when event if from spell that is already not in slot - decrease hp for cast
            if (e == SpellEvent.SubSpellCasted && subHandler != null)
            {
                _characterState.ApplyModifier(
                    ModificationParameter.HpFlat,
                    -subHandler.SubSpell.BloodCost.GetValue(subHandler.Stacks),
                    _characterState,
                    null);
            }


            for (var i = 0; i < SpellSlots.Length; i++)
            {
                if (handler.Equals(SpellSlots[i].SpellHandler))
                {
                    OnSlotHandlerStateChanged(i, handler, e, subHandler);
                    return;
                }
            }

            // If the handler (finished or aborted state) is inactive - unsubscribe
            if (!handler.IsActive)
            {
                // Unsubscribe
                handler.Event -= HandlerOnStateChanged;
            }
        }
Beispiel #6
0
        public void ApplyBuff(
            Buff newBuff,
            CharacterState sourceCharacter,
            int stacks,
            ISubSpellHandler subSpell = null)
        {
            if (!IsAlive)
            {
                return;
            }

            if (newBuff == null)
            {
                return;
            }

            // Try find buff state with the same buff that is going to be applied
            var existingState = _buffStates.FirstOrDefault(s => s.Buff.Equals(newBuff));

            if (existingState != null)
            {
                // State with same buff already exists
                switch (newBuff.Behaviour)
                {
                case BuffStackBehaviour.MaxStacksOfTwo:
                    existingState.Stacks = Mathf.Max(stacks, existingState.Stacks);
                    ApplyBuffModifiers(existingState);
                    existingState.RefreshTime();
                    existingState.SubSpellHandler = subSpell;
                    HandleBuffEvents(existingState, BuffEventType.OnRefresh);
                    break;

                case BuffStackBehaviour.AddNewAsSeparate:
                    AddNewBuff(newBuff, stacks, sourceCharacter, subSpell);
                    break;

                case BuffStackBehaviour.SumStacks:
                    existingState.Stacks += stacks;
                    ApplyBuffModifiers(existingState);
                    existingState.SubSpellHandler = subSpell;
                    existingState.RefreshTime();
                    HandleBuffEvents(existingState, BuffEventType.OnRefresh);
                    break;

                case BuffStackBehaviour.Discard:
                    // Do nothing. newBuff wont be added
                    break;
                }
#if DEBUG_COMBAT
                _combatLog.Log(
                    $"<b>{gameObject.name}</b> reapplied buff <b>{newBuff.name}</b> with <b>{newBuff.Behaviour}</b> behaviour. Stack after reapplied: <b>{existingState.Stacks}</b>");
#endif
            }
            else
            {
                // The buff is completely new. So create and store new BuffState and apply all effects
                AddNewBuff(newBuff, stacks, sourceCharacter, subSpell);
            }
        }
Beispiel #7
0
 public BuffState(Buff buff, CharacterState sourceCharacter, int stacks, ISubSpellHandler subSpell = null)
 {
     Stacks          = stacks;
     Buff            = buff;
     TimeRemaining   = buff.Duration;
     TickCd          = 0;
     SourceCharacter = sourceCharacter;
     SubSpellHandler = subSpell;
 }
Beispiel #8
0
    private void CharacterStateOnOnModifierApplied(ModificationParameter parameter, ISubSpellHandler spell, float actualChange)
    {
        var spellName = String.Empty;

        if (spell != null)
        {
            spellName = spell.Spell.name;
        }
        _modLog.Push($"{spellName} <color=yellow>{parameter}</color>: {actualChange:0.##}");

        foreach (var line in _modLog.Reverse())
        {
            _stringBuilder2.AppendLine(line);
        }

        Text2.text = _stringBuilder2.ToString();
        _stringBuilder2.Clear();
    }
Beispiel #9
0
        private BuffState AddNewBuff(
            Buff buff,
            int stacks,
            CharacterState sourceCharacter,
            ISubSpellHandler subSpell)
        {
            var buffState = new BuffState(buff, sourceCharacter, stacks, subSpell);

            _buffStates.Add(buffState);

#if DEBUG_COMBAT
            _combatLog.LogFormat("<b>{0}</b> received new buff <b>{1}</b> with <b>{2}</b> stacks",
                                 gameObject.name,
                                 buff.name,
                                 stacks);
#endif
            ApplyBuffModifiers(buffState);
            HandleBuffEvents(buffState, BuffEventType.OnApply);
            return(buffState);
        }
Beispiel #10
0
 public SubSpellEventArgs(ISubSpellHandler handler, SubSpellEvent e)
     : this(handler, e, default, default)
 {
 }
Beispiel #11
0
        private Change CalcChange(ModificationParameter parameter,
                                  float amount,
                                  CharacterState sourceCharacter,
                                  ISubSpellHandler subSpell)
        {
            // Zero-change
            if (parameter == ModificationParameter.None || Mathf.Abs(amount) < 1e-6)
            {
                return new Change
                       {
                           Parameter = ModificationParameter.None,
                           Amount    = 0
                       }
            }
            ;

            if (parameter == ModificationParameter.HpFlat || parameter == ModificationParameter.HpMult)
            {
                var targetHp = _hp;

                if (parameter == ModificationParameter.HpFlat)
                {
                    targetHp += amount;
                }
                if (parameter == ModificationParameter.HpMult)
                {
                    targetHp *= amount;
                }
                targetHp = Mathf.Min(targetHp, MaxHealth);
                var delta = targetHp - _hp;
                // If taking damage
                if (delta < 0)
                {
                    // If the damage comes from spell, amplify it buy character source damage multiplier
                    if (subSpell != null && sourceCharacter != null)
                    {
                        // Damage amplification
                        delta *= sourceCharacter.SpellDamageMultiplier;
#if DEBUG_COMBAT
                        _combatLog.Log(
                            $"Receiving in total <b>{-delta}</b> spell multiplied ({100 * sourceCharacter.SpellDamageMultiplier}%) damage from <b>{sourceCharacter.name}</b> " +
                            $"from spell <b>{subSpell.Spell.name}</b>");
#endif

                        // Lifesteal
                        // TODO: Shouldn't we apply lifesteal afterwards?
                        var lifeStealFactor = subSpell.Spell.LifeSteal.GetValue(subSpell.Stacks);
                        var hpStolen        = -delta * lifeStealFactor;
                        if (hpStolen > 0)
                        {
#if DEBUG_COMBAT
                            _combatLog.Log(
                                $"Returning <b>{hpStolen}</b> hp back to <b>{sourceCharacter.name}</b> " +
                                $"because spell <b>{subSpell.Spell.name}</b> has <b>{100 * lifeStealFactor}%</b> lifesteal");
#endif
                            sourceCharacter.ApplyModifier(ModificationParameter.HpFlat,
                                                          hpStolen,
                                                          this,
                                                          subSpell);
                        }
                    }
                }

                // Notice that we are returning HpFlat even if the original modifier was HpMult.
                // Because there was some additional modifer applied to damage (if any)
                return(new Change
                {
                    Parameter = ModificationParameter.HpFlat,
                    Amount = delta
                });
            }

            switch (parameter)
            {
            case ModificationParameter.CritChanceFlat:
            case ModificationParameter.EvasionChanceFlat:
                return(new Change
                {
                    Parameter = parameter,
                    Amount = 1 - amount
                });
            }

            // Default change computation for stats like speed and other relatively simple stats
            return(new Change
            {
                Parameter = parameter,
                Amount = amount
            });
        }
Beispiel #12
0
        private void OnSlotHandlerStateChanged(int slotIndex, ISpellHandler handler, SpellEvent e, ISubSpellHandler subHandler)
        {
            var slotState = GetSpellSlotState(slotIndex);

            if (e == SpellEvent.StartedFiring)
            {
                slotState.State = SlotState.Firing;
            }
            else if (e == SpellEvent.FinishedFire || e == SpellEvent.Aborted || e == SpellEvent.Ended)
            {
                // If we are ending spell that has not yet started
                if (slotState.State == SlotState.Preparing)
                {
                    slotState.RemainingCooldown = 0.1f;
                }
                else
                {
                    slotState.RemainingCooldown = slotState.Spell.Cooldown.GetValue(slotState.NumStacks);
                }

                // Remove handler from state and start recharging
                slotState.SpellHandler = null;
                slotState.State        = SlotState.Recharging;

                if (NoCooldowns)
                {
                    slotState.RemainingCooldown = 0.1f;
                }
            }
        }