using Godot;
namespace Cirno.Scripts.Interactables;
///
/// Listens to the signal and plays a named animation
/// on an that reflects the switch's new state.
///
/// Works with any Switch3D subclass (including ).
///
/// Usage:
/// 1. Add this node as a child of the Switch3D node.
/// 2. Optionally assign and
/// in the inspector; if left empty both are discovered automatically from the parent.
/// 3. Set the three animation name exports to match animations in your AnimationPlayer.
/// Leave a name empty to skip playing an animation for that state.
///
[Tool]
public partial class SwitchAnimationManager : Node
{
///
/// The switch to listen to. Auto-discovered from the parent if left empty.
///
[Export] public Switch3D TargetSwitch { get; set; }
///
/// The AnimationPlayer to drive. Auto-discovered from the parent if left empty.
///
[Export] public AnimationPlayer TargetAnimationPlayer { get; set; }
// --- State-based animation name exports ---
/// Animation to play when the switch transitions to the enabled (on) state.
[Export] public StringName AnimationEnabled { get; set; } = "";
/// Animation to play when the switch transitions to the disabled (off) state.
[Export] public StringName AnimationDisabled { get; set; } = "";
/// Animation to play when the switch is destroyed.
[Export] public StringName AnimationDestroyed { get; set; } = "";
///
/// Whether the switch is currently considered enabled (on) or disabled (off).
/// Updated on each successful activation.
///
public bool IsEnabled { get; private set; }
///
/// When true the switch has been destroyed and will no longer respond to activations.
///
public bool IsDestroyed { get; private set; }
public override void _Ready()
{
if (Engine.IsEditorHint()) return;
ResolveReferences();
if (TargetSwitch is null)
{
GD.PushWarning($"[SwitchAnimationManager:{Name}] No Switch3D found. Assign TargetSwitch or place this node as a child of one.");
return;
}
TargetSwitch.OnActivated += OnSwitchActivated;
// Start in the disabled state so the AnimationPlayer is running from the beginning.
PlayAnimation(AnimationDisabled);
}
///
/// Fills in and from the
/// parent node when they have not been assigned explicitly in the inspector.
///
private void ResolveReferences()
{
var parent = GetParent();
if (TargetSwitch is null)
TargetSwitch = parent as Switch3D;
if (TargetAnimationPlayer is null)
TargetAnimationPlayer = parent?.FindChild("AnimationPlayer", recursive: true, owned: false) as AnimationPlayer
?? parent?.GetNodeOrNull("AnimationPlayer");
}
private void OnSwitchActivated(ActivationType activationType, bool success)
{
// Ignore failed activations and permanently destroyed switches.
if (!success || IsDestroyed) return;
UpdateState(activationType);
StringName animationName = IsDestroyed ? AnimationDestroyed
: IsEnabled ? AnimationEnabled
: AnimationDisabled;
PlayAnimation(animationName);
}
///
/// Transitions (and ) according to
/// the activation type that was successfully applied:
///
/// - / → enabled
/// - / → disabled
/// - / → inverted
/// - → disabled + destroyed
///
///
private void UpdateState(ActivationType activationType)
{
switch (activationType)
{
case ActivationType.Enable:
case ActivationType.Open:
IsEnabled = true;
break;
case ActivationType.Disable:
case ActivationType.Close:
IsEnabled = false;
break;
case ActivationType.Toggle:
case ActivationType.Use:
IsEnabled = !IsEnabled;
break;
case ActivationType.Destroy:
IsEnabled = false;
IsDestroyed = true;
break;
}
}
///
/// Plays the given animation on if the name is non-empty
/// and the animation exists. Pushes a warning otherwise.
///
private void PlayAnimation(StringName animationName)
{
if (animationName is null || animationName == "") return;
if (TargetAnimationPlayer is null)
{
GD.PushWarning($"[SwitchAnimationManager:{Name}] No AnimationPlayer found. Assign TargetAnimationPlayer or add one under the switch.");
return;
}
if (!TargetAnimationPlayer.HasAnimation(animationName))
{
GD.PushWarning($"[SwitchAnimationManager:{Name}] AnimationPlayer has no animation named '{(string)animationName}'.");
return;
}
TargetAnimationPlayer.Play(animationName);
}
}