using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace MBT { [AddComponentMenu("")] [MBTNode(name = "Decorators/Cooldown")] public class Cooldown : Decorator, IMonoBehaviourTreeTickListener { public AbortTypes abort = AbortTypes.None; [Space] public FloatReference time = new FloatReference(1f); [Tooltip("When set to true, there will be no cooldown when child node returns failure")] public bool resetOnChildFailure = false; private float cooldownTime = 0f; private bool entered = false; private bool childFailed = false; public enum AbortTypes { None, LowerPriority } public override void OnAllowInterrupt() { if (abort == AbortTypes.LowerPriority) { ObtainTreeSnapshot(); } } public override NodeResult Execute() { if (!TryGetChild(out Node node)) { return NodeResult.failure; } if (node.status == Status.Success) { return NodeResult.success; } if (node.status == Status.Failure) { // If reset option is enabled flag will be raised and set true childFailed = resetOnChildFailure; return NodeResult.failure; } if (cooldownTime <= Time.time) { entered = true; return node.runningNodeResult; } else { return NodeResult.failure; } } public override void OnExit() { // Setup cooldown and event when child was entered // Check reset option too if (entered && !childFailed) { cooldownTime = Time.time + time.Value; // For LowerPriority try to abort after given time if (abort == AbortTypes.LowerPriority) { behaviourTree.AddTickListener(this); } } // Reset flags entered = false; childFailed = false; } public override void OnDisallowInterrupt() { behaviourTree.RemoveTickListener(this); } void IMonoBehaviourTreeTickListener.OnBehaviourTreeTick() { if (cooldownTime <= Time.time) { // Task should be aborted, so there is no need to listen anymore behaviourTree.RemoveTickListener(this); TryAbort(Abort.LowerPriority); } } } }