Создание сюжетных сценариев Game Mode
Сюжетный сценарий направляет развитие игры Game Mode: сцены, которые разыгрываются, когда отряд куда-то прибывает; поручения Game Master (ведущему игры на базе ИИ), которые он получает, когда выполнено условие; цели, за которыми игрок следит в журнале приключений; и моменты, которые Game Master может отметить сам. Напишите его, если создаете миры для других. Чтобы играть в мире, у которого есть сюжет, см. раздел Создание мира.
Сюжетный сценарий – это данные, а не код. Ничего из него не выполняется. Engine проверяет его по миру, для которого он написан, разыгрывает ход за ходом и отклоняет все, что не подходит.
Перед началом вам понадобится мир, к которому вы привяжете сюжет, и идентификаторы его мест и людей. Сюжет сохраняется через API игры, поэтому вы должны уметь отправлять JSON-запрос; см. Как опробовать сюжет.
Где хранится сюжет
Сюжет принадлежит одному миру. Он называет места и людей этого мира, поэтому имеет смысл только вместе с миром, для которого написан (с его зерном, описанием и ручными правками).
- В файле мира (
.world.json) – как ключ верхнего уровняstoryрядом сworld. Engine, который не знает о сюжетах, все равно прочитает мир. - В наборе карт Experience: каждый файл мира может нести свой сюжет, и новая игра получает его вместе с картой. См. Дополнительные пакеты агентов и возможностей.
- В мире, который хранится в библиотеке вне какой-либо игры:
GET,PUTиDELETE /api/game-worlds/:id/story, так же как у игры. Новая игра, начатая с этого мира, забирает сюжет с собой. - В игре, после ее начала:
GET,PUTиDELETE /api/game/:chatId/storyчитают, сохраняют и удаляют сюжет. Сохранение проверяется по миру игры с учетом ручных правок, а ручные правки, которые убрали бы что-то названное в сюжете, отклоняются.
При настройке новой игры сюжет, прочитанный из файла или набора карт, сохраняется, пока зерно и описание мира остаются прежними.
Структура
{
"storyVersion": 1,
"flags": [],
"directions": [],
"events": [],
"cutscenes": [],
"fights": [],
"endings": [],
"knowledge": []
}Минимальный рабочий сюжет состоит из одного флага и одного события. Этот сюжет сообщает Game Master кое-что в первом ответе игры:
{
"storyVersion": 1,
"flags": [{ "id": "met_guide", "kind": "bool", "initial": false }],
"events": [
{
"id": "welcome",
"when": { "on": "start" },
"do": [{ "tell": "Open with a guide waiting at the gate." }, { "set": "met_guide", "value": true }]
}
]
}Идентификатор – это от 1 до 40 строчных латинских букв, цифр, _ или -; он уникален в пределах своего списка. Сюжет содержит не более 256 флагов, 64 указаний, 256 событий, 64 заставок, 32 боев, 16 концовок и 600 записей знаний. Ни один текст в нем не может содержать перенос строки, квадратные скобки или {{, а имена, вписанные в тег (группа, фон), не могут содержать двойную кавычку: ничто сказанное сюжетом не должно сойти за тег Game Master.
Флаги
Флаг – это значение, которое хранит сюжет: "bool" (истина или ложь) или "number" (число).
{ "id": "trust", "kind": "number", "initial": 0, "gm": true, "note": "How far the town trusts the party" }gm: trueпозволяет Game Master задавать флаг (см. Теги Game Master);noteобъясняет ему, что флаг означает.- Флаги скрыты от игрока. С
questфлаг становится целью квеста в журнале приключений:
{
"id": "favours",
"kind": "number",
"initial": 0,
"quest": { "title": "Favours", "text": "Do the town three favours", "goal": 3 }
}Числовой флаг может иметь min и max: каждое действие set и add, включая теги самого Game Master, удерживает его в этих пределах. Так оценка одобрения остается между -10 и 10, сколько бы событий ни прибавляли к ней. Его initial должно быть в этих пределах.
{ "id": "approval", "kind": "number", "initial": 0, "min": -10, "max": 10, "gm": true }Цель с логическим флагом выполнена, когда флаг истинен; числовая – когда флаг достигает своего goal (1, если не указано), а если goal записан явно, журнал показывает прогресс. Цель с "hidden": true не видна в журнале, пока ее не покажет событие.
Часы
Числовой флаг может быть часами, за заполнением которых следит игрок: кругом из 2–12 сегментов, по одному заполненному на каждое очко. Они показываются на панели HUD игры и вкладке World с заголовком и описанием того, что произойдет при заполнении.
{
"id": "reeve",
"kind": "number",
"initial": 0,
"gm": true,
"clock": { "title": "The Reeve's patience", "segments": 6, "full": "The Reeve sends his men." }
}Задавайте значение, прибавляйте к нему и проверяйте в условиях, как любой числовой флаг. Game Master сообщают о часах каждый ход, а когда часы заполняются – один раз о том, что должно произойти (при заполнении событием или, для его собственного тега, на следующем ходу). Часы с "hidden": true скрыты, пока событие не покажет их через show.
Указания
Указание – это постоянная инструкция для Game Master, которая действует, пока выполняются ее условия:
{ "id": "wary", "text": "The town is wary of strangers.", "if": [{ "flag": "trust", "is": "<", "value": 2 }] }Условия
{ "flag": "<id>", "is": "=" | "!=" | ">" | ">=" | "<" | "<=", "value": <value> }. Должны выполняться все условия списка if. Логический флаг сравнивается только через = или !=.
{ "party": "<person id>", "is": "in" | "out" } проверяет, путешествует ли сейчас с отрядом человек из мира, например спутник, которого завербовал сюжет.
{ "partySize": { "is": "=" | "!=" | ">" | ">=" | "<" | "<=", "value": <1 to 32> } } проверяет численность отряда: персонаж игрока и все путешествующие с ним спутники, кроме тех, кто никогда не сражается. Условие выполняется только тогда, когда Engine знает численность отряда.
{ "any": [<condition>, <condition>, ...] } выполняется, когда выполняется любое из его 2–8 условий: выбор "или" в одном списке вместо двух событий.
"if": [{ "any": [{ "flag": "won_granary", "is": "=", "value": true }, { "party": "p11-3", "is": "in" }] }]Знания
То, что люди знают и говорят о себе, друг о друге и о мире, меняется с развитием сюжета. Каждая запись передается Game Master как то, что этот человек может сказать, если зайдет речь, на ходу, когда:
- выполняются ее условия;
- ее
personнаходится в сцене: назван в последнем ответе или сообщении игрока либо путешествует с отрядом; - и, если есть
keys, там же встречается один из этих ключей. Записи без человека нужны ключи, и она поступает только по ним.
За ход передается не более 12 записей. Они ранжируются: сначала люди, названные в сцене, затем записи без человека, вызванные ее словами, затем спутники, которые просто путешествуют вместе. Внутри каждой категории записи распределяются по людям, чтобы один разговорчивый спутник не вытеснял остальных. За путешествующими спутниками всегда остаются две из 12 записей, как бы ни была заполнена сцена; они распределяются так же.
"knowledge": [
{ "id": "hob-self", "person": "p3-4", "text": "Hob was a miller's boy before the year stopped." },
{ "id": "hob-mill", "person": "p3-4", "if": [{ "flag": "act", "is": ">=", "value": 2 }],
"text": "Since the second act, Hob is afraid of the mill." },
{ "id": "hob-bells", "person": "p3-4", "keys": ["bells"], "text": "Hob thinks the bells are a lie." },
{ "id": "wheel", "keys": ["mill", "millwheel"], "text": "The mill's wheel has not turned in a hundred autumns." }
]В сценарии может быть до 600 записей. За ход передается не более 12 в порядке сценария, поэтому ставьте самые важные первыми.
События
Событие – это то, что происходит: когда срабатывает его триггер и выполняются его условия, оно выполняет свои действия.
{
"id": "gates",
"when": { "on": "arrive", "place": "p11" },
"if": [{ "flag": "banished", "is": "=", "value": false }],
"do": [{ "cutscene": "gates" }, { "set": "arrived", "value": true }, { "show": "key" }]
}Событие происходит один раз, если у него нет "repeat": true (start, turn и day это игнорируют). За один ход происходит не более 32 событий, каждое не более одного раза, в том порядке, в котором их перечисляет сценарий.
Триггеры (when.on); все они читаются из того, что записала игра:
| Триггер | Срабатывает |
start | На первом ответе игры. |
turn | На ответе Game Master с номером turn за всю игру, с учетом всех сессий, или позже. |
day | Когда день мира (его сдвигают течение времени, о котором говорит Game Master, и переходы) становится равен day или больше. |
arrive | Пока отряд находится в place (идентификатор места) или в месте внутри него, попав туда при старте игры, переходом по общей карте мира, посещением в городе или потому, что это место назвал Game Master. С repeat – снова при каждом возвращении откуда-то еще. |
meet | Когда ответ назвал person (идентификатор человека, например p11-3, или p11-e1 для добавленного вручную) полным именем. С repeat – снова для каждого ответа, где он назван. Имена ищутся только в ответах текущей сессии. |
deed | Когда мир записал поступок отряда вида deed и, если указано, в месте place. С repeat – снова для каждого ответа, который записывает такой поступок. |
fight | Когда бой заканчивается результатом outcome: victory, defeat или flee. С fight (одним из боев сценария) – только когда так завершился именно этот бой: начатый последним ответом Game Master через действие сюжета fight или его собственный запуск. |
leave | Когда отряд покидает place (идентификатор места) и все места внутри него: переходом, посещением, местом, названным Game Master, или действием сюжета move, в последнем ответе или на этом ходу. С repeat – снова при каждом уходе. |
broke | Когда бой разрушил предмет обстановки с именем prop; регистр не учитывается. Назвать можно только предмет, нарисованный на одном из полей боя мира. |
flags | Когда выполняются его условия. С repeat – снова каждый раз, когда они становятся истинными после того, как были ложными. |
gm | Только когда его запускает Game Master (событию нужно "gm": true). |
rest | После ответа, в котором отряд отдыхал: принятого ответом Game Master тега [sheet: op="rest"], для отдыха набора правил, названного в rest (его идентификатор или название, например long), либо любого отдыха. |
travel | На ходу, когда отряд отправляется из одного места в другое, изнутри from и внутрь to, если они указаны. |
idle | После turns ответов подряд, в которых ничего не происходит: нет событий сюжета, переходов и боев. |
step | Когда переход проходит по клетке x, y (отсчет с 0 от левого верхнего угла) в place: по городу поселения (путь посещения, от двери до двери) или по карте места, созданной вручную (переход по ней). На клетку должен иметь возможность ступить отряд: в городе – земля, до которой можно дойти от площади, но не свободный участок, где сюжет может строить; на карте – пол, до которого можно дойти от входа. У сгенерированной карты нет клеток, которые можно назвать. С repeat – снова в каждый ход, переход которого проходит по ней. |
Ручные правки, которые отнимают клетку у события шага (на нее поставлено здание, пол карты обнесен стеной), отклоняются при сохранении, и в сообщении называется это событие.
Повторяющееся событие meet, чья собственная сцена называет этого человека, или повторяющееся событие deed, которое само совершает ожидаемый поступок, запускало бы себя каждый ход, поэтому Engine его отклоняет.
Действия (do):
| Действие | Что делает |
{ "set": "<flag>", "value": <value> } | Задает флаг. |
{ "add": "<flag>", "amount": <number> } | Прибавляет к числовому флагу. |
{ "tell": "<text>" } | Просит Game Master о чем-то один раз, на этом ходу. |
{ "cutscene": "<id>" } | Показывает заставку. |
{ "show": "<flag>" } | Показывает скрытую цель квеста в журнале. |
{ "world": { "deed": "<kind>", "group": "...", "with": "...", "place": "<place id>", "who": "..." } } | Записывает поступок в мир; он обрабатывается так же, как поступок, записанный самим Game Master. |
{ "give": { "item": "<catalog/entry or a name>", "count": 1, "who": "...", "summary": "..." } } | Выдает предмет: один из предметов набора правил игры по его идентификатору или любой другой по имени (с описанием в summary), в сумку игрока или участнику отряда, названному в who. Он добавляется так же, как от самого Game Master, с соблюдением правил инвентаря. Идентификатор, которого нет в наборе правил игры, отклоняется с причиной в ответе. |
{ "fight": "<fight id>" } | Начинает один из боев сценария. Game Master просят подвести к нему, а следующий бой получает противников сюжета. |
{ "move": "<place id>" } | Помещает отряд в место мира, как переход; вызванное этим событие arrive происходит на том же ходу. |
{ "ending": "<ending id>" } | Завершает игру одной из концовок сценария: разыгрывается ее сцена, Game Master завершает повествование эпилогом, а игрок видит концовку и предложение завершить сессию. После этого в сюжете ничего не происходит. |
{ "music": "<track id>" } или { "music": null } | Включает один из треков Experience вместо музыки места до следующей команды; null возвращает музыку места. Трек должен входить в music набора карт. |
{ "recruit": "<person id>" } | Принимает в отряд одного из спутников Experience с его листом для набора правил игры. Game Master просят показать его присоединение. |
{ "dismiss": "<person id>" } | Отпускает спутника из отряда. |
{ "season": { "place": "<place id>", "to": "winter" } } | Удерживает место и все места внутри него в сезоне независимо от даты; без place – весь мир. "to": null возвращает сезон к собственным seasons сценария или к календарному. |
{ "sheet": { "condition": "<id>", "state": "on" } или { "sheet": { "track": "<id>", "by": 1, "upTo": 3 } } | Накладывает состояние листа на каждого участника отряда или снимает его ("off"), либо сдвигает шкалу каждого листа до предела upTo: холод Rime Edge, который не исцеляет никакой отдых, через состояние, чье боевое состояние содержит cannot-heal-nonmagical. Собственный запуск Engine применяет действие вместе с записываемым ответом, а запуск Game Master – на ходу после его отметки. |
Любое действие может иметь собственное if: оно выполняется, только если условия соблюдены, когда событие до него доходит, уже выполнив предыдущие действия. Так одно событие может разветвляться.
"do": [
{ "add": "approval", "amount": 2 },
{ "tell": "Hob warms to the party.", "if": [{ "flag": "approval", "is": ">=", "value": 5 }] },
{ "tell": "Hob keeps his distance.", "if": [{ "flag": "approval", "is": "<", "value": 5 }] }
]Выполненные действия записываются вместе с запуском, поэтому сцены и поручения события gm приходят на следующем ходу в том виде, в котором были выполнены, когда Game Master отметил его.
Спутник – это человек из файла людей набора, помеченный как спутник (см. людей набора карт в разделе Дополнительные пакеты агентов и возможностей).
Из событий rest, travel и idle, которые могли бы произойти на одном ходу, происходит только одно: с наибольшим priority (целое число от -100 до 100, по умолчанию 0; при равенстве – первое в сценарии). Так разговор спутника у костра, ссора двух спутников в дороге или приход спутника к игроку в тихий час не накладываются друг на друга. С условием party такая сцена происходит, только пока эти спутники путешествуют с отрядом.
Воздействия
То, как нахождение в месте влияет на отряд со временем, например поле полуденного света, изматывающее путников вне боя так же, как правило света поля боя – в бою:
"exposures": [
{ "id": "noonfield", "place": "e9", "label": "Noonfield's light", "hours": 1,
"tracks": [{ "track": "exhaustion", "by": 1 }], "applies": ["sunstruck"],
"if": [{ "flag": "darkness_carried", "is": "=", "value": false }],
"tell": "The light presses on them; darkness would be a mercy." }
]По игровым часам: первый ход, на котором отряд находится в place (или внутри него) и выполняется if, запускает воздействие. Каждый последующий ход подсчитывает, сколько интервалов hours прошло там с тех пор. Каждый раз Engine сдвигает tracks на by и накладывает состояния applies на каждого участника отряда, применяя собственные команды листа вместе с командами ответа, и сообщает Game Master через tell. Уход из места или невыполнение if прекращает воздействие; в следующий раз оно начинается заново. Оно записывается в ответ ([story: exposure="<id>" ...]) один раз.
У шкалы может быть предел: { "track": "exhaustion", "by": 1, "upTo": 3 } никогда не поднимает ее выше 3 и не сдвигает ту, что уже выше. Воздействие может требовать спасбросок, а не затрагивать всех, в том же формате, что и save правила света поля боя:
"save": { "save": "con_save", "difficulty": 12, "against": { "conditions": ["noon_light"] } }При каждом срабатывании Engine делает этот спасбросок для каждого участника отряда по его листу. Только провалившие получают изменения шкал и состояния, каждый со своей командой листа. against задает, против чего делается спасбросок, поэтому ограниченный им модификатор действует вне боя так же, как в бою: соломенная шляпа из наложения с { "to": "saves", "mode": "advantage", "against": { "conditions": ["noon_light"] } } дает владельцу преимущество. Game Master сообщают, кто преуспел и кто провалил спасбросок, с итоговыми значениями.
С "sparedByShade": true включенный источник тени у любого участника отряда предотвращает воздействие, как невыполненное if: предмет с "shade": true в носимом или переносимом light (Lantern of Dusk из демонстрационного примера), а предмет с переключателем – только пока он включен. Включение прекращает воздействие; выключение запускает его заново.
Земля, удерживающая смерть
Место, где сдерживается смерть, как долина в демонстрационном примере:
"heldGround": [
{ "id": "valley", "place": "p0", "label": "The Held Autumn", "condition": "felled",
"marks": [{ "track": "owing", "by": 1 }],
"if": [{ "flag": "year_turned", "is": "=", "value": false }],
"tell": "Nobody here has died in forty years." }
]Пока отряд в place (или внутри него; без места – во всем мире) и выполняется if, начатый там бой по набору правил идет на Held Ground: тот, у кого не осталось здоровья, вместо этого становится сраженным, выбывает из боя, стабилен, не умирает и позже встает, если его не сразило нечто, что пожинает. На сраженных накладывается condition, и у каждого сраженного персонажа сдвигаются шкалы marks (отметка Owing). Действует первая подходящая запись. Сюжет записывает вход отряда на эту землю и уход с нее ([story: held="<id>" ...]; уход записывается с пустым идентификатором), каждый раз сообщая Game Master через tell; каждый ход, пока она действует, Game Master напоминают, что это означает.
Held Ground может отпустить: как при смене года в демонстрационном примере. Ее release задает, что тогда наступает:
"release": { "felled": "die", "owing": { "track": "owing", "bonus": { "flag": "hymn_bonus" } } }felled задает судьбу лежащих сраженными: они умирают ("die", по умолчанию) или падают и начинают умирать по собственному правилу набора ("down"). owing заставляет каждого участника отряда делать один спасбросок от смерти набора правил за каждую метку на track (если не указано, на первой отмечаемой шкале Held Ground), добавляя bonus к каждому (число или числовой флаг, прочитанный при освобождении), пока не закончатся метки или не определится исход; метки расходуются, а три провала означают смерть. В продолжающемся на этой земле бою по набору правил освобождение происходит в том шаге, который его вызвал: использование предмета, расходующее число сюжета, прочитанное его if, или разрушение предмета обстановки, на которое реагирует событие broke, и вызванные ими события флагов. Судьба сраженных и Owing решается в этом раунде собственным освобождением боя. Вне боя ход сюжета, записавший освобождение, разыгрывает Owing каждого участника по его листу и сообщает Game Master, кто выжил и кто умер; незавершенный бой на этой земле освобождается на следующем шаге. То, что уже разыграл бой, повторно не разыгрывается.
Сезоны
Сезоны мира следуют календарю, по 90 дней каждый. Сюжет может удерживать места в сезоне независимо от даты: долину в вечной осени, холм в зиме.
"seasons": [{ "place": "p3", "season": "autumn" }, { "season": "summer" }]Каждая запись удерживает место и все места внутри него; без place – весь мир. Решает ближайшее удерживаемое место: деревня в зиме внутри осеннего региона остается зимней. Действие season меняет или снимает удержание во время игры. Исключение – удержание с over над всем внутри: оно перекрывает любой сезон там, собственный сезон сценария и все другие удержания (сначала самое внешнее такое удержание), поэтому { "season": { "to": "spring", "over": true } } меняет весь мир сразу. Там, где сезон отряда удерживается, Game Master сообщают сезон и факт удержания; погода создается под него; общая карта мира рисует каждую клетку в сезоне ближайшего места (тайлы <id>@<season> набора), а город – в своем.
На нарисованном вручную поле боя мира тоже можно нарисовать сезоны: строка seasons на каждую строку тайлов, буква или . на тайл, с обозначением букв в seasonKeys ({ "a": "autumn", "w": "winter" }). Тайл с . получает сезон места боя. Тайлы начинают бой в этих сезонах, а события карты раунда могут их менять, например распространяющимся кольцом мороза или проходящей полосой весны.
Бои
Бой, который задает сюжет: с кем сражаться и где, если в мире для него нарисовано поле.
{
"id": "granary",
"name": "The Granary",
"creatures": [
{ "creature": "creatures/scarecrow", "count": 3 },
{ "creature": "The Owed", "name": "The Owed" }
],
"battlefield": "b2",
"note": "The jars break when hit."
}Каждое существо – из бестиария набора правил игры, по идентификатору (catalog/entry) или имени, в количестве count (с номерами, если их несколько), с именем name в бою, если оно задано. battlefield – нарисованное вручную поле мира (b<n>), на котором идет бой независимо от места начала; без него бой идет там, где начался, как любой другой. note сообщает Game Master, как он возникает. Идентификатор, которого нет в наборе правил игры, отклоняется: такие существа исключаются из боя, а отказ записывается в журнал. Бой без оставшихся существ все равно начинается так, как задал сюжет, на его поле, но противников выбирает Game Master.
Бой можно задать для отрядов другой численности. Отряд – это персонаж игрока и все путешествующие с ним спутники, кроме спутника с отметкой noncombatant.
"variants": [
{ "party": { "min": 3, "max": 4 }, "creatures": [{ "creature": "creatures/scarecrow", "count": 4 }] },
{ "party": 5, "creatures": [{ "creature": "creatures/scarecrow", "count": 5 }], "battlefield": "b3",
"note": "The Owed wakes in the loft." }
]Используется вариант, чей party охватывает численность отряда, с его существами и собственными battlefield и note, если они заданы (иначе – значениями боя). Если ни один вариант не подходит, используется исходный бой. Два варианта не могут охватывать одну численность.
Запись существа в бою или варианте может менять его через adjust для этого боя, чтобы босс масштабировался с отрядом без отдельного существа: "adjust": { "legendaryResistance": 2, "maxHp": 40 } дает ему такую Legendary Resistance (0 убирает ее) и такое здоровье (фиксированное число вместо значения блока, включая кубики). Game Master сообщают это рядом с существом. calls в настройке меняет тех, кого призывают действия существа: [{ "action": "shelves_lean", "creature": "creatures/wraith" }], по идентификатору или имени действия, для призывающего действия. levels меняет любое из этих значений начиная с уровня отряда, каждое поверх предыдущего: "levels": [{ "from": 8, "calls": [{ "action": "shelves_lean", "creature": "creatures/wraith" }] }]. Уровень отряда – наивысший достигнутый любым его участником, прочитанный из полей уровня, которые листы спутников Experience называют для набора правил игры; без такого поля levels не читается. party задает численность до 32; диапазон без max ({ "min": 7 }, Capability API 1.360) охватывает любой отряд от min, без верхней границы. Game Master сообщают, на какую численность рассчитан бой, в начале и снова после его сводки.
Концовки
{ "id": "kept", "title": "The Year Kept", "cutscene": "bells", "epilogue": "The valley stays held." }cutscene – одна из сцен сценария, разыгрываемая в начале концовки; epilogue – то, чем Game Master завершает игру и что читает игрок при показе концовки.
Заставки
Заставка либо показывается игроку точно так, как написана, либо передается Game Master, чтобы он ее рассказал.
{
"id": "gates",
"kind": "pages",
"background": "backgrounds:generated:town-gates",
"pages": [
{ "text": "The gates creak open." },
{ "speaker": "p11-3", "expression": "happy", "text": "Welcome, travellers." },
{ "speaker": "player", "text": "We come in peace." }
]
}Заставка pages разыгрывается перед ответом Game Master, в повествовании, по одной странице: страница без говорящего – это повествование, страница с говорящим – реплика этого человека под его именем в мире (или под именем игрока для player), с выражением expression из собственного списка Game Master. background – это фон, который есть в игре, или backgrounds:generated:<words>, чтобы фон был создан, когда включена генерация изображений. Game Master сообщают, что сцена показана, и он продолжает с нее.
Страница может иметь if: она показывается, только пока ее условия выполняются при воспроизведении сцены. Так сцена у костра может давать каждому спутнику реплику, только пока он путешествует с отрядом.
{ "speaker": "p11-3", "text": "Another night.", "if": [{ "party": "p11-3", "is": "in" }] }Сцена, у которой скрыты все страницы, ничего не показывает.
{ "id": "dusk", "kind": "beats", "beats": ["Lamps are lit.", "A bell tolls."] }Заставку beats Game Master рассказывает своими словами на этом же ходу, бит за битом (бит – короткое описание того, что происходит). Биты события gm сообщаются Game Master вместе с событием, и он рассказывает их в ответе, который отмечает этот момент. Поэтому сцена из битов, которую использует событие gm, известна Game Master с самого начала, даже если ее разыгрывает и событие Engine. Поскольку биты сообщаются ему на каждом ходу, биты всех событий gm вместе ограничены 16 000 символов.
Вступительное сообщение
intro задает начало игры – тот же выбор, который настройка GM предлагает любой игре:
"intro": { "mode": "defined", "text": "The leaves have not fallen in Hollowmere for nine years.", "locked": true }"defined" делает первое сообщение игры точно равным text: Game Master ничего для него не пишет, а повторная генерация дает тот же текст. "guided" лишь направляет начало, которое пишет Game Master: это указание он читает только для первого ответа. text занимает от 1 до 8000 символов и может содержать переносы строк (единственный текст сюжета, которому это разрешено), но никогда {{; в направляющем тексте нельзя использовать и квадратные скобки. С locked игрок видит вступление в настройке GM и не может его изменить; без него вступление лишь заполняет поле настройки, и игрок может изменить или очистить его. У игры, первый ответ которой уже написан или которая переносит свой отряд из прежней игры, вступления нет. Experience также может задать вступление рядом с другими значениями настройки GM (contributions.gameSurface.setup.defaults.intro); оно читается первым.
Как разыгрывается сюжет
Один раз за ход, перед ответом Game Master, Engine читает, что сюжет уже сделал и что приносит этот ход (переход, посещение, конец боя), и запускает события. Все произошедшее записывается в начало этого ответа: тег для каждого события и того, что оно задало, и каждая сцена, показанная как написано. Поскольку сюжет восстанавливается из ответов, свайп или повторная генерация отменяют то, что сделал их ответ, а сюжет, измененный посреди игры, никогда не переписывает уже произошедшее. Сюжет переходит в следующую сессию игры.
Теги Game Master
Каждый ход Game Master получает значения сюжета (скрытые от игрока) и действующие указания. Из остального сценария ему сообщается только то, что сценарий отдает ему самому: события gm (с их note и битами beats, которые нужно рассказать вместе с ними) и флаги gm, а также какие из этих событий он сейчас не может отметить (уже выполнены или сдерживаются условиями). Он отмечает их в своем ответе:
[story: event="<id>"]запускает событиеgm, условия которого выполняются (один раз, если оно не повторяется).[story: flag="<id>" value="<value>"]илиadd="<number>"для числового флага задает флагgm.
Подарки, бой и перемещение события gm попадают в ответ вместе с его тегом; сцена концовки и эпилог приходят в начале следующего ответа.
Engine отвечает на каждый тег на месте, на событие – не более одного раза за ход, а все остальное отклоняет с указанием причины. В игре без сюжета отклоняется любой тег сюжета. То, что запускает Game Master, действует сразу (его флаги, его поступки); его сцены и поручения приходят в начале следующего ответа, кроме beats (их Game Master просили рассказать вместе с моментом). Пишите pages события gm как то, что следует за моментом, ведь сам момент Game Master уже рассказал.
Как опробовать сюжет
- Начните игру в мире, для которого написан сюжет.
- Отправьте сюжет через
PUT /api/game/:chatId/storyс телом{ "story": { ... } }. Неподходящий сюжет отклоняется со всеми причинами. - Сыграйте ход. Вкладка World игры показывает цели и часы, которые открыл сюжет, а промпт Game Master каждый ход содержит значения и указания сюжета.
Используйте GET по тому же адресу, чтобы прочитать сохраненный сюжет, и DELETE, чтобы удалить его.
Возможности по версиям Capability API
Каждой возможности сюжета нужна определенная минимальная версия Capability API.
- событию
brokeнужна 1.316; introнужна 1.339, а полюcontributions.gameSurface.setup.defaults.introв Experience – 1.372;- часам нужна 1.342;
- боям, концовкам и действиям
give,fight,moveиendingнужна 1.343; - командам музыки нужна 1.345;
- вербовке и отпусканию спутников нужна 1.347;
- знаниям нужна 1.348;
- событиям
rest,travelиidle, полюpriority, условиюpartyили более чем 128 событиям нужна 1.349 (предел – 256); seasonsи действиюseasonнужна 1.351;- более чем 64 флагам нужна 1.353 (предел – 256);
variantsбоев нужна 1.356;- условиям
any, событиюfight, называющему свой бой, событиюleave, полям флагаminиmaxи полюifдействия или страницы нужна 1.358; - набору карт, в наложении набора правил которого есть запись
storyUses(использование предмета, расходующее число сюжета, которое может прочитатьifземли, удерживающей смерть), нужна 1.359; см. предметы, расходующие число сюжета; - условию
partySize, варианту для отряда больше 6 участников или без верхней границы либо более чем 6 вариантам нужна 1.360; - спутнику с
noncombatant, которого не учитывают в численности отряда, нужна 1.360; - действию
seasonсoverнад всем внутри нужна 1.361; - ранжированию записей знаний, передаваемых каждый ход (сначала люди, названные в сцене), нужна 1.361;
exposuresнужна 1.362;- существам боя с
adjustнужна 1.363; saveвоздействия илиupToшкалы нужна 1.364;sparedByShadeвоздействия нужна 1.365;heldGroundнужна 1.366;- действию
sheetнужна 1.368; releaseземли, удерживающей смерть, нужна 1.369;- выдаче списка альтернатив нужна 1.370. Начиная с 1.370 одиночный идентификатор записи без каталога ищется в том каталоге, где он есть, а более старый Engine читает его как имя;
- существам боя с
adjustдляcallsилиlevelsнужна 1.371.