extends Node signal combo_changed(count: int, multiplier: float) signal combo_broken(final_count: int) const WINDOW_SEC: float = 1.8 const STEP_BONUS: float = 0.15 # +15% per combo step const MAX_MULT: float = 3.0 var count: int = 0 var multiplier: float = 1.0 var _timer: float = 0.0 var _active: bool = false func _process(delta: float) -> void: if not _active: return _timer -= delta if _timer <= 0.0: _break() func bump() -> float: # Advances combo and returns multiplier to apply to the triggering gain. count += 1 multiplier = minf(1.0 + float(count - 1) * STEP_BONUS, MAX_MULT) _timer = WINDOW_SEC _active = true combo_changed.emit(count, multiplier) return multiplier func _break() -> void: var final_count: int = count _active = false combo_changed.emit(0, 1.0) if final_count >= 2: combo_broken.emit(final_count) count = 0 multiplier = 1.0 _timer = 0.0 func time_remaining_ratio() -> float: if not _active: return 0.0 return clampf(_timer / WINDOW_SEC, 0.0, 1.0)