using System; using Core; using UnityEngine; namespace Minigames.Airplane.Abilities { /// /// Abstract base class for airplane special abilities. /// Each ability defines its own execution logic, input handling, and cooldown. /// Subclasses override Execute() to implement specific ability behavior. /// Created from settings configuration at runtime. /// [System.Serializable] public abstract class BaseAirplaneAbility { #region Configuration protected readonly string abilityName; protected readonly Sprite abilityIcon; protected readonly float cooldownDuration; protected readonly bool canReuse; protected bool showDebugLogs; // Active duration configuration protected readonly float maxActiveDuration; protected readonly bool hasActiveDuration; #endregion #region Constructor /// /// Base constructor for abilities. Called by subclasses. /// protected BaseAirplaneAbility(string name, Sprite icon, float cooldown, bool reusable = true, float activeDuration = 0f) { abilityName = name; abilityIcon = icon; cooldownDuration = cooldown; canReuse = reusable; showDebugLogs = false; maxActiveDuration = activeDuration; hasActiveDuration = activeDuration > 0f; } #endregion #region Properties public string AbilityName => abilityName; public Sprite AbilityIcon => abilityIcon; public float CooldownDuration => cooldownDuration; public bool CanReuse => canReuse; public bool HasActiveDuration => hasActiveDuration; public float MaxActiveDuration => maxActiveDuration; #endregion #region State (Runtime) protected Core.AirplaneController currentAirplane; protected bool isActive; protected bool isOnCooldown; protected float cooldownTimer; protected float initialCooldownDuration; // Track initial cooldown for fill calculation // Active duration tracking protected float activeDurationTimer; protected float activeDurationUsed; // Track how long ability was active public bool IsActive => isActive; public bool IsOnCooldown => isOnCooldown; public float CooldownRemaining => cooldownTimer; public float InitialCooldownDuration => initialCooldownDuration; public bool CanActivate => !isOnCooldown && !isActive && currentAirplane != null && currentAirplane.IsFlying; // Active duration state public float ActiveDurationRemaining => activeDurationTimer; public float ActiveProgress => hasActiveDuration && maxActiveDuration > 0f ? activeDurationTimer / maxActiveDuration : 0f; #endregion #region Events public event Action OnAbilityActivated; public event Action OnAbilityDeactivated; public event Action OnCooldownChanged; // (remaining, total) public event Action OnActiveDurationChanged; // (remaining, total) #endregion #region Lifecycle /// /// Initialize ability with airplane reference. /// Called when airplane is spawned. /// public virtual void Initialize(Core.AirplaneController airplane) { currentAirplane = airplane; isActive = false; isOnCooldown = false; cooldownTimer = 0f; initialCooldownDuration = 0f; activeDurationTimer = 0f; activeDurationUsed = 0f; if (showDebugLogs) { Logging.Debug($"[{abilityName}] Initialized with airplane"); } } /// /// Update cooldown timer. Called every frame by ability manager. /// public virtual void UpdateCooldown(float deltaTime) { if (isOnCooldown) { cooldownTimer -= deltaTime; if (cooldownTimer <= 0f) { cooldownTimer = 0f; isOnCooldown = false; if (showDebugLogs) { Logging.Debug($"[{abilityName}] Cooldown complete"); } } OnCooldownChanged?.Invoke(cooldownTimer, initialCooldownDuration); } } /// /// Update active duration timer. Called every frame by ability manager when ability is active. /// Auto-deactivates when duration expires. /// public virtual void UpdateActiveDuration(float deltaTime) { if (!isActive || !hasActiveDuration) return; activeDurationTimer -= deltaTime; activeDurationUsed += deltaTime; if (activeDurationTimer <= 0f) { activeDurationTimer = 0f; if (showDebugLogs) { Logging.Debug($"[{abilityName}] Active duration expired, auto-deactivating"); } // Auto-deactivate when duration expires Deactivate(); } OnActiveDurationChanged?.Invoke(activeDurationTimer, maxActiveDuration); } /// /// Cleanup when airplane is destroyed or flight ends. /// public virtual void Cleanup() { if (isActive) { Deactivate(); } currentAirplane = null; isActive = false; isOnCooldown = false; cooldownTimer = 0f; initialCooldownDuration = 0f; activeDurationTimer = 0f; activeDurationUsed = 0f; if (showDebugLogs) { Logging.Debug($"[{abilityName}] Cleaned up"); } } #endregion #region Abstract Methods (Must Override) /// /// Execute the ability effect. /// Override to implement specific ability behavior. /// public abstract void Execute(); /// /// Stop the ability effect (for sustained abilities). /// Override if ability can be deactivated. /// public virtual void Deactivate() { if (!isActive) return; isActive = false; OnAbilityDeactivated?.Invoke(this); // Calculate and start dynamic cooldown float dynamicCooldown = CalculateDynamicCooldown(); StartCooldown(dynamicCooldown); if (showDebugLogs) { Logging.Debug($"[{abilityName}] Deactivated"); } } /// /// Calculate cooldown duration based on ability usage. /// Override in subclasses for custom dynamic cooldown logic. /// Default: returns base cooldown duration. /// protected virtual float CalculateDynamicCooldown() { return cooldownDuration; } #endregion #region Protected Helpers /// /// Start ability activation (called by subclasses). /// protected virtual void StartActivation() { if (!CanActivate) { if (showDebugLogs) { Logging.Warning($"[{abilityName}] Cannot activate - IsOnCooldown: {isOnCooldown}, IsActive: {isActive}, CanFly: {currentAirplane?.IsFlying}"); } return; } isActive = true; // Reset active duration timer if ability has active duration if (hasActiveDuration) { activeDurationTimer = maxActiveDuration; activeDurationUsed = 0f; } OnAbilityActivated?.Invoke(this); if (showDebugLogs) { Logging.Debug($"[{abilityName}] Activated"); } } /// /// Start cooldown timer (called by subclasses after execution). /// protected virtual void StartCooldown(float? customCooldown = null) { isOnCooldown = true; cooldownTimer = customCooldown ?? cooldownDuration; initialCooldownDuration = cooldownTimer; // Store the initial cooldown value OnCooldownChanged?.Invoke(cooldownTimer, initialCooldownDuration); if (showDebugLogs) { Logging.Debug($"[{abilityName}] Cooldown started: {cooldownTimer}s"); } } /// /// Check if airplane reference is valid. /// protected bool ValidateAirplane() { if (currentAirplane == null) { Logging.Warning($"[{abilityName}] Cannot execute - airplane reference is null!"); return false; } if (!currentAirplane.IsFlying) { if (showDebugLogs) { Logging.Debug($"[{abilityName}] Cannot execute - airplane is not flying!"); } return false; } return true; } #endregion } }