extends Control @onready var title_label: Label = $Center/Window/V/TitleBar/Title @onready var body_label: RichTextLabel = $Center/Window/V/Body @onready var input_field: LineEdit = $Center/Window/V/Input @onready var input_hint: Label = $Center/Window/V/InputHint @onready var btn_a: Button = $Center/Window/V/Buttons/BtnA @onready var btn_b: Button = $Center/Window/V/Buttons/BtnB @onready var error_label: Label = $Center/Window/V/ErrorLabel @onready var checkbox_no_pwd: CheckBox = $Center/Window/V/CheckBoxNoPwd @onready var tz_dropdown: OptionButton = $Center/Window/V/TimeZone @onready var progress_bar: ProgressBar = $Center/Window/V/Progress @onready var four_squares: Control = $FourSquares @onready var welcome_screen: Control = $WelcomeScreen @onready var welcome_text: Label = $WelcomeScreen/V/WelcomeText enum Step { BOOT, LICENSE_INTRO, LICENSE_FULL, DISK, USERNAME, PASSWORD, TIMEZONE, INSTALLING, COMPLETE } var current_step: Step = Step.BOOT var license_read_clicked: bool = false const BANNED_TITLES: Array[String] = ["повелитель", "владыка", "бог", "лорд", "царь", "хозяин"] const BANNED_MAT: Array[String] = ["хуй", "пизд", "ебал", "ебан", "бля", "сук", "блять"] const USERNAME_PLACEHOLDERS: Array[String] = [ "bossiara13", "fr3sh_n3kit", "Vasyok_07", "neoLich", "Дима_за_рулём", "p1ano", ] const TIMEZONES: Array[String] = [ "UTC+2 (Калининград)", "UTC+3 (С., страна Р)", "UTC+4 (Самара)", "UTC+5 (Екатеринбург)", "UTC+7 (Новосибирск)", "UTC+9 (Иркутск)", "UTC+10 (Владивосток)", ] const LICENSE_SHORT: String = "[center][b]Лицензионное соглашение Шиндовс 9[/b][/center]\n\nНажимая «Принять», Вы соглашаетесь с условиями использования операционной системы Шиндовс-Корп.\n\nДля просмотра полного текста нажмите «Читать»." const LICENSE_FULL: String = "[center][b]Лицензионное соглашение Шиндовс 9 (полная версия)[/b][/center]\n\n[i]п. 1.1[/i] Настоящее Лицензионное соглашение является обязывающим юридическим документом между Вами (далее — Пользователь) и корпорацией Шиндовс-Корп (далее — Корпорация).\n\n[i]п. 1.2[/i] Установив, скопировав, загрузив или иным образом используя ПО Шиндовс 9, Пользователь подтверждает согласие с условиями настоящего соглашения в полном объёме.\n\n[i]п. 2.1[/i] Корпорация предоставляет Пользователю неисключительную, непередаваемую, отзываемую лицензию на использование ПО на одном персональном устройстве.\n\n[i]п. 3.4[/i] Запрещается дизассемблировать, декомпилировать или иным образом изучать внутреннюю работу ПО, кроме случаев, прямо разрешённых законодательством.\n\n[i]п. 4.2[/i] Корпорация оставляет за собой право обновлять, модифицировать или прекращать поддержку ПО в любое время без предварительного уведомления.\n\n[i]п. 5.1[/i] ПО предоставляется «как есть». Корпорация не несёт ответственности за любые прямые, косвенные или сопутствующие убытки, возникшие в результате использования ПО.\n\n[i]п. 6.8[/i] Пользователь обязуется не использовать ПО для деятельности, противоречащей законодательству страны проживания Пользователя.\n\n[i]п. 7.3.2[/i] Этот персональный компьютер, на который Вы устанавливаете ПО, формально остаётся собственностью корпорации Шиндовс-Корп до момента окончательной выплаты Вашей души (далее — Душа).\n\n[i]п. 11.4[/i] Корпорация оставляет за собой право в любой момент запустить процесс «svchost.exe» с приоритетом «realtime». Жалобы не принимаются.\n\n[i]п. 12.1[/i] Все ваши скриншоты могут быть использованы в обучении ИИ, который заменит Вас на работе к 2027 году. Согласие подразумевается.\n\n[i]п. 15.7[/i] Корпорация молча переустановит Защитник раз в сутки, если установлен сторонний антивирус.\n\n[i]п. 18.0[/i] Раз в год Ваш рабочий стол может быть перемещён в облако. Восстановление платное.\n\n[i]п. 21.3[/i] Корпорация не несёт ответственности за случаи, когда после обновления у Вас перестаёт работать звук, мышь или Wi-Fi. Это нормально. Перезагрузитесь.\n\n[i]п. 23.9[/i] Все приложения могут наблюдать друг за другом и отправлять телеметрию в Облако. Облако — это не место, а состояние ума.\n\n[i]п. 27.1[/i] Нажав «Принять», Вы соглашаетесь не читать это соглашение. Если Вы дочитали до этого пункта — Вы нарушили условия." func _ready() -> void: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE DialogManager.clear_prompt() DialogManager.set_controls_hint("") DialogManager.set_crosshair_visible(false) DialogManager.set_date_time(GameState.game_date, GameState.game_time) DialogManager.set_objective("Установи Шиндовс 9") welcome_screen.visible = false progress_bar.visible = false input_field.visible = false input_hint.visible = false checkbox_no_pwd.visible = false tz_dropdown.visible = false error_label.visible = false btn_a.pressed.connect(_on_btn_a) btn_b.pressed.connect(_on_btn_b) for tz in TIMEZONES: tz_dropdown.add_item(tz) tz_dropdown.select(1) # UTC+3 по умолчанию # BOOT: 4 квадратика на 1.5 сек four_squares.visible = true await get_tree().create_timer(1.6).timeout four_squares.visible = false _to_license_intro() func _set_body_compact() -> void: body_label.fit_content = true body_label.custom_minimum_size = Vector2(540, 0) func _set_body_scrollable(min_h: int) -> void: body_label.fit_content = false body_label.custom_minimum_size = Vector2(540, min_h) body_label.scroll_to_line(0) func _to_license_intro() -> void: current_step = Step.LICENSE_INTRO title_label.text = "Шиндовс 9 — Шаг 1 из 5" _set_body_compact() body_label.text = LICENSE_SHORT body_label.visible = true btn_a.text = "Принять" btn_a.visible = true btn_b.text = "Читать" btn_b.visible = true input_field.visible = false input_hint.visible = false checkbox_no_pwd.visible = false tz_dropdown.visible = false error_label.visible = false func _to_license_full() -> void: current_step = Step.LICENSE_FULL license_read_clicked = true title_label.text = "Шиндовс 9 — Полный текст соглашения (прокрути колесом мыши)" _set_body_scrollable(220) body_label.text = LICENSE_FULL btn_a.text = "Принять" btn_a.visible = true btn_b.visible = false func _to_disk() -> void: current_step = Step.DISK title_label.text = "Шиндовс 9 — Шаг 2 из 5" _set_body_compact() body_label.text = "[center][b]Выбор диска для установки[/b][/center]\n\n[•] Диск C:\\\\ (250 ГБ свободно)\n\nДругие диски не обнаружены." btn_a.text = "Далее" btn_a.visible = true btn_b.visible = false func _to_username() -> void: current_step = Step.USERNAME title_label.text = "Шиндовс 9 — Шаг 3 из 5" _set_body_compact() body_label.text = "[center][b]Введите имя пользователя[/b][/center]\n\nЭто имя будет использоваться в системе. Минимум 2 символа, максимум 24. Только буквы и цифры." var rng: RandomNumberGenerator = RandomNumberGenerator.new() rng.randomize() input_field.placeholder_text = USERNAME_PLACEHOLDERS[rng.randi() % USERNAME_PLACEHOLDERS.size()] input_field.text = "" input_field.visible = true input_field.editable = true input_field.grab_focus() input_hint.text = "Например: bossiara13, fr3sh_n3kit, Vasyok_07, neoLich, КошкоПовелитель… ой, нет, этот нельзя" input_hint.visible = true error_label.visible = false btn_a.text = "Далее" btn_a.visible = true btn_b.visible = false func _to_password() -> void: current_step = Step.PASSWORD title_label.text = "Шиндовс 9 — Шаг 4 из 5" _set_body_compact() body_label.text = "[center][b]Введите пароль[/b][/center]\n\nИли оставьте поле пустым / отметьте «Без пароля». Можно потом изменить в настройках." input_field.text = "" input_field.secret = true input_field.placeholder_text = "********" input_field.visible = true input_field.editable = true input_field.grab_focus() input_hint.text = "Совет: запиши себе на бумажку. Минимум 4 символа, если ставишь." input_hint.visible = true checkbox_no_pwd.visible = true checkbox_no_pwd.button_pressed = false error_label.visible = false btn_a.text = "Далее" btn_a.visible = true btn_b.visible = false func _to_timezone() -> void: current_step = Step.TIMEZONE title_label.text = "Шиндовс 9 — Шаг 5 из 5" _set_body_compact() body_label.text = "[center][b]Выберите часовой пояс[/b][/center]\n\nЭто повлияет на время в системе. По умолчанию — UTC+3 (С., страна Р)." input_field.visible = false input_field.secret = false input_hint.visible = false checkbox_no_pwd.visible = false tz_dropdown.visible = true btn_a.text = "Готово" btn_a.visible = true btn_b.visible = false func _to_installing() -> void: current_step = Step.INSTALLING title_label.text = "Шиндовс 9 — Установка" _set_body_compact() body_label.text = "[center]Подождите, пока система устанавливается.\nЭто займёт пару минут.[/center]" input_field.visible = false input_hint.visible = false checkbox_no_pwd.visible = false tz_dropdown.visible = false btn_a.visible = false btn_b.visible = false progress_bar.visible = true progress_bar.value = 0 _run_install_progress() func _run_install_progress() -> void: var stages: Array = [ ["Распаковка файлов…", 0.25], ["Установка драйверов…", 0.5], ["Настройка реестра…", 0.75], ["Применение конфигурации…", 0.95], ["Готово!", 1.0], ] for stage in stages: body_label.text = "[center]" + stage[0] + "[/center]" var tween: Tween = create_tween() tween.tween_property(progress_bar, "value", stage[1] * 100.0, 0.6) await tween.finished await get_tree().create_timer(0.4).timeout _to_complete() func _to_complete() -> void: current_step = Step.COMPLETE $Center.visible = false welcome_screen.visible = true welcome_text.text = "Добро пожаловать, %s." % GameState.player_name DialogManager.set_objective("") func _on_btn_a() -> void: match current_step: Step.LICENSE_INTRO: if license_read_clicked: GameState.unlock_achievement("Юрист") GameState.unlock_achievement("Нарушитель ЛС") _to_disk() Step.LICENSE_FULL: GameState.unlock_achievement("Юрист") GameState.unlock_achievement("Нарушитель ЛС") _to_disk() Step.DISK: _to_username() Step.USERNAME: _validate_and_set_username() Step.PASSWORD: _validate_and_set_password() Step.TIMEZONE: GameState.act2_timezone = TIMEZONES[tz_dropdown.selected] _to_installing() func _on_btn_b() -> void: match current_step: Step.LICENSE_INTRO: _to_license_full() func _validate_and_set_username() -> void: var name: String = input_field.text.strip_edges() var result: Dictionary = _validate_name(name) if not result.get("valid", false): error_label.text = result.get("error", "Ошибка") error_label.visible = true return GameState.player_name = name _to_password() func _validate_name(name: String) -> Dictionary: if name.length() < 2: return {"valid": false, "error": "Минимум 2 символа"} if name.length() > 24: return {"valid": false, "error": "Максимум 24 символа"} var re: RegEx = RegEx.new() re.compile("^[\\wа-яёА-ЯЁ_]+$") if not re.search(name): return {"valid": false, "error": "Только буквы, цифры и подчёркивания"} var lower: String = name.to_lower() for t in BANNED_TITLES: if t in lower: return {"valid": false, "error": "Без громких титулов, ок?"} for m in BANNED_MAT: if m in lower: return {"valid": false, "error": "Эээ, давай прилично"} return {"valid": true} func _validate_and_set_password() -> void: if checkbox_no_pwd.button_pressed: GameState.act2_password_set = false GameState.unlock_achievement("Главное чтоб удобно") _to_timezone() return var pwd: String = input_field.text if pwd.is_empty() or pwd in ["123", "qwerty", "password", "1234"]: GameState.act2_password_set = false GameState.unlock_achievement("Главное чтоб удобно") _to_timezone() return if pwd.length() >= 12 and _has_special(pwd): GameState.unlock_achievement("Параноик") GameState.act2_password_set = true _to_timezone() func _has_special(s: String) -> bool: var specials: String = "!@#$%^&*()-_+=<>?/.," for c in s: if c in specials: return true return false func _on_launch_steme() -> void: # Акт 3 пока не реализован — выходим GameState.unlock_achievement("Конец альфа-сессии") await DialogManager.say("СИСТЕМА", "Акт 3 (стеме Big Picture) — TBD в следующей итерации. Игрок: %s. Спасибо за тест!" % GameState.player_name) get_tree().quit()