Играем в кости с Дейви Джонсом

2ofdsp5psctpp3hnxwj_nptn_ws.pngВ этот раз, поговорим о текстовых квестах. В далёких 2000-ых годах, легендой российского геймдева стала (и надолго осталась впоследствии) выдающаяся во многих отношениях игра — «Космические рейнджеры». В немалой степени, своим оглушительным успехом она была обязана текстовым квестам, очень атмосферным и разнообразным. Квесты с самого начала жили своей жизнью, а затем, благодаря Василию Рогину, появился Web-плейер с удобным графическим редактором, во многом подстегнувший процесс кустарного изготовления собственных квестов. Правда само программирование на нём традиционно очень далёко от «нормального». Окунёмся же в этот безумный мир, попутно разработав что-нибудь нетривиально-увлекательное…
Вот как всё это выглядит:

hp98kjzbrnmg4cxfmklbdrva3a8.png


но будем двигаться по порядку…

Прежде всего, имеет смысл определиться с тематикой квеста. Поскольку мы уже договорились, что собираемся делать что-то не тривиальное, обычный текстовый квест-бродилка нас не устроит. Помните, в «Сундуке мертвеца» пираты играли в кости? Оказывается, это реально существующая игра с весьма непростыми правилами.

Итак, в Перудо играют группами по 4–5 человек (можно больше). Вдвоём играть тоже можно, но не так интересно. В начале игры, каждый игрок имеет по 5 игровых кубиков (костей). Начиная раунд, все бросают свои кости, смотрят выпавшие очки, но другим игрокам не показывают. Цель игры — угадать сколько костей с определённым номиналом выпало у всех игроков.

Один из игроков делает ставку, называя номинал и количество выпавших костей, при этом, в большинстве случаев, «единички» играют роль «джокеров», заменяя собой любой номинал. Например, игрок говорит: «на столе четыре шестёрки» — это означает, что на всех костях, включая закрытые, не менее четырёх должно выпасть с указанным номиналом (шестёркой) или единичкой.

Следующий игрок может повысить ставку или сказать: «не верю» (в этом случае все кости вскрываются и подчитывается количество костей с требуемым номиналом). Ставка повышается в соответствии с следующими правилами:

  • Количество костей в ставке можно только повышать, за одним исключением: игрок вправе уменьшить количество костей в ставке в два раза (округление в большую сторону), если он называет номинал «единицы» (Например, после ставки «пять пятёрок» или после ставки «шесть шестёрок» можно сказать «три единицы»)
  • Если количество костей в ставке остаётся прежним, номинал должен быть увеличен (Например, можно сказать «три шестёрки» после ставки «три пятёрки», однако нельзя сказать «пять пятёрок» после ставки «пять шестёрок»)
  • Если количество костей в ставке увеличивается, то номинал костей может быть назван любой
  • Если номинал предыдущей ставки был «единицы», игрок вправе изменить ставку только увеличив количество костей в «единицах» или сделав ход в другом номинале, но с количеством костей на одну больше, чем двойное число ставки в единицах предыдущего игрока (Например, после ставки «две единицы» необходимо сказать «пять двоек» или «три единицы»)

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

Есть ещё одно правило: игрок, у которого осталась всего одна кость, может объявить специальный раунд «Мапуто» (в квесте, для простоты, будем считать, что специальный раунд объявляется автоматически), в рамках которого действуют следующие правила:

  • «Единички» не являются джокерами
  • Нельзя изменять номинал в последующих ставках
Немного математики
Чтобы успешно играть в Перудо, необходимо уметь оценивать вероятность выпадения количества k костей требуемого номинала из общего числа n костей. Сразу оговоримся, что делая ставку, мы видим перед собой несколько открытых костей. Так вот, эти кости ни в n ни в k не входят, а просто позволяют увеличить ставку.

Перед нами классическая комбинаторная задача. Имеется n закрытых костей, номинал которых (от 1 до 6) выпадает равновероятно и независимо. Нас интересуют те случаи, когда k из этих костей выпали с требуемым номиналом. Интересующие нас k костей могут быть рассредоточены среди n количеством способов, равном числу сочетаний k из n (кто хочет, может сам проверить). При этом, искомый номинал на них, очевидным образом, может выпасть единственным образом. Остальные кости (на которых номинал не выпал) дают количество размещений с повторениями оставшихся 5-ти значений на (n-k) костей:

28pz02_9sqfkfpr6toieg-kps1o.png

Это числитель (да и то не весь), а нам нужна была вероятность. В знаменателе будет количество размещений с повторениями всех 6-ти значений на n костях. Ну и вспоминаем, что нам интересны не только k, но и большие количества правильно выпавших костей вплоть до самого n. Значит, в числителе будет сумма:
n_aqcbdrd_pf8c1m7dqhtfjx160.png

Вдоволь полюбовавшись на формулу, вспоминаем про единички-джокеры и выдаём финальный итог формулы (это упражнение традиционно оставляется на откуп пытливому читателю):
xam7d93wtpuy69fkccasrjgx870.png

теперь можно и посчитать. Если зафиксировать n=15 и перебрать все k начиная с 1, получится красивая картинка:
uvww7mcmczkqmtirmbbwiwqvnm4.jpeg

Но, вообще-то, вероятности нам нужны для бота. Вот как вычислитель нашей формулы выглядит на языке текстовых квестов:
enyqnwzbyuiqjign39z9wyyehug.png

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


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

u1ychkie3tlauxka6uqy1wdnfdw.png


Здесь можно заметить как вполне понятные (ограничения максимального и минимального значений параметра, стартовое значение), так и более экзотические настройки. В частности, параметр можно объявить провальным, успешным или смертельным (завершающим квест при достижении критического значения), привязать к деньгам игрока, но всё это только половина дела. Переключившись на правую вкладку можно управлять отображением параметра:

4k2l29p9ffii3g6eepjovwr9f9s.png


Разумеется, только этим изобразительные возможности не ограничиваются. Вот здесь, например, отображается подстановка числового значения параметра:

7nmk8ni60iydsndktwlfjvu43fw.png


а здесь подставляется текстовое значение других параметров:

ujpjiyhcvwpejb4t_fkrcvuj1fo.png


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

Больше подробностей
Рассмотрим работу с параметрами на примере:
j7mmq_qthln_7a4-9_dzxm6dsvu.png

Игру начинаем с выбрасывания костей. Выражение [1…6] возвращает случайное число в указанном диапазоне. Выбрасываем все кости (по 5 у каждого из 4 игроков). Дальше почистим лишние. Количество костей — это параметры p61 по p64. Дуги графа выполняются в соответствии с заданными условиями:
w5z6zd9pfl-u04wigk4dwzw1b5g.png

