Когда в первой главе мы рассматривали основные части игровой программы, то в общих чертах показали, как строится многокадровая заставка и какие функции должны выполнять отдельные ее элементы. Теперь настало время всерьез поговорить о том, как реализовать эти элементы в виде законченных подпрограмм, а затем собрать их в единое целое для получения готовой заставки. Конечно, трудно дать ответы на все вопросы, с которыми вы можете столкнуться при решении данной задачи, поэтому мы решили ограничиться только теми проблемами, которые ранее не рассматривались совсем. Среди них - создание простейших звуковых эффектов, преобразование символов стандартного набора таким образом, чтобы надписи не стыдно было поместить на самое видное место экрана, скроллинги окон с графическими изображениями и текстами во всех направлениях, а также включение в программу элемента случайности. После того, как все это будет подробно рассмотрено, станет возможно, наконец, непосредственно заняться многокадровой заставкой.
LD DE,40
LD HL,500
CALL 949
RET
Несмотря на некоторую трудность подбора параметров, все же попытаемся создать с помощью приведенной подпрограммы что-либо интересное, причем так, чтобы время звучания и высоту тона можно было свободно регулировать. Поскольку при этом возможны самые разные варианты, то получится множество звуковых эффектов, что, собственно говоря, нам и требуется.
Рассмотрим программу, основанную на приведенном выше примере, генерирующую звуки длительностью порядка 1-3 секунд. Она отличается тем, что высота тона изменяется в цикле, а продолжительность звучания можно регулировать не только изменением DE, но и занося различные значения в регистр B. Мы предполагаем использовать ее в дальнейшем, для чего присвоим ей собственное имя:
SND LD B,10 ;количество циклов
LD HL,300 ;начальная частота звучания
LD DE,8 ;длительность звука
SND1 PUSH BC
PUSH DE
PUSH HL
CALL 949
POP HL
POP DE
POP BC
DEC HL ;или INC HL
DJNZ SND1
RET
После запуска вы услышите звук, увеличивающийся по высоте, но если где-то в игре потребуется, чтобы с течением времени частота уменьшалась, достаточно команду DEC HL заменить на INC HL. Для извлечения более коротких звуков (0.1-0.3 сек.) достаточно задать в SND другие значения регистров:
SND LD B,90
LD DE,2
LD HL,150
SND1 .........
Располагая этими программками, попробуйте поэкспериментировать, встроив, например, два резонатора в один цикл, либо, организовав несколько (в том числе и вложенных) циклов с одинаковыми или разными резонаторами. Уверены, что это занятие приведет вас ко многим «открытиям» и доставит немало приятных минут.
![]() а | ![]() б |
Приведем теперь текст программы BIGSYM, которая удваивает высоту одного символа, причем его код должен быть предварительно помещен в ячейку памяти по адресу 23296.
ORG 60000
ENT $
LD A,(23296) ;загружаем код печатаемого символа
BIGSYM LD L,A
LD H,0 ;переписываем этот код в HL
ADD HL,HL ;умножаем код на 8
ADD HL,HL
ADD HL,HL
LD DE,(23606) ;в DE загружаем адрес начала
; текущего фонта
ADD HL,DE
EX DE,HL
LD HL,(23684) ;в HL помещаем адрес в видеобуфере,
; по которому будет выводиться первый
; байт измененного символа
LD B,4
PUSH HL ;делаем две копии HL, чтобы
PUSH HL ; использовать их во втором цикле
BIGS1 LD A,(DE) ;считываем байт из фонта
LD (HL),A ;переписываем в видеобуфер
INC H
LD (HL),A ;еще раз - ниже
INC H
INC DE ;переходим к следующему байту
DJNZ BIGS1
POP HL ;восстанавливаем HL
LD BC,32 ;вычисляем адрес первого байта
ADD HL,BC ; второго знакоместа
LD B,4
BIGS2 LD A,(DE) ;аналогично циклу BIGS1
LD (HL),A
INC H
LD (HL),A
INC H
INC DE
DJNZ BIGS2
POP HL ;восстанавливаем HL
INC HL ;увеличиваем HL на 1 для подготовки
; печати следующего символа
LD (23684),HL ;записываем в системную переменную
; адрес следующего знакоместа экрана
RET
Обращаем ваше внимание на то, что процедура BIGSYM получилась не совсем универсальной. Сделано это с единственной целью упростить и сократить ее исходный текст. Применяя ее, нужно следить, чтобы символы при печати не выходили за пределы экрана ни по вертикали, ни по горизонтали. Кроме того, верхняя и нижняя половинки выводимых знаков не должны попадать в разные трети экрана, то есть не допускается позиционирование курсора на 7-ю и 15-ю строки экрана.
Чтобы посмотреть, как выглядит на экране целая строка удлиненных символов, введите небольшую программку на Бейсике. Само собой разумеется, что перед ее запуском ассемблерная программа должна быть оттранслирована.
10 PRINT AT 5,5; 20 LET a$="Starting program BIGSYM!" 30 FOR n=1 TO LEN a$ 40 POKE 23296,CODE a$(n) 50 RANDOMIZE USR 60000 60 NEXT nНасладившись созерцанием новых букв, возможно, вы захотите воспользоваться процедурой BIGSYM в собственной программе. В последнем разделе этой главы, где приводится программа и описание многокадровой заставки, можно посмотреть, как это лучше сделать. Пока же можем сказать следующее: перед вызовом процедуры из ассемблера необходимо установить позицию печати в нужное место экрана, воспользовавшись командой RST 16, а в аккумулятор занести код выводимого символа. В этом случае надобность в команде LD A,(23296), предваряющей в приведенном примере процедуру BIGSYM, отпадает.
![]() а | ![]() б |
Поскольку работа этой процедуры не столь очевидна, как может показаться с первого взгляда, то для лучшего ее понимания мы приводим небольшую схемку (рис. 6.3), отражающую пути перемещений битов при многократном выполнении команд сдвигов. Напоминаем, что эти команды вместе с аналогичными схемами приведены в разделе «Организация циклов в ассемблере» пятой главы.

