uh oh. create meta tile function

This commit is contained in:
Shoofle 2025-03-02 09:50:03 -05:00
parent d13bc1e54c
commit f2b25f25db
10 changed files with 335 additions and 561 deletions

View File

@ -5,28 +5,61 @@
; then a 16bit value of the offset between tile map and end
; then the 16bit address of the tile map
TheFool:
def Card_Offset_title equ @-TheFool
db 10, "THE FOOL "
db 10, " "
def Card_Offset_description equ @-TheFool
db 9, "beginning"
db 9, "leap "
db 9, "naivete "
def Card_Offset_tilemap equ @-TheFool
dw .BackgroundCopyEnd - .BackgroundCopy
dw .BackgroundCopy
def Card_Offset_keytiles equ @-TheFool
dw .KeyArtTilesEnd - .KeyArtTiles
dw .KeyArtTiles
def Card_Offset_spritetiles equ @-TheFool
dw .SpriteTilesEnd - .SpriteTiles
dw .SpriteTiles
def Card_Offset_functions equ @-TheFool
dw .fInit
dw .fUpdate
dw .fDraw
; original export script by gabriel reis, modified by shoofle
; CARD_VARS_START: timer
; CARD_VARS_START+2: timer 2
; CARD_VARS_START+4: animation frame for dog
; CARD_VARS_START+5:
; CARD_VARS_START+6: y of zero
; CARD_VARS_START+7:
.fInit:
ld h, $c2
ld l, $00
ld a, [rLCDC]
xor a, %0000_0100
ld [rLCDC], a
ld hl, CARD_VARS_START
ld a, 0
ld [hl+], a ; $c200 = timer for dog
ld [hl+], a ; $c201 = timer for big zero
ld [hl+], a ; timer for dog @ +0
ld [hl+], a
ld [hl+], a ; timer for big zero @ +2
ld [hl+], a
ld [hl+], a ; frame of dog animation
ld [hl+], a
ld [hl+], a ; y of zero
ld [hl+], a ; x of zero
ld hl, .doggie1
ld de, MY_OAM
ld b, 134
ld c, 34
ld a, $23
; takkes similar args as copytilestomapunsafe but builds several sprites
; instead.
; location of source tile map: hl
; location in memory to write to: de
; y and x in b and c
; height and width in a & %11110000 and a & %00001111 ??? that's deranged
call BuildMetaSprite
ret
.fUpdate:
ld a, [rDELTAT]
@ -47,6 +80,9 @@ TheFool:
ld a, 0
ld [CARD_VARS_START], a
ld [CARD_VARS_START+1], a
; and make the dog dance
call .dogDance
.doneWithTimer1
@ -55,7 +91,7 @@ TheFool:
ld [CARD_VARS_START+2], a
ld a, [CARD_VARS_START+2+1]
adc a, 0
ld [$c302+1], a
ld [CARD_VARS_START+2+1], a
ld a, [CARD_VARS_START+2+1]
cp a, $10 ; $10 00 = 1 second
@ -69,27 +105,76 @@ TheFool:
.doneWithTimer2
ret
println "card vars start is ", CARD_VARS_START
.fDraw:
ret
.dogDance:
ld hl, CARD_VARS_START+4
inc [hl]
ld a, 2
cp a, [hl]
jp nz, :+
ld [hl], 0
:
ld a, [hl] ; a now holds the frame of the animation.
cp a, 0
jp z, .frame1
cp a, 1
jp z, .frame2
ret
.frame1
ld hl, .doggie1
ld de, MY_OAM
ld b, 134
ld c, 34
ld a, $23
; takkes similar args as copytilestomapunsafe but builds several sprites
; instead.
; location of source tile map: hl
; location in memory to write to: de
; y and x in b and c
; height and width in a & %11110000 and a & %00001111 ??? that's deranged
call BuildMetaSprite
ret
.frame2
ld hl, .doggie2
ld de, MY_OAM
ld b, 133
ld c, 34
ld a, $23
call BuildMetaSprite
ret
.SpriteTiles:
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$01,$01,$01,$01,$01,$01,$0f,$0f,$1f,$10,$1f,$10,$0f,$0c
db $a0,$a0,$f8,$58,$fc,$04,$5e,$a2,$ff,$01,$ff,$00,$ff,$00,$ff,$00
db $00,$00,$00,$00,$00,$00,$02,$02,$07,$05,$ff,$fd,$ff,$01,$ff,$01
db $03,$03,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$7e,$52,$3c,$34,$08,$08
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$3f,$29,$1e,$1a,$04,$04
db $00,$00,$00,$00,$00,$00,$04,$04,$0e,$0a,$ff,$fd,$ff,$01,$ff,$01
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$fc,$94,$78,$58,$20,$20
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$7e,$4a,$3c,$2c,$10,$10
db $01,$01,$01,$01,$01,$01,$01,$01,$1f,$1f,$1f,$10,$1f,$10,$1f,$1c
db $f0,$f0,$fc,$5c,$fe,$06,$5f,$a3,$ff,$01,$ff,$00,$ff,$00,$ff,$00
db $00,$00,$00,$00,$00,$00,$07,$07,$87,$85,$ff,$fd,$ff,$01,$ff,$01
db $07,$07,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$fe,$d2,$7e,$76,$1c,$1c
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$7f,$69,$3f,$3b,$0e,$0e
db $00,$00,$00,$00,$00,$00,$0e,$0e,$8f,$8b,$ff,$fd,$ff,$01,$ff,$01
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$fe,$96,$fc,$dc,$70,$70
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$7f,$4b,$7e,$6e,$38,$38
db $00,$00,$03,$03,$0c,$0c,$10,$10,$20,$20,$20,$20,$40,$40,$40,$40
db $00,$00,$c0,$c0,$30,$30,$08,$08,$04,$04,$04,$04,$02,$02,$02,$02
db $40,$40,$40,$40,$20,$20,$20,$20,$10,$10,$0c,$0c,$03,$03,$00,$00
db $02,$02,$02,$02,$04,$04,$04,$04,$08,$08,$30,$30,$c0,$c0,$00,$00
.SpriteTilesEnd:
.doggie1: ; tiles start at 0
db $01, $02, $03
db $04, $08, $06
.doggie2:
db $01, $02, $07
db $04, $05, $09
.KeyArtTiles:
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $1f,$00,$0f,$00,$0f,$00,$0f,$00,$07,$00,$07,$00,$07,$00,$07,$00

