Touhou: Fading Illusion

Touhou: Fading Illusion

Not enough ratings
Руководство по созданию модов
By GiMark
В этом руководстве вы можете ознакомиться со всей информацией, необходимой дя создания несложного мода.
   
Award
Favorite
Favorited
Unfavorite
Предисловие
Приветствую вас, энтузиасты-мододелы! В данном руководстве вы сможете найти основную информацию, необходимую для создания мода. Перед тем, как приступить к созданию модов, рекомендую вам ознакомиться с правилами создания фанатского контента.

ВНИМАНИЕ: На данный момент инструмент для загрузки модов доступен только для пользователей Windows.

ВНИМАНИЕ: Изображения в папке "_game_resources" и некоторые части этого гайда могут содержать спойлеры.
Ограничения содержимого модов
Требования автора оригинальной серии игр
Поскольку Touhou: Fading Illusion является фанатской работой по вселенной Touhou Project, ваши моды также обязаны соответствовать требованиям, которые установил автор оригинальной серии игр ZUN. А именно, в ваших модах НИКОГДА не должно быть:
  • Чего-либо, что может нанести вред репутации Touhou Project.

  • Чего-либо, что нарушает другую интеллектуальную собственность.

  • Чего-либо, что может выдать ваш фанатский контент за одну из официальных игр Touhou Project.

  • Чего-либо, что вырезано из официальных игр Touhou Project.

  • Сцен концовок из официальных игр Touhou Project.

  • Любых материалов, направленных на рекламу личных убеждений и выходящих за рамки художественной литературы.

  • Стороннего фанатского контента по Touhou Project без разрешения его создателей.

  • Чрезмерный сексуальный контент, который считается незаконным.

  • Чего-либо, что пропагандирует ненависть к отдельным людям или группам людей.

  • Какие-либо фотографии самого ZUNа без разрешения ZUNа.
Вот на этом сайте[touhou-project.news] вы можете ознакомиться с полным списком требований.

Помимо этого ваши моды не должны содержать какой-либо вредоносный код. Если вы не желаете распространять исходники кода, то вам следует связаться с нами, и мы позволим вам опубликовать ваш мод после проверки исходников кода в частном порядке. Приступая к созданию мода, вы подтверждаете, что прочитали данное предупреждение и согласны с ним. В случае нарушений мы оставляем за собой право скрыть или заблокировать ваш мод.

Если у вас возникнут какие-либо вопросы, то предлагаем вам задать их на Discord-сервере нашей команды[discord.gg].
Начало работы
Что ж, если вы согласны со всем вышесказанным, то давайте приступим к работе. Для начала вам потребуется удобный текстовый редактор, так как работать с текстом и кодом вам предстоит МНОГО. Файлы ".rpy", с которыми предстоит работать, открываются и обычным встроенным блокнотом, но лично я рекомендую вам что-то более продвинутое, вроде VS Code или Notepad++. Обе эти программы бесплатны и находятся в общем доступе.

После этого убедитесь, что Touhou: Fading Illusion установлена на вашем компьютере, и подпишитесь на официальный мод, который поможет вам разобраться в работе кода и предоставит инструменты для загрузки.
Создание папки мода
Перейдите в папку Steam или SteamLibrary на том же диске, на котором установлена Touhou: Fading Illusion, и далее найдите папку по пути "steamapps\workshop\content\2132480\3565758917". Она должна появиться как только вы скачаете наш мод.
Не пугайтесь цифр в названии папок – это идентификаторы самого Steam, один из которых получите и вы, когда создадите свой мод.

Внутри папки нашего мода откройте папку "_upload_app" и запустите приложение. В приложении в левом меню введите название вашего мода и нажмите кнопку "Create Item" в левом нижнем углу. После этого в папке WorkshopContent появится папка для содержимого вашего мода, а также файл *ваше название*.workshop.json – он-то нам и нужен (советуем где-нибудь сохранить его после того, как заполните).
Откройте его, скопируйте значение поля "publishedfileid" и создайте папку с таким же именем в папке "steamapps\workshop\content\2132480". Поскольку у пользователей мод будет загружаться по этому же адресу, имеет смысл разрабатывать его сразу же на месте. Создайте в папке вашего мода файлы mod_info.rpy и script.rpy, после чего откройте аналогичный файл mod_info.rpy в папке нашего мода с помощью текстового редактора.



