async subsystem :)

This commit is contained in:
Shoofle 2025-01-13 15:44:01 -05:00
parent 1226ee7345
commit 97432b1c2b
9 changed files with 824 additions and 135 deletions

View File

@ -14,6 +14,7 @@ TheFool:
dw FoolMap dw FoolMap
dw FoolTilesEnd - FoolTiles dw FoolTilesEnd - FoolTiles
dw FoolTiles dw FoolTiles
FoolTiles: FoolTiles:
db $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
db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$01,$00,$02 db $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$01,$00,$02

260
Async.inc Normal file
View File

@ -0,0 +1,260 @@
def vAsyncAF equ $ff80
def vAsyncHL EQU $ff82
def vAsyncDE EQU $ff84
def vAsyncBC equ $ff86
def vAsyncPC equ $ff88
def vAsyncNext equ $ff8a
def vAsyncAfter equ $ff8c
def SAFE_ASYNC_START EQU 144
def SAFE_ASYNC_END EQU 151
DoInAsyncVBlank:
di
push af
ld a, l
ldh [vAsyncHL], a
ld a, h
ldh [vAsyncHL+1], a
ld a, e
ldh [vAsyncDE], a
ld a, d
ldh [vAsyncDE+1], a
ld a, c
ldh [vAsyncBC], a
ld a, b
ldh [vAsyncBC+1], a
pop hl
ld a, l
ldh [vAsyncAF], a
ld a, h
ldh [vAsyncAF+1], a
; set pu the next call!
ldh a, [vAsyncNext]
ldh [vAsyncPC], a
ldh a, [vAsyncNext+1]
ldh [vAsyncPC+1], a ; put next into pc
ldh a, [vAsyncAfter]
ldh [vAsyncNext], a
ldh a, [vAsyncAfter+1]
ldh [vAsyncNext+1], a ; puut after into next
ld a, 0
ldh [vAsyncAfter], a ; unless this gets overwritten later, end execution after that
ldh [vAsyncAfter+1], a
ld a, LOW(DoInAsyncVBlank_EnterThread)
ld [INTERRUPT_LCD], a
ld a, HIGH(DoInAsyncVBlank_EnterThread)
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER THREAD"
ld a, SAFE_ASYNC_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [rLYC], a ; set LYC
ld hl, rIE
set 1, [hl] ; enable vblank
ld hl, rSTAT
set 6, [hl] ; set the stat interrupt to LYC mode
ld hl, rIF
res 1, [hl] ; clear the interrupt so we don't immediately fire it
ei
ret
DoInAsyncVBlank_EnterThread:
;stack looks like:
;c113 (SMC int @ LYC 90 pc), 004b (hw int @ LYC 90 pc), outer context pc
push hl
push bc
push de
push af
;af, de, bc, hl, c113 (SMC interrupt pc), 004b (hardwired interrput pc), outer context pc
; check if there's anything queued up for next execution
ldh a, [vAsyncPC]
ld l, a
ldh a, [vAsyncPC+1]
ld h, a
or a, l
jp z, DoInAsyncVBlank_EndThread ; if nothing is queued up, jump to cleanup
ld a, LOW(DoInAsyncVBlank_ExitThread)
ld [INTERRUPT_LCD], a
ld a, HIGH(DoInAsyncVBlank_ExitThread)
ld [INTERRUPT_LCD+1], a
ld a, SAFE_ASYNC_END ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [rLYC], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
; what if our async thread calls return?
; we need to have a PC to return to. if that happens, we will want to
; reti.
ld hl, DoInAsyncVBlank_EarlyReturn
push hl ; address for if the thread retrns
ldh a, [vAsyncPC]
ld l, a
ldh a, [vAsyncPC+1]
ld h, a
push hl ; put vAsyncPC on the stack! for jumping to it!
; stack looks like: vasyncpc, early return, af, de, bc, hll, SMC interrput pc, hardwired interrupt pc, outer context pc
ldh a, [vAsyncAF]
ld l, a
ldh a, [vAsyncAF+1]
ld h, a
push hl
ldh a, [vAsyncHL]
ld l, a
ldh a, [vAsyncHL+1]
ld h, a
ldh a, [vAsyncDE]
ld e, a
ldh a, [vAsyncDE+1]
ld d, a
ldh a, [vAsyncBC]
ld c, a
ldh a, [vAsyncBC+1]
ld b, a
pop af; putting vAsyncAF into af requires this hoop-jumping
ei
ret ; "return" to the vAsyncPC wee put on the stack previously.
; this is more or less a jump, not a return.
; is that the source of our problems?
; after this instruction executes, stack looks like:
; early return, af, de, bc, hl, PC (smc int), PC (hardwired int), PC (outer context)
; and we'll be in the async thread, executing
DoInAsyncVBlank_EarlyReturn:
; stack:
; af, de, bc, hl, PC (smc int @ LYC90), PC (hw int @ LYC 90), PC (outer context)
PRINTln "early return handle is ", DoInAsyncVBlank_EarlyReturn
; save state of registers
di
push af
ld a, l
ldh [vAsyncHL], a
ld a, h
ldh [vAsyncHL+1], a
ld a, e
ldh [vAsyncDE], a
ld a, d
ldh [vAsyncDE+1], a
ld a, c
ldh [vAsyncBC], a
ld a, b
ldh [vAsyncBC+1], a
pop hl
ld a, l
ldh [vAsyncAF], a
ld a, h
ldh [vAsyncAF+1], a
; set pu the next call!
ldh a, [vAsyncNext]
ldh [vAsyncPC], a
ldh a, [vAsyncNext+1]
ldh [vAsyncPC+1], a ; put next into pc
ldh a, [vAsyncAfter]
ldh [vAsyncNext], a
ldh a, [vAsyncAfter+1]
ldh [vAsyncNext+1], a ; puut after into next
ld a, 0
ldh [vAsyncAfter], a ; unless this gets overwritten later, end execution after that
ldh [vAsyncAfter+1], a
ld a, LOW(DoInAsyncVBlank_EnterThread) ; set up next call
ld [INTERRUPT_LCD], a
ld a, HIGH(DoInAsyncVBlank_EnterThread)
ld [INTERRUPT_LCD+1], a
ld a, SAFE_ASYNC_START
ld [rLYC], a
; restore the pre-interrupt registers, return and enable interrupts
pop af
pop de
pop bc
pop hl
reti
DoInAsyncVBlank_EndThread:
; end execution of the thread by disabling the interrupt
; and restore the state for the outer thread
ld hl, rIE
res 1, [hl] ; disable STAT/vblank interrupt
pop af
pop de
pop bc
pop hl
reti
DoInAsyncVBlank_ExitThread:
; at this point, it's an interrpt being called from inside the interrupt
; our stack probably looks like this:
; PC (smc int), PC (hardwired int), PC (inside thread), early return, af, de, bc, hl, PC (smc int), PC (hardwired int), PC (outer context)
; first, save the interrpt thread registers.
push af
ld a, l
ldh [vAsyncHL], a
ld a, h
ldh [vAsyncHL+1], a
ld a, e
ldh [vAsyncDE], a
ld a, d
ldh [vAsyncDE+1], a
ld a, c
ldh [vAsyncBC], a
ld a, b
ldh [vAsyncBC+1], a
pop hl
ld a, l
ldh [vAsyncAF], a
ld a, h
ldh [vAsyncAF+1], a
;god i'm such a genius
; this was called as an interrupt inside the interrupt
;so our stack looks like this:
; PC (smc int), PC (hardwired int), PC (inside thread), early return, af, de, bc, hl, PC (smc int), PC (hardwired int), PC (outer context)
; we've got the two PCs from the inner interrupt call stack.
; get rid of them! we're running without handrails! i know what i'm doing! I hope!
pop hl
pop hl
; now, save the interrupt thread's pc., which is on the stack from this
; interrupt being called.
pop hl
ld a, l
ldh [vAsyncPC], a
ld a, h
ldh [vAsyncPC+1], a
; now we are done with this entire execution of thread. now we need to set up
; the next execution of this thread.
ld a, LOW(DoInAsyncVBlank_EnterThread)
ld [INTERRUPT_LCD], a
ld a, HIGH(DoInAsyncVBlank_EnterThread)
ld [INTERRUPT_LCD+1], a
ld a, SAFE_ASYNC_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [rLYC], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
;at present the stack looks like:
; early return, af, de, bc, hl, pc (smc int @ LYC 90), pc (hardwired int at LYC 90), PC (outer context)
; pop the early return and discard it.
pop hl
; and finally, we can restore the state of the registers to what they were
; before this whole handler got called.
pop af
pop de
pop bc
pop hl
reti ; this is a proper return

