; Чуточку оптимизированный и причёсанный вариант.
; Чтобы было удобнее в коде ориентироваться.
; игра обессмерчена и обнеуязвимлена, если нужна честная игра,
; найдите строки, содержащие ###, и закомментируйте/раскомментируйте нужное.


; Processor:        К1801ВМ1
; Target assembler: BKTurbo8 Cross Assembler

; ═══════════════════════════════════════════════════════════════════════════

FONT = 112276

; Переменные

F$DataBlock = 40            ; Начало блока данных
; для trap 4
F$ScrAddr   = F$DataBlock   ; адрес экрана
F$YScale    = F$DataBlock+2 ; масштаб по высоте
F$ColorMask = F$DataBlock+4 ; маска цвета
; для trap 2
F$DataAddr  = F$DataBlock+2 ; адрес данных
F$Delay     = F$DataBlock+6 ; задержка
F$Tmp       = F$DataBlock+10 ; временно храним количество символов
; для trap 0
F$GmNmColor = F$DataBlock    ; цвет цифры 2
F$GmNmAddr  = F$DataBlock+2  ; адрес с которого выводить цифру 2
F$Screen    = F$DataBlock+4  ; начало экрана
F$DataAddr2 = F$DataBlock+6  ; адрес данных
F$Color     = F$DataBlock+10 ; цвет
F$MaxScale  = F$DataBlock+12 ; макс.масштаб
F$GameNum   = F$DataBlock+14 ; цифра 2
F$Cycles    = F$DataBlock+16 ; количество циклов
F$GameAddr  = F$DataBlock+24 ; адрес с которого начинать выводить слово GAME
; для trap 10
F$Color2    = F$DataBlock+12 ; байт-заполнитель цвета линии 2
; для trap 12,22
F$YScale2   = F$DataBlock+6 ; масштаб по высоте

TopStack = 760
GameSpeed = 2
BlockBScrAddr = 100


Start0$:        jmp     NextStart$
; ───────────────────────────────────────────────────────────────────────────

DisTrap:        mov     R0, -(SP)
                mov     R1, -(SP)
                mov     R2, -(SP)
                mov     R3, -(SP)
                mov     R4, -(SP)
                mov     R5, -(SP)
                mov     14(SP), R5
                mov     -(R5), R5
                bic     #177400, R5
                call    @TrapTbl(R5)
                mov     (SP)+, R5
                mov     (SP)+, R4
                mov     (SP)+, R3
                mov     (SP)+, R2
                mov     (SP)+, R1
                mov     (SP)+, R0
VecKbdNo$:      rti
; ───────────────────────────────────────────────────────────────────────────
TrapTbl:        .word Trap00            ; Вывод слова GAME и цифры 3
                                        ; Вход: F$DataBlock - блок параметров (адрес слова и номер цифры)
                .word Trap02            ; Вывод информации на экран
                                        ; Вход: блок параметров по адресу F$DataBlock:
                                        ; .word адрес экрана
                                        ; .word адрес данных
                                        ; .word маска цвета
                                        ; .word задержка
                .word Trap04            ; Вывод символа на экран
                                        ; Вход: R2 - код символа - 20
                                        ;       R1 - адрес экрана, куда выводить
                                        ;       @#F$ScrAddr - адрес экрана, куда выводить
                                        ;       @#F$YScale - масштаб по высоте
                                        ;       @#F$ColorMask - маска цвета
                .word Trap06            ; Вывод текста сложного формата на экран
                                        ; Вход: R1 - адрес экрана
                                        ;       @#F$DataAddr2 - адрес массива данных
                .word Trap10            ; Рисует рамку заданного цвета
                                        ; Вход:R0 - адрес
                                        ;      @#F$Color, @#F$Color2 - байты заполнители цвета
                .word Trap12            ; Вывод текста
                                        ; Вход: блок параметров по адресу F$DataBlock
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
                .word Trap14            ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                .word Trap16            ; Анимация заставки
                                        ; Вход: R4 - адрес текста
                .word Trap20            ; Вывод падающей каплей буквы
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - высота падения
                                        ;       R3 - код буквы - 20
                .word Trap22            ; Вывод текста буквами тырк-тырк влево-вправо
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - адрес текста
                                        ;       @#F$ColorMask - маска цвета для 1 бита символа
                                        ;       @#F$YScale2 - масштаб по высоте
                .word Trap24            ; Вывод три зелёных полосы и на них копирайт спрайтами
                .word Trap26            ; Вывод и обработка меню
                                        ; Вход: R0 - номер начального пункта меню
                                        ;       R1 - номер последнего пункта меню
                                        ;       R4 - адрес параметров меню
                                        ; Выход: R0 - выбранный пункт меню
                .word Trap30            ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                .word Trap32            ; Вывод и обработка меню для задания управления
                                        ; Вход: R1 - количество пунктов меню
                                        ;       R2 - регистр данных
                                        ;       R3 - регистр управления
                                        ;       R4 - адрес блока параметров меню
                .word Trap34            ; Вывод спрайта на экран movом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                .word Trap36            ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                .word Trap40            ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                .word Trap42            ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                .word Trap44            ; Вспомогательная функция функции Trap46
                .word Trap46            ; Вывод звёзд на экран
off_Trp50s:     .word Trap50_1          ; Опрос клавиатуры 1
off_Trp52s:     .word Trap52_1          ; Опрос джойстика 1
                .word Trap54            ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                .word Trap56            ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта
                .word Trap60            ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана
                .word Trap62            ; Увеличение счёта
                .word Trap64            ; проверка попали ли вражеские выстрелы в объект
                                        ; Вход: R3 - адрес спрайта объекта
                                        ;       R5 - структура объекта
                .word Trap66            ; Расчёт направления выстрела вражеского объекта в игрока
                                        ; Вход: R0 - адрес экрана охранника или блока
                                        ;       R3 - адрес экрана игрока
                                        ; Выход: R3 - приращение адреса для полёта выстрела в игрока
                .word Trap70            ; Очистка экрана
                .word Trap72            ; Ждать нажатия чего-нибудь
                .word 100140            ; Trap 74 == Emt 14
                .word 0
; ───────────────────────────────────────────────────────────────────────────

NextStart$:     mov     #100112, @#30
                jmp     Init$
; ───────────────────────────────────────────────────────────────────────────
                emt     14
                mov     #strError, R1
                br      0Exit1$
; ───────────────────────────────────────────────────────────────────────────
strError:       .asciz <31>"ПРОГРАММА НЕ РАБОТОСПОСОБНА!"
strStart:       .asciz " ЗАПУСК "<265><265>" S 'ВВОД'"<12><12>
                .even

; ███████████████ S U B R O U T I N E ███████████████████████████████████████


GoExit:         trap    74              ; == EMT 14
                clr     @#320
                mov     #DisTrap, @#34  ; делаем приготовления
                mov     #1000, @#264
                mov     #233, R0
                emt     16              ; вывод символа
                mov     #40000, R0
                mov     #1000, R1

1$:             clr     (R0)+
                sob     R1, 1$
                trap    24              ; Вывод три зелёных полосы и на них копирайт спрайтами

Exit$:          mov     #strStart, R1   ; " ЗАПУСК "

0Exit1$:        clr     R2
                emt     20
                halt
; End of function GoExit


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Ждать нажатия чего-нибудь

Trap72:         bit     #100, @#177716
                beq     1$
                tst     @#177714
                beq     Trap72          ; Ждать нажатия чего-нибудь
1$:             return
; End of function Trap72


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод слова GAME и цифры 3
; Вход: F$DataBlock - блок параметров, в котором и указываются параметры вывода

Trap00:         mov     @#F$Screen, R5  ; адрес начала экрана

1$:             clr     (R5)+           ; очищаем эран
                tst     R5
                bpl     1$
                mov     #1, 00.ScaleY$  ; масштаб по высоте символа
                mov     @#F$GameAddr, R1 ; адрес начала вывода

2$:             mov     @#F$DataAddr2, R5 ; адрес адресов данных букв

3$:             mov     (R5)+, R3       ; берём очередной адрес
                beq     9$              ; 0 - конец

4$:             mov     (PC)+, R4
00.ScaleY$:     .word 0

5$:             movb    (R3), R2        ; берём очередной байт данных символа
                mov     #8., R0         ; в байте 8 бит

6$:             clr     (R1)
                rorb    R2
                bcc     7$
                mov     @#F$Color, (R1) ; цвет символа

7$:             tst     (R1)+           ; расширяем бит в слово
                sob     R0, 6$
                add     #60, R1
                sob     R4, 5$          ; масштабируем, повторяем вывод байта сколько надо
                movb    (R3)+, R0       ; вывели символ полностью?
                bne     4$              ; нет ещё - продолжаем
                mov     00.ScaleY$, R4  ; перейдём к позиции следующего символа

8$:             sub     #1000, R1
                sob     R4, 8$
                sub     #60, R1
                br      3$
; ───────────────────────────────────────────────────────────────────────────

9$:             inc     00.ScaleY$      ; увеличим масштаб
                mov     #20, R0         ; звук

10$:            mov     #100, R4
                mov     R4, R3
                mov     #320, @#177716
                sob     R3, .
                mov     #220, @#177716
                sob     R4, .
                sob     R0, 10$

                cmp     @#F$MaxScale, 00.ScaleY$ ; до предела дошли?
                bne     2$
                mov     @#F$GmNmAddr, R1 ; адрес вывода
                mov     @#F$GameNum, R0 ; что выводить
                swab    R0              ; старший байт есть?
                beq     11$             ; нету
                call    DrawDigit       ; вывод цифры
11$:            swab    R0              ; теперь младший
; End of function Trap00


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


DrawDigit:      bic     #177700, R0
                asl     R0
                mov     R0, R2
                asl     R0
                asl     R0
                add     R0, R2
                add     #FONT + <'0 - 40>*10. + 1, R2
                mov     @#F$GmNmColor, R0
2$:             mov     @#F$Cycles, R3

3$:             mov     #8., R5
                movb    (R2), R4

4$:             ror     R4
                bcs     7$
                cmp     (R1)+, (R1)+
                br      6$
; ───────────────────────────────────────────────────────────────────────────

7$:             tst     (R1)+
                bne     5$
                mov     R0, -2(R1)

5$:             tst     (R1)+
                bne     6$
                mov     R0, -2(R1)

6$:             sob     R5, 4$
                add     #40, R1
                sob     R3, 3$
                tstb    (R2)+
                bne     2$
                mov     @#F$GmNmAddr, R1
                add     #40, R1
                return
; End of function DrawDigit


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод информации на экран
; Вход: блок параметров по адресу F$DataBlock:
; .word адрес экрана
; .word адрес данных
; .word маска цвета
; .word задержка

Trap02:         mov     @#F$ScrAddr, R4 ; адрес экрана
                mov     R4, R1          ; адрес в регистр, где он используется
                mov     #40, R2         ; очищаем строку экрана

1$:             clr     (R4)+
                sob     R2, 1$
                mov     @#F$DataAddr, R5 ; адрес данных
                clr     R4
                bisb    (R5)+, R4       ; берём очередной байт
                beq     3$              ; если 0, то пропустим
                ; если не 0, то это число прокрутки экрана
2$:             call    MovAddrDnScrlUp ; Очистка следующей строки экрана и скроллинг
                sob     R4, 2$          ; скроллим экран на заданное кол-во строк

3$:             mov     R1, @#F$ScrAddr ; сохраняем новый адрес экрана
                clr     R4
                bisb    (R5)+, R4       ; берём следующий байт - смещение от левого края экрана
                clr     R3
                bisb    (R5)+, R3       ; берём следующий байт - количество символов
                mov     R4, @#F$Tmp     ; сохраняем
                mov     #300, R1        ; адрес буфера

4$:             clr     R2
                bisb    (R5)+, R2       ; берём следующий байт
                bne     5$              ; не 0 - нормально
                return                  ; 0 - конец данных
; ───────────────────────────────────────────────────────────────────────────

5$:             ; это код символа
                bpl     111$
                sub     #40, R2
111$:           asl     R2
                mov     R2, R0
                asl     R2
                asl     R2
                add     R2, R0
                add     #FONT-500, R0

                mov     R0, (R1)+       ; адрес данных символа сохраним в буфере
                sob     R3, 4$          ; и так всю строку
                clr     (R1)+           ; конец строки
                mov     R5, @#F$DataAddr ; указатель на данные сохраним

                mov     @#F$ScrAddr, R1 ; адрес экрана
                mov     #10., R5        ; это высота символа

7$:             mov     R5, -(SP)
                mov     #300, R0        ; адрес буфера
                add     @#F$Tmp, R1     ; сместимся к месту вывода строки

8$:             mov     (R0), R2        ; адрес данных символа
                beq     12$             ; 0 - конец строки
                movb    (R2), R2        ; очередные данные символа
                inc     (R0)+           ; указатель на следующий байт данных символа
                mov     #4, R3          ; байт -> в 2 слова

9$:             mov     #2, R4          ; два бита -> в байт
                clr     R5
10$:            rorb    R5
                rorb    R5
                rorb    R5
                rorb    R5
                bicb    #360, R5
                rorb    R2
                bcc     11$
                bisb    @#F$ColorMask, R5 ; маска цвета букв

11$:            sob     R4, 10$
                movb    R5, (R1)+
                sob     R3, 9$
                br      8$              ; и так, пока строку не выведем
; ───────────────────────────────────────────────────────────────────────────

12$:            bit     #77, R1         ; попали на следующую строку?
                beq     13$             ; да - переход
                bis     #77, R1         ; иначе - переход на следующую строку
                inc     R1

13$:            call    ScrlUp          ; Проверка, на границы экрана, чтоб адрес за них не вышел и скролл на 1 строку
                                        ; Вход: R1 - адрес начала следующей строки
                mov     (SP)+, R5
                sob     R5, 7$          ; и так все 8 строк символа
                mov     R1, @#F$ScrAddr ; новый адрес сохраним
                br      Trap02          ; и всё сначала
; End of function Trap02


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Очистка следующей строки экрана и скроллинг

MovAddrDnScrlUp:add     #100, R1
; End of function MovAddrDnScrlUp


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка, на границы экрана, чтоб адрес за них не вышел и скролл на 1 строку
; Вход: R1 - адрес начала следующей строки

ScrlUp:         cmp     #100000, R1     ; если адрес вышел за низ экрана
                bne     1$
                sub     #40000, R1      ; сделаем начало экрана

1$:             mov     #40, R3         ; очищаем строку экрана

2$:             clr     (R1)+
                sob     R3, 2$
                mov     @#F$Delay, R3   ; задержка
                sob     R3, .
                inc     @#177664        ; скролл вверх на 1 строку
                sub     #100, R1        ; вернёмся к началу очищенной строки
                cmp     #37700, R1      ; проверим, если вышли за верх экрана
                bne     3$
                add     #40000, R1      ; сделаем низ экрана

3$:             return
; End of function ScrlUp


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод символа на экран
; Вход: R2 - код символа - 20
;       R1 - адрес экрана, куда выводить
;       @#F$ScrAddr - адрес экрана, куда выводить
;       @#F$YScale - масштаб по высоте
;       @#F$ColorMask  - маска цвета

Trap04:         bic     #177400, R2
                asl     R2
                mov     R2, R0
                asl     R2
                asl     R2
                add     R2, R0
                add     #FONT-240, R0
                mov     #10., R5

2$:             mov     @#F$YScale, R2  ; масштаб по высоте

3$:             mov     #8., R3         ; в байте 8 бит
                movb    (R0), R4        ; берём данные

4$:             asrb    R4              ; берём бит
                bcc     5$              ; если 0, то пропускаем
                movb    @#F$ColorMask , (R1) ; иначе - рисуем точку (расширение бит в байт)

5$:             inc     R1
                sob     R3, 4$          ; и так все биты
                add     #70, R1         ; к следующей строке экрана
                sob     R2, 3$          ; масштабируем
                movb    (R0)+, R4       ; берём ещё данные
                sob     R5, 2$          ; пока не 0
                return                  ; 0 - конец, но так мы не сможем вывести знаки типа . , - (у которых вверху нули)
; End of function Trap04


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод текста сложного формата на экран
; Вход: R1 - адрес экрана
;       F$DataAddr2 - адрес массива данных

; формат:
; сперва идут два байта параметров: byte ScaleY, ColorMask
; затем данные, если 320 - то за ним снова два байта параметров
; если 377, то за ним байт - смещение по высоте в строках
; если 321..376 - то это смещение в строке + 320
; всё остальное - символы - 20

Trap06:         mov     @#F$DataAddr2, R0 ; адрес массива данных

1$:             clr     R2
                bisb    (R0)+, R2       ; берём байт
                mov     R2, @#F$YScale  ; это масштаб по высоте
                clr     R2
                bisb    (R0)+, R2       ; берём второй байт
                mov     R2, @#F$ColorMask ; это маска цвета

2$:             clr     R2
                bisb    (R0)+, R2       ; берём байт данных
                bne     3$              ; если 0,
                return                  ; то конец
; ───────────────────────────────────────────────────────────────────────────

3$:             cmp     #320, R2        ; если 320
                beq     1$              ; то снова надо брать параметры
                cmp     #377, R2        ; если 377
                bne     6$
                clr     R1
                bisb    (R0)+, R1       ; то берём следующий байт
                swab    R1              ; умножаем на 100
                ror     R1
                asr     R1
                add     @#F$ScrAddr, R1 ; прибавляем адрес экрана
                bis     #77, R1
                inc     R1              ; переводим на следующую строку экрана
                mov     R1, @#F$ScrAddr ; и сохраняем новый адрес экрана
5$:             br      2$              ; и идём за новыми данными
; ───────────────────────────────────────────────────────────────────────────

6$:             cmp     R2, #320        ; если данные меньше 320
                ble     8$              ;  переход
                sub     #320, R2        ; иначе, вычитаем 320
                add     R2, R1          ;  и это смещение в строке
7$:             br      2$              ; и идём за новыми данными
; ───────────────────────────────────────────────────────────────────────────

8$:             trap    4               ; Вывод символа на экран
                                        ; Вход: R2 - код символа - 20
                                        ;       R1 - адрес экрана, куда выводить
                                        ;       @#F$ScrAddr - адрес экрана, куда выводить
                                        ;       @#F$YScale - масштаб по высоте
                                        ;       @#F$ColorMask - маска цвета
                add     #10, R1
                br      2$
; End of function Trap06


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Рисует рамку заданного цвета
; Вход:R0 - адрес
;      @#F$Color, @#F$Color2 - байты заполнители цвета

Trap10:         mov     R0, R3
                mov     R0, R5
                bic     #177700, R5
                bis     #77, R3
                bic     R5, R3
                mov     #140000, R4
                sub     R0, R4
                add     R5, R4
                add     R5, R4
                mov     R3, R2
                add     #400, R3

1$:             sub     #400, R4
                mov     #4, R1

2$:             bit     #100, R0
                beq     3$
                mov     @#F$Color, R5
                br      4$
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     @#F$Color2, R5

4$:             movb    R5, (R0)
                movb    R5, (R2)
                movb    R5, (R3)
                movb    R5, (R4)
                add     #100, R0
                add     #100, R2
                add     #100, R3
                add     #100, R4
                sob     R1, 2$
                sub     #401, R2
                inc     R4
                cmp     R3, R4
                bne     1$
                return
; End of function Trap10


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод текста
; Вход: блок параметров по адресу F$DataBlock
; .word адрес экрана
; .word адрес данных (таблица адресов символов в шрифте)
; .word маска цвета для 1 бита символа
; .word масштаб по высоте

Trap12:         mov     @#F$YScale2, 12.ScaleY$
                mov     @#F$DataAddr, R0 ; данные
                mov     @#F$ScrAddr, R1 ; адрес экрана
                mov     R1, R5          ; сохраним тут

1$:             mov     (R0)+, R2       ; берём очередной адрес данных символа
                beq     9$              ; 0 - конец

2$:             movb    (R2)+, R4       ; данные символа

3$:             mov     #4, R3          ; расширяем байт в 2 слова

4$:             ror     (R1)
                ror     (R1)
                ror     (R1)
                ror     (R1)
                bic     #170000, (R1)   ; освобождаем место для очередных битов цвета
                ror     R4              ; смотрим бит
                bcc     5$              ; нету - 0
                bis     @#F$ColorMask, (R1) ; есть  - применяем маску цвета

5$:             sob     R3, 4$          ; и так всё слово
                tst     (R1)+           ; переходим к следующему
                mov     R1, R3
                sub     R5, R3
                bic     #177700, R3     ; посмотрим, какая уже ширина символа
                cmp     #4, R3          ; если ещё не 4 байта
                bne     3$              ; продолжаем
                mov     (PC)+, R3
12.ScaleY$:     .word 1
                beq     7$              ; 0 - не надо масштабировать

6$:             add     #74, R1         ; дублируем по высоте
                mov     -100(R1), (R1)+
                mov     -100(R1), (R1)+
                sob     R3, 6$          ; сколько надо

7$:             add     #74, R1
                mov     12.ScaleY$, R3
                inc     R3
                mov     R5, R4

8$:             add     #1000, R4        ; высота 8 строк
                sob     R3, 8$
                cmp     R1, R4
                blos    2$              ; цикл пока не выведем весь символ
                add     #4, R5          ; переход к следующему символу
                mov     R5, R1
                br      1$
; ───────────────────────────────────────────────────────────────────────────

9$:             return
; End of function Trap12


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Анимация заставки
; Вход: R4 - адрес текста
T16Buffer = 334
T16BufTxt = 340

Trap16:         mov     #44400, @#T16Buffer
                mov     #F$DataBlock, R0
                mov     #40004, (R0)+
                mov     #datText1, (R0)+ ; (C)  BIL corp.
                mov     #175000, (R0)+
                mov     #3, (R0)+
                trap    12              ; Вход: F$DataBlock - заполненный блок параметров
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в ширите)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
                mov     R4, R5          ; адрес данных
                add     #strSplashTxt1End-strSplashTxt1, R5 ; конец данных
                mov     R5, 16.DatEnd$
; тут заезжают в экран с боков буквы "**  PLANET  **"
T16TitleAddr = 64200
1$:             mov     (R4)+, R3       ; адрес данных одного символа
                mov     (R4)+, R2       ; адрес данных другого символа
                mov     #10., R1        ; высота символа
                mov     #T16BufTxt, R0  ; буфер

2$:             movb    (R3)+, (R0)+    ; копируем туда чересстрочно данные обоих символов
                movb    (R2)+, (R0)+
                sob     R1, 2$
                mov     #4, R5

3$:             mov     #T16TitleAddr + 37, R0
                mov     #T16TitleAddr + 41, R1
                mov     R4, -(SP)
                mov     R5, -(SP)

                mov     #30, R2         ; высота

4$:             mov     #17, R3         ; сдвиг побайтно
                mov     R0, R4
                mov     R1, R5
                inc     R4
                dec     R5

5$:             movb    -(R0), -(R4)    ; слева направо
                movb    (R1)+, (R5)+    ; справа налево
                movb    -(R0), -(R4)    ; слева направо
                movb    (R1)+, (R5)+    ; справа налево
                sob     R3, 5$
                movb    -(R0), -(R4)    ; слева направо
                movb    (R1)+, (R5)+    ; справа налево
                add     #41, R1
                add     #137, R0
                sob     R2, 4$
                mov     (SP)+, R5
                mov     (SP)+, R4
                mov     #T16TitleAddr, R0
                mov     #T16BufTxt, R2

6$:             clrb    (R0)
                rolb    (R2)
                bcc     7$
                bisb    #365, (R0)

7$:             rolb    (R2)+
                bcc     8$
                bisb    #17, (R0)

8$:             call    sub_3442        ; Дублируем по высоте
                sub     #101, R0
                clrb    (R0)
                rorb    (R2)
                bcc     9$
                bisb    #17, (R0)

9$:             rorb    (R2)+
                bcc     10$
                bisb    #365, (R0)

10$:            call    sub_3442        ; Дублируем по высоте
                inc     R0
                cmp     #T16TitleAddr + 3100, R0
                bge     6$
                call    sub_3462        ; Опускаем вниз копирайт "(C)  BIL corp."
                sob     R5, 3$
                cmp     (PC)+, R4
16.DatEnd$:     .word 0
                bne     1$

NextTrap16$:    mov     #Sound1$, R1
                call    Trap14          ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
; раздвигаем буквы вверх и вниз со звуком
                mov     #15, R1
                mov     #60300, R4      ; на какой адрес сдвигать верх
                mov     #71000, R5      ; на какой адрес сдвигать вниз

1$:             mov     #2000, R0       ; размер массива
                mov     R4, R2
                add     #100, R2        ; с какого адреса сдвигать вверх
                mov     R5, R3
                sub     #400, R3        ; с какого адреса сдвигать вниз
2$:             mov     (R2)+, (R4)+    ; двигаем вверх
                mov     -(R3), -(R5)    ; двигаем вниз
                sob     R0, 2$
                mov     #40, R0

3$:             clr     (R4)+
                clr     -(R5)
                clr     -(R5)
                clr     -(R5)
                clr     -(R5)
                sob     R0, 3$
                mov     #24, R2
                sub     R1, R2
                mov     #400, R3
                call    @#102062
                sub     #4200, R4
                add     #5000, R5
                sob     R1, 1$
; Вывод текста.
                mov     #F$DataBlock, R0
                mov     #64410, (R0)+
                mov     #datText3, (R0)+ ; ПРЕДСТАВЛЯЕТ
                mov     #150000, (R0)+
                mov     #3, (R0)+
                trap    12
                mov     #1, R0
                mov     #600, R1

4$:             mov     R0, R2
                mov     #220, @#177716

                sob     R2, .
                mov     R0, R2
                mov     #320, @#177716

                sob     R2, .
                inc     R0
                sob     R1, 4$
                return
; End of function Trap16


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Дублируем по высоте

sub_3442:       movb    (R0), R3
                add     #100, R0
                movb    R3, (R0)
                add     #100, R0
                movb    R3, (R0)
                return
