Overview
Будем учиться создавать свои моды на “Бесконечное Лето”
Предисловие
Сразу же оговорюсь, никаких модов в общий доступ я не выкладывал пока, по причине того что сценарист из меня так себе (ИМХО). Я лишь делал небольшие мини моды, которые выкидывались в корзину спустя 1-2 дня после их завершения. В моем руководстве будет лишь теория для Steam версии (совместимость с другими версиями возможна но не гарантированна)
Начинаем творить
Для создания мода нам понадобится:
- Сама игра, в нашем случае Everlasting Summer
- Текстовый редактор, я советую использовать Notepad++
В принципе для небольших и простеньких модов этого должно хватать, но если вы захотите использовать собственные bg, cg и спрайты, то необходим либо графический редактор, либо собственный художник.
Создаем текстовый файл, с любым названиме и расширением .rpy (Надеюсь вы знаете, как создавать файлы с другими расширениями)
А теперь открываем его нашим текстовым редактором (У меня это Notepad++) и продолжаем вникать в это руководство
Где мой мод? Почему передо мной пустой файл?
Весь моддинг “Бесконечного Лета” заключается в писании магических фраз в файлах .rpy, которые игра будет читать и делать то что мы захотим (но конечно же есть ограничения)
Подожди, писать заклинания еще рано, сначала нужно понять, как правильно расставлять слова для эффекта
Структура файла выглядит примерно так:
Команды в блоке ВСЕГДА имеют отступ в 4 пробела относительно команды говорящей нам о начале блока.
Есть несколько команд начинающих блок, пока стоит лишь запомнить то, что после команды, начинающей блок всегда ставится двоеточие (:)
На данном этапе создания мода нам понадобится лишь одна блоковая команда
label <Название метки>: – Обычно используется для разделения мода на части, для удобной навигации между ними
Существует 2 варианта перейти от одного блока к другому
Вариант 1 – “Прыжок”
В этом варианте сначала выполняется первый блок, а затем второй. При этом используется команда
jump <Название блока>
Вот уже знакомый нам пример:
В этом случае если написать в блоке vasya_mod_d1 что либо после jump’a, то игра просто пропустит это
Вариант 2 – “Вызов”
В отличии от прыжка, при использовании этого варианта после полного выполнения блока на который переходит игра, она вернется в первоначальный и продолжит его выполнение после команды. Команда для этого:
call <Название блока>
Ну и как же без примера:
Окончание блоков, переход к которым осуществляется именно этим методом имеет некоторые особенности, о которых можно узнать дальше
Если к этому блоку ведут jump’ы, то конец блока можно ничем не выделять, если только это не последний блок в вашем моде (Последний блок 1/x концовки). В ином же случае последней командой блока должна быть команда return. Зачем? В случае если это последний блок, чтобы игра могла закончить обработку мода и вернуться в главное меню. Если же на блок привела команда call, то игре просто необходимо знать, когда вернуться в предыдущий блок.
Получается что наш пример call не будет работать и нам придется привести его к такому виду:
Из всего этого можно понять то, что ваш мод запускается именно методом вызова, где блок из которого вызывают – главное меню игры.
Пора бы уже и поговорить
Как мы все знаем “Бесконечное Лето” – это визуальная новелла и весь сюжет в ней разворачивается посредством диалогов персонажей и выборами Главного Героя,
Благодаря движку игры, это было реализовано донельзя просто.
Просто в виде команды пишем следующий текст
<ID говорящего> “<Что он(а) сказал(а)>”
Ковычки обязательны!
Все просто, этот ID говорит нам о том, с кем же сейчас ГГ разговаривает
Вот их список:
Для текста от автора ID не нужен
Остальных говорящих вы можете увидеть на прикрепленной картинке да, картинка копипаст
Для примера мы попросим поздороваться каждого из основных говорящих
ID персонажей без определенного имени (Для использования пока имена персонажей не известны):
Как украсить речь персонажей?
В игре вы встречались с тем, что некоторые слова во фразах персонажей были как-то выделены или вовсе были в ковычках. Для этого используются специальные теги.
Как мы уже знаем, ковычки ограничивают реплики персонажей, так как же нам использовать их внутри этих реплик?
Чтобы ковычки не учитывались игрой, перед ними нужно поставить
Как мне показать где происходят действия героев?
В самой игре при смене местоположения нашего ГГ меняется и картинка на фоне (bg)
Так как же нам показать где сейчас наш герой?
А делается это при помощи команды scene bg <Название фона>
Например:
Все bg из игры -> Ссылка[drive.google.com]
Так же в архиве приложен текстовый файл из которого сразу можно скопировать нужную строку
Персонажи в игре – не что иное, как тоже картинки, только именуются они спрайты.
Перечислять их все на буду, но скажу, что их более 350
Вызываются все спрайты командой show <Имя спрайта>
Имя спрайта обычно состоит из нескольких слов, разделенных пробелами
<имя персонажа> <эмоция> <одежда>
В оригинальной игре имя персонажа совпадает с ID говорящего из предыдущего раздела этого руководства
Например:
И так далее
Список всех спрайтов -> Ссылка[drive.google.com]
Если персонаж уже на экране, то повторное использование show будет менять эмоцию и/или одежду
При простом использовании show <Спрайт> он будет появляться просто по центру, это можно исправить добавив в конец at <Позиция>
show <Спрайт> at <Позиция>
Всего в игре 7 позиций где может находиться спрайт:
fleft, left, cleft, center, cright, right, fright
На приведенном скриншоте были использованы команды:
Так же можно показать персонажа ближедальше. Для этого можно воспользоваться атрибутом close/far
На втором скриншоте как раз были использованны эти атрибуты. Команды:
Для того, чтобы убрать персонажа воспользуйтесь
hide <Имя персонажа>
Если вы хотите вслед за этим сменить декорации, то прописывать hide для каждого персонажа не обязательно, команда scene сама их уберет
Тут принцип как и с bg, только надо использовать scene cg
Все cg со списком -> Ссылка[drive.google.com]
Примеры думаю не нужны.
Как можно украсить спрайты, bg и cg
Мы можем показать спрайты, bg и cg с некоторым замедлением, плавно
Так же есть еще несколько эффектов, о которых речь пойдет далее, некоторые из эффектов можно применить не только к изображениям, но и даже друг к другу!
Чтобы показать наши картиночки более красиво для человеческого глаза, мы можем использовать специальный атрибут. Это будет выглядеть примерно так:
scene bg <Название bg> with <Атрибут>
Атрибутов для плавности 6, они отличаются лишь своей скоростью.
dspr – 0,2 сек – Самый быстрый, на практике не особо заметен
dissolve – 1 сек – Средняя скорость, считаю оптимальной для смены cg на bg и наоборот и для эмоций спрайтов
dissolve2 – 2 сек – Самая плавная картинка, считаю хорошим вариантом для переходов между локациями лагеря
dissolve_fast – 0.5 сек.
hell_dissolve – 50 секунд – на практике не особо применим, но вдруг пригодится.
dissolve_long – 100 секунд.
Так же можно группировать несколько обьектов для одновременного начала эффекта
В приведенном примере мы попадем в ночной автобус и перед нами предстанет улыбающаяся Славя, и все это с задержкой в 2 секунды.
Так же атрибут плавности может применяться к другим эффектам.
Если все вышеприведённые примеры Вас не устраивают, можно добавить свой атрибут плавности. Для этого, пропишите его в блоке init.
После этого мы можем использовать наш переход, так-же, как и все остальные.
Я более чем уверен, что вы видели эффект того, как иногда ГГ моргает или вовсе закрывает глаза. Мы можем реализовать подобную возможность!
show blink – Закрыть глаза
show unblink – Открыть глаза
show blinking – Моргание
Будьте осторожны: blink и unblink это разные эффекты, они не могут отменить друг друга
Как открыть глаза:
Так же к эффектам моргания можно применить атрибут плавности.
Больше о изображениях и их появлениях.
Вполне может быть, что по сюжету Вашего мода, может не хватить имеющихся БГ, ЦГ и спрайтов. В таком случае, мы добавим свои. Где искать картинки, спрайты и т.д. – разбирайтесь сами, но вот что с ними делать дальше…
Для начала нам надо объявить изображение в блоке init. Делается это, с помощью объявления переменной image. Покажем на примере. Допустим, мы нашли изображение с видом города и называется оно у нас gorod.jpg Для его объявления, пропишем такую команду:
image gorod = “gorod.jpg”
(Прим.: При условии, что изображение лежит в папке game. Если оно лежит в другом месте, например в папке вашего мода, который в свою очередь находится в папке mods, объявление изображения будет выглядеть так:
image gorod = “mods/nazvanie_moda/gorod.jpg” )
Теперь мы можем использовать имеющееся изображение так-же, как и остальные:
scene gorod with dissolve
или
show gorod with dissolve
Если Вам не хватает стандартных вышеперечисленных команд (cleft, center, fright и т.д.) на положение изображения на экране – не беда. Здесь поможет встроенный в РенПи язык – ATL. Для его использования надо сделать следующее:
Вместо команды at, мы пишем после изображения двоеточие и параметризируем его по следующим командам:
anchor(a, b) – якорь, от которого будут отсчитываться прочие коодинаты. Задаётся десятичными долями.
pos(a, b) – Положение на экране, относительно якоря. Задаётся, как десятичными долями, так и координатами в пикселях.
xpos a – координата горизонтальной оси, так-же задаётся, как десятичными долями, так и координатами в пикселях. Не используется вместе с pos.
ypos a – координата вертикальной оси. Свойства, как и у xpos.
align(a, b) – Положение на экане, относительно якоря и собственного размера изображения.
xalign и yalign – аналогично предыдущему примеру.
Для начала этих трёх команд нам хватит, с их помощью мы сможем разместить изображение в любом месте экрана.
Покажем на примере.
Разместим изображение нашего города ровно по центру экрана. Для этого мы поставим якорь на середине экрана, и укажем позицию.
Что за странные циферки? Ничего не понятно!
Сейчас объясним.
Возьмём наши координаты pos(0.5, 0.5), где первая цифра – xpos (положение по горизонтали), а вторая ypos (положение по вертикали).
Весь экран условно делится на части, где 0.0 – крайняя левая часть, а 1.0 – крайняя правая (по аналогии верхняя и нижняя). Соответственно, наше 0.5 – это середина. Назревает вопрос. Можно ли использовать отрицательные числа, и числа больше одного? Да. Но в этом случае изображение будет вылезать за пределы экрана.
У align назначение похожее, но немного отличается. Этот элемент, помимо указанных координат, использует собственный размер изображения. Для примера:
Если при якоре (0.5, 0.5) мы зададим позицию pos(1.0, 0.5) – у нас пропадёт половина изображения, ибо точкой его появления будет указан край экрана. С align ситуация обстоит иначе. При использовании align(1.0, 0.5) изображение прижмётся к краю экрана, но не исчезнет.
При назначении позиции координаты pos и align можно комбинировать.
Давайте, для примера выведем спрайт улыбающейся Мику слева экрана.
Так-же мы можем заранее назначать позиции. Давайте повторим предыдущий пример, но назначим всё заранее. Для этого реализуем переменную transform в блоке init:
После этого мы можем использовать её, так-же, как и остальные.
Очень и очень многое. Допустим, анимации.
Вот стоит у нас слева на экране Мику, объявленная в прошлом блоке, но вдруг появилась Ульяна, и Мику из вежливости решила подвинуться чуть правее. Как мы это сделаем? Можно просто задать координаты положения, и Мику “телепортируется” туда, но разве это красиво? Не. У нас другие методы.
Смена положения.
Для смены положния существует 4 метода: linear, ease, easein, easeout. Для начала нам понадобится только linear. Как он работает? Очень просто. После linear мы пишем время в секундах, а после новые координаты в системе ATL.
Пример. Созданим перемещение к правому краю экрана:
Теперь добавим это в наш код.
В одной трансформации можно создавать несколько анимаций, а так-же зацикливать их. Для зацикливания используется команда repeat и после неё пишется количество повторов. Если число не указано, повторы будут бесконечно.
Например. Добавим такую трансформацию:
И импортируем её в код:
Как добавить звук?
Наверное вы и сами слышали, что в “Совенке” никогда не бывает тихо, где-то играет приятная музыка, иногда мы слышим стуки в двери, три раза в день, звук горна собирает всех обитателей у столовой.
Для того чтобы проигрывания музыки используется всего две команды
play music music_list[“<Название>”] – Начинает проигрывать указанную музыку
и
stop music – Завершает проигрывание музыки
Список всей фоновой музыки в игре -> Ссылка[drive.google.com]
Послушать эту музыку можно прямо в игре, зайдя в раздел Галерея
Для проигрывания прочих звуков нам понадобится все та же команда play, только немного в другом виде
play ambience ambience_<Название> – Игра включает нам выбранный звук
и
stop ambience – Выключает его
Список этих звуков -> Ссылка[drive.google.com]
Увы, подобрать нужный звук вам поможет лишь базовое знание Английского языка и “метод научного тыка”
Время усложнять мод!
Все что мы узнали раньше позволяет нам писать лишь статичные моды, в которых от игрока ничего не зависит. Теперь же нам пора добавить игроку возможность выбора
Если вы хотите, чтобы игра запоминала каждый выбор игрока, то без переменных нам не обойтись.
Объявление переменных происходит в специальном блоке init. Имена и значения у переменных могут быть любые, но рекомендуется использовать короткие английские слова или цифры (цифры только в значении)
Изменение значения переменных будет выглядеть так:
После выполнения данных команд переменная “choice” будет иметь значение “True”, а переменная “Count” увеличит свое значение на единицу.
Если вы хотите дать игроку выбор, то вам необходимо использовать специальный блок menu:
В приведенном примере Ольга Дмитриевна попросит нас взять мешок с сахаром, мы же можем как подчиниться и увеличить переменную “good” на 1, так и отказаться, причем в зависимости от нашего выбора события в игре могут измениться
Будьте осторожны: Варианты ответа тоже открывают блок, и если мы не поставим после каждого двоеточие, мод может не запуститься
Что нам делать если мы хотим чтобы какие то из возможностей были у игрока в зависимости от его выборов? Для этого то мы и использовали переменные! Сейчас же мы воспользуемся специальной конструкцией
Поясню данный отрезок. Если значение переменной “good” больше нуля, то игра продолжится на метке “good”, если же нет, то мы переходим на метку “bad”
Теперь же мы постараемся реализовать выборы, в которых в зависимости от прошлых выборов персонажа будут добавляться или убираться различные варианты ответов
В данном случае мы можем либо возмущаться сложившейся ситуации, если мы уже заслужили доверие вожатой, мы можем попросить ее отсрочить дежурство или если не помогали отправить ее куда подальше. И в каждом случае нам, как создателям мода необходимо будет прописать что произойдет в каждом из этих случаев
Использование карты
Иногда по нуждам сюжета необходимо дать игроку выбор куда ему пойти, использование для этого обычного меню выбора выглядит несколько не эстетично, так давайте же научимся ориентироваться в “Совенке” при помощи карты!
Чтобы дать игре понять. когда развернуть перед игроком карту необходимо всего несколько простых команд.
Во первых:
Далее заполняем конструкцию set_zone()
Где первым значением будет выделенная на карте зона, а вторым – лейбл, куда прыгать, при клике на неё.
Вот список всех зон и как они обозначены в игре:
“me_mt_house” – “Мой домик”
“estrade” – “Эстрада”
“music_club” – “Музклуб”
“square” – “Площадь”
“dining_hall” – “Столовая”
“sport_area” – “Спорткомплекс”
“beach” – “Пляж”
“boat_station” – “Лодочный причал”
“clubs” – “Клубы”
“library” – “Библиотека”
“medic_house” – “Медпункт”
“camp_entrance” – “Ворота в лагерь”
“forest” – “о. Лес”
т.е. чтобы при нажатии на клубы мы прыгали на лейбл mymodlabel2 (название, примера ради) нужно реализовать такую конструкцию:
И в конце, выводим саму карту командой:
Показываю пример полностью. Допустим нам нужны три зоны. Сцена, Муз. клуб и Пляж, и каждая ведёт к совим лейблам label1, label2 и label3, для этого мы делаем всё то, что я уже описал выше:
Как-то так.
Заселяем лагерь
Вполне возможно, что вашем моде вам понадобится персонаж, которого по какой-то причины разработчики не стали заселять в лагерь, что же делать в этом случае? Правильно создать его!
Любой персонаж игры – простая переменная, с которой мы вольны делать что захотим (*зловещий смех*)
Переменные создаются двумя способами, методом движка – с помощью команды define и методом “Питона” – с помощью символа – $.
Далее мы присваиваем переменной свойство Character().
Для примера создадим Вашего покорного слугу:
define vladya = Character(u”Владя”)
(прим.: Символ u используется, для отображения русского текста у людей, у которых он не установлен в системе.)
Теперь мы можем использовать переменную vladya в своём моде. Давайте, я поздороваюсь с Вами:
vladya “Привет”
Но стоп! Что же мы видим? У всех персонажей игры есть свой цвет, а наш персонаж белый. Некрасиво! Надо исправить. Но как-же это сделать? С помощью параметризации свойства Character у нашей переменной.
Так давайте же это сделаем! Цвет имени персонажа указывается с помощью параметра color, так-же рекомендую использовать неизменный параметр what_color, для изменения цвета речи персонажа. В самой игре, все персонажи говорят цветом f1d076, так не будем выделяться. Назначим нашему персонажу в качестве цвета имени, скажем, зелёный цвет (008000) и установим в качестве цвета речи – f1d076:
define vladya = Character(u”Владя”, color=”#008000″, what_color=”#f1d076″)
И давайте я вновь поздороваюсь с Вами:
vladya “Привет”
Намного лучше, не правда ли?
Окей, окей. Без проблем.
Допустим наш персонаж пересмотрел Ваномаса и теперь после каждого предложения говорит “ёпты блин” (пардоньте, в Стиме цензура, оригинал не работает), можно конечно прописывать после каждой строчки это замечательное словосочетание, а можно использовать команду what_suffix. Давайте дополним переменную:
define vladya = Character(u”Владя”, color=”#008000″, what_color=”#f1d076″, what_suffix=u”, ёпты блин.”)
Окей. Организуем.
Для начала реализуем перед именем вот такую конструкцию:
Эта функция создаёт переменную vano, которая содержит случайно выбранную из списка фразу. Далее используем, уже известную нам команду what_suffix и дополняем переменную имени:
define vladya = Character(u”Владя”, color=”#008000″, what_color=”#f1d076″, what_suffix=u”[vano]”)
Используя эти настройки, РенПи выберет случайную фразу из списка, после реплики персонажа. Но! На данном этапе случайная фраза будет одна. Как нам это побороть и заставить движок менять фразы, после текста? Очень просто. После блока init мы реализуем следующую конструкцию:
И после начала нашего мода прописываем:
show screen scr123
Этой командой мы будем обновлять значение переменной vano, каждую 0.1 секунду.
И что-же будет теперь:
Монитор с номером дня.
И вот уже весь лагерь, включая нашего подопечного уснул. Несомненно вы видели, как в оригинальной игре о начале нового дня нас оповещали даже. не будящие нашего протагониста лучи солнца, а простой монитор компьютера, показывающий нам сколько времени мы провели в этом дивном месте. Чем же мы хуже, давайте сделаем себе такой же монитор!
Для выведения на экран монитора, необходимо прописать две команды:
Где:
backdrop – фон с монитором.
1 – номер дня, который будет показан на мониторе,
Текст – то, как будет называться сохранение.
Фонов (backdrop) в игре 5:
А как-же ачивки?
Вы 100% видели, как в оригинальной игре да и некоторых модах, при прохождении концовок появляется картинка а-ля “Achivement Complted” И хотели бы в свой мод такую же.
Для этого в нужном вам месте вставьте следующие команды
Где “myachiv” – Ваша картинка с ачивкой.
Ну, вот и всё. Ачивка выведена.
Нет. У меня есть моё личное правило: если какой-то код периодически повторяется – я пишу под него функцию. Ибо удобно.
К слову, в БЛ вывод ачивок реализован именно так, но оригинальная функция нам не подойдёт, ибо она подогнана только под уже заложенные ачивки “Лета”, так что нам нужно немного её переделать, под более универсальные нужды.
Для этого, реализуем следующую конструкцию в блоке питона.
Теперь, в месте вывода ачивки, надо прописать лишь обращение к функции, и в скобках прописать картинку с Вашей ачивкой в кавычках.
Где, опять же, “myachiv” – Ваша картинка с ачивкой.
P.S.: Название функции “achiv_for_my_mod” дано, для примера, и его можно и нужно менять. т.к. если функция, с одним и тем же названием, дважды (или больше) встретится в разных модах – будут конфликты.
Полезные советы
Старайтесь в своем моде задавать уникальные имена блоков и функций, иначе игра не будет знать куда же ей переходить и что выполнять, что зачастую черевато вылетом
Большинство модов, сценарий которых пишется одним человеком-разработчиком мода, да еще и в процессе написания самого мода, забрасываются на очень ранних этапах. Не советую вам начинать писать мод, не имея сценария, иначе это может ударить по вашей самооценке.
Если вам прямо не терпится создать мод, а сценария нет, загляните на “Книгу Фанфиков[ficbook.net]“, там вы вполне сможете найти себе сюжет по душе, только свяжитесь с автором фанфика и узнайте, согласен ли он на создание мода по его творчеству или нет
Исправляем ошибки в моде
Вполне возможно, что во время написания мода вы могли что-то где-то не так сделать и теперь у вас выдает ошибку, давайте разберемся в самых частых ошибках.
Решение: Проверьте свой мод на то что везде у вас отступ не Tab, а 4 пробела
Решение: Обычно при этой ошибке еще и указан номер строки, проверьте, закрыли ли вы ковычки на этой строке
Решение: Проверьте, везде ли отступ по 4 пробела
Решение: Проверьте команду в указанной строке
Решение: Проверьте label и jump/call на наличие опечаток
Пишите возникающие у вас ошибки и решения будут добавлены сюда
Прочее
Писать мод. не имея возможности самому его запустить и протестировать – по меньшей мере глупо.
Для того чтобы игра увидела ваш мод просто обьявите в init: блоке следующую переменную
$ mods[“<Mod ID>”] = u”<Название мода>”
Где:
MOD ID – Любое английское слово
Название мода – То, какое вы хотите видеть в меню игры
Проверьте, что ваш мод начнется с метки с тем же названием, что и Mod ID
Теперь, положив ваш .rpy файл в Everlasting Summer/game вы сможете запустить ваш мод, так же как и любой другой
Полезные вещи для написания мода
У вас в моде много картинок и вам не охота тратить 100500ч времени на прописывание их в файле мода? Вам поможет данное видео:
(Автор видео – Владя)
Преимущества:
- Вам не нужно отдельно прописывать все файлы
- Потенциально может сработать не только с изображениями, но и с музыкой
Недостатки:
- Имя файла задается по строго определенному алгоритму и если изображения предварительно были названы “как попало” то в получившихся именах “без бутылки и не разберешься”
Хотели использовать в своем моде возможность самостоятельно выбирать игроком музыку? Пришли к тому выводу, что лучший выбор – телефон / mp3 плеер , а делать его реализацию на Ren’Py весьма муторно? Обрадую вас, такая возможность уже реализована самым “прошаренным” в вопросах Ren’Py человеком в этом гайде – Владей
Скачать и посмотреть этот телефон можно по ссылке – Телефон[drive.google.com]
Весь код снабжен комментариями и должен быть понятен
Телефон выполнен в виде отдельного мода, но при желании его можно вытащить из .rpy файла и использовать у себя (Не забывайте про Полезный совет №1)
Преимущества:
- Готовая реализация переключения музыки прямо в игре.
- Возможность настроить внешний вид телефона
Недостатки:
- На мой взгляд несколько “не эстетичная” кнопка “Достать телефон” (Можно допилить до ума)
- При открытии телефона плейлист автоматически будет прокручен до самого низа
Раздел был написан Автором руководства, с использованием контента от Владя, с его личного разрешения.
Послесловие
Данное руководство еще не завершено, на данный момент в нем есть все необходимое для создания небольшого мода. Руководство будет дополняться.
Благодарности:
Команде Sovet Games – За создание столь прекрасной визуальной новеллы
Владя – Автору нескольких интересных модов, за помощь в дополнениии данного руководства
🔰 Лена 🔰 – за помошь в коментариях всем, кто столкнулся с затруднениями
Полезные ссылки:
Все используемые в руководстве ссылки -> Ссылка[drive.google.com]
Задавайте в комментариях свои вопросы, в процессе ответов на них, руководство будет дополняться