Files
AppleHillsProduction/Assets/Scripts/Minigames/Airplane/Abilities/BaseAirplaneAbility.cs
2025-12-18 12:09:58 +01:00

308 lines
10 KiB
C#

using System;
using Core;
using UnityEngine;
namespace Minigames.Airplane.Abilities
{
/// <summary>
/// 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.
/// </summary>
[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
/// <summary>
/// Base constructor for abilities. Called by subclasses.
/// </summary>
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<BaseAirplaneAbility> OnAbilityActivated;
public event Action<BaseAirplaneAbility> OnAbilityDeactivated;
public event Action<float, float> OnCooldownChanged; // (remaining, total)
public event Action<float, float> OnActiveDurationChanged; // (remaining, total)
#endregion
#region Lifecycle
/// <summary>
/// Initialize ability with airplane reference.
/// Called when airplane is spawned.
/// </summary>
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");
}
}
/// <summary>
/// Update cooldown timer. Called every frame by ability manager.
/// </summary>
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);
}
}
/// <summary>
/// Update active duration timer. Called every frame by ability manager when ability is active.
/// Auto-deactivates when duration expires.
/// </summary>
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);
}
/// <summary>
/// Cleanup when airplane is destroyed or flight ends.
/// </summary>
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)
/// <summary>
/// Execute the ability effect.
/// Override to implement specific ability behavior.
/// </summary>
public abstract void Execute();
/// <summary>
/// Stop the ability effect (for sustained abilities).
/// Override if ability can be deactivated.
/// </summary>
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");
}
}
/// <summary>
/// Calculate cooldown duration based on ability usage.
/// Override in subclasses for custom dynamic cooldown logic.
/// Default: returns base cooldown duration.
/// </summary>
protected virtual float CalculateDynamicCooldown()
{
return cooldownDuration;
}
#endregion
#region Protected Helpers
/// <summary>
/// Start ability activation (called by subclasses).
/// </summary>
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");
}
}
/// <summary>
/// Start cooldown timer (called by subclasses after execution).
/// </summary>
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");
}
}
/// <summary>
/// Check if airplane reference is valid.
/// </summary>
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
}
}