; End of function sub_3442


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Опускаем вниз копирайт "(C)  BIL corp."

sub_3462:       mov     #4, R3
                mov     @#T16Buffer, R1

1$:             mov     R1, R0
                add     #100, R0
                mov     #1000, R2

2$:             mov     -(R1), -(R0)
                mov     -(R1), -(R0)
                sob     R2, 2$
                mov     #20, R2

3$:             clr     -(R0)
                clr     -(R0)
                sob     R2, 3$
                add     #4100, R1
                sob     R3, 1$
                mov     R1, @#T16Buffer
                return
; End of function sub_3462


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод звука
; Вход R1 - адрес таблицы параметров
; .word длит
; .word тон, тон,... (0 - конец таблицы)

Trap14:         mov     (R1)+, R5       ; длительность звуков

1$:             mov     R5, R2
                mov     (R1)+, R3       ; очередной тон
                beq     2$
                call    @#102062
                br      1$
; ───────────────────────────────────────────────────────────────────────────

2$:             return
; End of function Trap14


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод падающей каплей буквы
; Вход: R1 - адрес экрана
;       R2 - высота падения
;       R3 - код буквы - 20

Trap20:         mov     #SpriteDrop, R0
                mov     #13, R5

1$:             movb    (R0)+, (R1)
                add     #100, R1
                sob     R5, 1$
                mov     #1000, R5

                sob     R5, .
                sub     #1200, R1
                sob     R2, Trap20      ; капля падает вниз на сколько надо
                dec     R1
                mov     R1, @#F$ScrAddr
                inc     R1
                mov     #12, R5         ; стирается

2$:             clrb    (R1)+
                add     #77, R1
                sob     R5, 2$
                bic     #177400, R3
                asl     R3
                mov     R3, R0
                asl     R3
                asl     R3
                add     R3, R0
                add     #FONT-240, R0 ; получаем адрес данных буквы

4$:             mov     #50, R5         ; по этому адресу формируется массив из одного элемента
                mov     R5, @#F$DataAddr
                mov     R0, (R5)+
                clr     (R5)+
                mov     #200, R3
                mov     #30, R2
                call    @#102062        ; звук
                                        ; и выведем букву
                jmp     Trap12          ; Вывод текста
                                        ; Вход: блок параметров по адресу F$DataBlock
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
; End of function Trap20

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод текста буквами тырк-тырк влево-вправо
; Вход: R1 - адрес экрана
;       R2 - адрес текста
;       @#F$ColorMask - маска цвета для 1 бита символа
;       @#F$YScale2 - масштаб по высоте

T22Addr = 334
T22Buffer = 340

Trap22:         mov     #T22Addr, @#F$DataAddr  ; это адрес массива для trap 12
                mov     #T22Buffer-2, R0 ; тут формируем буфер
                clr     (R0)+           ; сперва 0

1$:             clr     R4
                bisb    (R2)+, R4       ;  потом адреса букв
                beq     3$              ; пока строка не кончится
                asl     R4
                mov     R4, R5
                asl     R4
                asl     R4
                add     R4, R5
                add     #FONT-240, R5
                mov     R5, (R0)+
                br      1$
; ───────────────────────────────────────────────────────────────────────────

3$:             clr     (R0)+           ; в конце тоже 0
                mov     #T22Buffer, R5  ; адрес начала массива адресов данных символов строки

2$:             mov     (R5), @#T22Addr
                mov     R1, @#F$ScrAddr
                trap    12              ; Вход: @#F$DataBlock - заполненный блок параметров
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
                tst     -(R5)
                beq     4$
                sub     #4, R1
                call    sub_4276
                br      2$

4$:             mov     R1, R3
                mov     #Sound2$, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                mov     R3, R1
                tst     (R5)+
                clr     (R5)+
                tst     (R5)
                bne     5$
7$:             return

6$:             call    sub_4276
5$:             mov     (R5)+, @#T22Addr
                add     #4, R1
                mov     R1, @#F$ScrAddr
                trap    12              ; Вывод текста
                                        ; Вход: блок параметров по адресу F$DataBlock
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
                tst     (R5)
                bne     6$
                clr     -(R5)
                tst     -(R5)
                beq     7$
                sub     #4, R1
                mov     R1, R3
                mov     #Sound2$, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                mov     R3, R1
                br      2$
; End of function Trap22


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


sub_4276:       mov     #17000, R3

                sob     R3, .
                mov     @#F$ScrAddr, R4
                mov     @#F$YScale2, R3
                inc     R3

1$:             mov     #10., R2

2$:             clr     (R4)+
                clr     (R4)
                add     #76, R4
                sob     R2, 2$
                sob     R3, 1$

3$:             return
; End of function sub_4276


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод три зелёных полосы и на них копирайт спрайтами

Trap24:         mov     #40400, R0
                mov     #40, R1
; рисуем 3 зелёных полосы
                mov     #125252, R2

1$:             mov     R2, 400(R0)
                mov     R2, 200(R0)
                mov     R2, (R0)+
                sob     R1, 1$
; Выводим спрайт BIL
                mov     #SprBIL, R0
                mov     #40137, R1
                mov     #11, R2

2$:             mov     #6, R3
                clrb    (R1)+

3$:             movb    (R0)+, (R1)+
                sob     R3, 3$
                clrb    (R1)+
                add     #70, R1
                sob     R2, 2$
; выводим спрайт (С)
                mov     #40032, R1
                mov     #13, R2

4$:             mov     #3, R3
                clrb    (R1)+

5$:             movb    (R0)+, (R1)+
                sob     R3, 5$
                clrb    (R1)+
                add     #73, R1
                sob     R2, 4$
                return
; End of function Trap24


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и обработка меню
; Вход: R0 - номер начального пункта меню
;       R1 - номер последнего пункта меню
;       R4 - адрес параметров меню
; Выход: R0 - выбранный пункт меню

T26LastMenu = 300

Trap26:         mov     #176000, @#F$ColorMask ; маска цвета
                mov     #1, @#F$YScale2 ; масштаб по Y
                mov     R4, R5          ; адрес параметров меню
; выводим меню на экран
                mov     R1, R3          ; номер последнего пункта меню
                inc     R3              ; сделаем количество пунктов меню

11$:            mov     (R5)+, @#F$ScrAddr ; адрес экрана
                mov     (R5)+, @#F$Tmp  ; ширина курсора меню в словах
                mov     R5, @#F$DataAddr ; данные пункта меню
                trap    12              ; Вход: @#F$DataBlock - заполненный блок параметров
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте

12$:            tst     (R5)+           ; пропустим текст, переходим к следующему пункту
                bne     12$
                sob     R3, 11$         ; и так выведем все пункты меню
                mov     R1, @#T26LastMenu ; сохраним номер последнего пункта меню
                mov     R5, R1          ; сразу на меню - звук
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
; выбираем нужный пункт
13$:            mov     (R4)+, @#F$ScrAddr ; адрес экрана
                mov     (R4)+, @#F$Tmp  ; ширина в словах
                call    SelectMenu

0KeybProc:      tst     @#177714        ; джойстик нажат?
                bne     6$              ; да - это ввода
                bit     #100, @#177716  ; клавиша нажата?
                bne     0KeybProc       ; нет
                mov     @#177662, R5    ; да, берём код
                cmp     #33, R5         ; стрелка вниз?
                bne     3$              ; нет
                cmp     R0, @#T26LastMenu ; мы уже на последнем пункте?
                beq     0KeybProc       ; да - нечего делать
                inc     R0              ; нет - переходим к нижнему пункту меню

1$:             tst     (R4)+
                bne     1$

2$:             mov     #Sound3$, R1    ; звук выделения текущего пункта меню
                trap    14
                call    SelectMenu      ; развыделим текущий
                br      13$             ; перейдём к следующему
; ───────────────────────────────────────────────────────────────────────────

3$:             cmp     #32, R5         ; стрелка вверх?
                bne     5$              ; нет
                tst     R0              ; мы уже на первом пункте?
                beq     0KeybProc       ; да - нечего делать
                dec     R0              ; нет - переходим к верхнему пункту меню
                sub     #12, R4         ; возвращаем указатель на начало предыдущего пункта

4$:             tst     -(R4)
                bne     4$
                tst     (R4)+
                br      2$              ; идём развыделять текущий и далее
; ───────────────────────────────────────────────────────────────────────────

5$:             cmp     #12, R5         ; ввод?
                bne     0KeybProc       ; нет

6$:             mov     R0, 14(SP)      ; возвращаем значение
                mov     #Sound4$, R1    ; звук выбора пункта меню
                jmp     Trap14          ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
; End of function Trap26


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


SelectMenu:     mov     @#F$ScrAddr, R3 ; адрес экрана
                sub     #100, R3        ; на 3 строки вверх
                mov     @#F$Tmp, R5     ; ширина в словах

4$:             mov     #24, R2         ; высота курсора меню

5$:             com     (R3)            ; выделяем
                add     #100, R3
                sob     R2, 5$
                sub     #2376, R3
                sob     R5, 4$          ; и так по всей ширине
                return
; End of function SelectMenu

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Заполнение прямоугольной области экрана заданным цветом
; Вход: R1 - адрес экрана
;       R2 - ширина в байтах
;       R3 - высота в строках / 2
;       R0,R4 - чересстрочные цвета

Trap30:         mov     R3, -(SP)

1$:             mov     R1, R5
                mov     (SP), R3

2$:             mov     R0, (R5)
                add     #100, R5
                mov     R4, (R5)
                add     #100, R5
                sob     R3, 2$
                tst     (R1)+
                sob     R2, 1$
                tst     (SP)+
                return
; End of function Trap30


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и обработка меню для задания управления
; Вход: R2 - регистр данных
;       R3 - регистр управления
;       R4 - адрес блока параметров меню

Trap32:         mov     #175000, @#F$ColorMask
                mov     #1, @#F$YScale2
                mov     R4, R5

1$:             mov     (R5)+, @#F$ScrAddr
                mov     R5, @#F$DataAddr
                trap    12              ; Вход: блок параметров по адресу F$DataBlock
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
2$:             tst     (R5)+
                bne     2$
                sob     R1, 1$
                mov     R5, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
3$:             mov     (R4)+, R5
                sub     #100, R5
                call    SelCtrlMenu
                mov     (R2), R1        ; читаем регистр данных

4$:             tst     (R3)            ; ждём нового кода
                beq     4$
                mov     (R2), (R0)+     ; помещаем новый код в таблицу
                mov     #60000, R1
                sob     R1, .

5$:             tst     (R4)+           ; переходим к следующему пункту меню
                bne     5$
                mov     #Sound6$, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                call    SelCtrlMenu
                cmp     #20, (R4)       ; до звука дошли?
                bne     3$              ; нет, значит ещё не всё
                return
; End of function Trap32


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


SelCtrlMenu:    mov     #24, R1

1$:             com     (R5)+
                com     (R5)
                add     #76, R5
                sob     R1, 1$
                sub     #2400, R5
                return
; End of function SelCtrlMenu


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод спрайта на экран movом
; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
;       R1 - адрес экрана

Trap34:         mov     (R0)+, R2       ; берём высоту
                mov     (R0)+, R3       ; берём ширину
                mov     #100, R5
                sub     R3, R5
1$:             mov     R3, R4

2$:             movb    (R0)+, (R1)+
                sob     R4, 2$
                add     R5, R1
                sob     R2, 1$
                return
; End of function Trap34


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод спрайта на экран методом наложения
; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
;       R1 - адрес экрана

Trap36:         mov     (R0)+, R2
                mov     (R0)+, R3
                mov     #100, R5
                sub     R3, R5
1$:             mov     R3, R4

2$:             bisb    (R0)+, (R1)+
                sob     R4, 2$
                add     R5, R1
                sob     R2, 1$
                return
; End of function Trap36


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Стирание спрайта с экрана методом побитовой очистки
; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
;       R1 - адрес экрана

Trap40:         mov     (R0)+, R2
                mov     (R0)+, R3
                mov     #100, R5
                sub     R3, R5
1$:             mov     R3, R4

2$:             bicb    (R0)+, (R1)+
                sob     R4, 2$
                add     R5, R1
                sob     R2, 1$
                return
; End of function Trap40


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Стирание спрайта с экрана clrом
; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
;       R1 - адрес экрана

Trap42:         mov     (R0)+, R2
                mov     (R0)+, R3
                mov     #100, R5
                sub     R3, R5
1$:             mov     R3, R4

2$:             clrb    (R1)+
                sob     R4, 2$
                add     R5, R1
                sob     R2, 1$
                return
; End of function Trap42


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вспомогательная функция функции Trap46


Trap44:         mov     (R0), R5
                beq     3$
                clrb    (R5)
                add     R2, (R0)
                bit     #77, (R0)
                beq     1$
2$:             cmp     #42300, (R0)
                bgt     1$
                cmp     #76000, (R0)
                bgt     3$
1$:             clr     (R0)
                br      4$

3$:             bisb    #140, @(R0)+

4$:             sob     R1, Trap44
                return
; End of function Trap44


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод звёзд на экран

Trap46:         tst     (PC)+
T46Counter1:    .word 7
                bne     5$
                mov     #10, T46Counter1
                mov     #T46.Arr0, R0
                mov     #T46.ArrSize, R1

1$:             tst     (R0)+
                beq     2$
                sob     R1, 1$
                br      6$
; ───────────────────────────────────────────────────────────────────────────

2$:             mov     @#177710, -(R0)
                com     #0
                beq     3$
                bic     #77, (R0)
                br      4$
; ───────────────────────────────────────────────────────────────────────────

3$:             bic     #177700, (R0)
4$:             add     #42300, (R0)

5$:             dec     T46Counter1

6$:             mov     #T46.Arr0, R0
                mov     #T46.ArrSize, R1
                mov     (PC)+, R2
T46CntVal1:     .word 101
                trap    44
                tst     (PC)+
T46Counter2:    .word 5
                bne     15$
                mov     #10, T46Counter2
                mov     #T46.Arr1, R0
                mov     #T46.ArrSize, R1

11$:            tst     (R0)+
                beq     12$
                sob     R1, 11$
                br      16$
; ───────────────────────────────────────────────────────────────────────────

12$:            mov     @#177710, -(R0)
                com     #0
                beq     13$
                bic     #77, (R0)
                br      14$
; ───────────────────────────────────────────────────────────────────────────

13$:            bic     #177700, (R0)
                add     #35000, (R0)

14$:            add     #42300, (R0)

15$:            dec     T46Counter2

16$:            mov     #T46.Arr1, R0
                mov     #T46.ArrSize, R1
                mov     (PC)+, R2
T46CntVal2:     .word 101
                trap    44
                tst     (PC)+
T46Counter3:    .word 0
                bne     23$
                mov     #10, T46Counter3
                mov     #T46.Arr2, R0
                mov     #T46.ArrSize, R1

21$:            tst     (R0)+
                beq     22$
                sob     R1, 21$
                br      24$
; ───────────────────────────────────────────────────────────────────────────

22$:            mov     @#177710, -(R0)
                bic     #77, (R0)
                add     #42300, (R0)

23$:            dec     T46Counter3

24$:            mov     #T46.Arr2, R0
                mov     #10, R1
                mov     (PC)+, R2
T46CntVal3:     .word 1
                trap    44
                tst     (PC)+
T46Counter4:    .word 2
                bne     33$
                mov     #10, T46Counter4
                mov     #T46.Arr3, R0
                mov     #10, R1

31$:            tst     (R0)+
                beq     32$
                sob     R1, 31$
                br      34$
; ───────────────────────────────────────────────────────────────────────────

32$:            mov     @#177710, -(R0)
                bic     #77, (R0)
                add     #42300, (R0)

33$:            dec     T46Counter4

34$:            mov     #T46.Arr3, R0
                mov     #10, R1
                mov     (PC)+, R2
T46CntVal4:     .word 2
                trap    44
                return
; End of function Trap46


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Установка констант для движения грунта влево

GoLeftConst:    mov     #77, T46CntVal1
                mov     #-101, T46CntVal2
                mov     #-1, T46CntVal3
                mov     #-2, T46CntVal4
                return
; End of function GoLeftConst


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Установка констант для движения грунта вправо

GoRigthConst:   mov     #101, T46CntVal1
                mov     #101, T46CntVal2
                mov     #1, T46CntVal3
                mov     #2, T46CntVal4
                return
; End of function GoRigthConst


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Опрос клавиатуры 1

Trap50_1:       bit     @#177716, #100  ; клавиша нажата?
                bne     Trap50_2        ; нет - выход
                mov     #KeyTab, R1     ; таблица управляющих клавиш
                mov     @#177662, R2    ; берём код нажатой клавиши
                mov     #GrowPlayerAddr, R3 ; Приращение адреса игрока
                cmp     R2, (R1)+       ; нажали вправо?
                bne     1$              ; нет
                add     #1, (R3)        ; двигаться вперёд

1$:             cmp     R2, (R1)+       ; нажали влево?
                bne     2$              ; нет
                add     #-1, (R3)       ; двигаться назад

2$:             cmp     R2, (R1)+       ; нажали вверх?
                bne     3$              ; нет
                add     #-400, (R3)     ; двигаться вверх

3$:             cmp     R2, (R1)+       ; нажали вниз?
                bne     4$              ; нет
                add     #300, (R3)      ; двигаться вниз

4$:             cmp     R2, (R1)+       ; нажали стрелять?
                bne     Trap50_2        ; нет
                mov     #1, FireFlag    ; Стрелять

Trap50_2:       return
; End of function Trap50_1


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Опрос джойстика 1

Trap52_1:       mov     @#177714, R2    ; берём данные с джойстика
                beq     5$              ; ничего не нажато - выход
                mov     #JoyTab, R1     ; таблица масок битов джойстика
                mov     #GrowPlayerAddr, R3 ; Приращение адреса игрока
                bit     R2, (R1)+       ; нажали вправо?
                beq     1$              ; да
                add     #1, (R3)        ; нет - компенсируем

1$:             bit     R2, (R1)+       ; нажали влево?
                beq     2$              ; да
                add     #-1, (R3)       ; нет - компенсируем

2$:             bit     R2, (R1)+       ; нажали вверх?
                beq     3$              ; да
                add     #-400, (R3)     ; нет - компенсируем

3$:             bit     R2, (R1)+       ; нажали вниз?
                beq     4$              ; да
                add     #300, (R3)      ; нет - компенсируем

4$:             bit     R2, (R1)+       ; нажали стрелять?
                beq     5$              ; нет
                mov     #1, FireFlag    ; Стрелять

5$:             return
; End of function Trap52_1

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка на коллизию.
; Вход: R0 - адрес спрайта объекта 2
;       R3 - адрес спрайта объекта 1
;       R4 - структура объекта 2
;       R5 - структура объекта 1
; Формат структуры см в другом месте

Trap54:         mov     2(SP), R5       ; восстанавливаем значение R5
                mov     (R4)+, R1       ; адрес экрана объекта 2
                mov     (R5)+, R2       ; адрес экрана объекта 1
                add     (R4), R1        ; нижняя граница 2
                cmp     R2, R1
                bpl     0Ret$           ; объект 2 выше объекта 1

1$:             sub     (R4)+, R1       ; возвращаем как было
                add     (R5), R2        ; нижняя граница 1
                cmp     R2, R1
                bmi     0Ret$           ; объект 1 выше объекта 2

2$:             sub     (R5)+, R2       ; возвращаем как было
                bic     #177700, R2     ; теперь оставим горизонтальные позиции
                bic     #177700, R1
                add     (R4), R1        ; правая граница 2
                cmp     R2, R1
                bpl     0Ret$           ; объект 2 правее объекта 1

3$:             sub     (R4)+, R1       ; возвращаем как было
                add     (R5), R2        ; правая граница 1
                cmp     R2, R1
                bpl     4$
0Ret$:          return                  ; объект 1 правее объекта 2
; ───────────────────────────────────────────────────────────────────────────
; объекты пересеклись

4$:             sub     (R5)+, R2       ; возвращаем как было
                mov     -6(R4), R1
                trap    42              ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     -6(R5), R1
                mov     R3, R0
                trap    42              ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                call    sub_22474       ; Вход: R4 - адрес структуры + 6
                mov     R5, R4
; End of function Trap54

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вход: R4 - адрес структуры + 6

sub_22474:      mov     #ScratchBufferItemsNum, R3
                mov     #ScratchBuffer+2, R0

2$:             cmp     #3000, (R0)     ; ищем в таблице разлёта осколков пустое место
                bne     1$              ; не пустое, ищем дальше
                mov     -6(R4), R1      ; берём адрес экрана
                dec     (R4)+           ; нашли, снимаем хитпоинт, для игрока происходит фиксация коллизии
                bne     3$              ; ещё живёт
                clr     -10(R4)         ; всё, умер, обнуляем адрес экрана

3$:             sub     #2, R0
                mov     (R4)+, (R0)+    ; это адрес спрайта осколков
                beq     5$              ; если 0, то без осколков
                add     (R4)+, R1       ; смещение от адреса экрана - центр разлёта осколков
                                        ; получим центр разлёта осколков
                                        ; для объекта, которого нет на экране,
                                        ; получится число за пределами экрана
                clr     (R0)+
                mov     #8., R2         ; заполняем таблицу адресов осколков

4$:             mov     R1, (R0)+
                sob     R2, 4$
                br      5$

1$:             add     #ScratchBufferItemSize, R0
                sob     R3, 2$
5$:             trap    62              ; Увеличение счёта
                return

; End of function sub_22474


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка попаданиями пулек игрока в объект
; Вход: R3 - спрайт объекта
;       R5 - структура объекта

Trap56:         mov     #PlayersBulletBuffer+2, R4
                mov     2(SP), R5       ; восстанавливаем R5
                mov     #PlayersBulletBufferItemsNum, R1
                mov     #sprBulletLt, R0 ; тут лево/ право не важно, спрайт используется для стирания

1$:             tst     (R4)
                beq     2$
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте

2$:             add     #PlayersBulletBufferItemSize, R4
                sob     R1, 1$
                return
; End of function Trap56


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод числовых значений счёта, жизней и т.п.
; Вход: R5 - адрес данных
;       R1 - адрес экрана

Trap60:         mov     2(SP), R5       ; восстанавливаем значение R5

OutLivesI$:     movb    (R5)+, R0       ; берём очередное значение, 0..9.
                cmpb    #171777, R0     ; дошли до конца?
                bne     1$              ; нет
                return
; ───────────────────────────────────────────────────────────────────────────

1$:             asl     R0              ; * 6
                mov     R0, R2
                asl     R0
                add     R2, R0
                add     #Digits$, R0
                mov     (R0)+, R2
                mov     (R0)+, R3
                mov     (R0)+, R4
                mov     R2, (R1)
                bic     #7760, R2
                mov     R2, 100(R1)
                mov     R2, 200(R1)
                mov     R2, 300(R1)
                mov     R3, 400(R1)
                mov     R4, 1000(R1)
                bic     #7760, R4
                mov     R4, 500(R1)
                mov     R4, 600(R1)
                mov     R4, 700(R1)
                add     #2, R1
                br      OutLivesI$
; End of function Trap60


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Увеличение счёта

Trap62:         com     #-1
                beq     1$
                return
; ───────────────────────────────────────────────────────────────────────────

1$:             mov     #EndScore, R0

2$:             incb    -(R0)
                cmpb    #10., (R0)
                bne     3$
                clrb    (R0)
                br      2$
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     #41002, R1
                mov     #Score, R5
                br      OutLivesI$
; End of function Trap62


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; проверка попали ли вражеские выстрелы в объект
; Вход: R3 - адрес спрайта объекта 1
;       R5 - структура объекта 1

Trap64:         mov     2(SP), R5       ; восстанавливаем значение R5
                mov     #EnemyBulletBuffer+14, R1
                mov     #EnemyBulletBufferItemsNum, R2

1$:             mov     #TmpEnmyBulltStruct+10, R4 ; формируем временную структуру вражеского выстрела
                mov     -(R1), -(R4)    ; крепкость / убойная сила
                bne     3$
                add     #EnemyBulletBufferItemSize+2, R1

2$:             sob     R2, 1$
                return
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     -(R1), -(R4)    ; габариты
                mov     -(R1), -(R4)
                tst     -(R1)           ; приращение к адресу
                mov     -(R1), -(R4)    ; адрес экрана
                beq     4$              ; если 0 - то ничего не делать

5$:             mov     -2(R1), R0      ; спрайт выстрела
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                mov     (R4), (R1)      ; сохраним новый адрес экрана (0 - если выстрел куда-то попадает)
                mov     6(R4), 10(R1)   ; результат коллизии

4$:             add     #EnemyBulletBufferItemSize+12, R1
                br      2$

; End of function Trap64

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; проверка попали ли вражеские выстрелы в игрока
; и проверка, попал ли игрок куда-нибудь

sub_26320:      mov     #EnemyBulletBuffer+14, R1
                mov     #EnemyBulletBufferItemsNum, R2

1$:             mov     #TmpEnmyBulltStruct+10, R5 ; формируем временную структуру вражеского выстрела
                mov     -(R1), -(R5)    ; крепкость / убойная сила
                bne     3$
                add     #EnemyBulletBufferItemSize+2, R1

2$:             sob     R2, 1$
                return
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     -(R1), -(R5)    ; габариты
                mov     -(R1), -(R5)
                tst     -(R1)           ; приращение к адресу
                mov     -(R1), -(R5)    ; адрес экрана
                beq     4$              ; если 0 - то ничего не делать

5$:             mov     -2(R1), R3
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                mov     #PlayerScrAddr, R4 ; Адрес спрайта игрока
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                trap    56              ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта
                mov     (R5), (R1)      ; сохраним новый адрес экрана (0 - если выстрел куда-то попадает)
                mov     6(R5), 10(R1)   ; результат коллизии

4$:             add     #EnemyBulletBufferItemSize+12, R1
                br      2$
; ───────────────────────────────────────────────────────────────────────────


; End of function sub_26320


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Расчёт направления выстрела вражеского объекта в игрока
; Вход: R0 - адрес экрана охранника или блока
;       R3 - адрес экрана игрока
; Выход: R3 - приращение адреса для полёта выстрела в игрока