View File

@ -1,17 +1,31 @@
SECTION "Card Data", ROM0 SECTION "Card Data", ROM0
Spreads: Spreads:
db 5 ; length
.nospread .nospread
db 0 db 0
db 20, " Nothing "
db 20, " This is no spread. "
.onecard
db 1, $21
db 20, " One Card Spread "
db 20, " Draw a single card."
.tencard .tencard
db 10, $00, $10, $20, $30, $40, $02, $12, $22, $32, $42 db 10, $00, $10, $20, $30, $40, $02, $12, $22, $32, $42
db 20, " Ten Card Spread "
db 20, "Throw more cards on."
.fivecard .fivecard
db 5, $11, $20, $22, $31, $41 db 5, $11, $20, $22, $31, $41
db 20, " Horizontal Cross "
db 20, " A little spicy. "
.threecard .threecard
db 3, $11, $21, $31 db 3, $01, $21, $41
db 20, " Three Card Spread "
db 20, " Old reliable. "
.end
Cards: Cards:
db 5 db 5 ; length
dw TheFool dw TheFool
dw TheMagician dw TheMagician
dw TheHighPriestess dw TheHighPriestess

View File

@ -9,6 +9,8 @@ DEF vSafeCopySTAT EQU vSafeCopyLYC + 1 ; stashes $FF41, the STAT register
DEF vSafeCopyInterrupt EQU vSafeCopySTAT + 1 ; stashes the previous LCD interrupt DEF vSafeCopyInterrupt EQU vSafeCopySTAT + 1 ; stashes the previous LCD interrupt
DEF vSafeCopyInterruptEnable EQU vSafeCopyInterrupt + 2 ; stashes $FFFF, which interrupts are enabled DEF vSafeCopyInterruptEnable EQU vSafeCopyInterrupt + 2 ; stashes $FFFF, which interrupts are enabled
DEF SAFE_TRANSFER_START EQU 145
DEF SAFE_TRANSFER_END EQU 153
CopyRangeSafe: CopyRangeSafe:
; hl is source ; hl is source
@ -56,7 +58,7 @@ CopyRangeSafe:
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE" ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE"
ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ld [$ff45], a
ld hl, $ffff ld hl, $ffff
set 1, [hl] set 1, [hl]
@ -88,7 +90,7 @@ CopyRangeSafe_EnterSafeMode:
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD+1], a ld [INTERRUPT_LCD+1], a
ld a, 153 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING 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 ld [$ff45], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
ldh a, [vSafeCopySource] ldh a, [vSafeCopySource]
ld l, a ld l, a
@ -145,7 +147,7 @@ CopyRangeSafe_CleanUp:
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD+1], a ld [INTERRUPT_LCD+1], a
ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING 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 ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af pop af
pop de pop de
@ -174,7 +176,7 @@ CopyRangeSafe_Done: ; called when the complete transfer is finished,
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD+1], a ld [INTERRUPT_LCD+1], a
ld a, 143 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING 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 ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af pop af
pop de pop de
@ -205,7 +207,7 @@ CopyRangeSafe_Done: ; called when the complete transfer is finished,
CopyRangeSafe_Return: CopyRangeSafe_Return:
reti reti
CopyRangeUnsafe: CopyRangeUnsafe: ; this is threadsafe but not vblank safe
; hl is source ; hl is source
; de is destination ; de is destination
; bc is length to copy ; bc is length to copy

