;License:MIT ;(c) 2018-9 by 4am ; ; common UI functions ; ; Public functions ; - WaitForKeyFor30Seconds ; - GetOffscreenAddress ; - LoadTitleOffscreen ; - LoadCoverOffscreen ; - DrawSearchBarOffscreen ; - ShowOtherPage ; - ToggleOffscreenPage ; - CoverFade ; - SoftBell ; - Home ; - BlankHGR ; - BlankDHGR ; - ClearOffscreen ; - ExecuteTransitionAndWait ; - IsSearchKey ; Public variables ; - OffscreenPage ; - UILine1 ; - UILine2 ; - VisibleGameCount (set during init) ; !zone { OffscreenPage !byte 1 ; 0 = currently showing HGR page 2 ; (so offscreen is page 1 @ $2000) ; 1 = currently showing HGR page 1 ; (so offscreen is page 2 @ $4000) UILine1 !byte 0,0,0,0,0,0,0,0,0,0 !byte 0,0,0,0,0,0,0,0,0,0 !byte 0,0,0,0,0,0,0,0,0,0 !byte 0,0,0,0,0,0,0,0,0,0 UILine2 !byte 0,0,0,0,0,0,0,0,0,0 !byte 0,0,0,0,0,0,0,0,0,0 !byte 0,0,0,0,0,0,0,0,0,0 !byte 0 UI_ToPlay !byte 0,0,0,0,0,0,0,0,0 Instructions !text "[Type to search, " !byte $0B !text " to browse] " VisibleGameCount !text "000 games" ReturnToPlay !byte $0D !text " to play" ;------------------------------------------------------------------------------ ; GetOffscreenAddress ; get high byte of HGR page that is currently not showing ; ; in: none ; out: A = high byte of offscreen HGR page (#$20 or #$40) ; preserves X/Y ;------------------------------------------------------------------------------ GetOffscreenAddress lda OffscreenPage beq + lda #$40 rts + lda #$20 rts ;------------------------------------------------------------------------------ ; LoadTitleOffscreen ; load title screen in the HGR page that is currently not showing ; ; in: none ; out: all flags and registers clobbered ;------------------------------------------------------------------------------ LoadTitleOffscreen +LDADDR .TitleFile bne + ; Always branches, because Y is loaded ; last with the high byte of the address, ; which is never 0. I miss my 65c02. ;------------------------------------------------------------------------------ ; LoadCoverOffscreen ; load cover screen in the HGR page that is currently not showing ; ; in: none ; out: all flags and registers clobbered ;------------------------------------------------------------------------------ LoadCoverOffscreen ; clobbers all +LDADDR .CoverFile + +STAY @fname jsr GetOffscreenAddress sta + jsr LoadFile !word kRootDirectory @fname !word $FDFD ; SMC !byte $00 + !byte $FD ; SMC rts .TitleFile !byte 5 !text "TITLE" .CoverFile !byte 5 !text "COVER" ;------------------------------------------------------------------------------ ; CoverFade ; load cover screen and animate per-character fade ; ; in: none ; out: all flags and registers clobbered ;------------------------------------------------------------------------------ CoverFade jsr LoadCoverOffscreen jsr ShowOtherPage lda OffscreenPage bne + jsr LoadCoverOffscreen jsr ShowOtherPage + jsr LoadFile ; load transition effect code at $6000 !word kFXDirectory !word @CoverFadeFile !word $6000 jmp $6000 ; exit via loaded code @CoverFadeFile !byte 9 !text "COVERFADE" ;------------------------------------------------------------------------------ ; DrawSearchBarOffscreen ; draw 2-line search UI on the HGR page that is not currently showing ; ; in: X = game index, or #$FF if no game is selected ; out: all flags and registers clobbered ;------------------------------------------------------------------------------ DrawSearchBarOffscreen txa pha lda #22 ; draw visible search bar sta VTAB lda OffscreenPage ror ; draw line 1 on offscreen page +LDADDR UILine1 jsr Draw40Chars lda OffscreenPage ror ; draw line 2 on offscreen page +LDADDR UILine2 jsr Draw40Chars pla bit gCheatsEnabled bpl @done ; if cheats are not enabled, we're done pha tax lda #20 sta VTAB jsr BuildCheatLine1 lda OffscreenPage ror +LDADDR gPathname jsr DrawCenteredString inc VTAB pla tax jsr BuildCheatLine2 lda OffscreenPage ror +LDADDR gPathname jsr DrawCenteredString @done rts ;------------------------------------------------------------------------------ ; ClearOffscreen ; clear $2000..$3FFF or $4000..$5FFF, depending on which HGR page is not ; visible right now ; does not change HGR mode ; ; in: none ; out: $2000..$3FFF or $4000..$5FFF cleared ; A = 0 ; X = 0 ; Y = 0 ; Z = 1 ;------------------------------------------------------------------------------ ClearOffscreen jsr GetOffscreenAddress +HIDE_NEXT_2_BYTES .ClearHGR1 lda #$20 sta @a+2 ldx #$20 lda #$80 ldy #0 @a sta $2000,y iny bne @a inc @a+2 dex bne @a rts ;------------------------------------------------------------------------------ ; ShowOtherPage ; switch to the HGR page that is not currently showing ; ; in: none ; out: A = new value of OffscreenPage ; preserves X/Y ;------------------------------------------------------------------------------ ShowOtherPage jsr ToggleOffscreenPage bne + bit PAGE2 ; show page 2 rts + bit PAGE1 ; show page 1 rts ;------------------------------------------------------------------------------ ; ToggleOffscreenPage ; switch the internal variable that tracks which HGR page is showing ; (does not affect screen) ; ; in: none ; out: A = new value of OffscreenPage ; preserves X/Y ;------------------------------------------------------------------------------ ToggleOffscreenPage lda OffscreenPage eor #$01 sta OffscreenPage rts ;------------------------------------------------------------------------------ ; SoftBell ; yell at the user, but, like, gently ; ; in: none ; out: C clear ; Y preserved ; A=0 ; X=0 ; all flags preserved ;------------------------------------------------------------------------------ SoftBell ldx #32 - lda #2 jsr @wait bit SPEAKER lda #33 jsr @wait bit SPEAKER dex bne - clc rts @wait ; identical to $FCA8 ROM routine, but ROM is switched out when we need it sec -- pha - sbc #1 bne - pla sbc #1 bne -- rts ;------------------------------------------------------------------------------ ; Home ; clear and display text screen (HARDER THAN IT SOUNDS) ; ; in: none ; out: $0106..$011F clobbered ;------------------------------------------------------------------------------ Home MachineStatus = *+1 lda #$D1 ; SMC and #SUPPORTS_SHR beq @noSHR lda NEWVIDEO and #$3F sta NEWVIDEO ; get out of SHR mode and linear mode lda #$F0 sta TBCOLOR ; white text on black background lda #$00 sta CLOCKCTL ; black border sta CLOCKCTL ; set twice for VidHD @noSHR ldx #(@end-@start-1) - lda @start,x sta $106,x dex bpl - jmp $106 @start ; this will be run from main memory +READ_ROM_NO_WRITE sta CLR80VID ; get out of DHGR mode sta DHIRESOFF ; get out of DHGR mode jsr ROM_TEXT ; TEXT jsr ROM_HOME ; HOME +READ_RAM1_WRITE_RAM1 rts @end ;------------------------------------------------------------------------------ ; BlankDHGR ; clear and show DHGR page 1 without flickering ; ; in: none ; out: text page clobbered (but screen holes preserved) ; $2000..$3FFF/main and /aux cleared ;------------------------------------------------------------------------------ BlankDHGR jsr Home jsr .ClearHGR1 ; clear hi-res screen 1 sta WRITEAUXMEM jsr .ClearHGR1 ; clear hi-res screen 1 in auxmem sta WRITEMAINMEM sta SET80VID sta DHIRESON bit PAGE1 jmp HGRMode ;------------------------------------------------------------------------------ ; BlankHGR ; clear and show HGR page 1 without flickering ; ; in: none ; out: text page clobbered (but screen holes preserved) ; $2000..$3FFF cleared ;------------------------------------------------------------------------------ BlankHGR jsr Home jsr .ClearHGR1 ; clear hi-res screen 1 bit PAGE1 ; show hi-res screen 1 (now blank) ; execution falls through here ;------------------------------------------------------------------------------ ; HGRMode ; twiddles softswitches to set HGR mode (does not set page 1 or 2) ; ; in: none ; out: all registers preserved ;------------------------------------------------------------------------------ HGRMode bit $C057 bit $C052 bit $C050 rts ;------------------------------------------------------------------------------ ; ExecuteTransitionAndWait ; call transition effect code (address passed in) and wait a period of time ; or until the user presses a key ; ; in: A/Y = address of transition effect code ; out: all flags and registers clobbered ;------------------------------------------------------------------------------ ExecuteTransitionAndWait +STAY @j+1 @j jsr $FDFD ; SMC call transition effect code ldx #$20 ; picture is showing so now we wait - lda #0 jsr WaitForKeyWithTimeout bmi + dex bpl - + lda KBD cmp #$95 bne + bit CLEARKBD + rts ;------------------------------------------------------------------------------ ; IsSearchKey ; test whether accumulator contains a key that might trigger a new textrank ; search ; ; in: A = key ; out: A &= 0x7F ; Y preserved ; X clobbered ; Z = 1 if this is a search key ; Z = 0 if this is not a search key ;------------------------------------------------------------------------------ IsSearchKey and #$7F ; strip high bit for search characters cmp #$30 ; control keys and punctuation ignored bcc @badkey cmp #$3A ; numbers are good input bcc @goodkey cmp #$41 ; more punctuation (also ignored) bcc @badkey cmp #$5B ; uppercase letters are good input bcs + ora #$20 ; convert uppercase letters to lowercase bne @goodkey ; always branches + cmp #$61 ; more punctuation (also ignored) bcc @badkey cmp #$7B ; lowercase letters are good input bcc @goodkey @badkey ldx #1 rts @goodkey ldx #0 ConvenientlyPlacedRTS rts ; /!\ keep this last in the file to ensure it doesn't cross a page boundary /!\ ;------------------------------------------------------------------------------ ; WaitForKeyFor30Seconds ; does what it says on the tin ; ; in: none ; out: if user presses a key before the timer runs out, exits with A = key ; otherwise exits via MegaAttractMode ; X/Y preserved ;------------------------------------------------------------------------------ WaitForKeyFor30Seconds lda #$16 ; initialize timeout counters sta Timeout sta Timeout+1 sta Timeout+2 @loop lda KBD bmi ConvenientlyPlacedRTS inc RNDSEED+1 ; these are only ever incremented, never bne + ; reset (may be used as a pseudorandom inc RNDSEED ; seed) + dec Timeout ; these are a 3-byte timeout counter bne @loop ; that counts down from a number set dec Timeout+1 ; in .ResetInputTimeout and reset bne @loop ; on every keypress (whether or not dec Timeout+2 ; the key leads to an action) bne @loop jsr CoverFade ; no input for ~30 seconds, switch to jmp MegaAttractMode ; mega-attract mode }