Перейти к основному содержанию

Рецепты

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

Форма и ее отсутствие

Здесь все просто. Либо форм есть, либо те же предметы можно хаотично расскидать по слотам крафта (создания) и получить результат. К бесформенным рецептам можно отнести красители, зажигалку, вагонетки с сундуками, воронками и прочее. Остальные же, имеют форму и должны быть расположены с предопределенным сочетанием слотов.

Любой рецепт определяет предметы, которое должны находиться в сетке крафта. Для бесформенных рецептов списка в виде массива из предметов будет достаточно. Что же касается имеющих форму, необходимо предоставить игре паттерн (шаблон). Паттерн заполняет ячейки сетки крафта, образуя собой форму рецепта.

Представим, что у нас появилась необходимость добавить рецепт для двери. Зачем создавать дверь из досок, если можно использовать для этого палки?

[
[VanillaItemID.stick, VanillaItemID.stick],
[VanillaItemID.stick, VanillaItemID.stick],
[VanillaItemID.stick, VanillaItemID.stick]
]

Так выглядит паттерн рецепта, если представить его в виде двумерного массива из идентификаторов. Вроде неплохо, но зачем дублировать один и тот же идентификатор шесть раз. Разработчики игры, вероятно, подумали также, благодаря чему помимо паттерна к нам приходит понятие маски.

Маска определяет ключевые ссылки для паттерна. Несовсем понятно? Давайте рассмотрим это на примере.

// вот маска
{
s: VanillaItemID.stick
}
// а вот и паттерн, основанный на маске
[
"ss",
"ss",
"ss"
]

Маска позволяет задать список предметов для его последующего использования в паттерне. Ключи представляют собой символ, он не должен повторяться и обычно выделяет начало идентификатора. Думаю, можно переходить к практическому применению.

Крафтинг

Внутреигровой верстак представляет собой сетку крафта из слотов 3x3, сам игрок же может использовать собственный инвентарь для создания предметов и блоков в сетке 2x2. Это основная игровая механика, вокруг которой выстроена большая часть рецептов.

Бесформенный

Итак, вам неважно в какой последовательности будут распологаться предметы в слотах. Для добавления таких рецептов используются методы:

Recipes.addShapeless({
id: VanillaItemID.diamond, count: 1, data: 0
}, [
{ id: VanillaItemID.iron_ingot, data: 0 },
{ id: VanillaItemID.gold_ingot, data: -1 },
{ id: VanillaItemID.flint }
]);
Recipes.addShapeless2(VanillaItemID.diamond, 1, 0, [
{ id: VanillaItemID.iron_ingot, data: 0 },
{ id: VanillaItemID.gold_ingot, data: -1 },
{ id: VanillaItemID.flint }
]);

Это добавит рецепт крафта для алмаза из слитка железа и золота, скрещенныx с кремнием. Сами методы идентичны, за исключением того что первый обрабатывает объект и может принимать экстру.

Мета предмета может указывать как на весь идентификатор (-1), так и иметь ввиду только основной предмет, исключая его вариации (0). По умолчанию используется именно последнее, как это представлено в случае с кремнием.

Паттерном по маске

Куда более частым способом регистрации рецептов остается задание конкретной формы. Форма представляет собой комбинацию маски, описывающей идентификаторы предметов, и паттерна, представляющего из себя сетку:

Recipes.addShaped({
id: VanillaItemID.sapling, count: 1, data: 0
}, ["l", "l", "o"], [
"o", VanillaBlockID.log, 0,
"l", VanillaBlockID.leaves, 0
]);
Recipes.addShaped2(VanillaItemID.sapling, 1, 0, ["l", "l", "o"], [
"o", VanillaBlockID.log, 0,
"l", VanillaBlockID.leaves, 0
]);

Здесь же, комбинация из бревна и двух блоков листвы позволяет получить нам росток. При этом явно указан паттерн, вертикальный ряд этих блоков — листва, листва и бревно. Как и в случае с бесформенным крафтом, методы практически идентичны друг другу.

Маска состоит из массива перечисления символьного ключа, идентификатора предмета и его меты. Символьным ключом может быть любой ASCII символ, то есть любой из латиницы, чувствительный к регистру (могут быть вместе ключи h и H, не конфликтуя с друг другом).

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

Дополним рецепт ростка выше, добавив чуть больше листвы для его создания:

Recipes.addShaped2(VanillaItemID.sapling, 1, 0, [" l ", "lll", " o "], [
"o", VanillaBlockID.log, 0,
"l", VanillaBlockID.leaves, 0
]);

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

Переплавка

Помимо крафтинга на верстаке, не менее значимой механикой остается переплавка. Кроме обычной печки, здесь используются коптильня и плавильная печь. В регистрации рецептов нет ничего сложного:

Recipes.addFurnace(VanillaItemID.rotten_flesh, 0, VanillaItemID.leather, 0);

Что переплавит гнилую плоть в кожу, как это реализовано в проекте Ender Craft. Вторым аргументом после каждого идентификатора идет мета, она может принимать любую вариацию (-1).

И не менее важным аспектом переплавки остается топливо. В его добавлении также нет ничего сложного:

Recipes.addFurnaceFuel(VanillaBlockID.magma, 0, 400);

Это добавит возможность использовать магму как топливо, она будет "гореть" 20 секунд (400 тиков). Что касается переплавки руд в плавильной печи и приготовления еды в коптильне, предметы или блоки должны быть определены в соответствующую категорию творческого инвентаря.

События и правки

Любые рецепты верстака (как с собственным, так и внутреигровым интерфейсом) обрабатываются несколькими калбеками, прежде чем крафт будет совершен. Это позволяет полноценно изменить рецепты, отследить их совершение или полностью отменить их.

Начнем с простого, крафт уже был совершен, и теперь приходит событие об этом. Калбек VanillaWorkbenchPostCraft создан специально для этого:

Callback.addCallback("VanillaWorkbenchPostCraft", function(result, container, playerUid, recipe) {
if (result.id == VanillaItemID.stick) {
new PlayerActor(playerUid).addExperience(5);
}
});

Он сообщает о любых крафтах в верстаке, с уже обработанным результатом. Однако, в большинстве случаев, нам нужно узнать о использовании добавленного рецепта. Для этих целей, существует дополнительный аргумент в методах крафтинга:

Recipes.addShapeless2(VanillaItemID.diamond, 1, 0, [
{ id: VanillaItemID.iron_ingot, data: 0 },
{ id: VanillaItemID.gold_ingot, data: 0 },
{ id: VanillaItemID.flint, data: 0 }
], function(action, slots, result, playerUid) {
for (let i = 0; i < action.getFieldSize(); i++) {
action.decreaseFieldSlot(i);
}
});
Recipes.addShaped2(VanillaItemID.sapling, 1, 0, [" l ", "lll", " o "], [
"o", VanillaBlockID.log, 0,
"l", VanillaBlockID.leaves, 0
], function(action, slots, result, playerUid) {
for (let i = 0; i < action.getFieldSize(); i++) {
action.decreaseFieldSlot(i);
}
});

Функции крафта позволяют изменить предпологаемый результат рецепта, обрабатывают удаление предметов из слотов верстака (при успешном крафте) и отменить крафт. В последнем случае, слоты верстака, вероятно, очищать не нужно, но противоположное тоже возможно.

Усложним условия — мы хотим чтобы крафт происходил не всегда, для создания рецепта необходим инструмент, которому необходимо потратить прочность, а с некоторым шансом предметы из рецепта будут потрачены, а результат не получен. Все эти условия реализуются с помощью этого события:

Recipes.addShaped2(VanillaItemID.sapling, 1, 0, [" l ", "lhl", " o "], [
"o", VanillaBlockID.log, 0,
"l", VanillaBlockID.leaves, 0,
"h", VanillaItemID.wooden_hoe, 0
], function(action, slots, result, playerUid) {
const chance = Math.random();
// изменяем стандатное поведение
for (let i = 0; i < action.getFieldSize(); i++) {
if (slots[i].getId() != VanillaItemID.wooden_hoe) {
action.decreaseFieldSlot(i);
} else {
// разрушаем мотыгу на несколько единиц
slots[i].set(slots[i].getId(), slots[i].getCount(), slots[i].getData() + 5, slots[i].getExtra());
}
}
// думаю, 5% неудачи здесь не критично
if (chance < 0.05) {
action.prevent();
// еще 2.5% на увеличение количества ростков
} else if (chance < 0.075) {
result.count++;
}
});

Условия достигнуты, мотыга разрушается, а крафт не всегда предоставляет результат. И небольшой шанс получения сразу двух ростков. Независимо от выбранного метода крафтинга, функция крафта в каждом из них одинакова и по аргументам, и по принципам реализации.

Список доступных методов можно получить в сводке, а помимо события в конце функции создания рецепта, крафт может быть изменен в другом калбеке:

Callback.addCallback("VanillaWorkbenchCraft", function(result, container, playerUid, recipe) {
if (result.id == VanillaItemID.stick) {
result.count *= 2;
}
});

Также как и с остальными калбеками крафта, это событие вызывается для любых рецептов в верстаке.

Для чего нужны префиксы

Если заглянуть в сводку методов, методы рецептов последним аргументом принимают некий prefix. Он создан в первую очередь для поиска рецептов, создания верстаков на основе внутреигрового и прочего. Любые рецепты с префиксом не будут отображены в обычном верстаке. Рассмотрите Recipes для получения подробностей.