"Неожиданное путешествие" "Неожиданное Путешествие" - взгляд изнутри STD Недавно на zx-pk.ru форумчанин из Пско─ ва под ником STD выложил в общий дос─ туп свою текстово-графическую адвентюру "Неожиданное Путешествие", которая испол─ нена в достаточно нестандартной манере на фоне массы современных игр, сделанных на AGD -движке. Мы попросили автора рассказать о техни─ ческой части этой игры. * * * Необходимое лирическое вступление: Автор сам прекрасно понимает, что соз─ данный им код топорный и деревянный, что он жрет память Спекки, как не в себя, а также,что при просмотре листинга мастерами уровня Alone Coder и GoodBoy они рискуют заработать глазное кровотечение. Но. Мой движок все-таки имеет одно достоинство. Он вопреки всему работает! Так что рассматри─ вайте его и эту статью как совокупность неких идей,которые кто-то уже обдумал, как исходный материал для своего творчества и совершенствования, будь на то ваша воля. Итак, что представляет собой "Неожидан─ ное Путешествие" с точки зрения программи─ ста и как там всё устроено? Движок программы мной написан полностью на ассемблере и полностью в ZXASM - 100% аутентичная разработка в2017 г., что дос─ тавило мне много удовольствия уже само по себе. Распределение памяти При разработке игры под расположение движка в памяти я отвел место с26000 по 32767(#7FFF), то есть до самого конца 2-го окна памяти или всего около7 КБ. В дейст─ вительности же в откомпилированном виде движок занял 4 с небольшим килобайта, но менять я ничего не стал. С адреса 32768 (#8000) и до 37900 рас─ положен буфер для обработки текущей сцены игры. Таким образом, любая отдельно взятая сцена игры не может занимать более5123 байта памяти. О сценах подробнее далее. С адреса 37900 и до 38000 расположено место под флаги в игре.1 флаг = 1 байт. Таким образом, в игре можно оперировать сотней флагов. С 38000 расположен буфер для вырезки разных маленьких спрайтов. Я его использо─ вал для вырезки и временного хранения ку─ сочков экрана, когда открывал окно "листо─ чки" (в котором игрок выбирал все дейст─ вия), т.к. оно имело не строго прямоуголь─ ную форму, ввиду чего стандартная заложен─ ная в программу процедура сохранения гра─ фики под открываемым окном с ним не справ─ лялась. С адреса47000 хранится шрифт игры: 2КБ в кодировке 866 до самого конца 3-го окна памяти, то есть по49151 (#BFFF) включите─ льно. Как видно, с адреса38000 до 47000 аж целых 9 КБ места. Для вырезки маленьких спрайтов столько, конечно, не надо. Да так уж получилось, что такая дырка осталась. С адреса 49152 (#C000), как известно даже малышам, начинается 4-е окно памяти, куда на128K можно подключать банки (стра─ ницы) памяти0,1,3,4,6,7. Их я использовал следующим образом: Страница 0 - в неё всегда грузятся бло─ ки сцен, т.е. собственно текстовые файлы с описанием локаций,команд и т.д.В моей игре на диске они имеют именаblscOO, blscO1, blscO2, ... blsc13. Страница 1 - в неё грузятся блоки спра─ йтов, которые игрок видит в окне "фотогра─ фии" и которые сопровождают показ текстов. На диске это файлыblspOO ... blspO5. Страница 3 - в неё грузятся отдельные спрайты, нужные для игры (скрепыш, медаль─ ка в окне достижений, мем "мудрый старик", дискета "сохранить" и "листочки" для окна выбора действия"). Все они хранятся в фай─ леgfxOO. Страница 4 - с адреса #C000 в ней хра─ нится главное меню игры, с адреса57000 - основной игровой экран (собственно блок─ нот, ручка, фотография). Страница 6 - не используется. Страница 7 - отведена под буфер для со─ хранения содержимого экрана под открывае─ мым окном. Процедура сохранения может сох─ ранить последовательно до4 открытых окон. Программисту об адресах, куда именно это в пределах данной страницы сохраняется, ду─ мать не надо. Принцип построения движка Движок можно разделить4 логически обо─ собленные части. 1.Часть инициализации. Начиная отORG 26000 и до метки GLVOO. Этот кусок кода работает только при первом запуске программы, выводит на экран заста─ вки, инициализирует внутренние переменные программы,грузит шрифт и загружает в стра─ ницу0 первый текстовой файл с первым бло─ ком сцен игры -blscOO. Поле этого движок переходит кп.2. 2.Переброска текущей сцены в буфер об─ работки. С меткиGLVOO до GLVO2 небольшой кусо─ чек программы берёт из внутренний перемен─ ной движкаPOZGL (то есть ПОЗиция ГЛобаль─ ная) адрес начала конкретной сцены в блоке сцен, которую сейчас надо обрабатывать, и перебрасывает её из этого адреса в выше─ указанный буфер текущей сцены на32768 (#8000). При этом одна сцена от другой от─ деляются маркером#FE. То есть в результа─ те работы этой части программы кусок памя─ ти из нулевой страницы с адресаPOZGL до первого встреченного кода#FE будет переб─ рошен в адреса с32768 (#8000). При этом этот кусок, как я уже писал,не должен быть больше5123 байт, иначе он затрёт флаги! При первом запуске программыPOZGL за─ носится#C000, поэтому процедура GLVOO... GLVO2 перебросит в буфер самую первую (нулевую) сцену изblscOO. После того, как программа встретит код #FE, переброска сцены заканчивается. В пе─ ременную POZIC (т.е. текущая ПОЗИЦия) за─ носится число#8000, то есть встаём на на─ чало буфера, куда попала обрабатываемая сцена, и переходим кп.3. 3.Обработка текущей сцены или "блок распознания управляющих кодов". Начинается с меткиOSNOO и идёт до мет─ ки OSNЗЧ. В данном блоке движок работает 90% времени. Из переменной POZIC берется адрес в буфере обработки текущей сцены. Если мы только начали обрабатывать сцену,это будет #8000. Теперь берём из этого адреса имена команд и начинаем их сравнивать с команда─ ми, зашитыми в данной части движка. Имена всех возможных команд зашиты в этом блоке программы. Как только все три последова─ тельно считанные из буфера буквы совпадут с тремя буквами какой-либо команды, заши─ тыми в этом блоке, то этот блок вызывает из4-й части программы уже непосредственно её обработчик. После обработки в4-й части программы и выполнения команды управление вновь возвращается сюда, переменнаяPOZIC увеличивается (так как после команды обыч─ но ведь идут её параметры, которые только что использовали, обработали, и теперь их надо пропустить) на столько байтов, чтобы она начала указывать на следующую команду, и управление возвращается в начало этого блока. Если в данном блоке попалась команда "перейти к другой сцене", то после её вы─ полнения в переменнуюPOZGL будет занесён адрес этой сцены, к которой надо перейти, и управление вернётся не в начало блока3, а будет передано на блок2. 4.Процедуры обработки управляющих ко─ дов. Если блок 3 программы лишь распознаёт команды и после распознания вызывает их обработчики, то в блоке4 содержатся имен─ но эти самые обработчики. То есть тут находятся все процедуры "открыть окно","закрыть окно", "напечатать спрайт","напечатать текст", "ждать нажатия любой клавиши" и т.п. Больше, собственно, сказать нечего. Это нижний уровень, сама основа программы. Команды Для реализации своей игры я придумал следующие команды, которых мне хватило с лихвой: WWN- устанавливает параметры текущего окна, с которым дальше будут работать все процедуры окна; WC1- очищает всё текущее окно целиком, включая поле рамки; WC2- очищает внутреннюю часть текущего окна целиком, без поля рамки; WCL- заливает текущее окно цветом; WRM- рисует в текущем окне рамку; WCT- вырезает фон под текущим окном в буфер. Можно последовательно сохранить 4 окна! Вырезанный фон окон помещается в банк 7; WST- полностью рисует текущее окно - очищает его,заливает цветом,рисует рамку; WPT- восстанавливает сохраненный фон из-под окна из буфера. Процедура может по─ следовательно восстановить фон 4 окон, со─ хранных процедуройWCT; WN1- быстрая установка текущимИ ВЫВОД окна игры 1 (т.е. собственно страница дне─ вника, где печатается весь текст); W2O- быстрая установка, сохранение фо─ на и вывод спрайта окна "Листочки"-"выбора действия"; W2С- быстрое закрытие окна "выбора де─ йствия"; WЗO- быстрая установка,сохранение фона и вывод спрайта окна "помощь"; WЗC- быстрое закрытие окна "помощь"; WЧO- быстрая установка,сохранение фона и вывод спрайта окна "достижение"; WЧC- быстрое закрытие окна "достиже─ ние"; ";"- комментарий.Весь дальнейший текст игнорируется до перевода строки; "Enter"- знак перевода строки игнори─ руется. Введено для удобства редактирова─ ния; BNK- "Включение выбранного банка памя─ ти. Байт с номером страницы памяти +48 (т.е. просто текстовая цифра от 0 до 9)"; PAU- ожидание нажатия любой клавиши; CLS- очищает экран; FDI- зажигает экран; FDO- гасит экран; LDF- загрузка файла по имени. Загрузка происходит всегда по адресу#C000и в тот банк памяти, который в этот момент впеча─ тан в этот адрес командойBNK; TXT- команда печати текста. Имеет свои собственные управляющие коды; CSP- вырезка произвольного спрайта; PSP- печать произвольного спрайта; SP1- выводит спрайт с номером от00 до16 из блока спрайтов в окно "фотогра─ фии"; JMP- безусловный переход к сцене с указанным номером в текущем блоке сцен; FON- включает выбранный флаг в блоке переменных; FOF- выключает выбранный флаг в блоке переменных; JMF- переход к сцене в зависимости от того, включен выбранный флаг или нет; VIB- переход на сцену в соответствии с нажатием клавиш1-4,в окне "листочков"; VIN- спецоператор в игре. Используется единственный раз, для проверки,выполнил ли главный герой все три задания, и если да, то перебрасывает его к горе ведьмы. Этих немудрёных команд хватило, чтобы написать игру. Скажу больше, из них всех в 95% случаев используется с десяток. Команды WN1, W2O, W2С, WЗO, WЗC, WЧO, WЧC введены для удобства набора сцен. Их можно было бы не вводить, но тогда выпол─ нение очень частых действий, типа открытия и закрытия окон "скрепыша", "листочков" и т. д. приходилось бы выполнять серией опе─ раторовWWN, WC1, WCT, WST, WPT с парамет─ рами. Поэтому я посчитал, что самые глав─ ные окна в игре можно обозначить собствен─ ными операторами и открывать, закрывать их надо по "имени собственному", например, W2O/W2С. Раз - и всё! Строение блоков сцен Весь текст игры занимает порядка18ОКБ. Он разбит на файлы размерами до1бКБ: blscOO, blscO1, blscO2, ... blsc13. В каждый момент времени в страницу0 может быть загружен только один из этих файлов. Внутри каждый файл состоит из отдельных сцен, которые между собой разделены марке─ рами#FE. Каждая сцена состоит из команд для дви─ жка, параметров этих команд и текста для игрока, который печатается на экране кома─ ндойTXT. Движок забирает из загруженного в стра─ ницу 0 блока сцен одну сцену (называемую текущей) в буфер обработки текущей сцены с адреса #8000 и в этом буфере последовате─ льно обрабатывает все её команды. Так как сцена обрабатывается в этом бу─ фере, а не в нулевой странице, то в ходе выполнения этой текущей сцены находящимися в ней командами можно спокойно переключать банки памяти, грузить туда спрайты,грузить другие блоки сцен и переходить на них. Буфер был введён именно для этого. Ну а теперь, для примера, кусок исход─ ного текста блока сцен. Как это выглядит в игре, вы видели, а вот как это выглядит для её автора в Notepad++: ;Сцена 00 "Меню" BNK 1 - включили банк 1 LDF blspOO C - загрузили туда первый блок спрайтов BNK 4 - включили банк 4 FDI 49152 - вывели оттуда картинку главного меню игры, которая туда уже была загружена BNK 0 - вернулись к банку 0 FOF 03:FOF 04:FOF 05:FOF 06 FOF 07:FOF 08 FOF 09:FOF 10:FOF 11:FOF 12:FOF 13:FOF 14 FOF 15:FOF 16:FOF 17:FOF 18 FOF 19:FOF 20 FOF 21:FOF 22 - сбросили все флаги игры JMP 01 - перешли на сцену 1 · - это #FE маркер конца сцены ;Сцена 01 "Меню" VIB 3,02,06,03 - сцена состоит из одной команды: ждём, когда игрок нажмёт одну из трёх возможных клавиш: 1, 2 или 3, и соответственно переходим на сцены 2, 6 или 3. · ;Сцена 02 "Вступление" WWN 03,03,26,18,096,180,06,04 WCT:WST - этими командами мы вывели окно для вступления, сохранив фон под ним TXT Здравствуй, мой юный друг! Я не знаю кто ты, а ты, в свою очередь, не знаешь, что за книга у тебя в руках. И хо- тя твоя личность для меня нав- сегда останется тайной, свою тайну я тебе открою. Это - Дневник. Более того - это ЖИВОЙ дневник, который со- держит мои ЖИВЫЕ воспоминания. Раз ты держишь его в руках, значит я, наконец,спустя годы, нашел время, чтобы записать те PAU:WC2:TXT - ждём нажатия любой клавиши, очищаем и печатаем дальше... Заключение Мне кажется, что всё получилось в целом очень просто и весьма элегантно. Если ис─ пользовать именно такой интерфейс, как у меня, то игру в данном стиле, но со своим сюжетом может, в принципе, разработать че─ ловек, вообще не знакомый ни с Бейсиком,ни с ассемблером,просто в Notepad++ (конечно, если не учитывать необходимость создания блоков спрайтов для "фотографий", которые я также формировал ассемблерными програм─ мами, и необходимости изменения титульных экранов). Но в целом, всё-таки... Безусловно, есть определённые шерохова─ тости и нелепости даже в придуманных мной командах. Уже в процессе набора сцен я по─ нял, что пару из них следовало бы весьма изменить, но было набрано уже много игры,и переделывать я не стал. Именно это обусло─ вило наличие в ней многих "технических" сцен, которые не видны игроку, но их приш─ лось вводить для того, чтобы правильно га─ сить окно диалога при ветвлениях сюжета. В целом меня весьма увлекла идея возмо─ жности разработки действительно универса─ льного движка для такого типа игр, о чём я уже писал на форуме. Мне кажется, это было бы здорово, если бы на ZX-платформе появи─ лся такой продукт, который бы позволял использовать разные шрифты, задавать пара─ метры своих окон, и прочая, и прочая,и всё это - не выходя за пределы Notepad++. Это был бы наш с вами AGD - Адвентюре Гейм Дисингер фром Раша виз Лав!8) Всегда Ваш, STD.