View File

@ -40,7 +40,7 @@ CopyTilesSafe:
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE" ld [INTERRUPT_LCD + 1], a; set interrupt handler to "ENTER SAFE MODE"
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING ld a, SAFE_TRANSFER_START ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING
ld [$ff45], a ld [$ff45], a
ld hl, $ffff ld hl, $ffff
set 1, [hl] set 1, [hl]
@ -65,7 +65,7 @@ CopyTilesSafe_EnterSafeMode:
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD+1], a ld [INTERRUPT_LCD+1], a
ld a, 153 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING 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 ld [$ff45], a ; set lcd interrupt handler to EXIT SAFE MODE on line 153
ldh a, [vSafeCopySource] ldh a, [vSafeCopySource]
ld l, a ld l, a
@ -120,7 +120,6 @@ CopyTilesSafe_DoneWithLine:
dec b dec b
ld a, b ld a, b
cp a, 0
ldh [vSafeCopyOriginalCount+1], a ; store the decremented line count ldh [vSafeCopyOriginalCount+1], a ; store the decremented line count
jp nz, CopyTilesSafe_TransferLoop jp nz, CopyTilesSafe_TransferLoop
@ -151,7 +150,7 @@ CopyTilesSafe_CleanUp:
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD+1], a ld [INTERRUPT_LCD+1], a
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING 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 ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af pop af
pop de pop de
@ -180,7 +179,7 @@ CopyTilesSafe_Done: ; called when the complete transfer is finished,
ld [INTERRUPT_LCD], a ld [INTERRUPT_LCD], a
ld a, h ld a, h
ld [INTERRUPT_LCD+1], a ld [INTERRUPT_LCD+1], a
ld a, 148 ; CHANGE ME TO ADJUST SAFE TRANSFER TIMING 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 ld [$ff45], a ; set lcd interrupt handler to ENTER SAFE MODE on line 148
pop af pop af
pop de pop de
@ -213,11 +212,11 @@ CopyTilesSafe_Return:
CopyTilesToMapUnsafe: CopyTilesToMapUnsafe:
; copy tiles from where they are linearly packed at an origin (de) ; copy tiles from where they are linearly packed at an origin (hl)
; to a rectangle in the tilemap in vram (hl) ; to a rectangle in the tilemap in vram (de)
; assuming it has height in b and width in c. ; assuming it has height in b and width in c.
push bc push bc
CopyTile: .copyTile
ld a, [hl] ; load from the tile map into a ld a, [hl] ; load from the tile map into a
ld [de], a ; load from a into the destination 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 hl ; this is slower than using hli but i'm trying to work with this here
@ -226,8 +225,8 @@ CopyTile:
; check if we've completed a line? ; check if we've completed a line?
ld a, 0 ld a, 0
or a, c ; check if c is zero, if it's not zero go back and copy more bytes or a, c ; check if c is zero, if it's not zero go back and copy more bytes
jp nz, CopyTile jp nz, .copyTile
DoneWithLine: .doneWithLine
pop bc pop bc
ld a, e ld a, e
@ -247,4 +246,45 @@ DoneWithLine:
ld a, b ld a, b
cp a, 0 cp a, 0
jp nz, CopyTilesToMapUnsafe jp nz, CopyTilesToMapUnsafe
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
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
ret ret

