/// <summary>
        /// Applies a status effect to a group of characters.
        /// </summary>
        /// <param name="applicator">The character applying the status effect.</param>
        /// <param name="status">The status effect being applied.</param>
        /// <param name="characters">The characters the status effect is being applied to.</param>
        public void ApplyStatus(Character applicator, StatusEffect status, IEnumerable <Character> characters)
        {
            foreach (var character in characters)
            {
                ApplyStatus(applicator, status, character, false);
            }

            StatusEffectApplied?.Invoke(this, new StatusEffectAppliedEventArgs()
            {
                AffectedCharacterIds = new List <int>(characters.Select(chr => chr.Id)),
                LogMessage           = CombatMessenger.GetAffectedByStatusMessage(status.Name, characters.Select(chr => chr.Name).ToList())
            });
        }
 private void OnStatusEffectApplied(object sender, StatusEffectAppliedEventArgs args)
 {
     StatusEffectApplied?.Invoke(sender, args);
 }
        /// <summary>
        /// Applys a delayed status effect to a group of characters.
        /// </summary>
        /// <param name="status">The delayed status to apply.</param>
        private void ApplyStatus(DelayedStatus status)
        {
            var livingTargets = new List <Character>(
                AllCharacters.Where(
                    character => status.Targets.Contains(character.Position)));

            livingTargets.RemoveAll(target => target.CurrentHealth <= 0);

            foreach (var target in livingTargets)
            {
                if (!_appliedStatuses.ContainsKey(target))
                {
                    _appliedStatuses[target] = new List <AppliedStatus>();
                }
                // If the the same type of status is already on a character
                if (_appliedStatuses[target].Any(applied => applied.BaseStatus == status.BaseStatus))
                {
                    var matchingStatus = _appliedStatuses[target].First(applied => applied.BaseStatus == status.BaseStatus);
                    // If the status is stackable, refresh the duration and apply another layer of effects
                    if (status.BaseStatus.Stackable && matchingStatus.StackCount < status.BaseStatus.StackSize)
                    {
                        matchingStatus.Applicator      = status.Applicator;
                        matchingStatus.TurnsRemaining  = status.BaseStatus.Duration;
                        matchingStatus.TotalDamage    += status.TotalDamage;
                        matchingStatus.HealAmount     += status.HealAmount;
                        matchingStatus.HealPercentage += status.HealPercentage;
                        ApplyStatusEffects(status.BaseStatus, target);
                        matchingStatus.StackCount++;
                    }
                    // If the status is stackable but has reached its stack limit, refresh the duration only
                    else if (status.BaseStatus.Stackable)
                    {
                        matchingStatus.Applicator     = status.Applicator;
                        matchingStatus.TurnsRemaining = status.BaseStatus.Duration;
                    }
                    // If the status isn't stackable, refresh the duration and reset the damage
                    else
                    {
                        matchingStatus.Applicator     = status.Applicator;
                        matchingStatus.TurnsRemaining = status.BaseStatus.Duration;
                        matchingStatus.TotalDamage    = status.TotalDamage;
                        matchingStatus.HealAmount     = status.HealAmount;
                        matchingStatus.HealPercentage = status.HealPercentage;
                    }
                }
                // Create and apply a new status effect on a character
                else
                {
                    ApplyStatusEffects(status.BaseStatus, target);
                    _appliedStatuses[target].Add(CreateAppliedStatus(status));
                    if (status.BaseStatus.IsDebuff)
                    {
                        target.Debuffs.Add(status.BaseStatus);
                    }
                    else
                    {
                        target.Buffs.Add(status.BaseStatus);
                    }
                }
            }

            StatusEffectApplied?.Invoke(this, new StatusEffectAppliedEventArgs()
            {
                AffectedCharacterIds = new List <int>(livingTargets.Select(chr => chr.Id)),
                LogMessage           = CombatMessenger.GetAffectedByStatusMessage(status.BaseStatus.Name,
                                                                                  livingTargets.Select(target => target.Name).ToList())
            });
        }
        /// <summary>
        /// Applies a status effect on a character.
        /// </summary>
        /// <param name="applicator">The character that is applying the status effect.</param>
        /// <param name="status">The status effect being applied.</param>
        /// <param name="character">The character the status effect is being applied on.</param>
        public void ApplyStatus(Character applicator, StatusEffect status, Character character, bool invokeAppliedStatusEvent = true)
        {
            if (!_appliedStatuses.ContainsKey(character))
            {
                _appliedStatuses[character] = new List <AppliedStatus>();
            }
            // If the the same type of status is already on a character
            if (_appliedStatuses[character].Any(applied => applied.BaseStatus == status))
            {
                var matchingStatus = _appliedStatuses[character].First(applied => applied.BaseStatus == status);
                // If the status is stackable, refresh the duration and apply another layer of effects
                if (status.Stackable && matchingStatus.StackCount < status.StackSize)
                {
                    matchingStatus.TurnsRemaining  = status.Duration;
                    matchingStatus.TotalDamage    += DamageCalculator.GetDamage(applicator, status);
                    matchingStatus.HealAmount     += DamageCalculator.GetHealing(applicator, status);
                    matchingStatus.HealPercentage += DamageCalculator.GetHealingPercentage(applicator, status);
                    matchingStatus.CritChance      = status.CritChance + character.CritChance;
                    matchingStatus.CritMultiplier  = status.CritMultiplier + character.CritMultiplier;
                    ApplyStatusEffects(status, character);
                    matchingStatus.StackCount++;
                }
                // If the status is stackable but has reached its stack limit, refresh the duration only
                else if (status.Stackable)
                {
                    matchingStatus.TurnsRemaining = status.Duration;
                }
                // If the status isn't stackable, refresh the duration and reset the damage
                else
                {
                    matchingStatus.TurnsRemaining = status.Duration;
                    matchingStatus.TotalDamage    = DamageCalculator.GetDamage(applicator, status);
                    matchingStatus.HealAmount     = DamageCalculator.GetHealing(applicator, status);
                    matchingStatus.HealPercentage = DamageCalculator.GetHealingPercentage(applicator, status);
                    matchingStatus.CritChance     = status.CritChance + character.CritChance;
                    matchingStatus.CritMultiplier = status.CritMultiplier + character.CritMultiplier;
                }
            }
            // Create and apply a new status effect on a character
            else
            {
                ApplyStatusEffects(status, character);
                _appliedStatuses[character].Add(CreateAppliedStatus(applicator, status));
                if (status.IsDebuff)
                {
                    character.Debuffs.Add(status);
                }
                else
                {
                    character.Buffs.Add(status);
                }
            }

            if (invokeAppliedStatusEvent)
            {
                StatusEffectApplied?.Invoke(this, new StatusEffectAppliedEventArgs()
                {
                    AffectedCharacterIds = new List <int>()
                    {
                        character.Id
                    },
                    LogMessage = CombatMessenger.GetAffectedByStatusMessage(status.Name, character.Name)
                });
            }
        }