class_name PauseOverlay extends CanvasLayer ## Shift pause overlay: resume, restart the shift, open settings, or quit to the ## venue menu. Opened with Esc from the world (or a dedicated pause action) and ## while the overlay is open the guard is frozen. signal resume_requested() signal restart_requested() signal settings_requested() signal quit_to_menu_requested() const UiArt := preload("res://src/game/ui/art.gd") var _root: Control = null var _resume_button: Button = null func _ready() -> void: layer = 18 _build() hide() func _build() -> void: _root = Control.new() _root.name = "PauseRoot" _root.set_anchors_preset(Control.PRESET_FULL_RECT) _root.mouse_filter = Control.MOUSE_FILTER_STOP add_child(_root) var art := UiArt.new() if not art.add_screen_backdrop(_root, "pause_overlay", Rect2(0.172, 0.097, 0.59, 0.813)): var bg := ColorRect.new() bg.color = Color(0.02, 0.03, 0.05, 0.82) bg.set_anchors_preset(Control.PRESET_FULL_RECT) bg.mouse_filter = Control.MOUSE_FILTER_IGNORE _root.add_child(bg) var center := CenterContainer.new() center.set_anchors_preset(Control.PRESET_FULL_RECT) _root.add_child(center) var column := VBoxContainer.new() column.custom_minimum_size = Vector2(320, 0) column.add_theme_constant_override("separation", 10) center.add_child(column) var title := Label.new() title.text = "Paused" title.add_theme_font_size_override("font_size", 36) title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER column.add_child(title) _resume_button = _add_button(column, "Resume", "ResumeButton", func(): resume_requested.emit()) _add_button(column, "Restart shift", "RestartButton", func(): restart_requested.emit()) _add_button(column, "Settings", "SettingsButton", func(): settings_requested.emit()) _add_button(column, "Quit to menu", "MenuButton", func(): quit_to_menu_requested.emit()) var hint := Label.new() hint.text = "Esc resumes" hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER hint.add_theme_color_override("font_color", Color(0.55, 0.58, 0.65)) column.add_child(hint) func _add_button(parent: Control, text: String, node_name: String, cb: Callable) -> Button: var button := Button.new() button.name = node_name button.text = text button.custom_minimum_size = Vector2(380, 52) button.add_theme_font_size_override("font_size", 22) var normal := StyleBoxFlat.new() normal.bg_color = Color(0.115, 0.125, 0.15, 0.96) normal.corner_radius_top_left = 12 normal.corner_radius_top_right = 12 normal.corner_radius_bottom_left = 12 normal.corner_radius_bottom_right = 12 var hover := normal.duplicate() as StyleBoxFlat hover.bg_color = Color(0.16, 0.175, 0.21, 0.98) button.add_theme_stylebox_override("normal", normal) button.add_theme_stylebox_override("hover", hover) button.add_theme_stylebox_override("focus", hover) button.add_theme_stylebox_override("pressed", hover) button.pressed.connect(cb) parent.add_child(button) return button func open() -> void: visible = true _root.visible = true Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) if _resume_button: _resume_button.grab_focus() func close() -> void: visible = false _root.visible = false func _unhandled_input(event: InputEvent) -> void: if not visible: return if event is InputEventKey and event.pressed and not event.echo and event.keycode == KEY_ESCAPE: resume_requested.emit() get_viewport().set_input_as_handled()