Рис. 6.3. Перемещения битов
ORG 60000
ENT $
LD A,(23296) ;начало - как в процедуре BIGSYM
DBLSYM LD L,A
LD H,0
ADD HL,HL
ADD HL,HL
ADD HL,HL
LD DE,(23606)
ADD HL,DE
EX DE,HL
LD HL,(23684)
LD B,8 ;количество повторений внешнего цикла
PUSH HL
; Во внешнем цикле по очереди берутся 8 байтов исходного символа
; для преобразования во внутреннем цикле
DBLS1 PUSH BC ;сохраняем BC для внешнего цикла
PUSH DE ;сохраняем текущий адрес
; в символьном наборе
LD A,(DE)
LD DE,0 ;подготавливаем пару DE для последующего
; формирования в ней расширенного
; байта символа
LD B,8 ;количество повторений внутреннего цикла
; (равное числу бит в одном байте)
; Во внутреннем цикле каждый бит исходного символа дважды копируется
; в регистровую пару DE, где в конце концов получаем расширенный
; в два раза байт (рис. 6.3)
DBLS2 RLCA
PUSH AF
RL E
RL D
POP AF
RL E
RL D
DJNZ DBLS2
LD (HL),D ;вывод преобразованных байтов из
INC HL ; пары DE на экран
LD (HL),E
DEC HL
POP DE ;восстанавливаем значение DE
INC H
INC DE ;переходим к обработке следующего
; байта из набора символов
POP BC ;восстанавливаем BC для внешнего цикла
DJNZ DBLS1
POP HL
INC HL ;переходим к следующему
INC HL ; знакоместу экрана
LD (23684),HL ;записываем в системную переменную
; адрес следующего символа
RET
Чтобы напечатать на экране строку с каким-то текстом, можно воспользоваться той же программкой на Бейсике, что и для демонстрации процедуры BIGSYM.
Теперь в вашем распоряжении имеются три программы, в той или иной мере изменяющие форму стандартных символов и, чтобы лучше понять их работу, можно порекомендовать слегка «поиздеваться» над символами, создавая комбинированные программы. Например, часть символа увеличить по высоте, а оставшуюся часть - по ширине, или BIGSYM и DBLSYM соединить с программой BOLD. Надо сказать, что последний вариант дает совсем недурные результаты, в чем вы сможете убедиться, дойдя до последнего раздела этой главы.
Чтобы не утомлять вас долгими рассуждениями о том, каким образом формируется та или иная буква, лучше всего приведем в качестве своеобразного комментария программу на Бейсике с краткими пояснениями к ней, которые предлагаем внимательно изучить, после чего будет совсем нетрудно понять принцип работы соответствующей ей ассемблерной программы.
10 READ y: IF y=-1 THEN GO TO 100 20 READ x,hgt,len,ink,dx 30 LET y=113-y: LET x=x+40 40 INK ink 50 FOR i=1 TO hgt 60 PLOT x,y: DRAW len,0 70 PLOT x,y+1: DRAW len,0 80 LET y=y-4: LET x=x+dx: NEXT i 90 GO TO 10 100 STOP 1000 REM --- Буква «Н» --- 1010 DATA 0,0,12,6,2,0 1020 DATA 20,6,2,14,2,0 1030 DATA 0,20,12,10,2,0 1040 REM --- Буква «А» --- 1050 DATA 0,46,12,4,1,-1 1060 DATA 0,46,12,10,1,1 1070 DATA 24,42,2,16,1,0 1080 REM --- Буква «Р» --- 1090 DATA 0,72,12,10,3,0 1100 DATA 0,82,2,13,3,0 1110 DATA 24,82,2,13,3,0 1120 DATA 4,96,1,2,3,0 1130 DATA 24,96,1,2,3,0 1140 DATA 8,92,4,8,3,0 1150 REM --- Буква «Д» --- 1160 DATA 0,112,10,4,6,-1 1170 DATA 0,112,10,10,6,1 1180 DATA 40,100,2,34,6,0 1190 REM --- Буква «Ы» --- 1200 DATA 0,139,12,10,4,0 1210 DATA 16,150,2,13,4,0 1220 DATA 40,150,2,13,4,0 1230 DATA 20,163,1,2,4,0 1240 DATA 40,163,1,2,4,0 1250 DATA 24,160,4,8,4,0 1260 DATA 0,167,4,8,4,0 1270 DATA 16,169,1,6,4,0 1280 DATA 20,171,6,4,4,0 1290 DATA 44,169,1,6,4,0 1300 DATA -1Теперь скажем несколько слов об этой программе, поскольку все основные идеи, заложенные в ней, затем будут реализованы в программе на ассемблере, но в начале покажем, что вы увидите на экране после ее исполнения (рис. 6.4).