Информация о моде
Внутри mod_info.rpy вы можете увидеть следующий код:
init 99 python:
    tfi_official_mod_path = os.path.join(os.path.dirname(os.path.dirname(renpy.config.basedir)), "workshop/content/2132480/3565758917").replace("\\","/")
    global_game_mods["tfi_official_mod"] = {
      "start_scene": "tfi_official_mod_scene1",
      "description": _("This is a tutorial mod that also serves as a template for creating other mods. Open the folder steam/steamapps/workshop/content/2132480/3565758917 to look at the code and images in more detail."),
      "name": _("Tutorial mod"),
      "image": os.path.join(tfi_official_mod_path, "images/preview.png").replace("\\","/"),
    }
Для вашего мода вам потребуется скопировать этот код в свой файл mod_info.rpy и поменять в нём несколько вещей:
  • Замените tfi_official_mod в global_game_mods["tfi_official_mod"] на любое другое уникальное название на латинице. Это идентификатор вашего мода внутри файлов игры, и чтобы у вас точно не возникло конфликтов с другими модами предлагаем вам ввести название вашего мода на латинице и позже использовать его для наименования переменных и сцен.

  • Смените значение поля start_scene – это наименование первой сцены, на которую перейдёт игрок после того, как запустит ваш мод. Для простоты скопируйте туда название вашего мода, о котором мы говорили выше, и просто добавьте к нему "_scene1", так как наименования сцен также должны быть уникальными.

  • Поля description и name – это текст, который будет виден пользователям во внутриигровом меню выбора модов. Можете заполнить его по своему усмотрению, но учитывайте, что место ограничено. Вы можете использовать тег {size}, чтобы увеличивать или уменьшать размер текста.
    "{size=+2}Этот текст больше.{/size}"
    "{size=-2}Этот текст меньше.{/size}"


  • Поле image – это превью-изображение вашего мода, которое также будет показываться в меню выбора модов. Вы можете оставить это поле пустым или полностью убрать, если у вас нет картинки – в таком случае будет показана заглушка с вопросительным знаком.

В итоге у вас должно получиться нечто подобное:

После того, как вы закончите с mod_info.rpy, скопируйте информацию из нашего файла script.rpy в свой. Давайте разберём весь представленный код.
Блок "init:"
Здесь содержатся переменные, которые вы захотите задать для вашего мода. Например, команда "define tfi_official_mod_dev = Character(_('TFI Main Dev'))" задаёт нового персонажа с именем "TFI Main Dev". Вы можете сделать любое количество своих персонажей, но убедитесь, что названия переменных для ваших персонажей также уникальны и не пересекаются с нашими переменными или переменными из других модов. Мы рекомендуем вам и здесь использовать некий уникальный для вашего мода префикс в названиях.

Если персонаж ситуативный, то вы можете не задавать переменную, а использовать имя персонажа напрямую перед его репликой.
"TFI Main Dev" "Hello!"
"TFI Player" "Hey!"
В таблице ниже представлены переменные, которые на данный используются в нашей игре и к которым можете по необходимости обращаться и вы. По мере введения новых персонажей в сюжет мы будем добавлять новые переменные.

Персонажи официальной серии игр

Имя
Тег
Имя
Тег
Имя
Тег
Имя
Тег
Имя
Тег
Рейму
rei
Мариса
mar
Бякурен
byak
Рин
orin
Ринноске
korin
Юкари
yuk
Моко
moko
Канако
kan
Ёму
youmu
Санаэ
san
Касэн
kas
Клаунпис
clown
Эйрин
eirin
Рейсен
reisen
Назрин
naz
Сатори
sat
Уцухо
okuu
Сувако
suwa
Комачи
koma
Эйки
eiki
Чень
chen
Ран
ran
Ая
aya
Юги
yuugi
Мима
mima
Мамидзо
mami
Сумиреко
sum
Мэйлин
mei
Кокоро
kokoro
Сакуя
sak
Койши
koi
Ремилия
remi
Мизучи
mizu
Сейджа
seija
Фландр
flan
Гекатия
heca

