extends CanvasLayer ## Lock adulto: sequenza giallo → verde → blu → rosso. signal unlocked const COLORS := { "giallo": Color("#e8b84b"), "verde": Color("#88ce96"), "blu": Color("#1852de"), "rosso": Color("#de6b7e"), "viola": Color("#9b7ede"), } const BALL_ORDER := ["giallo", "verde", "blu", "rosso", "viola"] const SEQUENCE := ["giallo", "verde", "blu", "rosso"] var sequence_attempt: Array[String] = [] var progress_dots: Array[LockProgressDot] = [] var _busy := false var _click: AudioStreamWAV var _wrong: AudioStreamWAV var _unlock: AudioStreamWAV func _ready() -> void: process_mode = Node.PROCESS_MODE_ALWAYS visible = false _click = AudioFactory.create_tone(660.0, 0.09, 0.28) _wrong = AudioFactory.create_tone(330.0, 0.11, 0.18) _unlock = AudioFactory.create_arpeggio([523.25, 659.25, 783.99], 0.09, 0.24) _build() func _build() -> void: var dim := ColorRect.new() dim.color = Color(0.06, 0.035, 0.025, 0.78) dim.set_anchors_preset(Control.PRESET_FULL_RECT) dim.mouse_filter = Control.MOUSE_FILTER_STOP add_child(dim) var center := CenterContainer.new() center.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(center) var frame := PanelContainer.new() frame.custom_minimum_size = Vector2(720, 420) var frame_style := CircusTheme.flat_style(Color("#70411f"), Color("#e1ba59"), 6, 30) frame_style.shadow_color = Color(0, 0, 0, 0.52) frame_style.shadow_size = 20 frame_style.shadow_offset = Vector2(0, 8) for side in [SIDE_LEFT, SIDE_TOP, SIDE_RIGHT, SIDE_BOTTOM]: frame_style.set_content_margin(side, 10.0) frame.add_theme_stylebox_override("panel", frame_style) center.add_child(frame) var panel := PanelContainer.new() panel.add_theme_stylebox_override("panel", CircusTheme.wood_style()) frame.add_child(panel) var margin := MarginContainer.new() margin.add_theme_constant_override("margin_left", 42) margin.add_theme_constant_override("margin_right", 42) margin.add_theme_constant_override("margin_top", 27) margin.add_theme_constant_override("margin_bottom", 25) panel.add_child(margin) var content := VBoxContainer.new() content.add_theme_constant_override("separation", 12) margin.add_child(content) _add_header(content) _add_marbles(content) _add_progress(content) _add_cancel(content) func _add_header(parent: VBoxContainer) -> void: var title := Label.new() title.text = "AREA RISERVATA" title.add_theme_font_override("font", CircusTheme.FONT) title.add_theme_font_size_override("font_size", 36) title.add_theme_color_override("font_color", Color("#ffe08a")) title.add_theme_color_override("font_outline_color", Color("#673018")) title.add_theme_constant_override("outline_size", 8) title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER parent.add_child(title) var hint := Label.new() hint.text = "Chiedi a un adulto di premere la sequenza di colori" hint.add_theme_font_override("font", CircusTheme.FONT) hint.add_theme_font_size_override("font_size", 19) hint.add_theme_color_override("font_color", Color("#56321e")) hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER parent.add_child(hint) func _add_marbles(parent: VBoxContainer) -> void: var row := HBoxContainer.new() row.add_theme_constant_override("separation", 14) row.alignment = BoxContainer.ALIGNMENT_CENTER parent.add_child(row) for color_name in BALL_ORDER: var marble := LockMarbleButton.new() marble.setup(color_name, COLORS[color_name]) marble.chosen.connect(_on_press) row.add_child(marble) func _add_progress(parent: VBoxContainer) -> void: var row := HBoxContainer.new() row.alignment = BoxContainer.ALIGNMENT_CENTER row.add_theme_constant_override("separation", 12) parent.add_child(row) for index in SEQUENCE.size(): var dot := LockProgressDot.new() progress_dots.append(dot) row.add_child(dot) func _add_cancel(parent: VBoxContainer) -> void: var cancel := Button.new() cancel.text = "ANNULLA" cancel.custom_minimum_size = Vector2(210, 52) cancel.size_flags_horizontal = Control.SIZE_SHRINK_CENTER cancel.add_theme_font_override("font", CircusTheme.FONT) cancel.add_theme_font_size_override("font_size", 21) cancel.add_theme_color_override("font_color", Color("#fff0c4")) cancel.add_theme_stylebox_override("normal", CircusTheme.button_style(Color("#744020"), Color("#ce9b3d"), 4, 13)) cancel.add_theme_stylebox_override("hover", CircusTheme.button_style(Color("#8b5129"), Color("#f0ca68"), 4, 13)) cancel.add_theme_stylebox_override("pressed", CircusTheme.button_style(Color("#5c3019"), Color("#ae7927"), 4, 13)) cancel.pressed.connect(hide_menu) parent.add_child(cancel) func show_menu() -> void: sequence_attempt.clear() _update_progress() visible = true get_tree().paused = true func hide_menu() -> void: visible = false get_tree().paused = false func _on_press(color_name: String) -> void: if _busy: return AudioFactory.play_once(self, _click) sequence_attempt.append(color_name) _update_progress() if sequence_attempt.size() == SEQUENCE.size(): if sequence_attempt == SEQUENCE: call_deferred("_finish_unlock") else: _handle_wrong() func _handle_wrong() -> void: _busy = true AudioFactory.play_once(self, _wrong) for dot in progress_dots: dot.set_color(Color("#d9534f")) await get_tree().create_timer(2.0).timeout sequence_attempt.clear() _update_progress() _busy = false func _finish_unlock() -> void: AudioFactory.play_once(self, _unlock) hide_menu() unlocked.emit() func _update_progress() -> void: for index in progress_dots.size(): var color: Color = COLORS[sequence_attempt[index]] if index < sequence_attempt.size() else Color.TRANSPARENT progress_dots[index].set_color(color)