Так, если у первого игрока осталась всего одна кость, обнуляем кости со 2-ой по 5-ую и дополнительно к этому устанавливаем специальный режим игры «Мапуто». Повторяем это для всех четырёх игроков, учитывая то, что последние два могут просто отсутствовать (в этом случае, обнуляем им все 5 костей). Далее надо показать расклад игроку, скрыв кости выпавшие ботам. Для взаимодействия с игроком предназначены промежуточные локации (в графе квеста отображаются белым). Кроме того, локация может отображать несколько вариантов текстовки (в нашем случае, это состав игроков, управляемый параметром p32:
rv39csda-f3litntyhboxeg7zqg.png

Здесь есть хитрость: для первого игрока мы показываем выброшенные очки, но для всех остальных закрытые кости (знаками вопроса). Но как быть с тем, что костей может быть меньше 5-ти? Здесь нам помогает возможность гибкой настройки отображения значений параметров:
w0rqhemoazz7eku5ajc2sokk4zg.png

Внимательный читатель может спросить:, а что это за параметр p76? Это подсказка. Если разыграть квестовую часть правильно, Прихлоп будет показывать выпавшие ему очки:
193h1xdxyhk9xaypn5elfwvdc5w.png

Эта возможность сильно помогает в игре, но количество таких подсказок ограничено.


Формулы редактора квестов — инструмент безусловно мощный, но при неправильном употреблении способный отнять много сил и нервов. Приведу небольшой пример:

kmdrmq4ocubfsvxe6qmk94ubfzi.png


Цель этой хитрой формулы — определение количества очков в текущей ставке и раньше это было простое деление. К сожалению, выяснилось что деление в формулах квеста хоть и целочисленное, но с округлением в ближайшую сторону. С учётом отсутствия дробей, это правильно, но напрочь ломало всю логику. Баг с подсчётом вскрытых очков пришлось искать несколько дней. К счастью, в формулах действует неявное преобразование булевских значений в числовые, что и позволило написать эту ступенчатую функцию. Аналогичным образом осуществляется и сам подсчёт очков:

6tq8v1ywbbdj75zxdghcd47w8lm.png


Про реиграбельность
Чтобы с удовольствием играть в один и тот же квест снова и снова, важно обеспечить его вариативность. По-разному отыгрывая квестовую составляющую, можно подойти к игре с различными начальными условиями (или просто досрочно помереть). Прихлоп может вообще не участвовать в игре, а может помогать крайне полезными советами. Наконец, у него можно попросить денег:
1fhdzr7rx-acillgagp86g1nkjq.png

Это очень важный момент, поскольку «Деньги игрока» — внешний по отношению к квесту параметр и может получиться так, что у игрока не окажется денег, а чтобы начать игру, какую-то минимальную сумму иметь необходимо. Так что, денег можно попросить у Прихлопа (правда помогать в игре он после этого уже больше не будет).
Кстати, это не единственный способ заработать перед началом игры
Ночью можно обыскать каюту Капитана. Проявив некоторую настойчивость и изобретательность можно не только заработать немного денег, но и прийти к альтернативной выигрышной концовке (к проигрышным концовкам прийти тоже можно). Но… это будет сложнее чем просто сыграть в кости.
z8gy789qrh2pzrboju8qwazpnao.png

Надо, всего-навсего, погасить все плюсики. Каждый новый плюсик добавляет Капитану тревожности (и приближает момент, когда он очнётся). Те из вас, кто играли в «Братьев Пилотов», наверняка помнят сейф Карбофоса (кстати, квест про открывание сейфа тоже есть).
ffza_x3ptnlegvwxacvumehzfzi.jpeg

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

В версию квеста для Telegram внесены некоторые декоративные изменения. Например, такое меню в миниигре, на мой взгляд, выглядит более наглядно:
17unkvkfmgx3tp2dteu5x_xy2he.png

Тот же Прихлоп знакомит нас с правилами игры (причём делает это в двух совершенно различных локациях):
fuesy7zlzgb_zqhxqnzwvyiuubk.png

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

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

z0s_5aqshcvvftbegzpkigg5q7m.png

Для каждого из игроков бота заданы индивидуальные пороговые вероятности. Значения с Q2 по Q4 управляют «доверчивостью» игрока и определяет будет ли он вскрывать предыдущую ставку. В свою очередь P2 по P4 — это «оптимизм» в его собственных ставках. По задумке, Кок, например — это самый доверчивый и оптимистичный игрок, который вылетает из игры первым, после чего к игре присоединяется Капитан и проигрыш в игре переквалифицируется в «смерть» главного героя.
03aq781adczhcaewwu2ul5ni4ek.png

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


Немного расскажу о том, как со всем этим иметь дело. Прежде всего, есть Web-плейер с уже имеющимся огромным количеством готовых квестов. В нём есть редактор, в котором можно запустить любой из имеющихся квестов, загрузить qm или qmm-файл с клиента или создать его с нуля в самом редакторе. В какой-то момент вам захочется дать ссылку на один из собственноручно разработанных квестов. Это немного менее очевидно и начинается с установкиPWA-приложения. Далее, приложение синхронизируется с облаком и уже в его редакторе вы можете загрузить собственный квест, после чего нажать на иконку с облаком:

q1ex-v8zdfntmpdus_5n2rcpjxg.png


Здесь не забудьте включить чекбокс «Доступен для всех» и нажать кнопку «Сохранить», после чего появится ссылка. Также, можно открыть в редакторе чужую ссылку, если возникнет желание разобраться в том как работает квест.

© Habrahabr.ru