class_name ComboWindow extends Node signal combo_updated(inputs: Array[StringName]) signal combo_cleared(reason: StringName) @export var size := 4 @export var clear_display_time := 0.35 var slots: Array[StringName] = [] var pending_clear_reason: StringName = &"" var _timer: Timer func _ready() -> void: _timer = Timer.new() _timer.one_shot = true _timer.timeout.connect(flush_pending_clear) add_child(_timer) func record(input: StringName) -> void: if input.is_empty(): return slots.append(input) combo_updated.emit(get_slots()) _emit_bus_signal("combo_updated", [get_slots()]) if slots.size() >= size: queue_clear(&"full") func get_slots() -> Array[StringName]: return slots.duplicate() func has_pending_clear() -> bool: return not pending_clear_reason.is_empty() func consume_pending_clear_reason() -> StringName: var reason := pending_clear_reason pending_clear_reason = &"" return reason func get_pattern() -> String: var pattern := "" for slot: StringName in slots: if slot != &"Ø": pattern += str(slot) return pattern func get_contiguous_pattern() -> String: var pattern := "" for index: int in range(slots.size() - 1, -1, -1): var slot := slots[index] if slot == &"Ø": break pattern = str(slot) + pattern return pattern func queue_clear(reason: StringName, delay := -1.0) -> void: pending_clear_reason = reason if _timer == null: return _timer.stop() _timer.wait_time = clear_display_time if delay < 0.0 else delay _timer.start() func cancel_pending_clear() -> void: pending_clear_reason = &"" if _timer != null: _timer.stop() func flush_pending_clear() -> void: var reason := consume_pending_clear_reason() if reason.is_empty(): return if _timer != null: _timer.stop() clear(reason) func clear(reason: StringName = &"") -> void: slots.clear() pending_clear_reason = &"" combo_cleared.emit(reason) _emit_bus_signal("combo_cleared", [reason]) combo_updated.emit(get_slots()) _emit_bus_signal("combo_updated", [get_slots()]) func _emit_bus_signal(signal_name: StringName, args: Array) -> void: if not is_inside_tree(): return var bus := _event_bus_or_null() if bus != null: bus.emit_signal(signal_name, args[0]) func _event_bus_or_null() -> Node: if not is_inside_tree(): return null return get_tree().root.get_node_or_null("EventBus")