Binary file not shown.

View File

@ -3,15 +3,15 @@
.SpriteTiles:
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $00,$00,$01,$01,$01,$01,$01,$01,$0f,$0f,$1f,$10,$1f,$10,$0f,$0c
db $a0,$a0,$f8,$58,$fc,$04,$5e,$a2,$ff,$01,$ff,$00,$ff,$00,$ff,$00
db $00,$00,$00,$00,$00,$00,$02,$02,$07,$05,$ff,$fd,$ff,$01,$ff,$01
db $03,$03,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$7e,$52,$3c,$34,$08,$08
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$3f,$29,$1e,$1a,$04,$04
db $00,$00,$00,$00,$00,$00,$04,$04,$0e,$0a,$ff,$fd,$ff,$01,$ff,$01
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$fc,$94,$78,$58,$20,$20
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$7e,$4a,$3c,$2c,$10,$10
db $01,$01,$01,$01,$01,$01,$01,$01,$1f,$1f,$1f,$10,$1f,$10,$1f,$1c
db $f0,$f0,$fc,$5c,$fe,$06,$5f,$a3,$ff,$01,$ff,$00,$ff,$00,$ff,$00
db $00,$00,$00,$00,$00,$00,$07,$07,$87,$85,$ff,$fd,$ff,$01,$ff,$01
db $07,$07,$01,$01,$01,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$fe,$d2,$7e,$76,$1c,$1c
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$7f,$69,$3f,$3b,$0e,$0e
db $00,$00,$00,$00,$00,$00,$0e,$0e,$8f,$8b,$ff,$fd,$ff,$01,$ff,$01
db $ff,$00,$ff,$00,$ff,$00,$ff,$80,$ff,$93,$fe,$96,$fc,$dc,$70,$70
db $ff,$01,$ff,$01,$ff,$01,$ff,$01,$ff,$c9,$7f,$4b,$7e,$6e,$38,$38
db $00,$00,$03,$03,$0c,$0c,$10,$10,$20,$20,$20,$20,$40,$40,$40,$40
db $00,$00,$c0,$c0,$30,$30,$08,$08,$04,$04,$04,$04,$02,$02,$02,$02
db $40,$40,$40,$40,$20,$20,$20,$20,$10,$10,$0c,$0c,$03,$03,$00,$00
@ -19,22 +19,6 @@
.SpriteTilesEnd:
.Sprites: ; tiles start at 0
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $0a, $0b, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $0c, $0d, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $01, $02, $03, $01, $02, $07, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $04, $08, $06, $04, $05, $09, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $01, $02, $07
db $04, $05, $09
.SpritesEnd:

View File

@ -18,7 +18,7 @@ def ASYNC_STACK_TOP equ $ffc0
; second value is the destination of the async call, at ffbc = ffbe-2 = ffc0-2-2
def ASYNC_THREAD_CALL equ ASYNC_STACK_TOP - 2 - 2
def SAFE_ASYNC_START EQU 148
def SAFE_ASYNC_START EQU 150
def SAFE_ASYNC_END EQU 153
Async_Spawn_HL:

View File

@ -1,6 +1,27 @@
; CARD_HELPER_VARS_START defines the beginning of the $100 bytes set aside for system usage
def cvCardAddress equ 0 ; location of the current card's struct
LoadCardData:
LoadCardDataAsync:
ei
; first and foremost, clear the card init, update, and draw handles, so there's
; no chance of trying to jump into code from a previous card.
ld bc, Instructions
ld hl, CARD_INIT
ld [hl], c
inc hl
ld [hl], b
ld hl, CARD_UPDATE
ld [hl], c
inc hl
ld [hl], b
ld hl, CARD_DRAW
ld [hl], c
inc hl
ld [hl], b
ld a, [vSelectedCardIndex]
ld [vPreviousCardIndex], a
@ -13,19 +34,19 @@ LoadCardDataAsync:
ld a, [hl+]
ld [rROMB0], a ; select the specified bank
; follow the pointer we're looking at
; follow the pointer we're looking at, and write it to cvCardAddress
ld a, [hl+]
ld [CARD_HELPER_VARS_START + cvCardAddress], a
ld c, a
ld a, [hl+]
ld [CARD_HELPER_VARS_START + cvCardAddress + 1], a
ld b, a
ld h, b
ld l, c ; hl now contains the address of the card data.
.duringDraw
; synchronously
; hl points to a card struct.
; card struct starts with a sequence of length-prefixed strings in memory
; so when we're done writing one, hl will be correctly placed to read the next
; length-prefixed print doesn't require passing a length
@ -60,35 +81,15 @@ LoadCardDataAsync:
call CopyTilesToMapUnsafe
ld a, [vSelectedCardIndex]
ld [vPreviousCardIndex], a
ld b, 0
ld c, a ; load bc from a, the number of the card in the cards list
ld hl, Cards + 1 ; skip the length prefix
add hl, bc
add hl, bc
add hl, bc ; triple add bc entries are bank, addr, addr
ld a, [CARD_HELPER_VARS_START + cvCardAddress]
ld l, a
ld a, [CARD_HELPER_VARS_START + cvCardAddress + 1]
ld h, a ; hl now contains the address of the card data.
ld b, 0
ld c, Card_Offset_keytiles ; jump straight to keytiles length and location!
add hl, bc
ld a, [hl+]
ld [rROMB0], a ; select the specified bank
; follow the pointer we're looking at
ld a, [hl+]
ld c, a
ld a, [hl+]
ld b, a
ld h, b
ld l, c ; hl now contains the address of the card data.
call PassList
call PassList
call PassList
call PassList
call PassList ; skip the strings
inc hl
inc hl ; skip tile map width
inc hl
inc hl ; skip tile map pointer
ld a, [hl+]
ld c, a
ld a, [hl+]
@ -104,6 +105,54 @@ LoadCardDataAsync:
ld de, $9000 + VARIABLE_TILES_START*$10 ; always load tile data into the same spot in vram
call CopyRangeUnsafe
di
nop
ld a, [CARD_HELPER_VARS_START + cvCardAddress]
ld l, a
ld a, [CARD_HELPER_VARS_START + cvCardAddress + 1]
ld h, a ; hl now contains the address of the card data.
ld b, 0
ld c, Card_Offset_spritetiles ; jump straight to sprite tiles length and location!
add hl, bc
ld a, [hl+]
ld c, a
ld a, [hl+]
ld b, a ; bc has length of tile data
ld a, [hl+]
ld e, a
ld a, [hl+]
ld d, a ; de has source of tile range copy
ld h, d
ld l, e ; hl takes the source
ld de, $8000 ; sprite tiles get loaded into the bottom of vram
call CopyRangeUnsafe
ld a, [CARD_HELPER_VARS_START + cvCardAddress]
ld l, a
ld a, [CARD_HELPER_VARS_START + cvCardAddress + 1]
ld h, a ; hl now contains the address of the card data.
ld b, 0
ld c, Card_Offset_functions ; jump straight to sprite tiles length and location!
add hl, bc ; hl now points to the card functions
ld a, [hl+]
ld [CARD_INIT], a
ld a, [hl+]
ld [CARD_INIT+1], a
ld a, [hl+]
ld [CARD_UPDATE], a
ld a, [hl+]
ld [CARD_UPDATE+1], a
ld a, [hl+]
ld [CARD_DRAW], a
ld a, [hl+]
ld [CARD_DRAW+1], a
call CARD_INIT - 1
ret

