class_name PauseMenu extends Control ## In-game Pause & System Menu overlay. ## ## Provides resume, settings, controls guide, and safe exit confirmation. signal resume_requested signal edit_world_requested signal friends_requested signal chat_requested signal controls_requested signal leave_world_confirmed var can_edit: bool = false var world_title: String = "World" var _confirm_box: VBoxContainer var _main_menu_vbox: VBoxContainer var _fs_button: Button func _init(p_can_edit: bool = false, p_world_title: String = "World") -> void: name = "PauseMenu" can_edit = p_can_edit world_title = p_world_title set_anchors_preset(Control.PRESET_FULL_RECT) func _ready() -> void: mouse_filter = Control.MOUSE_FILTER_STOP # Dark semi-transparent background var bg := ColorRect.new() bg.color = Color(0.05, 0.07, 0.10, 0.85) bg.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(bg) var center := CenterContainer.new() center.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(center) var panel := PanelContainer.new() panel.custom_minimum_size = Vector2(400, 0) var style := StyleBoxFlat.new() style.bg_color = Color(0.12, 0.14, 0.18, 0.98) style.border_color = Color(0.35, 0.45, 0.65, 1.0) style.set_border_width_all(2) style.set_corner_radius_all(10) style.content_margin_left = 28 style.content_margin_right = 28 style.content_margin_top = 24 style.content_margin_bottom = 24 panel.add_theme_stylebox_override("panel", style) center.add_child(panel) var root_vbox := VBoxContainer.new() root_vbox.add_theme_constant_override("separation", 16) panel.add_child(root_vbox) # Title & World info var header_vbox := VBoxContainer.new() header_vbox.add_theme_constant_override("separation", 4) root_vbox.add_child(header_vbox) var title := Label.new() title.text = "PAUSED" title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER title.add_theme_font_size_override("font_size", 28) title.add_theme_color_override("font_color", Color(1.0, 1.0, 1.0)) header_vbox.add_child(title) var subtitle := Label.new() subtitle.text = world_title subtitle.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER subtitle.add_theme_font_size_override("font_size", 14) subtitle.add_theme_color_override("font_color", Color(0.65, 0.75, 0.9)) header_vbox.add_child(subtitle) # Main action buttons _main_menu_vbox = VBoxContainer.new() _main_menu_vbox.add_theme_constant_override("separation", 10) root_vbox.add_child(_main_menu_vbox) var resume_btn := _make_menu_btn("▶ Resume Game (ESC)", _on_resume_pressed, Color(0.4, 0.9, 0.5)) _main_menu_vbox.add_child(resume_btn) if can_edit: var edit_btn := _make_menu_btn("🛠️ Creator Studio / Edit World (F2)", func(): edit_world_requested.emit()) _main_menu_vbox.add_child(edit_btn) var friends_btn := _make_menu_btn("👥 Friends & Social (F1)", func(): friends_requested.emit()) _main_menu_vbox.add_child(friends_btn) var chat_btn := _make_menu_btn("💬 Chat (T / Enter)", func(): chat_requested.emit()) _main_menu_vbox.add_child(chat_btn) var controls_btn := _make_menu_btn("⌨️ Controls & Keybindings", func(): controls_requested.emit()) _main_menu_vbox.add_child(controls_btn) _fs_button = _make_menu_btn("⛶ Toggle Fullscreen (F11)", _on_toggle_fs) _update_fs_label() _main_menu_vbox.add_child(_fs_button) var leave_btn := _make_menu_btn("🚪 Leave World", _on_prompt_leave, Color(1.0, 0.45, 0.45)) _main_menu_vbox.add_child(leave_btn) # Confirmation Box (hidden initially) _confirm_box = VBoxContainer.new() _confirm_box.visible = false _confirm_box.add_theme_constant_override("separation", 14) root_vbox.add_child(_confirm_box) var confirm_msg := Label.new() confirm_msg.text = "Are you sure you want to leave this world?\nAny unsaved changes will be lost." confirm_msg.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER confirm_msg.autowrap_mode = TextServer.AUTOWRAP_WORD confirm_msg.add_theme_font_size_override("font_size", 14) confirm_msg.add_theme_color_override("font_color", Color(1.0, 0.85, 0.85)) _confirm_box.add_child(confirm_msg) var confirm_btns := HBoxContainer.new() confirm_btns.alignment = BoxContainer.ALIGNMENT_CENTER confirm_btns.add_theme_constant_override("separation", 16) _confirm_box.add_child(confirm_btns) var cancel_leave_btn := Button.new() cancel_leave_btn.text = "Stay in World" cancel_leave_btn.custom_minimum_size = Vector2(130, 36) cancel_leave_btn.pressed.connect(_on_cancel_leave) confirm_btns.add_child(cancel_leave_btn) var confirm_leave_btn := Button.new() confirm_leave_btn.text = "Confirm Leave" confirm_leave_btn.custom_minimum_size = Vector2(130, 36) confirm_leave_btn.add_theme_color_override("font_color", Color(1.0, 0.4, 0.4)) confirm_leave_btn.pressed.connect(func(): leave_world_confirmed.emit()) confirm_btns.add_child(confirm_leave_btn) func _make_menu_btn(label: String, callback: Callable, color: Color = Color.WHITE) -> Button: var btn := Button.new() btn.text = label btn.custom_minimum_size = Vector2(0, 38) if color != Color.WHITE: btn.add_theme_color_override("font_color", color) btn.pressed.connect(callback) return btn func _on_resume_pressed() -> void: resume_requested.emit() func _on_toggle_fs() -> void: Session.toggle_fullscreen() _update_fs_label() func _update_fs_label() -> void: if _fs_button == null: return if DisplayServer.get_name() == "headless": _fs_button.text = "⛶ Toggle Fullscreen (F11)" return var m := DisplayServer.window_get_mode() if m == DisplayServer.WINDOW_MODE_FULLSCREEN or m == DisplayServer.WINDOW_MODE_EXCLUSIVE_FULLSCREEN: _fs_button.text = "🗗 Windowed Mode (F11)" else: _fs_button.text = "⛶ Fullscreen Mode (F11)" func _on_prompt_leave() -> void: _main_menu_vbox.visible = false _confirm_box.visible = true func _on_cancel_leave() -> void: _confirm_box.visible = false _main_menu_vbox.visible = true func _unhandled_input(event: InputEvent) -> void: if event.is_action_pressed("ui_cancel"): get_viewport().set_input_as_handled() if _confirm_box.visible: _on_cancel_leave() else: _on_resume_pressed()