Цепочка квестов¶
Сюжет идёт по порядку: пройди первый квест — откроется второй; пройди второй — откроется третий. Самый частый паттерн в любой РПГ.
В InkQuest это делается одним полем after в JSON зависимого квеста. Никаких хуков, никаких функций — система сама выдаёт следующий квест, как только предыдущий завершится успехом.
Зачем нужен этот паттерн¶
- Линейный сюжет. Глава первая → глава вторая → глава третья. Игрок не может пропустить шаг.
- Контроль доступа к контенту. Сложный квест откроется только тем, кто прошёл подготовку.
- Автоматическая выдача. Не нужно слежение командными блоками — система сама подхватит момент завершения и выдаст следующий квест.
Шаг 1. Создаём первый квест¶
Положи data/story/quests/ch1_arrival.json:
{
"version": 3,
"variant": 0,
"title": "Прибытие в город",
"description": "Долгая дорога позади. У ворот ждёт начальник стражи.",
"tasks": {
"talk_to_captain": {
"title": "Поговорить с капитаном",
"condition": {
"success": { "type": "predicate", "predicate": "story:talked_to_captain" }
}
}
},
"stages": [["talk_to_captain"]]
}
Это обычный квест с одной задачей. Ничего особенного.
data/story/predicates/talked_to_captain.json — предикат, который сработает, когда NPC «капитан» поставит флаг разговора:
{
"condition": "minecraft:entity_scores",
"entity": "this",
"scores": {
"story.captain_spoken": { "min": 1 }
}
}
Сам флаг ставит командный блок у NPC: scoreboard players set @p story.captain_spoken 1. Перед первым использованием не забудь завести objective: scoreboard objectives add story.captain_spoken dummy.
Шаг 2. Создаём зависимый квест¶
Положи data/story/quests/ch1_first_task.json. Главное — поле after:
{
"version": 3,
"variant": 0,
"title": "Первое поручение",
"description": "Капитан просит проверить заброшенный пост у леса.",
"after": [["story:ch1_arrival"]],
"tasks": {
"visit_outpost": {
"title": "Дойти до поста"
}
},
"stages": [["visit_outpost"]]
}
Поле after — это список групп. В простейшем случае одна группа с одним квестом: «выдай этот квест, когда story:ch1_arrival завершён успехом».
Шаг 3. Выдаём только первый квест¶
В стартовой функции мира (#minecraft:load или функция при первом входе игрока):
Второй квест выдавать не нужно. InkQuest сам выдаст его, как только игрок успешно завершит первый.
Проверка¶
- Выдай себе первый квест — он появился в книге?
- Выполни его (
/quest complete @s story:ch1_arrival task talk_to_captain success) — второй квест появился в книге сам? ✅ - Если второй не появился — проверь, что:
- Имя в
afterсовпадает с ID файла (story:ch1_arrival, а неstory/ch1_arrival). - Первый квест завершился со статусом
success(неfailure— см. ниже про статусы).
Как именно работают зависимости¶
after — это список групп, и каждая группа — список квестов:
Читается как «AND внутри группы, OR между группами»:
[["a", "b"]]— выдать, если завершены И A, И B.[["a"], ["b"]]— выдать, если завершён A ИЛИ B.[["a", "b"], ["c"]]— выдать, если завершены (A И B), ИЛИ просто C.
В цепочке обычно достаточно простого [["предыдущий_квест"]].
Какой статус «считается»¶
after срабатывает только когда зависимость завершилась успехом (success). Провал или пропуск не открывают зависимый квест. Если хочешь, чтобы цепочка шла и через провалы — оформи их отдельной веткой (Развилка и память выбора).
Расширения¶
Ветвление: один квест → две ветки¶
Если из одного квеста должны открыться два разных дальнейших — заведи две зависимости с одинаковым after, и обе откроются одновременно. В файле data/story/quests/quest_a.json:
И то же самое в data/story/quests/quest_b.json:
После завершения ch1_arrival игроку выдадутся оба quest_a и quest_b. Он сможет проходить их параллельно или в любом порядке.
Слияние: два квеста → один общий¶
Финальный квест требует, чтобы оба «рукава» цепочки сошлись:
Откроется, только когда оба будут пройдены — типичный финал главы после параллельных подсюжетов.
Условное ветвление по выбору игрока¶
Если цепочка должна разойтись в зависимости от выбора в предыдущем квесте — комбинируй after с require.tags:
Откроется только тем, у кого после ch1_arrival появился тег story.chose_dark_path. Подробно — в Развилка и память выбора.
Пауза перед следующим квестом¶
Если следующий квест должен открыться не сразу, а после события (наступит ночь, игрок дойдёт до места) — добавь в первый квест задачу-ждун. См. Ожидание события.
Условие за пределами квестов¶
require.predicate позволяет добавить нативный Minecraft-predicate к условию разблокировки. Например, «открыть квест, только если игрок в Незере»:
data/story/predicates/in_nether.json:
{
"condition": "minecraft:entity_properties",
"entity": "this",
"predicate": {
"location": {
"dimension": "minecraft:the_nether"
}
}
}
⚠️ Помни: require проверяется в момент завершения зависимости — то есть прямо в тот тик, когда первый квест завершился. Если предикат сработает позже — квест не откроется автоматически. Подробнее — в Развилка и память выбора, раздел «Важный момент про момент проверки».
Подводные камни¶
afterне блокирует команду/quest give. Оператор всегда может выдать зависимый квест вручную, обойдя зависимости. Это нужное поведение: для дебага и QA.- Завершённый квест не «разблокирует» цепочку задним числом. Если ты добавил
after: [["A"]]к новому квесту, а игрок уже давно завершил A — зависимый квест выдастся при следующемquest reloadили сразу при загрузке (потому что система проверит условия после релоада датапаков). Но если новый квест уже был выдан, а в файле появилось новоеafterк ещё-не-завершённому квесту — нужна повторная выдача. - Цепочки могут зацикливаться.
Aзависит отB,Bзависит отA— оба никогда не откроются. Это твоя ответственность; система не валидирует циклы.
См. также¶
- Зависимости между квестами — полная документация по
afterиrequire - Ожидание события — если между квестами нужна пауза
- Развилка и память выбора — если цепочка должна ветвиться по выбору игрока
- Хуки жизненного цикла задачи — если нужно что-то сделать в момент перехода между квестами (выдать предмет, проиграть звук)