Рис. 6.4. Название для игры НАРДЫ
Вот такая симпатичная надпись, в которой каждая буква составлена из отрезков параллельных двойных линий, нарисованных DRAW'ами. В высоту укладывается двенадцать таких линий плюс промежутки между ними. Точно такие любой из вас сможет легко начертить по линейке на листе бумаги, измерить их длины и координаты, после чего ввести в программу свои вычисления в виде блока данных. Посмотрим, как это делается. Прежде всего разберемся со структурой строки блока данных, поскольку с подобным построением раньше мы еще не встречались, а именно оно все и определяет. Строка списка DATA содержит шесть элементов, каждому из которых в программе соответствует определенная переменная, а именно:
![]() а | ![]() б |
![]() в | ![]() г |
После того как мы выяснили способ формирования каждой буквы средствами Бейсика, перейдем непосредственно к ассемблерной программе строка за строкой. Но прежде чем приступить к описанию текста, следует заметить, что к этому моменту мы наговорили вам довольно много всякого, поэтому небольшие по размерам программы нет смысла разбивать на отдельные части и подробно распространяться о каждой из них, как мы это делали в четвертой и пятой главах. Думается, что сейчас будет уже вполне достаточно прокомментировать отдельные команды и только в случаях, представляющих особый интерес, рассмотреть более детально некоторые группы команд.
ORG 60000
LD HL,DATA
; Считывание параметров из блока данных
CICL1 LD B,(HL) ;Y-координата начала линии
INC B
RET Z ;выход, если это конец блока данных
LD A,112 ;отсчитывать будем не снизу, а сверху.
; Кроме того, сразу добавляем смещение
; от верхнего края в 64 пикселя и
; увеличиваем на 1, поскольку выполнялась
; команда INC B (175-64+1=112)
SUB B
LD B,A
INC HL
LD A,(HL) ;X-координата начала линии
ADD A,40 ;центрируем надпись
LD C,A
INC HL
LD D,(HL) ;высота рисуемой части буквы
INC HL
LD E,(HL) ; и ее ширина
INC HL
LD A,16 ;управляющий код для INK
RST 16
LD A,(HL) ;код цвета
RST 16
INC HL
LD A,(HL) ;наклон рисуемой части
INC HL
PUSH HL ;сохраняем текущий адрес в блоке данных
; Цикл рисования части буквы, описанной очередной порцией данных
CICL2 PUSH AF ;сохраняем в стеке аккумулятор
CALL DRAW ;чертим первую линию
DEC B ;вторая линия будет на 1 пиксель ниже
CALL DRAW ;чертим вторую линию
DEC B ;переходим ниже
DEC B ;пропускаем еще два ряда пикселей
DEC B
POP AF ;восстанавливаем в аккумуляторе
; параметр наклона
PUSH AF
ADD A,C ;смещаем X-координату для
LD C,A ; получения наклона
POP AF
DEC D ;повторяем заданное параметром
JR NZ,CICL2 ; «высота» количество раз
POP HL ;восстанавливаем адрес в блоке данных
JR CICL1 ;переходим на начало
; Подпрограмма рисования одной горизонтальной линии
DRAW PUSH BC ;сохраняем нужные регистры
PUSH DE ; в машинном стеке
CALL 8933 ;ставим точку с координатами
; из регистров B и C
POP DE ;регистр E нам понадобится,
; поэтому восстанавливаем
PUSH DE ; и снова сохраняем
EXX
PUSH HL ;сохраняем регистровую пару HL'
EXX
LD C,E ;длина линии (горизонтальное смещение)
LD B,0 ;вертикальное смещение - 0 (линия
; идет горизонтально)
LD DE,#101 ;положительное значение
; для обоих смещений
CALL 9402 ;рисуем линию
EXX
POP HL ;восстанавливаем регистры из стека
EXX
POP DE
POP BC
RET
; Блоки данных для рисования букв
; буква «Н»
DATA DEFB 0,0,12,6,2,0
DEFB 20,6,2,14,2,0
DEFB 0,20,12,10,2,0
; буква «А»
DEFB 0,46,12,4,1,-1
DEFB 0,46,12,10,1,1
DEFB 24,42,2,16,1,0
; буква «Р»
DEFB 0,72,12,10,3,0
DEFB 0,82,2,13,3,0
DEFB 24,82,2,13,3,0
DEFB 4,96,1,2,3,0
DEFB 24,96,1,2,3,0
DEFB 8,92,4,8,3,0
; буква «Д»
DEFB 0,112,10,4,6,-1
DEFB 0,112,10,10,6,1
DEFB 40,100,2,34,6,0
; буква «Ы»
DEFB 0,139,12,10,4,0
DEFB 16,150,2,13,4,0
DEFB 40,150,2,13,4,0
DEFB 20,163,1,2,4,0
DEFB 40,163,1,2,4,0
DEFB 24,160,4,8,4,0
DEFB 0,167,4,8,4,0
DEFB 16,169,1,6,4,0
DEFB 20,171,6,4,4,0
DEFB 44,169,1,6,4,0
DEFB -1 ;указатель конца блока данных
Не решите нечаянно, что таким методом допускается рисовать исключительно буквы. В заставке и, безусловно, в других частях программы ему найдется немало областей применения, например, для создания всевозможных орнаментов, статических рисунков, а если ее слегка дополнить, то возможно даже создавать элементы игрового пространства, скажем, лабиринты.
LD B,50 ;количество сдвигов
LOOP PUSH BC ;сохраняем содержимое регистра B
.......... ;процедура скроллинга
POP BC ;восстанавливаем регистр B
DJNZ LOOP
RET
До того, как мы приступим к детальному описанию процедуры скроллинга окна вверх, желательно рассмотреть все команды и подпрограммы ПЗУ, которые встречаются здесь впервые. Таких наберется всего две: чрезвычайно полезная команда LDIR, перемещающая блок памяти с инкрементом (т. е. с увеличением содержимого регистров, в которых записаны адреса пересылок) и подпрограмма ПЗУ, расположенная по адресу 8880. Рассмотрим их в том порядке, как они встречаются в программе.
Процедура 8880 вычисляет адрес байта в видеобуфере по координатам точки, заданным в пикселях. Началом отсчета считается левый верхний угол экрана. Таким образом, входными данными к подпрограмме являются:
MET LD A,(HL)
LD (DE),A
INC HL
INC DE
DEC BC
LD A,B
OR C
JR NZ,MET
RET
Глядя на этот фрагмент, можно заметить очевидные достоинства команды LDIR: в цикле изменяется регистр A, а в LDIR он не затрагивается, кроме того, программа занимает 8 строк текста вместо одной и работает примерно в два с половиной раза медленнее.
Если в программу ввести исходные данные, то может получиться эффект, который мы наблюдаем в некоторых играх, например, в SOKOBAN'е. Суть его состоит в том, что из ПЗУ с адреса 0 переписываются 6144 байта в область экранной памяти, начиная с адреса 16384. Если это действие повторять в цикле, то создастся впечатление бегущей по экрану ряби:
LD BC,6144
LD HL,0
LD DE,16384
LD A,255
MET PUSH BC
PUSH DE
PUSH HL
LDIR
POP HL
POP DE
POP BC
INC HL
DEC A
JR NZ,MET
RET
Кроме рассмотренной команды LDIR в ассемблерных программах довольно широко используются и другие команды пересылок байтов:
LDI - пересылка содержимого одной ячейки памяти с инкрементом. Байт из ячейки, адресуемой регистровой парой HL, переносится в ячейку, адресуемую парой DE; содержимое HL и DE увеличивается на 1, а BC уменьшается на 1. Если в результате выполнения команды BC=0, то флаг P/V сбрасывается, в противном случае P/V=1.
LDD - пересылка содержимого одной ячейки памяти с декрементом. Действие аналогично команде LDI, только содержимое регистровых пар HL и DE уменьшается на 1.
SCR_UP LD A,(COL)
LD C,A
LD A,(HGT)
LD B,A
LD A,(ROW)
; Значения из переменных ROW, COL и HGT умножаем на 8,
; то есть переводим знакоместа в пиксели
SLA A
SLA A
SLA A
SLA B
SLA B
SLA B
DEC B ;потому что один ряд пикселей просто
; заполняется нулями
SLA C
SLA C
SLA C
PUSH AF
PUSH BC
CALL 8880 ;вычисляем адрес верхнего левого угла окна
POP BC
POP AF
SCRUP1 INC A ;следующий ряд пикселей
PUSH AF
PUSH BC
PUSH HL
CALL 8880 ;вычисляем адрес
POP DE
PUSH HL
LD A,(LEN) ;пересылаем столько байт, сколько
; умещается по ширине окна
LD C,A
LD B,0
LDIR
POP HL
POP BC
POP AF
DJNZ SCRUP1
LD (HL),0 ;в последний ряд пикселей записываем нули
LD D,H
LD E,L
INC DE
LD A,(LEN) ;по ширине окна,
DEC A ; минус 1
RET Z ;выходим, если только одно знакоместо
LD C,A
LD B,0
LDIR ;иначе обнуляем и все остальные байты ряда
RET
Обратите особое внимание на последние строки процедуры, где в нижний ряд пикселей записываются нулевые байты. Этот прием весьма распространен и применяется для заполнения любой области памяти произвольным значением. Чтобы понять идею, нужно хорошо представлять, как работает команда LDIR. Сначала в первый байт массива, адресуемый парой HL, заносится какой-то определенный байт, в DE переписывается значение из HL и увеличивается на 1, в BC задается уменьшенный на единицу размер заполняемого массива, а дальше с выполнением команды LDIR происходит следующее. Байт из первого адреса (HL) переписывается во второй (DE), затем DE и HL увеличиваются, то есть HL будет указывать на второй байт, а DE - на третий. На следующем круге число из второго адреса пересылается в третий, но после первого выполнения цикла второй байт уже содержит ту же величину, что и первый, поэтому второй и третий байты к этому моменту станут равны первому. И так далее, до заполнения всего массива.
Практическое применение такому методу найти нетрудно. Кроме процедур вертикального скроллинга окон он может использоваться, например, для очистки экрана, инициализации блоков данных и других нужд. Попробуйте сами написать процедуру, аналогичную оператору CLS, в которой участвовала бы команда LDIR.
Вернемся к рассмотрению подпрограмм скроллингов окон. Процедура сдвига окна вниз во многом похожа на предыдущую:
SCR_DN LD A,(COL)
LD C,A
LD A,(HGT)
LD B,A
LD A,(ROW)
ADD A,B ;начинаем перемещать изображение не
; сверху, как в SCR_UP, а снизу
SLA A
SLA A
SLA A
DEC A
SLA B
SLA B
SLA B
DEC B
SLA C
SLA C
SLA C
PUSH AF
PUSH BC
CALL 8880
POP BC
POP AF
SCRDN1 DEC A ;следующий ряд пикселей (идем вверх)
PUSH AF
PUSH BC
PUSH HL
CALL 8880
POP DE
PUSH HL
LD A,(LEN)
LD C,A
LD B,0
LDIR
POP HL
POP BC
POP AF
DJNZ SCRDN1
LD (HL),0
LD D,H
LD E,L
INC DE
LD A,(LEN)
DEC A
RET Z
LD C,A
LD B,0
LDIR
RET
Теперь приведем подпрограмму, выполняющую скроллинг окна влево. Она уже совсем не похожа на предшествующие, но в принципе повторяет известную вам процедуру SCRLIN, описанную в разделе «Бегущая строка» предыдущей главы. Но это и понятно: ведь там мы также скроллировали окно, только оно имело фиксированные размеры в одно знакоместо высотой и 32 - шириной. Здесь же мы приводим универсальную процедуру, но и с ее помощью можно получить тот же эффект.
SCR_LF LD A,(HGT) ;количество повторений такое же,
LD B,A ; сколько строк занимает окно
LD A,(ROW) ;номер верхней строки
SCRLF1 PUSH AF ;дальше все очень похоже на процедуру SCRLIN
PUSH BC
CALL 3742
LD A,(COL)
LD B,A
LD A,(LEN)
DEC A
ADD A,B
ADD A,L
LD L,A
LD B,8
SCRLF2 PUSH HL
LD A,(LEN)
AND A
SCRLF3 RL (HL)
DEC HL
DEC A
JR NZ,SCRLF3
POP HL
INC H
DJNZ SCRLF2
POP BC
POP AF
INC A
DJNZ SCRLF1
RET
И наконец, для полного комплекта, напишем соответствующую подпрограмму, выполняющую скроллинг окна вправо:
SCR_RT LD A,(HGT)
LD B,A
LD A,(ROW)
SCRRT1 PUSH AF
PUSH BC
CALL 3742
LD A,(COL)
ADD A,L
LD L,A
LD B,8
SCRRT2 PUSH HL
LD A,(LEN)
AND A
SCRRT3 RR (HL)
INC HL
DEC A
JR NZ,SCRRT3
POP HL
INC H
DJNZ SCRRT2
POP BC
POP AF
INC A
DJNZ SCRRT1
RET
А сейчас рассмотрим программу, в которой демонстрируются возможности вертикального скроллинга вверх. После запуска вы увидите две быстро сменяющие друг друга картинки: сначала весь экран заполняется красивым орнаментом (фактурой), а затем средняя его часть стирается процедурой очистки окна. После этого строка за строкой снизу вверх начнет медленно перемещаться текст с правилами игры (рис. 6.6), который обычно вызывается из меню как один из кадров заставки.