Trap66:         mov     #SoundCannonShoot, R1
                trap    14
                mov     R0, R1          ; адрес спрайта охранника
                mov     R3, R2          ; адрес спрайта игрока
                bic     #177700, R0     ; получим горизонтальную позицию
                bic     #177700, R3
                bic     R0, R1          ; получим вертикальную позицию
                bic     R3, R2
                sub     R0, R3          ; расстояние друг от друга по горизонтали
                sub     R1, R2          ; расстояние друг от друга по вертикали
                bpl     1$              ; объект выши игрока
                ;объект ниже игрока
                neg     R2
                call    sub_35266       ; Расчёт направления выстрела объекта в игрока
                                        ; Вход: R3 - расстояние друг от друга по горизонтали
                                        ;       R2 - расстояние друг от друга по вертикали по модулю
                neg     R2
                br      2$
; ───────────────────────────────────────────────────────────────────────────
                ; объект выши игрока
1$:             call    sub_35266       ; Расчёт направления выстрела объекта в игрока
                                        ; Вход: R3 - расстояние друг от друга по горизонтали
                                        ;       R2 - расстояние друг от друга по вертикали по модулю
2$:             add     R3, R2          ; получим приращение адреса
                mov     R2, 6(SP)       ; возвращаем результат в R3
                return
; End of function Trap66


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Расчёт направления выстрела объекта в игрока
; Вход: R3 - расстояние друг от друга по горизонтали
;       R2 - расстояние друг от друга по вертикали по модулю

sub_35266:      mov     R3, R5          ; расстояние друг от друга по горизонтали
                bpl     1$              ; игрок правее объекта
                neg     R5              ; игрок левее объекта

1$:             asr     R5              ; / 2
                beq     3$              ; 0 - делать нечего

2$:             asr     R2              ; /2
                asr     R5              ; пока горизонтальное расстояние не обнулится
                bne     2$

3$:             bic     #77, R2
                tst     R3
                bpl     4$
                mov     #-2, R3         ; горизонтальное направление
                br      5$
; ───────────────────────────────────────────────────────────────────────────

4$:             mov     #2, R3

5$:             return
; End of function sub_35266


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Очистка экрана

Trap70:         mov     #40000, R1
                mov     R1, R2
                mov     #77700, R3
                mov     #40, R4

1$:             clr     (R2)+
                clr     (R3)+
                sob     R4, 1$
                mov     #40077, R0
                mov     #377, R2

2$:             mov     #1164, R3

3$:             bicb    R2, (R0)
                bicb    R2, (R1)
                add     #32, R0
                add     #32, R1
                sob     R3, 3$
                cmp     #323, R2
                beq     4$
                sub     #37711, R0
                sub     #37707, R1
                sob     R2, 2$

4$:             return
; End of function Trap70


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Уменьшение двоично-десятичного числа
; Вход: R0 - конец числа

DecreaseValue:  decb    -(R0)
                bmi     1$
                return
; ───────────────────────────────────────────────────────────────────────────

1$:             movb    #9., (R0)
                br      DecreaseValue
; End of function DecreaseValue


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Увеличение двоично-десятичного числа
; Вход: R0 - конец числа

IncreaseValue:  incb    -(R0)
                cmpb    #10., (R0)
                beq     1$
                return
; ───────────────────────────────────────────────────────────────────────────

1$:             clrb    (R0)
                br      IncreaseValue
; End of function IncreaseValue


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка, закончились  ли жизни, и если нет - то уменьшение
; если да - начать игру заново

CheckLives:     tst     Lives
                beq     PlayerDead

                mov     #EndLives, R0
                ;call    DecreaseValue   ; Уменьшение двоично-десятичного числа ; ### это для честной игры
                tst     DecreaseValue   ; Уменьшение двоично-десятичного числа ; ### это для бессмертия
                                        ; Вход: R0 - конец числа
                mov     #Lives, R5
                mov     #41036, R1
                mov     #400, ObjForce  ; !!! Возвращаем флаги как было, а то пушки самоуничтожаются.
                jmp     OutLivesI$

PlayerDead:     mov     #30, R0

1$:             mov     #Sound14$, R1
                trap    14
                mov     R0, -(SP)
                call    FragScratchAnim ; Обработка разлёта осколков от объектов при попадании
                mov     (SP)+, R0
                sob     R0, 1$

2$:             bit     #100, @#177716
                beq     3$
                tst     @#177714
                beq     2$

3$:             jmp     RestartGame

; End of function CheckLives


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Инициализация ачивок

InitAchievs:    clr     MoveSpeed       ; Скорость передвижения
                mov     #3, ShootSpeed  ; Ускорение стрельбы (меньше - быстрее)
                clr     NShooting       ; Количество выстреливаемых очередей
                return
; End of function InitAchievs


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Уменьшаем игровую задержку

GameSpeedup:    sub     #500, @#GameSpeed
                bpl     1$
                mov     #1, @#GameSpeed

1$:             return
; End of function GameSpeedup


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Снятие ачивок при попадании в игрока

AchievesDown:   cmp     #3, ShootSpeed  ; скорость стрельбы и так минимальная?
                beq     1$              ; да
                inc     ShootSpeed      ; нет - уменьшаем

1$:             cmp     #1, MoveSpeed   ; скорость передвижения и так минимальная?
                beq     2$              ; нет
                dec     MoveSpeed       ; да - уменьшаем

2$:             tst     NShooting       ; количество очередей одна?
                beq     3$              ; да
                dec     NShooting       ; нет - уменьшаем

3$:             return
; End of function AchievesDown

; ───────────────────────────────────────────────────────────────────────────
Sound1$:        .word 10
                .word 400
                .word 200
                .word 660
                .word 400
                .word 0

Sound2$:        .word 14
                .word 100
                .word 200
                .word 300
                .word 400
                .word 300
                .word 200
                .word 0

SoundKillGuard: .word 4
                .word 2000
                .word 1000
                .word 400
                .word 100
                .word 0

SoundPlayerShoot:.word 6
                .word 37
                .word 200
                .word 60
                .word 0

Sound6$:        .word 22
                .word 30
                .word 500
                .word 300
                .word 500
                .word 0

Sound4$:        .word 20
                .word 1000
                .word 200
                .word 0

Sound3$:        .word 14
                .word 700
                .word 400
                .word 100
                .word 0

SoundScratch:   .word 2
                .word 2
                .word 0

SoundCannonShoot:.word 10
                .word 20
                .word 200
                .word 0

SoundRogerFall: .word 2
                .word 1000
                .word 100
                .word 0

SoundLBoxCatch: .word 10
                .word 50
                .word 300
                .word 50
                .word 0

SoundSBoxCatch: .word 4
                .word 400
                .word 200
                .word 100
                .word 40
                .word 0

SoundNBoxCatch: .word 10
                .word 40
                .word 100
                .word 400
                .word 0

SoundFBoxCatch: .word 10
                .word 400
                .word 100
                .word 400
                .word 0

Sound14$:       .word 2
                .word 400
                .word 1000
                .word 2000
                .word 1000
                .word 37
                .word 0

Sound15$:       .word 10
                .word 100
                .word 400
                .word 1000
                .word 2000
                .word 1000
                .word 400
                .word 100
                .word 0

Sound16$:       .word 12
                .word 2000
                .word 0

Sound17$:       .word 20
                .word 2000
                .word 1000
                .word 400
                .word 200
                .word 100
                .word 400
                .word 200
                .word 1000
                .word 0
; ───────────────────────────────────────────────────────────────────────────
                .word 0
MainMenu$:      .word 62030
                .word 10
                .word FONT + <'И - 100>*10.
                .word FONT + <'Г - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'А - 100>*10.
                .word 0
                .word 64414
                .word 24
strControl:     .word FONT + <'У - 100>*10.
                .word FONT + <'П - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word 0
                .word 67014
                .word 24
                .word FONT + <'И - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'Ф - 100>*10.
                .word FONT + <'О - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'М - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'Ц - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Я - 100>*10.
                .word 0
                .word 71426
                .word 12
                .word FONT + <'В - 100>*10.
                .word FONT + <'Ы - 100>*10.
                .word FONT + <'Х - 100>*10.
                .word FONT + <'О - 100>*10.
                .word FONT + <'Д - 100>*10.
                .word 0
                .word 5                 ; звук сразу за меню
                .word 1400
                .word 1600
                .word 1000
                .word 0
; Меню - выбор органа управления
CtrlsMenu:      .word 55014
                .word 24
                .word FONT + <'К - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'У - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'А - 100>*10.
                .word 0
                .word 57420
                .word 20
                .word FONT + <'Д - 100>*10.
                .word FONT + <'Ж - 100>*10.
                .word FONT + <'О - 100>*10.
                .word FONT + <'Й - 100>*10.
                .word FONT + <'С - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'К - 100>*10.
                .word 0
                .word 62026
                .word 12
                .word FONT + <'В - 100>*10.
                .word FONT + <'Ы - 100>*10.
                .word FONT + <'Х - 100>*10.
                .word FONT + <'О - 100>*10.
                .word FONT + <'Д - 100>*10.
                .word 0
                .word 20                ; звук меню
                .word 200
                .word 200
                .word 200
                .word 1000
                .word 0
; Меню - задание управления
MenuCtrls2:     .word 52610
                .word FONT + <'1 - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'Д - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Ж - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'  - 040>*10.
                .word 112170
                .word 0
                .word 55210
                .word FONT + <'2 - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'Д - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Ж - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'  - 040>*10.
                .word 112050
                .word 0
                .word 57610
                .word FONT + <'3 - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'Д - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Ж - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'  - 040>*10.
                .word 112202
                .word 0
                .word 62210
                .word FONT + <'4 - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'Д - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Ж - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'  - 040>*10.
                .word 112213
                .word 0
                .word 64610
                .word FONT + <'5 - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'Ы - 100>*10.
                .word FONT + <'С - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word 0
                .word 20
                .word 500
                .word 1000
                .word 300
                .word 0
; Меню - выбор способа управления
Menu3:          .word 61406
                .word 32
                .word FONT + <'О - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'К - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'У - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'Ы - 100>*10.
                .word 0
                .word 64010
                .word 30
                .word FONT + <'О - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'Д - 100>*10.
                .word FONT + <'Ж - 100>*10.
                .word FONT + <'О - 100>*10.
                .word FONT + <'Й - 100>*10.
                .word FONT + <'С - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'И - 100>*10.
                .word FONT + <'К - 100>*10.
                .word FONT + <'А - 100>*10.
                .word 0
                .word 66410
                .word 30
                .word FONT + <'П - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'Ь - 100>*10.
                .word FONT + <'Н - 100>*10.
                .word FONT + <'О - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word 0
                .word 20
                .word 1000
                .word 300
                .word 1000
                .word 0

; ───────────────────────────────────────────────────────────────────────────
datText1:       .word FONT + <'( - 40>*10. ; (C)  BIL corp.
                .word FONT + <'C - 40>*10.
                .word FONT + <') - 40>*10.
                .word FONT + <'  - 40>*10.
                .word FONT + <'  - 40>*10.
                .word FONT + <'B - 40>*10.
                .word FONT + <'I - 40>*10.
                .word FONT + <'L - 40>*10.
                .word FONT + <'  - 40>*10.
                .word FONT + <'c - 40>*10. + 1
                .word FONT + <'o - 40>*10. + 1
                .word FONT + <'r - 40>*10. + 1
                .word FONT + <'p - 40>*10. + 1
                .word FONT + <'. - 40>*10.
                .word 0

datText3:       .word FONT + <'П - 100>*10. ; ПРЕДСТАВЛЯЕТ
                .word FONT + <'Р - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Д - 100>*10.
                .word FONT + <'С - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'В - 100>*10.
                .word FONT + <'Л - 100>*10.
                .word FONT + <'Я - 100>*10.
                .word FONT + <'Е - 100>*10.
                .word FONT + <'Т - 100>*10.
                .word 0

datTextGAMEE:   .word FONT + <'G - 040>*10. + 1
                .word FONT + <'A - 040>*10. + 1
                .word FONT + <'M - 040>*10. + 1
                .word FONT + <'E - 040>*10. + 1
                .word 0

strSplashTxt1:  .word FONT + <'A - 040>*10.
                .word FONT + <'N - 040>*10.
                .word FONT + <'L - 040>*10.
                .word FONT + <'E - 040>*10.
                .word FONT + <'P - 040>*10.
                .word FONT + <'T - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'* - 040>*10.
                .word FONT + <'* - 040>*10.
                .word FONT + <'* - 040>*10.
                .word FONT + <'* - 040>*10.
                .word FONT + <'  - 040>*10.
                .word FONT + <'  - 040>*10.
strSplashTxt1End:.word 0

                .word FONT + <'П - 100>*10. ; ПАУЗА-СБР (не используется)
                .word FONT + <'А - 100>*10.
                .word FONT + <'У - 100>*10.
                .word FONT + <'З - 100>*10.
                .word FONT + <'А - 100>*10.
                .word FONT + <'- -  40>*10.
                .word FONT + <'С - 100>*10.
                .word FONT + <'Б - 100>*10.
                .word FONT + <'Р - 100>*10.
                .word 0


strScore:       .asciz "SCORE"
strLive:        .asciz "LIVE"
strGuard:       .asciz "GUARD"
strGuardEnd:    .even
strSplashTxt2:  .asciz "БОРТНИК  БОРИС"
strSplashTxt2e: .even
; ───────────────────────────────────────────────────────────────────────────
strSplashTxt3:  .byte 5, 231
                .asciz "г.МОСКВА"
strSplashTxt3e: .even
datText10:      .byte 30, 231
                .asciz "END"
datText10End:   .even

AddrText11:     .word 74002             ; адрес вывода строки
                .word 0
datText11:      .asciz "СТОП ─ ЗАСТАВКА" ; вот этой строки
datText11End:   .even

datInfo$:       .byte 40, 10, 14
                .ascii "ВАША ЗАДАЧА:"
                .byte 10, 14, 12
                .ascii "УНИЧТОЖИТЬ"
                .byte 4, 2, 17
                .ascii "ОХРАНУ ПЛАНЕТЫ,"
                .byte 4, 4, 16
                .ascii "ЧТОБЫ СЕСТЬ НА"
                .byte 4, 4, 16
                .ascii "ЕЕ ПОВЕРХНОСТЬ"
                .byte 4, 10, 14
                .ascii "И НАЙТИ ВХОД"
                .byte 4, 20, 10
                .ascii "В ШАХТУ."
                .byte 12, 24, 6
                .ascii "ЖИЗНИ,"
                .byte 4, 0, 20
                .ascii "СКОРОСТЬ ПОЛЕТА,"
                .byte 4, 2, 17
                .ascii "ЧИСЛО И ЧАСТОТУ"
                .byte 4, 6, 15
                .ascii "ВЫСТРЕЛИВАНИЯ"
                .byte 4, 26, 5
                .ascii "МОЖНО"
                .byte 4, 0, 20
                .ascii "УВЕЛИЧИВАТЬ,ЛОВЯ"
                .byte 4, 4, 16
                .ascii "БУКВЫ: L S N F"
                .byte 4, 2, 17
                .ascii "СООТВЕТСТВЕННО."
                .byte 10, 0, 0
                .byte 0
                .even

; ───────────────────────────────────────────────────────────────────────────
Digits$:        .word ^B0011001111001100
                .word ^B0000000000000000
                .word ^B0011001111001100
Num1$:          .word ^B0011000000000000
                .word ^B0000000000000000
                .word ^B0011000000000000
Num2$:          .word ^B0011001111110000
                .word ^B0000001111000000
                .word ^B0000111111001100
Num3$:          .word ^B0011001111110000
                .word ^B0000001111000000
                .word ^B0011001111110000
Num4$:          .word ^B0011000000001100
                .word ^B0000001111000000
                .word ^B0011000000000000
Num5$:          .word ^B0000111111001100
                .word ^B0000001111000000
                .word ^B0011001111110000
Num6$:          .word ^B0000111111001100
                .word ^B0000001111000000
                .word ^B0011001111001100
Num7$:          .word ^B0011001111001100
                .word ^B0000000000000000
                .word ^B0011000000000000
Num8$:          .word ^B0011001111001100
                .word ^B0000001111000000
                .word ^B0011001111001100
Num9$:          .word ^B0011001111001100
                .word ^B0000001111000000
                .word ^B0011001111110000
                .word ^B0000000000000000
; ───────────────────────────────────────────────────────────────────────────
; Спрайт капля, ширина 1 байт, высота 13 строк
SpriteDrop:     .byte ^B00000000
                .byte ^B00010000
                .byte ^B00000100
                .byte ^B00010000
                .byte ^B00000100
                .byte ^B00010000
                .byte ^B00010100
                .byte ^B01010101
                .byte ^B01010101
                .byte ^B01010101
                .byte ^B00010100
                .even

sprBIL:         .byte 125, 125, 120, 25, 25, 0
                .byte 375, 377, 321, 77, 75, 0
                .byte 364, 320, 103, 17, 75, 0
                .byte 364, 325, 103, 17, 75, 0
                .byte 364, 377, 101, 17, 75, 0
                .byte 364, 320, 103, 17, 75, 125
                .byte 364, 320, 103, 17, 75, 375
                .byte 364, 325, 103, 17, 75, 375
                .byte 375, 377, 320, 77, 375, 377
sprCopyright:   .byte 300, 377, 3
                .byte 160, 125, 15
                .byte 134, 377, 65
                .byte 327, 327, 327
                .byte 327, 127, 325
                .byte 327, 127, 325
                .byte 327, 127, 325
                .byte 327, 327, 327
                .byte 134, 377, 65
                .byte 160, 125, 15
                .byte 300, 377, 3
                .even
; Спрайт  названия игры
sprPlanetTxt:   .byte 252,252,202,52, 0, 0,240,252,250,202,52,252,252,242,252,252
                .byte 377,377,312,57, 0, 0,370,277,374,312,57,377,377,362,377,277
                .byte 277,360,313,57, 0, 0,276,277,374,313,57,277,360,362,376,276
                .byte 277,360,313,57, 0,200,57,277,374,313,57,277,300,262,374,262
                .byte 277,360,313,57, 0,340,13,277,374,357,57,277,50, 0,374, 2
                .byte 277,360,313,57, 0,360,13,277,374,356,57,277,56, 0,374, 2
                .byte 277,372,313,57, 0,360,253,277,374,356,57,377,57, 0,374, 2
                .byte 377,377,302,57,240,362,377,277,374,356,57,277,54, 0,374, 2
                .byte 277, 0,300,57,370,362,13,277,374,376,57,277,200, 2,374, 2
                .byte 277, 0,300,57,376,362,13,277,374,362,57,277,340, 2,374, 2
                .byte 277, 0,300,257,377,362,13,277,374,362,57,277,372, 2,374, 2
                .byte 277, 0,300,377,377,362,13,277,374,302,57,377,377, 2,374, 2

sprBulletLt:    .word 3, 1
                .byte ^B11110000
                .byte ^B00111111
                .byte ^B11110000
                .even
sprBulletRt:    .word 3, 1
                .byte ^B00001111
                .byte ^B11111100
                .byte ^B00001111
                .even

sprPlayerRt:    .word 27, 4
                .byte 114, 5, 0, 0
                .byte 123, 125, 25, 0
                .byte 120, 25, 0, 0
                .byte 123, 77, 0, 0
                .byte 120, 35, 0, 0
                .byte 103, 5, 0, 0
                .byte 14, 65, 12, 0
                .byte 103, 363, 10, 40
                .byte 114, 217, 252, 252
                .byte 103, 377, 52, 0
                .byte 114, 374, 373, 0
                .byte 103, 3, 0, 0
                .byte 14, 375, 77, 0
                .byte 63, 124, 125, 0
                .byte 314, 120, 125, 1
                .byte 60, 3, 124, 1
                .byte 0, 314, 120, 1
                .byte 0, 60, 123, 1
                .byte 0, 300, 120, 1
                .byte 0, 0, 123, 3
                .byte 0, 300, 320, 15
                .byte 0, 0, 163, 167
                .byte 0, 0, 374, 377
sprPlayerLt:    .word 27, 4
                .byte 0, 0, 120, 61
                .byte 0, 124, 125, 305
                .byte 0, 0, 124, 5
                .byte 0, 0, 374, 305
                .byte 0, 0, 164, 5
                .byte 0, 0, 120, 301
                .byte 0, 240, 134, 60
                .byte 10, 40, 317, 301
                .byte 252, 252, 362, 61
                .byte 0, 250, 377, 301
                .byte 0, 357, 77, 61
                .byte 0, 0, 300, 301
                .byte 0, 374, 177, 60
                .byte 0, 125, 25, 314
                .byte 100, 125, 5, 63
                .byte 100, 25, 300, 14
                .byte 100, 5, 63, 0
                .byte 100, 305, 14, 0
                .byte 100, 5, 3, 0
                .byte 300, 305, 0, 0
                .byte 160, 7, 3, 0
                .byte 335, 315, 0, 0
                .byte 377, 77, 0, 0
sprVyhlopRt1:   .word 10, 2
                .word ^B0000000010000000
                .word ^B0000000000100000
                .word ^B0000001101000000
                .word ^B0010110111100000
                .word ^B0010101101110000
                .word ^B0000000010001000
                .word ^B0000000000100000
                .word ^B0000000000000010
sprVyhlopRt2:   .word 10, 2
                .word ^B0000000010000000
                .word ^B0000000000100000
                .word ^B0000011011000000
                .word ^B0010110001111000
                .word ^B0010001011000000
                .word ^B0000101100000010
                .word ^B0000001000000000
                .word ^B0000000010000000
sprVyhlopLt1:   .word 10, 2
                .word ^B0000001000000000
                .word ^B0000100000000000
                .word ^B0000000111000000
                .word ^B0000101101111000
                .word ^B0000110111101000
                .word ^B0010001000000000
                .word ^B0000100000000000
                .word ^B1000000000000000
sprVyhlopLt2:   .word 10, 2
                .word ^B0000001000000000
                .word ^B0000100000000000
                .word ^B0000001110010000
                .word ^B0010110100111000
                .word ^B0000001110001000
                .word ^B1000000011100000
                .word ^B0000000010000000
                .word ^B0000001000000000
SprVyhlopSize = sprVyhlopRt2 - sprVyhlopRt1

sprGuardRt:     .word 33, 3
                .byte 0, 24, 0
                .byte 0, 125, 0
                .byte 0, 175, 25
                .byte 0, 375, 3
                .byte 0, 375, 0
                .byte 0, 24, 0
                .byte 10, 74, 0
                .byte 4, 74, 0
                .byte 25, 250, 0
                .byte 21, 42, 2
                .byte 31, 50, 2
                .byte 221, 50, 3
                .byte 231, 350, 377
                .byte 221, 250, 17
                .byte 31, 242, 52
                .byte 21, 12, 0
                .byte 31, 250, 0
                .byte 21, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 164, 0
                .byte 0, 124, 0
                .byte 0, 124, 1
                .byte 0, 120, 5
                .byte 0
sprGuardLt:     .word 33, 3
                .byte 0, 24, 0
                .byte 0, 125, 0
                .byte 124, 175, 0
                .byte 300, 177, 0
                .byte 0, 177, 0
                .byte 0, 24, 0
                .byte 0, 74, 40
                .byte 0, 74, 20
                .byte 0, 52, 124
                .byte 200, 210, 104
                .byte 200, 50, 144
                .byte 300, 50, 106
                .byte 377, 53, 146
                .byte 360, 52, 106
                .byte 250, 212, 144
                .byte 0, 240, 104
                .byte 0, 52, 144
                .byte 0, 74, 104
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 74, 0
                .byte 0, 35, 0
                .byte 0, 25, 0
                .byte 100, 25, 0
                .byte 120, 5, 0
                .byte 0
; Это спрайты выхлопа ранца охранника
sprGuardFlame1: .word 14, 1
                .byte ^B00000000
                .byte ^B00100010
                .byte ^B00000000
                .byte ^B00100010
                .byte ^B00001000
                .byte ^B00101010
                .byte ^B00001000
                .byte ^B00100010
                .byte ^B00000000
                .byte ^B00000000
                .byte ^B00001000
                .byte ^B00000000
sprGuardFlame2: .word 14, 1
                .byte ^B00000000
                .byte ^B00001000
                .byte ^B00000000
                .byte ^B00001000
                .byte ^B00100010
                .byte ^B00001000
                .byte ^B00101010
                .byte ^B00001000
                .byte ^B00000000
                .byte ^B00000000
                .byte ^B00100010
                .byte ^B00000000
SprGuardFlameLen = sprGuardFlame2 - sprGuardFlame1

sprRedBallBullet:.word 5, 1
                .byte ^B00111100
                .byte ^B11111111
                .byte ^B11111111
                .byte ^B11111111
                .byte ^B00111100
                .even
sprBallBullet:  .word 5, 1
                .byte ^B00111100
                .byte ^B11101011
                .byte ^B11101011
                .byte ^B11101011
                .byte ^B00111100
                .even
sprCannonScratch:.word 4, 1
                .byte ^B01000001
                .byte ^B01010101
                .byte ^B01010101
                .byte ^B01000001

sprParticle1:   .word 1, 4
                .word ^B0011110011000011
                .word ^B1100001100111100
sprParticle2:   .word 2, 2
                .word ^B0010100010000010
                .word ^B1000001000101000

sprCloud1:      .word 15, 6
                .byte 200, 2, 240, 12, 0, 0
                .byte 240, 50, 12, 52, 250, 2
                .byte 40, 210, 202, 202, 202, 12
                .byte 40, 212, 242, 50, 0, 12
                .byte 10, 212, 42, 240, 10, 2
                .byte 12, 202, 0, 242, 200, 12
                .byte 212, 210, 240, 200, 42, 40
                .byte 50, 0, 52, 10, 12, 242
                .byte 40, 52, 240, 0, 212, 242
                .byte 240, 242, 210, 252, 202, 240
                .byte 50, 40, 2, 250, 250, 50
                .byte 250, 212, 250, 202, 240, 12
                .byte 240, 2, 12, 0, 52, 0