Второстепенные или оригинальные персонажи

Имя
Тег
Имя
Тег
Имя
Тег
Имя
Тег
Имя
Тег
Девочка
girl
Хитому
hito
Баке-дануки
bake
Кролик
usausa
Тенгу
tengu
Каппа
kappa
Ямараджа
yamaraja
Итимэ-кодзо
itime

Переменная "tfi_official_mod_path" работает как сокращение пути до папки вашего мода из основной папки игры. Если вы будете использовать какие-либо свои изображения, то эта переменная вам пригодится. Всё, что вам нужно сделать – это заменить "tfi_official_mod" в имени переменной на название своего мода, как и до этого, а также заменить имя последней папки в пути "workshop/content/2132480/3565758917". Соответственно, вы можете обращаться ко всем файлам из папки "3565758917/_game_resourses" без указания этой переменной, так как они присутствуют в основной игре, а если это ваш уникальный файл, то нужно добавлять её.
define mod_name_path = os.path.join(os.path.dirname(os.path.dirname(renpy.config.basedir)), "workshop/content/2132480/your_folder").replace("\\","/")
show image("[mod_name_path]/images/your_image1.png")
show image(Transform("images/backgrounds/hakurei_shrine_inter_d1.jpg", zoom=0.5))
Сцены и строки
Далее следует начало сцены, которое определяет метка label, которой вы присваиваете уникальное имя. До этого вы указали начальную сцену как "*ваш мод*_scene1", так что в теперь замените название этого label на неё же.

Если всё готово, то дело осталось за малым – придумать сюжет и записать его. Текст стоит выводить на экран порционно, чтобы он помещался в диалоговое окно. Если перед строкой стоит идентификатор персонажа, то одновременно с текстом будет показываться его имя, а если идентификатора нет, то будет показываться просто текст.

Также в игре присутствует возможность одновременных реплик двух или трёх персонажей. Всё что вам нужно сделать – это дописать справа от реплики (multiple = 2) или (multiple = 3):
rei "Удачи." (multiple = 2)
mar "Пока." (multiple = 2)
Изображения и их смена
Допустим, реплики вы придумали, но что делать с изображениями? С ними всё немного сложнее. Рекомендуем вам ознакомиться с соответствующим разделом документации RenPy[www.renpy.org], если вы не найдёте ответы на свои вопросы в примерах ниже.

Задний фон и статичные изображения
Вывести изображение на экран можно командой show image("путь до изображения"). Поскольку целевое разрешение игры это 1920*1080, а многие изображения выполнены в большем разрешении, их требуется сжимать командой Transform() перед выводом на экран. Для фонов и некоторых CG мы использовали коэффициент 0.5, а для спрайтов 0.6, но вы можете использовать любой другой на ваше усмотрение. Также рекомендуется применять в начале сцены команду scene, которая заменяет собой все остальные изображения.
scene image(Transform("images/backgrounds/human_village1_m.jpg", zoom=0.5))
show image(Transform(tfi_official_mod_reimu_happy, zoom=0.6))

Динамичные спрайты
Но помимо этого в Touhou: Fading Illusion мы использовали несколько нестандартных для RenPy методов, чтобы оптимизировать игру или добавить новые возможности для режиссуры. А именно: добавили новый слой в системе отображения изображений, на котором показываются собранные послойно спрайты персонажей.

В нашем моде представлен следующий код:
$ chars = 2
$ elems = 13
$ scale = 0.6

$ pict_ = [
["none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png",],
["none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png","none.png",],
]

$ pict_1 = [
[
"none.png",
"none.png",
"none.png",
"sprites/Sakuya/sak_body1.png",
"sprites/Sakuya/sak_body1_brow1.png",
"sprites/Sakuya/sak_body1_eyes1_d.png",
"sprites/Sakuya/sak_body1_mouth2.png",
"sprites/Sakuya/sak_body1_leftarm2.png",
"sprites/Sakuya/sak_body1_rightarm6.png",
"none.png",
"none.png",
"none.png",
"none.png",
],
[
"none.png",
"none.png",
"none.png",
"sprites/Nazrin/naz_body1.png",
"sprites/Nazrin/naz_body1_brow1.png",
"sprites/Nazrin/naz_body1_eyes5_f.png",
"sprites/Nazrin/naz_body1_mouth18.png",
"sprites/Nazrin/naz_body1_arms1.png",
"none.png",
"none.png",
"none.png",
"none.png",
"none.png",
],
]

