using Cirno.Scripts.Weapons; using Godot; namespace Cirno.Scripts.Interactables; /// /// A Switch3D variant that activates when hit by a Bullet3D. /// Supports filtering by bullet owner and an optional cooldown between activations. /// [Tool] public partial class ShootableSwitch3D : Switch3D { /// /// Which bullet owner can trigger this switch. /// None means both Player and Enemy bullets are accepted. /// [Export] public BulletOwner ReactsTo { get; set; } = BulletOwner.None; /// /// Minimum time in seconds between consecutive activations. 0 disables the cooldown. /// [Export] public float CooldownSeconds { get; set; } = 0f; /// /// Enable runtime debug logging for this node. Toggle in the editor to diagnose bullet-trigger behavior. /// [Export] public bool EnableDebugLogs { get; set; } = false; private double _cooldownRemaining = 0.0; // Track whether we were on cooldown last frame so we don't spam logs every frame. private bool _wasOnCooldown = false; public override void _Ready() { base._Ready(); Log($"_Ready() called (EditorHint={Engine.IsEditorHint()})"); // Log the initial ActivationType (name + numeric) to make it obvious what value was deserialized. Log($"Initial ActivationType={ActivationType} ({(int)ActivationType})"); if (Engine.IsEditorHint()) return; AreaEntered += OnAreaEntered; Log("Subscribed to AreaEntered events"); } public override void _Process(double delta) { if (_cooldownRemaining > 0.0) { // Log only when cooldown starts/ends to avoid spamming the console every frame. if (!_wasOnCooldown) { Log($"Cooldown started: {_cooldownRemaining:F2}s"); _wasOnCooldown = true; } _cooldownRemaining -= delta; if (_cooldownRemaining <= 0.0 && _wasOnCooldown) { Log("Cooldown ended"); _wasOnCooldown = false; } } } private void OnAreaEntered(Area3D area) { Log($"AreaEntered event received from: {area?.GetType().Name}"); if (area is not Bullet3D bullet) { Log("Area is not a Bullet3D - ignoring"); return; } Log($"Bullet detected - Enabled={bullet.Enabled}, Owner={bullet.BulletOwner}"); if (!bullet.Enabled) { Log("Bullet is disabled - ignoring"); return; } // Filter by owner if a specific owner is configured if (ReactsTo is not BulletOwner.None && bullet.BulletOwner != ReactsTo) { Log($"Bullet owner {bullet.BulletOwner} does not match configured ReactsTo={ReactsTo} - ignoring"); return; } if (_cooldownRemaining > 0.0) { Log($"On cooldown ({_cooldownRemaining:F2}s remaining) - ignoring"); return; } Log("Requesting bullet collision destruction"); bullet.RequestCollisionDestruction(); // Include the numeric value when logging so it's easy to cross-reference serialized files. Log($"Activating switch (ActivationType={ActivationType} ({(int)ActivationType}))"); Activate(ActivationType); if (CooldownSeconds > 0f) { _cooldownRemaining = CooldownSeconds; Log($"Cooldown set to {CooldownSeconds:F2}s"); } } /// /// Helper to centralize debug printing and include the node name for easier filtering. /// Respects the toggle. /// /// Message to print when logging is enabled. private void Log(string message) { if (!EnableDebugLogs) return; GD.Print($"[ShootableSwitch3D:{Name}] {message}"); } }