Рис. 6.6. Правила игры
Перед запуском ассемблерной программы следует с адреса 64768 загрузить набор русских букв, однако при желании вы можете использовать и аналогичные латинские, выполнив некоторые изменения в программе. О том, как это сделать, вполне достаточно сказано в четвертой главе.
ORG 60000
ENT $
; Задание адресов новых фонтов и постоянных атрибутов экрана
LATF EQU 64000-256
RUSF EQU LATF+768
LD A,6
LD (23693),A
LD A,0
CALL 8859
CALL 3435
LD A,2
CALL 5633
; Ввод символа UDG для рисования фактуры
LD HL,UDG
LD (23675),HL
; Заполнение всего экрана фактурой
CALL DESK
; Начало основной программы
LD HL,RUSF
LD (23606),HL
NEW LD HL,TEXT
CYCLE1 CALL PRINT
LD B,10
CYCLE2 PUSH HL
PUSH BC
CALL SCR_UP
CALL PAUSE
POP BC
POP HL
JR Z,EXIT
DJNZ CYCLE2
LD A,(HL)
AND A
JR NZ,CYCLE1
LD B,80 ;расстояние между текстами
CYCLE3 PUSH BC
CALL SCR_UP
CALL PAUSE
POP BC
JR Z,EXIT
DJNZ CYCLE3
JR NEW
; Восстановление стандартного набора символов и выход
EXIT LD HL,15360
LD (23606),HL
RET
; Для того, чтобы строки выводимого текста можно было успеть прочитать,
; в цикл вставлена подпрограмма задержки, а нажав клавишу Space,
; можно в любой момент завершить работу программы.
PAUSE LD BC,6
CALL 7997
LD A,(23560)
CP " "
RET
; Подпрограмма печати строки текста
PRINT PUSH BC
LD DE,PAR
LD BC,5
CALL 8252
LD B,24 ;число символов в строке
PR_CI LD A,(HL)
RST 16
INC HL
DJNZ PR_CI
POP BC
RET
PAR DEFB 22,15,4,16,0
; Подпрограмма заполнения экрана фактурой
DESK LD BC,704
LD A,#14
RST 16
LD A,1
RST 16
DESK1 LD A,144
RST 16
DEC BC
LD A,B
OR C
JR NZ,DESK1
LD A,#14
RST 16
LD A,0
RST 16
; Создание в фактуре окна для вывода текста
CALL CLSV
CALL SETV
RET
; Подпрограммы
CLSV .........
SETV .........
SCR_UP .........
; Данные для окна с текстом
COL1 DEFB 4
ROW1 DEFB 4
LEN1 DEFB 24
HGT1 DEFB 12
ATTR DEFB %01000010
; Данные для окна в фактуре
COL DEFB 3
ROW DEFB 3
LEN DEFB 26
HGT DEFB 13
; Данные для выводимого в окно текста
TEXT DEFM "····P·I·R·A·M·I·D·A·····"
DEFM "························"
DEFM "Celx igry sostoit w tom,"
DEFM "~toby··perwym··postawitx"
DEFM "swoi··fi{ki··na··wer{inu"
DEFM "piramidy. Dlq |togo nuv-"
DEFM "no ispolxzowatx gorizon-"
DEFM "talxnye··i··wertikalxnye"
DEFM "peredwiveniq fi{ek,krome"
DEFM "togo,velatelxno wospolx-"
DEFM "zowatxsq··dopolnitelxny-"
DEFM "mi prodwiveniqmi,···sutx"
DEFM "kotoryh··sostoit··w tom,"
DEFM "~toby sostawitx fi{ki··w"
DEFM "wide treugolxnika, posle"
DEFM "~ego sdelatx hod werhnej"
; При желании текст можно продолжить
DEFB 0
; Данные для фактуры вокруг окна
UDG DEFB 248,116,34,71,143,7,34,113
Два вида горизонтального скроллинга продемонстрируем на примере еще одной программы, где эти процедуры действуют одновременно. Сразу после запуска программа создает на экране фрагмент средневекового замка из красного кирпича с зубчатыми стенами и бойницами, а в средней его части - ажурные ворота. До тех пор, пока никакая клавиша не нажата, изображение неподвижно. После нажатия любой из них створки ворот начинают медленно расходиться в разные стороны (рис. 6.7), создавая совершенно бесподобный эффект.