$ xp = [111000, 111000, 111000]
$ yp = [-130, -130, -130]
$ copy()
show screen _Pers_ onlayer add_l
Здесь вы можете видеть, как в коде собираются спрайты Сакуи и Назрин: мы используем послойное отображение, чтобы можно было удобно менять выражение лица или положение рук, не ограничивая себя в вариациях. Перед тем, как указывать конкретные элементы спрайтов, вам нужно задать переменные chars (количество персонажей), elems (количество элементов) и scale (коэффициент масштабирования спрайтов), а также поместить в переменную pict_ аналогичные спрайтам массивы, но с изображениями "none.png".

Положение спрайтов задаётся двумя переменными – xp и yp, которые отвечают за вертикальное и горизонтальное положение соответственно. Для каждого спрайта эта переменная задаётся отдельно, например xp[1] = … , но также можно задать координаты всех спрайтов сразу с помощью массива – xp = […, …, …]

В довесок к этому методу прилагается отдельный слой, на котором отображаются спрайты: "show screen _Pers_ onlayer add_l". Этот слой стоит перед стандартным слоем, на котором показываются изображения, поэтому спрайты всегда будут стоять перед всеми остальными изображениями. Если вы захотите показать изображение перед спрайтами, то вам нужно будет добавить "onlayer add_l".

Но, конечно же, всё это не обязательно, и вы можете заранее создать один полный спрайт из слоёв, поместить его в переменную pict_1 аналогичным образом, а потом менять на любой другой, или же пользоваться стандартными методами RenPy.

В коде ниже представлены примеры смены элементов спрайтов или отображения "цельного" спрайта Рейму из файлов мода.
$ pict_[0][4] = "sprites/Sakuya/sak_body1_brow3.png" # 4
$ pict_[0][5] = "sprites/Sakuya/sak_body1_eyes3_f.png" # 5
$ pict_[0][6] = "sprites/Sakuya/sak_body1_mouth6.png" # 6
$ pict_[0][7] = "sprites/Sakuya/sak_body1_leftarm3.png" # 7
$ pict_[0][8] = "sprites/Sakuya/sak_body1_rightarm1.png" # 8

$ pict_[1][4] = "sprites/Nazrin/naz_body1_brow3.png" # 4
$ pict_[1][5] = "sprites/Nazrin/naz_body1_eyes3_f.png" # 5
$ pict_[1][6] = "sprites/Nazrin/naz_body1_mouth10.png" # 6
$ pict_[1][7] = "sprites/Nazrin/naz_body1_leftarm1.png" # 7
$ pict_[1][8] = "sprites/Nazrin/naz_body1_rightarm4.png" # 8

hide image(Transform(tfi_official_mod_reimu_happy, zoom=0.6))

show image(Transform(tfi_official_mod_reimu_sad, zoom=0.6)):
xalign 0.8
yalign -0.1
with dissolve

