Вор из ниоткуда#

Окно над улицей распахивается. Кто-то ругается с профессиональной беглостью, и помятое ведро с помоями падает на мостовую.

Мусор теперь — часть мира. Он может перекрыть проход, испачкать чьё-то пальто или дождаться человека, чья работа — его убрать. Но должен ли вместе с мусором появиться и тот, кто его выбросил? И если должен — сколько о нём нужно знать миру?

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

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

Когда событию нужен человек#

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

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

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

Существование персонажа в истории и его текущая активность — разные вещи. На площади может бурлить безымянная толпа. Кредитор из другой провинции, наоборот, останется определённым человеком, но будет лежать в хранилище до срока платежа. Чтобы тебя помнили, не обязательно думать на каждом такте.

Вор на ярмарке#

В v0.8.0 на ярмарке завёлся карманник. Между 09:00 и 18:00 игра ждала, пока на виду появится первый человек с кошельком, а затем создавала в толпе одного из четырёх незнакомцев: рябого парня в картузе, женщину в выцветшем платке, высокого мужчину в льняной рубахе или подростка в заплатанной рубахе.

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

Для русского понадобились все шесть падежей: не только «женщина в выцветшем платке», но и «женщину в выцветшем платке», «женщине в выцветшем платке» и остальные. Процедурный человек, который перестаёт склоняться сразу после обвинения, к общественной жизни пока не готов.

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

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

Вот как это выглядело в тестовой сессии v0.8.0:

09:00
На ярмарке женщина в выцветшем платке украла у помощника городового 1 рубль
Женщина в выцветшем платке находится на ярмарке

09:10
На ярмарке помощник городового задержал женщину в выцветшем платке
На ярмарке женщина в выцветшем платке вернула помощнику городового 1 рубль

09:20
Помощник городового перешёл от ярмарки к Колодезной площади
Женщина в выцветшем платке перешла от ярмарки к Колодезной площади

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

Почему вор остался#

Эксперименту требовался исход и для внимания, и для безразличия.

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

Если вора задержали или о нём успели рассказать, тот же человек оставался у лестницы на Дно. Именно оставался, не более. Он находился в мире, был видим и доступен для действий, но не строил планов, не наблюдал за окружающими и не разносил слухи. Мир сохранял человека, не назначая ему постоянно работающий разум.

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

Тест подтвердил ещё одно правило: материальные последствия живут дольше сцены. Человек может снова раствориться в населении, но украденный рубль, ушиб, долг или обвинение не должны растворяться вместе с ним.

Кто решает, кого запомнить#

В v0.8.0 всё решали несколько прямых правил. Это был тест, а не окончательная система.

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

Внутри этих границ ИИ может оценивать менее формальные вещи. Заинтересовались ли игроки этим человеком? Связывает ли он несколько незаконченных историй? Принесёт ли его возвращение новое последствие или только повторит старый трюк? Нужен ли району ещё один активный житель?

ИИ не получает права редактировать мир напрямую. Он может предложить структурированное изменение: оставить воровку спящим персонажем, связать её с уже существующим домом, пока не давать имени. Обычные правила проверят предложение. Принятое решение попадёт в ту же историю изменений, что и всё остальное; при повторном проигрывании модель не будет импровизировать заново.

Правила определяют, что мир обязан помнить. Местный мастер помогает решить, что стоит развивать дальше.

Чего тест не доказал#

Карманница так и не стала полноценной жительницей. Игра не дала ей имени, семьи, потребностей, привязанностей или второго происшествия, выросшего из первого. Сохранения и загрузки материализованного незнакомца ещё не было. Решение оставить его в мире сводилось к двум явным условиям, а не к работе местного мастера над историей города.

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

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

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

Это продолжение статьи «Когда день превратился в историю», где отдельные механики начали оставлять последствия друг для друга. Карманник поставил следующий вопрос: как долго миру хранить того, кто эти последствия создал?