View File

@ -8,8 +8,7 @@ ScreenCardRead:
dw CardReadUpdate dw CardReadUpdate
dw CardReadDraw dw CardReadDraw
dw CardReadTeardown dw CardReadTeardown
;; CARD READ PAGE STARTS HERE
CardReadSetup: CardReadSetup:
; Turn the LCD off ; Turn the LCD off
ld hl, rLCDC ld hl, rLCDC
@ -37,18 +36,8 @@ CardReadSetup:
ld c, 10 ; width ld c, 10 ; width
call CopyTilesToMapUnsafe call CopyTilesToMapUnsafe
ld a, 0
ld hl, $c000
ld bc, 18*10
.buildZeros
ld a, 0
ld [hl+], a
ld a, b
or a, c
dec bc
jp nz, .buildZeros
ld hl, $c000 ld hl, ZEROES
ld de, $9800 + 10 ld de, $9800 + 10
ld b, 18 ld b, 18
ld c, 10 ld c, 10
@ -75,37 +64,25 @@ CardReadSetup:
CardReadUpdate: CardReadUpdate:
ld hl, rMYBTNP ld hl, rMYBTNP
bit 5, [hl] bit 4, [hl]
jp z, .doneWithB jp z, .doneWithB
ld hl, ScreenMainMenu ld hl, ScreenMainMenu
call ChangeScene call ChangeScene
ret ret
.doneWithB .doneWithB
ldh a, [vSelectedCardIndex]
bit 3, [hl] ; select the down key bit 3, [hl] ; select the down key
jp z, :+ ; skip the following code if down is not pressed jp z, :+ ; skip the following code if down is not pressed
ldh a, [vSelectedCardIndex]
inc a ; increment when they press down because the deck has card 0 at the top inc a ; increment when they press down because the deck has card 0 at the top
ldh [vSelectedCardIndex], a
: :
bit 2, [hl] ; select up key %0000_0100 bit 2, [hl] ; select up key %0000_0100
jp z, :+ ; skip the following code if up is not pressed jp z, :+ ; skip the following code if up is not pressed
ldh a, [vSelectedCardIndex]
dec a ; decrement when they press up because the deck has card 0 at the top dec a ; decrement when they press up because the deck has card 0 at the top
ldh [vSelectedCardIndex], a
:
ldh a, [vSelectedCardIndex] ; load current selected tile index
ld hl, Cards ; deck length
cp a, [hl] ; ddoes the index equal the deck length?
jp nz, :+
ld a, 0 ; if the index equals the deck length replace it with zero
ldh [vSelectedCardIndex], a
:
cp a, $FF ; if the tile index is $FF (underflowed from dec)
jp nz, :+
ld a, [hl]
dec a ;replace with deck length - 1
ldh [vSelectedCardIndex], a
: :
ld hl, Cards
call ArrayClampLooping
ldh [vSelectedCardIndex], a ; load current selected tile index
ld hl, rMYBTNP ld hl, rMYBTNP
bit 1, [hl] bit 1, [hl]
@ -140,90 +117,13 @@ CardReadUpdate:
CardReadDraw: CardReadDraw:
; first, we draw the spread minimap ; first, we draw the spread minimap
.drawSpread
ldh a, [vCurrentSpread] ldh a, [vCurrentSpread]
ld c, a ld c, a
ldh a, [vCurrentSpread+1] ldh a, [vCurrentSpread+1]
ld b, a ld b, a
ld a, [bc]
ld e, a
ld d, 0
.foundSpread
push de ; length of the spread in e!
.drawCard
ld a, e
cp a, 0
jp z, .doneWithSpread
inc bc ; first card of spread is after the length of the spread
ld hl, $9800 + (32*12)+11 ld hl, $9800 + (32*12)+11
ld a, [bc]
swap a
and a, %0000_1111
ld d, 0
ld e, a ; add a to hl
add hl, de
.doneWithWalkRight
ld a, [bc]
and a, %0000_1111
ld d, 0
ld e, 32
jp z, .doneWithWalkDown
.walkDown
dec a
add hl, de
cp a, 0
jp nz, .walkDown
.doneWithWalkDown
.drawMiniCard
ld [hl], $83
add hl, de
ld [hl], $84
.doneDrawingCard
pop de
dec de
ld a, e
cp a, 0
jp nz, .foundSpread
.doneWithSpread
; highlight the selected card
ldh a, [vCurrentSpread]
ld l, a
ldh a, [vCurrentSpread+1]
ld h, a
ldh a, [vSelectedCardInSpread] ldh a, [vSelectedCardInSpread]
ld d, 0 call DrawSpreadMinimap
ld e, a ; index of selected card in spread
inc e ; skip length
add hl, de
ld b, h
ld c, l ; move location of selected card to bc
ld hl, $9800 + (32*12)+11
ld a, [bc] ; a has card location
swap a
and a, %0000_1111
ld e, a
add hl, de ; step right
ld e, 32
ld a, [bc]
and a, %0000_1111
jp z, CardReadDraw_DrawSelectedCard
:
dec a
add hl, de ; step down
cp a, 0
jp nz, :-
CardReadDraw_DrawSelectedCard:
ld [hl], $85
add hl, de
ld [hl], $86
; okay now we draw the deck minimap ; okay now we draw the deck minimap
ld a, [Cards] ld a, [Cards]
@ -384,8 +284,6 @@ INCLUDE "CopyRangeSafe.inc"
INCLUDE "CopyTilesSafe.inc" INCLUDE "CopyTilesSafe.inc"
INCLUDE "CardLibrary.inc"
SECTION "Tile data", ROM0 SECTION "Tile data", ROM0
UITiles: UITiles:

View File

@ -182,7 +182,11 @@ MainMenuUpdate:
jp z, .option3 jp z, .option3
jp .doneWithMenuSelect jp .doneWithMenuSelect
.option1 .option1
jp .doneWithMenuSelect ld a, 0
ld [vSelectedSpreadIndex], a
ld hl, ScreenSpreadSelect
call ChangeScene
ret
.option2 .option2
jp .doneWithMenuSelect jp .doneWithMenuSelect
.option3 .option3
@ -193,7 +197,6 @@ MainMenuUpdate:
ld hl, ScreenCardRead ld hl, ScreenCardRead
call ChangeScene call ChangeScene
ret ret
jp .doneWithMenuSelect
.doneWithMenuSelect .doneWithMenuSelect

View File

@ -0,0 +1,447 @@
DEF vSelectedSpreadIndex EQU VARIABLES_START
DEF vPreviousSpreadIndex EQU vSelectedSpreadIndex + 1
def vSelectedSpreadCard equ vPreviousSpreadIndex + 1
ScreenSpreadSelect:
dw SpreadSelectSetup
dw SpreadSelectUpdate
dw SpreadSelectDraw
dw SpreadSelectTeardown
SpreadSelectSetup:
ld a, 0
ldh [vSelectedCardInSpread], a
ldh [vPreviousSpreadIndex], a
ldh [vSelectedSpreadIndex], a
ld hl, ZEROES
ld de, $9800
ld b, 18
ld c, 20
ld a, LOW(CopyTilesToMapThreadsafe)
ld [vAsyncNext], a
ld a, HIGH(CopyTilesToMapThreadsafe)
ld [vAsyncNext+1], a
ld a, LOW(.loadUITiles)
ld [vAsyncAfter], a
ld a, HIGH(.loadUITiles)
ld [vAsyncAfter+1], a
call DoInAsyncVBlank
ld a, HIGH(ZEROES)
ld de, $ffc0
call RunDMA
ret
.loadUITiles
ld hl, UITiles ; source
ld de, $8000 + $80*16; destination of copy
ld bc, UITilesEnd - UITiles ; length to copy
ld a, LOW(CopyRangeUnsafe)
ld [vAsyncNext], a
ld a, HIGH(CopyRangeUnsafe)
ld [vAsyncNext+1], a
ld a, LOW(DrawSpreadAsync)
ld [vAsyncAfter], a
ld a, HIGH(DrawSpreadAsync)
ld [vAsyncAfter+1], a
ret
SpreadSelectUpdate:
ld hl, rMYBTNP
bit 4, [hl]
jp z, .doneB
ld hl, ScreenMainMenu
call ChangeScene
ret
.doneB
ld a, [vSelectedSpreadIndex]
bit 3, [hl] ; select the down key
jp z, .doneDown ; skip the following code if down is not pressed
dec a ; increment when they press down because the deck has card 0 at the top
.doneDown
bit 2, [hl] ; select up key
jp z, .doneUp ; skip the following code if up is not pressed
inc a ; decrement when they press up because the deck has card 0 at the top
.doneUp
ld hl, Spreads
call ArrayClampLooping
ldh [vSelectedSpreadIndex], a ; load current selected tile index
ld hl, vPreviousSpreadIndex
cp a, [hl]
ret z ; we're done if previous index is same as new index
; execute an async call to DrawSpreadAsync.
ld a, LOW(DrawSpreadAsync)
ld [vAsyncNext], a
ld a, HIGH(DrawSpreadAsync)
ld [vAsyncNext+1], a
call DoInAsyncVBlank
ret ; return from main thread. go back to looping.
DrawSpreadAsync:
ldh a, [vSelectedSpreadIndex]
ldh [vPreviousSpreadIndex], a
; find the correct spread address
ld hl, Spreads
inc hl ; skip length of spreads
ld a, [vSelectedSpreadIndex]
inc a ; we're decing at the start so we inc first to prepare...
ld d, 0
.findSpread
dec a
jp z, .spreadFound
ld e, [hl] ; skip cards in spread
inc hl
add hl, de
ld e, [hl] ; skip title of spread
inc hl
add hl, de
ld e, [hl] ; skip description
inc hl
add hl, de
jp .findSpread
.spreadFound
ld a, l
ld [vCurrentSpread], a
ld a, h
ld [vCurrentSpread+1], a ; save the current spread (hl) into vcurrentspread.
ld de, $9800 + 32*4 + 3
ld hl, ZEROES
ld b, 8
ld c, 10
ld a, LOW(CopyTilesToMapThreadsafe)
ld [vAsyncNext], a
ld a, HIGH(CopyTilesToMapThreadsafe)
ld [vAsyncNext+1], a
ld a, LOW(.afterClear)
ld [vAsyncAfter], a
ld a, HIGH(.afterClear)
ld [vAsyncAfter+1], a
ret ; return from async execution now that we've registered desire
; to call copytilestomapthreadsafe
; and then drawspread
.afterClear
ld a, [vCurrentSpread]
ld l, a
ld a, [vCurrentSpread+1]
ld h, a
ld d, 0
ld e, [hl]
inc e
add hl, de
ld de, $9800 + 32
ld a, LOW(PrintString)
ld [vAsyncNext], a
ld a, HIGH(PrintString)
ld [vAsyncNext+1], a
ld a, LOW(.afterTitle)
ld [vAsyncAfter], a
ld a, HIGH(.afterTitle)
ld [vAsyncAfter+1], a
ret
.afterTitle
ld de, $9800 + (32*2)
ld a, LOW(PrintString)
ld [vAsyncNext], a
ld a, HIGH(PrintString)
ld [vAsyncNext+1], a
ld a, LOW(.afterDescription)
ld [vAsyncAfter], a
ld a, HIGH(.afterDescription)
ld [vAsyncAfter+1], a
ret
.afterDescription
ld hl, $9800 + 32*4 + 3
ldh a, [vSelectedSpreadCard]
ld e, a ; e contains the selected index
ld a, LOW(DrawSpreadBigAndThreadsafe)
ld [vAsyncNext], a
ld a, HIGH(DrawSpreadBigAndThreadsafe)
ld [vAsyncNext+1], a
ld a, LOW(.finishAsyncUpdate)
ld [vAsyncAfter], a
ld a, HIGH(.finishAsyncUpdate)
ld [vAsyncAfter+1], a
ret
.finishAsyncUpdate
; signal that we're done with execution of the async thread
ld a, 0
ld [vAsyncNext], a
ld [vAsyncNext+1], a
ld [vAsyncAfter], a
ld [vAsyncAfter+1], a
ret
SpreadSelectDraw:
ret
SpreadSelectTeardown:
ret
DrawSpreadBigAndThreadsafe:
; hl for location on screen
; bc for current spread address ; actually holding that in vCurrentSpread
; e for index of selected card
di
ld a, [vCurrentSpread]
ld c, a
ld a, [vCurrentSpread+1]
ld b, a
ld a, [bc]
cp a, 0 ; length of spread
ret z ; return early if the spread is empty
ld d, a ; length of spread in d
inc d
.drawCards
ei
nop
di
dec d
jp z, .doneWithSpread ; if we're drawing zero remaining cards, stop drawing
inc bc ; step forward
push hl ; need this bc drawsmallcard changes hl
ld a, [bc]
call DrawBigCard
pop hl
jp .drawCards
.doneWithSpread
; stack has spread address
; d is zero
; e should have currently selected index
ld b, h
ld c, l ; stash hl in bc for a mo; this should be a location in vram
ld a, [vCurrentSpread]
ld l, a
ld a, [vCurrentSpread+1]
ld h, a
;spread address in hl
inc e ; skip the tiles length
add hl, de
ld a, [hl] ; load card descriptor into a
ld h, b
ld l, c; retrieve vram address
ei
nop
di
call DrawBigCardSelected
ei
ret
DrawSpreadBig:
; hl for location on screen
; bc for current spread address
; e for index of selected card
ld a, [bc]
cp a, 0 ; length of spread
ret z ; return early if the spread is empty
push bc
ld d, a ; length of spread in d
inc d
.drawCards
dec d
jp z, .doneWithSpread ; if we're drawing zero remaining cards, stop drawing
inc bc ; step forward
push hl ; need this bc drawsmallcard changes hl
ld a, [bc]
call DrawBigCard
pop hl
jp .drawCards
.doneWithSpread
; stack has spread address
; d is zero
; e should have currently selected index
ld b, h
ld c, l ; stash hl in bc for a mo; this should be a location in vram
pop hl ; put bc from stack into hl, this is the spread address
inc e ; skip the tiles length
add hl, de
ld a, [hl]
ld h, b
ld l, c; retrieve
;call DrawBigCardSelected
ret
DrawBigCard: ; starting from screen location hl, draw a card at
;the location described in a
; saves de and is therefore not threadsafe
push de
ld d, a
swap a
and a, %0000_1111
sla a
ld e, a
ld a, d
and a, %0000_1111
ld d, 0
add hl, de ; step right
ld e, 64
jp z, .drawCard
.stepDown
add hl, de ; step down
dec a
jp nz, .stepDown
.drawCard
ld de, 32
ld [hl], $12
inc hl
ld [hl], $1e
add hl, de
ld [hl], $1f
dec hl
ld [hl], $13
add hl, de
ld [hl], $13
inc hl
ld [hl], $1f
add hl, de
ld [hl], $23
dec hl
ld [hl], $17
pop de
ret
DrawBigCardSelected: ; starting from screen location hl, draw a card at
;the location described in a
push de
push af
swap a
ld d, 0
and a, %0000_1111
sla a
ld e, a
add hl, de ; step right
ld e, 64
pop af
and a, %0000_1111
jp z, .drawCard
.stepDown
add hl, de ; step down
dec a
jp nz, .stepDown
.drawCard
ld de, 32
ld [hl], $12
inc hl
ld [hl], $1e
add hl, de
ld [hl], $1f
dec hl
ld [hl], $13
add hl, de
ld [hl], $13
inc hl
ld [hl], $1f
add hl, de
ld [hl], $23
dec hl
ld [hl], $17
pop de
ret
DrawSpreadMinimap:
; hl for location on screen
; bc for current spread address
; a for index of selected card
push af
push bc
ld a, [bc]
ld d, 0
ld e, a ; length of spread in de
.drawCards
ld a, e
cp a, 0
jp z, .doneWithSpread ; if we're drawing zero remaining cards, stop drawing
dec e
inc bc ; step forward
push hl ; need this bc drawsmallcard changes hl
push bc
ld a, [bc]
ld bc, $8384
call DrawSmallCard
pop bc
pop hl
jp .drawCards
.doneWithSpread ; stack has hl, bc, af at the time of jumping here
pop bc ; stack: af
pop af
ld d, 0
ld e, a ; index of selected card in spread
inc e ; skip the length
push hl ; stack: hl
ld h, b
ld l, c ; put bc in hl temporarily so we can add to hl
add hl, de
ld a, [hl]
pop hl ; stack: empty
ld bc, $8586
call DrawSmallCard
ret
DrawSmallCard: ; starting from screen location hl, draw a card at
;the location described in a, top and bottom sprite in b and c
push de
push af
swap a
ld d, 0
and a, %0000_1111
ld e, a
add hl, de ; step right
ld e, 32
pop af
and a, %0000_1111
jp z, .drawCard
:
dec a
add hl, de ; step down
cp a, 0
jp nz, :-
.drawCard
ld [hl], b
add hl, de
ld [hl], c
pop de
ret