sprCloud2:      .word 15, 6
                .byte 200, 12, 0, 12, 240, 0
                .byte 240, 52, 10, 50, 250, 2
                .byte 0, 0, 12, 0, 12, 12
                .byte 240, 200, 202, 12, 0, 10
                .byte 50, 200, 40, 50, 0, 0
                .byte 12, 0, 2, 0, 210, 12
                .byte 12, 2, 2, 240, 0, 50
                .byte 50, 0, 202, 200, 2, 240
                .byte 0, 240, 2, 200, 202, 200
                .byte 0, 40, 12, 240, 200, 0
                .byte 10, 0, 0, 52, 200, 50
                .byte 50, 52, 240, 2, 210, 12
                .byte 240, 2, 52, 240, 2, 2
sprCloudEnd:
SprCloudSize = sprCloud2 - sprCloud1

sprSmlCloud1:   .word 12, 4
                .byte 240, 12, 250, 12
                .byte 250, 52, 52, 52
                .byte 12, 50, 52, 50
                .byte 212, 40, 250, 240
                .byte 212, 252, 200, 242
                .byte 12, 252, 212, 242
                .byte 52, 10, 250, 252
                .byte 252, 200, 40, 252
                .byte 250, 252, 2, 52
                .byte 240, 240, 200, 12
sprSmlCloud2:   .word 12, 4
                .byte 240, 12, 240, 12
                .byte 50, 10, 12, 50
                .byte 2, 240, 0, 40
                .byte 202, 200, 40, 242
                .byte 12, 200, 2, 200
                .byte 40, 10, 202, 210
                .byte 202, 2, 240, 200
                .byte 2, 0, 10, 200
                .byte 12, 12, 42, 50
                .byte 240, 250, 200, 12
sprSmlCloudEnd:
SprSmlCloudsSize = sprSmlCloud2 - sprSmlCloud1  ; 54

sprRoger:       .word 26, 4
                .byte 0, 120, 5, 0
                .byte 0, 164, 35, 0
                .byte 0, 164, 35, 0
                .byte 0, 20, 4, 0
                .byte 104, 100, 1, 21
                .byte 125, 21, 104, 125
                .byte 121, 101, 101, 125
                .byte 124, 1, 100, 25
                .byte 120, 1, 100, 5
                .byte 100, 5, 120, 1
                .byte 0, 25, 124, 0
                .byte 0, 124, 20, 0
                .byte 0, 120, 1, 0
                .byte 0, 100, 5, 0
                .byte 0, 4, 25, 0
                .byte 0, 25, 124, 0
                .byte 100, 5, 120, 1
                .byte 120, 1, 100, 5
                .byte 124, 1, 100, 25
                .byte 121, 1, 100, 125
                .byte 125, 1, 100, 125
                .byte 104, 0, 0, 21

sprTree:        .word 26, 3
                .byte 200, 252, 2
                .byte 240, 253, 12
                .byte 50, 252, 52
                .byte 310, 352, 56
                .byte 250, 250, 10
                .byte 252, 353, 252
                .byte 242, 262, 252
                .byte 216, 216, 256
                .byte 350, 262, 12
                .byte 270, 214, 56
                .byte 250, 262, 50
                .byte 340, 316, 12
                .byte 200, 263, 2
                .byte 0, 216, 0
                .byte 0, 262, 0
                .byte 0, 14, 0
                .byte 0, 60, 0
                .byte 0, 14, 0
                .byte 0, 60, 0
                .byte 0, 14, 0
                .byte 0, 60, 0
                .byte 0, 314, 0

sprBreakTree:   .word 10, 3
                .byte 72, 0, 0
                .byte 256, 0, 0
                .byte 272, 263, 16
                .byte 354, 342, 53
                .byte 270, 73, 256
                .byte 40, 14, 273
                .byte 0, 262, 240
                .byte 200, 314, 2

Sprite9$:       .word 3, 1
                .byte ^B00101000
                .byte ^B10101010
                .byte ^B00101000
                .even

sprCannon:      .word 20, 3
                .byte 0, 377, 0
                .byte 0, 377, 0
                .byte 0, 327, 0
                .byte 0, 327, 0
                .byte 300, 327, 3
                .byte 300, 175, 3
                .byte 300, 125, 3
                .byte 300, 125, 3
                .byte 360, 327, 17
                .byte 160, 377, 15
                .byte 160, 125, 15
                .byte 160, 125, 15
                .byte 160, 125, 15
                .byte 374, 377, 77
                .byte 377, 377, 377
                .byte 125, 125, 125
                .even
sprBreakCannon: .word 5, 3
                .byte 314, 60, 314
                .byte 163, 337, 303
                .byte 100, 125, 1
                .byte 124, 125, 25
                .byte 125, 125, 125
                .even

sprLiveBox:     .word 13, 3
                .byte 125, 0, 0
                .byte 167, 5, 0
                .byte 135, 5, 0
                .byte 167, 5, 0
                .byte 135, 5, 0
                .byte 167, 5, 0
                .byte 135, 105, 25
                .byte 167, 125, 127
                .byte 135, 325, 125
                .byte 167, 165, 127
                .byte 335, 335, 125
                .even
sprSpeedBox:    .word 13, 3
                .byte 120, 125, 5
                .byte 164, 167, 127
                .byte 335, 335, 125
                .byte 127, 1, 0
                .byte 135, 125, 5
                .byte 167, 167, 125
                .byte 334, 335, 125
                .byte 0, 100, 127
                .byte 125, 325, 125
                .byte 167, 167, 127
                .byte 334, 335, 25
                .even
sprNBox:        .word 13, 3
                .byte 25, 100, 5
                .byte 127, 101, 127
                .byte 135, 305, 125
                .byte 167, 125, 127
                .byte 335, 325, 125
                .byte 167, 127, 127
                .byte 335, 335, 125
                .byte 127, 167, 127
                .byte 135, 335, 125
                .byte 127, 161, 127
                .byte 135, 301, 125
                .even
sprForceBox:    .word 13, 3
                .byte 125, 125, 5
                .byte 167, 167, 127
                .byte 335, 335, 125
                .byte 167, 125, 127
                .byte 135, 325, 125
                .byte 167, 25, 0
                .byte 335, 135, 1
                .byte 167, 127, 1
                .byte 135, 5, 0
                .byte 167, 5, 0
                .byte 135, 5, 0
                .even

sprUFO1:        .word 7, 3
                .byte 0, 250, 52
                .byte 0, 212, 210
                .byte 0, 252, 252
                .byte 374, 377, 77
                .byte 252, 252, 0
                .byte 42, 242, 0
                .byte 250, 52, 0
                .even
sprUFO2:        .word 7, 3
                .byte 250, 52, 0
                .byte 42, 242, 0
                .byte 252, 252, 0
                .byte 374, 377, 77
                .byte 0, 252, 252
                .byte 0, 212, 210
                .byte 0, 250, 52
                .even
sprUFOEnd:
SprUFOSize = sprUFO2 - sprUFO1

sprBlockB:      .word 15, 3
                .byte 125, 125, 125
                .byte 125, 125, 125
                .byte 5, 0, 120
                .byte 365, 377, 123
                .byte 65, 125, 125
                .byte 65, 0, 124
                .byte 365, 377, 120
                .byte 65, 125, 123
                .byte 65, 125, 123
                .byte 65, 0, 123
                .byte 365, 377, 124
                .byte 125, 125, 125
                .byte 125, 125, 125
                .even
sprBlockO:      .word 15, 3
                .byte 374, 377, 77
                .byte 137, 125, 365
                .byte 127, 377, 325
                .byte 327, 377, 327
                .byte 367, 377, 337
                .byte 367, 327, 337
                .byte 367, 101, 337
                .byte 367, 327, 337
                .byte 367, 377, 337
                .byte 327, 377, 327
                .byte 127, 377, 325
                .byte 137, 125, 365
                .byte 374, 377, 77
                .even
; ───────────────────────────────────────────────────────────────────────────
JoyTab:         .word 1
                .word 2
                .word 4
                .word 10
                .word 40

KeyTab:         .word 31
                .word 10
                .word 32
                .word 33
                .word 40
; Смещения разлёта осколков
ScratchOffsetTbl:.word -300
                .word -77
                .word 2
                .word 101
                .word 300
                .word 77
                .word -2
                .word -101
ScratchOffsetTblEnd:
ScratchOffsetTblSize = ScratchOffsetTblEnd - ScratchOffsetTbl

; таблица смещений адреса ящиков, чтобы они летали по замысловатой траектории
; формат: .word задержка, смещение
                .word 10
BoxTrckOffsets: .word -676, 4
                .word 2,    10
                .word 702,  6
                .word 700,  4
                .word 676,  3
                .word -2,   4
                .word -702, 6
                .word -700
BoxTrckOffsetsEnd:
; таблица разлёта осколков при взрыве НЛО
UFOScratchTbl:  .word -400
                .word -202
                .word -176
                .word -301
                .word -277
                .word 0

; ───────────────────────────────────────────────────────────────────────────
FireFlag:       .word 0                 ; Флаг стрельбы
CtrlMode:       .word 0                 ; режим управления: 0 - от клавиатуры
                                        ;                   1 - от джойстика
                                        ;                   2 - клавиатура + джойстик

RogerScrAddr:   .word 0                 ; Экранный адрес черепа с костями
RogerOffset:    .word 0                 ; Приращение экранного адреса черепа с костями

NShooting:      .word 0                 ; Количество выстреливаемых очередей
MoveSpeed:      .word 1                 ; Скорость передвижения
GrowPlayerAddr: .word 0                 ; Приращение адреса игрока
DirSprPlayer:   .word -1                ; направление движения игрока
                                        ; -1 - влево, 1 - вправо
CurSprPlayer:   .word sprPlayerLt       ; Адрес текущего спрайта игрока
CurrVyhlopSpr:  .word sprVyhlopLt1      ; адрес текущего спрайта выхлопа игрока
; это структура параметров игрока
; размер 6 слов:
; 0 - адрес экрана
; 2,4 - два слова габаритов, для проверки на коллизию
; 6 - крепкость, т.е. сколько попаданий выдерживает
; для игрока так:
;   - мл.байт - ???
;   - ст.байт - флаг попадания в объект (коллизия)
; 10 - спрайт осколков
; 12 - смещение от адреса экрана - центр разлёта осколков
PlayerScrAddr:  .word 0                 ; Адрес спрайта игрока
                .word 2600, 4           ; габариты спрайта для сравнения на коллизию:
                                        ; высота в строках * 100, ширина в байтах
ObjForce:       .byte 0                 ; обычно, тут крепкость объекта
PlayerHit:      .byte 1                 ; 0 - есть попадание в игрока
                                        ; !0 - нет попадания
                .word sprRedBallBullet  ; спрайт осколков
                .word 1002              ; смещение от адреса экрана - центр разлёта осколков

; структура текущего охранника
CurrGuardStruct:.word 0                 ; Адрес экрана спрайта охранника
                .word 3300, 3           ; габариты охранника для сравнения на коллизию
                .word 177777            ; крепкость
                .word sprParticle2      ; спрайт осколков
                .word 1101              ; смещение от адреса экрана - центр разлёта осколков

; структура параметров для пушки, такая же как для игрока
CannonStruct:   .blkw 6

; структура черепа с костями, для проверки на коллизии
RogerStruct:    .word 0
                .word 2600, 4           ; тут предустановлены габариты
                .word 1
                .word 0
                .word 0
; две временные структуры для проверки, поймал ли игрок коробку
; временная структура игрока, для проверки на коллизии
TmpStructPlayer:.word 0
                .word 2700, 4           ; тут предустановлены габариты
                .word 1
                .word 0
                .word 0
; временная структура коробки с L,F,S,N, для проверки на коллизии
TmpStructBox:   .word 0
                .word 1300, 3           ; тут предустановлены габариты
                .word 1
                .word 0
                .word 0
; временная структура вражеского выстрела, для проверки на коллизии
TmpEnmyBulltStruct: .blkw 6
; временная структура блока О, для проверки на коллизии
TmpBlockStruct: .word 0
                .word 1500, 3
                .word 1
                .word sprParticle1
                .word 601

; это по сути тоже структура, эти переменные не должны отделяться друг от друга
; и должны быть проинициализированы
LiveBoxScrAddr: .word 0
LiveBoxDelay:   .word 7
LiveBoxTrack:   .word BoxTrckOffsets

SpeedBoxScrAddr:.word 0
SpeedBoxDelay:  .word 2
SpeedBoxTrack:  .word BoxTrckOffsets+10

NBoxScrAddr:    .word 0
NBoxDelay:      .word 6
NBoxTrack:      .word BoxTrckOffsets+14

ForceBoxScrAddr:.word 0
ForceBoxDelay:  .word 5
ForceBoxTrack:  .word BoxTrckOffsets

;  параметры облаков
CloudsNum = 2   ; количество облаков на экране
CloudsItemSize = 6  ; размер структуры для одного облака
; Формат:
; 0 - адрес спрайта
; 2 - адрес экрана
; 4 - направление движения
CloudsTbl:      .blkb CloudsNum * CloudsItemSize

; параметры малых облаков
SmlCloudsNum = 2
SmlCloudsItemSize = 4
; Формат:
; 0 - адрес спрайта
; 2 - адрес экрана
SmlCloudsTbl:   .blkb SmlCloudsNum *SmlCloudsItemSize

; параметры звёзд
T46.ArrSize = 10
T46.Arr0:       .word 42455
                .word 73026
                .word 64055
                .word 71775
                .word 50435
                .word 44452
                .word 52511
                .word 0
T46.Arr1:       .word 61717
                .word 0
                .word 55273
                .word 67753
                .word 0
                .word 0
                .word 0
                .word 0
T46.Arr2:       .word 61724
                .word 42610
                .word 56266
                .word 67656
                .word 73416
                .word 0
                .word 52676
                .word 72054
T46.Arr3:       .word 62014
                .word 0
                .word 62760
                .word 63740
                .word 56330
                .word 0
                .word 0
                .word 0

; Счёт, 8 разрядов, каждый байт - один разряд
Score:          .byte 0,0,0,0,0,0,0,0
EndScore:       .byte 377               ; байт-ограничитель
                .even
; Количество жизней, 2 разряда, каждый байт - один разряд
Lives:          .byte 0,0
EndLives:       .byte 377               ; байт-ограничитель
                .even
; Количество охранников, которых нужно уничтожить, 4 разряда, каждый байт - один разряд
Guard:          .byte 0,0,0,0
EndGuard:       .byte 377               ; байт-ограничитель
                .even

; буфер состояния деревьев размером 14 слов
; каждый бит слова - дерево, 1 - есть, 0 - сломанное, нет
Buffer2SizeW = 14
Buffer2:        .blkw Buffer2SizeW
Buffer2End:

; ───────────────────────────────────────────────────────────────────────────
; буфер деревьев на экране размером 60 слов, там каждый элемент - 10 слов
; итого - 6 элементов
; формат:
; 0 значение указателя в Buffer2
; 2 значение маски для слова по этому указателю
; 4 адрес экрана спрайта
; 6  \
; 10 - габариты
; 12 - крепкость
; 14 - адрес спрайта осколков
; 16 - 3 ???
TreeBufferItemsNum = 6
TreeBufferItemSize = 20
TreeBuffer:     .blkb TreeBufferItemSize * TreeBufferItemsNum
TreeBufferEnd:
TreeBufferSizeW = <TreeBufferEnd - TreeBuffer>/2

DigitsCounter:  .word 0 ; счётчик цифр в восьмеричном слове (их 6)
TreesDelays:    .word 0 ; задержки вывода деревьев, каждые 3 бита - задержка

CannonBufPtr:   .word 0 ; указатель в буфере CannonBuffer

; буфер пушек размером 42 байта
; тут хранятся значения счётчиков до появления новой пушки
; бит 6 (0100) - признак подбитой пушки
CannonBufSize = 34.
CannonBufInitPos = 16.
CannonBuffer:   .byte   2
                .byte  30,   2,   2,   2,   2,   2,   2,   2
                .byte   2,   2,   2,   2,   2,  14,  14,  14
                .byte  14,  14,  30,  30,  30,  20,   2,   2
                .byte   2,   2,   2,   2,   2,   2,   2,   2
CannonBufferEnd:.byte   2

; ───────────────────────────────────────────────────────────────────────────
; Массив из 34 элементов по 2 слова на элемент
; буфер блоков
; формат:
; 0 - адрес экрана
; 2 - количество жизней.
; если кол-во жизней станет 0, то элемент будет непригоден для использования
; когда все элементы станут непригодны - то всё, блоков на экране не будет.
BlockBufItemsNum = 34
BlockBufItemSize = 4
BlockBuf:       .blkb   BlockBufItemsNum * BlockBufItemSize
; первые 24 блока - общего назначения
; последние 10 блоков - специальные
BlockBufSpecItemsNum = 10
BlockBufCommonItemsNum = BlockBufItemsNum - BlockBufSpecItemsNum
BlockBufSpec = BlockBuf + BlockBufCommonItemsNum * BlockBufItemSize

; ───────────────────────────────────────────────────────────────────────────

; Буфер охранников на экране, размер 50 байтов
; размер элемента - 10 байтов, 4 слова. Количество элементов - 5
; Формат
; элемент массива охранников
; 0       адрес спрайта выхлопа ранца
; 2       адрес спрайта охранника
; 4       адрес экрана
; 6       число 3 (сколько выдерживает попаданий?)
GuardsItemsNum = 5
GuardsItemSize = 10
GuardsBufferSizeW = GuardsItemSize * GuardsItemsNum / 2
GuardsBuffer:   .blkw  GuardsItemSize * GuardsItemsNum / 2

; ───────────────────────────────────────────────────────────────────────────

; Массив разлёта осколков от попадания в объекты.
; элемент - структура размером 10. слов. количество 30 шт.
; первое слово - адрес спрайта,
; второе слово - число 3000
; это два байта:
; младший - время жизни
; старший - индекс в таблице приращений разлёта осколков
; затем 8 слов адресов разлёта

ScratchBufferItemsNum = 30
ScratchBufferItemSize = 24
ScratchBuffer:  .blkb ScratchBufferItemSize * ScratchBufferItemsNum

; ───────────────────────────────────────────────────────────────────────────

; Буфер размером 2220 байтов

; буфер всех выстрелов, в том числе и из пушки, количество элементов 40
; размер элемента 16
; 0  адрес спрайта выстрела
; 2  адрес экрана
; 4  приращение к адресу
; 6  500 \
; 10 2   - габариты
; 12 1   - крепкость
; 14 результат коллизии
; т.е. этот массив включает в себя и следующий
EnemyBulletBufferItemsNum = 40
EnemyBulletBufferItemSize = 16
EnemyBulletBuffer = OneStartSplash$
EnemyBulletBufferSize = EnemyBulletBufferItemsNum * EnemyBulletBufferItemSize

; буфер выстрелов из пушки, количество элементов 20
; размер элемента 16
; Этот массив входит в предыдущий
CannonBulletBufferItemsNum = 20
CannonBulletBuffer = EnemyBulletBuffer + EnemyBulletBufferSize / 2

; буфер пулек игрока
; размер элемента 14
; 0  приращение к адресу
; 2  адрес экрана
; 4  500 \
; 6  4   - габариты
; 10 1   - крепкость
; 12 результат коллизии
PlayersBulletBufferItemsNum = 74
PlayersBulletBufferItemSize = 14
PlayersBulletBuffer = EnemyBulletBuffer + EnemyBulletBufferSize
PlayersBulletBufferSsize = PlayersBulletBufferItemsNum * PlayersBulletBufferItemSize
AllBuffersSize = EnemyBulletBufferSize + PlayersBulletBufferSsize
; это последний элемент массива там формируется имба - череп с костями
LastItemPlrsBlltBuf = PlayersBulletBuffer + PlayersBulletBufferItemSize * <PlayersBulletBufferItemsNum - 1>

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; эта п/п и спрайт используется только один раз

OneStartSplash$:mov     #VecKbdNo$, @#60
                mov     #VecKbdNo$, @#274
                trap    70              ; Очистка экрана

                mov     #45000, R1
                mov     #1000, R2

1$:             mov     (R0), 5000(R1)
                mov     (R0), 12000(R1)
                mov     (R0), 17000(R1)
                mov     (R0), 24000(R1)
                mov     (R0)+, (R1)+
                sob     R2, 1$
                sob     R2, .
                sob     R2, .
                sob     R2, .
                return
; End of function OneStartSplash$

                .blkb 44
; Спрайт "Break IDea Leader"
SprBILun$:      .word 0, 125252, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 120000, 5252, 0, 0
                .word 0, 0, 0, 0, 0, 0, 125200, 52, 0, 0, 0, 0, 0, 0, 0, 0
                .word 0, 177776, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160000, 7777, 0, 0
                .word 0, 0, 0, 0, 0, 0, 177600, 77, 0, 0, 0, 0, 0, 0, 0, 0
                .word 0, 177776, 277, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160000, 7777, 0, 0
                .word 0, 0, 0, 0, 0, 0, 177600, 77, 0, 0, 0, 0, 0, 0, 0, 0
                .word 0, 107770, 377, 25252, 125000, 1252, 25240, 5200, 1250, 0, 0, 0, 100000, 1777, 125252, 124002
                .word 1252, 125200, 0, 0, 0, 0, 177000, 3, 125240, 52, 1252, 125252, 124002, 5252, 25252, 0
                .word 0, 1770, 376, 137776, 177000, 1777, 37750, 7600, 1772, 0, 0, 0, 100000, 377, 177776, 174013
                .word 1777, 177640, 0, 0, 0, 0, 177000, 3, 177740, 100077, 1776, 177776, 174013, 7777, 137776, 0
                .word 0, 101772, 376, 177776, 177002, 1777, 37772, 107600, 376, 0, 0, 0, 100000, 377, 177776, 174017
                .word 1777, 177750, 0, 0, 0, 0, 177000, 3, 177740, 120077, 1777, 177776, 174017, 7777, 177776, 2
                .word 0, 125776, 377, 174076, 37003, 100000, 37376, 127600, 77, 0, 0, 0, 120000, 377, 100370, 174017
                .word 0, 175772, 0, 0, 0, 0, 177200, 3, 1740, 164000, 1757, 100370, 174017, 0, 174076, 3
                .word 0, 177776, 100077, 164076, 137203, 100052, 37077, 167640, 17, 0, 0, 0, 160000, 377, 100370, 175017
                .word 252, 174376, 0, 0, 0, 0, 177600, 3, 125750, 174002, 1743, 100370, 175017, 100252, 164076, 3
                .word 0, 177776, 100017, 175277, 177600, 120077, 37257, 177740, 3, 0, 0, 0, 160000, 77, 120372, 177017
                .word 100377, 175276, 0, 0, 0, 0, 177600, 0, 177770, 175003, 1752, 120372, 177017, 100377, 175277, 0
                .word 100000, 177776, 100057, 37777, 177600, 160077, 37777, 177740, 0, 0, 0, 0, 160000, 77, 160376, 177017
                .word 100377, 177777, 0, 0, 0, 0, 177600, 25200, 177770, 177003, 1777, 160376, 177017, 100377, 37777, 0
                .word 100000, 100377, 100277, 7777, 7600, 164000, 7777, 177740, 2, 0, 0, 0, 164000, 77, 164076, 37003
                .word 120000, 37777, 0, 0, 0, 0, 177640, 37600, 370, 177200, 377, 164076, 37003, 100000, 7777, 0
                .word 100000, 100377, 120376, 27617, 127600, 174012, 7603, 175750, 13, 0, 0, 0, 174000, 120077, 175276, 137003
                .word 160052, 37017, 0, 0, 0, 0, 177740, 37600, 125370, 37600, 120370, 175276, 137003, 120052, 27617, 0
                .word 100000, 120077, 160377, 137617, 177640, 175017, 7600, 161770, 57, 0, 0, 0, 174000, 160077, 177777, 177200
                .word 164077, 37003, 0, 0, 0, 0, 37740, 37640, 177772, 7640, 160370, 177777, 177200, 160077, 137617, 0
                .word 120000, 165277, 160077, 177003, 177740, 177017, 7600, 100370, 77, 0, 0, 0, 175000, 160017, 37777, 177600
                .word 174077, 37003, 0, 0, 0, 0, 137750, 7752, 177776, 7740, 160370, 37777, 177600, 160077, 177003, 0
                .word 160000, 177777, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177000, 77, 0, 0
                .word 0, 0, 0, 0, 0, 0, 177770, 7777, 0, 0, 0, 0, 0, 0, 0, 0
                .word 160000, 177777, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177000, 77, 0, 0
                .word 0, 0, 0, 0, 0, 0, 177770, 1777, 0, 0, 0, 0, 0, 0, 0, 0
                .blkb 72
                .word 0

; ───────────────────────────────────────────────────────────────────────────

TrapTo4:
; Начальная инициализация
Init$:          mov     #TopStack, SP
                mov     #TrapTo4, @#4
                mov     #DisTrap, @#34
                clr     @#36
                mov     #20, @#177712
                mov     #34000, @#177706
                mov     #1330, @#177664

MorphBR$:       nop     ; тут ставится BR, чтобы пропускать начальную заставку
                mov     #SprBILun$, R0
                call    OneStartSplash$
SkipSTSpl$:     sob     R2, .
                clr     @#177660
                mtps    #0
                mov     @#177662, R0
                mov     #SkipSplash$, @#60
                mov     #SkipSplash$, @#274
                call    Trap70          ; Очистка экрана