Рис. 6.7. Раскрытие ворот замка скроллингом окон
А теперь перейдем непосредственно к программе.
ORG 60000
ENT $
; Подготовка экрана
LD A,7
LD (23693),A
XOR A
CALL 8859
CALL 3435
LD A,2
CALL 5633
; Назначение нового адреса символов UDG
LD HL,UDG
LD (23675),HL
; Вывод на экран изображения крепостной стены с воротами
CALL SCRN
LD BC,0
CALL 7997
; Основная часть программы, в которой створки ворот
; со стуком разъезжаются в разные стороны
LD B,64
MAIN PUSH BC
CALL SCR_LF
LD A,0
OUT (254),A
CALL SCR_RT
LD A,16
OUT (254),A
LD BC,6
CALL 7997
POP BC
DJNZ MAIN
RET
; Формирование изображения крепостной стены с воротами:
; Изображение стены
SCRN LD DE,D_WALL
LD BC,7
CALL 8252
LD BC,384
SCRN1 LD A,147
RST 16
DEC BC
LD A,B
OR C
JR NZ,SCRN1
; Зеленая трава
LD DE,D_GRAS
LD BC,5
CALL 8252
LD B,32
SCRN2 LD A," "
RST 16
DJNZ SCRN2
; Зубцы на стене
LD BC,#400 ;AT 4,0
CALL PR_AT
LD B,16
SCRN3 LD DE,D_BATT
PUSH BC
LD BC,10
CALL 8252
POP BC
DJNZ SCRN3
; Ворота
LD BC,#908 ;AT 9,8
CALL PR_AT
LD B,16
SCRN4 LD A," "
RST 16
DJNZ SCRN4
; Бойницы
LD H,4
SCRN5 LD A,H
ADD A,7
LD B,A
LD C,4
CALL PR_AT
LD A," "
RST 16
LD C,27
CALL PR_AT
LD A," "
RST 16
DEC H
JR NZ,SCRN5
; Штыри решетки
LD A,16
RST 16
LD A,5
RST 16
LD B,10 ;Y
LD H,8
SCRN6 LD L,16
LD C,8 ;X
SCRN7 CALL PR_AT
LD A,145
RST 16
INC C
DEC L
JR NZ,SCRN7
INC B
DEC H
JR NZ,SCRN6
; Пики решетки
LD BC,#A08 ;AT 10,8
CALL PR_AT
LD B,16
SCRN8 LD A,144
RST 16
DJNZ SCRN8
; Узор решетки
LD L,2
LD B,13
SCRN9 LD C,8
CALL PR_AT
LD B,16
SCRN10 LD A,146
RST 16
DJNZ SCRN10
LD B,16
DEC L
JR NZ,SCRN9
RET
; Подпрограмма позиционирования вывода спрайтов
PR_AT LD A,22
RST 16
LD A,B
RST 16
LD A,C
RST 16
RET
; Подпрограммы скроллинга окон
SCR_LF ........
SCR_RT ........
; Данные для левого окна
COL DEFB 8
ROW DEFB 10
HGT DEFB 8
LEN DEFB 8
; Данные для правого окна
COL1 DEFB 16
ROW1 DEFB 10
LEN1 DEFB 8
HGT1 DEFB 8
; Данные для рисования крепостной стены и решетки
UDG DEFB 34,34,34,119,34,34,34,34 ;пики (144)
DEFB 34,34,34,34,34,34,34,34 ;штыри (145)
DEFB 54,42,170,255,170,42,54,34 ;узор (146)
DEFB 255,2,2,2,255,32,32,32 ;кирпич (147)
; Данные позиционирования печати
D_BATT DEFB 17,2,16,7,147,147,17,0,32,32
D_WALL DEFB 22,6,0,17,2,16,7
D_GRAS DEFB 22,18,0,17,4
В качестве «случайных» чисел довольно часто используют последовательность кодов ПЗУ. Такой метод крайне прост и дает неплохую степень случайности в циклах. Если вы не забыли, именно такой метод мы применили в программе «растворения» символов, описанной в предыдущей главе. Сейчас же мы расскажем и о некоторых других способах получения псевдослучайных чисел.
Иногда «случайные» числа извлекают из системного регистра регенерации R. Поскольку его значение постоянно увеличивается после выполнения каждой команды микропроцессора, предугадать, что же он содержит в какой-то момент времени практически невозможно. Таким образом, простейший генератор случайных чисел может выглядеть так:
LD A,R
Но помните, что это справедливо только для достаточно разветвленных программ, особенно если их работа зависит от внешних воздействий (например, при управлении с помощью клавиатуры или джойстика). В коротких же циклах ни о какой непредсказуемости говорить не приходится.
Кроме того, есть и еще один недостаток использования регистра регенерации. Значение его никогда не превышает 127. Иными словами, седьмой бит этого регистра обычно «сброшен» в 0, и, дойдя до значения 127, он вновь обнуляется.
Однако, справедливости ради, стоит заметить, что это относится лишь к тем программам, в которых регистр R не изменяется принудительным образом. При желании вы можете установить его 7-й бит и тогда постоянно будете получать из него значения от 128 до 255. Правда, делается это обычно в целях защиты программ (например, такой метод применен в игре NIGHT SHADE), но это уже совсем другая тема.
Когда требуется получить наибольшую степень случайности, прибегают к математическим расчетам. Разберем одну из таких «математических» подпрограмм. Несмотря на ее простоту, она вырабатывает все же достаточно длинную последовательность неповторяющихся значений, чтобы их можно было рассматривать в качестве случайных.
RND255 PUSH BC
PUSH DE
PUSH HL
; Регистровая пара HL загружается значением из счетчика «случайных» чисел
; (это может быть, например, системная переменная 23670/23671,
; которая используется Бейсиком для тех же целей)
LD HL,(ADDR)
LD DE,7 ;дальше следует расчет очередного
; значения счетчика
ADD HL,DE
LD E,L
LD D,H
ADD HL,HL
ADD HL,HL
LD C,L
LD B,H
ADD HL,HL
ADD HL,BC
ADD HL,DE
LD (ADDR),HL ;сохранение значения счетчика «случайных»
; чисел для последующих расчетов
LD A,H ;регистр A загружается значением
; старшего байта счетчика
POP HL
POP DE
POP BC
RET
ADDR DEFW 0
Эта процедура возвращает в аккумуляторе «случайные» числа от 0 до 255. Однако в подавляющем большинстве случаев нужно иметь возможность получать значения из произвольного диапазона. С этой целью дополним подпрограмму RND255 расчетами по ограничению максимального значения и назовем новую процедуру просто RND. Перед обращением к ней в регистре E задается верхняя граница вырабатываемых «случайных» чисел. Например, для получения в аккумуляторе числа от 0 до 50 в регистр E нужно загрузить значение 51:
RND CALL RND255
LD L,A
LD H,0
LD D,H
CALL 12457
LD A,H
RET
RND255 .........
Здесь вновь появилась еще одна подпрограмма ПЗУ, расположенная по адресу 12457. Она выполняет целочисленное умножение двух чисел, записанных в регистровых парах DE и HL. Произведение возвращается в HL. Если в результате умножения получится число, превышающее 65535, то будет установлен флаг CY, иначе выполняется условие NC. Проверка переполнения может оказаться полезной, когда перемножаются не известные заранее величины. В подпрограмме RND это условие проверять не нужно, так как оба сомножителя не превышают величины 255 (H и D предварительно обнуляются).
После того, как мы получили в свое распоряжение подпрограмму генерации случайных чисел, рассмотрим один занимательный пример ее применения. Представьте себе некое подобие мишени, состоящей, как и положено, из окружностей и ряда цифр, характеризующих заработанные вами очки при попадании в ту или иную ее часть. Вы нажимаете любую клавишу компьютера и в ту же секунду раздается звук, очень похожий на пролетающую мимо вашего уха пулю, а в мишени появляется отверстие с рваными краями. Нажимаете еще раз - снова попадание, но уже совсем в другом месте (рис. 6.8) и изображение отверстия тоже стало каким-то другим. Повторив эту процедуру много раз, вы легко можете убедиться в том, что «пули», как и при настоящей стрельбе, ложатся на мишень совершенно случайно. То же самое можно сказать и о характере отверстий. Отсюда ясно, что программа, реализующая эту игрушку, должна вырабатывать для каждого выстрела три случайных числа: координаты X и Y места попадания и номер изображения для пулевого отверстия. Теперь можно обратиться к самой программе и кратко ее прокомментировать.

