Игрострой. Отрендеренная логика, часть первая

Ввод в предлагаемую дичь
  Наглядное пособие для начинающих программистов, не умеющих пока программировать и ищущих обходные пути. Таким вот образом можно делать квесты на "движке" программы меню (в данном случае используется моя любимая программа "ABCSoft: menu 4.2" от Барышева Алексея). Предлагаемый тут результат как самостоятельная игра ценности не представляет.
  Где-то через год после этого эксперимента я всё же научился работать в "Delphi", прочитав краткий курс в справочнике школьника и полистав предлагаемый в ссылках сайт-мануал, - ничего особенно сложного. Описанный же метод построения игр хочется посоветовать "профессиональным" игроделам, чтобы они тысячу раз обдумывали и взвешивали каждую свою идею, а не клепали всё подряд на удобном конвейере.
  Для наглядого ознакомления с "игрой" распакуйте иллюстрацию (RARJpeg) в какую-нибудь директорию на винте, киньте туда же содержимое иллюстрации второй части статьи (вся игра не уместилась в одну иллюстрацию), программу меню (ищите её в сети или в резерве программ) и запустите последнюю.


  Альтернативное название данной "работы" - "Сколько существует возможных вариантов следующей секунды и можно ли их все смоделировать?".

Предмет эксперимента
  За несколько лет до начала работы над "игрой", описанной тут, я уже создал первую её версию: там был почти тот же сюжет (то есть - никакой), вороха однотипных фонов с намертво прорисованными в них объектами, ни одной кнопки-картинки и почти никаких логических связей во взаимодействии с объектами (нашёл ключ - дверь открывается, не нашёл - можешь тыкать одни и те же предметы с одним и тем же эффектом). И вот я ради интереса взялся за проектирование второй версии.
  Программировать я не умею вообще, а что-нибудь создать руки время от времени чешутся. Почти завершённая игра для DOS-режима, в которой активно используются переменные, надоела. Хочется, знаете ли, чтобы графика была тоже. Правда, в новом проекте графики не так уж и много, зато литературной ценности ещё меньше, чем в DOS-игре, написанной в формет пакетного bat-файла. Данный проект, считаю, интересен в первую очередь логикой своего проектирования и устройства.

Сюжет игры. "Игровой мир"
  Безымянный главгерой (или безымянная главгероиня) пытается выбраться из собственной квартиры, чтобы отправиться в магазин. Проблема в том, что на входной двери установлен примитивный замок, который даже изнутри нужно открывать ключом (бывают и такие, я сам видел), а ключ, как водится, всё время болтался перед глазами, а как стал нужен, сразу потерялся. Игрок выступает как бы в роли смекалки главгероя/главгероини, подсказывая те или иные действия, в ответ на что главгерой/главгероиня осыпает игрока комментариями, указывающими смекалке на её ошибки. Всё это не вполне здраво, но так устроено множество игр.
  Искать ключ будем в небольшой квартире, содержащей как минимум два помещения - спальню (в которую главгерой/главгероиня идти не хочет) и кухню, а также огромную прихожую, которая логически разбита на вестибюль и гостиную. Есть, наверное, и туалет с ванной, но в игре это помещение/эти помещения не упоминается/не упоминаются, и очень хорошо - возня с разработкой и без того предстоит неслабая.
  Интерактивных объектов в игре минимально: две двери, ключ и ноутбук. Решение игровой задачи займёт минимум времени, зато сколько времени займёт проработка игрового мира!..

Интерпретатор
  Игра представляет собой конфигурацию программы "ABCSoft Menu 4.2.2.56" (автор программы - Барышев Алексей Станиславович), предназначенной для создания меню запуска программ и всего такого (ну, знаете). Выбранная программа поддерживает переменные, но использует их просто для подстановки в значениях своих параметров путей к файлам, фрагментов текста. Изменение переменных и создание новых из интерфейса меню невозможно, проверок условий с последующим выбором реакции нет. Однако едва ли это помешает тому, кто программировать так и не научился. "Завалил сессию - готовься жить весело!".

