using System.Collections.Generic; using System.Linq; using UnityEngine; public class TickingEffectHandler : StatusEffectHandler { // Separate list for ONLY ticking effects protected List tickingEffects = new List(); protected override void UpdateEffects(float deltaTime) { // Only iterate effects that can tick for (int i = 0; i < tickingEffects.Count; i++) { tickingEffects[i].Tick(deltaTime); } } protected override void UpdateCollections(StatusEffect effect, RuntimeEffectInstance runtimeEffect) { base.UpdateCollections(effect, runtimeEffect); // Track ticking effects separately if (runtimeEffect is TickingRuntimeEffectInstance tickingEffect) { tickingEffects.Add(tickingEffect); } } protected override void RemoveFromCollections(RuntimeEffectInstance runtimeEffect) { base.RemoveFromCollections(runtimeEffect); // Remove from ticking list if (runtimeEffect is TickingRuntimeEffectInstance tickingEffect) { tickingEffects.Remove(tickingEffect); } } #region Effect Query Utilities /// /// Get all effects of a specific type, optionally from a specific source /// public List GetEffects(StatusEffect effectType, Taggable source = null) { if (!activeEffectsByType.TryGetValue(effectType, out var effects)) return new List(); if (source == null) return new List(effects); return effects.Where(e => e.user == source).ToList(); } /// /// Get total stack count for a specific effect type /// public int GetStackCount(StatusEffect effectType, Taggable source = null) { var effects = GetEffects(effectType, source); return effects.Sum(e => e.numberOfStacks); } /// /// Get the strongest effect of a type (highest stack count) /// public RuntimeEffectInstance GetStrongestEffect(StatusEffect effectType) { if (!activeEffectsByType.TryGetValue(effectType, out var effects) || effects.Count == 0) return null; return effects.OrderByDescending(e => e.numberOfStacks).First(); } /// /// Get all damage ticking effects of a specific damage type /// public List GetDamageEffects(DamageType damageType) { return tickingEffects .OfType() .Where(effect => effect.sourceEffect is DamageOverTimeEffect source && source.damageType == damageType) .ToList(); } /// /// Get total damage per second from all DOTs of a specific type /// public float GetTotalDPS(DamageType damageType) { return GetDamageEffects(damageType) .Sum(effect => (effect.sourceEffect as DamageOverTimeEffect).baseDamagePerTick / GameConstants.GameBalancing.EffectsTickingRate); } /// /// Generic method to check for any effect matching a condition /// public bool HasEffectWhere(System.Func predicate) where T : RuntimeEffectInstance { return activeEffects.OfType().Any(predicate); } /// /// Get remaining time for the longest duration effect of a type /// public float GetRemainingTime(StatusEffect effectType) { if (!activeEffectsByType.TryGetValue(effectType, out var effects) || effects.Count == 0) return 0f; var longestEffect = effects.OrderByDescending(e => e.endEffectTime).First(); return Mathf.Max(0f, longestEffect.endEffectTime - Time.time); } #endregion #region Simplified Status Checks // Your existing methods can now be simplified: public bool IsBurning() => GetDamageEffects(DamageType.Fire).Count > 0; public bool IsPoisoned() => GetDamageEffects(DamageType.Poison).Count > 0; public bool IsBleeding() => GetDamageEffects(DamageType.Physical).Count > 0; // Additional useful checks: public int GetBurnStacks() => GetDamageEffects(DamageType.Fire).Sum(e => e.numberOfStacks); public float GetBurnDPS() => GetTotalDPS(DamageType.Fire); public float GetBurnTimeRemaining() => GetDamageEffects(DamageType.Fire).Max(e => e?.endEffectTime - Time.time ?? 0f); #endregion }