class_name GCDTimer extends RefCounted ## Global Cooldown timer. Server-authoritative. ## Controls the rhythm of combat: combo hits and on-GCD abilities ## consume a GCD tick; off-GCD abilities do not interact with this timer. var _remaining: float = 0.0 var _total: float = 2.5 var _queue_window: float = 0.3 # Input queuing window (last 0.3s of sweep) ## Creates a new GCD timer with the given duration in seconds. func _init(gcd_duration: float = 2.5): _total = gcd_duration _remaining = 0.0 ## Returns true if the GCD is ready to accept a new on-GCD action. func is_ready() -> bool: return _remaining <= 0.0 ## Returns true if we're within the input queuing window. ## Actions pressed during this window will fire the instant the GCD completes. func is_in_queue_window() -> bool: return _remaining > 0.0 and _remaining <= _queue_window ## Advances the timer by delta_time seconds. Call once per server tick. func tick(delta_time: float) -> void: if _remaining > 0.0: _remaining = max(_remaining - delta_time, 0.0) ## Attempts to consume a GCD tick. Returns true if successful (GCD was ready), ## false if the GCD is still active. On success, restarts the full timer. func consume() -> bool: if not is_ready(): return false _remaining = _total return true ## Returns progress from 0.0 (just consumed) to 1.0 (ready). ## Used for UI radial sweep rendering. func get_progress() -> float: if _total <= 0.0: return 1.0 return 1.0 - (_remaining / _total) ## Returns the remaining time in seconds. func get_remaining() -> float: return _remaining ## Returns the total GCD duration in seconds. func get_total() -> float: return _total ## Modifies the GCD duration. Can be called by Artifact modifiers. ## If the GCD is currently active, the remaining time is scaled proportionally. func set_duration(new_duration: float) -> void: if new_duration <= 0.0: push_warning("GCDTimer: duration must be > 0") return var progress := get_progress() _total = new_duration if _remaining > 0.0: _remaining = _total * (1.0 - progress) ## Resets the timer to ready state (e.g., between fights). func reset() -> void: _remaining = 0.0