Создание мода
Для начала нужно создать файл с расширением .rpy. Затем открыть его в текстовом редакторе и приступить к объявлению модификации.
Шаги, приведенные ниже, крайне важны. Без них мод не будет виден в списке модов в игре.
Написание кода
Стиль и синтаксис Ren'Py похож на Python. Если знакомы с ним, то проблем возникнуть не должно.
Файлы состоят из блоков и команд в блоках, например:
1<Блок>: 2 <Команды> 3 4<Блок>
Команды в blocks должны везде иметь одинаковый отступ. Будь то 2 или 4 пробела. В большинстве случаев рекомендуется использовать 4 пробела.
В редакторе кода будет по умолчанию выставлено значение отступов, поэтому рекомендуется использовать TAB для отступов.
Следует помнить, что Ren'Py не любит табуляцию, выкидывая ошибку (Traceback) при наличии подобного. Настройте авто-замену табов на пробелы в настройках вашего редактора.
Объяснение кода
Шаги, приведенные ниже крайне важны. Без них мод не будет виден в списке модов в игре.
Для того чтобы игра поняла, что файл (в котором строчки будут написаны) является модом, нужно написать следующее:
init: $ mods["my_mod"] = "Мой мод"
Разберем более детально пример выше:
1. my_mod — название начального лейбла мода. При запуске мода всегда первым начинает запускаться этот лейбл, указанный внутри командных скобок. Он не будет виден пользователю. Должен быть уникальным, иначе возможны конфликты с модификациями, имеющими лейблы с таким же названием. Рекомендуется использовать только латиницу!
2. Мой мод — название мода, которое будет отображаться в списке модов. Допускается использование кириллицы.
Теперь, для того чтобы игра поняла, где начинается мод, нужно добавить начальный лейбл:
init: $ mods["my_mod"] = "Мой мод" label my_mod: "Реплика" # Далее будут идти команды
В коде выше была объявлена метка (label), имя которой обязательно должно соответствовать имени мода, указанного в квадратных скобках. В нашем случае — my_mod.
Если вы хотите поменять шрифт в списке, то конструкция будет следующей:
init: $ mods["my_mod"] = u"{font=mods/my_mod/<название шрифта>.ttf}Мой мод{/font}"
Можно использовать форматы как TrueType (.ttf), так и OpenType (.otf).
Также можно добавить цвет:
init: $ mods["my_mod"] = u"{font=mods/my_mod/<название шрифта>.ttf}{color=#45B39D}Мой мод{/color}{/font}"
И изменить размер шрифта:
init: $ mods["my_mod"] = u"{font=mods/my_mod/<название шрифта>.ttf}{color=#45B39D}{size=50}Мой мод{/size}{/color}{/font}"
Написание сценария
Далее, в метке my_mod можно начинать писать сценарий. В нем используется специальный синтаксис Ren'Py, который мы разберем далее.
Метки
Использование меток позволяет облегчить процесс создания мода, путем разделения сценария на части.
Имена меток должны быть уникальными во избежание конфликтов. Рекомендуется использовать названия меток, начиная с названия мода, например, my_mod_day1.
Общий синтаксис метки выглядит так:
label <Название>: <Команды>
Переходы между лейблами
Есть два вида переходов:
1. Прыжок (jump)
label my_mod_day1: "..." jump my_mod_day2 # Прыжок на my_mod_day2 label my_mod_day2: "..."
В данном случае команды после "прыжка" будут пропущены игрой, например, фраза "действия после прыжка" из примера ниже не будет выведена на экран игрока. Любые другие команды, которые были написаны после прыжка также не сработают.
label my_mod_day1: "..." jump my_mod_day2 "действия после прыжка" label my_mod_day2: "..."
2. Вызов (call)
В этом случае фраза из примера выше будет выведена на экран после завершения действий из метки my_mod_day2.
label my_mod_day1: "..." call my_mod_day2 # Вызов второго лейбла "Действия после прыжка" # После того, как нас выбросит из лейбла my_mod_day2 командой return, появится данная фраза. label my_mod_day2: "..."
Закончить блок можно командой return. После неё мод будет завершен и будет показано главное меню игры, если до этого мы не вызывали какой-либо из лейблов, а лишь прыгали по ним с помощью команды jump.
Приведём ещё один пример для наглядности:
label my_mod_day1: "..." "Сейчас вызовем другой лейбл!" call my_mod_day2 # Вызываем второй лейбл "Второй лейбл закончился, можем продолжать работать на первом." return # А вот здесь уже, если ничего другого не вызывали, нас выкинет из мода. label my_mod_day2: "Вот мы и вызвали второй лейбл. Делаем тут что хотим." "..." "Второй лейбл подходит к концу" return # Заканчиваем вызов лейбла, перескок обратно на первый.
В первом лейбле идут некие действия, затем мы вызываем второй лейбл, в котором тоже идут некие действия. Из-за того, что мы вызвали второй лейбл, а не прыгнули на него, при команде return внутри вызванного лейбла мод не завершится — нас просто выкинет обратно на первый лейбл, потому что мы прекратили 'вызов' второго лейбла и вернулись обратно на первый. Но! Вернулись не в самое его начало, а продолжили работу после момента с вызовом второго лейбла.
Реплики
Реплики персонажей имеют следующий общий вид: <ID персонажа> "<Реплика>", где:
<ID персонажа>— название переменной, которой он был объявлен.Реплика— текст, который будет говорить персонаж.
Список персонажей и их переменные представлены в таблице по ссылке: Игровые ресурсы - Персонажи.
В примере ниже представлен пример реплик Мику и Ульяны, имена которых ещё не известны:
label my_mod: mip "Привет, ты меня ещё не знаешь, но это я – Мику!" mip "В данный момент я у тебя отображаюсь как 'Пионерка'." usg "Привет, а я – Ульянка! Но у тебя я написана как \"Девочка\"."
В первом случае имя пионера или пионерки будет сменено на "Пионер/Пионерка", сохраняя свой цвет. Во втором же случае имя персонажа будет сменено на "Девочка", сохраняя свой цвет.
Смена стиля интерфейса
Есть всего 4 варианта:
prolog_time()— Интерфейс пролога.day_time()— Интерфейс дня.sunset_time()— Интерфейс заката.night_time()— Интерфейс ночи.
Пример использования:
label my_mod: $ prolog_time() # Интерфейс изменит стиль на стиль из пролога "..." $ day_time() # Интерфейс изменит стиль на дневной
Смена окраски спрайтов согласно времени
Всего существует 3 варианта раскраски спрайтов. Все они происходят через переменную persistent.sprite_time:
$ persistent.sprite_time = "day"— Дневная версия окраски спрайтов.$ persistent.sprite_time = "sunset"— Вечерняя версия окраски спрайтов.$ persistent.sprite_time = "night"— Ночная версия окраски спрайтов.
Пример использования смены окраски спрайтов вкупе со сменой стилей интерфейса выглядит так:
label my_mod: $ day_time() # Смена стиля интерфейса на дневной $ persistent.sprite_time = "day" # Смена окраски спрайтов на дневную версию. "..." $ sunset_time() # Смена стиля интерфейса на вечерний $ persistent.sprite_time = "sunset" # Смена окраски спрайтов на вечернюю версию. "..." $ night_time() # Смена стиля интерфейса на ночной $ persistent.sprite_time = "night" # Смена окраски спрайтов на ночную версию. "..." $ prolog_time() # Смена стиля интерфейса на зимнюю версию. Версию пролога. $ persistent.sprite_time = "night" # Смена окраски спрайтов на ночную версию.
Обратите внимание: если в моде не менять значение переменной смены стиля интерфейса и смены окраски спрайтов, то по умолчанию стиль интерфейса будет равен $ prolog_time(), а окраска спрайтов — $ persistent.sprite_time = "night".
ADV и NVL режимы повествования
Существует два основных стиля изложения материала, используемых в визуальных новеллах:
ADV: Визуальные новеллы, созданные в стиле ADV, представляют собой диалог и повествование, выводимые на экран по одной строке за раз, как правило, в окне, расположенном в нижней части экрана.NVL: Визуальные новеллы, созданные в стиле NVL, представляют собой несколько строк на экране, выводимые одновременно в окне, которое занимает весь экран.
По умолчанию меню отображаются в ADV-режиме, занимая весь экран. Существует также альтернативное представление меню в NVL-режиме, в котором меню отображаются сразу после текущей страницы текста NVL-режима.
Для перехода в NVL-режим повествования используйте следующую команду: $ set_mode_nvl()
Для перехода обратно в ADV-режим повествования используйте следующее: $ set_mode_adv()
Примеры перехода в NVL и ADV режимы повествования:
label my_mod: "По умолчанию стоит adv-режим повествования." $ set_mode_nvl() "Теперь повествование ведётся в nvl-режиме." $ set_mode_adv() "Повествование вернулось обратно в adv-режим."
Плавные переходы окон
Не забывайте про плавные переходы для окон, в которых ведётся повествование.
Для ADV-режима:
window hide— плавное скрытие диалогового окна.window show— плавное появление диалогового окна.
Для NVL-режима:
nvl show dissolve— плавное появление NVL-окна.nvl hide dissolve— плавное скрытие NVL-окна.
Пример использования плавных переходов окон выглядит так:
label my_mod: "Повествование в adv-режиме." window hide # Плавное скрытие окна pause(1) # Секундная пауза, чтобы сокрытие окна успело произойти до смены режима повествования $ set_mode_nvl() # Переключение на новелльный режим повествования nvl show dissolve # Плавное появление nvl-окна "Повествование в nvl-режиме." nvl hide dissolve # Плавное скрытие nvl-окна pause(1) # Секундная пауза, чтобы сокрытие окна успело произойти до смены режима повествования $ set_mode_adv() # Переключение на adv-режим повествования window show # Плавное появление диалогового окна "Повествование в adv-режиме."
Появление персонажа в NVL-режиме
Персонажи могут быть объявлены для использования в NVL-режиме путём создания ещё одного персонажа, но с добавлением параметра kind=nvl. Например:
define maks_nvl = Character('Максим', kind=nvl, color="#c8ffc8")
Если этого не сделать, то внутри nvl-режима повествования персонажи без параметра kind=nvl будут говорить в adv-режиме.
Обратите своё внимание: что можно сделать и по-другому — сделать цикл, который будет менять объявление персонажей в зависимости от текущего режима повествования. Именно такой способ и используется в БЛ.
Оформление текста
Примеры текстовых тегов, которые позволяют динамически изменять внешний вид реплик и повествования прямо внутри строк:
1. alpha
Текстовый тег alpha отображает текст, расположенный между самим тегом и его закрывающим тегом, с указанной непрозрачностью. Непрозрачность должна иметь значение между 0.0 и 1.0, что соответствует полной прозрачности и полной непрозрачности соответственно.
Если значение начинается с префикса + (добавить на) или - (убавить на), непрозрачность будет изменена на указанное число, а не полностью заменена. Если значение начинается с префикса * (умножить на), непрозрачность будет умножена на это число.
"{alpha=0.1}Этот текст едва читаем!{/alpha}" "{alpha=-0.1}Этот текст на 10 процентов прозрачнее, чем текст по умолчанию.{/alpha}" "{alpha=*0.5}Этот текст наполовину такой же непрозрачный, как и по умолчанию.{/alpha}"
2. b (bold)
Тег жирного шрифта выводит текст, расположенный между самим тегом и его закрывающим тегом, жирным шрифтом.
"Пример {b}текста, выделенного жирным шрифтом{/b}."
3. color
Текстовый тег color отображает текст, расположенный между самим тегом и его закрывающим тегом, в указанном цвете. Цвет должен быть в формате #rgb, #rgba, #rrggbb или #rrggbbaa.
"{color=#f00}Красный{/color}, {color=#00ff00}Зелёный{/color}, {color=#0000ffff}Синий{/color}"
4. i (italic)
Тег курсива отображает текст, расположенный между самим тегом и его закрывающим тегом, курсивом.
mt "Добро пожаловать в {i}СОЛ «Совёнок»!{/i}"
5. s (strikethrough)
Тег зачеркивания проводит черту через текст, расположенный между самим тегом и его закрывающим тегом.
mi "Я очень надеюсь, что {s}тебе понравилось{/s}."
6. u (underline)
Тег подчеркивания подчеркивает текст, расположенный между самим тегом и его закрывающим тегом.
mi "Рада видеть {u}тебя{/u}!"
7. w (wait)
Тег ожидание — самозакрывающийся тег, который ждёт, пока читатель нажмёт на кнопку для продолжения. Если для тега задан аргумент в форме числа, то ожидание автоматически заканчивается, когда заданные секунды проходят.
un "Я{w} очень{w=1.0} рада!"
Фоны
Бэкграунды [BG]
Общий синтаксис для вывода фона: scene <Название фона> или show <Название фона>
Разница между scene и show
В первом случае команда очищает все слои и показывает изображение, во втором — просто показывает изображение поверх других. Приведём пример:
label my_mod: show bg ext_square_day # Площадь show dv smile pioneer2 at left # Слева появляется Алиса show mi happy pioneer at center # Мику посередине show un smile pioneer at left # А Лена левее with dissolve # Пишем в конце всех строчек, а не у каждой, чтобы и БГ, и спрайты появились сразу, а не поочерёдно. "Некие действия" scene bg ext_square_day with dissolve "Показываем площадь, но теперь все спрайты убрались совсем." "Если уберём фон с помощью `hide`, то позади него ничего не будет."
Это был пример с использованием scene для показа изображения. Фона, в нашем случае.
label my_mod_2: show bg ext_square_day # Площадь show dv smile pioneer2 at left # Слева появляется Алиса show mi happy pioneer at center # Мику посередине show un smile pioneer at left # А Лена левее with dissolve # Пишем в конце всех строчек, а не у каждой, чтобы и БГ, и спрайты, и спрайты появились сразу, а не поочерёдно. "Некие действия" show bg ext_square_night with dissolve "Показываем ночную площадь." "Спрайты никуда не исчезают, остаются поверх фона, который меняется с дневного на ночной."
А здесь была использована команда show, которая лишь сменила фон на другой, не затрагивая другие изображения. Почему в нашем случае оно сменило только фон, а не показало изображение поверх всех, смотрите ниже.
В данном случае, из-за того, что у фона имеется отступ после слова bg, слово bg сработало как "тэг" и сменился только фон, а не показался новый поверх спрайтов (А если бы изображение было без тэга и показалось поверх всего, то если бы мы его убрали при помощи hide, мы бы снова увидели нашу дневную площадь и спрайты девушек). Более подробно об этом рассказано чуть ниже.
Например:
scene bg bus_stop # Покажет нам автобусную остановку из времени Семена scene bg int_bus # Внутри автобуса, привезшего нас в "Совенок" scene bg ext_bus_night # Снаружи этого же автобуса, но уже ночью
Фоны из игры представлены в таблице по ссылке: Игровые ресурсы - Изображения - BG.
Иллюстрации [CG]
Общий синтаксис для вывода иллюстраций: scene <Название арта> или show <Название арта>
Например:
scene cg d3_dv_scene_1 # Покажет арт с Алисой и Семёном на сцене, ночью. scene cg d3_ussr_catched # Покажет лежащую на траве Ульянку. scene cg d1_sl_dinner_0 # Славя и Семён ночью в столовой.
Все иллюстрации из игры представлены в таблице по ссылке: Игровые ресурсы - Изображения - CG.
Спрайты
Вызывается спрайт с помощью: show <Имя спрайта>
Обычно спрайты состоят из слов, разделённых пробелом: <имя персонажа> <эмоция> <одежда>
В оригинальной игре имя персонажа совпадает с ID говорящего из предыдущего раздела этого руководства
Например:
show dv angry pioneer # Злая Алиса show un cry sport # Плачущая Лена в спортивной форме
Все спрайты из игры представлены в таблице по ссылке: Игровые ресурсы - Изображения - Спрайты.
Если персонаж уже на экране, то повторное использование show будет менять эмоцию и/или одежду, если при повторном использовании у персонажа имеется "тэг". Скажем, в команде show un cry sport — un выступает в качестве "тэга" персонажа, поэтому при смене одежды/эмоции не нужно будет убирать предыдущую картинку. Точно также тэги работают и с изображениями по типу БГ, ЦГ, и прочих.
Для того, чтобы убрать персонажа, воспользуйтесь: hide <Имя персонажа>
Если вы хотите вслед за этим сменить декорации, то прописывать hide для каждого персонажа не обязательно, команда scene сама их уберет.
Действия с изображениями
Позиционирование
При простом использовании show <Спрайт> он будет появляться просто по центру, это можно исправить, добавив в конец at <Позиция>: show <Спрайт> at <Позиция>.
Всего в игре 7 позиций где может находиться спрайт:
fleftleftcleftcentercrightrightfright
На скриншоте выше были использованы следующие команды:
scene bg ext_bus_night show dv angry pioneer2 at left show un smile pioneer at right show mi cry_smile pioneer at cleft show sl serious pioneer at cright show mt rage panama pioneer at center
Также, если не хотите использовать стандартные расположения спрайтов, можно сделать свои собственные! Для этого необходимо показать спрайт, а затем прописать его расположение по х и у координатам. Для этого используем команду center, куда вписываем кортеж float чисел. Первое число — х координата, вторая — у координата.
label mod_start: show bg ext_square_day with dissolve show sl smile pioneer: # Славя стоит левее. center(0.4, 0.5) show dv normal pioneer: # Алиса стоит правее. center(0.6, 0.5)
Обращаем внимание: что позиционирование идёт по center, а не по align или pos.
Так же можно показать персонажа ближе / дальше. Для этого можно воспользоваться атрибутом close / far.
На скриншоте выше как раз были использованы эти атрибуты. Команды:
scene bg ext_bus_night show dv angry pioneer2 far at left show un smile pioneer far at right show mi cry_smile pioneer at cleft show sl serious pioneer at cright show mt rage panama pioneer close at center
Анимации появления
Мы можем показать спрайты, bg и cg с некоторым замедлением, плавно.
Плавность
scene <Название> with <Атрибут>
Атрибутов для плавности 6, они отличаются лишь своей скоростью:
dspr— 0,2 сек — Самый быстрый, на практике не особо заметен. Оптимален для смены эмоций спрайтов.dissolve_fast— 0.5 сек.dissolve— также 0.5 сек. Оптимален для смены BG/CG.dissolve2— 2 сек — хороший вариант для длинных переходов между локациями лагеря.hell_dissolve— 50 секунд — на практике не особо применим, но вдруг пригодится.dissolve_long— 100 секунд.
Также можно группировать несколько объектов для одновременного начала эффекта:
scene bg ext_bus_night show sl smile pioner far with dissolve2
В приведенном примере мы попадем в ночной автобус, и перед нами предстанет улыбающаяся Слава. Все это с задержкой в 2 секунды.
Если все вышеприведённые примеры Вас не устраивают, можно добавить свой атрибут плавности. Для этого, пропишите его в блоке init.
Например,
init: $ trisekundi = Dissolve(3.0) label my_mod: scene bg ext_bus_night show sl smile pioner far with trisekundi
Моргание
Я более чем уверен, что вы видели эффект того, как иногда ГГ моргает или вовсе закрывает глаза. Мы можем реализовать подобную возможность!
show blink— Закрыть глазаshow unblink— Открыть глазаshow blinking— Моргание
blink и unblink — это разные эффекты, они не могут отменить друг друга.
Пример:
show blink <Ваши события> hide blink show unblink
Так же к эффектам моргания можно применить атрибут плавности.
Добавление своих изображений
Вполне может быть, что по сюжету Вашего мода, может не хватить имеющихся БГ, ЦГ и спрайтов. В таком случае, мы добавим свои.
Для начала нам надо объявить изображение в блоке init. Делается это, с помощью объявления переменной image. Например, если есть изображение city.jpg, и оно находится в папке game/mods/my_mod/city.jpg, то объявить его можно вот так:
init: image gorod = "mods/my_mod/city.jpg"
И использовать его:
init: image gorod = "mods/my_mod/city.jpg" label my_mod: scene gorod with dissolve
Настоятельно рекомендую использовать тэги. В приведённом ниже примере слово bg выступает в виде тэга к изображению. Если объявить несколько БГ с таким тегом, то при показе следующего он автоматически заменит предыдущий.
init: image bg city = "mods/my_mod/city.jpg"
Звуки
Ren'Py поддерживает воспроизведение музыки и звуковых эффектов, используя следующие форматы аудио файлов: Opus, Ogg Vorbis, mp3, wav.
Добавление звуков, музыки, эмбиенса
$ <Название аудиофайла> = <Путь к аудиофайлу>
Добавление различных аудио файлов в ваш мод происходит посредством команды, приведённой выше. Приведём пример использования.
init: $ city_ambience = "mods/sounds/city_ambience.mp3" label mod_start: play ambience city_ambience # Проигрываем эмбиенс города на канале `ambience`
Музыка
Для начала проигрывания музыки используется: play music <Название>, а для остановки — stop music.
Список музыки из игры представлен в таблице по ссылке: Игровые ресурсы - Звуки - Музыка.
Окружение
play ambience <Название>
stop ambience
Звуки окружения из игры представлены в таблице по ссылке: Игровые ресурсы - Звуки - Окружение.
Прочее
play sound <Название>
Прочие звуки из игры представлены в таблице по ссылке: Игровые ресурсы - Звуки - Прочие звуки.
Плавный вход/выход музыки
Команды fadein и fadeout являются необязательными. fadeout дает время затухания для текущей проигрываемой музыки в секундах, в то время как fadein дает время, необходимое для плавного "входа" новой музыки.
Пример:
label my_mod: play music sabaton_rock fadein 4 # Воспроизведение музыки с "входом" в 4 секунды '...' # Происходят некие действия по сюжету stop music fadeout 4 # Остановка музыки с затуханием в 4 секунды
Зацикливание и разцикливание музыки
Команды loop и noloop также являются необязательными. loop заставляет музыку зацикливаться, в то время как noloop заставляет ее играть только один раз. Если ни один из них не задан, используется значение канала по умолчанию.
Пример:
label my_mod: play sound house_crush loop # Зацикливаем звук рушения дома play music sabaton_rock noloop # Разцикливаем музыку, заставляя её играть только один раз
Поочерёдное воспроизведение
Оператор queue используется для создания очереди аудио файлов. Они будут воспроизведены, когда канал закончит воспроизведение текущего воспроизводимого файла, если таковой имеется.
Команда для кортежа воспроизводимых файлов начинается с ключевого слова queue, за которым следует имя канала для воспроизведения звука. Он опционально принимает команды fadein, loop и noloop.
Пример:
label my_mod: queue music ["rock.mp3", "hip_hop.mp3", "jazz.mp3"] # Поочерёдно воспроизводит три аудиофайла через канал 'music'. После окончания первого файла, сразу же начинается следующий.
Также queue поддерживает параметры loop и fadein.
Видео
Ren'Py предусматривает возможность использования встроенной версии Libav для воспроизведения видеороликов с такими форматами, как: .webm, .matroska, .ogg, .avi.
Полноэкранные видеоролики
Самый простой способ отображения видео в полноэкранном режиме заключается в использовании функции renpy.movie_cutscene. Она отображает видео в полноэкранном режиме до тех пор, пока оно не закончится, либо пока игрок не щелкнет кнопкой мыши, чтобы прекратить воспроизведение.
Пример использования:
label my_mod: dv "Сейчас запустится фильм!" $ renpy.movie_cutscene("Брат.webm") dv "Фильм закончился."
Видео, как отображаемые объекты и спрайты
Видеоролик, отображаемый на экране посредством команды Movie, можно использовать для отображения в любом месте, где Ren'Py может его показать. Например, видео может выводиться как фон экрана меню или в качестве фона.
Отображаемый видеоролик также можно использовать для определения видео спрайта, который представляет собой спрайт, склеенный из двух видео. Первый видеоролик обеспечивает цвет спрайта. Второй — так называемый «маска-ролик» — обеспечивает альфа-канал, где белый цвет — полная непрозрачность, а чёрный — полная прозрачность.
Видео, которые воспроизводятся в отображаемом объекте Movie, зацикливаются автоматически.
Movie принимает два параметра:
play— строка, содержащая имя воспроизводимого видеофайла. Параметр всегда должен быть задан.mask— строка, содержащая наименование видеофайла для использования в качестве альфа-маски. Она должна быть того же размера, продолжительности и частоты кадров, что и видеофайл, заданный вplay.
Вот пример определения видео спрайта:
init: image brat movie = Movie(play="brat.webm", mask="brat_mask.webm")
Видео спрайт можно показать с помощью оператора show, который автоматически запускает воспроизведение видео. Он будет автоматически остановлен при скрытии отображаемого объекта.
label my_mod: show brat movie "Данный видеоролик показан как спрайт." hide brat "Ролик убран."
Видеоролик, прописанный через Movie, также можно использовать как часть экрана, при условии, что он создан во время фазы инициализации (init-блок) (например, как часть оператора image).
Приведём пример:
init: image main_menu = Movie(play="main_menu.ogv") screen main_menu: add "main_menu" textbutton "Start" action Start() xalign 0.5 yalign 0.5
Экраны можно прописывать и вне init-блока.
Несколько отображаемых видеороликов, прописанных через Movie, или спрайтов могут отображаться на экране одновременно с учетом производительности системы и при условии, что все они имеют одинаковую частоту кадров. Поведение Ren'Py при отображении видеороликов с разной частотой кадров не определено, но, скорее всего, будет включать значительную потерю кадров.
Продвинутое руководство
Переменные
Если вы хотите, чтобы игра запоминала каждый выбор игрока, то без переменных нам не обойтись.
Объявление переменных происходит в специальном блоке init. Имена и значения у переменных могут быть любые, но рекомендуется использовать короткие английские слова или цифры (цифры только в значении).
init: $ choice = False # Переменная будет объявлена со значением False $ count = 0 # А у этой переменной будет значение 0
Изменение значения переменных будет выглядеть так:
init: $ choice = False # Переменная будет объявлена со значением False $ count = 0 # А у этой переменной будет значение 0 label my_mod: $ choice = True # Переменная `choice` становится равна `True` $ count += 1 # К переменной `count` добавляется одно очко
Выборы
Если вы хотите дать игроку выбор, то вам необходимо использовать специальный блок menu:
mt "Возьми-ка этот мешок с сахаром." menu: "И куда мне его девать?": $ good += 1 jump good_label "Да идите вы со своим сахаром на ...": jump bad_label
В приведенном примере Ольга Дмитриевна попросит нас взять мешок с сахаром, мы же можем как подчиниться и увеличить переменную "good" на 1, так и отказаться, причем в зависимости от нашего выбора события в игре могут измениться.
Варианты ответа тоже открывают блок, и если мы не поставим после каждого двоеточие, мод может не запуститься.
Проверка условий
Что нам делать если мы хотим чтобы какие-то из возможностей были у игрока в зависимости от его выборов? Для этого то мы и использовали переменные! Сейчас же мы воспользуемся специальной конструкцией:
label my_mod: if good > 0: # Если очков `good` больше 0, то прыгаем на лейбл хорошей концовки jump good_end else: # Иначе прыгаем на лейбл плохой концовки jump bad_end
Если значение переменной good больше нуля, то игра продолжится на метке good_end, если нет, то мы переходим на метку bad_end.
Теперь же мы постараемся реализовать выборы, в которых, в зависимости от прошлых выборов персонажа, будут добавляться или убираться различные варианты ответов:
label my_mod: mt "Семен, сегодня после обеда ты будешь убираться в столовой." menu: "Почему именно я?": jump why_me "Я же уже помог вам сегодня" if good > 0: jump helped_today "Не намерен я вам тут прислуживать!" if good == 0: jump angry
В данном случае мы можем:
- возмутиться сложившейся ситуации;
- мы можем попросить ее отсрочить дежурство, если мы уже заслужили доверие вожатой;
- отправить ее куда подальше, если не помогали. И в каждом случае нам, как создателям мода необходимо будет прописать что произойдет в каждом из этих случаев.
Проверка на значение True или False значения переменной происходит схоже:
label my_mod: if Otnes_saxar == True: # Если помог отнести сахар, то Ольга хвалит нас. mt "Молодец, Семён, помог отнести сахар!" else: # Если же не помогли отнести, то Ольга нас ругает. Стерва. mt "Бездарность, не пионер, а размазня!"
Обратите своё внимание, что проверка на значение переменной проходит с двумя знаками 'равно'. Напомним, один знак равно — присваивание значения переменной, а два — проверка на значение переменной.
Также, переменным можно присваивать не только очки и состояния True или False — а всё, что вашей душе заблагорассудится. Приведём пример:
init: $ Ya_molodec = None # Оставляем переменную без значения. Равна `None`. label my_mod: $ Ya_molodec = "Krasavec" # Присваиваем переменной значение "Krasavec" if Ya_molodec == "Krasavec": # Если переменная равна "Krasavec", то мы хвалим себя. th "А я хорош!" else: # Иначе негодуем. th "Не получилось, не фартануло."
Обратим внимание, что в примере выше проверка на значение переменной была с кавычками. Если бы мы сделали проверку без кавычек, то игра бы просто пропустила проверку.
Также советую запомнить, что True и "True" при проверке переменной — это два разных значения.
Использование карты
Чтобы дать игре понять, когда развернуть перед игроком карту, необходимо всего несколько простых команд.
1. Перед выводом карты нужно сбросить все прошлые зоны на ней:
disable_all_zones() # Отключает все старые маркеры карты.
2. Заполняем конструкцию set_zone().
Первым значением будет выделенная на карте зона, а вторым - лейбл, куда прыгать, при клике на неё.
Вот список всех зон и как они обозначены в игре:
me_mt_house- Домик Семёна и Ольги Дмитриевныestrade- Сценаmusic_club- Музклубsquare- Площадьdining_hall- Столоваяsport_area- Спорткомплексbeach- Пляжboat_station- Лодочный причалclubs- Клубыlibrary- Библиотекаmedic_house- Медпунктcamp_entrance- Ворота в лагерьforest- Лес
Например, чтобы при нажатии на клубы мы прыгали на лейбл day1_gone_to_clubs (название лишь для примера) нужно реализовать такую конструкцию:
set_zone("clubs", "day1_gone_to_clubs")
И в конце выводим саму карту командой:
show_map()
Полный пример:
label my_mod: $ disable_all_zones() $ set_zone("clubs", "day1_gone_to_clubs") $ show_map()
Вариант кода со всеми позициями на карте:
label my_mod: $ disable_all_zones() $ set_zone("me_mt_house", "day1_gone_to_mt_house") # Домик Семёна и Ольги Дмитриевны $ set_zone("estrade", "day1_gone_to_estrade") # Сцена $ set_zone("music_club", "day1_gone_to_music_club") # Музклуб $ set_zone("square", "day1_gone_to_square") # Площадь $ set_zone("dining_hall", "day1_gone_to_dining_hall") # Столовая $ set_zone("sport_area", "day1_gone_to_sport_area") # Спорткомплекс $ set_zone("beach", "day1_gone_to_beach") # Пляж $ set_zone("boat_station", "day1_gone_to_boat_station") # Лодочный причал $ set_zone("clubs", "day1_gone_to_clubs") # Клубы $ set_zone("library", "day1_gone_to_library") # Библиотека $ set_zone("medic_house", "day1_gone_to_medic_house") # Медпункт $ set_zone("camp_entrance", "day1_gone_to_camp_entrance") # Ворота в лагерь $ set_zone("forest", "day1_gone_to_forest") # Лес $ show_map()
Добавление персонажа
Любой персонаж игры — простая переменная. Переменные создаются двумя способами: методом движка — с помощью команды define, и методом Python — с помощью символа $.
$ ivan = Character(u"Иван")
Символ u используется для отображения русского текста у людей, у которых он не установлен в системе.
Теперь персонажа можно использовать в моде:
$ ivan = Character(u"Иван") label my_mod: ivan "Привет"
Цвет имени персонажа указывается с помощью параметра color, также рекомендую использовать неизменный параметр what_color для изменения цвета речи персонажа. В самой игре все персонажи говорят цветом #f1d076, так не будем выделяться: назначим нашему персонажу в качестве цвета имени, скажем, зелёный цвет (#008000) и установим в качестве цвета речи — #f1d076:
$ ivan = Character(u"Иван", color="#008000", what_color="#f1d076") label my_mod: ivan "Привет"
Монитор с номерами дня
Для выведения на экран монитора необходимо прописать две команды:
backdrop = "days" new_chapter(1, u"Мой мод. День первый.")
backdrop— фон с монитором.1— номер дня, который будет показан на мониторе.текст(в примере — Мой мод. День первый.) — то, как будет называться сохранение.
Фонов (backdrop) в игре 5:
backdrop = "days" # Просто монитор. backdrop = "un" # Монитор с проплывающей Леной. backdrop = "us" # Монитор с проплывающей Ульяной. backdrop = "sl" # Монитор с проплывающей Славей. backdrop = "dv" # Монитор с проплывающей Алисой.
Обратите внимание, что при использовании команды new_chapter сбрасываются плавные переходы для изображений, следующих после неё. Проверено на опыте. Советуем прописать pause в n-ное количество секунд, чтобы сначала проигрались плавные анимации перехода, а затем сработала команда new_chapter.
Достижения
Для вывода достижения в нужном вам месте, вставьте следующие команды:
define myachiv = "mods/my_mod/images/myachiv.png" label my_mod: play sound sfx_achievement show myachiv at achievement_trans with dspr $ renpy.pause(3, hard=True) hide myachiv
myachiv— Ваше изображение с достижением.
Аудиоканалы
Всего внутри "Бесконечного Лета" 8 аудиоканалов: ambience, music, sound, sound2, sound3, sound_loop, sound_loop2, sound_loop3.
Если вам необходимо добавить новый аудиоканал, то в init-блоке вашего мода пропишите следующее:
renpy.music.register_channel("название_канала", "название_микшера", True)
Пример:
init: $ renpy.music.register_channel("voices", "voice", True)
Есть три возможных микшера громкости: music, sfx и voice. Подбирайте необходимый вам микшер в соответствии с предназначением дорожки.
Если вам необходимо создать свой микшер для звука или музыки, пропишите следующее:
renpy.sound.set_mixer("название_канала", "номер_микшера")
Это задает имя микшера, связанного с данным каналом. "sfx" находится на каналах от 0 до 3, а "music" — от 3 до 7.
Пример:
init: $ renpy.sound.set_mixer(voices_mixer, 10)
Экраны
Предисловие
Экраны имеют две основные функции:
- Отображение информации. С помощью различных панелей, изображений, или вовсе текста. Например, экран диалогов (
say) используется для отображения диалога с пользователем, отображая имя говорящего. - Взаимодействие. Различные кнопки и панели, показанные экраном, позволяют игроку совершать различные действия или менять какие-либо значения.
Экраны могут отображаться четырьмя способами:
- Неявно, как, например, экран
say. - Явно, используя операторы, вызывающие отображения других экранов.
- Автоматически. Например, экран с именем
main_menuбудет автоматически вызываться, когда игрок вернётся в главное меню игры или модификации, если она, конечно, заменяет этот экран на свой. - Как действие, связанное с любой кнопкой. Например, можно привязать появление какого-либо скрина на нажатие правой/левой кнопки мыши или при нажатии на клавишу.
Язык экрана
Он состоит из оператора, объявляющего новый экран (screen), операторов, добавляющих отображаемые объекты на этот экран (например, add или imagebutton), и операторов управления (xalign, yalign, spacing).
Пример экрана:
screen test_screen: tag test modal True add "test bg"
В этом примере первая строка — оператор screen, использующийся для объявления экрана. Не забываем про то, что необходимо дать экрану имя. Оператор tag выступает в роли "тэга" для этого окна, заменяя другие экраны с таким же тегом, если вызывается ещё один экран с аналогичным тегом. Оператор modal при значении True не позволяет игроку взаимодействовать с отображаемыми объектами «под» экраном, ограничивая взаимодействие только кнопками или объектами внутри самого экрана. Оператор add добавляет изображение или любой отображаемый объект на экран. Возможно расположение по указанным координатам благодаря стандартным командам из трансформов (align, pos и прочее).
Синтаксис языка экрана
У операторов экрана в большинстве своём общий синтаксис. Если оператор заканчивается двоеточием, то он создаёт блок, в котором может быть одно из следующих составляющих:
- Список свойств (
modal True,tag menu,sensitive). - Операторы языка экрана (
imagebutton,textbutton,textи прочее).
Операторы-кнопки
button, imagebutton, textbutton — все эти операторы позволяют создать внутри экрана кнопку, которой можно задать свойства (hover, idle, action и т.д.). Как понятно из названия, imagebutton создаёт кнопку-изображение, textbutton — текстовую кнопку, а button — просто область экрана, при нажатии на которую будет выполнено какое-либо действие, указанное для такой кнопки.
Пример экрана с кнопками:
screen my_screen: tag menu modal True add "black" textbutton "Текстовая кнопка": align(0.5, 0.5) # Располагаем кнопку по центру экрана imagebutton: align(0.1, 0.1) # Располагаем кнопку в левом верхнем углу экрана idle "Путь до изображения-кнопки в состоянии 'не наведена мышка'" hover "Путь до изображения-кнопки в состоянии 'наведена мышка'" action NullAction() # Даём кнопке "нулевое действие" — при нажатии ничего не происходит
Оператор "auto"
Также, если вы не хотите прописывать idle и hover версии в две строчки, можно воспользоваться оператором auto, который автоматически находит idle и hover версии кнопки в зависимости от названия. Учтите, что в названиях файлов кнопок должны присутствовать ключевые слова idle и hover.
Пример:
screen my_screen: tag menu modal True imagebutton: auto "mymod/buttons/my_button_%s.png" # Слово, на которое опирается оператор
Полный список действий (action), которые можно дать кнопкам, можно найти здесь.
Операторы экрана
В дополнение к оператору screen, есть три оператора, которые включают экраны. Это show screen, call screen и hide screen.
Оператор show screen вызывает отображение экрана. Возможно использование с with. Также их можно вызывать с какими-либо параметрами. Например, show screen my_screen(_layer = "screens").
screen my_screen: add "black" label my_mod: show screen my_screen with dissolve # Показываем экран с растворением в 0.5 секунды.
Учтите, что screen прописываются за блоком лейбла. Можно прописать вне всяких блоков, а также внутри блока init.
Показанные таким образом экраны отображаются до тех пор, пока они не будут скрыты командой hide screen.
Оператор hide screen используется для скрытия экрана, который отображается в данный момент. Возможно использование с with.
screen my_screen: add "black" label my_mod: show screen my_screen with dissolve # Показываем экран с растворением в 0.5 секунды. pause(2) # Пауза 2 секунды hide screen my_screen with dissolve # Убираем экран с растворением в 0.5 секунды.
Оператор call screen показывает экран, а затем снова скрывает его, как только с ним закончится взаимодействие (скажем, когда будет произведён прыжок на другой лейбл). Убрать экран можно также с помощью действия return (или Return(), если мы говорим о действии для кнопки). При нажатии на неё экран будет скрыт. Если же экран был показан с помощью show screen — нас выбросит в главное меню игры. Возможно использование с with.
screen my_screen: add "black" textbutton "Нажми!": action Return() # Закрываем экран при нажатии на кнопку. label my_mod: call screen my_screen with dissolve # Показываем экран с растворением в 0.5 секунды.
Различие между Show и ShowMenu при задавании действий для кнопки
Если внутри экрана мы откроем ещё один экран, который при нажатии на кнопку был вызван действием Show (Show("my_screen")) и затем нажмём на кнопку с действием Return(), то нас выбросит в главное меню. Но! Если мы вызовем экран с действием ShowMenu (ShowMenu("my_screen")), то при нажатии на кнопку с Return() внутри второго экрана нас возвратит обратно на предыдущий экран. Удобно!
screen my_screen: add "black" textbutton "Нажми!": action Show("my_screen2") # Открываем экран "my_screen2" screen my_screen2: add "black" textbutton "Нажми!": action Return() # Нас выбрасывает в главное меню игры. И screen my_screen: add "black" textbutton "Нажми!": action ShowMenu("my_screen2") # Открываем экран "my_screen2" screen my_screen2: add "black" textbutton "Нажми!": action Return() # Нас возвращает обратно на экран "my_screen"