StartSplash$:   mov     #strSplashTxt1, R4
                trap    16              ; Анимация заставки
                                        ; Вход: R4 - адрес текста
                mov     #41004, R1
                mov     #strSplashTxt2, R2
                mov     #162000, @#F$ColorMask
                mov     #3, @#F$YScale2
                trap    22              ; Вывод текста буквами тырк-тырк влево-вправо
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - адрес текста
                                        ;       @#F$ColorMask - маска цвета для 1 бита символа
                                        ;       @#F$YScale2 - масштаб по высоте
                mov     #47200, R1
                mov     #strSplashTxt3, @#F$DataAddr2
                trap    6               ; Вывод текста сложного формата на экран
                                        ; Вход: R1 - адрес экрана
                                        ;       @#F$DataAddr2 - адрес массива данных
                sob     R0, .
                sob     R0, .
                sob     R0, .

                mov     #40040, R1
                mov     #364, R2
                mov     #20, R3
                clr     @#F$YScale2
                trap    20              ; Вывод падающей каплей буквы
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - высота падения
                                        ;       R3 - код буквы - 20
                call    Trap70          ; Очистка экрана
                mov     #F$DataBlock,  R0
                mov     #146314, (R0)+
                mov     #42020, (R0)+
                mov     #77700, (R0)+
                mov     #datTextGAMEE, (R0)+
                mov     #126664, (R0)+
                mov     #12, (R0)+
                mov     #3, (R0)+       ; номер игры
                mov     #40, (R0)+
                mov     #60000, @#F$GameAddr
                trap    0               ; Вывод слова GAME и цифры 3
                                        ; Вход: @#F$DataBlock - блок параметров (адрес слова и номер цифры)
                mov     #1400, R2
                mov     R2, R3
                call    @#102062
; ───────────────────────────────────────────────────────────────────────────
SkipSplash$:    mov     #1330, @#177664
                mov     #VecKbdNo$, @#60
                mov     #VecKbdNo$, @#274
; ───────────────────────────────────────────────────────────────────────────
DrawMenu$:      call    Trap70          ; Очистка экрана
                trap    24              ; Вывод три зелёных полосы и на них копирайт спрайтами
                mov     #sprPlanetTxt, R0
                mov     #44000, R1
                mov     #14, R2

1$:             mov     #20, R3

2$:             mov     #4, R4
                movb    (R0)+, R5

3$:             clrb    (R1)
                ror     R5
                bcc     4$
                bisb    #52525, (R1)

4$:             ror     R5
                bcc     5$
                bisb    #125252, (R1)

5$:             inc     R1
                sob     R4, 3$
                sob     R3, 2$
                mov     #500, R3
                add     #0, R1

6$:             movb    -100(R1), (R1)+
                sob     R3, 6$
                sob     R2, 1$
                mov     #MainMenu$, R4
                mov     #3, R1
                clr     R0
                trap    26              ; Вывод и обработка меню
                                        ; Вход: R0 - номер начального пункта меню
                                        ;       R1 - номер последнего пункта меню
                                        ;       R4 - адрес параметров меню
                                        ; Выход: R0 - выбранный пункт меню
                dec     R0              ; 0 - игра, 1 - управление, 2 - информация, 3 - выход
                beq     SetControls
7$:             dec     R0
                beq     ShowInfo
                dec     R0
                bne     8$
                call    GoExit

8$:             jmp     StartGame
; ───────────────────────────────────────────────────────────────────────────

ShowInfo:       mov     #F$DataBlock, R0
                mov     #77700, (R0)+
                mov     #datInfo$, (R0)+
                mov     #372, (R0)+
                mov     #10000, (R0)+
                trap    2               ; Вывод информации на экран
                                        ; Вход: блок параметров по адресу F$DataBlock:
                                        ; .word адрес экрана
                                        ; .word адрес данных
                                        ; .word маска цвета
                                        ; .word задержка
                trap    24              ; Вывод три зелёных полосы и на них копирайт спрайтами
                trap    72              ; Ждать нажатия чего-нибудь
                jmp     DrawMenu$
; ───────────────────────────────────────────────────────────────────────────

SetControls:    mov     #42000, R1
                mov     #73567, R0
                clr     R4
                mov     #40, R2
                mov     #170, R3
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                mov     #52412, R1
                clr     R0
                mov     #26, R2
                mov     #60, R3
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                mov     #CtrlsMenu, R4
                mov     #2, R1
                trap    26              ; Вывод и обработка меню
                                        ; Вход: R0 - номер начального пункта меню
                                        ;       R1 - номер последнего пункта меню
                                        ;       R4 - адрес параметров меню
                                        ; Выход: R0 - выбранный пункт меню
                mov     #52312, R1
                mov     #73567, R4
                dec     R0
                beq     SetJoystick$
                dec     R0
                bne     SetKeyboard$
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
ExitControls$:  clr     R0
                clr     R4
                mov     #47412, R1
                mov     #26, R2
                mov     #22, R3
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                mov     #60004, R1
                mov     #34, R2
                mov     #50, R3
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                mov     #F$DataBlock, R5
                mov     #50114, (R5)+
                mov     #strControl, (R5)+
                mov     #124000, (R5)+
                mov     #2, (R5)+
                trap    12              ; Вывод текста
                                        ; Вход: блок параметров по адресу F$DataBlock
                                        ; .word адрес экрана
                                        ; .word адрес данных (таблица адресов символов в шрифте)
                                        ; .word маска цвета для 1 бита символа
                                        ; .word масштаб по высоте
                mov     #2, R1
                mov     #Menu3, R4
                trap    26              ; Вывод и обработка меню
                                        ; Вход: R0 - номер начального пункта меню
                                        ;       R1 - номер последнего пункта меню
                                        ;       R4 - адрес параметров меню
                                        ; Выход: R0 - выбранный пункт меню
                mov     R0, CtrlMode    ; режим управления: 0 - от клавиатуры
                                        ;                   1 - от джойстика
                                        ;                   2 - клавиатура + джойстик
                jmp     DrawMenu$
; ───────────────────────────────────────────────────────────────────────────
SetKeyboard$:   call    sub_7316
                mov     #KeyTab, R0
                mov     #177660, R3
                mov     R3, R2
                tst     (R2)+
                br      1Next$
; ───────────────────────────────────────────────────────────────────────────

SetJoystick$:   call    sub_7316
                mov     #JoyTab, R0
                mov     #177714, R2
                mov     R2, R3

1Next$:         mov     #5, R1
                mov     #MenuCtrls2, R4
                trap    32              ; Вывод и обработка меню для задания управления
                                        ; Вход: R2 - регистр данных
                                        ;       R3 - регистр управления
                                        ;       R4 - адрес блока параметров меню
                br      SetControls
; ───────────────────────────────────────────────────────────────────────────

; ███████████████ S U B R O U T I N E ███████████████████████████████████████


sub_7316:       clr     R0
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                clr     R4
                mov     #51406, R1
                mov     #32, R2
                mov     #74, R3
                trap    30              ; Заполнение прямоугольной области экрана заданным цветом
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - ширина в байтах
                                        ;       R3 - высота в строках / 2
                                        ;       R0,R4 - чересстрочные цвета
                return
; End of function sub_7316

; ───────────────────────────────────────────────────────────────────────────

StartGame:      mov     #37700, R1
                mov     #strScore, R2
                mov     #110000, @#F$ColorMask
                clr     @#F$YScale2
                trap    22              ; Вывод текста буквами тырк-тырк влево-вправо
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - адрес текста
                                        ;       @#F$ColorMask - маска цвета для 1 бита символа
                                        ;       @#F$YScale2 - масштаб по высоте
                add     #31, R1
                add     #strLive-strScore, R2
                trap    22              ; Вывод текста буквами тырк-тырк влево-вправо
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - адрес текста
                                        ;       @#F$ColorMask - маска цвета для 1 бита символа
                                        ;       @#F$YScale2 - масштаб по высоте
                add     #23, R1
                add     #strGuard-strLive, R2
                trap    22              ; Вывод текста буквами тырк-тырк влево-вправо
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - адрес текста
                                        ;       @#F$ColorMask - маска цвета для 1 бита символа
                                        ;       @#F$YScale2 - масштаб по высоте

                mov     (PC)+, @(PC)+
                        br . + <SkipSTSpl$ - MorphBR$>
                        .word MorphBR$   ; глушим появления экрана "BREAK IDEA LEADER"
                                        ; чтобы больше не появлялось
RestartGame:    mov     #40700, R0      ; очистка экрана
1$:             clr     (R0)+
                tst     R0
                bpl     1$

                mov     #EndScore, R5
                movb    #377, (R5)      ; обнуление счёта
                mov     #4, R1
2$:             clr     -(R5)
                sob     R1, 2$
                add     #41002, R1      ; Выводим счёт
                trap    60              ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана
                mov     #Lives, R5
                mov     #1, (R5)        ; начальное значение - 10 жизней
                mov     #41036, R1      ; Выводим жизни
                trap    60              ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана
                mov     #EndGuard, R5
                mov     #2, -(R5)
                clr     -(R5)
                mov     #41062, R1      ; Выводим кол-во охранников
                trap    60              ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана

                mov     #100000, R0     ; Рисуем подложку
                mov     #200, R3
3$:             mov     #125252, -(R0)
                sob     R3, 3$

                mov     #400, ObjForce ; инициализация флагов попадания в игрока
                mov     #56636, PlayerScrAddr ; Адрес спрайта игрока
                mov     #6, DigitsCounter
                mov     #75037, TreesDelays

                mov     #TreeBuffer, R0
                mov     #TreeBufferSizeW, R1
4$:             clr     (R0)+
                sob     R1, 4$

                mov     #1, Buf2Mask$
                mov     #Buffer2, R0
                mov     R0, Buf2Ptr$
                mov     #Buffer2SizeW, R1
5$:             mov     #-1, (R0)+
                sob     R1, 5$

                mov     #CannonBuffer+CannonBufInitPos, CannonBufPtr
                mov     #6, NewCannonCnt
                clr     CannonStruct
                mov     #CannonBuffer, R0
                mov     #CannonBufSize, R1
6$:             bicb    #100, (R0)+
                sob     R1, 6$

                mov     #ScratchBuffer+2, R0
                mov     #ScratchBufferItemsNum, R1
7$:             mov     #3000, (R0)
                add     #ScratchBufferItemSize, R0
                sob     R1, 7$

                mov     #BlockBuf, R5
                mov     #BlockBufItemsNum, R4
8$:             clr     (R5)+
                mov     #13, (R5)+
                sob     R4, 8$

                mov     #GuardsBuffer, R0
                mov     #GuardsBufferSizeW, R1
9$:             clr     (R0)+
                sob     R1, 9$

                mov     #EnemyBulletBuffer, R0
                mov     #AllBuffersSize, R1
10$:            clrb    (R0)+
                sob     R1, 10$

                clr     LiveBoxScrAddr
                clr     SpeedBoxScrAddr
                clr     NBoxScrAddr
                clr     ForceBoxScrAddr
                mov     #1, R0
                mov     R0, LiveBoxDelay
                mov     R0, SpeedBoxDelay
                mov     R0, NBoxDelay
                mov     R0, ForceBoxDelay
                call    InitAchievs     ; Инициализация ачивок
                call    InitRoger

                mov     #2000, BlockBOutCnt
                mov     #60000, @#BlockBScrAddr

                mov     #Trap50_1, off_Trp50s ; Опрос клавиатуры 1
                mov     #Trap52_1, off_Trp52s ; Опрос джойстика 1

                mov     #1, MoveSpeed   ; Скорость передвижения

GameLoop$:      mov     #10000, @#GameSpeed ; игровая задержка
                com     #-1
                beq     1$
                trap    46              ; Вывод звёзд на экран

1$:             call    PlayerAnim      ; Обработка и анимация движения игрока
                                        ; Обработка стрельбы, заполнение массива выстреленных пуль.
                call    PlayerBulletsAnim ; Обработка и анимация полёта пулек игрока
                call    FragScratchAnim ; Обработка разлёта осколков от объектов при попадании
                tstb    PlayerHit       ; 0 - есть попадание в игрока
                                        ; !0 - нет попадания
                bne     2$
                call    CheckLives      ; Проверка, закончились  ли жизни, и если нет - то уменьшение
                                        ; если да - начать игру заново
                ;call    AchievesDown    ; Снятие ачивок при попадании в игрока ; ### это для честной игры
                tst     AchievesDown    ; Снятие ачивок при попадании в игрока ; ### это для бессмертия

2$:             tst     CannonStruct
                bne     5$
                call    CannonPrepare   ; Функция подготавливает структуру параметров пушки

5$:             call    CannonAnim      ; Обработка и вывод пушек, проверка на коллизии
                                        ; и вывод сломанных пушек
                call    DrawTrees       ; Прорисовка деревьев
                call    CannonShootAnim ; Выстрел из пушки
                call    EnemyShootAnim  ; Анимация полёта выстрелов врагов
                call    sub_26320       ; проверка попали ли вражеские выстрелы в игрока
                                        ; и проверка, попал ли игрок куда-нибудь
                bis     #125252, @#77402
                call    DustCloudAnim
                call    LiveBoxAnim     ; Вывод и анимация ящика с жизнью
                call    LiveBoxCatch    ; Проверка поймал ли игрок коробку с жизнью
                                        ; и если да - то увеличение жизней
                call    SpeedBoxAnim    ; Вывод и анимация ящика с ускорением
                call    SpeedBoxCatch   ; Проверка поймал ли игрок коробку с ускорением
                                        ; и если да - то увеличение скорости передвижения
                call    NBoxAnim        ; Вывод и анимация ящика N - Увеличение числа очередей
                call    NBoxCatch       ; Проверка поймал ли игрок коробку с N
                                        ; и если да - то увеличение числа очередей
                call    ForceBoxAnim    ; Вывод и анимация ящика F - увеличение скорострельности
                call    FBoxCatch       ; Проверка поймал ли игрок коробку с F
                                        ; и если да - увеличиваем скорострельность
                call    RogerAnim
                call    UfoAnim
                call    BlockWallAnim   ; вывод и анимация простых блоков на экран
                call    BlockWall2Anim  ; проверка на подбитие блоков, и анимация выстрелов
                call    BlockWall3Anim  ; анимация защищённого блока Б

                bit     #100, @#177716
                bne     7$
6$:             cmp     @#177662, #14   ; клавиша СБР - пауза
                bne     7$
                tst     @#177714
                beq     6$

7$:             call    CheckBlockB     ; Проверка, есть ли блок Б и если есть, то добавление
                                        ; охранника, если нет - проверка на конец игры
                com     #0
                beq     8$
                call    GuardsAnim      ; Обработка и анимация охранников

8$:             call    GuardShootsAnim ; Обработка и анимация выстрелов охранников

                mov     @#GameSpeed, R1
                sob     R1, .
                com     #-1
                beq     9$
                call    CloudsAnim      ; Вывод и анимация облаков

9$:             jmp     GameLoop$
; ───────────────────────────────────────────────────────────────────────────

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и анимация облаков

CloudsAnim:     tst     (PC)+           ; новое облако выводить надо?
NewCloudCnt:    .word   10
                bne     3$              ; нет пока
                mov     #10, NewCloudCnt ; надо, инициализируем счётчик
                mov     #CloudsNum, R4
                mov     #CloudsTbl, R5  ; таблица параметров облаков
20$:            tst     (R5)            ; элемент пуст?
                beq     1$              ; да - нашли пустое место
                add     #CloudsItemSize, R5 ; переходим к следующему элементу
                sob     R4, 20$         ; и так всю таблицу
                br      3$              ; пустых мест нет, нечего добавлять
                ; добавляем
1$:             mov     #sprCloud1, (R5)+ ; начальный спрайт
                mov     @#177710, R4
                add     #42000, R4      ; псевдослучайный адрес
                bit     #1, R4          ; нечётный?
                beq     2$              ; нет
                bic     #77, R4         ; да - появится справа
                bis     #72, R4
                mov     #-1, R0         ; направление движения
                br      21$
; ───────────────────────────────────────────────────────────────────────────

2$:             bic     #74, R4         ; появится слева
                mov     #1, R0          ; направление движения
21$:            mov     R4, (R5)+       ; сохраним начальный адрес
                mov     R0, (R5)+       ; сохраним направление движения

                ; обрабатываем таблицу облаков
3$:             dec     NewCloudCnt
                mov     #CloudsTbl, R5
                mov     #CloudsNum, R4

4$:             mov     (R5)+, R0       ; спрайт облака
                bne     7$              ; есть на экране
                ; нет на экране, переходим к следующему элементу
5$:             tst     (R5)+
6$:             tst     (R5)+
                sob     R4, 4$
                return
; ───────────────────────────────────────────────────────────────────────────

7$:             mov     (R5)+, R1       ; адрес экрана
                beq     6$              ; 0 - нету на экране, переходим к следующему
                mov     CurSprPlayer, R3 ; Адрес текущего спрайта игрока
                mov     (R5), R2        ; направление движения
                bmi     8$              ; влево
                ; вправо
                cmp     #sprPlayerRt, R3 ; если игрок движется вправо
                beq     9$              ; то ничего не делать
                inc     R2              ; а если тоже влево
                inc     R2              ; то облако будет двигаться быстрее вправо
                br      9$
; ───────────────────────────────────────────────────────────────────────────
                ; влево
8$:             cmp     #sprPlayerRt, R3 ; если игрок движется тоже влево
                bne     9$              ; то ничего не делать
                asl     R2              ; а если вправо
                dec     R2              ; то ничего не меняется

9$:             bit     #1, @#177710    ; элемент случайности
                beq     10$
                add     #200, R2        ; опускается вниз
                br      11$
; ───────────────────────────────────────────────────────────────────────────

10$:            sub     #200, R2        ; подымается вверх

11$:            add     R1, R2          ; это новый адрес экрана
                trap    42              ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                cmp     #42300, R2      ; за верх экрана вылетело?
                blo     13$             ; нет ещё
                ; вышло за пределы экрана
                ; удаляем облако из таблицы
12$:            mov     R5, R3
                clr     -(R3)           ; адрес экрана
                clr     -(R3)           ; адрес спрайта
                br      6$              ; пойдём к следующему элементу
; ───────────────────────────────────────────────────────────────────────────

13$:            bit     #76, R2         ; за левый край экрана вышло?
                beq     12$             ; да
                mov     R2, R3
                add     #6, R3
                bit     #74, R3         ; за правый край экрана вышло?
                beq     12$             ; да

                cmp     #75600, R2      ; слишком низко опустилось?
                bhi     14$             ; нет
                sub     #2000, R2       ; да - приподымем

14$:            mov     R2, R1          ; нарисуем на новом месте
                trap    34              ; Вывод спрайта на экран movом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R5, R3
                mov     R1, -(R3)       ; новый адрес экрана сохраним
                add     #SprCloudSize, R0 ; следующий спрайт
                cmp     #sprCloudEnd, R0 ; за конец вышли?
                bne     15$             ; нет
                mov     #sprCloud1, R0  ; да - начинаем сначала

15$:            mov     R0, -(R3)       ; новый спрайт облака сохраним
                br      6$              ; пойдём к следующему элементу
; End of function CloudsAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Обработка и анимация охранников

GuardsAnim:     clr     R0              ; сколько охранников видно на экране
                mov     #<GuardsBuffer+4>, R5 ; указатель в буфере на адрес экрана
                mov     #GuardsItemsNum, R4 ; количество элементов
1$:             tst     (R5)            ; пусто?
                beq     2$              ; да
                inc     R0              ; нет - считаем сколько охранников на экране
                                        ; максимум - 5
2$:             add     #GuardsItemSize, R5
                sob     R4, 1$
                mov     #Guard, R5
                tst     (R5)+           ; охранников ещё много?
                bne     3$              ; да
                tstb    (R5)+           ; больше 10.?
                bne     3$              ; да
                cmpb    (R5), R0        ; меньше 10, и все видны на экране?
                blos    10$             ; все видны - не нужно добавлять
                                        ; можно ещё добавить
3$:             tst     (PC)+
NewGuardCnt:    .word 51                ; счётчик появления нового охранника на экране
                bne     9$              ; ещё рано добавлять
                call    sub_15514       ; Коррекция счётчика появления нового охранника
                mov     #<GuardsBuffer+4>, R5 ; указатель в буфере на адрес экрана
                mov     #GuardsItemsNum, R4 ; количество элементов

4$:             tst     (R5)            ; ищем в массиве пустое место
                beq     5$              ; нашли
                add     #GuardsItemSize, R5
                sob     R4, 4$
                br      9$              ; некуда добавлять
; ───────────────────────────────────────────────────────────────────────────

5$:             sub     #4, R5          ; добавляем
                mov     #sprGuardFlame1, (R5)+ ; спрайт выхлопа ранца
                mov     @#177710, R1    ; псевдослучайный адрес экрана
                sub     #10000, R1
                bpl     6$
                clr     R1

6$:             add     #42200, R1
                bic     #77, R1
                tst     DirSprPlayer    ; смотрим вправо?
                bpl     7$              ; да
                mov     #sprGuardRt, (R5)+ ; нет - охранник смотрит вправо
                br      8$
; ───────────────────────────────────────────────────────────────────────────

7$:             bis     #75, R1
                mov     #sprGuardLt, (R5)+ ; нет - охранник смотрит влево

8$:             mov     R1, (R5)+       ; адрес экрана
                mov     #3, (R5)+       ; кол-во жизней

9$:             dec     NewGuardCnt     ; уменьшаем счётчик
                ; теперь анимация охранников
10$:            mov     #<GuardsBuffer+4>, R2 ; буфер
                mov     #GuardsItemsNum, R3 ; кол-во элементов

11$:            mov     (R2), R1        ; пусто?
                bne     13$             ; нет
                add     #GuardsItemSize, R2 ; да - к следующему

12$:            sob     R3, 11$
                return
; ───────────────────────────────────────────────────────────────────────────

13$:            ; в R1 адрес экрана
                mov     -(R2), R0       ; адрес спрайта
                mov     -(R2), R5       ; адрес спрайта выхлопа
                cmp     #sprGuardRt, R0
                beq     14$
                mov     #2202, R4       ; смещение для выхлопа если смотрит влево
                br      15$
; ───────────────────────────────────────────────────────────────────────────

14$:            mov     #2200, R4       ; смещение для выхлопа если смотрит право

15$:            trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R5, R0
                add     R4, R1          ; теперь сотрём выхлоп
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                sub     R4, R1
                tst     6(R2)           ; жизни ещё остались?
                bpl     17$             ; да
                call    RemoveDeadGuard ; Уменьшаем количество охранников.
                                        ; Вход: R2 - адрес элемента в массиве GuardsBuffer

16$:            add     #GuardsItemSize+4, R2
                br      12$
; ───────────────────────────────────────────────────────────────────────────
; теперь определим, куда двигаться охраннику

17$:            mov     PlayerScrAddr, R5 ; Адрес спрайта игрока
                add     #2600, R5
                clr     R4              ; приращение к адресу экрана
                cmp     R5, R1
                bpl     18$
                mov     #-200, R4
                br      19$
; ───────────────────────────────────────────────────────────────────────────

18$:            sub     #4400, R5
                cmp     R5, R1
                bmi     19$
                mov     #200, R4

19$:            bic     #177700, R1
                bic     #177700, R5
                cmp     R5, R1
                bmi     20$
                inc     R4
                mov     #sprGuardRt, R0
                mov     #2200, R5
                br      21$
; ───────────────────────────────────────────────────────────────────────────

20$:            dec     R4
                mov     #sprGuardLt, R0
                mov     #2202, R5
21$:            mov     4(R2), R1
                add     R4, R1          ; корректируем адрес экрана
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R0, 2(R2)       ; сохраняем новый адрес спрайта
                mov     R1, 4(R2)       ; сохраняем новый адрес экрана
                ; анимируем выхлоп
                add     R5, R1
                mov     (R2), R0
                cmp     #sprGuardFlame2, R0
                bne     24$
                mov     #sprGuardFlame1, R0
                br      25$
; ───────────────────────────────────────────────────────────────────────────

24$:            add     #SprGuardFlameLen, R0

25$:            mov     R0, (R2)        ; сохраняем новый спрайт выхлопа
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                br      16$
; End of function GuardsAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Коррекция счётчика появления нового охранника

sub_15514:      clr     R0
                mov     #<BlockBuf+2>, R5 ; буфер
                mov     #BlockBufItemsNum, R4 ; количество элементов

1$:             tst     (R5)+           ; там пусто?
                beq     2$              ; да
                add     #3, R0          ; нет - корректируем счётчик

2$:             tst     (R5)+           ; переходим к следующему элементу
                sob     R4, 1$          ; и так весь массив
                add     #34, R0
                mov     R0, NewGuardCnt ; счётчик появления нового охранника на экране
                return
; End of function sub_15514


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Уменьшаем количество охранников.
; Вход: R2 - адрес элемента в массиве GuardsBuffer

RemoveDeadGuard:clr     4(R2)           ; очищаем адрес экрана
                mov     #EndGuard, R0
                call    DecreaseValue   ; Уменьшение двоично-десятичного числа
                                        ; Вход: R0 - конец числа
                mov     #41062, R1
                mov     #Guard, R5
                trap    60              ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана
                tst     (R5)+           ; Если убили всех. то конец игры
                bne     1$
                tst     (R5)+
                bne     1$
                jmp     FinalGame
; ───────────────────────────────────────────────────────────────────────────

1$:             mov     #SoundKillGuard, R1
                trap    14
                return
; End of function RemoveDeadGuard


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Обработка и анимация выстрелов охранников

GuardShootsAnim:mov     #<GuardsBuffer+4>, R1
                mov     #GuardsItemsNum, R2 ; количество элементов

1$:             tst     (R1)            ; там пусто?
                bne     3$              ; нет

2$:             add     #GuardsItemSize, R1 ; идём к следующему
                sob     R2, 1$          ; и так весь массив
                return
; ───────────────────────────────────────────────────────────────────────────
                ; заполним структуру коллизий и проверим, не подбили ли охранника
3$:             call    sub_15410
                beq     2$              ; мёртвый охранник стрелять не может
                tst     (PC)+           ; время выстрела пришло?
0GuardNewShootCnt$:.word 30
                beq     4$              ; да
                dec     0GuardNewShootCnt$ ;нет ещё
                br      2$              ; обработаем следующего охранника
; ───────────────────────────────────────────────────────────────────────────