Изменение цвета
Также у вас есть возможность изменить цветовую гамму изображения с помощью функции blur() по трём показателям – hue, brightness и saturation. То есть blur(image, 320, 120, 100) изменит показатели hue на 320, brightness на 120 и saturation на 100 для изображения image.
$ pict_[0][3] = blur("sprites/Sakuya/sak_body1.png", -10, -0.22, 0.9) # 4
$ pict_[0][4] = blur("sprites/Sakuya/sak_body1_brow3.png", -10, -0.22, 0.9) # 4
$ pict_[0][5] = blur("sprites/Sakuya/sak_body1_eyes3_f.png", -10, -0.22, 0.9) # 5
$ pict_[0][6] = blur("sprites/Sakuya/sak_body1_mouth6.png", -10, -0.22, 0.9) # 6
$ pict_[0][7] = blur("sprites/Sakuya/sak_body1_leftarm3.png", -10, -0.22, 0.9) # 7
$ pict_[0][8] = blur("sprites/Sakuya/sak_body1_rightarm1.png", -10, -0.22, 0.9) # 8
Эффекты
RenPy поддерживает разнообразные визуальные эффекты, с которыми может появляться или исчезать изображение. Вы могли заметить, многие команды в приведённых примерах заканчиваются командой "with dissolve". Она нужна для того, чтобы изображения появлялись или исчезали не сразу, а с переходом в 1 секунду. Также есть другая встроенная версия – dissolve_f, которая равняется 0,25 секундам и используется при смене элементом спрайтов, чтобы не растягивать игровое время слишком сильно. Вы можете создать свою версию перехода с помощью подобной переменной:
define dissolve_five = Dissolve(5) # переход длительностью 5 секунд
По большей части мы пользуемся только этим эффектом, но вы можете использовать и другие эффекты, которые применяются аналогичным образом. Подробнее об эффектах вы можете прочитать на соответствующей странице документации RenPy[www.renpy.org].
Музыка и звуки
Вы можете проиграть или остановить музыку с помощью команд renpy.music.play и renpy.music.stop. После пути файла вы можете указать канал, в котором будет воспроизводиться трек, а также эффект, с которым он начнёт проигрываться или затихать.
$ renpy.music.play("sounds/ambience/crowd_medium1.ogg", channel="music_2", synchro_start=True, fadein=2.0)
$ renpy.music.stop(channel="music_2", fadeout=1.5)
Всего существуют 3 канала для музыки – music, music_1 и music_2, а также один канал для одноразового воспроизведения звуков – sound.
Выборы
Мы модифицировали стандартное меню с выборами, чтобы отображались не только возможные варианты, но и вопрос, который ставится перед игроком. Для того, чтобы отображался вопрос, вам нужно обновить переменную menu_question:
$ menu_question = _("Do you need an extra round?")

$ quick_menu = False
window hide dissolve

menu:
    with dissolve
    "Yes, please!":
      $ quick_menu = True
      window show dissolve
      jump tfi_official_mod_scene1
    "Nah, I got it.":
      $ quick_menu = True
      window show dissolve
Использование переменных
Вы можете использовать переменные, например, для того, чтобы запоминать выборы игрока. Переменные могут быть как текстовые (= "один"), так и числовые (= 1) или логические (= True). Больше про переменные вы можете прочитать в соответствующем разделе документации RenPy[www.renpy.org].
$ menu_question = _("Один или два?")

menu:
    with dissolve
    "Один!":
      $ mod_name_player_choice = 1
      jump mod_name_scene_player_pick_one
    "Два!":
      $ mod_name_player_choice = 2
      jump mod_name_scene_player_pick_two
if your_mod_condition == 2:
    jump destitute1_scene2_5
else:
    jump destitute1_scene1_5
Перевод
ВНИМАНИЕ: Некоторые члены нашей команды высказали своё желание переводить помимо основной игры понравившиеся им моды, так что если у вас есть желание, то вы можете написать им на нашем Discord-сервере[discord.gg].

Если вы планируете делать мод на нескольких языках, то вам нужно будет сгенерировать файлы перевода. Для их генерации потребуется загрузить RenPy 8.3.7[www.renpy.org], указать путь игры в настройках и сгенерировать перевод на желаемый язык.
Вы можете переводить не только диалоговые строки, но и переменные и имена персонажей: для этого нужно заключить текст в кавчыки с нижним подчёркиванием _(...) во время объявления переменной:
define tfi_official_mod_dev = Character(_('TFI Main Dev'))
Однако предупреждаем вас, что некоторые переменные могут вызывать ошибки в новом проекте, и поэтому рекомендуется сгенерировать там только файлы перевода диалоговых строк, для которых нужен идентификатор перевода строки, а идентификатором переменных выступает сам переводимый текст.
# переводимая строка
translate english prologue_scene_0_89ef4bf6:
    "Humanity has always been afraid of the unknown."

# переводимая переменная
translate english strings:
    old "Продолжение следует..."
    new "To be continued..."
