label main_menu: return init python: import random renpy.music.register_channel("ambient_generator", "ambient", loop=True) renpy.music.register_channel("ambient_server", "ambient", loop=True) renpy.music.register_channel("ambient_wind", "ambient", loop=True) renpy.music.register_channel("footsteps", "ambient", loop=False) _game_menu_screen = None _skipping = False coffee_done = False window_done = False power_done = False battery = 100 fragments = 0 thoughts_processed = False journal = [] date_input = "" current_input = [0, 0, 0, 0, 0] arget_code = [] time_left = 15 puzzle_parts = [False, False, False, False] puzzle_complete = False signal_sequence = [0, 1, 2] player_input = [] signal_active = True visited_locations = {"room": False, "corridor": False, "terminal": False} game_started = False def use_battery(amount): global battery battery -= amount if battery < 0: battery = 0 def generate_code(): return [random.randint(0, 9) for _ in range(5)] screen game_ui(): if game_started: frame: align (0.02, 0.02) vbox: text "ЭНЕРГИЯ: [battery]%" size 40 text "ФРАГМЕНТЫ: [fragments]/3" size 40 screen journal_button(): textbutton "ЖУРНАЛ" action Show("journal") align (0.98, 0.98) screen journal(): modal True frame: align (0.5, 0.5) xsize 700 ysize 500 vbox: text "МЫСЛИ" size 50 for entry in journal: text "- [entry]" size 20 if fragments >= 3 and not thoughts_processed: textbutton "ПОДУМАТЬ ОБ ЭТОМ": action [Hide("journal"), Jump("deep_reflection")] textbutton "ЗАКРЫТЬ" action Hide("journal") screen corridor_puzzle_screen(): modal True frame: align (0.5, 0.5) xsize 640 ysize 750 background "#333333" vbox: align (0.5, 0.5) spacing 20 grid 2 2: xalign 0.5 spacing 10 for i in range(4): button: action [ SetDict(puzzle_parts, i, True), Function(renpy.restart_interaction) ] xsize 300 ysize 300 background "#1a1a1a" if puzzle_parts[i]: add "puzzle_[i].png" align (0.5, 0.5) else: add "puzzle_unknown.png" align (0.5, 0.5) textbutton "ЗАВЕРШИТЬ СБОРКУ": action If(all(puzzle_parts), [Hide("corridor_puzzle_screen"), Return(True)], [Hide("corridor_puzzle_screen"), Return(False)]) xalign 0.5 xpadding 40 ypadding 20 background "#555555" screen terminal_code_game(): modal True timer 1.0 repeat True action If(time_left > 0, SetVariable("time_left", time_left - 1), Return(False)) frame: align (0.5, 0.5) padding (30, 30) xsize 650 ysize 450 background "#262626" vbox: spacing 20 text "ПОДБОР ЧАСТОТЫ" xalign 0.5 size 35 hbox: spacing 40 xalign 0.5 for i in range(5): vbox: spacing 5 xalign 0.5 textbutton "/\\": xsize 80 ysize 60 background "#494949ec" text_xalign 0.5 text_yalign 0 action SetDict(current_input, i, (current_input[i] + 1) % 10) text str(current_input[i]): xalign 0.5 color ("#3b7d3b" if current_input[i] == target_code[i] else "#9b0e0e") size 60 textbutton "\\/": xsize 80 ysize 60 background "#494949ec" text_xalign 0.5 text_yalign 0 action SetDict(current_input, i, (current_input[i] - 1) % 10) textbutton "ВВОД": action Return(current_input == target_code) xalign 0.5 yalign 1.0 xpadding 60 ypadding 10 background "#555555" null height 60 text "Осталось: [time_left] сек." xalign 0.5 size 50 color "#ffffff" screen keypad_screen(): modal True frame: align (0.5, 0.5) xsize 400 ysize 500 background "#262626d3" vbox: spacing 10 align (0.5, 0.5) null height 60 text "[date_input]" size 50 xalign 0.5 yalign 0.5 min_width 350 grid 3 4: spacing 15 xalign 0.5 for i in range(1, 10): textbutton str(i): action If(len(date_input) < 10, SetVariable("date_input", date_input + str(i)), None) background "#494949ec" xsize 80 ysize 80 xalign 0.5 text_xalign 0.5 text_yalign 0.5 textbutton ".": action If(len(date_input) < 10, SetVariable("date_input", date_input + "."), None) background "#363636ec" xsize 80 ysize 80 xalign 0.5 text_xalign 0.5 text_yalign 0.5 textbutton "0": action If(len(date_input) < 10, SetVariable("date_input", date_input + "0"), None) background "#494949ec" xsize 80 ysize 80 xalign 0.5 text_xalign 0.5 text_yalign 0.5 textbutton "<-": action SetVariable("date_input", date_input[:-1]) background "#363636ec" xsize 80 ysize 80 xalign 0.5 text_xalign 0.5 text_yalign 0.5 null height 20 textbutton "ВВОД" action Return(date_input): xalign 0.5 background "#555555d2" xpadding 40 transform slow_zoom_pan: zoom 1.0 linear 15.0 zoom 1.02 linear 15.0 zoom 1.0 repeat transform shake_effect(rate=0.090): zoom 1.1 align (0.5, 0.5) linear rate xoffset 2 yoffset -6 linear rate xoffset -2.8 yoffset -2 linear rate xoffset 2.8 yoffset -2 linear rate xoffset -2 yoffset -6 linear rate xoffset +0 yoffset +0 transform rotate_180: rotate 180 define chapter_title = Character(None, what_xalign=0.5, what_yalign=0.4, window_yalign=0.5, window_background = None ) label start: scene black play sound "audio/typing.ogg" loop fadein 0.5 chapter_title "{size=150}{cps=5}ТИШИНА{/cps}{/size}" with dissolve pause 2.0 hide text with dissolve chapter_title "{size=120}{cps=5}20.04.2023{/cps}{/size}" with dissolve pause 2.0 hide text with dissolve stop sound fadeout 0.5 $ player_name = renpy.input("Как меня зовут?", length=12) $ player_name = player_name.strip() if not player_name: $ player_name = "Техник" "Приятно познакомиться, [player_name]." jump phase_1_intro label phase_1_intro: $ routine_tasks = 0 scene bg_room at slow_zoom_pan with dissolve play music "audio/main_theme.ogg" $ renpy.music.set_volume(0.6, delay=0, channel='ambient_generator') play ambient_generator "audio/generator.ogg" "Я просыпаюсь. Шум генератора — единственное, что доказывает, что я еще здесь. Но сегодня этот звук другой. Он надтреснутый, хриплый, как дыхание умирающего." "Индикатор на консоли мигает тусклым оранжевым. 100\%. Это последняя порция топлива. Последние искры жизни этой консервной банки." "Семь лет назад я считал эту станцию своей крепостью. Теперь — это мой склеп, где я сам себе надсмотрщик, а генератор — мой метроном, отсчитывающий секунды до полной темноты." "В воздухе пахнет озоном, гнилью и невыполненными обещаниями. Я чувствую каждый вдох, как попытку проглотить этот тяжелый, мертвый воздух, который скоро станет моим единственным спутником." "Сегодня двадцатое апреля. И если верить датчикам, сегодня — последний день, когда станция сможет поддерживать жизнеобеспечение. К полуночи, если я не решусь на что-то, здесь станет холодно по-настоящему." "Мои руки привычно тянутся к вещам, которые я переставляю изо дня в день. Это не привычка. Это попытка доказать самому себе, что я всё ещё существую в этой физической реальности, а не стал частью фонового шума оборудования." "Мне нужно закончить утренний ритуал. Последний утренний ритуал. Только после этого я смогу сосредоточиться на том, чтобы принять решение, от которого я бежал три года." jump routine_loop label routine_loop: if "bg_room" not in renpy.get_showing_tags("master"): scene bg_room at slow_zoom_pan with dissolve $ renpy.music.set_volume(0.6, delay=0, channel='ambient_generator') if routine_tasks >= 3: jump start_game_proper "Комната кажется пустой, но в ней всё ещё остались вещи, которые требуют моего внимания. Вещи, которые я должен 'оживить' в последний раз." menu: "Налить остывший кофе" if not coffee_done: $ coffee_done = True $ routine_tasks += 1 play footsteps "audio/footsteps.ogg" pause 1.0 scene bg_room_coffee at slow_zoom_pan with dissolve play sound "audio/pouring.ogg" "Чашка холодная, стенки покрыты въевшимся коричневым налетом. Я смотрю на эту мутную жидкость и вспоминаю, как раньше мы спорили о том, какой сорт кофе лучше — с кислинкой или с горчинкой." "Теперь мне всё равно. Это просто топливо. Жидкая горечь, чтобы хоть как-то почувствовать себя живым. Я делаю глоток, и холод металла чашки обжигает губы сильнее, чем сам напиток. Это вкус прощания." jump routine_loop "Подойти к окну и стереть иней" if not window_done: $ window_done = True $ routine_tasks += 1 play footsteps "audio/footsteps.ogg" pause 1.0 scene bg_room_iney at slow_zoom_pan with dissolve play sound "audio/glass_rub.ogg" "Стекло промерзло насквозь. Я провожу рукавом, оставляя длинную, неровную полосу. Иней осыпается, как пепел." "За окном — только серая, бескрайняя пелена. Ни горизонта, ни неба. Иногда мне кажется, что я нахожусь не на станции связи, а внутри собственного разума, куда забыли подать свет." "Я вглядываюсь в это 'ничто', надеясь увидеть хоть что-то, кроме собственного бледного отражения. Но вижу лишь глаза человека, который три года назад решил, что ожидание лучше, чем риск." jump routine_loop "Проверить статус генератора" if not power_done: $ power_done = True $ routine_tasks += 1 play footsteps "audio/footsteps.ogg" pause 1.0 scene bg_room_generator at slow_zoom_pan with dissolve $ renpy.music.set_volume(1, delay=0, channel='ambient_generator') "Я подхожу к главному щитку. Индикаторы мерцают, как нервные окончания, готовые вот-вот перегореть. Семь лет эксплуатации — это не шутки. Сегодня он сдастся." "Генератор стонет под нагрузкой. Я касаюсь рычага, чувствуя его дрожь. Если я сейчас уйду — он просто сгорит. Если останусь — буду жечь последние крохи энергии на поддержание пустоты." "Каждый мой шаг здесь — это повторение того, от чего я пытаюсь сбежать, но я не могу позволить станции заглохнуть раньше времени. Это моё единственное наследие, мой памятник трусости." jump routine_loop label start_game_proper: "Ритуал завершен. Пустота внутри стала немного привычнее, но теперь она давит сильнее." "Станция издает низкий, вибрирующий гул. Это звук умирающего сердца станции, и он резонирует где-то в моих ребрах." "Каждый мой шаг отзывается эхом. Здесь слишком много тишины для места, которое когда-то было наполнено смехом и голосами." "Что мне делать сегодня? Время утекает, как песок сквозь пальцы, и заряд батареи с каждой минутой становится всё ближе к нулю." $ game_started = True jump main_loop label main_loop: $ renpy.music.set_volume(0.0, delay=0.2, channel='ambient_wind') if battery <= 0: jump ending_silence show screen game_ui show screen journal_button "Станция ждет. Сегодня всё закончится. Что я буду делать, пока ещё есть свет?" menu: "Осмотреть рабочий стол (Комната)" if not visited_locations["room"]: $ use_battery(26) $ visited_locations["room"] = True hide screen journal_button jump qte_date_input "Идти в коридор" if not visited_locations["corridor"]: $ use_battery(29) $ visited_locations["corridor"] = True hide screen journal_button jump qte_corridor_puzzle "Подойти к терминалу" if not visited_locations["terminal"]: $ use_battery(34) $ visited_locations["terminal"] = True hide screen journal_button jump qte_terminal_hack "Идти в серверную" if visited_locations["room"] and visited_locations["corridor"] and visited_locations["terminal"]: hide screen journal_button jump phase_3_culmination "Сдаться": hide screen journal_button "Я..." "Просто закрою глаза." $ use_battery(battery) jump main_loop label qte_date_input: play footsteps "audio/footsteps.ogg" pause 1.0 $ renpy.music.set_volume(0.4, delay=0, channel='ambient_generator') if "bg_room" not in renpy.get_showing_tags("master"): scene bg_desk_close at slow_zoom_pan with fade else: scene bg_desk_close at slow_zoom_pan with dissolve "Рабочий стол. Слой пыли здесь настолько толстый, что кажется, будто никто не садился сюда вечность." "Курсор на экране терминала мигает в ритме моего пульса. Сегодня двадцатое апреля, двадцать третьего года." "Ровно три года с того дня, когда всё пошло прахом. Три года тишины, которую я сам на себя наложил." "Чтобы получить доступ к архиву за тот день, система требует подтвердить текущую дату. Словно издевается, заставляя меня признать, сколько времени я потратил на это самобичевание." call screen keypad_screen $ date_input = _return if date_input == "20.04.2023": play sound "audio/access_granted.ogg" "Экран на мгновение вспыхивает ярким, почти болезненным белым цветом. Система приняла ввод." "Я вхожу в архив. Передо мной всплывают логи трехлетней давности. Двадцатое апреля, двадцатый год." "Я помню этот день по секундам. День, когда я должен был сказать одно слово, но вместо этого промолчал." "Молчание стало моей клеткой. Я сам запер себя здесь, внутри этого 'сегодня', чтобы не сталкиваться с 'тем самым вчера'." $ fragments += 1 $ journal.append("20.04.2020. Дата моего заточения. Спустя три года я наконец-то открыл архив, который так боялся увидеть.") else: play sound "audio/access_denied.ogg" "На экране высветилось: 'ОШИБКА ДОСТУПА'." "Даже простая проверка даты выбивает меня из колеи. Мои руки дрожат так сильно, что я путаю цифры." "Я чувствую, как с каждой неудачной попыткой станция становится всё холоднее. Или это просто моё отчаяние?" "Я отхожу от стола. В голове пульсирует лишь одна мысль: я всё ещё здесь. Всё ещё в этом 2020-м." jump main_loop label qte_corridor_puzzle: play footsteps "audio/footsteps.ogg" pause 1.0 $ renpy.music.set_volume(0.2, delay=0, channel='ambient_generator') $ renpy.music.set_volume(0.8, delay=0.2, channel='ambient_wind') play ambient_wind "audio/wind.ogg" scene bg_corridor at slow_zoom_pan with fade "Коридор. Место, где время растянулось, как жевательная резинка." "В конце — разбитое зеркало. Я смотрю в него, и мои глаза встречаются с глазами человека, который проиграл эту жизнь три года назад." "Оно разбито на четыре неравных куска. Я вижу в этих осколках фрагменты того самого дня. Если я соберу их... если я заставлю себя посмотреть на них..." call screen corridor_puzzle_screen if not _return: play sound "audio/glass_break.ogg" "Я смотрю на пустые места в зеркале. Я не могу... Руки не слушаются. В голове только шум и липкий страх." "Я слишком слаб, чтобы видеть всё это целиком. Может быть, позже..." jump main_loop "Последний осколок встал на место. Изображение сложилось." "Я вижу себя. Я вижу её. Она стоит у двери, её ладонь касается ручки. Она ждёт одного слова. Любого слова." "А я? Я просто смотрю в пол. Я не могу поднять взгляд, потому что боюсь увидеть в её глазах подтверждение того, что я — ничтожество." "Это зеркало — не отражение. Это приговор, который я сам себе вынес." $ fragments += 1 $ journal.append("Коридор. Я увидел правду в зеркале: я не 'ждал', я намеренно молчал, чтобы она ушла.") "Больше здесь не на что смотреть. Я оставляю зеркало в покое, хотя оно всё ещё преследует меня своей правдой." jump main_loop label qte_terminal_hack: play footsteps "audio/footsteps.ogg" pause 1.0 $ renpy.music.set_volume(0.6, delay=0, channel='ambient_generator') scene bg_terminal at slow_zoom_pan with fade "Терминал. Моё единственное окно в мир, который меня забыл." "Экран забит мусором — тысячи системных сообщений, ошибок и битых секторов. Где-то там, под слоем цифровой пыли, всё ещё лежат записи того дня." "Сигнал нестабилен, поток данных рвется. Если я не выровняю частоту прямо сейчас, архив удалит себя автоматически как 'неактуальный'." "Мне нужно поймать этот поток. Не для того, чтобы отправить сообщение... а для того, чтобы наконец увидеть, что она мне писала." $ target_code = generate_code() $ current_input = [0, 0, 0, 0, 0] call screen terminal_code_game if _return: play sound "audio/access_granted.ogg" "Синхронизация завершена. Помехи исчезли, оставив на экране четкие строки." "Я прокручиваю лог вниз. Вот оно. Сообщение, которое я никогда не открывал." "Моё сердце пропускает удар. Я не отправляю ничего. Я просто читаю её последние слова, и это ранит сильнее, чем любая ошибка связи." $ fragments += 1 $ journal.append("Терминал: Я открыл её последнее сообщение. Теперь я знаю, что именно я потерял.") else: play sound "audio/access_denied.ogg" "Ошибка синхронизации. Архив свернулся, защищая себя от доступа." "Я снова промахнулся. Руки дрожат, экран гаснет, и я остаюсь в тишине." "Она осталась для меня неразгаданной. Снова. Всегда опаздываю — даже чтобы просто узнать правду." "Я выхожу из системы. Терминал остывает, но теперь в комнате стало ещё холоднее от осознания того, что я (не) узнал." jump main_loop label deep_reflection: "Я читаю свои записи. За каждой строчкой — трусость. За каждым 'потом' — страх." "Я был таким слепым. Всё это время я думал, что храню память о ней, а на самом деле я просто бережно лелеял собственное бессилие." "Хватит. Я всё понял." $ sync_points = 3 $ thoughts_processed = True "Я закрываю записи. Теперь я знаю, что должен сделать." jump main_loop label phase_3_culmination: play footsteps "audio/footsteps.ogg" pause 1.0 $ renpy.music.set_volume(0.1, delay=0, channel='ambient_generator') scene bg_door_to_server at slow_zoom_pan with fade "Серверная. Место, где родилась вся эта ложь." "Я помню, как три года назад входил сюда, чтобы заглушить голос совести. Семь лет работы, три года молчания — всё это здесь." jump final_choice label final_choice: stop music fadeout 0.3 play footsteps "audio/footsteps.ogg" pause 1.0 $ renpy.music.set_volume(0.6, delay=0, channel='ambient_generator') play ambient_server "audio/server.ogg" play music "audio/final_theme.ogg" play sound "audio/door_open.ogg" scene bg_server_close with dissolve "Светодиоды на стойках серверов мигают, словно конвульсии умирающего. Воздух здесь настолько сухой и горячий, что обжигает горло при каждом вдохе." "На центральном терминале мерцает последний интерфейс. Если я нажму 'Ввод', пути назад не будет. Станция отключит жизнеобеспечение окончательно." "Курсор пульсирует. Он ждет. Решение, от которого я бежал три года, теперь стоит передо мной во весь рост." "Я чувствую, как холод металла терминала пробирает до костей, несмотря на жар в серверной." menu: "Разбить экран (Гнев)": jump ending_anger "Остаться и ждать конца (Принятие)": jump ending_acceptance "Признать ошибки и выйти (Переосмысление)" if fragments >= 3: jump ending_reflection "Отправить извинения (Свет)" if fragments >= 3 and thoughts_processed: jump ending_light label ending_silence: scene black with Fade(0.1, 0.0, 0.0) stop music fadeout 0.1 stop ambient_generator fadeout 0.1 stop ambient_server fadeout 0.1 stop ambient_wind fadeout 0.1 "Экран погас. Вместе с ним погас и последний источник света в этом склепе." "Генератор сделал последний судорожный вдох и замолчал. В этой абсолютной темноте я наконец-то слышу то, чего так боялся." "Ничего. Пустоту. Тишину, которая заполняет легкие вместо воздуха." "Наконец-таки настала ТИШИНА." jump quit_after_ending label ending_anger: scene bg_server_close_broken at shake_effect stop music fadeout 0.1 stop ambient_generator fadeout 0.1 stop ambient_server fadeout 0.1 stop ambient_wind fadeout 0.1 play sound "audio/explosion.ogg" "Гнев — это единственное, что заставляет меня чувствовать себя живым. Я срываю красную панель, сдирая кожу на пальцах до крови." "Тумблер падает вниз с хрустом ломающихся костей. Искры бьют в лицо, выжигая остатки рассудка." "Станция умирает, и я тяну её за собой в небытие. Я зол на этот холод, на эти три года, на её молчание... я зол на себя, но мне проще сжечь этот мир, чем признать свою вину." "Я зол." jump quit_after_ending label ending_acceptance: stop music fadeout 2.0 "Курсор мигает в ритме моего безразличия. Раз, два... Раз, два..." "Зачем что-то менять? Зачем бороться с энтропией, если она всё равно победит?" "Я откидываюсь на спинку кресла. Инфантильное желание просто закрыть глаза и ждать, пока тьма поглотит эту станцию, кажется единственно верным." scene bg_server_close_off with dissolve "Пусть всё закончится само собой. Я устал играть в героя. Я просто... буду ждать." jump quit_after_ending label ending_reflection: scene bg_server_close_keyboard with dissolve play sound "audio/typing.ogg" "Я печатаю дрожащими пальцами: 'Я был неправ. Это была глупая, бесконечная игра в мученика, в которой не было победителей'." "Я признаю это. Но не могу отправить сообщение." "Три года я строил стены из своего молчания, думая, что защищаюсь. Но я просто возвел свою собственную тюрьму." scene bg_server_close_off with dissolve "Я выключаю станцию. Впервые за долгое время я чувствую, что в воздухе стало меньше гари. Я должен двигаться дальше. Я не знаю, что там, во внешнем мире, но я больше не заперт внутри себя." jump quit_after_ending label ending_light: scene bg_server_close_light_from_monitor at slow_zoom_pan with dissolve stop ambient_generator fadeout 1.0 stop ambient_server fadeout 1.0 stop ambient_wind fadeout 1.0 "Я направляю остатки энергии на передатчик. Каждый процент заряда — это вырванный из жизни кусок, который я отдаю за шанс сказать правду." "Я пишу не для того, чтобы получить ответ. Я пишу, чтобы освободиться. 'Прости за тишину. Она была моей ошибкой'." "Нажимаю 'Отправить'. Система оповещает о передаче пакета, и тут же питание отключается. Станция замирает." scene bg_exit at slow_zoom_pan with dissolve $ use_battery(battery) "Я встаю и иду к выходу. Я не оглядываюсь. Мой долг перед прошлым оплачен, а будущее... будущее наконец-то принадлежит мне." jump quit_after_ending label quit_after_ending: $ renpy.quit() return