diff --git a/game/script.rpy b/game/script.rpy index 3e924f8..0d86404 100644 --- a/game/script.rpy +++ b/game/script.rpy @@ -2,6 +2,8 @@ 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) @@ -19,6 +21,12 @@ init python: 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 @@ -33,6 +41,9 @@ init python: 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: @@ -41,6 +52,8 @@ screen game_ui(): vbox: text "ЭНЕРГИЯ: [battery]%" size 40 text "ФРАГМЕНТЫ: [fragments]/3" size 40 + +screen journal_button(): textbutton "ЖУРНАЛ" action Show("journal") align (0.98, 0.98) screen journal(): @@ -94,28 +107,112 @@ screen corridor_puzzle_screen(): ypadding 20 background "#555555" -screen terminal_rhythm_screen(): +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 600 ysize 300 - background "#333333" + xsize 400 ysize 500 + background "#262626d3" - hbox: + vbox: + spacing 10 align (0.5, 0.5) - spacing 20 - for i in range(3): - button: - action [ - Function(player_input.append, i), - Function(renpy.restart_interaction) - ] - xsize 150 ysize 150 - background ("#aaaaaa" if i in player_input else "#1a1a1a") - text "[i]" align (0.5, 0.5) - - if len(player_input) >= 3: - timer 0.3 action Return(player_input == signal_sequence) + + 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 @@ -131,6 +228,9 @@ transform shake_effect(rate=0.090): 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, @@ -257,28 +357,40 @@ label main_loop: jump ending_silence show screen game_ui + show screen journal_button "Станция ждет. Сегодня всё закончится. Что я буду делать, пока ещё есть свет?" menu: "Осмотреть рабочий стол (Комната)" if not visited_locations["room"]: - $ use_battery(5) + $ use_battery(26) $ visited_locations["room"] = True + hide screen journal_button jump qte_date_input "Идти в коридор" if not visited_locations["corridor"]: - $ use_battery(5) + $ use_battery(29) $ visited_locations["corridor"] = True + hide screen journal_button jump qte_corridor_puzzle "Подойти к терминалу" if not visited_locations["terminal"]: - $ use_battery(5) + $ use_battery(34) $ visited_locations["terminal"] = True - jump qte_terminal_rhythm + 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 @@ -295,9 +407,8 @@ label qte_date_input: "Ровно три года с того дня, когда всё пошло прахом. Три года тишины, которую я сам на себя наложил." "Чтобы получить доступ к архиву за тот день, система требует подтвердить текущую дату. Словно издевается, заставляя меня признать, сколько времени я потратил на это самобичевание." - play sound "audio/typing.ogg" loop - $ date_input = renpy.input("Введите сегодняшнюю дату (ДД.ММ.ГГГГ):", length=10) - stop sound + call screen keypad_screen + $ date_input = _return if date_input == "20.04.2023": play sound "audio/access_granted.ogg" @@ -352,7 +463,7 @@ label qte_corridor_puzzle: "Больше здесь не на что смотреть. Я оставляю зеркало в покое, хотя оно всё ещё преследует меня своей правдой." jump main_loop -label qte_terminal_rhythm: +label qte_terminal_hack: play footsteps "audio/footsteps.ogg" pause 1.0 @@ -365,8 +476,10 @@ label qte_terminal_rhythm: "Сигнал нестабилен, поток данных рвется. Если я не выровняю частоту прямо сейчас, архив удалит себя автоматически как 'неактуальный'." "Мне нужно поймать этот поток. Не для того, чтобы отправить сообщение... а для того, чтобы наконец увидеть, что она мне писала." - $ player_input = [] - call screen terminal_rhythm_screen + $ target_code = generate_code() + $ current_input = [0, 0, 0, 0, 0] + + call screen terminal_code_game if _return: play sound "audio/access_granted.ogg" @@ -436,11 +549,11 @@ label final_choice: "Признать ошибки и выйти (Переосмысление)" if fragments >= 3: jump ending_reflection - "Отправить извинения (Свет)" if fragments >= 3 and thoughts_processed >= 3: + "Отправить извинения (Свет)" if fragments >= 3 and thoughts_processed: jump ending_light label ending_silence: - scene black with Fade(0.1) + scene black with Fade(0.1, 0.0, 0.0) stop music fadeout 0.1 stop ambient_generator fadeout 0.1 @@ -497,7 +610,8 @@ label ending_light: "Я направляю остатки энергии на передатчик. Каждый процент заряда — это вырванный из жизни кусок, который я отдаю за шанс сказать правду." "Я пишу не для того, чтобы получить ответ. Я пишу, чтобы освободиться. 'Прости за тишину. Она была моей ошибкой'." "Нажимаю 'Отправить'. Система оповещает о передаче пакета, и тут же питание отключается. Станция замирает." - scene bg_exit_winter at slow_zoom_pan with dissolve + scene bg_exit at slow_zoom_pan with dissolve + $ use_battery(battery) "Я встаю и иду к выходу. Я не оглядываюсь. Мой долг перед прошлым оплачен, а будущее... будущее наконец-то принадлежит мне." jump quit_after_ending diff --git a/Идея.txt b/Идея.txt new file mode 100644 index 0000000..c8a65a4 --- /dev/null +++ b/Идея.txt @@ -0,0 +1,9 @@ +1. Главный герой — человек, запертый в добровольной изоляции из-за неспособности преодолеть прошлую эмоциональную травму. + +2. Весь окружающий мир и техническое состояние станции являются визуальной метафорой разрушающейся психики протагониста. + +3. Локальный конфликт строится на драматической ошибке прошлого: герой намеренно выбрал молчание вместо действия, что привело к разрыву с близким человеком. + +4. Механика сбора воспоминаний служит инструментом принудительной деконструкции психологических защит героя, блокировавших правду о случившемся. + +5. Основная цель игры — не спасение персонажа, а достижение им психологической целостности через принятие ответственности за свои действия в финале. \ No newline at end of file