4$:             mov     #30, 0GuardNewShootCnt$ ; инициализируем счётчик
                mov     #<EnemyBulletBuffer+2>, R5 ; ищем в таблице вражеских выстрелов
                mov     #EnemyBulletBufferItemsNum, R4 ; пустое место

5$:             tst     (R5)
                beq     6$              ; нашли
                add     #EnemyBulletBufferItemSize, R5
                sob     R4, 5$
                br      2$              ; не нашли, идём обрабатывать следующего охранника
; ───────────────────────────────────────────────────────────────────────────

6$:             mov     (R1), R0        ; адрес экрана охранника
                mov     PlayerScrAddr, R3 ; Адрес спрайта игрока
                trap    66              ; Расчёт направления выстрела вражеского объекта в игрока
                                        ; Вход: R0 - адрес экрана охранника или блока
                                        ;       R3 - адрес экрана игрока
                                        ; Выход: R3 - приращение адреса для полёта выстрела в игрока
                mov     #sprBallBullet, -2(R5)
                add     #1101, R0       ; это начальный адрес выстрела
                call    sub_36200       ; Коррекция приращения и заполнение параметров структуры
                                        ; Вход: R0 - начальный адрес экрана
                                        ;       R3 - приращение адреса к выстрелу
                                        ;       R5 - указатель на текущий элемент в массиве EnemyBulletBuffer + 2
                mov     #500, (R5)+
                mov     #2, (R5)+
                mov     #1, (R5)+
                br      2$
; End of function GuardShootsAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; проверяем подбили ли охранника
; Вход: R1 - указатель в массиве GuardsBuffer на текущий элемент + 4

sub_15410:      mov     #CurrGuardStruct, R5
                mov     (R1), (R5)      ; адрес экрана охранника
                mov     2(R1), 6(R5)    ; количество жизней
                mov     -2(R1), R3      ; адрес спрайта охранника
                trap    56              ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта
                mov     6(R5), 2(R1)    ; корректируем количество жизней в таблице GuardsBuffer
                return
; End of function sub_15410

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

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

PlayerAnim:     clr     FireFlag        ; Флаг стрельбы
                add     #100, GrowPlayerAddr ; если ничего не делать - то плавно снижаемся к земле
                mov     MoveSpeed, R4   ; Скорость передвижения

1$:             mov     CtrlMode, R5    ; режим управления: 0 - от клавиатуры
                                        ;                   1 - от джойстика
                                        ;                   2 - клавиатура + джойстик
                bne     2$              ; не только от клавиатуры
                                        ; от клавиатуры
                trap    50              ; Опрос клавиатуры
                br      4$
; ───────────────────────────────────────────────────────────────────────────

2$:             dec     R5
                beq     3$              ; только от джойстика
                tst     @#177714        ; параллельное, джойстик нажат?
                bne     3$              ; да - значит опросим джойстик
                trap    50              ; иначе - Опрос клавиатуры

3$:             trap    52              ; Опрос джойстика

4$:             dec     R4              ; дадим шанс нажать что-нибудь ещё
                bpl     1$
                mov     #177700, R4
                mov     PlayerScrAddr, R5 ; Адрес спрайта игрока
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                mov     R5, R1          ; это текущий адрес
                mov     GrowPlayerAddr, R3 ; Приращение адреса игрока
                add     R3, R5          ; это новый адрес
                cmp     #74400, R5      ; нижней границы достигли?
                bhis    5$              ; нет
                bic     R4, R5          ; да - не дадим опуститься ниже нижней границы
                bis     #74400, R5

5$:             cmp     #42300, R5      ; верхней границы достигли?
                blos    6$              ; нет
                bic     R4, R5          ; да - не дадим подняться выше верхней границы
                bis     #42300, R5

6$:             mov     R1, R2          ; текущий адрес
                bic     R4, R2          ; текущая горизонтальная позиция
                bic     #177770, R3
                beq     10$
                cmp     #5, R3
                bgt     8$
                mov     R5, R3          ; новый адрес
                bic     R4, R3          ; новая горизонтальная позиция
                cmp     R3, R2          ; движемся влево?
                blt     7$              ; да - переход
                add     #100, R5        ; коррекция при движении вправо
                sub     R3, R5

7$:             mov     #sprPlayerLt, CurSprPlayer ; Адрес текущего спрайта игрока
                mov     #-1, DirSprPlayer
                call    Morph_Left
                call    GoRigthConst    ; Установка констант для движения грунта вправо
                br      10$
; ───────────────────────────────────────────────────────────────────────────

8$:             mov     R5, R3
                add     #4, R3
                bic     R4, R3
                cmp     R2, R3
                blt     9$
                sub     R3, R5

9$:             mov     #sprPlayerRt, CurSprPlayer ; Адрес текущего спрайта игрока
                mov     #1, DirSprPlayer
                call    Morph_Right
                call    GoLeftConst     ; Установка констант для движения грунта влево
10$:            mov     R0, -(SP)
                mov     R1, -(SP)
                cmp     #sprPlayerRt, R0
                bne     14$
                ; смотрели вправо
                mov     CurrVyhlopSpr, R0 ; адрес текущего спрайта выхлопа игрока
                add     #2000, R1
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R5, R1
                add     #2000, R1
                tst     DirSprPlayer    ; куда теперь смотрим?
                bpl     11$             ; по прежнему вправо
                tst     (R1)+           ; влево
31$:            mov     #sprVyhlopLt1, R0 ; будет левый выхлоп
                br      30$
; ───────────────────────────────────────────────────────────────────────────
                ; продолжаем смотреть вправо
11$:            cmp     #sprVyhlopRt2, R0
                bhi     13$
                br      32$
; ───────────────────────────────────────────────────────────────────────────
                ; смотрели влево
14$:            mov     CurrVyhlopSpr, R0 ; адрес текущего спрайта выхлопа игрока
                add     #2002, R1
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R5, R1
                add     #2002, R1
                tst     DirSprPlayer    ; куда теперь смотрим?
                bmi     15$             ; по прежнему влево
                tst     -(R1)           ; вправо
32$:            mov     #sprVyhlopRt1, R0 ; будет правый выхлоп
                br      30$
; ───────────────────────────────────────────────────────────────────────────
                ; продолжаем смотреть влево
15$:            cmp     #sprVyhlopLt2, R0
                blos    31$

13$:            add     #SprVyhlopSize, R0
30$:            mov     R0, CurrVyhlopSpr ; адрес текущего спрайта выхлопа игрока
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     (SP)+, R1
                mov     (SP)+, R0
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R5, R1
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R1, PlayerScrAddr ; Адрес спрайта игрока
; теперь обработка стрельбы
                tst     FireFlag        ; Флаг стрельбы
                beq     25$             ; не стреляет, выходим
                bic     #177770, NewShootCnt ; счётчик до возможности нового выстрела
                dec     NewShootCnt     ; выстреливать пора?
                bne     25$             ; нет ещё - выходим
                mov     R1, R0          ; Адрес спрайта игрока
                mov     (PC)+, (PC)+
ShootSpeed:     .word   5               ; Ускорение стрельбы (меньше - быстрее)
NewShootCnt:    .word   1               ; счётчик до возможности нового выстрела
                mov     #SoundPlayerShoot, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                add     #700, R0
                mov     NShooting, R3   ; Количество выстреливаемых очередей
                bne     21$
                mov     #-3, R1         ; одна очередь
                br      23$
; ───────────────────────────────────────────────────────────────────────────

21$:            cmp     #1, R3
                bne     22$
                mov     #-103, R1       ; две очереди
                br      23$
; ───────────────────────────────────────────────────────────────────────────

22$:            mov     #-203, R1       ; три очереди

23$:            tst     DirSprPlayer
                bmi     24$
                add     #3, R0          ; направление вправо
                neg     R1

24$:            call    sub_20650       ; Поиск в массиве свободного пространства для рисования пульки
                                        ; Выход: R5 - указатель в массиве на пустой элемент
                                        ; Размер одного элемента 6 слов
                mov     R1, -2(R5)      ; приращение к адресу
                mov     R0, (R5)+       ; адрес экрана
                mov     #500, (R5)+
                mov     #4, (R5)+
                mov     #1, (R5)+
                clr     (R5)+

                dec     R3              ; сколько очередей?
                bmi     25$             ; одна - выход
26$:            cmp     #-103, R1       ; две?
                beq     27$
                cmp     #-3, R1
                bne     28$

27$:            add     #400, R1        ; новый адрес для второй очереди
                br      24$

28$:            cmp     #-203, R1
                beq     27$
                sub     #200, R1
                br      24$

25$:            return

; End of function PlayerAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Поиск в массиве свободного пространства для рисования пульки
; Выход: R5 - указатель в массиве на пустой элемент
; Размер одного элемента 6 слов

sub_20650:      mov     #PlayersBulletBuffer+2, R5 ; буфер пулек игрока
                mov     #PlayersBulletBufferItemsNum, R4 ; количество элементов

1$:             tst     (R5)            ; пусто?
                beq     2$              ; да - нашли место
                add     #PlayersBulletBufferItemSize, R5 ; переходим к следующей позиции
                sob     R4, 1$          ; и так весь массив
                tst     (SP)+           ; массив заполнен, вообще выходим из родительской функции

2$:             return
; End of function sub_20650


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Обработка и анимация полёта пулек игрока

PlayerBulletsAnim:
                mov     #PlayersBulletBuffer+2, R5 ; массив пулек игрока
                mov     #PlayersBulletBufferItemsNum, R4 ; количество элементов

1$:             mov     (R5), R1        ; пулька на экране?
                beq     3$              ; нет
                mov     -2(R5), R3      ; приращение к адресу
                mov     #sprBulletLt, R0
                bit     #2, R3          ; куда летит?
                beq     4$              ; влево
                mov     #sprBulletRt, R0 ; вправо - корректируем спрайт

4$:             trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                cmp     #76600, R1      ; до нижней границы долетели?
                blos    10$             ; да - очищаем элемент, пулька улетела за экран
                cmp     #42300, R1      ; до верхней границы долетели?
                bhis    10$             ; да - очищаем элемент, пулька улетела за экран
                bit     #74, R1         ; до левой границы долетели?
                beq     10$             ; да - очищаем элемент, пулька улетела за экран
                mov     R1, R2
                add     #4, R2          ; до правой границы долетели?
                bit     #74, R2
                bne     8$              ; нет
10$:            clr     R1              ; да - очищаем элемент, пулька улетела за экран
                br      9$              ; пульки уже нету, не надо рисовать

8$:             add     R3, R1          ; новый адрес
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
9$:             mov     R1, (R5)        ; сохраняем новый адрес

3$:             add     #PlayersBulletBufferItemSize, R5 ; нет - переходим к следующему элементу
2$:             sob     R4, 1$
                return
; ───────────────────────────────────────────────────────────────────────────

; End of function PlayerBulletsAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Обработка разлёта осколков от объектов при попадании

FragScratchAnim:mov     #ScratchBuffer, R5
                mov     #ScratchBufferItemsNum, R4

1$:             mov     (R5)+, R0       ; это адрес спрайта осколков
                mov     R5, R3          ; указатель на мл байт
                cmp     #3000, (R5)     ; второе число 3000?
                beq     13$             ; да - элемент считается пустым
                cmpb    (R5)+, (R5)     ; сравним мл. байт и ст. байт
                bne     2$              ; не равны
                incb    (R5)            ; равны - увеличим ст. байт
                clrb    (R3)            ; обнулим мл.байт
                br      3$
; ───────────────────────────────────────────────────────────────────────────

2$:             incb    (R3)            ; увеличим мл.байт

3$:             movb    (R5)+, R3       ; берём ст.байт, это индекс в таблице приращений разлёта осколков
                asl     R3              ; *2
                mov     R3, -(SP)
                mov     R4, -(SP)

                mov     #8., R2         ; 8 осколков
4$:             mov     (R5), R1        ; берём очередной адрес
                beq     8$              ; нету - не надо ничего делать
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     ScratchOffsetTbl(R3), R1 ; формируем новый адрес
                cmp     #42300, R1      ; верхней границы достигли?
                bhis    7$              ; да - удаляем
                                        ; нет
                cmp     #77000, R1      ; нижней границы достигли?
                blos    7$              ; да - удаляем
                                        ; нет
                mov     R1, R4          ; левого края экрана достигли?
                bic     #177700, R4
                beq     7$              ; да - удаляем
                                        ; нет
                cmp     #77, R4         ; правого края экрана достигли?
                bne     8$              ; нет
7$:             clr     R1              ; да - удаляем
8$:             tst     (R3)+           ; следующий индекс приращения
                cmp     #ScratchOffsetTblSize, R3 ; двигаем указатель циклически
                bne     9$
                clr     R3

9$:             mov     R1, (R5)+       ; следующий адрес
                sob     R2, 4$          ; и так все 8 осколков
                mov     (SP)+, R4
                mov     (SP)+, R3       ; берём значение
                cmp     #14, R3         ; там начальное значение?
                beq     14$             ; да - ничего не делать
                                        ; иначе, это индекс в таблице приращений адресов разлёта осколков
; теперь выводим на новых местах
                sub     #ScratchBufferItemSize-4, R5 ; возвращаемся началу таблицы адресов осколков
                mov     #8., R2         ; у нас 8 осколков

10$:            mov     (R5)+, R1       ; берём очередной адрес
                beq     11$             ; 0 - нету
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана

11$:            tst     (R3)+           ; следующий индекс приращения
                cmp     #ScratchOffsetTblSize, R3 ; двигаем указатель циклически
                bne     12$
                clr     R3

12$:            sob     R2, 10$         ; и так все 8 осколков
                mov     #SoundScratch, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                call    GameSpeedup     ; Уменьшаем игровую задержку
                br      14$
; ───────────────────────────────────────────────────────────────────────────

13$:            add     #ScratchBufferItemSize-2, R5 ; переходим к следующему элементу
14$:            dec     R4
                bne     1$              ; пока всю таблицу не осмотрим
                return
; End of function FragScratchAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Подготовка прорисовки элементов на поверхности земли

Morph_Left:     mov     #6005, Morph1$          ; ror
                mov     #sub_left, Morph2$+2
                mov     #6100, Morph3$          ; rol
                mov     #6100, Morph4$          ; rol
                mov     #62701, Morph5$         ; add
                mov     #Buffer2End, Morph6$+2
                mov     #Buffer2, Morph7$+2
                bic     #77, Morph8$            ; левый край экрана
                bic     #77, Morph9$            ; левый край экрана
                mov     #4, Morph10$
                mov     #3, Morph11$
                return

Morph_Right:    mov     #6105, Morph1$          ; rol
                mov     #sub_Right, Morph2$+2
                mov     #6000, Morph3$          ; ror
                mov     #6000, Morph4$          ; ror
                mov     #162701, Morph5$        ; sub
                mov     #Buffer2-2, Morph6$+2
                mov     #Buffer2End-2, Morph7$+2
                bis     #73, Morph8$            ; правый край экрана
                bis     #73, Morph9$            ; правый край экрана
                mov     #0, Morph10$
                mov     #1, Morph11$
                return

; End of function

; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Прорисовка элементов на поверхности земли

DrawTrees:      dec     (PC)+           ; новое дерево пора выводить?
NewTreeCnt:     .word 3
                bne     8$              ; нет ещё
                ; пора
                mov     TreesDelays, R5 ; формируем новую задержку
                mov     R5, R4
                bic     #177770, R4
                add     #7, R4
                mov     R4, NewTreeCnt
                mov     #3, R0          ; сдвигаем циклически, чтобы получить новую задержку
                ccc

Morph1$:        ror     R5
                sob     R0, Morph1$

Morph2$:        call    @#sub_left      ; корректируем значение
                mov     R5, TreesDelays ; сохраняем
                ; ищем в буфере деревьев пустое место
                mov     #TreeBuffer, R5
                mov     #TreeBufferItemsNum, R4 ; количество элементов в буфере

1$:             tst     (R5)            ; пусто?
                beq     2$              ; да
                add     #TreeBufferItemSize, R5 ; нет - идём к следующему элементу
                sob     R4, 1$          ; и так весь массив
                return
; ───────────────────────────────────────────────────────────────────────────
                ; нашли
2$:             mov     (PC)+, R0
Buf2Mask$:      .word   0               ; начальное значение 1
                mov     (PC)+, R1
Buf2Ptr$:       .word   0               ; начальное значение - начало буфера 2
                mov     R1, (R5)+       ; сохраним текущий указатель
                bit     (R1), R0        ; бит есть в массиве Buffer2?
                bne     3$              ; да
                clr     (R5)            ; нет - маску обнулим
                br      4$
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     R0, (R5)        ; если бит есть в массиве Buffer2, маску сохраним

4$:             ccc
Morph3$:        rol     R0              ; двигаем циклически бит по разрядам
                bcc     5$
Morph4$:        rol     R0              ; если случился перенос
Morph5$:        add     #2, R1          ; то переходим к следующему слову массива

Morph6$:        cmp     #Buffer2End, R1
                bne     5$
Morph7$:        mov     #Buffer2, R1

5$:             mov     R1, Buf2Ptr$
                mov     R0, Buf2Mask$
                tst     (R5)+           ; маска есть?
                beq     6$              ; нету
                mov     (PC)+, (R5)+    ; есть - адрес нормального дерева
Morph8$:        .word 74600
                br      7$
; ───────────────────────────────────────────────────────────────────────────

6$:             mov     (PC)+, (R5)+    ; нету - адрес сломанного дерева
Morph9$:        .word 76400

7$:             mov     #2600, (R5)+    ; габариты
                mov     #3, (R5)+
                mov     #401, (R5)+     ; крепкость
                mov     #Sprite9$, (R5)+  ; спрайт частиц осколков
                mov     #3, (R5)+
                ; теперь выводим на экран
8$:             mov     #TreeBuffer+4, R2

OutTreeLoop$:   mov     #sprTree, R0    ; спрайт дерева
                mov     (R2), R1        ; адрес спрайта
                beq     12$             ; 0 - нету дерева
                bit     #2000, R1       ; нормальное?
                beq     9$              ; да
                add     #sprBreakTree-sprTree, R0 ; нет - сломанное

9$:             trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     (PC)+, R1       ; проверка на выход за границы экрана
Morph10$:       .word 4
                bit     #77, R1
                bne     11$             ; ещё не вышло
                clr     (R2)            ; вышло - обнуляем адрес экрана
                cmp     #sprTree, R0    ; это дерево?
                beq     10$             ; да
                bic     -(R2), @-(R2)   ; нет - очищаем биты второго слова по адресу первого слова
                add     #4, R2

10$:            clr     -4(R2)          ; обнуляем первое слово
                br      12$
; ───────────────────────────────────────────────────────────────────────────

11$:            sub     (PC)+, R1       ; сдвигаем
Morph11$:       .word 3
                mov     R1, (R2)        ; сохраняем новый адрес
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                cmp     #sprBreakTree, R0 ; если дерево сломано, ничего не надо делать
                beq     12$
                mov     R0, R3          ; адрес спрайта сохраним
                mov     R2, R5
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                mov     #PlayerScrAddr, R4 ; Адрес спрайта игрока
                ; Проверка на разрушение дерева игроком или случайным попаданием врага
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                trap    56              ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта
                trap    64              ; проверка попали ли вражеские выстрелы в объект
                                        ; Вход: R3 - адрес спрайта объекта
                                        ;       R5 - структура объекта
                tstb    7(R2)           ; дерево сломалось?
                bne     12$             ; нет
                tstb    PlayerHit       ; 0 - есть попадание в игрока
                                        ; !0 - нет попадания
                bne     13$
                inc     ObjForce

13$:            bic     #177700, (R2)   ; да - теперь у него такой адрес
                bis     #76400, (R2)

12$:            add     #TreeBufferItemSize, R2
                cmp     #TreeBufferEnd+4, R2
                bne     OutTreeLoop$
                return
; ───────────────────────────────────────────────────────────────────────────

sub_Left:       dec     DigitsCounter
                bpl     1$
                mov     #6, DigitsCounter
                mov     #75037, R5

1$:             return

sub_Right:      inc     DigitsCounter
                cmp     #6, DigitsCounter
                bne     1$
                clr     DigitsCounter
                mov     #[75037 << 1], R5
                ;asl     R5

1$:             return
; End of function DrawTrees


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Функция подготавливает структуру параметров пушки

CannonPrepare:  mov     CannonBufPtr, R5 ; берём указатель в буфере пушек
                mov     (PC)+, R1
NewCannonCnt:   .word 14                ; Счётчик до появления новой пушки на экране
                tst     DirSprPlayer    ; направление движения?
                bpl     6$              ; вправо
                ;влево
                dec     R1
                bne     0ret$           ; ещё рано

                movb    (R5), R1        ; инициализируем счётчик

2$:             clr     R0              ; флаг подбитой пушки
                bitb    #100, (R5)+     ; пушка подбитая?
                beq     3$              ; нет
                com     R0              ; да

3$:             bic     #100, R1        ; снимаем флаг подбитой пушки у счётчика
                mov     #CannonStruct, R5 ; структура пушки
                tst     R0              ; пушка подбитая?
                beq     4$              ; нет
                mov     #1400, (R5)     ; да - вот такое будет приращение к адресу

4$:             tst     DirSprPlayer    ; направление движения?
                bmi     5$              ; влево
                bis     #73, (R5)       ; вправо - значит пушка появится с правого края

5$:             add     #75400, (R5)+
                mov     #2000, (R5)+
                mov     #3, (R5)+
                mov     #402, (R5)+
                mov     #sprCannonScratch, (R5)+
                mov     #1, (R5)+
0ret$:          mov     R1, NewCannonCnt
                return
; ───────────────────────────────────────────────────────────────────────────
; вправо
6$:             inc     R1              ; отматываем назад счётчик
                movb    (R5), R4        ; значение по указателю
                bic     #100, R4        ; признак сломанной пушки сбросим
                cmp     R1, R4          ; если значения ещё не достигло
                ble     0ret$           ; то просто выход

7$:             mov     #6, R1          ; вот такой счётчик по умолчанию
                dec     R5              ; указатель чуть назад
                br      2$
; End of function CannonPrepare


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Обработка и вывод пушек, проверка на коллизии
; и вывод сломанных пушек

CannonAnim:     mov     #CannonStruct, R5
                mov     (R5), R1        ; пушка на экране есть?
                beq     0Ret$           ; нету

1$:             bit     #2000, R1       ; какой у неё адрес
                beq     2$              ; как у нормальной
                mov     #sprBreakCannon, R0 ; будет сломанная пушка
                br      3$
; ───────────────────────────────────────────────────────────────────────────

2$:             mov     #sprCannon, R0  ; будет нормальная пушка
3$:             trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                tst     DirSprPlayer    ; куда летим?
                bmi     5$              ; влево
                ; вправо, значит грунт движется влево
                bit     #77, R1         ; за левый край ушла?
                beq     9$              ; да
                dec     R1
                br      6$
; ───────────────────────────────────────────────────────────────────────────
                ; влево, значит грунт движется вправо
5$:             mov     R1, R3
                add     #4, R3
                bit     #77, R3         ; за правый край ушла?
                beq     9$              ; да
                inc     R1

6$:             mov     R0, R3          ; спрайт пушки
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                mov     #PlayerScrAddr, R4 ; Адрес спрайта игрока
                call    sub_25600       ; проверка на столкновение игрока с пушкой
                                        ; и проверка подбил ли игрок пушку
                                        ; Вход: R3 - спрайт пушки
                                        ;       R5 - структура пушки
                mov     R3, R0
                tstb    PlayerHit       ; 0 - есть попадание в игрока
                                        ; !0 - нет попадания
                beq     7$
                tstb    7(R5)           ; кто кого заборол?
                bne     8$              ; пушка игрока
                ; игрок пушку
7$:             mov     #sprBreakCannon, R0 ; всё, пушка поломатая
                bic     #77700, R1
                bis     #77100, R1

8$:             mov     R1, (R5)        ; новый адрес экрана в структуре
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
0ret$:          return
; ───────────────────────────────────────────────────────────────────────────

9$:             mov     #CannonBufPtr, R3
                mov     (R3), R4        ; указатель в массиве
                bit     #2000, (R5)     ; пушка подбитая?
                beq     10$             ; нет
                bisb    #100, (R4)      ; да - поставим флаг

10$:            clr     (R5)            ; очищаем адрес экрана в структуре (пушка уехала за экран)
                tst     DirSprPlayer    ; куда летим?
                bpl     12$             ; вправо
                ; влево
                inc     R4
                cmp     #CannonBufferEnd+1, R4
                bne     11$
                mov     #CannonBuffer, R4
11$:            mov     R4, (R3)
                return
; ───────────────────────────────────────────────────────────────────────────
                ;вправо
12$:            dec     R4
                cmp     #CannonBuffer-1, R4
                bne     11$
                mov     #CannonBufferEnd, R4
                br      11$
; End of function CannonAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; проверка на столкновение игрока с пушкой
; и проверка подбил ли игрок пушку
; Вход: R3 - спрайт пушки
;       R5 - структура пушки

sub_25600:      bit     #2000, R1       ; пушка подбита
                bne     1$              ; да - ничего не делать
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                trap    56              ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта
1$:             return
; End of function sub_25600


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Выстрел из пушки

CannonShootAnim:bit     #400, CannonStruct  ; пушка поломатая, или её вообще нет?
                beq     0ret$           ; да - значит ничего не делать
                tst     (PC)+           ; время стрелять пришло?
NewCannonShootCnt:.word 7
                bne     12$             ; нет ещё
                ; да
                mov     #CannonBulletBuffer+2, R5
                mov     #CannonBulletBufferItemsNum, R4

2$:             tst     (R5)            ; адрес экрана
                beq     3$              ; нету - можно добавлять
                add     #EnemyBulletBufferItemSize, R5
                sob     R4, 2$
0ret$:          return