View File

@ -12,194 +12,6 @@ DEF vSafeCopyInterruptEnable EQU vSafeCopyInterrupt + 2 ; stashes $FFFF, which i
DEF SAFE_TRANSFER_START EQU 145
DEF SAFE_TRANSFER_END EQU 153
CopyRangeSafe:
; hl is source
; de is destination
; bc is length to copy
; copy an array of bytes to a destination in memory.
; this is completely different from CopyRangeUnsafe.
; this initiates an asynchronous, interrupt-driven copy of BC bytes of memory
; from HL to DE.
; it may return a memory address to look at for progress of the transfer,
; or else it's just going to do it with a hard-coded address.
; check the transfer status address for zero; when it's zero, the transfer is done!
; this works by using the STAT interrupt in LYC mode to interrupt its own execution at
; two scanlines inside the vblank interval to know when to start and stop.
; stash arguments in memory
di
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a
ld a, c
ldh [vSafeCopyCount], a
ld a, b
ldh [vSafeCopyCount+1], a
; stash interrupt state in memory
ldh a, [$ff41]
ldh [vSafeCopySTAT], a ; stashes $FF41, the STAT register
ldh a, [$ff45]
ldh [vSafeCopyLYC], a ; stashes $FF45, the LYC register
ld a, [INTERRUPT_LCD]
ld [vSafeCopyInterrupt], a
ld a, [INTERRUPT_LCD+1]
ld [vSafeCopyInterrupt+1], a ; stashes the current STAT interrupt handler
ld a, [$ffff]
and a, %0000_0010
ld [vSafeCopyInterruptEnable], a ; stashes whether LCD interrupt are enabled
ld hl, CopyRangeSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE"
ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a
ld hl, $ffff
set 1, [hl]
ld a, %0100_0000
ld [$ff41], a
ld hl, vSafeCopyCount
ld a, 0
ld [$ff0f], a
ei
nop
ret ; return address of bytes remaining to copy
CopyRangeSafe_EnterSafeMode:
push hl
push bc
push de
push af
ld hl, CopyRangeSafe_ExitSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, SAFE_TRANSFER_END ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
ldh a, [vSafeCopySource]
ld l, a
ldh a, [vSafeCopySource+1]
ld h, a ; fetch the source
ldh a, [vSafeCopyDest]
ld e, a
ldh a, [vSafeCopyDest+1]
ld d, a ; fetch the dest
ldh a, [vSafeCopyCount]
ld c, a
ldh a, [vSafeCopyCount+1]
ld b, a ; fetch the count
; before starting transfer, make sure the zero flag is false.
ld a, 1
cp a, 0
CopyRangeSafe_TransferLoop:
ei
nop ; ei only sets the flag one instruction later apparently. safety nop!
di ; process interrupts
jp z, CopyRangeSafe_CleanUp ; zero flag will only be set if the exitsafemode handler fired
ld a, [hl+]
ld [de], a ;
inc de
dec bc
ld a, b
or a, c
jp nz, CopyRangeSafe_TransferLoop
jp CopyRangeSafe_Done
CopyRangeSafe_ExitSafeMode:
ld a, 0
cp a, 0 ; set the zero flag, which we're using as a signal to stop transferring
reti ; set a to zero and set the zero flag true. now the transfer loop will end
CopyRangeSafe_CleanUp:
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a ; store new source
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a ; store new dest
ld a, c
ldh [vSafeCopyCount], a
ld a, b
ldh [vSafeCopyCount+1], a ; store new count
ld hl, CopyRangeSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af
pop de
pop bc
pop hl
reti ; we're done with this memcpy cycle so we return from interrupt.
CopyRangeSafe_Done: ; called when the complete transfer is finished,
; this restores interrupts to how they were.
; stash interrupt state in memory
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a ; store new source
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a ; store new dest
ld a, c
ldh [vSafeCopyCount], a
ld a, b
ldh [vSafeCopyCount+1], a ; store new count
ld hl, CopyRangeSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af
pop de
pop bc
pop hl
ldh a, [vSafeCopySTAT]
ldh [$ff41], a
ldh a, [vSafeCopyLYC]
ldh [$ff45], a
ldh a, [vSafeCopyInterrupt]
ld [INTERRUPT_LCD], a
ldh a, [vSafeCopyInterrupt+1]
ld [INTERRUPT_LCD+1], a
ld hl, $ffff
ld a, [hl]
cpl
set 1, a
cpl ; turn off the lcd interrupt enable
ld [hl], a
ld a, [vSafeCopyInterruptEnable]
cp a, 0 ; if the stashed enable was 0 return. if the stashed enable was 1 then turn it on
jp z, CopyRangeSafe_Return
set 1, [hl] ; turn on the lcd interrupt
CopyRangeSafe_Return:
reti
CopyRangeUnsafe: ; this is threadsafe but not vblank safe
; hl is source