После генерации переместите папку tl в папку вашего мода и заполните поля для перевода во всех новых файлах.
Также рекомендуем вам сделать аналогичное меню в начале вашего мода, чтобы пользователи понимали, какие языки доступны и что они доступны в принципе.
menu:
with dissolve
"{font=fonts/Merriweather-Regular.ttf}Я хочу играть на Русском{/font}":
$ renpy.change_language("russian")

"{font=fonts/Merriweather-Regular.ttf}I want to play in English{/font}":
$ renpy.change_language("english")

"{font=fonts/SourceHanSansCN-Regular.otf}{size=26}以简体中文开始{/size}{/font}":
$ renpy.change_language("schinese")

"{font=fonts/NotoSansJP-Regular.ttf}{size=26}日本語でプレイする{/size}{/font}":
$ renpy.change_language("japanese")
Всего на момент написания гайда в игре поддерживается 9 языков: Русский (russian), Английский (english), Французский (french), Испанский (spanish), Бразильский Португальский (portuguese), Традиционный Китайский (tchinese), Упрощённый Китайский (schinese), Корейский (korean) и Японский (japanese). Если вы используете язык, для которого не используются алфавиты какого-либо из этих языков, то вам потребуется включить в свой мод новые шрифты.
Дополнительные возможности
Работа с камерой
Из-за того, что персонажи отображаются на отдельном экране, вам потребуется двигать и этот экран одновременно со стандартным слоем камеры, если вы захотите приблизить или отдалить картинку.
camera:
    perspective True
    gl_depth True
    zpos -1100 xpos -375 ypos -380
    easein 3.0 zpos 0 xpos 0 ypos 0
show layer add_l:
    perspective True
    gl_depth True
    zpos -1100 xpos -375 ypos -380
    easein 3.0 zpos 0 xpos 0 ypos 0

Экран с датой и временем
В игре встроена возможность показать экран с местом, датой и временем, если вдруг в вашей истории также будет разделение на дни и часы.
$ date_place = _("Муэндзука")
$ date_date = _("17 апреля 2018 года")
$ date_time = _("Вечер, через несколько часов")
show screen date with dissolve

Экран загрузки
Если "пересборка" или изменение цвета спрайтов достаточно масштабное, оно может привести к небольшой задержке в игре, так как RenPy требуется время, чтобы обработать и разместить на экране все изображения по отдельности. Чтобы подобные моменты не бросались в глаза, мы сделали экран перехода с надписью "Девушки молятся…". Для его вызова вам потребуется ввести команду show screen loading и потом hide screen loading. Для плавности перехода мы перед этим скрываем и потом показываем диалоговые окна следующими командами.
$ quick_menu = False
window hide dissolve

$ quick_menu = True
window show dissolve
Тестирование мода
Перед тем, как публиковать свой мод, вам нужно убедиться в его работоспособности. Помочь в этом может режим разработчика. Для того, чтобы активировать его, вам нужно добавить следующий код в ваш блок b]init[/b]:
define config.developer = True
define config.default_developer = True
Теперь если вы нажмёте сочетание клавиш Shift + R, то игра будет перезагружаться на то же самое место каждый раз, когда происходят изменения в файлах. Это значит, что вы сможете оперативно вносить изменения в свой код и сразу же смотреть на результат. Однако отмечу, что в при обновлении игры файл будет восстановлен до своего первоначального состояния.
Загрузка мода
После того, как вы закончите со всеми действиями, вам нужно:
1. Поместить файлы мода в папку мода в приложении для загрузки. Не забудьте про превью-изображение, которое должно быть квадратным и как минимум в разрешении 500*500 пикселей.
2. Ввести все необходимые данные. Советуем переместить всю папку _upload_app куда-нибудь за пределы папки 2132480, чтобы загружаемые вами копии файлов мода в будущем не конфликтовали с файлами модов.
3. Ввести комментарий и нажать кнопку Submit. Вся введённая информация будет сохранена в вашем файле .workshop.json.

Если у вас остались какие-либо вопросы, то предлагаем вам написать их в комментариях к этому гайду, чтобы мы могли обновить информацию. Надеемся, что у вас всё получится, и удачи в создании качественной литературы!