12$:            dec     NewCannonShootCnt ; просто уменьшаем счётчик
                return
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     #SoundCannonShoot, R1
                trap    14              ; Вывод звука
                                        ; Вход R1 - адрес таблицы параметров
                                        ; .word длит
                                        ; .word тон, тон,... (0 - конец таблицы)
                mov     #sprBallBullet, -2(R5)
                mov     CannonStruct, R4 ; адрес экрана пушки
                inc     R4
                mov     R4, (R5)+       ; начальный адрес выстрела
                mov     PlayerScrAddr, R3 ; Адрес спрайта игрока
                ; вот тут мы рассчитываем приращение к адресу в зависимости от положения игрока
                ; тоже по принципу как у охранников
                add     #3000, R3
                mov     R3, R1
                mov     R4, R2
                bic     #177700, R1
                bic     #177700, R2
                sub     R1, R2
                cmp     #3, R2
                blt     4$
                cmp     #-1, R2
                bgt     4$
                mov     #-500, (R5)+
                br      11$
; ───────────────────────────────────────────────────────────────────────────

4$:             cmp     R3, R4
                bmi     7$
                tst     R2
                bmi     5$
                mov     #-2, (R5)+
                br      11$
; ───────────────────────────────────────────────────────────────────────────

5$:             mov     #2, (R5)+
                br      11$
; ───────────────────────────────────────────────────────────────────────────

7$:             tst     R2
                bmi     9$
                sub     R3, R4

8$:             asr     R4
                asr     R2
                bne     8$
                bic     #77, R4
                inc     R4
                br      6$
; ───────────────────────────────────────────────────────────────────────────

9$:             sub     R3, R4
                com     R2

10$:            asr     R4
                asr     R2
                bne     10$
                bis     #77, R4
                add     #100, R4
6$:             neg     R4
                mov     R4, (R5)+

11$:            mov     #16, NewCannonShootCnt
                mov     #400, (R5)+     ; габариты выстрела
                mov     #2, (R5)+
                mov     #1, (R5)+       ; крепкость / убойная сила
                clr     (R5)            ; результат коллизии

13$:            tst     DirSprPlayer
                bpl     14$
                dec     -10(R5) ; если движемся влево, то приращение к адресу корректируем
14$:            return
; End of function CannonShootAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Анимация полёта выстрелов врагов

EnemyShootAnim: mov     #EnemyBulletBuffer, R5
                mov     #EnemyBulletBufferItemsNum, R2

1$:             mov     (R5)+, R0       ; адрес спрайта выстрела
                cmp     #sprBallBullet, R0 ; такой?
                bne     3$              ; нет - не такие не обрабатываем
                mov     (R5), R1        ; адрес экрана
                beq     3$              ; 0 - тоже не обрабатываем

5$:             trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     2(R5), R1       ; новый адрес
                tst     DirSprPlayer    ; куда летим?
                bpl     6$              ; вправо
                inc     R1              ; влево

6$:             cmp     #77000, R1      ; за нижнюю границу вышли?
                bmi     7$              ; да - удаляем
                cmp     #42300, R1      ; за верхнюю границу вышли?
                bmi     8$              ; нет

7$:             clr     (R5)            ; удаляем с экрана
                br      3$
; ───────────────────────────────────────────────────────────────────────────

8$:             bit     #74, R1         ; за левую границу вышли?
                beq     7$              ; да
                mov     R1, R3          ; за правую границу вышли?
                add     #2, R3
                bit     #74, R3
                beq     7$              ; да
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R1, (R5)
3$:             add     #EnemyBulletBufferItemSize-2, R5
2$:             sob     R2, 1$
                return
; End of function EnemyShootAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

;  тут мы едем по земле и поднимаем клубы пыли

DustCloudAnim:  clr     GrowPlayerAddr  ; ниже опускаться некуда
                cmp     PlayerScrAddr, #74300 ; Адрес спрайта игрока
                blo     4$
                sub     #600, GrowPlayerAddr ; подпрыгиваем на столько
                mov     #SmlCloudsTbl, R5
                mov     #SmlCloudsNum, R4
20$:            tst     (R5)            ; ищем в таблице пустое место
                beq     1$              ; нашли
                add     #SmlCloudsItemSize, R5
                sob     R4, 20$
                br      4$              ; не нашли

1$:             mov     #sprSmlCloud1-SprSmlCloudsSize, (R5)+ ; адрес спрайта облака
                mov     PlayerScrAddr, R4 ; Адрес спрайта игрока
                tst     DirSprPlayer
                bpl     2$
                add     #1501, R4
                br      3$
; ───────────────────────────────────────────────────────────────────────────

2$:             add     #1477, R4
3$:             mov     R4, (R5)+       ; адрес экрана

4$:             ;com     #0
                ;bne     21$
                ; обработаем таблицу
                mov     #SmlCloudsTbl, R5
                mov     #SmlCloudsNum, R4

5$:             mov     (R5)+, R0       ; адрес спрайта
                bne     7$              ; есть

6$:             tst     (R5)+
                sob     R4, 5$
21$:            return
; ───────────────────────────────────────────────────────────────────────────

7$:             mov     (R5), R1        ; адрес экрана
                beq     6$              ; нету - пропускаем
                cmp     #sprSmlCloudEnd, R0
                bne     8$
                mov     #sprSmlCloud1, R0
                trap    42              ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                clr     -2(R5)          ; всё кончилось облако
                br      6$
; ───────────────────────────────────────────────────────────────────────────

8$:             cmp     #sprSmlCloud1-SprSmlCloudsSize, R0 ; начальное состояние?
                beq     9$              ; да - ещё нечего стирать
                trap    42              ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
9$:             add     #SprSmlCloudsSize, R0 ; следующий спрайт
                cmp     #sprSmlCloudEnd, R0 ; дошли до конца?
                bne     10$             ; нет
                ; да
                mov     #sprSmlCloud1, R0 ; рисуем первое облако
                trap    34              ; Вывод спрайта на экран movом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     #SprSmlCloudsSize, R0 ; а стираем второе
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     #sprSmlCloudEnd, R0 ;делаем конечный вариант
                br      11$             ; в следующий раз очистим.
; ───────────────────────────────────────────────────────────────────────────

10$:            trap    34              ; Вывод спрайта на экран movом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
11$:            mov     R0, -2(R5)      ; сохраняем новый спрайт
                br      6$
; End of function DustCloudAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и анимация ящика с жизнью

LiveBoxAnim:    cmp     Lives, #<9. | [9. << 8.]> ; жизней и так максимум?
                beq     0ret$           ; да - никаких ящиков
                mov     #LiveBoxScrAddr, R5
                tst     (PC)+           ; пришло время выводить на экран?
LiveBoxCnt:     .word 324
                bne     3$              ; нет ещё
                ; пришло, формируем новый ящик
                mov     #500, LiveBoxCnt
                tst     (R5)            ; ящик на экране?
                bne     0ret$           ; да - не надо добавлять новый
                ; нет - добавим
                mov     @#177710, R4
                bic     #77, R4
                add     #42002, R4
                mov     R4, (R5)        ; новый адрес ящика

3$:             dec     LiveBoxCnt
                mov     (R5)+, R1       ; текущий адрес ящика
                beq     0ret$           ; вне экрана - выход
                ; если на экране - продолжаем
                mov     #sprLiveBox, R0
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                dec     (R5)+           ; LiveBoxDelay
                bne     6$              ; задержка ещё не истекла

5$:             mov     (R5), R4        ; LiveBoxTrack - указатель в массиве BoxTrckOffsets
                tst     (R4)+           ; там было смещение
                mov     (R4)+, R3       ; берём новую задержку, ещё раз двигаем указатель на новое смещение
                cmp     #BoxTrckOffsetsEnd+2, R4 ; дошли до конца массива?
                bhi     8$              ; нет
                mov     #11, R3         ; да
                mov     #BoxTrckOffsets, R4

8$:             mov     R3, -2(R5)      ; сохраняем новую задержку
                mov     R4, (R5)        ; сохраняем новое значение указателя

6$:             mov     R1, R2          ; адрес экрана
                add     @(R5)+, R2      ; прибавляем смещение
                tst     -(R5)           ; возвращаем указатель назад
                cmp     #42300, R2      ; проверяем не вышло ли за экран
                bhis    5$
                cmp     #76000, R2
                blos    5$
                bit     #76, R2
                beq     5$
                mov     R2, R4
                add     #3, R4
                bit     #76, R4
                bne     7$
                clr     -4(R5)          ; вышло за экран
                return
; ───────────────────────────────────────────────────────────────────────────
                ; не вышло - рисуем на новом месте
7$:             mov     R2, R1
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R1, -4(R5)
0ret$:          return

; End of function LiveBoxAnim



; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка поймал ли игрок коробку с жизнью
; и если да - то увеличение жизней

LiveBoxCatch:   mov     #TmpStructBox, R5
                mov     #TmpStructPlayer, R4
                mov     #1, 6(R4)
                mov     PlayerScrAddr, (R4) ; Адрес спрайта игрока
                mov     #1, 6(R5)
                mov     LiveBoxScrAddr, (R5)
                mov     #sprLiveBox, R3
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                tst     6(R5)
                bne     1$
                tst     6(R4)
                bne     1$

                mov     #EndLives, R0
                call    IncreaseValue   ; Увеличение двоично-десятичного числа
                                        ; Вход: R0 - конец числа
                mov     #SoundLBoxCatch, R1
                trap    14
                clr     LiveBoxScrAddr
                mov     #Lives, R5
                mov     #41036, R1
                trap    60              ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана
1$:             return
; End of function LiveBoxCatch

; ───────────────────────────────────────────────────────────────────────────


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и анимация ящика с ускорением

SpeedBoxAnim:   cmp     MoveSpeed, #2   ; Скорость и так максимум?
                beq     0Ret$           ; да - выход
                mov     #SpeedBoxScrAddr, R5
                tst     (PC)+           ; пришла пора выводить новый ящик?
SpeedBoxCnt:    .word 263
                bne     3$              ; нет
                ; да
                mov     #440, SpeedBoxCnt
                tst     (R5)            ; ящик на экране?
                bne     0Ret$           ; да - не надо добавлять новый
                ; нет - добавим
                mov     @#177710, R4
                bic     #77, R4
                add     #42002, R4
                mov     R4, (R5)

3$:             dec     SpeedBoxCnt
                mov     (R5)+, R1       ; текущий адрес ящика
                beq     0Ret$           ; вне экрана - выход
                ; если на экране - продолжаем
                mov     #sprSpeedBox, R0
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                dec     (R5)+
                bne     6$              ; задержка ещё не истекла

5$:             mov     (R5), R4        ; указатель в массиве BoxTrckOffsets
                tst     (R4)+           ; там было смещение
                mov     (R4)+, R3       ; берём новую задержку, ещё раз двигаем указатель на новое смещение
                cmp     #BoxTrckOffsetsEnd+2, R4 ; дошли до конца массива?
                bhi     8$              ; нет
                mov     #11, R3         ; да
                mov     #BoxTrckOffsets, R4

8$:             mov     R3, -2(R5)      ; сохраняем новую задержку
                mov     R4, (R5)        ; сохраняем новое значение указателя

6$:             mov     R1, R2          ; адрес экрана
                add     @(R5)+, R2      ; прибавляем смещение
                tst     -(R5)           ; возвращаем указатель назад
                cmp     #42300, R2      ; проверяем не вышло ли за экран
                bhis    5$
                cmp     #76000, R2
                blos    5$
                bit     #76, R2
                beq     5$
                mov     R2, R4
                add     #3, R4
                bit     #76, R4
                bne     7$
                clr     -4(R5)          ; вышло за экран
                return
; ───────────────────────────────────────────────────────────────────────────
                ; не вышло - рисуем на новом месте
7$:             mov     R2, R1
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R2, -4(R5)
0Ret$:          return
; End of function SpeedBoxAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка поймал ли игрок коробку с ускорением
; и если да - то увеличение скорости передвижения

SpeedBoxCatch:  mov     #TmpStructBox, R5
                mov     #TmpStructPlayer, R4
                mov     #1, 6(R4)
                mov     PlayerScrAddr, (R4) ; Адрес спрайта игрока
                mov     #1, 6(R5)
                mov     SpeedBoxScrAddr, (R5)
                mov     #sprSpeedBox, R3
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                tst     6(R5)
                bne     1$
                tst     6(R4)
                bne     1$

                inc     MoveSpeed       ; Скорость передвижения
                mov     #SoundSBoxCatch, R1
                trap    14
                clr     SpeedBoxScrAddr
1$:             return
; End of function SpeedBoxCatch


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и анимация ящика N - Увеличение числа очередей

NBoxAnim:       cmp     NShooting, #2   ; Количество выстреливаемых очередей и так максимум?
                beq     0ret$           ; да - никаких ящиков
                mov     #NBoxScrAddr, R5
                tst     (PC)+           ; пришло время выводить на экран?
NBoxCnt:        .word 10
                bne     3$              ; нет ещё
                ; пришло, формируем новый ящик
                mov     #411, NBoxCnt
                tst     (R5)            ; ящик на экране?
                bne     0ret$           ; да - не надо добавлять новый
                ; нет - добавим
                mov     @#177710, R4
                bic     #77, R4
                add     #42002, R4
                mov     R4, (R5)        ; новый адрес ящика

3$:             dec     NBoxCnt
                mov     (R5)+, R1       ; текущий адрес ящика
                beq     0ret$           ; вне экрана - выход
                ; если на экране - продолжаем
                mov     #sprNBox, R0
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                dec     (R5)+
                bne     6$              ; задержка ещё не истекла

5$:             mov     (R5), R4        ; указатель в массиве BoxTrckOffsets
                tst     (R4)+           ; там было смещение
                mov     (R4)+, R3       ; берём новую задержку, ещё раз двигаем указатель на новое смещение
                cmp     #BoxTrckOffsetsEnd+2, R4 ; дошли до конца массива?
                bhi     8$              ; нет
                mov     #11, R3         ; да
                mov     #BoxTrckOffsets, R4

8$:             mov     R3, -2(R5)      ; сохраняем новую задержку
                mov     R4, (R5)        ; сохраняем новое значение указателя

6$:             mov     R1, R2          ; адрес экрана
                add     @(R5)+, R2      ; прибавляем смещение
                tst     -(R5)           ; возвращаем указатель назад
                cmp     #42300, R2      ; проверяем не вышло ли за экран
                bhis    5$
                cmp     #76000, R2
                blos    5$
                bit     #76, R2
                beq     5$
                mov     R2, R4
                add     #3, R4
                bit     #76, R4
                bne     7$
                clr     -4(R5)          ; вышло за экран
                return
; ───────────────────────────────────────────────────────────────────────────
                ; не вышло - рисуем на новом месте
7$:             mov     R2, R1
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R2, -4(R5)
0ret$:          return
; End of function NBoxAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка поймал ли игрок коробку с N
; и если да - то увеличение числа выстреливаемых очередей

NBoxCatch:      mov     #TmpStructBox, R5
                mov     #TmpStructPlayer, R4
                mov     #1, 6(R4)
                mov     PlayerScrAddr, (R4) ; Адрес спрайта игрока
                mov     #1, 6(R5)
                mov     NBoxScrAddr, (R5)
                mov     #sprNBox, R3
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                tst     6(R5)
                bne     1$
                tst     6(R4)
                bne     1$

                inc     NShooting       ; Количество выстреливаемых очередей
                mov     #SoundNBoxCatch, R1
                trap    14
                clr     NBoxScrAddr
1$:             return
; End of function NBoxCatch


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Вывод и анимация ящика F - увеличение скорострельности

ForceBoxAnim:   cmp     #1, ShootSpeed  ; стрельба и так максимально ускорена?
                beq     0ret$           ; да - ничего не делаем
                mov     #ForceBoxScrAddr, R5
                tst     (PC)+           ; пришло время выводить на экран?
ForceBoxCnt:    .word 161
                bne     3$              ; нет ещё
                ; пришло, формируем новый ящик
                mov     #333, ForceBoxCnt
                tst     (R5)            ; ящик на экране?
                bne     0ret$           ; да - не надо добавлять новый
                ; нет - добавим
                mov     @#177710, R4
                bic     #77, R4
                add     #42002, R4
                mov     R4, (R5)        ; новый адрес ящика

3$:             dec     ForceBoxCnt
                mov     (R5)+, R1       ; текущий адрес ящика
                beq     0ret$           ; вне экрана - выход
                ; если на экране - продолжаем
                mov     #sprForceBox, R0
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                dec     (R5)+
                bne     6$              ; задержка ещё не истекла

5$:             mov     (R5), R4        ; указатель в массиве BoxTrckOffsets
                tst     (R4)+           ; там было смещение
                mov     (R4)+, R3       ; берём новую задержку, ещё раз двигаем указатель на новое смещение
                cmp     #BoxTrckOffsetsEnd+2, R4 ; дошли до конца массива?
                bhi     8$              ; нет
                mov     #11, R3         ; да
                mov     #BoxTrckOffsets, R4

8$:             mov     R3, -2(R5)      ; сохраняем новую задержку
                mov     R4, (R5)        ; сохраняем новое значение указателя

6$:             mov     R1, R2          ; адрес экрана
                add     @(R5)+, R2      ; прибавляем смещение
                tst     -(R5)           ; возвращаем указатель назад
                cmp     #42300, R2      ; проверяем не вышло ли за экран
                bhis    5$
                cmp     #76000, R2
                blos    5$
                bit     #76, R2
                beq     5$
                mov     R2, R4
                add     #3, R4
                bit     #76, R4
                bne     7$
                clr     -4(R5)          ; вышло за экран
                return
; ───────────────────────────────────────────────────────────────────────────
                ; не вышло - рисуем на новом месте
7$:             mov     R2, R1
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R2, -4(R5)
0ret$:          return
; End of function ForceBoxAnim

; ───────────────────────────────────────────────────────────────────────────


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка поймал ли игрок коробку с F
; и если да - увеличиваем скорострельность

FBoxCatch:      mov     #TmpStructBox, R5
                mov     #TmpStructPlayer, R4
                mov     #1, 6(R4)
                mov     PlayerScrAddr, (R4) ; Адрес спрайта игрока
                mov     #1, 6(R5)
                mov     ForceBoxScrAddr, (R5)
                mov     #sprForceBox, R3
                mov     CurSprPlayer, R0 ; Адрес текущего спрайта игрока
                trap    54              ; Проверка на коллизию.
                                        ; Вход: R0 - адрес спрайта объекта 2
                                        ;       R3 - адрес спрайта объекта 1
                                        ;       R4 - структура объекта 2
                                        ;       R5 - структура объекта 1
                                        ; Формат структуры см в другом месте
                tst     6(R5)
                bne     1$
                tst     6(R4)
                bne     1$

                dec     ShootSpeed      ; Ускорение стрельбы (меньше - быстрее)
                mov     #SoundFBoxCatch, R1
                trap    14
                clr     ForceBoxScrAddr
1$:             return
; End of function FBoxCatch


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


InitRoger:      clr     RogerScrAddr    ; Экранный адрес черепа с костями
                clr     RogerOffset     ; Приращение экранного адреса черепа с костями
                return
; End of function InitRoger


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


RogerAnim:      mov     RogerScrAddr, R1 ; Экранный адрес черепа с костями
                tst     (PC)+           ; пора выводить на экран?
RogerCnt:       .word 201
                bne     3$              ; нет ещё
                ; пора
                tst     R1              ; а по экрану ещё старый летает?
                bne     4$              ; да - его будем обрабатывать
                ; нет, новый выведем
                mov     #244, RogerCnt  ; инициализируем счётчик
                mov     @#177710, R1    ; генерируем адрес экрана
                bic     #7777, R1
                tst     DirSprPlayer
                bpl     1$
                add     #42201, R1
                br      2$
; ───────────────────────────────────────────────────────────────────────────

1$:             add     #42273, R1
2$:             mov     R1, RogerScrAddr ; сохраняем новый адрес

3$:             dec     RogerCnt
4$:             mov     #sprRoger, R0
                tst     R1              ; череп на экране?
                beq     0Ret$           ; нету - и делать нечего
; ───────────────────────────────────────────────────────────────────────────

5$:             mov     DirSprPlayer, R2
                neg     R2              ; движение в противоположную игроку сторону

                add     RogerOffset, R2 ; Приращение экранного адреса черепа с костями
                add     R1, R2          ; новый адрес экрана
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                cmp     #74000, R2      ; на землю упал?
                blos    11$             ; да - идём обрабатывать
                ; нет
                bit     #77, R2         ; за левый край вылетел?
                beq     InitRoger       ; да - всё нету его

8$:             mov     R2, R1
                add     #4, R2          ; за правый край вылетел?
                bit     #77, R2
                beq     InitRoger       ; да - всё нету его
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R1, RogerScrAddr ; сохраним новый адрес
                mov     #RogerStruct, R5
                mov     #1, 6(R5)       ; крепкость
                mov     RogerScrAddr, (R5) ; Экранный адрес черепа с костями
                mov     #sprRoger, R3
                tst     RogerOffset     ; Приращение экранного адреса черепа с костями
                bne     9$
                trap    56              ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта

9$:             tst     6(R5)           ; подбили?
                bne     0Ret$           ; нет
                ; подбили, начал падать
10$:            mov     #400, RogerOffset ; Приращение экранного адреса черепа с костями
                mov     #5, <0RogerCnt$>
0Ret$:          return
; ───────────────────────────────────────────────────────────────────────────
; упал на землю.
11$:            bic     #77000, R1      ; старый адрес экрана
                bis     #74000, R1      ; не дадим упасть ещё ниже
                clr     RogerOffset     ; всё, падать перестал
                mov     R1, RogerScrAddr ; вот его текущий адрес
                sub     #1500, R1
                bit     #1, <0RogerCnt$>
                beq     12$
                mov     #sprCloud1, R0
                br      13$
; ───────────────────────────────────────────────────────────────────────────

12$:            mov     #sprCloud2, R0
13$:            mov     #3, R3          ; три облака

14$:            trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     #1300, R1
                sob     R3, 14$
                tst     (PC)+
0RogerCnt$:     .word 0
                beq     18$
                mov     #LastItemPlrsBlltBuf, R5 ; заполняем структуру
                clr     (R5)+
                mov     (R5), @#102
                mov     #42310, (R5)+
                mov     #35000, (R5)+
                mov     #100, (R5)+
                mov     #-1, (R5)+
                clr     (R5)+
                dec     <0RogerCnt$> ; пока счётчик не кончился
                bit     #1, <0RogerCnt$> ; рисуем облака
                beq     15$
                mov     #sprCloud1, R0
                br      16$
; ───────────────────────────────────────────────────────────────────────────

15$:            mov     #sprCloud2, R0

16$:            mov     #3, R3
                sub     #4100, R1

17$:            trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     #1300, R1
                sob     R3, 17$
                mov     #SoundRogerFall, R1
                trap    14
                return
; ───────────────────────────────────────────────────────────────────────────

18$:            clr     RogerScrAddr  ; Экранный адрес черепа с костями
                mov     #LastItemPlrsBlltBuf, R5
                mov     #5, R4

19$:            clr     (R5)+
                sob     R4, 19$
                mov     @#102, R1
                beq     20$
                mov     #sprBulletLt, R0
                trap    42              ; Стирание спрайта с экрана clrом
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
20$:            return
; End of function RogerAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


UfoAnim:        tst     (PC)+
NewUFOCnt:      .word 57
                bne     5$
                mov     #101, @#NewUFOCnt
                ; ищем в буфере пустое место
                mov     #<EnemyBulletBuffer+2>, R5
                mov     #EnemyBulletBufferItemsNum, R4

1$:             tst     (R5)
                beq     2$
                add     #EnemyBulletBufferItemSize, R5
                sob     R4, 1$
                br      5$              ; не нашли
; ───────────────────────────────────────────────────────────────────────────
                ; нашли
2$:             tst     -(R5)
                mov     #sprUFO1, (R5)+ ; спрайт выстрела
                mov     @#177710, R4
                bic     #77, R4
                mov     DirSprPlayer, R3; куда летим?
                bpl     3$              ; вправо
                ; влево
                add     #42201, R4
                br      4$
; ───────────────────────────────────────────────────────────────────────────
                ; вправо
3$:             add     #42274, R4
4$:             neg     R3
                mov     R4, (R5)+       ; адрес экрана
                mov     R3, (R5)+       ; приращение к адресу
                mov     #700, (R5)+     ; габариты
                mov     #3, (R5)+
                mov     #400, (R5)+     ; крепкость
                clr     (R5)+           ; результат коллизии

5$:             dec     NewUFOCnt
                ; обработаем
                mov     #EnemyBulletBuffer, R5
                mov     #EnemyBulletBufferItemsNum, R4
                ; ищем в таблице только UFO
6$:             cmp     #sprUFO1, (R5)
                beq     8$
                cmp     #sprUFO2, (R5)
                beq     8$

7$:             add     #EnemyBulletBufferItemSize, R5
                sob     R4, 6$
16$:            return
; ───────────────────────────────────────────────────────────────────────────
                ; вылетел за экран
11$:            clr     -(R5)           ; удаляем из массива
                clr     -(R5)
                br      7$              ; и продолжим поиск

8$:             tstb    13(R5)          ; подбитый?
                beq     17$             ; да
                ; нет
                mov     (R5)+, R0       ; спрайт
                mov     (R5)+, R1       ; адрес экрана
                beq     15$             ; нету на экране
                ; есть
                mov     DirSprPlayer, R2 ; куда летим?
                neg     R2              ; приращение противоположно направлению движения
                add     (R5), R2        ; складываем с приращением спрайта
                add     R1, R2          ; получим новый адрес экрана
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                bit     #76, R2         ; за левый край экрана вылетел?
                beq     11$             ; да
                mov     R2, R3
                add     #3, R3
                bit     #76, R3         ; за правый край экрана вылетел?
                beq     11$             ; да
                add     #SprUFOSize, R0
                cmp     #sprUFOEnd, R0
                bne     14$
                mov     #sprUFO1, R0
14$:            mov     R2, R1          ; рисуем на новом месте
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
15$:            mov     R1, -(R5)       ; сохраняем новые параметры
                mov     R0, -(R5)
                br      7$              ; и продолжим поиск