View File

@ -1,216 +1,4 @@
CopyTilesSafe:
; hl is source
; de is destination
; bc is length to copy
; copy an array of bytes to the bgmap in vram.
; this is the safe-copy analogue of CopyTilesToMap
; stash arguments in memory
di
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a
ld a, c
ldh [vSafeCopyCount], a
ldh [vSafeCopyOriginalCount], a
ld a, b
ldh [vSafeCopyCount+1], a
ldh [vSafeCopyOriginalCount+1], a
; stash interrupt state in memory
ldh a, [$ff41]
ldh [vSafeCopySTAT], a ; stashes $FF41, the STAT register
ldh a, [$ff45]
ldh [vSafeCopyLYC], a ; stashes $FF45, the LYC register
ld a, [INTERRUPT_LCD]
ld [vSafeCopyInterrupt], a
ld a, [INTERRUPT_LCD+1]
ld [vSafeCopyInterrupt+1], a ; stashes the current STAT interrupt handler
ld a, [$ffff]
and a, %0000_0010
ld [vSafeCopyInterruptEnable], a ; stashes whether LCD interrupt are enabled
ld hl, CopyTilesSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE"
ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a
ld hl, $ffff
set 1, [hl]
ld a, %0100_0000
ld [$ff41], a
ld hl, vSafeCopyCount
ld a, 0
ld [$ff0f], a
ei
ret ; return address of bytes remaining to copy
CopyTilesSafe_EnterSafeMode:
push hl ; stash registers! we just took over as an interrupt!
push bc
push de
push af
ld hl, CopyTilesSafe_ExitSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, SAFE_TRANSFER_END ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
ldh a, [vSafeCopySource]
ld l, a
ldh a, [vSafeCopySource+1]
ld h, a ; fetch the source
ldh a, [vSafeCopyDest]
ld e, a
ldh a, [vSafeCopyDest+1]
ld d, a ; fetch the dest
ldh a, [vSafeCopyCount]
ld c, a
ldh a, [vSafeCopyCount+1]
ld b, a ; fetch the count
; before starting transfer, make sure the zero flag is false.
ld a, 1
cp a, 0
CopyTilesSafe_TransferLoop:
ei
nop ; ei only sets the flag one instruction later apparently. safety nop!
nop ; we're processing interrupts here
di
jp z, CopyTilesSafe_CleanUp ; zero flag will only be set if the exit handler fired
ld a, [hl] ; load from the tile map into a
ld [de], a ; load from a into the destination
inc hl ; this is slower than using hli but i'm trying to work with this here
inc de
dec c
; check if we've completed a line?
ld a, 0
or a, c ; check if c is zero, if it's not zero go back and copy more bytes
jp nz, CopyTilesSafe_TransferLoop
CopyTilesSafe_DoneWithLine:
ldh a, [vSafeCopyOriginalCount]
ld c, a
ldh a, [vSafeCopyOriginalCount+1]
ld b, a
ld a, e
add a, 32
ld e, a
ld a, d
adc a, 0
ld d, a
ld a, e
sub a, c
ld e, a
ld a, d
sbc a, 0
ld d, a
dec b
ld a, b
ldh [vSafeCopyOriginalCount+1], a ; store the decremented line count
jp nz, CopyTilesSafe_TransferLoop
jp CopyTilesSafe_Done
CopyTilesSafe_ExitSafeMode:
ld a, 0
cp a, 0 ; set the zero flag, which we're using as a signal to stop transferring
reti ; set a to zero and set the zero flag true. now the transfer loop will end
CopyTilesSafe_CleanUp:
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a ; store new source
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a ; store new dest
ld a, c
ldh [vSafeCopyCount], a
ld a, b
ldh [vSafeCopyCount+1], a ; store new count
ld hl, CopyTilesSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af
pop de
pop bc
pop hl
reti ; we're done with this memcpy cycle so we return from interrupt.
CopyTilesSafe_Done: ; called when the complete transfer is finished,
; this restores interrupts to how they were.
; stash interrupt state in memory
ld a, l
ldh [vSafeCopySource], a
ld a, h
ldh [vSafeCopySource+1], a ; store new source
ld a, e
ldh [vSafeCopyDest], a
ld a, d
ldh [vSafeCopyDest+1], a ; store new dest
ld a, 0
ldh [vSafeCopyCount], a
ld a, 0
ldh [vSafeCopyCount+1], a ; store new count
ld hl, CopyRangeSafe_EnterSafeMode
ld a, l
ld [INTERRUPT_LCD], a
ld a, h
ld [INTERRUPT_LCD+1], a
ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af
pop de
pop bc
pop hl
ldh a, [vSafeCopySTAT]
ldh [$ff41], a
ldh a, [vSafeCopyLYC]
ldh [$ff45], a
ldh a, [vSafeCopyInterrupt]
ld [INTERRUPT_LCD], a
ldh a, [vSafeCopyInterrupt+1]
ld [INTERRUPT_LCD+1], a
ld hl, $ffff
ld a, [hl]
cpl
set 1, a
cpl ; turn off the lcd interrupt enable
ld [hl], a
ld a, [vSafeCopyInterruptEnable]
cp a, 0 ; check if the stat interrupt was active before we took over
jp z, CopyRangeSafe_Return
set 1, [hl] ; turn on the lcd interrupt
CopyTilesSafe_Return:
reti
CopyTilesToMap:
CopyTilesToMapUnsafe:
; copy tiles from where they are linearly packed at an origin (hl)
; to a rectangle in the tilemap in vram (de)
@ -245,51 +33,77 @@ CopyTilesToMapUnsafe:
dec b
ld a, b
cp a, 0
jp nz, CopyTilesToMapUnsafe
jp nz, CopyTilesToMap
ret
CopyTilesToMapThreadsafe:
; copy tiles from where they are linearly packed at an origin (hl)
; to a rectangle in the tilemap in vram (de)
; assuming it has height in b and width in c.
di
ei
nop
di
push bc
.copyTile
ld a, [hl] ; load from the tile map into a
ld [de], a ; load from a into the destination
inc hl ; this is slower than using hli but i'm trying to work with this here
inc de
dec c
; check if we've completed a line?
ld a, 0
or a, c ; check if c is zero, if it's not zero go back and copy more bytes
jp nz, .copyTile
.doneWithLine
pop bc
ei
BuildMetaSprite:
; takkes similar args as copytilestomapunsafe but builds several sprites
; instead.
; location of source tile map: hl
; location in memory to write to: de
; y and x in b and c
; height and width in a & %11110000 and a & %00001111 ??? that's deranged
push hl
push de
pop hl ; want hl and de to be swapped just for the sake of consistent apis
pop de ; hl now holds the OAM location, de holds the sprite map
push af ; save to the stack so we can retrieve it for row-wise decrement
push bc ; hold onto the upper-left corner so we can update it each row
ld a, e
add a, 32
ld e, a
ld a, d
adc a, 0
ld d, a
ld a, e
sub a, c
ld e, a
ld a, d
sbc a, 0
ld d, a
dec b
ld a, b
cp a, 0
jp nz, CopyTilesToMapThreadsafe
di
nop
nop
ret
.writeRow
pop bc
pop af
push af
push bc ; refresh af and bc from their authoritative stack versions
and a, $0F ; take only the horizontal tile count
.buildSprite
;
ld [hl], b ; write y byte
inc hl
ld [hl], c ; write x byte
inc hl
push af ; save a before we use it for transferring de to hl
ld a, [de]
inc de ; move to the next sprite
ld [hl], a
inc hl
inc hl ; skip the attributes byte
; we're going to wait to get our a value (number of tiles left to draw in this
; row) until after we've used a for changing c
;we've written a whole sprite. hl and de are in the right state, we need to
; update a and bc.
; update bc
ld a, c
add a, 8
ld c, a
pop af ; get back the number of tiles to draw in this row
dec a
jp nz, .buildSprite ; if there are still tiles left to draw in this row, do it!
; otherwise we have no more tiles to write this row bc needs to be updated
pop bc
ld a, b
add a, 8
ld b, a ; add 8 to the y coordinate
pop af
sub a, $10
push af
push bc
and a, $F0
; stakc has bc and af, ready for repeating from the top
jp nz, .writeRow ; last numerical operation was and a, $F0 so checking if upper byte is zero
pop bc
pop af
ret

