DEVICE ZXSPECTRUM128
include "../../_sdk/sys_h.asm"
Z80=1
Z80ATTR=1
Z80OPT=1 ;не влияет?
Z80OPT2=1 ;не влияет?
Z80OPT2bug=1 ;при 1 черепахи не сталкиваются друг об друга (там записана дема в 3-3, TODO переделать дему) - в релизе включать не надо!!!
Z80OPT2a=1 ;не влияет?
Z80OPT3=1 ;распаковка карты - не влияет?
Z80OPT3ly=1 ;не влияет?
Z80OPT3hy=1 ;не влияет?
Z80OPT3hybug=1 ;при 1 не падает в первую яму в 1-4, а должен (задержка старта уровня на несколько фреймов, а карта та же) - в релизе включать не надо!!!
Z80OPT4=1 ;вывод распакованной карты - не влияет?
Z80MARIOCOLOR=1
Z80BGCOLOR=1
Z80MARIOCYCLECOLOR=1
Z80COINCYCLECOLOR=1
INFINITELIVES=1
NOPIRANHAPLANT=0 ;нет кактуса
GOODPIRANHAPLANT=1 ;кактус и плевок лавы не убивают (для демы)
GOODBULLET=0 ;пуля не убивает (не помогает для демы 8-2 при MULTITASKING)
ALWAYSPRINCESS=0;1 ;no mushroom retainer (Toad), princess in every level-4
FASTDEMOBEFOREBREAKPOINT=0;1 ;(без костыля влияет на прохождение 1-2 при MUSICONINT=1) до брякпоинта в деме (прописывается как reset, т.е. вторая клеточка) реже работает видеоконтроллер
;при запуске грузится дема antipac.fm2 - если её нет, то включается режим записи
;кнопки: стрелки, a="A", s="B", Enter="START", Space="SELECT"
;Esc (Break, Caps Shift + Space) - выход в OS
;C=продолжить показ демы после брякпоинта
;D=прервать показ демы (включается запись с клавиатуры с этого же места)
;V=записать на диск текущее записанное demo.fb2 (добавленные строчки с плюсиками)
;демы пишем так:
;- ставим в текущую дему в нужном месте брякпоинт (|.r|)
;запускаем с FASTDEMOBEFOREBREAKPOINT=1
;когда появляется изображение, жмём D, играем
;после ошибки жмём V (сохранение)
;экстрактим demo.fm2
;ищем строчку с |.r|
;исправляем следующую строчку на пустую? (сейчас вроде и так пустая)
;копируем из demo.fm2 то, что после |.r| до ошибки, в текущую дему, строчку с |.r| вообще стираем (она не участвует в таймингах игры)
;include "6502.asm"
include "6502fast.asm"
RESTOREPG16K=1
MUSIC=1
MUSICONINT=0;1
OSCALLS=0
MULTITASKING=0;1 ;при MUSICONINT=1 влияет на прохождение 8-2 в деме (место облома зависит от числа тактов!), даже костыль мало помогает, приходится делать GOODBULLET
;display "OSCALLS=",OSCALLS
SWEEP=0
DEMO=1
tempintstack=0x4000 ;2 bytes
STACK=0x3ffe
INTSTACK=0x3f00
scrbase=0x8000
scrwid=320
scrhgt=200
;title safe area 224x192 (не видно 3 верхних знакоместа)
;добавим внизу ещё 8 пикс. под ямы
YSKIPFROMTOP=2;3
;font=0x4000+0x2000 ;TODO
COMPACTDATA=0 ;1 портит память после прерывания демы
SCRATCHPAD=0x100 ;в оригинале 0x000
ENDLINETILE=0xff;10+('J'-'A');0xff ;letter 'J' unused
EMPTYTILE=0x24 ;там и было в оригинале
FASTEMPTYTILES=1
org PROGSTART
begin
OS_HIDEFROMPARENT
ld e,0
OS_SETGFX ;e=0:EGA, e=2:MC, e=3:6912, e=6:text ;+SET FOCUS ;e=-1: disable gfx (out: e=old gfxmode)
ld e,0 ;color byte
OS_CLS
ld e,1
OS_SETSCREEN
ld e,0 ;color byte
OS_CLS
OS_GETMAINPAGES
;dehl=номера страниц в 0000,4000,8000,c000
ld a,e
ld (codepage4000),a
ld a,h
ld (codepage8000),a
ld a,l
ld (codepagec000),a
OS_NEWPAGE
ld a,e
ld (tilepage),a
OS_NEWPAGE
ld a,e
ld (spritepage),a
OS_NEWPAGE
ld a,e
ld (spritepagemirver),a
OS_NEWPAGE
ld a,e
ld (spritepagemirhor),a
OS_NEWPAGE
ld a,e
ld (spritepagemirhorver),a
OS_NEWPAGE
ld a,e
ld (pgtileprocL),a
OS_NEWPAGE
ld a,e
ld (pgtileprocR),a
OS_NEWPAGE
ld a,e
ld (pgaddrstack),a
OS_NEWPAGE
ld a,e
ld (pgaddrstackcopy),a
;OS_GETSCREENPAGES
;de=страницы 0-го экрана (d=старшая), hl=страницы 1-го экрана (h=старшая)
;ld a,e
;ld (setpgs_scr_low),a
;xor l
;ld (setpgs_scr_low_xor),a
;ld a,d
;ld (setpgs_scr_high),a
;xor h
;ld (setpgs_scr_high_xor),a
ld de,gfxfilename
call openstream_file
or a
jp nz,noloadgfx
;skip 0x8010 bytes
ld de,0
ld hl,0x8010
;dehl=shift
ld a,(filehandle)
ld b,a
OS_SEEKHANDLE
ld de,tilegfx
ld hl,0x2000
;DE = Buffer address, HL = Number of bytes to read
call readstream_file
call closestream_file
ld hl,0x2000+TitleScreenDataOffset
ld de,TitleScreen
ld bc,TitleScreenDataSize
ldir
call copytilesgfx
ld a,(tilepage)
SETPG16K ;stack in 0xfffx
call recodetiles
ld a,(spritepage)
SETPG16K ;stack in 0xfffx
call recodesprites
call mirspritesver
ld a,(spritepagemirver)
SETPG16K ;stack in 0xfffx
call recodesprites
call mirspriteshor
ld a,(spritepagemirhorver)
SETPG16K ;stack in 0xfffx
call recodesprites
call mirspritesver
ld a,(spritepagemirhor)
SETPG16K
call recodesprites
;result in 0x4000: 32bytes/tile
ld sp,STACK
ld de,filename
call openstream_file
or a
jr nz,noloaddemo
ld hl,0
ld de,0
nvview_load0
push de
push hl
call reservepage
pop hl
pop de
ret nz ;no memory
push de
push hl
ld de,0xc000
ld hl,0x4000
;DE = Buffer address, HL = Number of bytes to read
push hl
call readstream_file
;hl=loaded bytes
ld b,h
ld c,l
pop hl ;Number of bytes to read
or a
sbc hl,bc ;z=loaded as requested
;bc=loaded bytes
pop hl
pop de
;hlde=size
;z=loaded as requested
ex de,hl
add hl,bc
ex de,hl
jr nc,$+3
inc hl
jr z,nvview_load0
;hlde=true file size (for TRDOSFS)
;ld (fcb+FCB_FSIZE),de
;ld (fcb+FCB_FSIZE+2),hl
call closestream_file
jr loaddemoq
noloaddemo
call demooff
loaddemoq
call gentileproc_all
call genaddrstack
call shutay
ld e,13
ld bc,0xfffd
out (c),e
ld a,0x08 ;sawtooth
ld b,0xbf
out (c),a
ld de,mariopal
OS_SETPAL
;OS_GETTIMER ;dehl=timer
;ld (oldtimer),hl
YIELD ;иначе палитра не установится
call setpgs_code
call swapimer
jp Start
mirspriteshor
ld hl,0x2000
ld bc,0x1000
mirspriteshor0
ld e,(hl)
ld a,1
mirspriteshor00
rr e
rla
jr nc,mirspriteshor00
ld (hl),a
cpi
jp pe,mirspriteshor0
ret
mirspritesver
ld de,0x2000
;sprite gfx: 256 tiles *2 (high, low bitchars)
mirspritesver0
ld h,d
ld l,e
ld bc,4
add hl,bc
add hl,bc
push hl
mirspritesver00
dec hl
ld a,(de)
ldi
dec hl
ld (hl),a
jp pe,mirspritesver00
pop de
bit 4,d ;<0x3000
jr z,mirspritesver0
ret
recodesprites
ld hl,0x2000
ld de,0x4000
;sprite gfx: 256 tiles
ld hy,_K;_1 ;_3 too dark
ld hx,0 ;256
recodesprites0
push hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
ld l,h ;номер тайла
ld h,tileattr/256+1
ld a,(hl) ;номер палитры
ld hy,a
pop hl
call recodesprite
dec hx;bit 6,h ;<0x4000
jr nz,recodesprites0
ret
recodetiles
ld hl,0x3000
ld de,0x6000
;tile gfx: 256-tiles
ld hx,0 ;256
recodetiles0
push hl
add hl,hl
add hl,hl
add hl,hl
add hl,hl
ld l,h ;номер тайла
ld h,tileattr/256
ld a,(hl) ;_0.._3 номер палитры
ld hy,a
pop hl
call recodetile
dec hx;bit 6,h ;<0x4000
jr nz,recodetiles0
ret
recodetile
;16bytes/tile: 8bytes low bit, 8bytes high bit
ld lx,8
recodetile0
ld c,(hl) ;low bits
set 3,l
ld b,(hl) ;high bits
res 3,l
inc l
;c=high gfx byte
;b=low gfx byte
;hy=_0.._3 номер палитры
;de=to
push hl
ld h,ttilepalrecode/256
recodetilebyte0
;сдвигом имеем номер цвета a=0..3
;складываем с номером палитры - получаем левый цвет
;так же получаем правый цвет
;пересчитываем в цветовой байт
call recodetilepixel
ld (de),a
inc de
ld a,e
and 3
jr nz,recodetilebyte0
pop hl
dec lx
jr nz,recodetile0
ld bc,8
add hl,bc
ret
recodesprite
;16bytes/tile: 8bytes low bit, 8bytes high bit
ld lx,8
recodesprite0
push de
ld a,d;e
add a,3*16 ;with mask
ld d,a;e,a
ld c,(hl) ;low bits
set 3,l
ld b,(hl) ;high bits
res 3,l
inc l
push hl
ld h,ttilepalrecode/256
recodespritebyte0
call recodetilepixel
ld ly,a
ld a,b
or c
rra ;right pixel mask (0=transparent)
bit 0,a ;left pixel mask (0=transparent)
ld a,0x00 ;skip all pixels
jr c,$+4
ld a,0xb8 ;keep right pixel
jr nz,$+4
or 0x47 ;keep left pixel
ld (de),a ;mask
ld a,ly
inc d;e
ld (de),a ;gfx
ld a,d;e
sub 16+1 ;with mask
ld d,a;e,a
cpl
and 3*16 ;with mask
jr nz,recodespritebyte0
pop hl
pop de
inc d;e
inc d;e ;next row
dec lx
jr nz,recodesprite0
;ex de,hl
;ld bc,3*16 ;with mask
;add hl,bc
;ex de,hl
ld d,0x40
inc e
ld bc,8
add hl,bc
ret
recodetilepixel
;c=high gfx byte (берём два старших бита и сдвигаем)
;b=low gfx byte (берём два старших бита и сдвигаем)
;hy=_0.._3 номер палитры
;h=ttilepalrecode/256
;out: a=color byte
xor a
rlc c
rla
rlc b
adc a,a ;a=0..3=номер цвета в палитре
add a,hy
ld l,a
ld a,(hl)
ld ly,a ;%LLLLLlll
xor a
rlc c
rla
rlc b
adc a,a ;a=0..3=номер цвета в палитре
add a,hy
ld l,a
ld a,(hl) ;a=%RRRRRrrr
;ly=%LLLLLlll
add a,a
add a,a
add a,a
;a=%RRrrr000
xor ly
and %10111000
xor ly
;a=%RLrrrlll
ret
noaddr=0x6000 ;там можно портить 7*40+1 байт
genaddrstack
call setpgaddrstack4000
call genaddrstack_onepage
call setpgaddrstackcopy4000
genaddrstack_onepage
;для scroll phase 0 стек такой:
;(scrL) 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 2
;(scrR) 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 2
;для scroll phase 1 стек такой:
;(scrR) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;(scrL) 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 2
;для scroll phase 2 стек такой:
;(scrL) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;(scrR) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;для scroll phase 3 стек такой:
;(scrR) noaddr, noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023
;(scrL) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;генерируем один стек на все фазы (строки лежат через 256 байт):
;noaddr, noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr, noaddr
ld h,0x40
ld de,0x8004
ld b,25
genaddrstack_lines0
ld l,2 ;2 spare bytes for interrupt
push bc
push de
ld bc,noaddr
ld (hl),c
inc hl
ld (hl),b
inc hl
ld (hl),c
inc hl
ld (hl),b
inc hl
ld b,32
genaddrstack_line0
ld (hl),e
inc hl
ld (hl),d
inc hl
set 5,d
ld (hl),e
inc hl
ld (hl),d
inc hl
res 5,d
inc de
djnz genaddrstack_line0
ld bc,noaddr
ld (hl),c
inc hl
ld (hl),b
inc hl
ld (hl),c
inc hl
ld (hl),b
;inc hl
;выравнивание на 64*4 = 256
inc h
pop de
ex de,hl
ld bc,40*8
add hl,bc
ex de,hl
pop bc
djnz genaddrstack_lines0
ret
copytilesgfx
ld de,0x3000+(16*0xec) ;tile 0xec
ld hl,copytiles_table
ld b,copytiles_sz
copytilesgfx0
push bc
push hl
ld l,(hl)
;l=tile from
;de=addr to
ld h,3
add hl,hl
add hl,hl
add hl,hl
add hl,hl ;*16 + 0x3000
ld bc,16
ldir
pop hl
inc hl
pop bc
djnz copytilesgfx0
ld hl,0x3000+(16*0x26)
ld de,0x3000+(16*w26)
ld c,16
ldir
ld hl,0x3000+(16*0x91)
ld de,0x3000+(16*x91)
ld c,16
ldir
ld de,0x3000+(16*x92)
ld c,16
ldir
ret
copytiles_table
db 0xa0
db 0xa1
db 0xa2
db 0xa3
db 0x27
db 0xba
db 0xbb
db 0x86
db 0x87
db 0x8a
db 0x8b
db 0x8e
db 0x8f
db 0x25
db 0x26
db 0x35
db 0x36
db 0x37 ;cloud middle
db 0x38 ;cloud right
copytiles_sz=$-copytiles_table
gentileproc_all
ld a,(tilepage)
SETPG16K
ld de,0x6000 ;data
call setpgtileprocL
call gentileproc_all_half
ld de,0x6001 ;data
call setpgtileprocR
gentileproc_all_half
ld hl,0xc000 ;proc
gentileproc_all0
push hl
push de
call gentileproc
pop de
ld hl,32
add hl,de
ex de,hl
pop hl
inc h
ld a,h
or 0xc0
ld h,a
inc l
ld a,l
inc a
jr nz,gentileproc_all0
ld (hl),0xf7 ;rst 0x30 for tile #0xff
;tile for endline = ENDLINETILE;0xff?
ld hl,(0) ;ok
ld (oldquitcode),hl
ld hl,ENDLINETILE*0x0101|0xc000;0xffff
ld (hl),0xc3 ;"jp"
ret
gentileproc
;hl=proc
;de=data
;out: de=next data
;генерирует такое:
;pop hl ;пиксели 0..1
;dup 7
;[ld (hl),n]
;add hl,bc
;edup
;[ld (hl),n]
;pop hl ;пиксели 4..5 в той же странице (другой bit 5 и возможно +1)
;dup 7
;[ld (hl),n]
;add hl,bc
;edup
;[ld (hl),n]
;ld a,(de)
;inc e
;ld l,a
;or 0xc0
;ld h,a
;jp (hl)
push de
call gentileproc_bytes
pop de
inc de
inc de
call gentileproc_bytes
push de
ex de,hl
ld hl,gentileproc_jpcode
ld c,gentileproc_jpcode_sz
ldir
if FASTEMPTYTILES
ld hl,premptytiles_was
ld de,premptytiles;EMPTYTILE*257+0xc000
ld c,premptytiles_sz
ldir
endif
pop de
ret
gentileproc_bytes
ld (hl),0xe1 ;"pop hl"
inc hl
ld (gentileproc_lastnonzeroaddr),hl
;find most popular byte (at least 3 times), change to ld a,n:ld (hl),a
;это один из первых 6 байтов или 0 (если не найдено)
;TODO уметь находить две группы по 3 и более
ld c,0 ;most popular byte (0=not found)
push de
push hl
ex de,hl
ld e,2 ;max times (find more than that!)
ld b,7
gentileproc_testpopular_allbytes0
ld a,(hl)
push bc
push hl
ld d,1 ;times
gentileproc_testpopular0
inc hl
inc hl
inc hl
inc hl
cp (hl)
jr nz,$+3
inc d ;times
djnz gentileproc_testpopular0
pop hl
pop bc
ld a,e ;max times
cp d ;times
jr nc,gentileproc_testpopular_nomax
ld e,d ;max times = times
ld c,(hl) ;most popular byte
gentileproc_testpopular_nomax
inc hl
inc hl
inc hl
inc hl ;try next byte
djnz gentileproc_testpopular_allbytes0
pop hl
pop de
ld a,c
or a
jr z,gentileproc_nooldbyte
ld (hl),0x3e ;"ld a,n"
inc hl
ld (hl),c
inc hl
gentileproc_nooldbyte
ld b,8
gentileproc_bytes0
ld a,(de)
inc de
inc de
inc de
inc de
or a
jr z,gentileproc_skipbyte
cp c
ld (hl),0x77 ;"ld (hl),a
jr z,gentileproc_oldbyte
ld (hl),0x36 ;"ld (hl),n"
inc hl
ld (hl),a
gentileproc_oldbyte
inc hl
ld (gentileproc_lastnonzeroaddr),hl
gentileproc_skipbyte
ld (hl),0x09 ;add hl,bc
inc hl
djnz gentileproc_bytes0
;dec hl ;skip last add
gentileproc_lastnonzeroaddr=$+1
ld hl,0
ret
if FASTEMPTYTILES
;сейчас процедура пустого тайла (0xe424) выглядит так:
;pop hl
;pop hl ;чтобы был правильный sp
;inc e
;ld a,(de)
;ld l,a
;or 0xc0
;ld h,a
;jp (hl) ;50t
;оптимизировать последовательность пустых тайлов:
;1 пустой тайл: проигрыш 54t (проигрыш 35t)
;2 пустых тайла: проигрыш 26t (выигрыш 23t)
;3 пустых тайла: выигрыш 0t (выигрыш 31t)
;>=4 пустых тайла: выигрыш 29..32t/tile
premptytiles_was
disp EMPTYTILE*257+0xc000
premptytiles
;-24t
ld a,l;EMPTYTILE
ld h,d
ld l,e ;+12t
inc l
cp (hl)
jr nz,premptytilesq1
inc l
cp (hl)
jr nz,premptytilesq2
inc l
cp (hl)
jr nz,premptytilesq3
premptytiles0
dup 3
inc l
cp (hl)
jr nz,premptytilesq
edup
inc l
cp (hl)
jp z,premptytiles0 ;+18..21t/tile
premptytilesq
ld a,l
sub e
ld e,l
add a,a
add a,a
ld l,a
ld h,0
add hl,sp
ld sp,hl ;48t
ld a,(de)
ld l,a
or 0xc0
ld h,a
jp (hl)
premptytilesq3
pop hl
pop hl
inc e
premptytilesq2
pop hl
pop hl
inc e
premptytilesq1
pop hl
pop hl
ent
gentileproc_jpcode
inc e
ld a,(de)
ld l,a
or 0xc0
ld h,a
jp (hl)
premptytiles_sz=$-premptytiles_was
;display "premptytiles_sz=",premptytiles_sz,"<=0x40!"
gentileproc_jpcode_sz=$-gentileproc_jpcode
else
gentileproc_jpcode
inc e
ld a,(de)
ld l,a
or 0xc0
ld h,a
jp (hl)
gentileproc_jpcode_sz=$-gentileproc_jpcode
endif
align 256
tileattr
include "tileattr.asm"
ttilepalrecode
db 0,1,2,3 ;tilepal0
db 0,4,5,6 ;tilepal1
db 0,7,0xf8,0xf9 ;tilepal2
db 0,0xfa,0xfb,6 ;tilepal3 ;10=тень монеты/каёмка огня, 11=яркая монета/огонь, 12=рубашка Марио (каёмка монеты бывает синяя - для неё берём цвет 6)
;цвета Марио: [1]=4 (лицо) или 13=0x3131, [2]=14=0xb1b1 (фартук красный, а может быть белый), [3]=12 (рубашка может быть коричневая и зелёная!!!)
;цвета черепахи/Lakitu: [1]=8 (белый), [2]=2 (зелёный панцирь, а может быть синий!!!) или 15=0xe3e3, [3]=13 (голова черепахи)
;цвета Goomba/жук/пушка/пуля: [1]=5 (ножка), [2]=6 (чёрный, а может быть тёмно-серый!!!), [3]=4 (шляпа)
;цвета огня: [1]=8 (белая внутренность), [2]=10 (красный), [3]=11 (жёлтый)
;цвета гриба: [1]=5 (ножка), [2]=10 (красный), [3]=13 (оранжевый)
;цветок отличается от черепахи тем, что всегда зелёная ножка
;платформа отличается от Марио стабильными цветами??? или она ближе к грибу/Goomba наверху
;наш флаг отличается от черепахи тем, что всегда красная звезда
db 0,0xfd,0xfe,0xfc ;Mario
db 0,0xf8,0xff,0xfd ;Koopa/Lakitu
db 0,5,6,4 ;Goomba/жук/пушка/пуля
db 0,0xf8,0xfa,0xfb ;огонь
db 0,5,0xfa,0xfd ;гриб
db 0,0xf8,2,0xfd ;цветок (всегда зелёная ножка)
db 0,0xfb,0xf8,0xfa ;монета
;db 0,0xfd,0xfa,4 ;платформа
db 0,5,0xfa,0xfd ;платформа
db 0,0xf8,0xfa,0xfd ;наш флаг (всегда красная звезда)
;ds 0x0200-$
if COMPACTDATA
Sprite_Data=$ ;= $0200
Sprite_Y_Position=Sprite_Data ;db 0;= $0200
;Sprite data is delayed by one scanline; you must subtract 1 from the sprite's Y coordinate before writing it here. Hide a sprite by writing any values in $EF-$FF here.
;Sprites are never displayed on the first line of the picture, and it is impossible to place a sprite partially off the top of the screen.
Sprite_Tilenumber=Sprite_Data+1 ;db 0;= $0201
;For 8x8 sprites, this is the tile number of this sprite within the pattern table selected in bit 3 of PPUCTRL ($2000).
;For 8x16 sprites, the PPU ignores the pattern table selection and selects a pattern table from bit 0 of this number.
;76543210
;||||||||
;|||||||+- Bank ($0000 or $1000) of tiles
;+++++++-- Tile number of top of sprite (0 to 254; bottom half gets the next tile)
Sprite_Attributes=Sprite_Data+2 ;db 0;= $0202
;76543210
;||||||||
;||||||++- Palette (4 to 7) of sprite
;|||+++--- Unimplemented
;||+------ Priority (0: in front of background; 1: behind background)
;|+------- Flip sprite horizontally
;+-------- Flip sprite vertically
Sprite_X_Position=Sprite_Data+3 ;db 0;= $0203
;X-scroll values of $F9-FF results in parts of the sprite to be past the right edge of the screen, thus invisible. It is not possible to have a sprite partially visible on the left edge.
;Instead, left-clipping through PPUMASK ($2001) can be used to simulate this effect.
ds 0x0300-$
;tile buf
VRAM_Buffer1_Offset db 0;= $0300
VRAM_Buffer1 ds 63;???;= $0301
VRAM_Buffer2_Offset db 0;= $0340
VRAM_Buffer2 ds 0x100;TitleScreenDataSize-64;63;???;= $0341 ;следующий блок данных в $0363, но нужен буфер до 0x043a (невключительно)
ds 0x0500-$ ;ClearBuffersDrawIcon чистит 512 байт
endif
ds 0x0800-$
SCRATCHPAD2=$-0x100
ds 0x100 ;адреса SCRATCHPAD2+$01xx (сколько???)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 256
filepages
ds 128
;DDp palette: %grbG11RB(low),%grbG11RB(high)
mariopalblack
castlepalette
dw 0xffff
dw 0xafaf,0xeded,0x7f7f ;1=средняя труба, 2=яркая труба, 3=каёмка трубы
dw 0xecec,0x0c0c,0x1f1f ;4=яркий кирпич, 5=блик на кирпиче, 6=дверь замка=тень в кирпичах (по идее чёрные, но на 8-4 тёмно-серые)
dw 0x3d3d,0x0c0c,0xffff ;7=вода/тень облака, 8=белый, 9=каёмка облака (чёрная)
dw 0xfdfd,0xadad,0x3f3f ;10=тень монеты, 11=яркая монета, 12=рубашка Марио (каёмка монеты бывает синяя - для неё берём цвет 6)
dw 0x3d3d,0xbdbd,0xefef ;13=лицо Марио/голова черепахи, 14=фартук Марио, 15=панцирь
undergroundpalette
;с чёрным фоном: каёмка трубы лицо фартук дверь замка, тень в кирпичах (по идее чёрные); рубашка Марио (по идее коричневая), шляпа злого гриба (в подземелье голубая), голова черепахи (по идее оранжевая), стебель кактуса (по идее оранжевый), лицо toad
;dw 0xf3f3,0xa3a3,0x6161,0x7373,0xf3f3,0x3131,0xa0a0,0xb3b3
;dw 0xf3f3,0x0202,0x0000,0xd3d3,0xf3f3,0xf1f1,0xa1a1,0xb3b3
;край облака разбитый блок с призом, край монеты
dw 0xffff
dw 0xafaf,0xeded,0x7f7f ;1=средняя труба, 2=яркая труба, 3=каёмка трубы
dw 0xeeee,0x4c4c,0x5f5f ;4=яркий кирпич, 5=блик на кирпиче, 6=дверь замка=тень в кирпичах (по идее чёрные, но на 8-4 тёмно-серые)
dw 0x0e0e,0x0c0c,0xffff ;7=вода/тень облака, 8=белый, 9=каёмка облака (чёрная)
dw 0xfdfd,0xadad,0x3f3f ;10=тень монеты, 11=яркая монета, 12=рубашка Марио (каёмка монеты бывает синяя - для неё берём цвет 6)
dw 0x3d3d,0xbdbd,0xefef ;13=лицо Марио/голова черепахи, 14=фартук Марио, 15=панцирь
waterpalette
dw 0xcccc ;небо
dw 0xafaf,0xeded,0x7f7f ;1=средняя труба, 2=яркая труба, 3=каёмка трубы
dw 0x6f6f,0x6c6c,0xffff ;4=яркий кирпич, 5=блик на кирпиче, 6=дверь замка=тень в кирпичах (по идее чёрные, но на 8-4 тёмно-серые)
dw 0x0e0e,0x0c0c,0xffff ;7=вода/тень облака, 8=белый/коралл???/подводная монета???, 9=каёмка облака (чёрная)
dw 0xfdfd,0xadad,0x3f3f ;10=тень монеты, 11=яркая монета, 12=рубашка Марио (каёмка монеты бывает синяя - для неё берём цвет 6)
dw 0x3d3d,0xbdbd,0xecec ;13=лицо Марио/голова черепахи, 14=фартук Марио, 15=панцирь/серая рыбка
mariopal
groundpalette
;с синим небом:
;23 ;e3 ;e0
;dw 0xc0c0,0xa3a3,0x6161,0x7373,0xc0c0,0x3131,0xa0a0,0xb3b3
;dw 0xc0c0,0x0202,0x0000,0xd3d3,0xc0c0,0xf1f1,0xa1a1,0xb3b3
;вода/кусок облака
dw 0xcccc ;небо
dw 0xafaf,0xeded,0x7f7f ;1=средняя труба (0xe3 слишком холодно), 2=яркая труба (0x61 слишком ярко), 3=каёмка трубы
dw 0x7d7d,0xacac,0xffff ;4=яркий кирпич (0x11 слишком ярко, 0x31 слишком насыщенно, 0x71 слишком коричнево - но в VirtualNES так), 5=блик на кирпиче, 6=дверь замка=тень в кирпичах (по идее чёрные, но на 8-4 тёмно-серые)
dw 0x0e0e,0x0c0c,0xffff ;7=вода/тень облака, 8=белый, 9=каёмка облака (чёрная)
dw 0xfdfd,0xadad,0x3f3f ;10=тень монеты/каёмка огня, 11=яркая монета/огонь, 12=рубашка Марио (0xb3 слишком насыщенно, каёмка монеты бывает синяя - для неё берём цвет 6)
dw 0x3d3d,0xbdbd,0xefef ;13=лицо Марио/голова черепахи, 14=фартук Марио, 15=панцирь
;цвета Марио: [1]=4 (лицо) или 13=0x3131, [2]=14=0xb1b1 (фартук красный, а может быть белый), [3]=12 (рубашка может быть коричневая и зелёная!!!)
;цвета черепахи/Lakitu: [1]=8 (белый), [2]=2 (зелёный панцирь, а может быть синий!!!) или 15=0xe3e3, [3]=13 (голова черепахи)
;цвета Goomba/жук/пушка/пуля: [1]=5 (ножка), [2]=6 (чёрный, а может быть тёмно-серый!!!), [3]=4 (шляпа)
;цвета огня: [1]=8 (белая внутренность), [2]=10 (красный), [3]=11 (жёлтый)
;цвета рыбы: [1]=8 (белое брюшко), [2]=15 (серый), [3]=13 (розовый хвост) - как у черепахи
;цвета гриба: [1]=5 (ножка), [2]=10 (красный), [3]=13 (ярко-оранжевый)
quit
call swapimer
call shutay
oldquitcode=$+1
ld hl,0
ld (0),hl
quitquit
halt
GET_KEY ;вычитать Break
QUIT
noloadgfx
ld e,6
OS_SETGFX ;e=0:EGA, e=2:MC, e=3:6912, e=6:text ;+SET FOCUS ;e=-1: disable gfx (out: e=old gfxmode)
ld e,0
OS_SETSCREEN
ld e,0 ;color byte
OS_CLS
ld hl,tnofile
prerr0
ld a,(hl)
or a
jr z,quitquit
inc hl
push hl
PRCHAR
pop hl
jr prerr0
swapimer
di
if MULTITASKING
;ld hl,(0x0038+3) ;адрес intjp
;ld (intjpaddr),hl
endif
ld de,0x0038
ld hl,oldimer
ld bc,3
swapimer0
ld a,(de)
ldi ;[oldimer] -> [0x0038]
dec hl
ld (hl),a ;[0x0038] -> [oldimer]
inc hl
jp pe,swapimer0
ei
ret
oldimer
jp on_int ;заменится на код из 0x0038
jp 0x0038+3
setpgs_code
codepage4000=$+1
ld a,0
if RESTOREPG16K
;ld (curpg4000),a
endif
SETPG16K
codepage8000=$+1
ld a,0
SETPG32KLOW
codepagec000=$+1
ld a,0
SETPG32KHIGH
ret
setpgs_scr
tilepage=$+1
ld a,0
if RESTOREPG16K
;ld (curpg4000),a
endif
SETPG16K
;setpgs_scr_low=$+1
; ld a,0;pgscr0_0 ;scr0_0
call getuser_scr_low
SETPG32KLOW
;setpgs_scr_high=$+1
; ld a,0;pgscr0_1 ;scr0_1
call getuser_scr_high
SETPG32KHIGH
ret
getuser_scr_low
getuser_scr_low_patch=$+1
getuser_scr_low_patchN=0xff&(user_scr0_low^user_scr1_low)
ld a,(user_scr0_low) ;ok
ret
getuser_scr_high
getuser_scr_high_patch=$+1
getuser_scr_high_patchN=0xff&(user_scr0_high^user_scr1_high)
ld a,(user_scr0_high) ;ok
ret
align 256
tytoscr
dup 200
db (($&0xff)*40)&0xff
edup
align 256
dup 200
db (($&0xff)*40)/256 + 0x80
edup
macro NEXTCOLUMN
bit 6,h
set 6,h
jr z,$+2+4+2+2+1
ld a,h
xor 0x60
ld h,a
and 0x20
jr nz,$+3
inc hl
endm
macro COUNTSCRADDR
add a,(hl)
inc h
ld c,a
;ld h,(hl)
adc a,(hl)
sub c
ld l,c;a
;ld a,b
;adc a,h
;inc h
;ld l,c ;x
;add a,(hl) ;8+7=15t, а если rra:srl a=12t, плюс выигрываем 2 команды bit
;inc h
;ld a,(hl)
;ld (prcharxy_jr),a ;4+7+13+12(jr) = 35t, а если bit:jr z:bit:jr z, то в среднем 16+7+12=35t тоже
endm
macro NEXTCOLUMNS0
ld h,a ;.00
push hl
set 6,h ;.10
push hl
xor 0x20
ld h,a ;.01
push hl
set 6,h ;.11
endm
macro NEXTCOLUMNS1
ld c,a
xor 0x40
ld h,a ;.10
push hl
xor 0x60
ld h,a ;.01
push hl
set 6,h ;.11
push hl
ld h,c ;.00
inc hl
endm
macro NEXTCOLUMNS2
ld h,a
set 5,h ;.01
push hl
set 6,h ;.11
push hl
ld h,a ;.00
inc hl
push hl
set 6,h ;.10
endm
macro NEXTCOLUMNS3
ld c,a
xor 0x60
ld h,a ;.11
push hl
ld h,c ;.00
inc hl
push hl
set 6,h ;.10
push hl
ld a,h ;нельзя старое, т.к. было inc hl
xor 0x60
ld h,a ;.01
endm
prcharxy
;de=gfx
;la=yx
;CY=0
ld h,tytoscr/256
rra
jr c,prcharxy_nextcolumns13
rra;srl a
jr c,prcharxy_nextcolumns2
prcharxy_nextcolumns0
COUNTSCRADDR
NEXTCOLUMNS0
jp prcharxy_scrok
prcharxy_nextcolumns2
COUNTSCRADDR
NEXTCOLUMNS2
jp prcharxy_scrok
prcharxy_nextcolumns13
srl a
jr c,prcharxy_nextcolumns3
prcharxy_nextcolumns1
COUNTSCRADDR
NEXTCOLUMNS1
jp prcharxy_scrok
prcharxy_nextcolumns3
COUNTSCRADDR
NEXTCOLUMNS3
prcharxy_scrok
macro SHOWBYTEBEHIND
inc d;e
cp (hl) ;scr
jr nz,$+5
ld a,(de)
ld (hl),a ;scr
xor a
inc d;e
endm
macro SHOWBYTEBEHIND_LAST
cp (hl) ;scr
ret nz
inc d;e
ld a,(de)
ld (hl),a ;scr
ret
endm
macro SHOWBYTE ;TODO pop de
ex de,hl
ld a,(de) ;scr
and (hl) ;font
inc h;l
or (hl)
inc h;l
ld (de),a ;scr
ex de,hl
endm
macro SHOWBYTE_LAST ;TODO pop de
ex de,hl
ld a,(de) ;scr
and (hl) ;font
inc h;l
or (hl)
ld (de),a ;scr
ret
endm
;ld a,(de) ;font
;ld (hl),a ;scr
; inc d;e
;add hl,bc
;x=???432Xx
;scraddr = %1xX????? ?????432
ld bc,40 ;TODO в зависимости от переворота
bit 5,(ix+2) ;attributes.behind
jp nz,prcharxy_behind
dup 7
SHOWBYTE
add hl,bc
edup
SHOWBYTE
pop hl
dup 7
SHOWBYTE
add hl,bc
edup
SHOWBYTE
pop hl
dup 7
SHOWBYTE
add hl,bc
edup
SHOWBYTE
pop hl
dup 7
SHOWBYTE
add hl,bc
edup
SHOWBYTE_LAST
;ret ;там уже есть
prcharxy_behind
xor a
dup 7
SHOWBYTEBEHIND
add hl,bc
edup
SHOWBYTEBEHIND
pop hl
dup 7
SHOWBYTEBEHIND
add hl,bc
edup
SHOWBYTEBEHIND
pop hl
dup 7
SHOWBYTEBEHIND
add hl,bc
edup
SHOWBYTEBEHIND
pop hl
dup 7
SHOWBYTEBEHIND
add hl,bc
edup
SHOWBYTEBEHIND_LAST
;ret ;там уже есть
EmulatePPU
if FASTDEMOBEFOREBREAKPOINT
ld a,0
sub 4
ld ($-1-2),a
;scf
jr c,EmulatePPU_noskipgo
skipPPU=$
ret
EmulatePPU_noskipgo
endif
;ждать флаг ожидания готовности экрана (включается по прерыванию)
;иначе будет так:
;фрейм 1:
;видим экран0, рисуем экран1
;фрейм 2:
;видим экран0, закончили рисовать экран1, [вот тут нужно ожидание], начали рисовать экран0 (хотя его видим)
;фрейм 3:
;видим экран1
;готовность - это когда текущий таймер != таймер конца прошлой отрисовки
;проверяем оба таймера, а то могло случиться системное прерывание
EmulatePPU_waitforscreenready0
call gettimer
endoflastredrawtimer=$+1
ld de,0
or a
sbc hl,de
jr z,EmulatePPU_waitforscreenready0
if OSCALLS
curpalette=$+1
ld de,mariopal
oldpalette=$+1
ld hl,0
ld (oldpalette),de
or a
sbc hl,de
jp z,EmulatePPU_nochpal ;реально поддержано изменение цвета Марио в палитре: при этом пишется oldpalette=левоечисло
push de
;OS_GETTIMER ;dehl=timer
;ld (oldtimer),hl ;иначе yield вылетит без ожидания прерывания
YIELD ;иначе можем напороться на di в swapimer
call swapimer ;делать это после YIELD, т.к. внутри di..ei
pop de
OS_SETPAL ;на это время восстановлен обработчик прерываний, музыка выключена (а так надо посчитать, сколько прошло прерываний по системному таймеру и добавить в игровой таймер)
YIELD ;иначе палитра не установится
call swapimer
else
EmulatePPU_nochpal
endif
call setpgs_scr
wascurkeyredraw=$+1
ld a,0
cp key_redraw
if 1==1
jr nz,EmulatePPU_nofullcls
xor a
ld (wascurkeyredraw),a
;ld hl,0x8000
;ld de,0x8000+1
;ld bc,0x7fff
;ld (hl),l;0
;ldir
ld e,0
OS_SETSCREEN
ld e,0 ;color byte
OS_CLS
ld e,1
OS_SETSCREEN
ld e,0 ;color byte
OS_CLS
EmulatePPU_nofullcls
endif
ld hl,0x8000+4+32
call emppucls
ld hl,0xa000+4+32
call emppucls
ld hl,0xc000+4+32
call emppucls
ld hl,0xe000+4+32
call emppucls ;cls=173000
ld hl,proc_endline
ld (0),hl ;иначе системный обработчик прерываний успевает запортить (0x0001)
call prtilesfast ;143700
call setpgs_scr
;ld a,0x40
;ld (fonthsb),a
;рисуем спрайты в обратном порядке (0-й на переднем плане)
ld ix,Sprite_Data+256-4
;ld b,64;8
prsprites0
;push bc
ld a,(ix) ;y
sub 8*YSKIPFROMTOP
cp 200-8
jp nc,prsprites_skip ;большинство спрайтовых записей пустые, можно даже проверять на ==0xf8
ld l,a ;y
ld a,(ix+2) ;attributes
rla ;flip vertically ;TODO программно
spritepage=$+1
spritepagemirhor=$+2
ld bc,0
jr nc,$+5
spritepagemirver=$+1
spritepagemirhorver=$+2
ld bc,0
rla ;flip horizontally
ld a,c;
jr nc,$+3
ld a,b;mirver
if RESTOREPG16K
;ld (curpg4000),a
endif
SETPG16K
ld a,(ix+3) ;x
inc a
jr z,prsprites_skip ;почему-то прыжки на левой границе экрана в контакте с камнем дают x=0xff TODO
srl a
add a,4*4
ld e,(ix+1) ;tile
ld d,0x40 ;gfx
;ld l,e
;ld h,0x40/64
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
; add hl,hl
;ex de,hl
;la=yx
;de=gfx
call prcharxy
prsprites_skip
;ld bc,-4
;add ix,bc
;pop bc
;djnz prsprites0
ld a,lx
sub 4
ld lx,a
jp nz,prsprites0 ;0-й спрайт - край монетки, можно не выводить
;jp nc,prsprites0
ld a,1
curscreen=$+1
xor 1
ld (curscreen),a
if OSCALLS
ld e,a
OS_SETSCREEN ;фактически включится по прерыванию ;первый отобразится 0-й экран
ld a,e
endif
add a,a
add a,a
add a,a
ld (imer_curscreen_value),a
;ld bc,0x7ffd
;out (c),a
call gettimer
ld (endoflastredrawtimer),hl
; ld hl,setpgs_scr_low
; ld a,(hl)
;setpgs_scr_low_xor=$+1
; xor 2
; ld (hl),a
; ld hl,setpgs_scr_high
; ld a,(hl)
;setpgs_scr_high_xor=$+1
; xor 2
; ld (hl),a
ld hl,getuser_scr_low_patch
ld a,(hl)
xor getuser_scr_low_patchN
ld (hl),a
ld hl,getuser_scr_high_patch
ld a,(hl)
xor getuser_scr_high_patchN
ld (hl),a
call setpgs_code
ld d,0
ld b,d
ret
emppucls
ld (emppuclssp),sp
ld de,0
ld bc,40
ld a,200
emppucls0
ld sp,hl ;во время прерывания de=0
ld (hl),e
dup 32/2
push de
edup
add hl,bc
dec a
jr nz,emppucls0
emppuclssp=$+1
ld sp,0
ret
include "nesconst.asm"
include "smbconst.asm"
TitleScreen
ds TitleScreenDataSize
prtilesfast
call setpgaddrstack4000
ld hl,0x2000 + (32*YSKIPFROMTOP)
ld de,0x4000+6 ;addrstack
ld bc,0x0280;0x0220
call prtilesfast0block
ld a,(Sprite0HitDetectFlag)
or a
ld c,0x80
jr z,prtilesfastbottom ;no scroll
ld a,(PPU_CTRL_REG1)
rra
jr nc,$+4
set 2,h ;2nd tilemap
ld a,(PPU_SCROLL_REG_H)
rra
;rra
;rra
and 127;31
ld c,a ;scroll
push hl
srl a
srl a
add a,l
ld l,a
;будем выводить слева 32-scroll, справа scroll знакомест
push bc
push de ;screen (addrstack)
ld a,c
and 3
jr z,prtilesfast_noblankleft
dec de
dec a
jr nz,$-3
prtilesfast_noblankleft
ld a,128;32
sub c
ld c,a
ld b,25-2
call prtilesfast0block
pop de ;screen (addrstack)
pop bc ;scroll
pop hl
ld a,h
xor 4
ld h,a ;another tilemap
;ld b,0
ld a,128;32
sub c
;add a,a
;add a,a
add a,e
ld e,a
;adc a,d
;sub e
;ld d,a
prtilesfastbottom
ld b,25-2
ld a,c
or a
ret z
;для scroll phase 0 стек такой:
;(scrL) 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 2
;(scrR) 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 2
;для scroll phase 1 стек такой:
;(scrR) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;(scrL) 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 2
;для scroll phase 2 стек такой:
;(scrL) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;(scrR) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;для scroll phase 3 стек такой:
;(scrR) noaddr, noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023
;(scrL) noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr x 1
;генерируем один стек на все фазы (строки лежат через 256 байт):
;noaddr, noaddr, 0x8004, 0xa004, 0x8005, ... 0xa023, noaddr, noaddr
prtilesfast0block
bit 0,e
jr z,prtilesfast0block_even
res 0,e
push bc
push de
push hl
push bc
;ld a,(setpgs_scr_high)
call getuser_scr_high
SETPG32KLOW
call setpgtileprocL
pop bc
call prtilesfast0lines
;ld a,(setpgs_scr_low)
call getuser_scr_low
SETPG32KLOW
call setpgtileprocR
pop hl
pop de
pop bc
inc de
inc de
jp prtilesfast0lines
prtilesfast0block_even
push bc
push de
push hl
push bc
;ld a,(setpgs_scr_low)
call getuser_scr_low
SETPG32KLOW
call setpgtileprocL
pop bc
call prtilesfast0lines
;ld a,(setpgs_scr_high)
call getuser_scr_high
SETPG32KLOW
call setpgtileprocR
pop hl
pop de
pop bc
;call prtilesfast0
;ret
;hl=tileaddr for line start
;de=addrstack
;b=hgt
;c=width ;max 128
;out: hl=tileaddr after last line, de=addrstack after last line
prtilesfast0lines
ld hy,d
ld ly,e ;iy=addrstack
ld (prtilelinefast_sp),sp
dec c
srl c
srl c
inc c ;c=((width+3)/4)
ld a,l
add a,c ;без переноса, т.к. читаем тайлы через inc e
ld l,a ;hl=tileaddr for line end
;hl=tileaddr for line end
;iy=addrstack
;b=hgt
;c=((width+3)/4)
exx
ld bc,40
exx
ld e,32
;a=l
;jr $
_prtilesfast0
ld sp,iy ;addrstack for this line
inc hy ;addrstack for next line
sub c ;без переноса, т.к. читаем тайлы через inc e
ld d,(hl) ;old tile after last tile
ld (hl),ENDLINETILE;0xfe ;patch after last tile
exx
ld e,a
exx
ld a,h
exx
ld d,a ;de=tileaddr for line start
ld a,(de)
;inc e
ld l,a
or 0xc0
ld h,a
jp (hl)
proc_endline
exx
ld (hl),d ;unpatch after last tile
;add hl,de ;+32 (for next tileline) ;это надо делать для адреса начала строки, а адрес конца строки перекошен по HSB
ld a,l
sub c
add a,e
jp nc,$+4
inc h
add a,c
ld l,a
djnz _prtilesfast0
prtilelinefast_sp=$+1
ld sp,0
ld d,hy
ld e,ly
sub c ;без переноса, т.к. читаем тайлы через inc e
ld l,a ;hl=tileaddr after last line
ret
setpgaddrstack4000
pgaddrstack=$+1
ld a,0
if RESTOREPG16K
;ld (curpg4000),a
endif
SETPG16K
ret
setpgaddrstackcopy4000 ;только в ините и int
pgaddrstackcopy=$+1
ld a,0
SETPG16K
ret
setpgtileprocL
pgtileprocL=$+1
ld a,0
SETPG32KHIGH
ret
setpgtileprocR
pgtileprocR=$+1
ld a,0
SETPG32KHIGH
ret
shutay
ld de,0xe00
shutay0
dec d
ld bc,0xfffd
out (c),d
ld b,0xbf
out (c),e
jr nz,shutay0
ret
if OSCALLS==0
oldpalette=$
dw 0
endif
on_int
;if stack in 0x4000..0x7fff:
;restore stack from pgaddrstackcopy (set in 0x4000 temporarily, then set pgaddrstack)
;else restore stack with de;0
ld (on_int_hl),hl
ld (on_int_sp),sp
ld (on_int_spcopy),sp
pop hl
ld (on_int_sp2),sp
ld (on_int_jp),hl
ld sp,INTSTACK
push af
push bc
push de
if RESTOREPG16K
ld a,(curpg16k) ;ok
push af
endif
imer_curscreen_value=$+1
ld a,0
ld bc,0x7ffd
out (c),a
ld a,(on_int_sp+1)
sub 0x40
cp 0x3f ;запас, чтобы не захватить очистку экрана в 0x8000
ex de,hl;ld hl,0
jr nc,on_int_norestoredata
;jr $
ld a,(pgaddrstackcopy)
SETPG16K
on_int_spcopy=$+1
ld hl,(0) ;ok
;if RESTOREPG16K==0
ld a,(pgaddrstack)
SETPG16K
;endif
on_int_norestoredata
on_int_sp=$+1
ld (0),hl ;восстановили запоротый стек
if MULTITASKING
; ld hl,on_int_q
;intjpaddr=$+1
; ld (0),hl
push ix
push iy
ex af,af'
exx
push af
push bc
push de
push hl
ld a,(curscreen)
ld e,a
OS_SETSCREEN ;вызываем здесь, а не в рандомном месте, иначе даже с одной задачей можем получить непредсказуемую задержку, которую не фиксирует наш таймер? с несколькими задачами надо учитывать и системный - TODO
curpalette=$+1
ld de,mariopal
OS_SETPAL
GET_KEY
cp key_redraw
jr nz,$+5
ld (wascurkeyredraw),a ;иначе не пишем
pop hl
pop de
pop bc
pop af
exx
ex af,af'
pop iy
pop ix
endif
if MULTITASKING==0 ;OSCALLS==0
curpalette=$+1
ld de,mariopal
ld hl,31
add hl,de
ld c,0xff
ld a,7
dup 8
OUT (0xF6),A
ld d,(hl)
dec hl
ld b,(hl) ;DDp palette low bits
OUT (c),d;(0xFF),A
dec hl
dec a
edup
ld a,7
dup 7
OUT (0xFE),A
ld d,(hl)
dec hl
ld b,(hl) ;DDp palette low bits
OUT (c),d;(0xFF),A
dec hl
dec a
edup
OUT (0xFE),A ;0
ld d,(hl)
dec hl
ld b,(hl) ;DDp palette low bits
OUT (c),d;(0xFF),A
endif
ld hl,(curtimer)
inc hl
ld (curtimer),hl
if MUSIC
if MUSICONINT
ld a,(codepage4000)
SETPG16K
ld b,0
ld d,b
soundenginecall=$
call SoundEngine
endif
ld c,0xfd
if SWEEP
;$4001(sq1)/$4005(sq2) bits
;--------------------------
;0-2 right shift amount
;3 decrease / increase (1/0) wavelength
;4-6 sweep update rate ;frequency at which $4002/3 is updated with the new calculated wavelength. The refresh rate frequency is 120Hz/(N+1), where N is the value written
;7 sweep enable
sweep1=$+1
ld de,0 ;сколько бит в этом счётчике??? будем считать, что 8
ld a,(SND_SQUARE1_REG+1)
rra
rra
rra
rra
and 7 ;sweep rate
inc a
ld b,a
sweep1counter=$+1
ld a,0
sub 2 ;2 "sound frames"
jr nc,$+3
add a,b ;sweep rate
ld (sweep1counter),a
jr nc,sweep1noinc
inc e
ld (sweep1),de
sweep1noinc
ld a,(SND_SQUARE1_REG+1)
and 7 ;right shift
jr z,sweep1noshift
ld b,a
sweep1shift0
srl e
djnz sweep1shift0
sweep1noshift
endif
ld hl,SND_SQUARE1_REG+3
ld a,(hl)
dec hl
ld l,(hl)
and 7
ld h,a
if SWEEP
ld a,(SND_SQUARE1_REG+1)
or a
jp p,sweep1disabled
;add/sub sweep:
scf ;for sq1 only!
sbc hl,de
and 8
jr nz,$+5 ;decrease wavelength
inc hl ;for sq1 only!
add hl,de
add hl,de ;increase wavelength
sweep1disabled
endif
ld a,1
ld b,0xff
out (c),a
ld b,0xbf
out (c),h
dec a
ld b,0xff
out (c),a
ld b,0xbf
out (c),l
if SWEEP
sweep2=$+1
ld de,0 ;сколько бит в этом счётчике??? будем считать, что 8
ld a,(SND_SQUARE2_REG+1)
rra
rra
rra
rra
and 7 ;sweep rate
inc a
ld b,a
sweep2counter=$+1
ld a,0
sub 2 ;2 "sound frames"
jr nc,$+3
add a,b ;sweep rate
ld (sweep2counter),a
jr nc,sweep2noinc
inc e
ld (sweep2),de
sweep2noinc
ld a,(SND_SQUARE2_REG+1)
and 7 ;right shift
jr z,sweep2noshift
ld b,a
sweep2shift0
srl e
djnz sweep2shift0
sweep2noshift
endif
ld hl,SND_SQUARE2_REG+3
ld a,(hl)
dec hl
ld l,(hl)
and 7
ld h,a
if SWEEP
ld a,(SND_SQUARE2_REG+1)
or a
jp p,sweep2disabled
;add/sub sweep:
sbc hl,de
ld a,(SND_SQUARE2_REG+1)
and 8
jr nz,$+4 ;decrease wavelength
add hl,de
add hl,de ;increase wavelength
sweep2disabled
endif
ld a,5
ld b,0xff
out (c),a
ld b,0xbf
out (c),h
dec a
ld b,0xff
out (c),a
ld b,0xbf
out (c),l
ld d,0x0f ;all channels enabled
ld a,11
ld b,0xff
out (c),a
ld hl,SND_TRIANGLE_REG+3
ld a,(hl)
and 7
dec hl
ld e,(hl)
sla e
adc a,a
jr z,$+2+2+2 ;иначе немного фальшивят верхние ноты в басу
srl a
rr e
srl a
rr e
ld hl,curtimer
bit 0,(hl)
jr z,$+3
inc e ;уседняем фальшь по 2 прерываниям
srl a
rr e
jr nz,$+4
res 1,d ;disable triangle if freq=0
ld b,0xbf
out (c),e
;ld e,12;3
;ld b,0xff
;out (c),e
;ld b,0xbf
;out (c),a
ld a,6
ld b,0xff
out (c),a
ld a,(SND_NOISE_REG+2)
add a,a
ld b,0xbf
out (c),a
;counters
ld a,(SND_TRIANGLE_REG)
or a
jp m,trianglecount
;linear counter load, stop length counter
;and 0x7f
ld (trianglelinearcounter),a
;jp trianglehalt
trianglecount
trianglelinearcounter=$+1
ld a,0
sub 4
jr nc,$+3
xor a
ld (trianglelinearcounter),a ;ld (SND_TRIANGLE_REG),a
jr nz,$+4
res 1,d ;triangle disabled because of linear counter=0
ld a,(SND_COUNTER+8) ;(SND_TRIANGLE_REG+3) ;counter register, load it = f(SND_TRIANGLE_REG+3) at write there
sub 1;2
jr nc,$+3
xor a
ld (SND_COUNTER+8),a ;(SND_TRIANGLE_REG+3),a
jr nz,$+4
res 1,d ;triangle disabled because of counter=0
trianglehalt
ld a,(SND_SQUARE2_REG)
bit 5,a
jp nz,square2halt ;counter disable
ld a,(SND_COUNTER+4) ;(SND_SQUARE2_REG+3) ;counter register, load it = f(SND_SQUARE2_REG+3) at write there
sub 1;2
jr nc,$+3
xor a
ld (SND_COUNTER+4),a ;(SND_SQUARE2_REG+3),a
jr nz,$+4
res 2,d ;disabled because of counter=0
square2halt
ld a,(SND_SQUARE1_REG)
bit 5,a
jp nz,square1halt ;counter disable
ld a,(SND_COUNTER+0) ;(SND_SQUARE1_REG+3) ;counter register, load it = f(SND_SQUARE2_REG+1) at write there
sub 1;2
jr nc,$+3
xor a
ld (SND_COUNTER+0),a ;(SND_SQUARE1_REG+3),a
jr nz,$+4
res 0,d ;disabled because of counter=0
square1halt
ld a,(SND_NOISE_REG)
bit 5,a
jp nz,noisehalt ;counter disable
ld a,(SND_COUNTER+12) ;(SND_SQUARE1_REG+3) ;counter register, load it = f(SND_SQUARE2_REG+1) at write there
sub 16;1;2
jr nc,$+3
xor a
ld (SND_COUNTER+12),a ;(SND_SQUARE1_REG+3),a
jr nz,$+4
res 3,d ;disabled because of counter=0
noisehalt
;channel enable
ld a,7
ld b,0xff
out (c),a
ld hl,SND_MASTERCTRL_REG ;%???DNT21
ld a,(hl)
if 1==1
add a,0x2 ;%00? -> %01? (bit 2 reset), %11? -> %00? (bit 2 reset)
and 0x4 ;was %00? or %11? - no swap
ld a,(hl)
jr z,noswap21 ;bit 2 reset - no swap
xor 0x6 ;swap %01? <-> %10?
noswap21
else
rra ;%??????T?
xor (hl)
and 0x02
xor (hl) ;%???DNTT1
and 0xfb ;%???DN0T1
bit 1,(hl)
jr z,$+4
or 0x04 ;%???DN2T1
endif
;or 8 ;noise
and d
ld d,a
cpl
;and 7
and 5 ;enable B (тихая огибающая) ;or 2 ;disable triangle(B) here
or 0x38 ;disable noise
bit 3,d
jr z,$+2+2+2
set 1,a ;disable tone in B
res 4,a ;enable noise in B
ld b,0xbf
out (c),a
;Only a write out to $4003/$4007/$400F will reset the current envelope decay counter to a known state (to $F, the maximum volume level) for the appropriate channel's envelope decay hardware.
;Otherwise, the envelope decay counter is always counting down (by 1) at the frequency currently contained in the volume / envelope decay rate bits (even when envelope decays are disabled (setting bit 4)), except when the envelope decay counter contains a value of 0, and envelope decay looping (bit 5) is disabled (0).
;vol
ld e,8
ld b,0xff
out (c),e
ld a,(SND_SQUARE1_REG) ;bit4=constant volume, or else envelope
bit 4,a
jr nz,vol1const
ld a,(SND_DECAYVOL+0)
vol1const
and 15
ld hl,tvolume
add a,l
ld l,a
adc a,h
sub l
ld h,a
ld l,(hl)
ld b,0xbf
out (c),l
ld hl,SND_SQUARE1_REG
ld a,(hl)
and 15 ;decay rate
inc a
ld b,a
vol1decaycounter=$+1
ld a,0
sub 4 ;4 "sound frames"
jr nc,$+3
add a,b ;decay rate
ld (vol1decaycounter),a
jr nc,vol1nodecay
ld a,(SND_DECAYVOL+0)
dec a
jp p,vol1noenddecay
and 0xf
bit 5,(hl)
jr nz,vol1noenddecay ;decay looping enabled
xor a
vol1noenddecay
ld (SND_DECAYVOL+0),a
vol1nodecay
ld e,10
ld b,0xff
out (c),e
ld a,(SND_SQUARE2_REG) ;bit4=constant volume, or else envelope
bit 4,a
jr nz,vol2const
ld a,(SND_DECAYVOL+4)
vol2const
and 15
ld hl,tvolume
add a,l
ld l,a
adc a,h
sub l
ld h,a
ld l,(hl)
ld b,0xbf
out (c),l
ld hl,SND_SQUARE2_REG
ld a,(hl)
and 15 ;decay rate
inc a
ld b,a
vol2decaycounter=$+1
ld a,0
sub 4 ;4 "sound frames"
jr nc,$+3
add a,b ;decay rate
ld (vol2decaycounter),a
jr nc,vol2nodecay
ld a,(SND_DECAYVOL+4)
dec a
jp p,vol2noenddecay
and 0xf
bit 5,(hl)
jr nz,vol2noenddecay ;decay looping enabled
xor a
vol2noenddecay
ld (SND_DECAYVOL+4),a
vol2nodecay
ld e,9
ld b,0xff
out (c),e
ld a,(SND_NOISE_REG) ;bit4=constant volume, or else envelope
bit 4,a
jr nz,noiseconst
ld a,(SND_DECAYVOL+12)
noiseconst
and 15
ld hl,tvolume
add a,l
ld l,a
adc a,h
sub l
ld h,a
ld a,(hl)
;ld b,0xbf
;out (c),l
;ld e,9
;ld b,0xff
;out (c),e
bit 3,d ;noise
jr nz,notrianglevolumeout
xor a
bit 1,d ;triangle
jr z,$+4
ld a,16
notrianglevolumeout
ld b,0xbf
out (c),a
;and 15
;jr nz,$
ld hl,SND_NOISE_REG
ld a,(hl)
and 15 ;decay rate
inc a
ld b,a
noisedecaycounter=$+1
ld a,0
sub 4 ;4 "sound frames"
jr nc,$+3
add a,b ;decay rate
ld (noisedecaycounter),a
jr nc,noisenodecay
ld a,(SND_DECAYVOL+12)
dec a
jp p,noisenoenddecay
and 0xf
bit 5,(hl)
jr nz,noisenoenddecay ;decay looping enabled
xor a
noisenoenddecay
ld (SND_DECAYVOL+12),a
noisenodecay
endif
if MULTITASKING
call oldimer
endif
if RESTOREPG16K
;curpg4000=$+1
; ld a,0
pop af
SETPG16K
endif
pop de
pop bc
pop af
on_int_hl=$+1
ld hl,0
on_int_sp2=$+1
ld sp,0
ei
on_int_jp=$+1
jp 0
SND_COUNTER
SND_DECAYVOL=$+1
ds 4+4+4+2 ;sq1,sq2,tri,noise (2 bytes used from 4)
tvolume
db 0,9,10,11, 12,12,13,13, 13,14,14,14, 15,15,15,15
;что-то не так с этой таблицей
tcounterload
db 0x7f,0x05
db 0x01,0x0a
db 0x02,0x14
db 0x03,0x28
db 0x04,0x50
db 0x05,0x1e
db 0x06,0x07
db 0x07,0x0d
db 0x08,0x06
db 0x09,0x0c
db 0x0a,0x18
db 0x0b,0x30
db 0x0c,0x60
db 0x0d,0x24
db 0x0e,0x08
db 0x0f,0x10
gettimer
;out: hl=timer
;суммируем оба таймера - вдруг было системное прерывание
if OSCALLS
OS_GETTIMER ;dehl=timer
curtimer=$+1
ld de,0
add hl,de
else
curtimer=$+1
ld hl,0
endif
ret
;include "smbsound.asm"
;include "smbmusic.asm"
reservepage
;new page, set page in textpages, npages++, set page in #c000
;nz=error
OS_NEWPAGE
or a
ret nz
npages=$+1
ld hl,filepages
ld (hl),e
inc l
ld (npages),hl
ld a,e
SETPG32KHIGH
xor a
ret ;z
DEMOLONGLINE=1
demooff
;выключение демы, играем и пишем с клавиатуры
ld a,55; ;scf ;201 ;ret
ld (readdemo),a
;ld a,0x77
;ld (getbyte_opcode),a
xor a
ld (InjurePlayer_PiranhaPlant),a
;jp democontinue ;иначе будет вечная пауза
democontinue
;продолжение после брякпоинта
xor a
ld (readdemo_stopflag),a
ret
macro NEXTBYTEFAST
inc l
call z,getbyte_inch_pp
endm
macro NEXTBYTEEND
ld (getbyte_addr),hl
endm
writedemo
;сейчас указатель на разделителе после кнопок джойстика
;a=keys
;DEMOLONGLINE=1!!!
push af
call getbyte_setpg
NEXTBYTEFAST
ld (hl),'+'
ld b,8
writedemo0
NEXTBYTEFAST
ld (hl),'.'
djnz writedemo0
NEXTBYTEFAST
ld (hl),'|'
NEXTBYTEFAST
ld (hl),0x0d
NEXTBYTEFAST
ld (hl),0x0a
NEXTBYTEFAST
ld (hl),'|'
NEXTBYTEFAST
ld (hl),'.'
NEXTBYTEFAST
ld (hl),'.'
NEXTBYTEFAST
ld (hl),'|'
pop af
push af
ld c,a
if DEMOLONGLINE
xor a
ld b,c
rr c
rla
rr c
rla
rr c
rla
rr c
rla ;%0000UDLR
xor b
and 0x0f
xor b
ld c,a
endif
ld b,8
writedemo1
NEXTBYTEFAST
rrc c
ld (hl),'.'
jr nc,$+4
ld (hl),'Z'
djnz writedemo1
NEXTBYTEEND
call setpgs_code
pop af
ret
readdemo
display "readdemo=",$
or a ;/scf
jr c,writedemo
readdemo_stopflag=$
nop ;/ret
;jr $
call getbyte_setpg
if 1==0 ;однобайтный формат дем
ld a,(hl)
;a=buttons = %R?D?t?BA
ld b,8
rra
rl c
djnz $-3
NEXTBYTEEND
ld a,c
;a=buttons
;bit - button (ZX key)
;7 - A (A)
;6 - B (S)
;5 - Select (Space)
;4 - Start (Enter)
;3 - Up (7)
;2 - Down (6)
;1 - Left (5)
;0 - Right (8)
else
;"|0|RLDUTsBA|||",0x0a = 15 bytes, реально начинаем на 4 байта раньше
;"|.r|UDLRSsBA|........|",0x0d,0x0a = 24 bytes, реально начинаем на 12 байт раньше
;лучше перейти на короткий формат, а то 6000t после оптимизации (один байт = 194t)
if DEMOLONGLINE
ld d,12+4
else
ld d,3+4
endif
readdemo0
NEXTBYTEFAST
ld a,(hl)
add a,256-'A'
rr e
dec d
jp nz,readdemo0
ld d,0x80
readdemo1
NEXTBYTEFAST
ld a,(hl)
add a,256-'A'
rr d
jp nc,readdemo1
NEXTBYTEEND
if DEMOLONGLINE
;ld a,e
;and 0x40 ;reset
;cp 0
;ld ($-1),a
bit 6,e
jp z,readdemo_noreset
;or a
;jr nz,readdemo_noreset
;pop af
;jp Start
if FASTDEMOBEFOREBREAKPOINT
push de
xor a
ld (skipPPU),a
call EmulatePPU
call EmulatePPU
pop de
endif
ld a,201
ld (readdemo_stopflag),a
readdemo_noreset
xor a
ld b,d
rr d
rla
rr d
rla
rr d
rla
rr d
rla ;%0000UDLR
xor b
and 0x0f
xor b
else
ld a,d
endif
endif
;a=buttons
;bit - button (ZX key)
;7 - A (A)
;6 - B (S)
;5 - Select (Space)
;4 - Start (Enter)
;3 - Up (7)
;2 - Down (6)
;1 - Left (5)
;0 - Right (8)
push af
call setpgs_code
pop af
ret
getbyte_setpg
;портит hl,bc
;не портит de
;out: a=pg, hl=addr in pg
getbyte_addr=$+1 ;реально читать начнём со следующего адреса
;ld hl,0xffe0+5 ;148974
;правдоподобно только 5..6, что-то не так с отскоком от врага?
;ld hl,0xffe0+14 ;53672
;ld hl,0xc260+4 ;53672
;было (когда старт нажимался слишком поздно - уже во встроенной деме)
;12..13 проход через трубу медленно, сдох на монстре
;14 (+4) проход через трубу с задержкой справа, потом застрял на лестнице
;15 не допрыгнул до трубы с бонусом
;16-20 ещё хуже
;ld hl,0xd2c8-12-1+(15*24) ;1904330 (pg1)
;11..13 сбил кирпич, пропрыгал две трубы
;14 прошёл 1-1, сдох на черепахе в 1-2
;15 прошёл 1-1, сдох на грибе после черепахи в 1-2
;16 нырнул в трубу, но не собрал монетки, а застрял
;17..20 не стартует
;ld hl,0xc111-4-1+(16*15) ;351918
;11..14 - застреваем после убийства второго монстра
;15 - перепрыгиваем его, застреваем дальше
;16 - пролезаем через трубу, застреваем на лестнице
;17..20- умираем на втором монстре
;ld hl,0xc0f4-4-1+(7*15) ;307549
;7..8 - довольно быстро бежим, но попадаем на первого монстра
;9 прыжок явно мимо
;12 медленно
;16..20 не стартует
ld hl,0xc090-12-1 +(4*24) ;1775978 (cropped)
;0,1 - проходим world 1-1 (при jr RImpd застреваем возле замка)
;2,3 - застреваем на конечной лестнице 1-1 (при jr RImpd застреваем в трубе)
;4 - доходим дальше в 1-2 (при jr RImpd застреваем возле замка)
;5,6,7,8,9,10,11,12,13,14,15,16,17,18 - не проходим 1-1 (18 при jr RImpd застреваем возле замка)
;19,20 - застреваем на конечной лестнице 1-1 (при jr RImpd застреваем возле замка)
;21,22 - проходим world 1-1
;23,24 - застреваем на конечной лестнице 1-1
;25 - доходим дальше в 1-2
getbyte_pg=$+1
ld a,(filepages)
SETPG32KHIGH
ret
getbyte_inch_pp
;не портит bc, переустанавливает hl в начале новой страницы (тогда же щёлкает страницу)
;l=0
inc h
ret nz
ld hl,getbyte_pg
inc (hl)
push bc
getbyte_inch_memoryretry_m
ld c,(hl)
ld b,filepages/256
getbyte_inch_memoryretry
ld a,(bc)
or a
jr z,getbyte_inch_newpg
SETPG32KHIGH
pop bc
ld hl,0xc000
ret
getbyte_inch_newpg
push bc
push de
halt ;чтобы не сработало системное прерывание
call reservepage ;nz=error ;портит все регистры (но нам hl не важен)
ld a,(imer_curscreen_value)
ld bc,0x7ffd
out (c),a
pop de
pop bc
jr z,getbyte_inch_memoryretry
ld hl,getbyte_pg
dec (hl)
jr getbyte_inch_memoryretry_m ;no more memory
savedemo
ld de,filename2
OS_CREATEHANDLE
;b=new file handle
push af
ld a,b
ld (filehandle),a
pop af
;or a
;ret nz
ld hl,0
ld de,0
ld a,0
nvview_save0
;push de
;push hl
;call reservepage
;pop hl
;pop de
;ret nz ;no memory
push af
ld c,a
ld b,filepages/256
ld a,(bc)
SETPG32KHIGH
push de
push hl
ld de,0xc000
ld hl,0x4000
;DE = Buffer address, HL = Number of bytes to read
push hl
ld a,(filehandle)
ld b,a
OS_WRITEHANDLE
;hl=actual size
;hl=loaded bytes
ld b,h
ld c,l
pop hl ;Number of bytes to read
or a
sbc hl,bc ;z=loaded as requested
;bc=loaded bytes
pop hl
pop de
pop af
;hlde=size
;z=loaded as requested
;ex de,hl
;add hl,bc
;ex de,hl
;jr nc,$+3
;inc hl
;jr z,nvview_save0
inc a
ld ix,npages
cp (ix)
jr nz,nvview_save0
;hlde=true file size (for TRDOSFS)
;ld (fcb+FCB_FSIZE),de
;ld (fcb+FCB_FSIZE+2),hl
call closestream_file
jp setpgs_code
gfxfilename
db "smb.nes",0
filename
db "antipac.fm2",0
filename2
db "demo.fm2",0
include "../../_sdk/file.asm"
tnofile
db "smb.nes not found",0x0d,0x0a,0
;oldtimer
; ds 2
;display "free before 0x2000=",0x2000-$
ds 0x2000-$
;tile gfx: 2 256-tile maps
;16bytes/tile: 8bytes low bit, 8bytes high bit
tilegfx
ds 0x2000 ;incbin "smbtiles"
include "SMBDIS.ASM"
end
;display "End=",end
;display "Free after end=",/d,0xc000-end
;display "Size ",/d,end-begin," bytes"
savebin "smb.com",begin,end-begin
;LABELSLIST "user.l"