Моды вносят различные изменения в игру. Например, меняют интерфейс, добавляют костюмы для персонажей, добавляют новых персонажей, изменяют сцены, которые уже есть в игре.
Официальные моды можно найти в самой игре. В главном меню сверху есть вкладка Моды.
По-умолчанию у вас должно быть 3 источника модов: Локальные моды, Моды для патронов и Official.
По-умолчанию, моды находятся в папке Kunoichi Trainer/mods
. Папки mods
может не быть. В таком случае её нужно создать вручную.
Так же в настройках игры, если пролистать в самый низ, можно указать другой путь до папки с модами.
Каждый мод должен находится в отдельной папке, которая называется так же, как и id мода.
В папке мода должен быть файл manifest.json
. В этом файле должна быть такая же информация, что и в источнике, кроме поля file_name
.
{ "id": "mod-id", "name": "Название мода", "version": "1.0", "description": "Описание мода", "game_version": "0.16" }
Файлы с кодом должны иметь формат .rpym, либо .rpymc. Это тоже самое, что и .rpy и .rpyc. Не знаете про .rpy и .rpyc? Смотрите документацию RenPy.
Вы пишите код мода в файлах .rpym, при запуске игры они будут скомпилированы в .rpymc.
Файлы могут лежать просто в папке, либо в .rpa архиве.
Для этого необходимо в manifest.json
добавить новый параметр merge_folders
, который является массивом строк.
В этом параметре указывается список папок, файлы из которых будут распознаваться игрой, как будто они были в самой игре изначально.
Чтобы изменить изображение в игре, нужно знать расположение оригинального изображения. В папке, указанной в параметре merge_folders
, нужно разместить новое изображение по такому же пути, что и оригинальное изображение.
Простой мод, который заменяет фон комнаты, в которой игрок появляется в самом начале игры.
Оригинальный фон хранится по такому пути:
images/bg/beginning_room.webp
Структура папок мода:
mods └───mod-id │ │ manifest.json │ └───my_folder │ └───images │ └───bg │ └───beginning_room.webp
Где mod-id/my_folder/images/bg/beginning_room.webp
- это новое изображение, на которое хотим заменить оригинальное.
Содержимое файла manifest.json
:
{ "id": "mod-id", "name": "Название мода", "version": "1.0", "description": "Описание мода", "game_version": "0.16", "merge_folders": ["my_folder"] }
Это всё, что нужно, чтобы заменить изображение.
Для этого необходимо создать класс (в файле .rpym), наследующий класс Module
и подписаться на нужные события. См. Список событий
Например, модуль, который реагирует на изменение времени суток и смену локации.
init python: # У каждого модуля должно быть уникальное название и id class DemoModule(Module): id="demo" subscribe_on_events=["time_update", "change_location"] def on_event(self, event): if event.type == "time_update": if event.is_morning: renpy.notify("Наступило утро") elif event.is_evening: renpy.notify("Наступил вечер") elif event.type == "change_location": renpy.notify("Новая локация: " + event.new_location.id)
Для этого, нужно создать переменную от класса Item, если это просто предмет, или от класса Outfit, если это элемент одежды.
item_
.Добавление обычного предмета в магазин Тен-Тен.
init python: item_pen = Item( name=__("Ручка"), cost=5, icon="my_mod_folder/pen.webp", descr=__("Ручка с чернилами."), shop="tenten", )
Добавление одежды в магазин Тен-Тен.
init python: item_ino_my_new_costume = Outfit( name=__("Новый костюм для Ино"), cost=100, descr=__("Описание предмета"), char="Ino", lust=10, layer="costume", val="my_new_costume", shop="tenten", ptr=False, icon=KTCharInventoryPreview( char_name="ino", layers=ino_preview_layers + [("costume", "my_new_costume")], crop=ino_costume_inv_preview ), )
Структура папок мода:
mods └───mod-id │ │ manifest.json │ │ item.rpym │ └───merge_folder │ └───images │ └───characters │ └───ino │ └───costume │ └───my_new_costume.webp
При таком подходе предмет будет в магазине, только если начать новую игру. Чтобы добавить предмет в магазин, если игрок загружает уже существующее сохранение надо использовать Module. См. Как взаимодействовать с игровыми событиями и событие game_loaded.
Получится что-то вроде такого:
def on_event(self, event): if event.type == "game_loaded" and not inv_shop.has_item(item_my_item): inv_shop.add(item_my_item)
if game.time.is_morning: "Сейчас день" elif game.time.is_evening: "Сейчас вечер" $ game.time.set_morning() "Сейчас точно день" $ game.time.set_evening() "Сейчас точно вечер" $ game.time.next_cycle() "Если был день, сейчас вечер. Если был вечер, сейчас день и счетчик дней увеличился." $ game.time.next_day() "Сейчас точно день и счетчик дней увеличился на 1." $ game.time.skip_days(10) "Счетчик дней увеличился на 10."