View File

@ -11,11 +11,11 @@ CardBrowseSetup:
ld a, 1
ld [vBlocked], a
ld hl, .loadUIMap
ld hl, .asyncTask
call Async_Spawn_HL
ret
.loadUIMap
.asyncTask
ld a, HIGH(ZEROES)
ld de, SAFE_DMA_LOCATION ; arguments to the first async call.
call RunDMA
@ -24,10 +24,12 @@ CardBrowseSetup:
ld de, $9800 ; destination
ld b, 18 ; height
ld c, 20 ; width
call CopyTilesToMapUnsafe
call LoadCardTask
call RefreshCardTask
ld a, 0
ld [vBlocked], a
ret
CardBrowseUpdate:
@ -91,18 +93,11 @@ CardBrowseUpdate:
cp a, 0
ret nz
ld hl, LoadCardTask
ld hl, RefreshCardTask
call Async_Spawn_HL
ret
LoadCardTask:
ld a, 1
ld [vBlocked], a
call LoadCardData
ld a, 0
ld [vBlocked], a
ret
CardBrowseDraw:
; the card data is loaded asynchronously, initiated in CardReadUpdate
@ -123,9 +118,14 @@ CardBrowseDraw:
ld bc, (SquaresTileset8 - SquaresTileset7) / 8
call CopyRangeUnsafeBy8s
call DrawDeckMinimap
call RunDMA
ret
RefreshCardTask:
call DrawDeckMinimap
call LoadCardData
ret
DrawDeckMinimap:
ld hl, Cards
ld c, [hl] ; count of cards

