1. Программа Sokoban для DENDY *************************************************** ; * Игровая программа Sokoban для приставки DENDY * ; *************************************************** ; *** Область с картами уровней *** .org $8000 ; Уровень 1. .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $0Е, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $02, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $11, $00, $00, $00, $00, $01, $11, $11 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $21, $00, $00, $00, $00, $01, $22, $21 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $0F, $00, $00, $00, $00, $01, $42, $21 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $02, $00, $00, $00, $01, $11, $22, $41 .byte $10, $00, $00, $00, $00, $00, $00, $00 .byte $05, $00, $00, $00, $01, $22, $42, $42 .byte $10, $00, $00, $00, $00, $00, $00, $00 .byte $36, $00, $00, $01, $11, $21, $21, $12 .byte $10, $00, $11, $11, $11, $00, $00, $00 .byte $0F, $00, $00, $01, $22," $21, $21, $12 .byte $11, $11, $12, $23, $31, $00, $00, $00 .byte $05, $00, $00, $01, $24, $22, $42, $22 .byte $22, $22, $22, $23, $31, $00, $00, $00 .byte $15, $00, $00, $01, $11, $11, $21, $11 .byte $21, $51, $12, $23, $31, $00, $00, $00 .byte $14, $00, $00, $00, $00, $01, $22, $22 .byte $21, $11, $11, $11, $11, $00, $00, $00 .byte $00, $00, $00, $00, $00, $01, $11, $11 .byte $11, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 .byte $00, $00, $00, $00, $00, $00, $00, $00 ; Уровень 2. ; Остальные уровни добавьте сами или используйте ; файл sokoban.dat с готовыми уровнями. ; *** Титульный экран, меню и палитры. ; Титульный экран. .org $В200 screen1: .byte $FF, $FF, $FC, $FB, $F8, $FF, $FF, $FF .byte $FF, $FF, $FA, $FF, $FA, $FF, $FF, $FF .byte $FF, $FF, $FC, $FB, $FD, $FF, $FF, $FF .byte $FF, $FF, $FC, $FB, $FD, $FF, $FF, $FF .byte $FF, $FF, $FB, $FF, $FF, $FF, $FF, $FF .byte $FF, $FF, $FB, $FF, $FB, $FF, $FF, $FF .byte $FF, $FF, $FB, $FF, $FB, $FF, $FF, $FF .byte $FF, $FF, $FB, $FF, $FB, $FF, $FF, $FF .byte $FF,. $FF, $FE, $FB, $FD, $FF, $FC, $FB .byte $FD, $FF, $FB, $FB, $F5, $FF, $FC, $FB .byte $FD, $FF, $FB, $FF, $FB, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FB, $FF, $FB, $FF .byte $FB, $FF, $FB, $FF, $FB, $FF, $FB, $FF .byte $FB, $FF, $FB, $FF, $FB, $FF, $FB, $FF .byte $FB, $FF, $FB, $FF, $FB, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FB, $FF, $FB, $FF .byte $FB, $FF, $FB, $FF, $FB, $FF, $FB, $FF .byte $FB, $FF, $FB, $FF, $FB, $FF, $FB, $FB .byte $FB, $FF, $FB, $FF, $FB, $FF, $FF, $FF .byte $FF, $FF, $F7, $FB, $F6, $FF, $FE, $FB .byte $F6, $FF, $F9, $FF, $F9, $FF, $FE, $FB .byte $F6, $FF, $FE, $FB, $F6, $FF, $F9, $FF .byte $F9, $FF, $F9, $FF, $F9, $00 ; Меню (надпись PRESS START). .org $B2C0 menul: .byte $9A, $9B, $9C, $9D, $9D, $FF, $9D, $9E .byte $9F, $9B, $9E, $00 ; Палитры. .org $B300 pal_0: .byte $06, $0A, $0B, $14, $0C, $0A, $0B, $12 .byte $0E, $20, $0E, $0F, $10, $12, $0D, $0F .org $BFE0 pal_l: .byte $0D, $01, $3C, $22, $D0, $FF, $FF, $FF .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF pal_2: .byte $0D, $38, $15, $1C, $D0, $07, $06, $15 .byte $FF, $FF, $FF, $FF, $FF, $FF, $FF, $FF ; *** Текст программы. spritemem = $200 playerxdata = $20 ppuconl = $ 61 playerx = $2FF playery = $2FC px = $310 РУ = $311 lvlmatrix = $300 behbox = $500 lvlptr = $0 boxcount = $10 boxptr = $11 boxleft = $12 tx = $20 ty = $21 curboxptr = $40 temp = $50 dirx = $45 diry = $46 bgwall = $60 bgground = $65 bggoal = $62 spbox = $63 spchar = $64 memlvlptr = $2 startflag = $58 .org $C000 ; Адрес начала программы, reset: sei cld ldx #$0 stx $2000 ; Выключение видеопроцессора, stx ppuconl stx $2001 ldx #$FF txs ; Установка указателя стека. lda #7 ; Подготовка к очистке ОЗУ sta $1 ; по адресам 0 - $7FF. lda #0 ldy #0 clrram: sta (0) ,y ; Цикл очистки ОЗУ. dey bne clrram dec $1 bpl clrram lda #$20 ; Подготовка к очистке видеопамяти, sta $2006 ; Запись в регистры видеопроцессора lda #0 ; адреса для доступа к видеопамяти, sta $2006 ldy #$10 ldx #0 clrvram: sta $2007 ; Цикл очистки видеопамяти, dex bne clrvram dey bne clrvram lda #$3F ; Установка адреса ldx #$0 ; для копирования палитры sta $2006 ; в память видеопроцессора. stx $2006 ldy #$20 setpal: Ida pal_1,x ; Цикл копирования данных sta $2007 ; в ОЗУ палитры, inx dey bne setpal lda #$0 ; Задание используемых символов sta bgwall ; для стен, lda #$50 sta bgground ; для пола, lda #$A0 sta bggoal ; для мест контейнеров, lda #$0 sta spchar ; для игрока, lda #$40 sta spbox ; для контейнера. lda #1 sta boxleft lda #$90 ; Включение видеопроцессора. sta $2000 ; задание экранной страницы sta ppuconl ; и разрешение формировать запрос NMI. lda #0 sta startflag jsr title ; Вывод титульного экрана. lda #$80 ; Установка указателя sta lvlptr+1 ; на адрес $8000 (уровень 1) . loop: jsr loadlevel ; Загрузка уровня, waitnmi: jmp waitnmi ; Ожидание кадрового импульса, vblank: pha ; Сохранение регистров А, X и Y в стеке. txa pha tya pha lda boxleft ; Если boxleft = 0, bne play ; то уровень завершен, inc lvlptr+1 ; Изменение указателя на данные jsr loadlevel ; и загрузка нового уровня, play: lda #0 ; Отключение скроллинга изображения, sta $2005 sta $2005 sta dirx ; Обнуление переменных, задающих sta diry ; направление движения. lda #2 sta $4014 ; Программирование звукового процессора, ldx #1 ; Фиксация состояния кнопок stx $4016 ; на игровом пульте, dex stx $4016 lda $4016 ; Кнопки А, В и SELECT не используются, lda $4016 ; поэтому их состояние игнорируется. lda $4016 lda $4016 ; Проверка состояния кнопки START. and #1 beq notstart lda startflag ; Если нажата кнопка START, bne test2 ; повторная загрузка текущего уровня. lda #$FF ; Если при этом переменная startflag sta startflag; не равна 0, значит, уровень pla ; только что был загружен pla ; и ничего делать не надо. Pla ; Если уровень перезагружается, dec bgwall ; стек очищается, dec bgground ; номера символов для рисования dec bggoal ; данного уровня восстанавливаются dec spchar ; и производится переход на загрузку уровня. dec spbox jmp loop notstart: lda #0 ; Разрешение перезагрузки уровня sta startflag ; при нажатии кнопки START. test2: lda $4016 ; Проверка состояния кнопок and #1 ; перемещения игрока, beq notup lda #$FF ; Передвижение вверх, sta diry jmp trymove notup: lda $4016 and #1 beq notdown lda #1 ; Передвижение вниз. sta diry jmp trymove notdown: lda $4016 and #1 beq notleft lda #255 ; Передвижение влево. sta dirx jmp trymove notleft: lda $4016 and #1 beq notright lda #1 ; Передвижение вправо. sta dirx jmp trymove nomove: pla ; Ни одна кнопка не нажата. tay ; Восстановление регистров pla ; и возврат в цикл ожидания. tax pla rti ; Проверка возможности перемещения. trymove: lda #6 ; Установка указателя, sta memlvlptr+1 lda #0 sta memlvlptr sta temp+3 ; Сохранение указателя, sta temp+4 lda playerx ; Загрузка координаты x игрока, lsr a lsr a ; Деление на 8 (размер спрайта) lsr а sta рх ; и сохранение, clc adc dirx ; Прибавление перемещения по оси X sta temp+1 ; и сохранение. lda playery ; Те же действия для оси Y. clc adc #1 lsr а lsr а ; Деление на 8 (размер спрайта). lsr а sec sbc # 6 ; Вычитание 6, поскольку поле clc ; расположено в центре экрана, adc diry ; Прибавление перемещения по оси Y. asl а ; Умножение на 32 (ширина экрана) . asl а asl а asl а asl а sta memlvlptr ; Сохранение в memlvlptr. Ida #0 adc memlvlptr+1 ; В случае переноса старший байт sta memlvlptr+1 ; указателя увеличивается на 1 sta temp+8 ; и сохраняется. lda memlvlptr clc adc temp+1 ; Прибавление к указателю смещения sta temp+7 ; по оси X и сохранение, sta memlvlptr ldy #0 ; Загрузка байта, на который lda (memlvlptr) ,у ; показывает указатель. cmp #$50 ; Если это пол или место для контейнера, beq move ; производится перемещение, cmp #$А0 beq move cmp #$FE ; Если это контейнер, beq boxmove ; можно ли его двигать? jmp nomove ; Если стена, положение не меняется, boxmove: jsr boxtest ; Движение с контейнером. jmp nomove move: jsr move ; Движение игрока. jmp nomove ; Проверка возможности перемещения контейнера и его движение, boxtest: lda diry asl a asl a asl a asl a asl a sta temp+1 lda memlvlptr pha clc adc dirx clc adc temp+1 sta memlvlptr sta temp+5 pla lsr a lsr a lsr a lsr a lsr a cmp #7 bne notway lda diry cmp #1 bne nobig jmp bigstep notway: cmp #0 bne nobigchange lda diry cmp #$FF bne nobigchange bigstep: lda memlvlptr+1 eor #1 sta memlvlptr+1 nobig: lda memlvlptr+1 sta temp+6 lda (memlvlptr),y sta temp+3 cmp #$50 beq okmove ; Можно перемещаться. cmp #$A0 beq boxgoal ; Контейнер поставлен на место. rts boxgoal: dec boxleft okmove: lda dirx ; Поиск спрайта перемещаемого контейнера asl а ; и изменение его координат. asl а asl а clc adc playerx sta temp+1 lda diry asl a asl a asl a clc adc playery sta temp+2 ldy #0 trynext: lda spritemem,y ; Проверка спрайтов. cmp temp+2 ; Сравнение координаты у beq tryx ; из памяти спрайтов iny ; с координатой у контейнера. iny iny iny bne trynext tryx: lda spritemem+3,y ; Координата у совпала. cmp temp+1 ; Сравним координату x beq found ; аналогичным образом. iny iny iny iny bne trynext found: sty curboxptr ; Спрайт найден. lda curboxptr lsr a ; Деление на 4, чтобы узнать lsr а ; номер спрайта. tax lda temp+7 sta memlvlptr lda temp+8 sta memlvlptr+1 ldy #0 lda behbox,x ; Что находится sta (memlvlptr),y ; под передвигаемым контейнером? cmp #$A0 bne notgoal inc boxleft ; Контейнер сдвинули с места. notgoal: lda temp+5 sta memlvlptr lda temp+6 sta memlvlptr+1 lda (memlvlptr),y ; Запоминание того, что находится sta behbox,x ; под контейнером, lda #$FE ; передвижение контейнера. sta (memlvlptr),y lda ppuconl , Анимация и изменение координат. and #$7F sta ppuconl sta $2000 ldy #8 ldx curboxptr vblank2: lda $2002 bpl vblank2 lda #$2 sta $4014 lda dirx clc adc playerx sta playerx lda diry clc adc playery sta playery lda spritemem,x clc adc diry sta spritemem,x lda spritemem+3,x clc adc dirx sta spritemem+3,x dey bne vblank2 lda ppuconl ora #$80 sta ppuconl sta $2000 rts move: lda ppuconl ; Перемещение игрока. and #$7F sta ppuconl sta $2000 ldy #8 vblankl: lda $2002 bpl vblankl lda #$2 sta $4014 lda dirx clc adc playerx sta playerx lda diry clc adc playery sta playery dey bne vblankl lda ppuconl ora #$80 sta ppuconl sta $2000 rts ; Подпрограмма загрузки уровня loadlevel: inc bgwall ; Переключение знакогенератора. inc bgground inc bggoal inc spchar inc spbox lda #0 sta $2001 ; Выключение видеопроцессора. lda ppuconl and #$7F sta $2000 sta ppuconl load1: lda $2002 bpl loadl lda #$3F ; Задание адреса для доступа sta $2006 ; к ОЗУ палитры. lda #$00 sta $2006 lda #0 ldx #4 clc newpal: adc #$10 ; Запись новой палитры. tay pha lda (lvlptr),y sta $2007 pla dex bne newpal pha lda #$3F sta $2006 lda #$10 sta $2006 pla ldx #8 newpal2: adc #$10 tay pha Ida (lvlptr) ,y sta $2007 pla dex bne newpal2 load2: lda $2002 bpl load2 lda #6 sta ty sta memlvlptr+1 ldy #0 ; Очищение ОЗУ спрайтов. sty tx sty boxptr sty boxcount sty memlvlptr resspr: tya lsr a lsr a tay lda #$50 sta behbox,y tya asl a asl a tay lda #$F2 sta spritemem,y iny lda spbox sta spritemem,y iny lda #1 sta spritemem,y iny iny bne resspr sty playery+2 ldy spchar sty playery+1 lda #$20 ldy #$C0 sta $2006 lda #0 sta $2006 ldx #$FF settoff: stx $2007 dey bne settoff ldx #1 loadmore: lda (lvlptr),y dex bmi notshift lsr a lsr a lsr a lsr a jmp done notshift: and #$F done: cmp #5 ; Это игрок? bne notplayer lda ty asl a asl a asl a ; Сохранение координат игрока. sbc #0 sta playery lda tx asl a asl a asl a sta playerx lda #$50 pha lda bgground jmp notfloor notplayer: cmp #6 ; Может, это контейнер? bne notbox2 inc boxcount tya ; Если да, для него создается спрайт. pha lda ty asl a asl a asl a sbc #0 pha ldy boxptr lda #$A0 sta behbox,y pla sta spritemem,y iny iny iny lda tx asl a asl a asl a sta spritemem,y iny sty boxptr lda #1 sta temp+4 pla tay lda #$A0 pha lda bggoal jmp notfloor notbox2: cmp #4 bne notbox tya pha inc boxcount lda ty asl a asl a asl a sbc #0 ldy boxptr sta spritemem,y iny iny iny lda tx asl a asl a asl a sta spritemem,y iny sty boxptr lda #1 sta temp+4 pla tay lda #$50 pha lda bgground jmp notfloor notbox: cmp #0 ; Может, это пустой квадрат? Bne notempty lda #$FF ; Да, отображение пустого квадрата pha ; (символа с кодом FFh) . jmp notfloor notempty: cmp #1 ; Может, это стена? bne notwall lda #$0 ; Да, отображение стены, pha lda bgwall jmp notfloor notwall: cmp #3 ; Это место для контейнера, bne notgoal lda #$A0 pha lda bggoal jmp notfloor notgoal: cmp #2 ; Это пол? bne notfloor lda #$50 pha lda bgground notfloor: sta $2007 ; Запись байта в видеопамять. lda temp+4 beq nochange pla lda #$FE pha nochange: tya asl a bcc notpage2 lda #7 sta memlvlptr+1 notpage2: txa beq noadd tya asl a bcs cool adc #1 jmp add cool: clc adc #1 sec jmp add noadd: tya asl a add: tay pla sta (memlvlptr),y tya ror a tay lda #0 sta temp+4 inc tx lda #$20 cmp tx bne oldline lda #$FF sta $2007 sta $2007 lda #2 iny beq doneload sta tx inc ty oldline: txa bne dotheiny jmp loadmore dotheiny: ldx #1 iny beq doneloading jmp loadmore doneloading: ldx #$FF settoff2: stx $2007 dey bne settoff2 lda lvlptr+1 sec sbc #$80 tay ldx noboxdata,y stx boxesleft uuu: lda $2002 bpl uuu lda #$18 sta $2001 lda ppucontroll ora #$80 sta ppucontroll sta $2000 rts title: lda #0 ; Показ заставки sta $2001 ; и ожидание нажатия кнопки START. lda ppuconl and #$7F sta ppuconl sta $2000 lda #$20 sta $2006 lda #0 sta $2006 ldy #$C0 ldx #4 lda #$FF black: sta $2007 ; Заполнение экрана пробелами, dey ; код пробела - FFh. bne black dex bne black lda #$21 sta $2006 ldx #0 stx $2006 draw1: lda $B200,x ; Копирование титульного экрана beq draw2 ; в видеопамять. sta $2007 inx bne drawl draw2: lda #$22 sta $2006 lda #$A sta $2006 ldx #0 draw3: lda $B2C0,x ; Копирование в видеопамять меню. beq draw4 sta $2007 inx bne draw3 draw4: lda #$18 sta $2001 lda ppuconl and #$7f sta ppuconl sta $2000 waitkey: ldx #1 ; Ожидание нажатия на кнопку START, stx $4016 dex stx 4016 stx $2005 stx $2005 lda $4016 lda $4016 lda $4016 lda $4016 and #1 cmp #1 beq startl jmp waitkey startl: lda ppuconl ora #$80 sta ppuconl sta $2000 rts ; Векторы перехода. .org $FFFA .word vblank .word reset .word reset . end |