Рис. 6.8. Программа МИШЕНЬ
ORG 60000
ENT $
; Задание постоянных атрибутов экрана
LD A,7
LD (23693),A
XOR A
CALL 8859
CALL 3435
LD A,2
CALL 5633
; Ввод символов UDG - три «пулевые отверстия»
LD HL,UDG
LD (23675),HL
; Основная часть программы
CALL MISH ;рисование мишени
MAIN CALL WAIT ;ожидание нажатия любой клавиши
CP " "
RET Z
LD A,22
RST 16
LD E,20 ;задание диапазона для координаты Y
CALL RND
RST 16
LD E,30 ;задание диапазона для координаты X
CALL RND
RST 16
LD A,16
RST 16
LD A,6
RST 16
LD E,3 ;задание номера «пулевого отверстия»
CALL RND
ADD A,144 ;вычисление кода спрайта
RST 16
CALL SND ;звуковой сигнал
JR MAIN
; Подпрограмма вывода на экран мишени
MISH LD C,20
CALL CIRC
LD C,40
CALL CIRC
LD C,60
CALL CIRC
LD C,80
CALL CIRC
LD DE,TEXT
LD BC,LENTXT
JP 8252
; Подпрограмма рисования окружностей
CIRC EXX
PUSH HL
EXX
PUSH BC
LD A,120
CALL 11560
LD A,90
CALL 11560
POP BC
LD B,0
CALL 11563
CALL 9005
EXX
POP HL
EXX
RET
; Подпрограмма остановки счета
WAIT XOR A
LD (23560),A
WAIT1 LD A,(23560)
AND A
JR Z,WAIT1
RET
; Подпрограммы
RND .........
SND LD B,80
LD HL,150
LD DE,1
SND1 .........
; Данные для мишени
TEXT DEFB 22,10,14
DEFM "10"
DEFB 22,10,18
DEFM "8"
DEFB 22,10,21
DEFM "6"
DEFB 22,10,23
DEFM "4"
DEFB 22,10,11
DEFM "8"
DEFB 22,10,8
DEFM "6"
DEFB 22,10,6
DEFM "4"
LENTXT EQU $-TEXT
; Данные для «пулевых отверстий»
UDG DEFB 4,20,62,60,127,60,40,8
DEFB 9,95,252,63,126,44,8,8
DEFB 16,48,244,63,28,56,28,8
Что касается окон, то в принципе этот вопрос нами уже решен и можно было бы к нему вновь не возвращаться. Однако использование подпрограмм, работающих с окнами в том виде, в котором мы их предложили ранее, не всегда удобно. Если все параметры окон фиксированы, то нелепо каждый раз переопределять переменные ROW, COL и иже с ними. Лучше составить блоки данных, содержащие сведения о размерах, местоположении и всех прочих характеристиках, а затем выполнять любые преобразования окон, передавая подпрограммам единственное значение - адрес таблицы параметров (то бишь блока данных).
В начале книги мы говорили о существовании такой группы регистров, как индексные. Группа эта немногочисленна и включает в себя лишь два регистра: IX и IY. Как мы уже сообщали, оба они состоят из 16 бит и разделить их на половинки «законными» методами невозможно, поэтому они обычно рассматриваются не как регистровые пары, а как отдельные регистры.
Но для каких целей они существуют, в каких ситуациях их удобно применять и в каких группах команд они могут встречаться? Обычно эти регистры используются при обработке массивов, блоков данных или таблиц, а употребляются они практически во всех типах команд, в которых может принимать участие регистровая пара HL. За более подробной информацией на этот счет можете обратиться к Приложению I, где в алфавитном порядке приведены все команды микропроцессора.
Известно, что в Бейсике к любому элементу массива можно обратиться по индексу, например, оператор LET b=a(8) присвоит переменной b значение 8-го элемента массива a(). В ассемблере подобная запись может выглядеть так:
LD B,(IX+7)
Обратите внимание, что первый элемент массива имеет индекс 0, а не 1. В отличие от массивов Бейсика, максимальный индекс у регистров IX и IY не может превышать 127, но зато допускаются отрицательные значения номера элемента массива. Таким образом, общий размер адресуемой области составляет 256 байтовых элементов, а индексный регистр указывает на его «середину».
Реальным примером большой структуры данных могут служить системные переменные Бейсика. Обычно они адресуются регистром IY, который указывает на переменную ERR_NR, находящуюся по адресу 23610. Кстати, именно в связи с этим регистр IY лучше оставить в покое и никак не изменять его в своих программах, по крайней мере, до тех пор, пока вы так или иначе используете операционную систему компьютера. Что касается регистра IX, то им вы можете смело пользоваться при любых обстоятельствах.
Наверное, лучше всего объяснить идею применения индексных регистров на конкретном примере. В качестве такого примера приведем уже знакомые вам процедуры очистки окон и установки в них постоянных атрибутов (тем более, что они понадобятся при составлении программы многокадровой заставки), но графические переменные заменим единой структурой, первый элемент которой адресуем через IX. Саму же структуру оставим без изменения, то есть на первом месте (по смещению 0, задаваемом как IX+0 или просто IX) по-прежнему будет находиться параметр COL, на втором (задаваемом как IX+1) - ROW, дальше LEN, HGT и ATTR. А чтобы новые процедуры отличить от описанных выше, изменим их имена на SETW и CLSW:
SETW LD DE,#5800
LD B,(IX+3) ;HGT
LD C,(IX+2) ;LEN
LD A,(IX+1) ;ROW
LD L,A
LD H,0
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,HL
ADD HL,DE
LD A,L
ADD A,(IX) ;COL
LD L,A
LD A,(IX+4) ;ATTR
SETW1 PUSH BC
PUSH HL
SETW2 LD (HL),A
INC HL
DEC C
JR NZ,SETW2
POP HL
POP BC
LD DE,32
ADD HL,DE
DJNZ SETW1
RET
; -----------------
CLSW LD B,(IX+3) ;HGT
LD C,(IX+2) ;LEN
LD A,(IX+1) ;ROW
CLSW1 PUSH AF
PUSH BC
PUSH DE
CALL 3742
POP DE
LD A,L
ADD A,(IX) ;COL
LD L,A
LD B,8
CLSW2 PUSH HL
PUSH BC
LD B,C
CLSW3 LD (HL),0
INC HL
DJNZ CLSW3
POP BC
POP HL
INC H
DJNZ CLSW2
POP BC
POP AF
INC A
DJNZ CLSW1
RET
Сравнив эти подпрограммы с SETV и CLSV, вы найдете много общего. Собственно, отличаются они друг от друга только способом передачи параметров. И это лишний раз доказывает, насколько ассемблер гибче всех прочих языков программирования - всякий раз вы можете использовать совершенно новые или видоизмененные процедуры, наиболее пригодные для применения именно в данном конкретном случае.
Составим блоки данных, включающих в себя по пять известных вам параметров для пяти различных окон, которые будут появляться на экране:
WIN0 DEFB 5,0,23,3,%01001110 WIN1 DEFB 8,6,17,13,%01010111 WIN2 DEFB 13,5,13,15,%01011110 WIN3 DEFB 13,9,13,11,%01101000 WIN4 DEFB 6,5,12,15,%01110101Теперь перед обращением к процедурам SETW и CLSW достаточно в регистр IX записать адрес соответствующего блока и окно появится на экране. Напишем подпрограмму формирования окна заданных размеров и черной «тени» под ним:
WINDOW INC (IX) ;смещаем окно вправо (COL)
INC (IX+1) ; и вниз (ROW)
LD A,(IX+4) ;ATTR
PUSH AF
LD (IX+4),1 ;байт атрибутов для «тени»
CALL SETW ;изменяем только атрибуты
DEC (IX) ;возвращаем окно на прежнее место
DEC (IX+1)
POP AF
LD (IX+4),A ;восстанавливаем байт атрибутов
CALL CLSW ;очищаем окно
CALL SETW ;окрашиваем заданным цветом
CALL BOX ;рисуем рамку вокруг окна
RET
; Подпрограмма, рисующая рамку вокруг окна
BOX LD A,(IX+1) ;ROW
PUSH AF
CALL 3742 ;вычисляем адрес экрана
LD A,L
ADD A,(IX) ;COL
LD L,A
LD B,(IX+2) ;LEN
BOX1 LD (HL),255 ;проводим верхнюю линию
INC HL
DJNZ BOX1
LD B,(IX+3) ;HGT
POP AF
BOX2 PUSH AF ;по точкам рисуем боковые линии
; сверху вниз
PUSH BC
CALL 3742
LD A,L
ADD A,(IX)
LD L,A
LD B,8
BOX3 PUSH HL
LD A,(HL)
OR 128 ;левая точка
LD (HL),A
LD A,(IX+2)
ADD A,L
DEC A
LD L,A
LD A,(HL)
OR 1 ;правая точка
LD (HL),A
POP HL
INC H
DJNZ BOX3
POP BC
POP AF
INC A
DJNZ BOX2
DEC H
LD B,(IX+2) ;LEN
BOX4 LD (HL),255 ;проводим нижнюю линию
INC HL
DJNZ BOX4
RET
Начало программы традиционное - задание постоянных атрибутов экрана и окрашивание бордюра. Ну, а чтобы тексты выглядели более привлекательно, обратимся к уже известной процедуре утолщения символов - BOLD.
ORG 60000
ENT $
LD A,38
LD (23693),A
LD A,4
CALL 8859
CALL BOLD
Затем сформируем окно, в которое должно быть помещено название игры (рис. 6.9), а в нижней части заставки напечатаем принятый в таких случаях текст «Select options 0 to 4» («Выберите опции от 0 до 4»). Поскольку к метке MENU программа будет неоднократно возвращаться из кадров, то чтобы избежать хаотического наложения окон, целесообразно каждый раз очищать экран.