View File

@ -10,6 +10,8 @@ DEF SCENE_TEARDOWN EQU SCENE_DRAW + 4
DEF INTERRUPT_LCD EQU $c111 DEF INTERRUPT_LCD EQU $c111
def ZEROES equ $D000
DEF rMYBTN EQU $FFA8 DEF rMYBTN EQU $FFA8
DEF rMYBTNP EQU rMYBTN + 1 DEF rMYBTNP EQU rMYBTN + 1
DEF rDELTAT EQU rMYBTNP + 1 DEF rDELTAT EQU rMYBTNP + 1
@ -30,8 +32,20 @@ SECTION "Header", ROM0[$100]
EntryPoint: EntryPoint:
; Shut down audio circuitry ; Shut down audio circuitry
ld a, 0 ld a, 0
ld [rNR52], a ; shut down audio ldh [rNR52], a ; shut down audio
ldh [rDIV], a ; reset timer just in case?? ldh [rDIV], a ; reset timer just in case??
ld a, 0
ld hl, ZEROES
ld bc, $200
.buildZeros
ld a, 0
ld [hl+], a
ld a, b
or a, c
dec bc
jp nz, .buildZeros
; set up the scene and interrupt vectors ; set up the scene and interrupt vectors
ld hl, Instructions ld hl, Instructions
@ -101,7 +115,6 @@ EntryPoint:
call ChangeScene call ChangeScene
Loop: Loop:
di
; okay this is kinda sketchy. we want a delta time variable. ; okay this is kinda sketchy. we want a delta time variable.
; we've got two eight-bit counters, one at 4096hz and one at 16384hz ; we've got two eight-bit counters, one at 4096hz and one at 16384hz
; we can definitely reset the faster counter. ; we can definitely reset the faster counter.
@ -156,7 +169,13 @@ Loop:
call SCENE_DRAW - 1 ; hope this takes fewer than 9 scanlines! call SCENE_DRAW - 1 ; hope this takes fewer than 9 scanlines!
; either way it's going to eat into the update timing ; either way it's going to eat into the update timing
; at this point we want to make sure that scanline 153 has passed
; we should check if we're past there and skip this await if necessary
ld b, 5
call AwaitLine
jp Loop jp Loop
ChangeScene: ; hl should be a pointer to, in sequence, setup update draw teardown ChangeScene: ; hl should be a pointer to, in sequence, setup update draw teardown
call SCENE_TEARDOWN - 1 call SCENE_TEARDOWN - 1
@ -199,8 +218,11 @@ ArrayClampLooping: ; loops a to be in the array, assuming hl points to the lengt
: :
ret ; a is return value ret ; a is return value
PrintString: ; write ascii string which has been prefixed by its length. PrintString: ; write ascii string which has been prefixed by its length. at hl
ld b, [hl] ld b, [hl]
ld a, b
cp a, 0
ret z
inc hl inc hl
PrintBChars: ;write ascii characters. will not respect newlines or anything like that PrintBChars: ;write ascii characters. will not respect newlines or anything like that
; hl should be the source of ascii text ; hl should be the source of ascii text
@ -240,7 +262,9 @@ run_dma_tail: ; This part must be in HRAM.
Instructions: Instructions:
call SCENE_UPDATE + 2 call SCENE_UPDATE + 2
ret ret
INCLUDE "Async.inc"
INCLUDE "ScreenMainMenu.inc" INCLUDE "ScreenMainMenu.inc"
INCLUDE "ScreenSpreadSelect.inc"
INCLUDE "ScreenCardRead.inc" INCLUDE "ScreenCardRead.inc"
INCLUDE "ScreenSpreadSelect.inc"
INCLUDE "CardLibrary.inc"