View File

@ -13,18 +13,28 @@ CardReadSetup:
ld hl, CardReadSetupAsyncTask
call Async_Spawn_HL
ld hl, ZEROES
ld de, MY_OAM
ld bc, $100
call CopyRangeUnsafe
ret
CardReadSetupAsyncTask:
ld hl, UITilemap ; origin
ld hl, CardRead.UITilemap ; origin
ld de, $9800 ; destination
ld b, 18 ; height
ld c, 20 ; width
call CopyTilesToMapUnsafe
call ChangedCardTask
ret
CardReadUpdate:
call CARD_UPDATE - 1
ld hl, vTime
ld a, [rDELTAT]
ld b, a
@ -88,10 +98,9 @@ CardReadUpdate:
cp a, 0
ret nz
ld a, 1
ld [vBlocked], a
ld hl, ChangedCardTask
call Async_Spawn_HL
ret
CardReadDraw:
@ -110,8 +119,11 @@ CardReadDraw:
ld de, $8000+$100*16 + 1*16
ld bc, (SquaresTileset8 - SquaresTileset7) / 8
call CopyRangeUnsafeBy8s
ld de, SAFE_DMA_LOCATION
ld a, HIGH(MY_OAM)
call RunDMA
; the card data is loaded asynchronously, initiated in CardReadUpdate
ret
CardReadTeardown:
@ -158,13 +170,11 @@ ChangedCardTask:
ld [vPreviousCardIndex], a
call LoadCardData
ld a, 0
ld [vBlocked], a
ret
UITilemap:
CardRead.UITilemap:
db $0e, $0a, $0a, $0a, $0a, $0a, $0a, $0a, $0a, $0f, $09, $02, $02, $02, $02, $02, $02, $02, $08, $01
db $0b, $00, $00, $00, $00, $00, $00, $00, $00, $0c, $03, $00, $00, $00, $00, $00, $00, $00, $04, $01
db $0b, $00, $00, $00, $00, $00, $00, $00, $00, $0c, $03, $00, $00, $00, $00, $00, $00, $00, $04, $01
@ -183,4 +193,4 @@ UITilemap:
db $0b, $00, $00, $00, $00, $00, $00, $00, $00, $0c, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $0b, $00, $00, $00, $00, $00, $00, $00, $00, $0c, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
db $11, $0d, $0d, $0d, $0d, $0d, $0d, $0d, $0d, $10, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
UITilemapEnd:
CardRead.UITilemapEnd:

View File

@ -13,12 +13,16 @@
; 0xc104 CALL ...
def MY_OAM equ $c000
; $c100 - c120 call handles, scene stack and interrupt
; $c100 - c120 call handles, scene stack, interrupt, card functions
DEF SCENE_SETUP EQU $c101
DEF SCENE_UPDATE EQU SCENE_SETUP + 4 ; call then ret is 3+1 bytes
DEF SCENE_DRAW EQU SCENE_UPDATE + 4
DEF SCENE_TEARDOWN EQU SCENE_DRAW + 4
DEF INTERRUPT_LCD EQU SCENE_TEARDOWN + 4
def CARD_INIT equ INTERRUPT_LCD + 4
def CARD_UPDATE equ CARD_INIT + 4
def CARD_DRAW equ CARD_UPDATE + 4
println "Card Draw is ", CARD_DRAW
; each of these sections is way bgger than it needs to be
; i doubt any of them will hold more than $20 bytes at all
@ -27,9 +31,9 @@ def ASYNC_VARS_START equ $c200 ; this space's layout defined manually in async.i
def SYSTEM_VARS_START equ $c300 ; system variables like buttons pressed, rng, time
def GLOBAL_VARS_START equ $c400 ; defined mostly in mainmenu, program-wide state
def SCREEN_VARS_START equ $c500 ; per-screen variables like animation stuff
def CARD_VARS_START equ $c600 ; variables for animation of individual cards
def SHUFFLED_DECK equ $c700 ; location for the shuffled deck
def CARD_HELPER_VARS_START equ $c600
def CARD_VARS_START equ $c700 ; variables for animation of individual cards
def SHUFFLED_DECK equ $c800 ; location for the shuffled deck
def ZEROES equ $D000
def ONES equ $D200
@ -41,14 +45,6 @@ DEF rDELTAT EQU rMYBTNP + 1 ; delta_t where $1000 = 1 second
def rLFSR equ rDELTAT + 1 ; 16 bit
; WRAM Layout looks like this:
; $c000 - $c100 OAM DMA source
; $c100 - $c114 self-modifying code interrupts
; $c200 - $c21a shuffled deck
; $c300 - $c400 card display variables
; $c300 - $c30f timers
; $c300 - $c400 card display variables
; $d000 - $d400 zeroes and ones, just because they're handy!
def SAFE_DMA_LOCATION equ $ffc1
@ -144,6 +140,12 @@ EntryPoint:
ld [hl], a
ld hl, INTERRUPT_LCD - 1
ld [hl], a
ld hl, CARD_INIT - 1
ld [hl], a
ld hl, CARD_UPDATE - 1
ld [hl], a
ld hl, CARD_DRAW - 1
ld [hl], a
ld hl, Instructions
inc hl
@ -159,6 +161,12 @@ EntryPoint:
ld [hl], a
ld hl, INTERRUPT_LCD
ld [hl], a
ld hl, CARD_INIT
ld [hl], a
ld hl, CARD_UPDATE
ld [hl], a
ld hl, CARD_DRAW
ld [hl], a
ld hl, Instructions
inc hl
@ -175,6 +183,12 @@ EntryPoint:
ld [hl], a
ld hl, INTERRUPT_LCD + 1
ld [hl], a
ld hl, CARD_INIT + 1
ld [hl], a
ld hl, CARD_UPDATE + 1
ld [hl], a
ld hl, CARD_DRAW + 1
ld [hl], a
ld hl, Instructions
inc hl
@ -192,8 +206,14 @@ EntryPoint:
ld [hl], a
ld hl, INTERRUPT_LCD + 2
ld [hl], a
ld hl, CARD_INIT + 2
ld [hl], a
ld hl, CARD_UPDATE + 2
ld [hl], a
ld hl, CARD_DRAW + 2
ld [hl], a
; set up our scene vectors
; set up our scene handle
ld hl, ScreenMainMenu
call ChangeScene
@ -353,7 +373,7 @@ run_dma_tail: ; This part must be in HRAM.
.run_dma_tail_end
Instructions:
call SCENE_UPDATE + 2
call Instructions+3
ret