Рис. 6.9. Многокадровая заставка
MENU CALL 3435
LD A,2
CALL 5633
LD DE,TEXT5
LD BC,ENDTXT-TEXT5
CALL 8252 ;«Select options 0 to 4»
LD IX,WIN0 ;окно для названия игры
CALL CLSW
CALL SETW
CALL BOX
В сформированном окне напечатаем название игры FOOTBALL, для чего используем расширенные подпрограммой DBLSYM буквы.
LD DE,COORD ;позиционирование курсора
LD BC,TEXT-COORD
CALL 8252
LD HL,TEXT ;вывод названия игры
LD B,8
MET LD A,(HL)
PUSH HL
PUSH BC
CALL DBLSYM
POP BC
POP HL
INC HL
DJNZ MET
Сделаем для меню окно с черной тенью и поместим в него текст, в соответствии с которым вы можете обратиться к одному из четырех кадров, нажав клавиши 1-4, или начать игру, выбрав клавишу 0 (для упрощения программы нажатие 0 или 4 возвращает вас в редактор GENS4 или в Бейсик).
LD IX,WIN1 ;окно основного меню
CALL WINDOW
LD DE,TEXT1 ;текст меню
LD BC,TEXT2-TEXT1
CALL 8252
Теперь можно написать блок управления, который, как ни странно, выглядит довольно простым. Программка «крутится» в цикле, пока не нажата одна из указанных в кавычках клавиш. При нажатии же на клавишу, команда сравнения CP изменит биты флагового регистра (в частности флаг Z установится в ноль), после чего следующая команда JR Z,KADR? осуществит переход на выбранный вами кадр.
XOR A
LD (23560),A
CYCLE LD A,(23560)
CP "1"
JR Z,KADR1
CP "2"
JR Z,KADR2
CP "3"
JR Z,KADR3
CP "4"
JR Z,EXIT
CP "0"
JR NZ,CYCLE
; При нажатии на клавиши 0 или 4 восстанавливаются атрибуты экрана и стандартный
; набор символов, после чего происходит выход в редактор GENS или в Бейсик.
EXIT LD A,7
CALL 8859 ;белый бордюр
LD A,%00111000 ;стандартные атрибуты
LD (23693),A
CALL 3435
LD A,2
CALL 5633
LD HL,15360
LD (23606),HL
RET
Части программы, формирующие окна кадров и печатающие в них тексты, исключительно похожи друг на друга. Тем не менее, имеются и некоторые отличия, которые определяются конкретными данными для окон и текстов. Каждый из кадров начинается со звукового сигнала SND, о котором мы говорили в начале этой главы и заканчивается процедурой WAIT, которая фиксирует кадр на экране, позволяя увидеть его содержание и выбрать дальнейшие действия (в этой программе чисто умозрительно, за исключением клавиши Е, которая действительно возвращает вас в меню).
KADR1 CALL SND ;звуковой сигнал
LD IX,WIN2
CALL WINDOW ;вывод окна
LD DE,TEXT2 ;текст в окне
LD BC,TEXT3-TEXT2
CALL 8252
CALL WAIT ;ожидание нажатия клавиши E
JP MENU ;возврат в меню
; Формирование окна Кадра 2 и печать в нем текста
KADR2 CALL SND
LD IX,WIN3
CALL WINDOW
LD DE,TEXT3
LD BC,TEXT4-TEXT3
CALL 8252
CALL WAIT
JP MENU
; Формирование окна Кадра 3 и печать в нем текста
KADR3 CALL SND
LD IX,WIN4
CALL WINDOW
LD DE,TEXT4
LD BC,TEXT5-TEXT4
CALL 8252
CALL WAIT
JP MENU
; Подпрограмма ожидания нажатия клавиши E
WAIT XOR A
LD (23560),A
WAIT1 LD A,(23560)
CP "E"
RET Z
CP "e"
JR NZ,WAIT1
RET
SND LD B,10
LD HL,350
LD DE,4
SND1 .........
DBLSYM .........
BOLD .........
SETW .........
CLSW .........
WINDOW .........
BOX .........
; Данные для формирования окна с названием игры
WIN0 .........
; Данные для формирования всех окон с тенями
WIN1 .........
WIN2 .........
WIN3 .........
WIN4 .........
; Данные для печати названия игры
COORD DEFB 22,1,8,16,6,19,1
TEXT DEFM "FOOTBALL"
; Данные для печати текста Меню
TEXT1 DEFB 22,7,13,16,7,17,2,19,1
DEFM "M E N U"
DEFB 22,9,9
DEFM "0. START··GAME"
DEFB 22,11,9
DEFM "1. KEYBOARD"
DEFB 22,13,9
DEFM "2. JOYSTICK"
DEFB 22,15,9
DEFM "3. HI··SCORE"
DEFB 22,17,9
DEFM "4. DEMO MODE"
; Данные для печати текста Кадра 1
TEXT2 DEFB 22,6,14,17,3,16,1
DEFM "Define keys"
DEFB 22,8,15
DEFM "LEFT....O"
DEFB 22,10,15
DEFM "RIGHT...P"
DEFB 22,12,15
DEFM "UP......Q"
DEFB 22,14,15
DEFM "DOWN....A"
DEFB 22,16,15
DEFM "FIRE....M"
DEFB 22,18,16
DEFM "MENU--E"
; Данные для печати текста Кадра 2
TEXT3 DEFB 22,10,16,17,5,16,0
DEFM "Joystick"
DEFB 22,12,14
DEFM "1. KEMPSTON"
DEFB 22,14,14
DEFM "2. SINCLAIR"
DEFB 22,16,14
DEFM "3. CURSOR"
DEFB 22,18,16
DEFM "MENU--E"
; Данные для печати текста Кадра 3
TEXT4 DEFB 22,7,8,17,6,16,1
DEFM "Hi score"
DEFB 22,8,7
DEFM "PETR...726"
DEFB 22,10,7
DEFM "IGOR...694"
DEFB 22,12,7
DEFM "ALEX...605"
DEFB 22,14,7
DEFM "SERG...523"
DEFB 22,16,7
DEFM "WLAD...419"
DEFB 22,18,8
DEFM "MENU--E"
; Данные для текста под заставкой
TEXT5 DEFB 22,21,6,16,7,17,4,19,0
DEFM "Select options 0 to 4"
ENDTXT
Глава 5 |
Глава 7