Моделирование через переменные. Представление о количестве меню
  Сначала перечислим все объекты, состояние которых (внешний вид, сообщения при нажатии) может измениться:
 - дверь на улицу
 - ключ на кухне
 - дверь в спальню
 - ноутбук в гостиной
  Теперь присвоим каждому объекту уникальную переменную и условную литеру, а также перечислим все возможные значения этой переменной, снабдив каждое уникальное значение уникальным байтом (позднее я объясню, зачем так сделано):
   A. "OutDoor" (2 значения):
      A0. SECOND (вторая попытка открыть дверь)
      A1. OPEN (открытие найденным ключом)
   B. "Key" (2 значения):
      B0. OFF (ключ ещё не взят)
      B1. ON (ключ взят)
   C. "BedRoomDoor" (4 значения):
      C0. MESS (первое нажатие: сообщение о бардаке)
      C1. NOWANT (второе нажатие: сообщение о нежелании искать в бардаке)
      C2. NOTHING (сообщение о том, что нечего там уже делать (когда ключ найден, а дверь не открывали))
      C3. GOOD (сообщение о том, что хорошо, что не полезли искать (когда ключ уже найден, а дверь пытались открыть))
   D. "NoteBook" (6 значений):
      D0. DEFAULT (ноутбук включён, его не трогали)
      D1. DISPOFF_SHMONING (поиск под ноутбуком: дисплей выключается, ноутбук перемещается по столу)
      D2. DISPOFF_AFTERSHMON (убедились, что ничего нет, ноутбук стоит выключенный)
      D3. DEFRAG (если ноутбук не трогали, а ключ найден, его (ноутбук) взять нельзя (пусть дефрагментирует файлы))
      D4. WANTTAKE (ключ найден, а ноутбук шмонался: берём с собой в магазин)
      D5. TAKED (ноутбука на столе нет (то есть, он взят после того, как мы нашли ключ))
  В будущем выяснится, что переменная "A" со всеми её значениями лишняя (она логически полностью дублирует значения переменной "B"), а переменные "D3" и "D4" логически дублируют переменные "D0" и "D2" соответственно.
  Кстати, значения переменной "B" влияют сразу на два объекта в игре - на наличие/отсутствие ключа на кухне и на наличие/отсутствие ключа в инвентаре (оба объекта - всего лишь кнопки, а не отдельные, скажем, меню), но мы рассматриваем это как единую переменную, потому что вся логика игры крутится вокруг этого ключа. Вот в первой версии игры, собранной за несколько лет до той, которая в данный момент проектируется, не использовались кнопки-картинки, а существовало множество отдельных фоновых изображений комнат с ключом или без ключа в интерфейсе и с ключом или без ключа на кухне; при таком устройстве следовало бы создать как минимум две разные переменные.
  Список переменных и их возможных значений составлен. Считаем количество возможных комбинаций:
A B C D
2*2*4*6
  Получаем на выходе 96 комбинаций. Что это значит?
  Как можно понять, состояние сразу всех действующих переменных можно выразить одной общей, состоящей из четырёх байт (восьми символов) в значении. Например: ALLES=A0B0C0D0 означает, что в прихожей дверь ещё ни разу не пробовали открывать, ключ не взят, дверь в спальню ещё не пробовали открывать, ноутбук не трогали.
  Но программа меню вовсе не может работать с анализом переменных. Значит, для каждой комнаты нашего игрового мира (всего три штуки) должно существовать девяносто шесть меню, чтобы можно было организовать соответствующие кнопки навигации (например, чтобы вы, имея ключ, не попали на кухню, где он лежит, но всё это в контексте вашего взаимодействия с остальными объектами игрового мира). Значит, умножаем девяносто шесть комбинаций на три - получаем в общей сложности 288 секций меню, необходимых для формирования игры.
  Много? Тогда обратите внимание на то, что среди изначальных девяноста шести комбинаций есть аномальные, которые нет смысла включать в игру. Например, такой вариант: ALLES=A0B1C0D0 означает, что прихожая загрузится с изображением найденного ключа, но при попытке открыть дверь вы получите сообщение о том, что ломать её ради похода в магазин не хочется. Нужна такая ерунда в игре? Нет, разумеется. Значит, треба перебрать все значения общей переменной и отсечь аномальные. Обратите внимание на то, что аномалии можно было бы тоже включить в конфигурацию - меню, их содержащие, всё равно никогда бы не использовались во время игры, если будут правильно настроены все переходы навигации.
  Трудно? Вовсе нет. Трудно только перечислить все девяносто шесть комбинаций (как бы пригодилась программа-генератор на такие случаи!), а вот отсечь аномальные - дело куда более простое. Можно создать список масок, по которым удаляются ненужные комбинации (например, все значения "A0B1????" будут неправильны).
  Итак, вот все возможные комбинации:
A0B0C0D0
A0B0C0D1
A0B0C0D2
A0B0C0D3
A0B0C0D4
A0B0C0D5
A0B0C1D0
A0B0C1D1
A0B0C1D2
A0B0C1D3
A0B0C1D4
A0B0C1D5
A0B0C2D0
A0B0C2D1
A0B0C2D2
A0B0C2D3
A0B0C2D4
A0B0C2D5
A0B0C3D0
A0B0C3D1
A0B0C3D2
A0B0C3D3
A0B0C3D4
A0B0C3D5
A0B1C0D0
A0B1C0D1
A0B1C0D2
A0B1C0D3
A0B1C0D4
A0B1C0D5
A0B1C1D0
A0B1C1D1
A0B1C1D2
A0B1C1D3
A0B1C1D4
A0B1C1D5
A0B1C2D0
A0B1C2D1
A0B1C2D2
A0B1C2D3
A0B1C2D4
A0B1C2D5
A0B1C3D0
A0B1C3D1
A0B1C3D2
A0B1C3D3
A0B1C3D4
A0B1C3D5
A1B0C0D0
A1B0C0D1
A1B0C0D2
A1B0C0D3
A1B0C0D4
A1B0C0D5
A1B0C1D0
A1B0C1D1
A1B0C1D2
A1B0C1D3
A1B0C1D4
A1B0C1D5
A1B0C2D0
A1B0C2D1
A1B0C2D2
A1B0C2D3
A1B0C2D4
A1B0C2D5
A1B0C3D0
A1B0C3D1
A1B0C3D2
A1B0C3D3
A1B0C3D4
A1B0C3D5
A1B1C0D0
A1B1C0D1
A1B1C0D2
A1B1C0D3
A1B1C0D4
A1B1C0D5
A1B1C1D0
A1B1C1D1
A1B1C1D2
A1B1C1D3
A1B1C1D4
A1B1C1D5
A1B1C2D0
A1B1C2D1
A1B1C2D2
A1B1C2D3
A1B1C2D4
A1B1C2D5
A1B1C3D0
A1B1C3D1
A1B1C3D2
A1B1C3D3
A1B1C3D4
A1B1C3D5
  Уникальность комбинаций я проверил, преобразовав кажду строку в команду создания директории с именем, равным значению комбинации. Все девяносто шесть директорий были созданы.
  Теперь давайте всерьёз займёмся перечислением аномальных состояний игры:
 - A0B1???? - невозможно: ключ взят, но мы не хотим ломать дверь
 - A1B0???? - невозможно: ключ не взят, а мы уже открываем дверь
 - ??B0??D3 - невозможно: ключ не взят, а мы оставляем ноутбук дефрагментировать файлы
 - A0????D3 - невозможно одновременно не хотеть ломать дверь и оставить ноутбук дефрагментировать файлы
 - ??B0??D4 - невозможно: ключ не взят, при этом можно взять ноутбук с собой
 - A0????D4 - пока мы не можем открыть дверь, мы не можем взять ноутбук с собой
 - ??B0??D5 - невозможно: ключ не взят, а ноутбука на столе уже нет
 - A0????D5 - пока мы не можем открыть дверь, ноутбук не может исчезнуть со стола
 - ??B1C0?? - невозможно: ключ найден, а мы узнаём о бардаке в комнате
 - A1??C0?? - невозможно узнать о бардаке в комнате, когда мы уже можем открыть дверь
 - ??B1C1?? - невозможно: ключ найден, а мы не хотим рыться в бардаке
 - A1??C1?? - невозможно не хотеть рыться в бардаке, если мы уже можем открыть дверь
 - ??B1??D1 - если ключ найден, невозможно шмонать ноутбук
 - A1????D1 - если дверь доступна для открытия, невозможно шмонать ноутбук
 - ??B0C2?? - если ключ не найден, невозможно получить сообщение о том, что нет уже необходимости лезть в спальню
 - A0??C2?? - если мы ещё не можем открыть дверь, невозможно получить сообщение о том, что нет уже необходимости лезть в спальню
 - ??B0C3?? - если ключ не найден, невозможно получить сообщение о том, что хорошо, что не полезли искать в бардак
 - A0??C3?? - если мы ещё не можем открыть дверь, невозможно получить сообщение о том, что хорошо, что не полезли искать в бардак
  Сразу бросается в глаза лишняя переменная - "A", так как она логически полностью дублирует переменную "B". Вот если бы для неё было доступно больше двух значений, тогда имелся бы смысл её вводить, а так... Однако, сколько бы лишних переменных мы ни ввели, тщательный анализ логики всё равно должен оставить на выходе только нужные комбинации. Обратите внимание, как все маски, в которых содержится переменная ключа, дублируются масками с переменной сообщения открытия двери.
  Возможно, на данный момент найдены не все аномальные комбинации, и всё же пока остановимся, чтобы исключить их из списка.
  Отсеивание уже первых двух масок даёт нам двукратное уменьшение количества возможных комбинаций!
  Получаем на выходе всего шестнадцать уникальных комбинаций:
A0B0C0D0
A0B0C0D1
A0B0C0D2
A0B0C1D0
A0B0C1D1
A0B0C1D2
A1B1C2D0
A1B1C2D2
A1B1C2D3
A1B1C2D4
A1B1C2D5
A1B1C3D0
A1B1C3D2
A1B1C3D3
A1B1C3D4
A1B1C3D5
  Не напрасно я так сформировал уникальные байты: теперь мы можем в автоматическом режиме заменить коды переменных текстовыми определениями, не опасаясь, что какие-либо значения будут неверно прочитаны (то есть, буквы и цифры у нас чередуются на стыках, чётко разграничивая отдельные "байты"):
К:(A0B0C0D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
К:(A0B0C0D1); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ИЩЕМ_ПОД_НОУТБУКОМ)
К:(A0B0C0D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
К:(A0B0C1D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
К:(A0B0C1D1); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ИЩЕМ_ПОД_НОУТБУКОМ)
К:(A0B0C1D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
К:(A1B1C2D0); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НОУТБУК_НЕ_ТРОГАЛИ)
К:(A1B1C2D2); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
К:(A1B1C2D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
К:(A1B1C2D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; МОЖНО_ВЗЯТЬ_НОУТБУК)
К:(A1B1C2D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НОУТБУК_ЗАБРАЛИ)
К:(A1B1C3D0); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
К:(A1B1C3D2); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
К:(A1B1C3D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
К:(A1B1C3D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; МОЖНО_ВЗЯТЬ_НОУТБУК)
К:(A1B1C3D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НОУТБУК_ЗАБРАЛИ)
  Окончательно подтвердилось мнение о том, что переменная "A" была лишней: в каждой строке она имеет то же значение, что и переменная "B". Если присмотреться к результату, можно увидеть незначительную логическую ошибку: все комбинации, когда ключ уже у нас, содержат логически дублирующиеся состояния: "НОУТБУК_НЕ_ТРОГАЛИ"/"НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК" и Если бы нам требовалось сообщения вроде "Вот, какие мы молодцы, что поискали под ноутбуком. Теперь можно ещё раз щёлкнуть на нём, чтобы забрать", подошла бы имеющаяся логика, но лишние сообщения нам не нужны, поэтому исключаем комбинации "A1B1C2D0", "A1B1C2D2", "A1B1C3D0" и "A1B1C3D2". Получаем окончательные двенадцать уникальных комбинаций:
К:(A0B0C0D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
К:(A0B0C0D1); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ИЩЕМ_ПОД_НОУТБУКОМ)
К:(A0B0C0D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
К:(A0B0C1D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
К:(A0B0C1D1); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ИЩЕМ_ПОД_НОУТБУКОМ)
К:(A0B0C1D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
К:(A1B1C2D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
К:(A1B1C2D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; МОЖНО_ВЗЯТЬ_НОУТБУК)
К:(A1B1C2D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НОУТБУК_ЗАБРАЛИ)
К:(A1B1C3D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
К:(A1B1C3D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; МОЖНО_ВЗЯТЬ_НОУТБУК)
К:(A1B1C3D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НОУТБУК_ЗАБРАЛИ)
  Подготовлительный этап работы над игрой почти завершён, мы вплотную подобрались к конфигурированию файла программы меню.
  Как конфигурируется "ABCSoft Menu 4.2.2.56"? На этот вопрос я подробно ответил, создав тестовую конфигурацию. Сейчас хочу обратить ваше внимание на другое: на меню-комнаты и кнопки-объекты.
  Не все кнопки будут формироваться по единой схеме. Кнопки игры можно разделить на три категории:
 - лишённое функциональности оформление (сюда входят строка интерфейса и хинты к деталям)
 - навигация (стрелки, дающие возможность перемещаться из одной комнаты в другую)
 - интерактивные объекты
  Параметры кнопок оформления всегда одни и те же для конкретной комнаты, их формирование сводится к вставке заготовленного текста без каких-либо изменений. Кнопки навигации и кнопки интерактивных объектов хранят в себе состояние общей переменной игры. Причём, кнопки навигации общую переменную никогда не меняют: перейти из "Вестибюля A0B0C0D0" можно только в "Гостиную A0B0C0D0" или на "Кухню A0B0C0D0", но не, скажем, в "Гостиную A0B0C1D0". Другое дело - интерактивные кнопки. Они могут либо никак не касаться переменной, напоминая кнопки оформления (например, сколько угодно можно дёргать входную дверь, но, пока нет ключа, эффект не поменяется - сообщение останется тем же), либо изменять состояние переменной, а в некоторых случаях и свой внешний вид (что, впрочем, тоже относится к изменению переменной).
  Такой, например, вопрос: "К какому типу кнопки относится лежащий где-то в квартире ключ?". Чтобы ответить, перечислим, что происходит при нажатии на него: тут же загружается одна из версий комнаты без ключа, в строке интерфейса появляется предмет, мы можем открыть входную дверь вестибюля и по-новому взглянуть на ноутбук в гостиной. Кнопка лежащего ключа является, извините, ключевой для всей игры, но мы назовём её интерактивной только потому, что она "меняет" переменную.
  Напоминаю, что на самом деле никакой переменной не существует: она эмулируется за счёт объединения в игре д.жины параллельно существующих квартир (например, "Квартира A0B0C0D0"), между которыми путешествует игрок, считающий их единым "живым" пространством (если только он не знаком с устройством конфигурации).
  Внимательно посмотрите на окончательный список уникальных комбинаций. Видите, как удачно получилось, что ноутбук, у которого полно разных состояний, находится у нас в самом конце строк? Теперь нам достаточно создать, например, шаблон кнопок "НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ", скопировать его три раза и добавить разные кнопки для ноутбука, а не мучаться, подбирая кнопоки по одной для той или иной комнаты. Впрочем, можно делать всё и вручную, с любовью, так как комбинаций у нас получилось не очень много.
  По какой методике бы мы ни формировали текст конфигурации ("конвейерно-штамповальную" методику я применять и объяснять не буду, так как намерен внимательно добавлять одно меню за другим, одну кнопку за другой, без копипасты огромных кусков - вот нравится мне конфигурировать эту программу и я люблю точно знать, что делаю (хотя, возможно, в некоторых случаях чудовищная копипаста будет применяться)), нам необходимо заранее перечислить каждое меню игры и присвоить ему номер. Зачем? Потому что в первой же комнате (не считая вводного вестибюля, где главгерой ещё не знает, что не так просто бывает покинуть собственную квартиру) нам понадобится знать эти номера при формировании кнопок навигации. Начинать будем с меню номер три, так как первый номер зарезервирован для главного меню, а второй - для вестибюля без интерфейса.
  Прежде чем начать, внесу ещё один корректив. В данный момент мы знаем, что для формирования всех комнат потребуется тридцать шесть меню, но в действительности это число ещё меньше. Обратите внимание на переменную "D1" (шмонающийся, так сказать, ноутбук). Разумеется, можно было бы сделать доступными кнопки навигации во время поиска ключа под ноутбуком, но это странно, ведь ноутбук - не такая большая вещь, чтобы, изучив часть стола под ним, мчаться куда-то ещё, а затем возвращаться и продолжать поиск под упомянутым гаджетом. Получается, для ряда значений глобальной переменной нет необходимости формировать вестибюль и кухню. Итак, вот полный список меню игры:
3 - вестибюль. К:(A0B0C0D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
4 - вестибюль. К:(A0B0C0D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
5 - вестибюль. К:(A0B0C1D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
6 - вестибюль. К:(A0B0C1D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
7 - вестибюль. К:(A1B1C2D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
8 - вестибюль. К:(A1B1C2D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; МОЖНО_ВЗЯТЬ_НОУТБУК)
9 - вестибюль. К:(A1B1C2D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НОУТБУК_ЗАБРАЛИ)
10 - вестибюль. К:(A1B1C3D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
11 - вестибюль. К:(A1B1C3D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; МОЖНО_ВЗЯТЬ_НОУТБУК)
12 - вестибюль. К:(A1B1C3D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НОУТБУК_ЗАБРАЛИ)
13 - гостиная. К:(A0B0C0D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
14 - гостиная. К:(A0B0C0D1); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ИЩЕМ_ПОД_НОУТБУКОМ)
15 - гостиная. К:(A0B0C0D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
16 - гостиная. К:(A0B0C1D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
17 - гостиная. К:(A0B0C1D1); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ИЩЕМ_ПОД_НОУТБУКОМ)
18 - гостиная. К:(A0B0C1D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
19 - гостиная. К:(A1B1C2D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
20 - гостиная. К:(A1B1C2D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; МОЖНО_ВЗЯТЬ_НОУТБУК)
21 - гостиная. К:(A1B1C2D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НОУТБУК_ЗАБРАЛИ)
22 - гостиная. К:(A1B1C3D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
23 - гостиная. К:(A1B1C3D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; МОЖНО_ВЗЯТЬ_НОУТБУК)
24 - гостиная. К:(A1B1C3D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НОУТБУК_ЗАБРАЛИ)
25 - кухня. К:(A0B0C0D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
26 - кухня. К:(A0B0C0D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; МОЖНО_УЗНАТЬ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
27 - кухня. К:(A0B0C1D0); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; НОУТБУК_НЕ_ТРОГАЛИ)
28 - кухня. К:(A0B0C1D2); Р:(НЕ_ЛОМАТЬ; КЛЮЧА_НЕТ; УЗНАЛИ_О_БАРДАКЕ; ПОИСКАЛИ_ПОД_НОУТБУКОМ)
29 - кухня. К:(A1B1C2D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
30 - кухня. К:(A1B1C2D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; МОЖНО_ВЗЯТЬ_НОУТБУК)
31 - кухня. К:(A1B1C2D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; НЕЗАЧЕМ_НАМ_УЖЕ_БАРДАК; НОУТБУК_ЗАБРАЛИ)
32 - кухня. К:(A1B1C3D3); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НЕЛЬЗЯ_ВЗЯТЬ_НОУТБУК)
33 - кухня. К:(A1B1C3D4); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; МОЖНО_ВЗЯТЬ_НОУТБУК)
34 - кухня. К:(A1B1C3D5); Р:(МОЖНО_ВЫЙТИ; КЛЮЧ_ЕСТЬ; ХОРОШО,_ЧТО_НЕ_ИСКАЛИ_В_БАРДАКЕ; НОУТБУК_ЗАБРАЛИ)
  Получилось тридцать четыре меню на всю игру, включая интерфейс запуска, из которых тридцать два меню описывают квартиру с учётом всех возможных сочетаний событий. Недаром существует понятие "переменная окружения"; в нашем случае имеем двенадцать уникальных состояний окружения.
  Может показаться, будто дополнительные значения переменной ноутбука ("можно взять"/"нельзя взять") лишние, потому что они и так следуют из значений "трогали"/"не трогали", однако благодаря проведённому логическому анализу с последующим отсеиванием по маске это не привело к увеличению количества меню, зато упростило восприятие глобальной переменной.
  На этом заканчивается подготовительная часть работы, а вместе с тем и данная статья. Продолжение смотрите в игре. До свидания!


Рецензии