; ───────────────────────────────────────────────────────────────────────────
                ; анимация подбития
17$:            mov     #Sound14$, R1
                trap    14
                clr     (R5)+           ; очищаем спрайт
                mov     (R5), R1        ; берём адрес экрана
                clr     (R5)            ; а в массиве - очищаем
                tst     -(R5)           ; возвращаем указатель на начало
                mov     R5, -(SP)
                mov     R4, -(SP)
                mov     #UFOScratchTbl, R3 ; таблица разлёта осколков
                mov     #<EnemyBulletBuffer+2>, R5
                mov     #EnemyBulletBufferItemsNum, R4

18$:            tst     (R5)            ; ищем пустое место
                bne     21$             ; нету
                ; нашли
                mov     (R3)+, R2       ; берём приращение
                beq     20$             ; таблица кончилась - всё
                mov     #sprBallBullet, -2(R5) ; спрайт
                mov     R5, R0
                mov     R1, (R0)+       ; адрес экрана
                mov     R2, (R0)+       ; приращение
                mov     #500, (R0)+     ; габариты
                mov     #2, (R0)+
                mov     #1, (R0)+       ; крепкость
                clr     (R0)+           ; результат коллизии

21$:            add     #EnemyBulletBufferItemSize, R5
19$:            sob     R4, 18$

20$:            mov     (SP)+, R4
                mov     (SP)+, R5
                br      7$
; End of function UfoAnim



; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; вывод и анимация простых блоков на экран

BlockMoveDir = 12

BlockWallAnim:  tst     (PC)+           ; пора выводить новый блок?
BlockWallCnt:   .word 146
                bne     7$              ; нет ещё
                ; пора
                mov     #207, BlockWallCnt
                mov     @#177710, R4
                bic     #177774, R4
                beq     BlockWallAnim   ; если 0 - ничего не получилось
                                        ; иначе - это количество блоков
                mov     @#177710, R3    ; получим случайный адрес экрана
                bic     #77, R3
                sub     #6000, R3
                bpl     1$
                clr     R3

1$:             add     #42200, R3
                mov     DirSprPlayer, R5 ; куда летим?
                bpl     2$               ; вправо
                ; влево
                add     #1, R3
                br      3$
; ───────────────────────────────────────────────────────────────────────────

2$:             add     #74, R3
3$:             neg     R5              ; приращение адреса
                mov     R5, @#BlockMoveDir ; будет противоположно направлению движения игрока
                ; ищем свободное место
                mov     #BlockBuf, R5
                mov     #BlockBufCommonItemsNum, R2

4$:             tst     (R5)+           ; свободно?
                beq     6$              ; да
                                        ; нет
5$:             tst     (R5)+
                sob     R2, 4$
                br      7$              ; не нашли
; ───────────────────────────────────────────────────────────────────────────
                ; нашли свободное место
6$:             tst     (R5)            ; второй параметр 0
                beq     5$              ; да - это плохое место, ищем дальше
                                        ; с нулём - блок при смерти, его надо удалить
                ; нашли
                mov     R3, -(R5)       ; адрес экрана сохраним
                add     #1500, R3       ; вниз
                sob     R4, 4$          ; и так всё кол-во блоков
                ; теперь обработка
7$:             dec     BlockWallCnt
                mov     #BlockBuf, R5
                mov     #BlockBufCommonItemsNum, R4
                mov     #sprBlockO, R0  ; спрайт блока

8$:             mov     (R5)+, R1       ; адрес экрана
                beq     12$             ; 0 - пропускаем
                tst     (R5)            ; количество жизней
                beq     9$              ; 0 - всё, надо удалять
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     @#BlockMoveDir, R1 ; новый адрес экрана
                bit     #76, R1         ; за левый край вылетел?
                bne     10$             ; нет
                                        ; да
9$:             clr     -2(R5)          ; удаляем блок
                br      12$
; ───────────────────────────────────────────────────────────────────────────

10$:            mov     R1, R2
                add     #3, R2
                bit     #76, R2         ; за правый край вылетел?
                beq     9$              ; да - удаляем блок
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                mov     R1, -2(R5)      ; сохраняем новый адрес
12$:            tst     (R5)+           ; переходим к следующему элементу
                sob     R4, 8$          ; массива
                return
; End of function BlockWallAnim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; проверка на подбитие блоков, и анимация выстрелов

BlockWall2Anim: mov     #BlockBuf, R2
                mov     #BlockBufItemsNum, R1

bw2.1$:         tst     (R2)            ; элемент пуст?
                bne     3$              ; нет
                add     #BlockBufItemSize, R2

bw2.2$:         sob     R1, bw2.1$
                return
; ───────────────────────────────────────────────────────────────────────────
                ; нашли элемент, который надо обработать
3$:             mov     #TmpBlockStruct, R5
                mov     (R2)+, (R5)     ; адрес экрана
                mov     (R2), 6(R5)     ; крепкость
                mov     #sprBlockO, R3
                trap    56              ; Проверка попаданиями пулек игрока в объект
                                        ; Вход: R3 - спрайт объекта
                                        ;       R5 - структура объекта
                mov     6(R5), (R2)+    ; сохраним результат
                bne     10$             ; блок не умер ещё
                mov     R1, -(SP)       ; умер - звук убитого блока
                mov     #Sound16$, R1
                trap    14
                mov     (SP)+, R1
                br      bw2.2$
                ; блок может стрелять
10$:            tst     (PC)+           ; стрелять пора?
BlkShootCnt:    .word 10                ; счётчик до выстрела
                bne     4$              ; нет ещё
                ; пора, поищем в таблице выстрелов свободное место
                mov     #20, BlkShootCnt
                mov     #EnemyBulletBuffer, R5
                mov     #EnemyBulletBufferItemsNum, R4

5$:             tst     2(R5)
                beq     6$              ; нашли
                add     #EnemyBulletBufferItemSize, R5
                sob     R4, 5$
                br      bw2.2$          ; не нашли
; ───────────────────────────────────────────────────────────────────────────
4$:             dec     BlkShootCnt
                br      bw2.2$
                ; выстрел
6$:             mov     -4(R2), R0      ; адрес экрана блока
                mov     PlayerScrAddr, R3 ; Адрес спрайта игрока
                trap    66              ; Расчёт направления выстрела вражеского объекта в игрока
                                        ; Вход: R0 - адрес экрана охранника или блока
                                        ;       R3 - адрес экрана игрока
                                        ; Выход: R3 - приращение адреса для полёта выстрела в игрока
                mov     #sprBallBullet, (R5)+
                call    sub_36200     ; Коррекция приращения и заполнение параметров структуры
                                        ; Вход: R0 - начальный адрес экрана
                                        ;       R3 - приращение адреса к выстрелу
                                        ;       R5 - указатель на текущий элемент в массиве EnemyBulletBuffer + 2
                mov     #500, (R5)+     ; габариты
                mov     #2, (R5)+
                mov     #1, (R5)+       ; крепкость
                clr     (R5)+           ;
                br      bw2.2$
; End of function BlockWall2Anim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Коррекция приращения и заполнение параметров структуры
; Вход: R0 - начальный адрес экрана
;       R3 - приращение адреса к выстрелу
;       R5 - указатель на текущий элемент в массиве EnemyBulletBuffer + 2

sub_36200:      tst     R3
                bpl     1$
                neg     R3
                call    sub_36230
                neg     R3
                br      2$
; ───────────────────────────────────────────────────────────────────────────

1$:             call    sub_36230

2$:             mov     R0, (R5)+       ; заполним начальный адрес экрана
                mov     R3, (R5)+       ; приращение к адресу
                return
; End of function sub_36200


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


sub_36230:      cmp     #700, R3        ; если R3 < 700
                bpl     1$              ; то всё нормально
                bic     #177700, R3     ; иначе делаем 7хх
                bis     #700, R3
1$:             return
; End of function sub_36230


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; анимация защищённого блока Б

BlockWall3Anim: tst     (PC)+           ; блок Б уже на экране?
BlockBOutCnt:   .word 1167
                beq     8$              ; да
                ; нет, проверим, пора ли формировать
                tst     DirSprPlayer    ; куда летим?
                bpl     0ret$           ; вправо - не туда
                dec     BlockBOutCnt    ; влево - приближаем момент истины
                bne     0ret$           ; ещё не пора
                ; формируем блок Б
                mov     #BlockBufSpec, R5 ; вот его место
                mov     #55500, R1      ; адрес экрана
                mov     #3, R2          ; три ряда

3$:             mov     #3, R3          ; три штуки в ряду

4$:             cmp     #2, R2          ; средний ряд?
                bne     5$              ; нет
                cmp     #2, R3          ; да, средний блок?
                beq     7$              ; да - пропускаем

5$:             clr     (R5)+           ; адрес блока заранее обнулим
                tst     (R5)+           ; блок ещё живой?
                beq     7$              ; нет
                mov     R1, -4(R5)      ; да - значит зададим адрес блока

7$:             add     #3, R1          ; следующий адрес
                sob     R3, 4$          ; и так весь ряд
                add     #1467, R1       ; переходи к следующему ряду
                sob     R2, 3$          ; и так все ряды
                mov     #57203, @#BlockBScrAddr ; а это адрес блока Б
                ; теперь анимация
8$:             mov     DirSprPlayer, R3 ; направление движения
                neg     R3              ; если летим влево - будет двигаться быстрее
                inc     R3              ; если летим вправо - будет стоять на месте
                ; стираем блоки О
                mov     #BlockBufSpec, R5
                mov     #BlockBufSpecItemsNum, R4
                mov     #sprBlockO, R0

10$:            mov     (R5), R1
                beq     11$
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     R3, (R5)        ; новый адрес

11$:            add     #BlockBufItemSize, R5
                sob     R4, 10$
                ; теперь стираем блок Б
                mov     @#BlockBScrAddr, R1
                beq     14$             ; если его нет, то его и не рисуем
                mov     #sprBlockB, R0
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                add     R3, R1
                mov     R1, R2
                add     #6, R2
                bit     #76, R2         ; за правый край экрана уехал?
                bne     13$             ; нет
                ; да - удаляем с экрана всё
                mov     #BlockBufSpec, R5
                mov     #BlockBufSpecItemsNum, R4

12$:            clr     (R5)+
                tst     (R5)+
                sob     R4, 12$
                mov     #2000, BlockBOutCnt ; и снова будем рисовать через вот столько
0ret$:          return
; ───────────────────────────────────────────────────────────────────────────

13$:            mov     R1, @#BlockBScrAddr ; сохраняем новый адрес
                trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                ; теперь выводим на новом месте блоки О
14$:            mov     #sprBlockO, R0
                mov     #BlockBufSpec, R5
                mov     #BlockBufSpecItemsNum, R4

15$:            mov     (R5)+, R1       ; адрес экрана
                beq     17$             ; 0 - пропускаем
                tst     (R5)            ; блок живой?
                bne     16$             ; да
                clr     -2(R5)          ; нет - удаляем из массива
                br      17$             ; и не выводим
; ───────────────────────────────────────────────────────────────────────────

16$:            trap    36              ; Вывод спрайта на экран методом наложения
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
17$:            tst     (R5)+
                sob     R4, 15$
                mov     #1, @#GameSpeed ; игровую задержку  на минимум
                return
; End of function BlockWall3Anim


; ███████████████ S U B R O U T I N E ███████████████████████████████████████

; Проверка, есть ли блок Б и если есть, то добавление
; охранника, если нет - проверка на конец игры

CheckBlockB:    mov     @#BlockBScrAddr, R1 ; блок Б уничтожен?
                beq     5$              ; да
                ; нет
                mov     #BlockBufSpec + 2, R5
                mov     #BlockBufSpecItemsNum, R4 ; проверим, есть ли вокруг блока Б защитные блоки

1$:             tst     (R5)+
                bne     2$              ; есть ещё, значит можно добавлять охранников
                tst     (R5)+
                sob     R4, 1$
                mov     #sprBlockB, R0  ; кончились - всё, уничтожаем блок Б
                trap    40              ; Стирание спрайта с экрана методом побитовой очистки
                                        ; Вход: R0 - адрес спрайта в памяти, первые 2 слова высота в строках и ширина в байтах
                                        ;       R1 - адрес экрана
                ; Барак, генератор охранников уничтожен
                clr     @#BlockBScrAddr ; всё, нету больше блока Б
                mov     #Sound15$, R1
                trap    14
                trap    14

2$:             tst     (PC)+           ; Нового охранника добавлять?
AddNewGuardCnt: .word 21
                beq     3$              ; пора
                dec     AddNewGuardCnt ; нет ещё
                return
; ───────────────────────────────────────────────────────────────────────────

3$:             mov     #140, AddNewGuardCnt ; добавим нового охранника
                mov     #Guard, R5
                cmp     #<9. | [9. << 8.]>, (R5) ; их и так максимум?
                beq     4$              ; да - выходим
                mov     #EndGuard, R0
                call    IncreaseValue   ; Увеличение двоично-десятичного числа
                                        ; Вход: R0 - конец числа
                mov     #41062, R1
                trap    60              ; Вывод числовых значений счёта, жизней и т.п.
                                        ; Вход: R5 - адрес данных
                                        ;       R1 - адрес экрана
4$:             return
; ───────────────────────────────────────────────────────────────────────────

5$:             mov     #2000, BlockBOutCnt ; счётчик всегда инициализируем, не даём уменьшаться
                tst     Guard           ; охранники ещё остались?
                bne     4$              ; да - выходим
                tst     Guard+2
                bne     4$
                jmp     FinalGame       ; нет - конец игры
; End of function CheckBlockB


; ───────────────────────────────────────────────────────────────────────────
; это битовый массив "GAME OVER"
datGAMEOVER:    .word ^B1111111101111111
                .word ^B0000000000000000
                .word ^B0000000000000000
                .word ^B0000000000000000
                .word ^B1101000100100110
                .word ^B0101101101010001
                .word ^B0101010101010001
                .word ^B1101010101010001
                .word ^B0101010101110101
                .word ^B0101010101010101
                .word ^B1101000101010110
                .word ^B0000000000000000
                .word ^B0000000000000000
                .word ^B0000000000000000
                .word ^B0111011101010010
                .word ^B1001000101010101
                .word ^B1001000101010101
                .word ^B1001011101010101
                .word ^B0111000101010101
                .word ^B1001000101010101
                .word ^B1001011100100010
                .word ^B0000000000000000
                .word ^B0000000000000000
                .word ^B0000000000000000
                .word ^B1111111101111111
; это битовый массив "Вход в шахту"
datShachta:     .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B1111111001111111
                .word ^B1111111001111111
                .word ^B0111111001111110
                .word ^B0111111001111110
                .word ^B0011111001111100
                .word ^B0011111001111100
                .word ^B0001111001111000
                .word ^B0001111001111000
                .word ^B0000111001110000
                .word ^B0000111001110000
                .word ^B0000011001100000
                .word ^B0000011001100000
                .word ^B0000001001000000
                .word ^B0000001001000000
                .word ^B0000001001000000
                .word ^B0000001001000000
                .word ^B0000001001000000
; это спрайт стены
sprWall:        .word 156735, 156535
                .word  73567, 73567
                .word 156735, 156535
                .word  73567, 73567
                .word  52525, 52525
                .word  73567, 73567
                .word 156535, 156735
                .word  73567, 73567
                .word 156535, 156735
                .word  52525, 52525
sprWallEnd:
; ───────────────────────────────────────────────────────────────────────────

; ███████████████ S U B R O U T I N E ███████████████████████████████████████


OutFinalScore:  mov     #Score, R0
                mov     R0, @#F$DataAddr2
                mov     #114434, (R0)+  ; делаем из цифр строку
                mov     #3, R1

1$:             add     #20040, (R0)+
                sob     R1, 1$
                clr     (R0)+
                mov     #41010, R1
                trap    6               ; Вывод текста сложного формата на экран
                                        ; Вход: R1 - адрес экрана
                                        ;       @#F$DataAddr2 - адрес массива данных
                trap    72              ; Ждать нажатия чего-нибудь
                return
; End of function OutFinalScore


FinalGame:      mov     #TrapTo4.Fin$, @#4
                call    OutFinalScore

TrapTo4.Fin$:   mov     #TopStack, SP
                mov     #1330, @#177664

                mov     #Trap50_2, off_Trp50s ; глушим опросы клавиатуры и джойстика
                mov     #Trap50_2, off_Trp52s
                mov     #datGAMEOVER, R0

1$:             mov     #40000, R1
                mov     R0, <0Offset$>
                add     #datShachta-datGAMEOVER, <0Offset$>

2$:             mov     #sprWall, R3

3$:             inc     @#177664
                mov     #16., R2        ; в слове 16 бит
                mov     (R0), R5        ; берём очередное слово

4$:             ror     R5              ; берём бит
                bcc     5$
                mov     (R3), (R1)+     ; 1 - спрайт
                mov     2(R3), (R1)+
                br      6$
; ───────────────────────────────────────────────────────────────────────────

5$:             clr     (R1)+           ; 0 - пусто
                clr     (R1)+

6$:             sob     R2, 4$
                add     #4, R3          ; следующая строка спрайта
                mov     #2000, R4
                sob     R4, .

                cmp     #sprWallEnd, R3 ; пока не дойдём до конца спрайта
                bne     3$
                tst     (R0)+           ; двигаем указатель
                cmp     (PC)+, R0       ; пока не обработаем весь массива
0Offset$:       .word 0
                bne     2$
                mov     #300, R5

7$:             clr     (R1)+
                sob     R5, 7$
                add     #6, @#177664
                cmp     #datShachta, R0
                bne     8$
                mov     #42234, PlayerScrAddr ; Адрес спрайта игрока
                br      9$
; ───────────────────────────────────────────────────────────────────────────

8$:             mov     #40036, PlayerScrAddr ; Адрес спрайта игрока

9$:             mov     R0, -(SP)

10$:            mov     #100, GrowPlayerAddr ; Приращение адреса игрока
                call    PlayerAnim      ; Обработка и анимация движения игрока
                                        ; Обработка стрельбы, заполнение массива выстреленных пуль.
                mov     #14000, R5
                sob     R5, .

                cmp     #74300, R1
                bpl     10$
                mov     (SP)+, R0
                mov     #Sound17$, R1
                trap    14
                cmp     #sprWall, R0
                bne     1$
; ───────────────────────────────────────────────────────────────────────────
                mov     #addrText5$, R5
                mov     #datText5$, R2
                call    sub_37014
                trap    70              ; Очистка экрана
                mov     #60010, R1
                mov     #datText7$, @#F$DataAddr2
                trap    6               ; Вывод текста сложного формата на экран
                                        ; Вход: R1 - адрес экрана
                                        ;       @#F$DataAddr2 - адрес массива данных
                mov     #AddrText8$, R5
                mov     #datText8$, R2
                mov     #114000, @#F$ColorMask
                call    sub_37024
                trap    70              ; Очистка экрана
                mov     #60010, R1
                mov     #datText2$, @#F$DataAddr2
                trap    6               ; Вывод текста сложного формата на экран
                                        ; Вход: R1 - адрес экрана
                                        ;       @#F$DataAddr2 - адрес массива данных
                mov     #AddrText8$, R5
                mov     #datText4$, R2
                mov     #175000, @#F$ColorMask
                call    sub_37024
                mov     #datText6$, R2
                mov     #addrText6$, R5
                call    sub_37014
                trap    70              ; Очистка экрана
; ───────────────────────────────────────────────────────────────────────────
                mov     #41024, R1
                mov     #datText10, @#F$DataAddr2
                trap    6               ; Вывод текста сложного формата на экран
                                        ; Вход: R1 - адрес экрана
                                        ;       @#F$DataAddr2 - адрес массива данных
                mov     #175000, @#F$ColorMask
                mov     #AddrText11, R5 ; адрес, где находится адрес экрана
                mov     #datText11, R2  ; адрес текста
                call    sub_37024
                mov     #TrapTo4, @#4
                jmp     DrawMenu$

; ███████████████ S U B R O U T I N E ███████████████████████████████████████


sub_37014:      mov     #134000, @#F$ColorMask
                trap    70              ; Очистка экрана
; End of function sub_37014


; ███████████████ S U B R O U T I N E ███████████████████████████████████████


sub_37024:      clr     @#F$YScale2

1$:             mov     (R5)+, R1
                beq     3$
                trap    22              ; Вывод текста буквами тырк-тырк влево-вправо
                                        ; Вход: R1 - адрес экрана
                                        ;       R2 - адрес текста
                                        ;       @#F$ColorMask - маска цвета для 1 бита символа
                                        ;       @#F$YScale2 - масштаб по высоте
2$:             tstb    (R2)+
                bne     2$
                br      1$
; ───────────────────────────────────────────────────────────────────────────

3$:             trap    24              ; Вывод три зелёных полосы и на них копирайт спрайтами
                trap    72              ; Ждать нажатия чего-нибудь
                return
; End of function sub_37024

; ───────────────────────────────────────────────────────────────────────────
addrText6$:     .word 50024
                .word 56010
                .word 60006
                .word 62014
                .word 64016
                .word 66012
                .word 70012
                .word 72022
                .word 74012
                .word 0
datText6$:      .asciz "RUNING"
                .asciz "ВАША ЗАДАЧА:"
                .asciz "ПРОБРАТЬСЯ НА"
                .asciz "ДНО ШАХТЫ,"
                .asciz "УНИЧТОЖАЯ"
                .asciz "СВИДЕТЕЛЕЙ,"
                .asciz "СПАСАЯСЬ ОТ"
                .asciz "ДУХОВ И"
                .asciz "ПОКОЙНИКОВ."
datText6End$:
datText4$:      .asciz "СЛЕДУЮЩАЯ ИГРА"
                .asciz "GAME 4"
datText4End$:

datText2$:      .byte 14, 231
                .asciz "RUNING"
datText2End$:
AddrText8$:     .word 47002
                .word 51424
                .word 0
datText8$:      .asciz "ПРЕДЫДУЩАЯ ИГРА"
                .asciz "GAME 2"
datText8End$:

datText7$:      .byte 14, 274
                .asciz "SECOND"
datText7End$:
; таблица адресов экрана для вывода строк текста, 0 - конец
; текст - ниже
addrText5$:     .word 45200
                .word 46602
                .word 50204
                .word 51616
                .word 60010
                .word 61406
                .word 63010
                .word 64404
                .word 66000
                .word 67406
                .word 71004
                .word 72402
                .word 0
datText5$:      .asciz "ВЫ РАЗДЕЛАЛИСЬ С"
                .asciz "ОХРАНОЙ ПЛАНЕТЫ"
                .asciz "И ПРОБРАЛИСЬ В"
                .asciz "ЕЕ НЕДРА."
                .asciz "ПРИОБРЕТАЙТЕ"
                .asciz "СЛЕДУЮЩУЮ ИГРУ"
                .asciz "И ВЫ СМОЖЕТЕ"
                .asciz "ПОСЛУЖИТЬ ДЕЛУ"
                .asciz "МИРА- УНИЧТОЖИТЬ"
                .asciz "ВОЕННУЮ БАЗУ,"
                .asciz "ЗАЛОЖИВ МИНУ В"
                .ascii "НЕДРАХ ПЛАНЕТЫ."
datText5End$:   .even
; ───────────────────────────────────────────────────────────────────────────

.SCRIPT "Text Encode"
    mov #strScore, R1
2$: movb (R1), R0
    beq 1$
    bpl 3$
    sub #40, R0
3$: sub #20, R0
1$: movb R0, (R1)+
    cmp R1, #strGuardEnd
    blo 2$

    mov #strSplashTxt2, R1
5$: movb (R1), R0
    beq 4$
    bpl 6$
    sub #40, R0
6$: sub #20, R0
4$: movb R0, (R1)+
    cmp R1, #strSplashTxt2e
    blo 5$

    mov #datText11, R1
8$: movb (R1), R0
    beq 7$
    bpl 9$
    sub #40, R0
9$: sub #20, R0
7$: movb R0, (R1)+
    cmp R1, #datText11End
    blo 8$

    mov #datText5$, R1
11$: movb (R1), R0
    beq 10$
    bpl 12$
    sub #40, R0
12$: sub #20, R0
10$: movb R0, (R1)+
    cmp R1, #datText5End$
    blo 11$

    mov #datText4$, R1
14$: movb (R1), R0
    beq 13$
    bpl 15$
    sub #40, R0
15$: sub #20, R0
13$: movb R0, (R1)+
    cmp R1, #datText4End$
    blo 14$

    mov #datText8$, R1
17$: movb (R1), R0
    beq 16$
    bpl 18$
    sub #40, R0
18$: sub #20, R0
16$: movb R0, (R1)+
    cmp R1, #datText8End$
    blo 17$

    mov #datText6$, R1
20$: movb (R1), R0
    beq 19$
    bpl 21$
    sub #40, R0
21$: sub #20, R0
19$: movb R0, (R1)+
    cmp R1, #datText6End$
    blo 20$


.ENDS


.SCRIPT "Text Encode2"

    mov #datText7$, R1
    tst (R1)+
2$: movb (R1), R0
    beq 1$
    bpl 3$
    sub #40, R0
3$: sub #20, R0
1$: movb R0, (R1)+
    cmp R1, #datText7End$
    blo 2$

    mov #datText2$, R1
    tst (R1)+
5$: movb (R1), R0
    beq 4$
    bpl 6$
    sub #40, R0
6$: sub #20, R0
4$: movb R0, (R1)+
    cmp R1, #datText2End$
    blo 5$


    mov #strSplashTxt3, R1
    tst (R1)+
18$: movb (R1), R0
    beq 17$
    bpl 19$
    sub #40, R0
19$: sub #20, R0
17$: movb R0, (R1)+
    cmp R1, #strSplashTxt3e
    blo 18$

    mov #datText10, R1
    tst (R1)+
21$: movb (R1), R0
    beq 20$
    bpl 22$
    sub #40, R0
22$: sub #20, R0
20$: movb R0, (R1)+
    cmp R1, #datText10End
    blo 21$

.ENDS

                .END
